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

#include <ERF.H>

Inheritance diagram for ERF:
Collaboration diagram for ERF:

Public Member Functions

 ERF ()
 
 ~ERF () override
 
void ERF_shared ()
 
 ERF (ERF &&) noexcept=delete
 
ERFoperator= (ERF &&other) noexcept=delete
 
 ERF (const ERF &other)=delete
 
ERFoperator= (const ERF &other)=delete
 
void Evolve ()
 
void ErrorEst (int lev, amrex::TagBoxArray &tags, amrex::Real time, int ngrow) override
 
void InitData ()
 
void InitData_pre ()
 
void InitData_post ()
 
void 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 write_1D_profiles (amrex::Real time)
 
void write_1D_profiles_stag (amrex::Real time)
 
amrex::Real cloud_fraction (amrex::Real time)
 
void FillBdyCCVels (amrex::Vector< amrex::MultiFab > &mf_cc_vel)
 
void sample_points (int lev, amrex::Real time, amrex::IntVect cell, amrex::MultiFab &mf)
 
void sample_lines (int lev, amrex::Real time, amrex::IntVect cell, amrex::MultiFab &mf)
 
void derive_diag_profiles (amrex::Real time, amrex::Gpu::HostVector< amrex::Real > &h_avg_u, amrex::Gpu::HostVector< amrex::Real > &h_avg_v, amrex::Gpu::HostVector< amrex::Real > &h_avg_w, amrex::Gpu::HostVector< amrex::Real > &h_avg_rho, amrex::Gpu::HostVector< amrex::Real > &h_avg_th, amrex::Gpu::HostVector< amrex::Real > &h_avg_ksgs, amrex::Gpu::HostVector< amrex::Real > &h_avg_Kmv, amrex::Gpu::HostVector< amrex::Real > &h_avg_Khv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qc, amrex::Gpu::HostVector< amrex::Real > &h_avg_qr, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqv, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqc, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqr, amrex::Gpu::HostVector< amrex::Real > &h_avg_qi, amrex::Gpu::HostVector< amrex::Real > &h_avg_qs, amrex::Gpu::HostVector< amrex::Real > &h_avg_qg, amrex::Gpu::HostVector< amrex::Real > &h_avg_uu, amrex::Gpu::HostVector< amrex::Real > &h_avg_uv, amrex::Gpu::HostVector< amrex::Real > &h_avg_uw, amrex::Gpu::HostVector< amrex::Real > &h_avg_vv, amrex::Gpu::HostVector< amrex::Real > &h_avg_vw, amrex::Gpu::HostVector< amrex::Real > &h_avg_ww, amrex::Gpu::HostVector< amrex::Real > &h_avg_uth, amrex::Gpu::HostVector< amrex::Real > &h_avg_vth, amrex::Gpu::HostVector< amrex::Real > &h_avg_wth, amrex::Gpu::HostVector< amrex::Real > &h_avg_thth, amrex::Gpu::HostVector< amrex::Real > &h_avg_ku, amrex::Gpu::HostVector< amrex::Real > &h_avg_kv, amrex::Gpu::HostVector< amrex::Real > &h_avg_kw, amrex::Gpu::HostVector< amrex::Real > &h_avg_p, amrex::Gpu::HostVector< amrex::Real > &h_avg_pu, amrex::Gpu::HostVector< amrex::Real > &h_avg_pv, amrex::Gpu::HostVector< amrex::Real > &h_avg_pw, amrex::Gpu::HostVector< amrex::Real > &h_avg_wthv)
 
void derive_diag_profiles_stag (amrex::Real time, amrex::Gpu::HostVector< amrex::Real > &h_avg_u, amrex::Gpu::HostVector< amrex::Real > &h_avg_v, amrex::Gpu::HostVector< amrex::Real > &h_avg_w, amrex::Gpu::HostVector< amrex::Real > &h_avg_rho, amrex::Gpu::HostVector< amrex::Real > &h_avg_th, amrex::Gpu::HostVector< amrex::Real > &h_avg_ksgs, amrex::Gpu::HostVector< amrex::Real > &h_avg_Kmv, amrex::Gpu::HostVector< amrex::Real > &h_avg_Khv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qv, amrex::Gpu::HostVector< amrex::Real > &h_avg_qc, amrex::Gpu::HostVector< amrex::Real > &h_avg_qr, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqv, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqc, amrex::Gpu::HostVector< amrex::Real > &h_avg_wqr, amrex::Gpu::HostVector< amrex::Real > &h_avg_qi, amrex::Gpu::HostVector< amrex::Real > &h_avg_qs, amrex::Gpu::HostVector< amrex::Real > &h_avg_qg, amrex::Gpu::HostVector< amrex::Real > &h_avg_uu, amrex::Gpu::HostVector< amrex::Real > &h_avg_uv, amrex::Gpu::HostVector< amrex::Real > &h_avg_uw, amrex::Gpu::HostVector< amrex::Real > &h_avg_vv, amrex::Gpu::HostVector< amrex::Real > &h_avg_vw, amrex::Gpu::HostVector< amrex::Real > &h_avg_ww, amrex::Gpu::HostVector< amrex::Real > &h_avg_uth, amrex::Gpu::HostVector< amrex::Real > &h_avg_vth, amrex::Gpu::HostVector< amrex::Real > &h_avg_wth, amrex::Gpu::HostVector< amrex::Real > &h_avg_thth, amrex::Gpu::HostVector< amrex::Real > &h_avg_ku, amrex::Gpu::HostVector< amrex::Real > &h_avg_kv, amrex::Gpu::HostVector< amrex::Real > &h_avg_kw, amrex::Gpu::HostVector< amrex::Real > &h_avg_p, amrex::Gpu::HostVector< amrex::Real > &h_avg_pu, amrex::Gpu::HostVector< amrex::Real > &h_avg_pv, amrex::Gpu::HostVector< amrex::Real > &h_avg_pw, amrex::Gpu::HostVector< amrex::Real > &h_avg_wthv)
 
void derive_stress_profiles (amrex::Gpu::HostVector< amrex::Real > &h_avg_tau11, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau12, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau13, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau22, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau23, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau33, amrex::Gpu::HostVector< amrex::Real > &h_avg_hfx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q1fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q2fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_diss)
 
void derive_stress_profiles_stag (amrex::Gpu::HostVector< amrex::Real > &h_avg_tau11, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau12, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau13, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau22, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau23, amrex::Gpu::HostVector< amrex::Real > &h_avg_tau33, amrex::Gpu::HostVector< amrex::Real > &h_avg_hfx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q1fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_q2fx3, amrex::Gpu::HostVector< amrex::Real > &h_avg_diss)
 
amrex::Real volWgtSumMF (int lev, const amrex::MultiFab &mf, int comp, const amrex::MultiFab &mapfac, bool local, bool finemask)
 
void MakeNewLevelFromCoarse (int lev, amrex::Real time, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm) override
 
void RemakeLevel (int lev, amrex::Real time, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm) override
 
void ClearLevel (int lev) override
 
void MakeNewLevelFromScratch (int lev, amrex::Real time, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm) override
 
amrex::Real estTimeStep (int lev, long &dt_fast_ratio) const
 
void advance_dycore (int level, amrex::Vector< amrex::MultiFab > &state_old, amrex::Vector< amrex::MultiFab > &state_new, amrex::MultiFab &xvel_old, amrex::MultiFab &yvel_old, amrex::MultiFab &zvel_old, amrex::MultiFab &xvel_new, amrex::MultiFab &yvel_new, amrex::MultiFab &zvel_new, amrex::MultiFab &source, amrex::MultiFab &xmom_src, amrex::MultiFab &ymom_src, amrex::MultiFab &zmom_src, amrex::Geometry fine_geom, amrex::Real dt, amrex::Real time)
 
void advance_microphysics (int lev, amrex::MultiFab &cons_in, const amrex::Real &dt_advance, const int &iteration, const amrex::Real &time)
 
void advance_lsm (int lev, amrex::MultiFab &, const amrex::Real &dt_advance)
 
amrex::MultiFab & build_fine_mask (int lev)
 
void MakeHorizontalAverages ()
 
void MakeDiagnosticAverage (amrex::Vector< amrex::Real > &h_havg, amrex::MultiFab &S, int n)
 
void derive_upwp (amrex::Vector< amrex::Real > &h_havg)
 
void WritePlotFile (int which, PlotFileType plotfile_type, amrex::Vector< std::string > plot_var_names)
 
void WriteMultiLevelPlotfileWithTerrain (const std::string &plotfilename, int nlevels, const amrex::Vector< const amrex::MultiFab * > &mf, const amrex::Vector< const amrex::MultiFab * > &mf_nd, const amrex::Vector< std::string > &varnames, const amrex::Vector< amrex::Geometry > &my_geom, amrex::Real time, const amrex::Vector< int > &level_steps, const amrex::Vector< amrex::IntVect > &my_ref_ratio, const std::string &versionName="HyperCLaw-V1.1", const std::string &levelPrefix="Level_", const std::string &mfPrefix="Cell", const amrex::Vector< std::string > &extra_dirs=amrex::Vector< std::string >()) const
 
void WriteGenericPlotfileHeaderWithTerrain (std::ostream &HeaderFile, int nlevels, const amrex::Vector< amrex::BoxArray > &bArray, const amrex::Vector< std::string > &varnames, const amrex::Vector< amrex::Geometry > &my_geom, amrex::Real time, const amrex::Vector< int > &level_steps, const amrex::Vector< amrex::IntVect > &my_ref_ratio, const std::string &versionName, const std::string &levelPrefix, const std::string &mfPrefix) const
 
void erf_enforce_hse (int lev, amrex::MultiFab &dens, amrex::MultiFab &pres, amrex::MultiFab &pi, amrex::MultiFab &th, std::unique_ptr< amrex::MultiFab > &z_cc)
 
void init_from_input_sounding (int lev)
 
void input_sponge (int lev)
 
void init_from_hse (int lev)
 
void init_thin_body (int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm)
 
void fill_from_bndryregs (const amrex::Vector< amrex::MultiFab * > &mfs, amrex::Real time)
 
void MakeEBGeometry ()
 
void make_eb_box ()
 
void make_eb_regular ()
 
void redistribute_term (int lev, int ncomp, amrex::MultiFab &result, amrex::MultiFab &result_tmp, amrex::MultiFab const &state, amrex::BCRec const *bc, amrex::Real const dt)
 
void redistribute_term (amrex::MFIter const &mfi, int lev, int ncomp, amrex::MultiFab &result, amrex::MultiFab &result_tmp, amrex::MultiFab const &state, amrex::BCRec const *bc, amrex::Real const dt)
 
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 int NumDataLogs () noexcept
 
AMREX_FORCE_INLINE std::ostream & SamplePointLog (int i)
 
AMREX_FORCE_INLINE int NumSamplePointLogs () noexcept
 
AMREX_FORCE_INLINE std::ostream & SampleLineLog (int i)
 
AMREX_FORCE_INLINE int NumSampleLineLogs () noexcept
 
amrex::IntVect & SamplePoint (int i)
 
AMREX_FORCE_INLINE int NumSamplePoints () noexcept
 
amrex::IntVect & SampleLine (int i)
 
AMREX_FORCE_INLINE int NumSampleLines () noexcept
 
void setRecordDataInfo (int i, const std::string &filename)
 
void setRecordSamplePointInfo (int i, int lev, amrex::IntVect &cell, const std::string &filename)
 
void setRecordSampleLineInfo (int i, int lev, amrex::IntVect &cell, const std::string &filename)
 
std::string DataLogName (int i) const noexcept
 The filename of the ith datalog file. More...
 
std::string SamplePointLogName (int i) const noexcept
 The filename of the ith sampleptlog file. More...
 
std::string SampleLineLogName (int i) const noexcept
 The filename of the ith samplelinelog file. More...
 
amrex::FabFactory< amrex::FArrayBox > const & Factory (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

InputSoundingData input_sounding_data
 
InputSpongeData input_sponge_data
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > xvel_bc_data
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > yvel_bc_data
 
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > zvel_bc_data
 
std::unique_ptr< ProblemBaseprob = nullptr
 
amrex::Vector< int > num_boxes_at_level
 
amrex::Vector< int > num_files_at_level
 
amrex::Vector< amrex::Vector< amrex::Box > > boxes_at_level
 
amrex::Vector< int > istep
 
amrex::Vector< int > nsubsteps
 
amrex::Vector< amrex::Real > t_new
 
amrex::Vector< amrex::Real > t_old
 
amrex::Vector< amrex::Real > dt
 
amrex::Vector< long > dt_mri_ratio
 
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_new
 
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_old
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vel_t_avg
 
amrex::Vector< amrex::Real > t_avg_cnt
 
amrex::Vector< std::unique_ptr< MRISplitIntegrator< amrex::Vector< amrex::MultiFab > > > > mri_integrator_mem
 
amrex::Vector< amrex::MultiFab > pp_inc
 
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_cons > > physbcs_cons
 
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_u > > physbcs_u
 
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_v > > physbcs_v
 
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_w > > physbcs_w
 
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_base > > physbcs_base
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Theta_prim
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qv_prim
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qr_prim
 
amrex::Vector< amrex::MultiFab > rU_old
 
amrex::Vector< amrex::MultiFab > rU_new
 
amrex::Vector< amrex::MultiFab > rV_old
 
amrex::Vector< amrex::MultiFab > rV_new
 
amrex::Vector< amrex::MultiFab > rW_old
 
amrex::Vector< amrex::MultiFab > rW_new
 
amrex::Vector< amrex::MultiFab > zmom_crse_rhs
 
std::unique_ptr< Microphysicsmicro
 
amrex::Vector< amrex::Vector< amrex::MultiFab * > > qmoist
 
LandSurface lsm
 
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_data
 
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_flux
 
int cf_width {0}
 
int cf_set_width {0}
 
amrex::Vector< ERFFillPatcherFPr_c
 
amrex::Vector< ERFFillPatcherFPr_u
 
amrex::Vector< ERFFillPatcherFPr_v
 
amrex::Vector< ERFFillPatcherFPr_w
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau11_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau22_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau33_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau12_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau21_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau13_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau31_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau23_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau32_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > eddyDiffs_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SmnSmn_lev
 
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > sst_lev
 
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab > > > lmask_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx1_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx2_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx3_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_diss_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx1_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx2_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx3_lev
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q2fx3_lev
 
amrex::Vector< amrex::Vector< amrex::Real > > zlevels_stag
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_cc
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd_src
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc_src
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax_src
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay_src
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az_src
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd_new
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc_new
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax_new
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay_new
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az_new
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_t_rk
 
amrex::Vector< std::unique_ptr< amrex::MultiFab > > 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_check_file_step
 
int plot_file_on_restart = 1
 
int max_step = std::numeric_limits<int>::max()
 
amrex::Real start_time = 0.0
 
amrex::Real stop_time = std::numeric_limits<amrex::Real>::max()
 
std::string restart_chkfile = ""
 
amrex::Vector< amrex::Real > fixed_dt
 
amrex::Vector< amrex::Real > fixed_fast_dt
 
int regrid_int = -1
 
std::string plot_file_1 {"plt_1_"}
 
std::string plot_file_2 {"plt_2_"}
 
bool m_expand_plotvars_to_unif_rr = false
 
int m_plot_int_1 = -1
 
int m_plot_int_2 = -1
 
amrex::Real m_plot_per_1 = -1.0
 
amrex::Real m_plot_per_2 = -1.0
 
bool m_plot_face_vels = false
 
bool plot_lsm = false
 
int profile_int = -1
 
bool destag_profiles = true
 
std::string check_file {"chk"}
 
std::string check_type {"native"}
 
std::string restart_type {"native"}
 
int m_check_int = -1
 
amrex::Real m_check_per = -1.0
 
amrex::Vector< std::string > plot_var_names_1
 
amrex::Vector< std::string > plot_var_names_2
 
const amrex::Vector< std::string > cons_names
 
const amrex::Vector< std::string > derived_names
 
TurbulentPerturbation turbPert
 
int real_width {0}
 
int real_set_width {0}
 
bool metgrid_debug_quiescent {false}
 
bool metgrid_debug_isothermal {false}
 
bool metgrid_debug_dry {false}
 
bool metgrid_debug_psfc {false}
 
bool metgrid_debug_msf {false}
 
bool metgrid_interp_theta {false}
 
bool metgrid_basic_linear {false}
 
bool metgrid_use_below_sfc {true}
 
bool metgrid_use_sfc {true}
 
bool metgrid_retain_sfc {false}
 
amrex::Real metgrid_proximity {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::string > datalogname
 
amrex::Vector< std::unique_ptr< std::fstream > > sampleptlog
 
amrex::Vector< std::string > sampleptlogname
 
amrex::Vector< amrex::IntVect > samplepoint
 
amrex::Vector< std::unique_ptr< std::fstream > > samplelinelog
 
amrex::Vector< std::string > samplelinelogname
 
amrex::Vector< amrex::IntVect > sampleline
 
amrex::Vector< std::unique_ptr< amrex::FabFactory< amrex::FArrayBox > > > m_factory
 

Static Private Attributes

static amrex::Real cfl = 0.8
 
static amrex::Real sub_cfl = 1.0
 
static amrex::Real init_shrink = 1.0
 
static amrex::Real change_max = 1.1
 
static amrex::Real dt_max_initial = 1.0
 
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 InitType init_type
 
static StateInterpType interpolation_type
 
static std::string sponge_type
 
static bool use_real_bcs
 
static amrex::Vector< amrex::Vector< std::string > > nc_init_file = {{""}}
 
static std::string nc_bdy_file
 
static bool init_sounding_ideal = false
 
static int output_1d_column = 0
 
static int column_interval = -1
 
static amrex::Real column_per = -1.0
 
static amrex::Real column_loc_x = 0.0
 
static amrex::Real column_loc_y = 0.0
 
static std::string column_file_name = "column_data.nc"
 
static int output_bndry_planes = 0
 
static int bndry_output_planes_interval = -1
 
static amrex::Real bndry_output_planes_per = -1.0
 
static amrex::Real bndry_output_planes_start_time = 0.0
 
static int input_bndry_planes = 0
 
static int ng_dens_hse
 
static int ng_pres_hse
 
static amrex::Vector< amrex::AMRErrorTag > ref_tags
 
static amrex::Real startCPUTime = 0.0
 
static amrex::Real previousCPUTimeUsed = 0.0
 

Detailed Description

Main class in ERF code, instantiated from main.cpp

Constructor & Destructor Documentation

◆ ERF() [1/3]

ERF::ERF ( )
90 {
91  int fix_random_seed = 0;
92  ParmParse pp("erf"); pp.query("fix_random_seed", fix_random_seed);
93  // Note that the value of 1024UL is not significant -- the point here is just to set the
94  // same seed for all MPI processes for the purpose of regression testing
95  if (fix_random_seed) {
96  Print() << "Fixing the random seed" << std::endl;
97  InitRandom(1024UL);
98  }
99 
100  ERF_shared();
101 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real pp(amrex::Real y)
Definition: ERF_MicrophysicsUtils.H:219
void ERF_shared()
Definition: ERF.cpp:104
Here is the call graph for this function:

◆ ~ERF()

ERF::~ERF ( )
overridedefault

◆ ERF() [2/3]

ERF::ERF ( ERF &&  )
deletenoexcept

◆ ERF() [3/3]

ERF::ERF ( const ERF other)
delete

Member Function Documentation

◆ Advance()

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

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

Parameters
[in]levlevel of refinement (coarsest level is 0)
[in]timestart time for time advance
[in]dt_levtime step for this time advance
21 {
22  BL_PROFILE("ERF::Advance()");
23 
24  // We must swap the pointers so the previous step's "new" is now this step's "old"
25  std::swap(vars_old[lev], vars_new[lev]);
26 
27  MultiFab& S_old = vars_old[lev][Vars::cons];
28  MultiFab& S_new = vars_new[lev][Vars::cons];
29 
30  MultiFab& U_old = vars_old[lev][Vars::xvel];
31  MultiFab& V_old = vars_old[lev][Vars::yvel];
32  MultiFab& W_old = vars_old[lev][Vars::zvel];
33 
34  MultiFab& U_new = vars_new[lev][Vars::xvel];
35  MultiFab& V_new = vars_new[lev][Vars::yvel];
36  MultiFab& W_new = vars_new[lev][Vars::zvel];
37 
38  // We need to set these because otherwise in the first call to erf_advance we may
39  // read uninitialized data on ghost values in setting the bc's on the velocities
40  U_new.setVal(1.e34,U_new.nGrowVect());
41  V_new.setVal(1.e34,V_new.nGrowVect());
42  W_new.setVal(1.e34,W_new.nGrowVect());
43 
44  //
45  // NOTE: the momenta here are not fillpatched (they are only used as scratch space)
46  // If lev == 0 we have already FillPatched this in ERF::TimeStep
47  //
48 // if (lev == 0) {
49 // FillPatch(lev, time, {&S_old, &U_old, &V_old, &W_old});
50 // } else {
51  if (lev > 0) {
52  FillPatch(lev, time, {&S_old, &U_old, &V_old, &W_old},
53  {&S_old, &rU_old[lev], &rV_old[lev], &rW_old[lev]},
54  base_state[lev], base_state[lev]);
55  }
56 
57  //
58  // So we must convert the fillpatched to momenta, including the ghost values
59  //
60  VelocityToMomentum(U_old, rU_old[lev].nGrowVect(),
61  V_old, rV_old[lev].nGrowVect(),
62  W_old, rW_old[lev].nGrowVect(),
63  S_old, rU_old[lev], rV_old[lev], rW_old[lev],
64  Geom(lev).Domain(),
66 
67  // TODO: Can test on multiple levels later
68  // Update the inflow perturbation update time and amplitude
69  if (lev == 0) {
70  if (solverChoice.pert_type == PerturbationType::Source ||
71  solverChoice.pert_type == PerturbationType::Direct)
72  {
73  turbPert.calc_tpi_update(lev, dt_lev, U_old, V_old, S_old);
74  }
75 
76  // If PerturbationType::Direct is selected, directly add the computed perturbation
77  // on the conserved field
78  if (solverChoice.pert_type == PerturbationType::Direct)
79  {
80  auto m_ixtype = S_old.boxArray().ixType(); // Conserved term
81  for (MFIter mfi(S_old,TileNoZ()); mfi.isValid(); ++mfi) {
82  Box bx = mfi.tilebox();
83  const Array4<Real> &cell_data = S_old.array(mfi);
84  const Array4<const Real> &pert_cell = turbPert.pb_cell.array(mfi);
85  turbPert.apply_tpi(lev, bx, RhoTheta_comp, m_ixtype, cell_data, pert_cell);
86  }
87  }
88  }
89 
90  // configure ABLMost params if used MostWall boundary condition
91  if (phys_bc_type[Orientation(Direction::z,Orientation::low)] == ERF_BC::MOST) {
92  if (m_most) {
93  IntVect ng = Theta_prim[lev]->nGrowVect();
94  MultiFab::Copy( *Theta_prim[lev], S_old, RhoTheta_comp, 0, 1, ng);
95  MultiFab::Divide(*Theta_prim[lev], S_old, Rho_comp , 0, 1, ng);
96  if (solverChoice.moisture_type != MoistureType::None) {
97  ng = Qv_prim[lev]->nGrowVect();
98 
99  MultiFab::Copy( *Qv_prim[lev], S_old, RhoQ1_comp, 0, 1, ng);
100  MultiFab::Divide(*Qv_prim[lev], S_old, Rho_comp , 0, 1, ng);
101 
102  if (solverChoice.RhoQr_comp > -1) {
103  MultiFab::Copy( *Qr_prim[lev], S_old, solverChoice.RhoQr_comp, 0, 1, ng);
104  MultiFab::Divide(*Qr_prim[lev], S_old, Rho_comp , 0, 1, ng);
105  } else {
106  Qr_prim[lev]->setVal(0.0);
107  }
108  }
109  // NOTE: std::swap above causes the field ptrs to be out of date.
110  // Reassign the field ptrs for MAC avg computation.
111  m_most->update_mac_ptrs(lev, vars_old, Theta_prim, Qv_prim, Qr_prim);
112  m_most->update_pblh(lev, vars_old, z_phys_cc[lev].get(),
116  m_most->update_fluxes(lev, time);
117  }
118  }
119 
120 #if defined(ERF_USE_WINDFARM)
121  if (solverChoice.windfarm_type != WindFarmType::None) {
122  advance_windfarm(Geom(lev), dt_lev, S_old,
123  U_old, V_old, W_old, vars_windfarm[lev], Nturb[lev], SMark[lev], time);
124  }
125 
126 #endif
127 
128  const BoxArray& ba = S_old.boxArray();
129  const DistributionMapping& dm = S_old.DistributionMap();
130 
131  int nvars = S_old.nComp();
132 
133  // Source array for conserved cell-centered quantities -- this will be filled
134  // in the call to make_sources in ERF_TI_slow_rhs_fun.H
135  MultiFab cc_source(ba,dm,nvars,1); cc_source.setVal(0.0);
136 
137  // Source arrays for momenta -- these will be filled
138  // in the call to make_mom_sources in ERF_TI_slow_rhs_fun.H
139  BoxArray ba_x(ba); ba_x.surroundingNodes(0);
140  MultiFab xmom_source(ba_x,dm,nvars,1); xmom_source.setVal(0.0);
141 
142  BoxArray ba_y(ba); ba_y.surroundingNodes(1);
143  MultiFab ymom_source(ba_y,dm,nvars,1); ymom_source.setVal(0.0);
144 
145  BoxArray ba_z(ba); ba_z.surroundingNodes(2);
146  MultiFab zmom_source(ba_z,dm,nvars,1); zmom_source.setVal(0.0);
147 
148  // We don't need to call FillPatch on cons_mf because we have fillpatch'ed S_old above
149  MultiFab cons_mf(ba,dm,nvars,S_old.nGrowVect());
150  MultiFab::Copy(cons_mf,S_old,0,0,S_old.nComp(),S_old.nGrowVect());
151 
152  amrex::Vector<MultiFab> state_old;
153  amrex::Vector<MultiFab> state_new;
154 
155  // **************************************************************************************
156  // Here we define state_old and state_new which are to be advanced
157  // **************************************************************************************
158  // Initial solution
159  // Note that "old" and "new" here are relative to each RK stage.
160  state_old.push_back(MultiFab(cons_mf , amrex::make_alias, 0, nvars)); // cons
161  state_old.push_back(MultiFab(rU_old[lev], amrex::make_alias, 0, 1)); // xmom
162  state_old.push_back(MultiFab(rV_old[lev], amrex::make_alias, 0, 1)); // ymom
163  state_old.push_back(MultiFab(rW_old[lev], amrex::make_alias, 0, 1)); // zmom
164 
165  // Final solution
166  // state_new at the end of the last RK stage holds the t^{n+1} data
167  state_new.push_back(MultiFab(S_new , amrex::make_alias, 0, nvars)); // cons
168  state_new.push_back(MultiFab(rU_new[lev], amrex::make_alias, 0, 1)); // xmom
169  state_new.push_back(MultiFab(rV_new[lev], amrex::make_alias, 0, 1)); // ymom
170  state_new.push_back(MultiFab(rW_new[lev], amrex::make_alias, 0, 1)); // zmom
171 
172  // **************************************************************************************
173  // Update the dycore
174  // **************************************************************************************
175  advance_dycore(lev, state_old, state_new,
176  U_old, V_old, W_old,
177  U_new, V_new, W_new,
178  cc_source, xmom_source, ymom_source, zmom_source,
179  Geom(lev), dt_lev, time);
180 
181  // **************************************************************************************
182  // Update the microphysics (moisture)
183  // **************************************************************************************
184  advance_microphysics(lev, S_new, dt_lev, iteration, time);
185 
186  // **************************************************************************************
187  // Update the land surface model
188  // **************************************************************************************
189  advance_lsm(lev, S_new, dt_lev);
190 
191 #if defined(ERF_USE_RRTMGP)
192  // **************************************************************************************
193  // Update the radiation
194  // **************************************************************************************
195  advance_radiation(lev, S_new, dt_lev);
196 #endif
197 
198 #ifdef ERF_USE_PARTICLES
199  // **************************************************************************************
200  // Update the particle positions
201  // **************************************************************************************
202  evolveTracers( lev, dt_lev, vars_new, z_phys_nd );
203 #endif
204 
205  // ***********************************************************************************************
206  // Impose domain boundary conditions here so that in FillPatching the fine data we won't
207  // need to re-fill these
208  // ***********************************************************************************************
209  if (lev < finest_level) {
210  IntVect ngvect_vels = vars_new[lev][Vars::xvel].nGrowVect();
211  (*physbcs_cons[lev])(vars_new[lev][Vars::cons],0,vars_new[lev][Vars::cons].nComp(),
212  vars_new[lev][Vars::cons].nGrowVect(),time,BCVars::cons_bc,true);
213  (*physbcs_u[lev])(vars_new[lev][Vars::xvel],0,1,ngvect_vels,time,BCVars::xvel_bc,true);
214  (*physbcs_v[lev])(vars_new[lev][Vars::yvel],0,1,ngvect_vels,time,BCVars::yvel_bc,true);
215  (*physbcs_w[lev])(vars_new[lev][Vars::zvel], vars_new[lev][Vars::xvel], vars_new[lev][Vars::yvel],
216  ngvect_vels,time,BCVars::zvel_bc,true);
217  }
218 
219  // **************************************************************************************
220  // Register old and new coarse data if we are at a level less than the finest level
221  // **************************************************************************************
222  if (lev < finest_level)
223  {
224  if (cf_width > 0) {
225  // We must fill the ghost cells of these so that the parallel copy works correctly
226  state_old[IntVars::cons].FillBoundary(geom[lev].periodicity());
227  state_new[IntVars::cons].FillBoundary(geom[lev].periodicity());
228  FPr_c[lev].RegisterCoarseData({&state_old[IntVars::cons], &state_new[IntVars::cons]},
229  {time, time + dt_lev});
230  }
231 
232  if (cf_width >= 0) {
233  // We must fill the ghost cells of these so that the parallel copy works correctly
234  state_old[IntVars::xmom].FillBoundary(geom[lev].periodicity());
235  state_new[IntVars::xmom].FillBoundary(geom[lev].periodicity());
236  FPr_u[lev].RegisterCoarseData({&state_old[IntVars::xmom], &state_new[IntVars::xmom]},
237  {time, time + dt_lev});
238 
239  state_old[IntVars::ymom].FillBoundary(geom[lev].periodicity());
240  state_new[IntVars::ymom].FillBoundary(geom[lev].periodicity());
241  FPr_v[lev].RegisterCoarseData({&state_old[IntVars::ymom], &state_new[IntVars::ymom]},
242  {time, time + dt_lev});
243 
244  state_old[IntVars::zmom].FillBoundary(geom[lev].periodicity());
245  state_new[IntVars::zmom].FillBoundary(geom[lev].periodicity());
246  FPr_w[lev].RegisterCoarseData({&state_old[IntVars::zmom], &state_new[IntVars::zmom]},
247  {time, time + dt_lev});
248  }
249 
250  //
251  // Now create a MultiFab that holds (S_new - S_old) / dt from the coarse level interpolated
252  // on to the coarse/fine boundary at the fine resolution
253  //
254  Interpolater* mapper_f = &face_cons_linear_interp;
255 
256  // PhysBCFunctNoOp null_bc;
257  // MultiFab tempx(vars_new[lev+1][Vars::xvel].boxArray(),vars_new[lev+1][Vars::xvel].DistributionMap(),1,0);
258  // tempx.setVal(0.0);
259  // xmom_crse_rhs[lev+1].setVal(0.0);
260  // FPr_u[lev].FillSet(tempx , time , null_bc, domain_bcs_type);
261  // FPr_u[lev].FillSet(xmom_crse_rhs[lev+1], time+dt_lev, null_bc, domain_bcs_type);
262  // MultiFab::Subtract(xmom_crse_rhs[lev+1],tempx,0,0,1,IntVect{0});
263  // xmom_crse_rhs[lev+1].mult(1.0/dt_lev,0,1,0);
264 
265  // MultiFab tempy(vars_new[lev+1][Vars::yvel].boxArray(),vars_new[lev+1][Vars::yvel].DistributionMap(),1,0);
266  // tempy.setVal(0.0);
267  // ymom_crse_rhs[lev+1].setVal(0.0);
268  // FPr_v[lev].FillSet(tempy , time , null_bc, domain_bcs_type);
269  // FPr_v[lev].FillSet(ymom_crse_rhs[lev+1], time+dt_lev, null_bc, domain_bcs_type);
270  // MultiFab::Subtract(ymom_crse_rhs[lev+1],tempy,0,0,1,IntVect{0});
271  // ymom_crse_rhs[lev+1].mult(1.0/dt_lev,0,1,0);
272 
273  MultiFab temp_state(zmom_crse_rhs[lev+1].boxArray(),zmom_crse_rhs[lev+1].DistributionMap(),1,0);
274  InterpFromCoarseLevel(temp_state, IntVect{0}, IntVect{0}, state_old[IntVars::zmom], 0, 0, 1,
275  geom[lev], geom[lev+1], refRatio(lev), mapper_f, domain_bcs_type, BCVars::zvel_bc);
276  InterpFromCoarseLevel(zmom_crse_rhs[lev+1], IntVect{0}, IntVect{0}, state_new[IntVars::zmom], 0, 0, 1,
277  geom[lev], geom[lev+1], refRatio(lev), mapper_f, domain_bcs_type, BCVars::zvel_bc);
278  MultiFab::Subtract(zmom_crse_rhs[lev+1],temp_state,0,0,1,IntVect{0});
279  zmom_crse_rhs[lev+1].mult(1.0/dt_lev,0,1,0);
280  }
281 
282  // ***********************************************************************************************
283  // Update the time averaged velocities if they are requested
284  // ***********************************************************************************************
286  Time_Avg_Vel_atCC(dt[lev], t_avg_cnt[lev], vel_t_avg[lev].get(), U_new, V_new, W_new);
287  }
288 }
@ nvars
Definition: ERF_DataStruct.H:70
#define Rho_comp
Definition: ERF_IndexDefines.H:36
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:37
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:42
AMREX_FORCE_INLINE amrex::IntVect TileNoZ()
Definition: ERF_TileNoZ.H:11
void Time_Avg_Vel_atCC(const Real &dt, Real &t_avg_cnt, MultiFab *vel_t_avg, MultiFab &xvel, MultiFab &yvel, MultiFab &zvel)
Definition: ERF_TimeAvgVel.cpp:9
void VelocityToMomentum(const amrex::MultiFab &xvel_in, const amrex::IntVect &xvel_ngrow, const amrex::MultiFab &yvel_in, const amrex::IntVect &yvel_ngrow, const amrex::MultiFab &zvel_in, const amrex::IntVect &zvel_ngrow, const amrex::MultiFab &cons_in, amrex::MultiFab &xmom_out, amrex::MultiFab &ymom_out, amrex::MultiFab &zmom_out, const amrex::Box &domain, const amrex::Vector< amrex::BCRec > &domain_bcs_type_h)
amrex::Vector< amrex::MultiFab > rU_new
Definition: ERF.H:760
std::unique_ptr< ABLMost > m_most
Definition: ERF.H:1169
amrex::Vector< ERFFillPatcher > FPr_u
Definition: ERF.H:805
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_new
Definition: ERF.H:735
amrex::Vector< ERFFillPatcher > FPr_v
Definition: ERF.H:806
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_cons > > physbcs_cons
Definition: ERF.H:747
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_cc
Definition: ERF.H:832
static SolverChoice solverChoice
Definition: ERF.H:1011
amrex::Vector< ERFFillPatcher > FPr_c
Definition: ERF.H:804
amrex::Vector< std::unique_ptr< amrex::MultiFab > > vel_t_avg
Definition: ERF.H:739
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_w > > physbcs_w
Definition: ERF.H:750
amrex::Vector< amrex::MultiFab > base_state
Definition: ERF.H:867
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qv_prim
Definition: ERF.H:755
amrex::Vector< amrex::MultiFab > rV_new
Definition: ERF.H:762
amrex::Vector< amrex::BCRec > domain_bcs_type
Definition: ERF.H:883
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Qr_prim
Definition: ERF.H:756
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_u > > physbcs_u
Definition: ERF.H:748
amrex::Vector< amrex::Real > t_avg_cnt
Definition: ERF.H:740
amrex::Vector< amrex::MultiFab > rU_old
Definition: ERF.H:759
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Theta_prim
Definition: ERF.H:754
amrex::Vector< std::unique_ptr< ERFPhysBCFunct_v > > physbcs_v
Definition: ERF.H:749
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd
Definition: ERF.H:831
amrex::Vector< amrex::MultiFab > rW_new
Definition: ERF.H:764
amrex::Vector< amrex::MultiFab > zmom_crse_rhs
Definition: ERF.H:768
TurbulentPerturbation turbPert
Definition: ERF.H:1014
amrex::Vector< amrex::MultiFab > rW_old
Definition: ERF.H:763
void advance_lsm(int lev, amrex::MultiFab &, const amrex::Real &dt_advance)
Definition: ERF_AdvanceLSM.cpp:5
amrex::Vector< ERFFillPatcher > FPr_w
Definition: ERF.H:807
amrex::Vector< amrex::Real > dt
Definition: ERF.H:729
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:802
amrex::GpuArray< ERF_BC, AMREX_SPACEDIM *2 > phys_bc_type
Definition: ERF.H:896
amrex::Vector< amrex::MultiFab > rV_old
Definition: ERF.H:761
amrex::Vector< amrex::Vector< amrex::MultiFab > > vars_old
Definition: ERF.H:736
void advance_dycore(int level, amrex::Vector< amrex::MultiFab > &state_old, amrex::Vector< amrex::MultiFab > &state_new, amrex::MultiFab &xvel_old, amrex::MultiFab &yvel_old, amrex::MultiFab &zvel_old, amrex::MultiFab &xvel_new, amrex::MultiFab &yvel_new, amrex::MultiFab &zvel_new, amrex::MultiFab &source, amrex::MultiFab &xmom_src, amrex::MultiFab &ymom_src, amrex::MultiFab &zmom_src, amrex::Geometry fine_geom, amrex::Real dt, amrex::Real time)
Definition: ERF_AdvanceDycore.cpp:37
void FillPatch(int lev, amrex::Real time, const amrex::Vector< amrex::MultiFab * > &mfs_vel, bool cons_only=false)
@ zvel_bc
Definition: ERF_IndexDefines.H:90
@ yvel_bc
Definition: ERF_IndexDefines.H:89
@ cons_bc
Definition: ERF_IndexDefines.H:76
@ xvel_bc
Definition: ERF_IndexDefines.H:88
@ ymom
Definition: ERF_IndexDefines.H:141
@ cons
Definition: ERF_IndexDefines.H:139
@ zmom
Definition: ERF_IndexDefines.H:142
@ xmom
Definition: ERF_IndexDefines.H:140
@ xvel
Definition: ERF_IndexDefines.H:130
@ cons
Definition: ERF_IndexDefines.H:129
@ zvel
Definition: ERF_IndexDefines.H:132
@ yvel
Definition: ERF_IndexDefines.H:131
int RhoQr_comp
Definition: ERF_DataStruct.H:700
int RhoQc_comp
Definition: ERF_DataStruct.H:694
int RhoQv_comp
Definition: ERF_DataStruct.H:693
MoistureType moisture_type
Definition: ERF_DataStruct.H:677
PerturbationType pert_type
Definition: ERF_DataStruct.H:667
WindFarmType windfarm_type
Definition: ERF_DataStruct.H:678
bool time_avg_vel
Definition: ERF_DataStruct.H:664
void calc_tpi_update(const int lev, const amrex::Real dt, amrex::MultiFab &mf_xvel, amrex::MultiFab &mf_yvel, amrex::MultiFab &mf_cons)
Definition: ERF_TurbPertStruct.H:184
amrex::MultiFab pb_cell
Definition: ERF_TurbPertStruct.H:536
void apply_tpi(const int &lev, const amrex::Box &vbx, const int &comp, const amrex::IndexType &m_ixtype, const amrex::Array4< amrex::Real > &src_arr, const amrex::Array4< amrex::Real const > &pert_cell)
Definition: ERF_TurbPertStruct.H:245
Here is the call graph for this function:

◆ advance_dycore()

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

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

Parameters
[in]levellevel of refinement (coarsest level is 0)
[in]state_oldold-time conserved variables
[in]state_newnew-time conserved variables
[in]xvel_oldold-time x-component of velocity
[in]yvel_oldold-time y-component of velocity
[in]zvel_oldold-time z-component of velocity
[in]xvel_newnew-time x-component of velocity
[in]yvel_newnew-time y-component of velocity
[in]zvel_newnew-time z-component of velocity
[in]cc_srcsource term for conserved variables
[in]xmom_srcsource term for x-momenta
[in]ymom_srcsource term for y-momenta
[in]zmom_srcsource term for z-momenta
[in]fine_geomcontainer for geometry information at current level
[in]dt_advancetime step for this time advance
[in]old_timeold time for this time advance
46 {
47  BL_PROFILE_VAR("erf_advance_dycore()",erf_advance_dycore);
48 
49  const Box& domain = fine_geom.Domain();
50 
54 
55  MultiFab r_hse (base_state[level], make_alias, BaseState::r0_comp , 1);
56  MultiFab p_hse (base_state[level], make_alias, BaseState::p0_comp , 1);
57  MultiFab pi_hse(base_state[level], make_alias, BaseState::pi0_comp, 1);
58 
59  // These pointers are used in the MRI utility functions
60  MultiFab* r0 = &r_hse;
61  MultiFab* p0 = &p_hse;
62  MultiFab* pi0 = &pi_hse;
63 
64  Real* dptr_rhotheta_src = solverChoice.custom_rhotheta_forcing ? d_rhotheta_src[level].data() : nullptr;
65  Real* dptr_rhoqt_src = solverChoice.custom_moisture_forcing ? d_rhoqt_src[level].data() : nullptr;
66  Real* dptr_wbar_sub = solverChoice.custom_w_subsidence ? d_w_subsid[level].data() : nullptr;
67 
68  // Turbulent Perturbation Pointer
69  //Real* dptr_rhotheta_src = solverChoice.pert_type ? d_rhotheta_src[level].data() : nullptr;
70 
71  Vector<Real*> d_rayleigh_ptrs_at_lev;
72  d_rayleigh_ptrs_at_lev.resize(Rayleigh::nvars);
73  d_rayleigh_ptrs_at_lev[Rayleigh::ubar] = solverChoice.rayleigh_damp_U ? d_rayleigh_ptrs[level][Rayleigh::ubar].data() : nullptr;
74  d_rayleigh_ptrs_at_lev[Rayleigh::vbar] = solverChoice.rayleigh_damp_V ? d_rayleigh_ptrs[level][Rayleigh::vbar].data() : nullptr;
75  d_rayleigh_ptrs_at_lev[Rayleigh::wbar] = solverChoice.rayleigh_damp_W ? d_rayleigh_ptrs[level][Rayleigh::wbar].data() : nullptr;
76  d_rayleigh_ptrs_at_lev[Rayleigh::thetabar] = solverChoice.rayleigh_damp_T ? d_rayleigh_ptrs[level][Rayleigh::thetabar].data() : nullptr;
77 
78  Vector<Real*> d_sponge_ptrs_at_lev;
79  if(sc.sponge_type=="input_sponge")
80  {
81  d_sponge_ptrs_at_lev.resize(Sponge::nvars_sponge);
82  d_sponge_ptrs_at_lev[Sponge::ubar_sponge] = d_sponge_ptrs[level][Sponge::ubar_sponge].data();
83  d_sponge_ptrs_at_lev[Sponge::vbar_sponge] = d_sponge_ptrs[level][Sponge::vbar_sponge].data();
84  }
85 
86  bool l_use_terrain_fitted_coords = (z_phys_nd[level] != nullptr);
87  bool l_use_kturb = ( (tc.les_type != LESType::None) ||
88  (tc.rans_type != RANSType::None) ||
89  (tc.pbl_type != PBLType::None) );
90  bool l_use_diff = ( (dc.molec_diff_type != MolecDiffType::None) ||
91  l_use_kturb );
92  bool l_use_moisture = ( solverChoice.moisture_type != MoistureType::None );
93  bool l_implicit_substepping = ( solverChoice.substepping_type[level] == SubsteppingType::Implicit );
94 
95  const bool use_most = (m_most != nullptr);
96  const bool exp_most = (solverChoice.use_explicit_most);
97  const FArrayBox* z_0 = (use_most) ? m_most->get_z0(level) : nullptr;
98 
99  const BoxArray& ba = state_old[IntVars::cons].boxArray();
100  const BoxArray& ba_z = zvel_old.boxArray();
101  const DistributionMapping& dm = state_old[IntVars::cons].DistributionMap();
102 
103  int num_prim = state_old[IntVars::cons].nComp() - 1;
104 
105  MultiFab S_prim (ba , dm, num_prim, state_old[IntVars::cons].nGrowVect());
106  MultiFab pi_stage (ba , dm, 1, state_old[IntVars::cons].nGrowVect());
107  MultiFab fast_coeffs(ba_z, dm, 5, 0);
108  MultiFab* eddyDiffs = eddyDiffs_lev[level].get();
109  MultiFab* SmnSmn = SmnSmn_lev[level].get();
110 
111  // **************************************************************************************
112  // Compute strain for use in slow RHS, Smagorinsky model, and MOST
113  // **************************************************************************************
114  {
115  BL_PROFILE("erf_advance_strain");
116  if (l_use_diff) {
117 
118  const BCRec* bc_ptr_h = domain_bcs_type.data();
119  const GpuArray<Real, AMREX_SPACEDIM> dxInv = fine_geom.InvCellSizeArray();
120 
121 #ifdef _OPENMP
122 #pragma omp parallel if (Gpu::notInLaunchRegion())
123 #endif
124  for ( MFIter mfi(state_new[IntVars::cons],TileNoZ()); mfi.isValid(); ++mfi)
125  {
126  Box bxcc = mfi.growntilebox(IntVect(1,1,0));
127  Box tbxxy = mfi.tilebox(IntVect(1,1,0),IntVect(1,1,0));
128  Box tbxxz = mfi.tilebox(IntVect(1,0,1),IntVect(1,1,0));
129  Box tbxyz = mfi.tilebox(IntVect(0,1,1),IntVect(1,1,0));
130 
131  if (bxcc.smallEnd(2) != domain.smallEnd(2)) {
132  bxcc.growLo(2,1);
133  tbxxy.growLo(2,1);
134  tbxxz.growLo(2,1);
135  tbxyz.growLo(2,1);
136  }
137 
138  if (bxcc.bigEnd(2) != domain.bigEnd(2)) {
139  bxcc.growHi(2,1);
140  tbxxy.growHi(2,1);
141  tbxxz.growHi(2,1);
142  tbxyz.growHi(2,1);
143  }
144 
145  const Array4<const Real> & u = xvel_old.array(mfi);
146  const Array4<const Real> & v = yvel_old.array(mfi);
147  const Array4<const Real> & w = zvel_old.array(mfi);
148 
149  Array4<Real> tau11 = Tau11_lev[level].get()->array(mfi);
150  Array4<Real> tau22 = Tau22_lev[level].get()->array(mfi);
151  Array4<Real> tau33 = Tau33_lev[level].get()->array(mfi);
152  Array4<Real> tau12 = Tau12_lev[level].get()->array(mfi);
153  Array4<Real> tau13 = Tau13_lev[level].get()->array(mfi);
154  Array4<Real> tau23 = Tau23_lev[level].get()->array(mfi);
155 
156  Array4<Real> tau21 = l_use_terrain_fitted_coords ? Tau21_lev[level].get()->array(mfi) : Array4<Real>{};
157  Array4<Real> tau31 = l_use_terrain_fitted_coords ? Tau31_lev[level].get()->array(mfi) : Array4<Real>{};
158  Array4<Real> tau32 = l_use_terrain_fitted_coords ? Tau32_lev[level].get()->array(mfi) : Array4<Real>{};
159  const Array4<const Real>& z_nd = l_use_terrain_fitted_coords ? z_phys_nd[level]->const_array(mfi) : Array4<const Real>{};
160 
161  const Array4<const Real> mf_m = mapfac_m[level]->array(mfi);
162  const Array4<const Real> mf_u = mapfac_u[level]->array(mfi);
163  const Array4<const Real> mf_v = mapfac_v[level]->array(mfi);
164 
165  if (l_use_terrain_fitted_coords) {
166  ComputeStrain_T(bxcc, tbxxy, tbxxz, tbxyz, domain,
167  u, v, w,
168  tau11, tau22, tau33,
169  tau12, tau13,
170  tau21, tau23,
171  tau31, tau32,
172  z_nd, detJ_cc[level]->const_array(mfi), bc_ptr_h, dxInv,
173  mf_m, mf_u, mf_v);
174  } else {
175  ComputeStrain_N(bxcc, tbxxy, tbxxz, tbxyz, domain,
176  u, v, w,
177  tau11, tau22, tau33,
178  tau12, tau13, tau23,
179  bc_ptr_h, dxInv,
180  mf_m, mf_u, mf_v);
181  }
182  } // mfi
183  } // l_use_diff
184  } // profile
185 
186 #include "ERF_TI_utils.H"
187 
188  // Additional SFS quantities, calculated once per timestep
189  MultiFab* Hfx1 = SFS_hfx1_lev[level].get();
190  MultiFab* Hfx2 = SFS_hfx2_lev[level].get();
191  MultiFab* Hfx3 = SFS_hfx3_lev[level].get();
192  MultiFab* Q1fx1 = SFS_q1fx1_lev[level].get();
193  MultiFab* Q1fx2 = SFS_q1fx2_lev[level].get();
194  MultiFab* Q1fx3 = SFS_q1fx3_lev[level].get();
195  MultiFab* Q2fx3 = SFS_q2fx3_lev[level].get();
196  MultiFab* Diss = SFS_diss_lev[level].get();
197 
198  // *************************************************************************
199  // Calculate cell-centered eddy viscosity & diffusivities
200  //
201  // Notes -- we fill all the data in ghost cells before calling this so
202  // that we can fill the eddy viscosity in the ghost regions and
203  // not have to call a boundary filler on this data itself
204  //
205  // LES - updates both horizontal and vertical eddy viscosity components
206  // PBL - only updates vertical eddy viscosity components so horizontal
207  // components come from the LES model or are left as zero.
208  // *************************************************************************
209  if (l_use_kturb)
210  {
211  // NOTE: state_new transfers to state_old for PBL (due to ptr swap in advance)
212  const BCRec* bc_ptr_h = domain_bcs_type.data();
213  ComputeTurbulentViscosity(xvel_old, yvel_old,
214  *Tau11_lev[level].get(), *Tau22_lev[level].get(), *Tau33_lev[level].get(),
215  *Tau12_lev[level].get(), *Tau13_lev[level].get(), *Tau23_lev[level].get(),
216  state_old[IntVars::cons],
217  *walldist[level].get(),
218  *eddyDiffs, *Hfx1, *Hfx2, *Hfx3, *Diss, // to be updated
219  fine_geom, *mapfac_u[level], *mapfac_v[level],
220  z_phys_nd[level], solverChoice,
221  m_most, z_0, exp_most,
222  l_use_moisture, level, bc_ptr_h);
223  }
224 
225  // ***********************************************************************************************
226  // Update user-defined source terms -- these are defined once per time step (not per RK stage)
227  // ***********************************************************************************************
229  prob->update_rhotheta_sources(old_time,
230  h_rhotheta_src[level], d_rhotheta_src[level],
231  fine_geom, z_phys_cc[level]);
232  }
233 
235  prob->update_rhoqt_sources(old_time,
236  h_rhoqt_src[level], d_rhoqt_src[level],
237  fine_geom, z_phys_cc[level]);
238  }
239 
241  prob->update_geostrophic_profile(old_time,
242  h_u_geos[level], d_u_geos[level],
243  h_v_geos[level], d_v_geos[level],
244  fine_geom, z_phys_cc[level]);
245  }
246 
247  // ***********************************************************************************************
248  // Convert old velocity available on faces to old momentum on faces to be used in time integration
249  // ***********************************************************************************************
250  MultiFab density(state_old[IntVars::cons], make_alias, Rho_comp, 1);
251 
252  //
253  // This is an optimization since we won't need more than one ghost
254  // cell of momentum in the integrator if not using numerical diffusion
255  //
256  IntVect ngu = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : xvel_old.nGrowVect();
257  IntVect ngv = (!solverChoice.use_num_diff) ? IntVect(1,1,1) : yvel_old.nGrowVect();
258  IntVect ngw = (!solverChoice.use_num_diff) ? IntVect(1,1,0) : zvel_old.nGrowVect();
259 
260  VelocityToMomentum(xvel_old, ngu, yvel_old, ngv, zvel_old, ngw, density,
261  state_old[IntVars::xmom],
262  state_old[IntVars::ymom],
263  state_old[IntVars::zmom],
264  domain, domain_bcs_type);
265 
266  MultiFab::Copy(xvel_new,xvel_old,0,0,1,xvel_old.nGrowVect());
267  MultiFab::Copy(yvel_new,yvel_old,0,0,1,yvel_old.nGrowVect());
268  MultiFab::Copy(zvel_new,zvel_old,0,0,1,zvel_old.nGrowVect());
269 
270  bool fast_only = false;
271  bool vel_and_mom_synced = true;
272 
273  apply_bcs(state_old, old_time,
274  state_old[IntVars::cons].nGrow(), state_old[IntVars::xmom].nGrow(),
275  fast_only, vel_and_mom_synced);
276  cons_to_prim(state_old[IntVars::cons], state_old[IntVars::cons].nGrow());
277 
278 #include "ERF_TI_no_substep_fun.H"
279 #include "ERF_TI_substep_fun.H"
280 #include "ERF_TI_slow_rhs_fun.H"
281 
282  // ***************************************************************************************
283  // Setup the integrator and integrate for a single timestep
284  // **************************************************************************************
285  MRISplitIntegrator<Vector<MultiFab> >& mri_integrator = *mri_integrator_mem[level];
286 
287  // Define rhs and 'post update' utility function that is called after calculating
288  // any state data (e.g. at RK stages or at the end of a timestep)
289  mri_integrator.set_slow_rhs_pre(slow_rhs_fun_pre);
290  mri_integrator.set_slow_rhs_post(slow_rhs_fun_post);
291 
292  if (solverChoice.anelastic[level]) {
293  mri_integrator.set_slow_rhs_inc(slow_rhs_fun_inc);
294  }
295 
296  mri_integrator.set_fast_rhs(fast_rhs_fun);
298  mri_integrator.set_no_substep(no_substep_fun);
299 
300  mri_integrator.advance(state_old, state_new, old_time, dt_advance);
301 
302  if (verbose) Print() << "Done with advance_dycore at level " << level << std::endl;
303 }
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_moisture, int level, const BCRec *bc_ptr, bool vert_only)
Definition: ERF_ComputeTurbulentViscosity.cpp:784
@ ubar
Definition: ERF_DataStruct.H:70
@ wbar
Definition: ERF_DataStruct.H:70
@ vbar
Definition: ERF_DataStruct.H:70
@ thetabar
Definition: ERF_DataStruct.H:70
@ nvars_sponge
Definition: ERF_DataStruct.H:75
@ vbar_sponge
Definition: ERF_DataStruct.H:75
@ ubar_sponge
Definition: ERF_DataStruct.H:75
auto no_substep_fun
Definition: ERF_TI_no_substep_fun.H:4
auto slow_rhs_fun_inc
Definition: ERF_TI_slow_rhs_fun.H:408
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:318
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:857
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau23_lev
Definition: ERF.H:813
amrex::Vector< std::unique_ptr< MRISplitIntegrator< amrex::Vector< amrex::MultiFab > > > > mri_integrator_mem
Definition: ERF.H:742
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_rhotheta_src
Definition: ERF.H:1118
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx3_lev
Definition: ERF.H:824
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx3_lev
Definition: ERF.H:822
amrex::Vector< std::unique_ptr< amrex::MultiFab > > mapfac_u
Definition: ERF.H:861
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau31_lev
Definition: ERF.H:812
amrex::Vector< std::unique_ptr< amrex::MultiFab > > mapfac_m
Definition: ERF.H:860
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx1_lev
Definition: ERF.H:822
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc
Definition: ERF.H:834
amrex::Vector< std::unique_ptr< amrex::MultiFab > > eddyDiffs_lev
Definition: ERF.H:814
amrex::Vector< amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > > d_sponge_ptrs
Definition: ERF.H:1151
amrex::Vector< amrex::Vector< amrex::Real > > h_rhoqt_src
Definition: ERF.H:1120
amrex::Vector< long > dt_mri_ratio
Definition: ERF.H:730
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q2fx3_lev
Definition: ERF.H:825
static int verbose
Definition: ERF.H:1046
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau13_lev
Definition: ERF.H:812
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx2_lev
Definition: ERF.H:824
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau21_lev
Definition: ERF.H:811
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau33_lev
Definition: ERF.H:810
std::unique_ptr< ProblemBase > prob
Definition: ERF.H:717
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_diss_lev
Definition: ERF.H:823
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_v_geos
Definition: ERF.H:1130
amrex::Vector< amrex::Vector< amrex::Real > > h_v_geos
Definition: ERF.H:1129
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_rhoqt_src
Definition: ERF.H:1121
amrex::Vector< amrex::Vector< amrex::Real > > h_rhotheta_src
Definition: ERF.H:1117
amrex::Vector< amrex::Vector< amrex::Real > > h_u_geos
Definition: ERF.H:1126
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SmnSmn_lev
Definition: ERF.H:815
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau32_lev
Definition: ERF.H:813
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_u_geos
Definition: ERF.H:1127
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > d_w_subsid
Definition: ERF.H:1124
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_hfx2_lev
Definition: ERF.H:822
static int fixed_mri_dt_ratio
Definition: ERF.H:937
amrex::Vector< amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > > d_rayleigh_ptrs
Definition: ERF.H:1148
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau12_lev
Definition: ERF.H:811
amrex::Vector< std::unique_ptr< amrex::MultiFab > > SFS_q1fx1_lev
Definition: ERF.H:824
amrex::Vector< std::unique_ptr< amrex::MultiFab > > mapfac_v
Definition: ERF.H:862
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau11_lev
Definition: ERF.H:810
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Tau22_lev
Definition: ERF.H:810
Definition: ERF_MRI.H:16
void set_slow_rhs_pre(std::function< void(T &, T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const int)> F)
Definition: ERF_MRI.H:134
void set_no_substep(std::function< void(T &, T &, T &, amrex::Real, amrex::Real, int)> F)
Definition: ERF_MRI.H:164
void set_slow_rhs_inc(std::function< void(T &, T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const int)> F)
Definition: ERF_MRI.H:138
void set_fast_rhs(std::function< void(int, int, int, T &, const T &, T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const amrex::Real)> F)
Definition: ERF_MRI.H:147
void set_slow_fast_timestep_ratio(const int timestep_ratio=1)
Definition: ERF_MRI.H:154
amrex::Real advance(T &S_old, T &S_new, amrex::Real time, const amrex::Real time_step)
Definition: ERF_MRI.H:174
void set_slow_rhs_post(std::function< void(T &, T &, T &, T &, T &, const amrex::Real, const amrex::Real, const amrex::Real, const int)> F)
Definition: ERF_MRI.H:142
@ pi0_comp
Definition: ERF_IndexDefines.H:65
@ p0_comp
Definition: ERF_IndexDefines.H:64
@ r0_comp
Definition: ERF_IndexDefines.H:63
Definition: ERF_DiffStruct.H:19
MolecDiffType molec_diff_type
Definition: ERF_DiffStruct.H:84
bool rayleigh_damp_T
Definition: ERF_DataStruct.H:621
bool use_explicit_most
Definition: ERF_DataStruct.H:658
bool rayleigh_damp_V
Definition: ERF_DataStruct.H:619
DiffChoice diffChoice
Definition: ERF_DataStruct.H:592
bool custom_rhotheta_forcing
Definition: ERF_DataStruct.H:647
bool custom_w_subsidence
Definition: ERF_DataStruct.H:649
bool rayleigh_damp_U
Definition: ERF_DataStruct.H:618
bool custom_geostrophic_profile
Definition: ERF_DataStruct.H:650
amrex::Vector< SubsteppingType > substepping_type
Definition: ERF_DataStruct.H:601
bool use_num_diff
Definition: ERF_DataStruct.H:670
bool custom_moisture_forcing
Definition: ERF_DataStruct.H:648
amrex::Vector< TurbChoice > turbChoice
Definition: ERF_DataStruct.H:594
amrex::Vector< int > anelastic
Definition: ERF_DataStruct.H:602
bool rayleigh_damp_W
Definition: ERF_DataStruct.H:620
SpongeChoice spongeChoice
Definition: ERF_DataStruct.H:593
Definition: ERF_SpongeStruct.H:15
std::string sponge_type
Definition: ERF_SpongeStruct.H:61
Definition: ERF_TurbStruct.H:31
PBLType pbl_type
Definition: ERF_TurbStruct.H:241
RANSType rans_type
Definition: ERF_TurbStruct.H:238
LESType les_type
Definition: ERF_TurbStruct.H:205
Here is the call graph for this function:

◆ advance_lsm()

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

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

◆ appendPlotVariables()

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

◆ 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:1060
@ th0_comp
Definition: ERF_IndexDefines.H:66
static MeshType mesh_type
Definition: ERF_DataStruct.H:583
Here is the call graph for this function:

◆ build_fine_mask()

MultiFab & ERF::build_fine_mask ( int  level)

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

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

◆ ClearLevel()

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

◆ cloud_fraction()

Real ERF::cloud_fraction ( amrex::Real  time)
174 {
175  BL_PROFILE("ERF::cloud_fraction()");
176 
177  int lev = 0;
178  // This holds all of qc
179  MultiFab qc(vars_new[lev][Vars::cons],make_alias,RhoQ2_comp,1);
180 
181  int direction = 2; // z-direction
182  Box const& domain = geom[lev].Domain();
183 
184  auto const& qc_arr = qc.const_arrays();
185 
186  // qc_2d is an BaseFab<int> holding the max value over the column
187  auto qc_2d = ReduceToPlane<ReduceOpMax,int>(direction, domain, qc,
188  [=] AMREX_GPU_DEVICE (int box_no, int i, int j, int k) -> int
189  {
190  if (qc_arr[box_no](i,j,k) > 0) {
191  return 1;
192  } else {
193  return 0;
194  }
195  });
196 
197  auto* p = qc_2d.dataPtr();
198 
199  Long numpts = qc_2d.numPts();
200 
201  AMREX_ASSERT(numpts < Long(std::numeric_limits<int>::max));
202 
203 #if 1
204  if (ParallelDescriptor::UseGpuAwareMpi()) {
205  ParallelDescriptor::ReduceIntMax(p,static_cast<int>(numpts));
206  } else {
207  Gpu::PinnedVector<int> hv(numpts);
208  Gpu::copyAsync(Gpu::deviceToHost, p, p+numpts, hv.data());
209  Gpu::streamSynchronize();
210  ParallelDescriptor::ReduceIntMax(hv.data(),static_cast<int>(numpts));
211  Gpu::copyAsync(Gpu::hostToDevice, hv.data(), hv.data()+numpts, p);
212  }
213 
214  // Sum over component 0
215  Long num_cloudy = qc_2d.template sum<RunOn::Device>(0);
216 
217 #else
218  //
219  // We need this if we allow domain decomposition in the vertical
220  // but for now we leave it commented out
221  //
222  Long num_cloudy = Reduce::Sum<Long>(numpts,
223  [=] AMREX_GPU_DEVICE (Long i) -> Long {
224  if (p[i] == 1) {
225  return 1;
226  } else {
227  return 0;
228  }
229  });
230  ParallelDescriptor::ReduceLongSum(num_cloudy);
231 #endif
232 
233  Real num_total = qc_2d.box().d_numPts();
234 
235  Real cloud_frac = num_cloudy / num_total;
236 
237  return cloud_frac;
238 }
#define RhoQ2_comp
Definition: ERF_IndexDefines.H:43
@ qc
Definition: ERF_SatAdj.H:36

◆ compute_divergence()

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

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

11 {
12  BL_PROFILE("ERF::compute_divergence()");
13 
14  auto dxInv = geom_at_lev.InvCellSizeArray();
15 
16  // ****************************************************************************
17  // Compute divergence which will form RHS
18  // Note that we replace "rho0w" with the contravariant momentum, Omega
19  // ****************************************************************************
20  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:865
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax
Definition: ERF.H:835
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay
Definition: ERF.H:836
static TerrainType terrain_type
Definition: ERF_DataStruct.H:580

◆ 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:921
amrex::Vector< amrex::Real > t_new
Definition: ERF.H:727
amrex::Real estTimeStep(int lev, long &dt_fast_ratio) const
Definition: ERF_ComputeTimestep.cpp:54
amrex::Vector< int > nsubsteps
Definition: ERF.H:724
static amrex::Real init_shrink
Definition: ERF.H:929
static amrex::Real change_max
Definition: ERF.H:930

◆ ComputeGhostCells()

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

◆ Construct_ERFFillPatchers()

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

◆ DataLog()

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

◆ DataLogName()

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

The filename of the ith datalog file.

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

◆ Define_ERFFillPatchers()

void ERF::Define_ERFFillPatchers ( int  lev)
private
1926 {
1927  auto& fine_new = vars_new[lev];
1928  auto& crse_new = vars_new[lev-1];
1929  auto& ba_fine = fine_new[Vars::cons].boxArray();
1930  auto& ba_crse = crse_new[Vars::cons].boxArray();
1931  auto& dm_fine = fine_new[Vars::cons].DistributionMap();
1932  auto& dm_crse = crse_new[Vars::cons].DistributionMap();
1933 
1934  int ncomp = fine_new[Vars::cons].nComp();
1935 
1936  FPr_c[lev-1].Define(ba_fine, dm_fine, geom[lev] ,
1937  ba_crse, dm_crse, geom[lev-1],
1938  -cf_width, -cf_set_width, ncomp, &cell_cons_interp);
1939  FPr_u[lev-1].Define(convert(ba_fine, IntVect(1,0,0)), dm_fine, geom[lev] ,
1940  convert(ba_crse, IntVect(1,0,0)), dm_crse, geom[lev-1],
1941  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
1942  FPr_v[lev-1].Define(convert(ba_fine, IntVect(0,1,0)), dm_fine, geom[lev] ,
1943  convert(ba_crse, IntVect(0,1,0)), dm_crse, geom[lev-1],
1944  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
1945  FPr_w[lev-1].Define(convert(ba_fine, IntVect(0,0,1)), dm_fine, geom[lev] ,
1946  convert(ba_crse, IntVect(0,0,1)), dm_crse, geom[lev-1],
1947  -cf_width, -cf_set_width, 1, &face_cons_linear_interp);
1948 }

◆ derive_diag_profiles()

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

Computes the profiles for diagnostic quantities.

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

◆ derive_diag_profiles_stag()

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

Computes the profiles for diagnostic quantities at staggered heights.

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

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

◆ derive_upwp()

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

◆ EBFactory()

amrex::EBFArrayBoxFactory const& ERF::EBFactory ( int  lev) const
inlineprivatenoexcept
1404  {
1405  return static_cast<amrex::EBFArrayBoxFactory const&>(*m_factory[lev]);
1406  }
amrex::Vector< std::unique_ptr< amrex::FabFactory< amrex::FArrayBox > > > m_factory
Definition: ERF.H:1399

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

◆ ERF_shared()

void ERF::ERF_shared ( )
105 {
106  if (ParallelDescriptor::IOProcessor()) {
107  const char* erf_hash = buildInfoGetGitHash(1);
108  const char* amrex_hash = buildInfoGetGitHash(2);
109  const char* buildgithash = buildInfoGetBuildGitHash();
110  const char* buildgitname = buildInfoGetBuildGitName();
111 
112  if (strlen(erf_hash) > 0) {
113  Print() << "\n"
114  << "ERF git hash: " << erf_hash << "\n";
115  }
116  if (strlen(amrex_hash) > 0) {
117  Print() << "AMReX git hash: " << amrex_hash << "\n";
118  }
119  if (strlen(buildgithash) > 0) {
120  Print() << buildgitname << " git hash: " << buildgithash << "\n";
121  }
122 
123  Print() << "\n";
124  }
125 
126  int nlevs_max = max_level + 1;
127 
128 #ifdef ERF_USE_WINDFARM
129  Nturb.resize(nlevs_max);
130  vars_windfarm.resize(nlevs_max);
131  SMark.resize(nlevs_max);
132 #endif
133 
134 #if defined(ERF_USE_RRTMGP)
135  qheating_rates.resize(nlevs_max);
136  sw_lw_fluxes.resize(nlevs_max);
137  solar_zenith.resize(nlevs_max);
138 #endif
139 
140  // NOTE: size lsm before readparams (chooses the model at all levels)
141  lsm.ReSize(nlevs_max);
142  lsm_data.resize(nlevs_max);
143  lsm_flux.resize(nlevs_max);
144 
145  // NOTE: size canopy model before readparams (if file exists, we construct)
146  m_forest_drag.resize(nlevs_max);
147  for (int lev = 0; lev <= max_level; ++lev) { m_forest_drag[lev] = nullptr;}
148 
149  ReadParameters();
150  initializeMicrophysics(nlevs_max);
151 
152 #ifdef ERF_USE_WINDFARM
153  initializeWindFarm(nlevs_max);
154 #endif
155 
156 #ifdef ERF_USE_RRTMGP
157  rad.resize(nlevs_max);
158  for (int lev = 0; lev <= max_level; ++lev) { rad[lev] = std::make_unique<Radiation>(lev,solverChoice); }
159 #endif
160 
161  const std::string& pv1 = "plot_vars_1"; setPlotVariables(pv1,plot_var_names_1);
162  const std::string& pv2 = "plot_vars_2"; setPlotVariables(pv2,plot_var_names_2);
163 
164  // This is only used when we have mesh_type == MeshType::StretchedDz
165  stretched_dz_h.resize(nlevs_max);
166  stretched_dz_d.resize(nlevs_max);
167 
168  // Initialize staggered vertical levels for grid stretching or terrain, and
169  // to simplify Rayleigh damping layer calculations.
170  zlevels_stag.resize(max_level+1);
174  geom,
175  refRatio(),
178  solverChoice.dz0);
179 
180  if (SolverChoice::mesh_type == MeshType::StretchedDz ||
181  SolverChoice::mesh_type == MeshType::VariableDz) {
182  int nz = geom[0].Domain().length(2) + 1; // staggered
183  if (std::fabs(zlevels_stag[0][nz-1]-geom[0].ProbHi(2)) > 1.0e-4) {
184  Print() << "Note: prob_hi[2]=" << geom[0].ProbHi(2)
185  << " does not match highest requested z level " << zlevels_stag[0][nz-1]
186  << std::endl;
187  }
188  if (std::fabs(zlevels_stag[0][0]-geom[0].ProbLo(2)) > 1.0e-4) {
189  Print() << "Note: prob_lo[2]=" << geom[0].ProbLo(2)
190  << " does not match lowest requested level " << zlevels_stag[0][0]
191  << std::endl;
192  }
193 
194  // Redefine the problem domain here?
195  }
196 
197  prob = amrex_probinit(geom[0].ProbLo(),geom[0].ProbHi());
198 
199  // Geometry on all levels has been defined already.
200 
201  // No valid BoxArray and DistributionMapping have been defined.
202  // But the arrays for them have been resized.
203 
204  istep.resize(nlevs_max, 0);
205  nsubsteps.resize(nlevs_max, 1);
206  for (int lev = 1; lev <= max_level; ++lev) {
207  nsubsteps[lev] = MaxRefRatio(lev-1);
208  }
209 
210  t_new.resize(nlevs_max, 0.0);
211  t_old.resize(nlevs_max, -1.e100);
212  dt.resize(nlevs_max, 1.e100);
213  dt_mri_ratio.resize(nlevs_max, 1);
214 
215  vars_new.resize(nlevs_max);
216  vars_old.resize(nlevs_max);
217 
218  // We resize this regardless in order to pass it without error
219  pp_inc.resize(nlevs_max);
220 
221  rU_new.resize(nlevs_max);
222  rV_new.resize(nlevs_max);
223  rW_new.resize(nlevs_max);
224 
225  rU_old.resize(nlevs_max);
226  rV_old.resize(nlevs_max);
227  rW_old.resize(nlevs_max);
228 
229  // xmom_crse_rhs.resize(nlevs_max);
230  // ymom_crse_rhs.resize(nlevs_max);
231  zmom_crse_rhs.resize(nlevs_max);
232 
233  for (int lev = 0; lev < nlevs_max; ++lev) {
234  vars_new[lev].resize(Vars::NumTypes);
235  vars_old[lev].resize(Vars::NumTypes);
236  }
237 
238  // Time integrator
239  mri_integrator_mem.resize(nlevs_max);
240 
241  // Physical boundary conditions
242  physbcs_cons.resize(nlevs_max);
243  physbcs_u.resize(nlevs_max);
244  physbcs_v.resize(nlevs_max);
245  physbcs_w.resize(nlevs_max);
246  physbcs_base.resize(nlevs_max);
247 
248  // Planes to hold Dirichlet values at boundaries
249  xvel_bc_data.resize(nlevs_max);
250  yvel_bc_data.resize(nlevs_max);
251  zvel_bc_data.resize(nlevs_max);
252 
253  advflux_reg.resize(nlevs_max);
254 
255  // Stresses
256  Tau11_lev.resize(nlevs_max); Tau22_lev.resize(nlevs_max); Tau33_lev.resize(nlevs_max);
257  Tau12_lev.resize(nlevs_max); Tau21_lev.resize(nlevs_max);
258  Tau13_lev.resize(nlevs_max); Tau31_lev.resize(nlevs_max);
259  Tau23_lev.resize(nlevs_max); Tau32_lev.resize(nlevs_max);
260  SFS_hfx1_lev.resize(nlevs_max); SFS_hfx2_lev.resize(nlevs_max); SFS_hfx3_lev.resize(nlevs_max);
261  SFS_diss_lev.resize(nlevs_max);
262  SFS_q1fx1_lev.resize(nlevs_max); SFS_q1fx2_lev.resize(nlevs_max); SFS_q1fx3_lev.resize(nlevs_max);
263  SFS_q2fx3_lev.resize(nlevs_max);
264  eddyDiffs_lev.resize(nlevs_max);
265  SmnSmn_lev.resize(nlevs_max);
266 
267  // Sea surface temps
268  sst_lev.resize(nlevs_max);
269  lmask_lev.resize(nlevs_max);
270 
271  // Metric terms
272  z_phys_nd.resize(nlevs_max);
273  z_phys_cc.resize(nlevs_max);
274  detJ_cc.resize(nlevs_max);
275  ax.resize(nlevs_max);
276  ay.resize(nlevs_max);
277  az.resize(nlevs_max);
278 
279  z_phys_nd_new.resize(nlevs_max);
280  detJ_cc_new.resize(nlevs_max);
281  ax_new.resize(nlevs_max);
282  ay_new.resize(nlevs_max);
283  az_new.resize(nlevs_max);
284 
285  z_phys_nd_src.resize(nlevs_max);
286  detJ_cc_src.resize(nlevs_max);
287  ax_src.resize(nlevs_max);
288  ay_src.resize(nlevs_max);
289  az_src.resize(nlevs_max);
290 
291  z_t_rk.resize(nlevs_max);
292 
293  terrain_blanking.resize(nlevs_max);
294 
295  // Wall distance
296  walldist.resize(nlevs_max);
297 
298  // Mapfactors
299  mapfac_m.resize(nlevs_max);
300  mapfac_u.resize(nlevs_max);
301  mapfac_v.resize(nlevs_max);
302 
303  // Thin immersed body
304  xflux_imask.resize(nlevs_max);
305  yflux_imask.resize(nlevs_max);
306  zflux_imask.resize(nlevs_max);
307  //overset_imask.resize(nlevs_max);
308  thin_xforce.resize(nlevs_max);
309  thin_yforce.resize(nlevs_max);
310  thin_zforce.resize(nlevs_max);
311 
312  // Base state
313  base_state.resize(nlevs_max);
314  base_state_new.resize(nlevs_max);
315 
316  // Wave coupling data
317  Hwave.resize(nlevs_max);
318  Lwave.resize(nlevs_max);
319  for (int lev = 0; lev < max_level; ++lev)
320  {
321  Hwave[lev] = nullptr;
322  Lwave[lev] = nullptr;
323  }
324  Hwave_onegrid.resize(nlevs_max);
325  Lwave_onegrid.resize(nlevs_max);
326  for (int lev = 0; lev < max_level; ++lev)
327  {
328  Hwave_onegrid[lev] = nullptr;
329  Lwave_onegrid[lev] = nullptr;
330  }
331 
332  // Theta prim for MOST
333  Theta_prim.resize(nlevs_max);
334 
335  // Qv prim for MOST
336  Qv_prim.resize(nlevs_max);
337 
338  // Qr prim for MOST
339  Qr_prim.resize(nlevs_max);
340 
341  // Time averaged velocity field
342  vel_t_avg.resize(nlevs_max);
343  t_avg_cnt.resize(nlevs_max);
344 
345 #ifdef ERF_USE_NETCDF
346  // Size lat long arrays if using netcdf
347  lat_m.resize(nlevs_max);
348  lon_m.resize(nlevs_max);
349  for (int lev = 0; lev < max_level; ++lev)
350  {
351  lat_m[lev] = nullptr;
352  lon_m[lev] = nullptr;
353  }
354 #endif
355 
356  // Initialize tagging criteria for mesh refinement
358 
359  for (int lev = 0; lev < max_level; ++lev)
360  {
361  Print() << "Refinement ratio at level " << lev+1 << " set to be " <<
362  ref_ratio[lev][0] << " " << ref_ratio[lev][1] << " " << ref_ratio[lev][2] << std::endl;
363  }
364 
365  // We will create each of these in MakeNewLevel.../RemakeLevel
366  m_factory.resize(max_level+1);
367 
368  //
369  // Construct the EB data structures and store in a separate class
370  //
371  // This is needed before initializing level MultiFabs
372  if ( solverChoice.terrain_type == TerrainType::EB ||
373  solverChoice.terrain_type == TerrainType::ImmersedForcing)
374  {
375  int lev = 0; Real dummy_time = 0.0;
376  Box terrain_bx(surroundingNodes(geom[lev].Domain())); terrain_bx.grow(3);
377  FArrayBox terrain_fab(makeSlab(terrain_bx,2,0),1);
378  prob->init_terrain_surface(geom[lev], terrain_fab, dummy_time);
379 
380  amrex::Print() << "MAKING EB GEOMETRY " << std::endl;
381  eb_ eb(geom[lev], terrain_fab, stretched_dz_d[lev], solverChoice.anelastic[lev]);
382  // MakeEBGeometry();
383  }
384 }
std::unique_ptr< ProblemBase > amrex_probinit(const amrex_real *problo, const amrex_real *probhi) AMREX_ATTRIBUTE_WEAK
void init_zlevels(Vector< Vector< Real >> &zlevels_stag, Vector< Vector< Real >> &stretched_dz_h, Vector< Gpu::DeviceVector< Real >> &stretched_dz_d, Vector< Geometry > const &geom, Vector< IntVect > const &ref_ratio, const Real grid_stretching_ratio, const Real zsurf, const Real dz0)
Definition: ERF_TerrainMetrics.cpp:11
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Hwave_onegrid
Definition: ERF.H:873
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_yforce
Definition: ERF.H:906
void setPlotVariables(const std::string &pp_plot_var_names, amrex::Vector< std::string > &plot_var_names)
Definition: ERF_Plotfile.cpp:17
void ReadParameters()
Definition: ERF.cpp:1398
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay_new
Definition: ERF.H:848
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd_src
Definition: ERF.H:839
amrex::Vector< amrex::MultiFab > base_state_new
Definition: ERF.H:868
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az
Definition: ERF.H:837
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::iMultiFab > > > lmask_lev
Definition: ERF.H:819
amrex::Vector< std::unique_ptr< amrex::MultiFab > > terrain_blanking
Definition: ERF.H:854
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_phys_nd_new
Definition: ERF.H:845
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_zforce
Definition: ERF.H:907
amrex::Vector< amrex::Vector< std::unique_ptr< amrex::MultiFab > > > sst_lev
Definition: ERF.H:818
amrex::Vector< std::unique_ptr< amrex::MultiFab > > thin_xforce
Definition: ERF.H:905
amrex::Vector< std::string > plot_var_names_1
Definition: ERF.H:966
amrex::Vector< amrex::Real > t_old
Definition: ERF.H:728
amrex::Vector< std::unique_ptr< amrex::MultiFab > > z_t_rk
Definition: ERF.H:851
amrex::Vector< std::string > plot_var_names_2
Definition: ERF.H:967
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Lwave_onegrid
Definition: ERF.H:874
amrex::Vector< std::unique_ptr< ForestDrag > > m_forest_drag
Definition: ERF.H:1170
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > xvel_bc_data
Definition: ERF.H:692
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc_src
Definition: ERF.H:840
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ay_src
Definition: ERF.H:842
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > yflux_imask
Definition: ERF.H:900
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az_new
Definition: ERF.H:849
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_flux
Definition: ERF.H:788
void refinement_criteria_setup()
Definition: ERF_Tagging.cpp:127
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax_src
Definition: ERF.H:841
amrex::Vector< amrex::Vector< amrex::Real > > zlevels_stag
Definition: ERF.H:828
amrex::Vector< amrex::Vector< amrex::MultiFab * > > lsm_data
Definition: ERF.H:787
amrex::Vector< amrex::Vector< amrex::Real > > stretched_dz_h
Definition: ERF.H:864
amrex::Vector< std::unique_ptr< amrex::MultiFab > > az_src
Definition: ERF.H:843
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Lwave
Definition: ERF.H:872
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > zflux_imask
Definition: ERF.H:901
amrex::Vector< std::unique_ptr< amrex::MultiFab > > ax_new
Definition: ERF.H:847
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > zvel_bc_data
Definition: ERF.H:694
amrex::Vector< std::unique_ptr< amrex::MultiFab > > detJ_cc_new
Definition: ERF.H:846
amrex::Vector< amrex::Gpu::DeviceVector< amrex::Real > > yvel_bc_data
Definition: ERF.H:693
amrex::Vector< std::unique_ptr< amrex::MultiFab > > Hwave
Definition: ERF.H:871
amrex::Vector< int > istep
Definition: ERF.H:723
amrex::Vector< std::unique_ptr< amrex::iMultiFab > > xflux_imask
Definition: ERF.H:899
void initializeMicrophysics(const int &)
Definition: ERF.cpp:1231
void ReSize(const int &nlev)
Definition: ERF_LandSurface.H:23
Definition: ERF_EB.H:13
const char * buildInfoGetGitHash(int i)
amrex::Real dz0
Definition: ERF_DataStruct.H:637
amrex::Real grid_stretching_ratio
Definition: ERF_DataStruct.H:635
amrex::Real zsurf
Definition: ERF_DataStruct.H:636
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,0);
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, 0);
54  MultiFab::Divide(*mf, vars_new[levc][Vars::cons], Rho_comp, 0, 1, 0);
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, 0);
60  MultiFab::Divide(*mf, vars_new[levc][Vars::cons], Rho_comp, 0, 1, 0);
61 
62 
63  // This allows dynamic refinement based on the value of the scalar/pressure/theta
64  } else if ( (ref_tags[j].Field() == "scalar" ) ||
65  (ref_tags[j].Field() == "pressure") ||
66  (ref_tags[j].Field() == "theta" ) )
67  {
68  for (MFIter mfi(*mf, TilingIfNotGPU()); mfi.isValid(); ++mfi)
69  {
70  const Box& bx = mfi.growntilebox();
71  auto& dfab = (*mf)[mfi];
72  auto& sfab = vars_new[levc][Vars::cons][mfi];
73  if (ref_tags[j].Field() == "scalar") {
74  derived::erf_derscalar(bx, dfab, 0, 1, sfab, Geom(levc), time, nullptr, levc);
75  } else if (ref_tags[j].Field() == "theta") {
76  derived::erf_dertheta(bx, dfab, 0, 1, sfab, Geom(levc), time, nullptr, levc);
77  }
78  } // mfi
79 #ifdef ERF_USE_PARTICLES
80  } else {
81  //
82  // This allows dynamic refinement based on the number of particles per cell
83  //
84  // Note that we must count all the particles in levels both at and above the current,
85  // since otherwise, e.g., if the particles are all at level 1, counting particles at
86  // level 0 will not trigger refinement when regridding so level 1 will disappear,
87  // then come back at the next regridding
88  //
89  const auto& particles_namelist( particleData.getNames() );
90  mf->setVal(0.0);
91  for (ParticlesNamesVector::size_type i = 0; i < particles_namelist.size(); i++)
92  {
93  std::string tmp_string(particles_namelist[i]+"_count");
94  IntVect rr = IntVect::TheUnitVector();
95  if (ref_tags[j].Field() == tmp_string) {
96  for (int lev = levc; lev <= finest_level; lev++)
97  {
98  MultiFab temp_dat(grids[lev], dmap[lev], 1, 0); temp_dat.setVal(0);
99  particleData[particles_namelist[i]]->IncrementWithTotal(temp_dat, lev);
100 
101  MultiFab temp_dat_crse(grids[levc], dmap[levc], 1, 0); temp_dat_crse.setVal(0);
102 
103  if (lev == levc) {
104  MultiFab::Copy(*mf, temp_dat, 0, 0, 1, 0);
105  } else {
106  for (int d = 0; d < AMREX_SPACEDIM; d++) {
107  rr[d] *= ref_ratio[levc][d];
108  }
109  average_down(temp_dat, temp_dat_crse, 0, 1, rr);
110  MultiFab::Add(*mf, temp_dat_crse, 0, 0, 1, 0);
111  }
112  }
113  }
114  }
115 #endif
116  }
117 
118  ref_tags[j](tags,mf.get(),clearval,tagval,time,levc,geom[levc]);
119  } // loop over j
120 }
static amrex::Vector< amrex::AMRErrorTag > ref_tags
Definition: ERF.H:1175
void erf_derscalar(const Box &bx, FArrayBox &derfab, int, int, const FArrayBox &datfab, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:165
void erf_dertheta(const Box &bx, FArrayBox &derfab, int, int, const FArrayBox &datfab, const Geometry &, Real, const int *, const int)
Definition: ERF_Derive.cpp:144
Here is the call graph for this function:

◆ estTimeStep()

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

Function that calls estTimeStep for each level

Parameters
[in]levellevel of refinement (coarsest level i 0)
[out]dt_fast_ratioratio of slow to fast time step
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  EBFArrayBoxFactory ebfact = EBFactory(level);
85  const MultiFab& detJ = ebfact.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:1183
amrex::Vector< amrex::Real > fixed_dt
Definition: ERF.H:935
static amrex::Real dt_max
Definition: ERF.H:932
amrex::Vector< amrex::Real > fixed_fast_dt
Definition: ERF.H:936
static amrex::Real cfl
Definition: ERF.H:927
amrex::EBFArrayBoxFactory const & EBFactory(int lev) const noexcept
Definition: ERF.H:1404
static amrex::Real dt_max_initial
Definition: ERF.H:931
static amrex::Real sub_cfl
Definition: ERF.H:928
@ rho
Definition: ERF_Kessler.H:30
int force_stage1_single_substep
Definition: ERF_DataStruct.H:599
Here is the call graph for this function:

◆ Evolve()

void ERF::Evolve ( )
391 {
392  BL_PROFILE_VAR("ERF::Evolve()", evolve);
393 
394  Real cur_time = t_new[0];
395 
396  // Take one coarse timestep by calling timeStep -- which recursively calls timeStep
397  // for finer levels (with or without subcycling)
398  for (int step = istep[0]; step < max_step && cur_time < stop_time; ++step)
399  {
400  Print() << "\nCoarse STEP " << step+1 << " starts ..." << std::endl;
401 
402  ComputeDt(step);
403 
404  // Make sure we have read enough of the boundary plane data to make it through this timestep
405  if (input_bndry_planes)
406  {
407  m_r2d->read_input_files(cur_time,dt[0],m_bc_extdir_vals);
408  }
409 
410  int lev = 0;
411  int iteration = 1;
412  timeStep(lev, cur_time, iteration);
413 
414  cur_time += dt[0];
415 
416  Print() << "Coarse STEP " << step+1 << " ends." << " TIME = " << cur_time
417  << " DT = " << dt[0] << std::endl;
418 
419  post_timestep(step, cur_time, dt[0]);
420 
421  if (writeNow(cur_time, dt[0], step+1, m_plot_int_1, m_plot_per_1)) {
422  last_plot_file_step_1 = step+1;
424  }
425  if (writeNow(cur_time, dt[0], step+1, m_plot_int_2, m_plot_per_2)) {
426  last_plot_file_step_2 = step+1;
428  }
429 
430  if (writeNow(cur_time, dt[0], step+1, m_check_int, m_check_per)) {
431  last_check_file_step = step+1;
432 #ifdef ERF_USE_NETCDF
433  if (check_type == "netcdf") {
434  WriteNCCheckpointFile();
435  }
436 #endif
437  if (check_type == "native") {
439  }
440  }
441 
442 #ifdef AMREX_MEM_PROFILING
443  {
444  std::ostringstream ss;
445  ss << "[STEP " << step+1 << "]";
446  MemProfiler::report(ss.str());
447  }
448 #endif
449 
450  if (cur_time >= stop_time - 1.e-6*dt[0]) break;
451  }
452 
453  // Write plotfiles at final time
454  if ( (m_plot_int_1 > 0 || m_plot_per_1 > 0.) && istep[0] > last_plot_file_step_1 ) {
456  }
457  if ( (m_plot_int_2 > 0 || m_plot_per_2 > 0.) && istep[0] > last_plot_file_step_2) {
459  }
460 
461  if ( (m_check_int > 0 || m_check_per > 0.) && istep[0] > last_check_file_step) {
462 #ifdef ERF_USE_NETCDF
463  if (check_type == "netcdf") {
464  WriteNCCheckpointFile();
465  }
466 #endif
467  if (check_type == "native") {
469  }
470  }
471 
472  BL_PROFILE_VAR_STOP(evolve);
473 }
int last_check_file_step
Definition: ERF.H:912
int max_step
Definition: ERF.H:919
int last_plot_file_step_2
Definition: ERF.H:910
static PlotFileType plotfile_type_1
Definition: ERF.H:1056
amrex::Array< amrex::Array< amrex::Real, AMREX_SPACEDIM *2 >, AMREX_SPACEDIM+NBCVAR_max > m_bc_extdir_vals
Definition: ERF.H:890
amrex::Real m_plot_per_1
Definition: ERF.H:949
std::string check_type
Definition: ERF.H:961
int m_plot_int_1
Definition: ERF.H:947
void post_timestep(int nstep, amrex::Real time, amrex::Real dt_lev)
Definition: ERF.cpp:477
amrex::Real m_check_per
Definition: ERF.H:964
int m_check_int
Definition: ERF.H:963
int last_plot_file_step_1
Definition: ERF.H:909
static int input_bndry_planes
Definition: ERF.H:1111
static PlotFileType plotfile_type_2
Definition: ERF.H:1057
void WritePlotFile(int which, PlotFileType plotfile_type, amrex::Vector< std::string > plot_var_names)
Definition: ERF_Plotfile.cpp:186
void ComputeDt(int step=-1)
Definition: ERF_ComputeTimestep.cpp:11
void WriteCheckpointFile() const
Definition: ERF_Checkpoint.cpp:25
int m_plot_int_2
Definition: ERF.H:948
std::unique_ptr< ReadBndryPlanes > m_r2d
Definition: ERF.H:1168
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:1976
void timeStep(int lev, amrex::Real time, int iteration)
Definition: ERF_TimeStep.cpp:16
amrex::Real m_plot_per_2
Definition: ERF.H:950

Referenced by main().

Here is the caller graph for this function:

◆ Factory()

amrex::FabFactory<amrex::FArrayBox> const& ERF::Factory ( int  lev) const
inlineprivatenoexcept
1402 { return *m_factory[lev]; }

◆ 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:884
@ RhoScalar_bc_comp
Definition: ERF_IndexDefines.H:80
@ ext_dir_ingested
Definition: ERF_IndexDefines.H:183

◆ fill_rhs()

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

◆ FillBdyCCVels()

void ERF::FillBdyCCVels ( amrex::Vector< amrex::MultiFab > &  mf_cc_vel)
12 {
13  // Impose bc's at domain boundaries
14  for (int lev = 0; lev <= finest_level; ++lev)
15  {
16  Box domain(Geom(lev).Domain());
17 
18  int ihi = domain.bigEnd(0);
19  int jhi = domain.bigEnd(1);
20  int khi = domain.bigEnd(2);
21 
22  // Impose periodicity first
23  mf_cc_vel[lev].FillBoundary(geom[lev].periodicity());
24 
25  for (MFIter mfi(mf_cc_vel[lev], TilingIfNotGPU()); mfi.isValid(); ++mfi)
26  {
27  // Note that we don't fill corners here -- only the cells that share a face
28  // with interior cells -- this is all that is needed to calculate vorticity
29  const Box& bx = mfi.tilebox();
30  const Array4<Real>& vel_arr = mf_cc_vel[lev].array(mfi);
31 
32  if (!Geom(lev).isPeriodic(0)) {
33  // Low-x side
34  if (bx.smallEnd(0) <= domain.smallEnd(0)) {
35  Real mult = (phys_bc_type[0] == ERF_BC::no_slip_wall) ? -1. : 1.;
36  ParallelFor(makeSlab(bx,0,0), [=] AMREX_GPU_DEVICE(int , int j, int k) noexcept
37  {
38  vel_arr(-1,j,k,1) = mult*vel_arr(0,j,k,1); // v
39  vel_arr(-1,j,k,2) = mult*vel_arr(0,j,k,2); // w
40  });
41  }
42 
43  // High-x side
44  if (bx.bigEnd(0) >= domain.bigEnd(0)) {
45  Real mult = (phys_bc_type[3] == ERF_BC::no_slip_wall) ? -1. : 1.;
46  ParallelFor(makeSlab(bx,0,0), [=] AMREX_GPU_DEVICE(int , int j, int k) noexcept
47  {
48  vel_arr(ihi+1,j,k,1) = mult*vel_arr(ihi,j,k,1); // v
49  vel_arr(ihi+1,j,k,2) = mult*vel_arr(ihi,j,k,2); // w
50  });
51  }
52  } // !periodic
53 
54  if (!Geom(lev).isPeriodic(1)) {
55  // Low-y side
56  if (bx.smallEnd(1) <= domain.smallEnd(1)) {
57  Real mult = (phys_bc_type[1] == ERF_BC::no_slip_wall) ? -1. : 1.;
58  ParallelFor(makeSlab(bx,1,0), [=] AMREX_GPU_DEVICE(int i, int , int k) noexcept
59  {
60  vel_arr(i,-1,k,0) = mult*vel_arr(i,0,k,0); // u
61  vel_arr(i,-1,k,2) = mult*vel_arr(i,0,k,2); // w
62  });
63  }
64 
65  // High-y side
66  if (bx.bigEnd(1) >= domain.bigEnd(1)) {
67  Real mult = (phys_bc_type[4] == ERF_BC::no_slip_wall) ? -1. : 1.;
68  ParallelFor(makeSlab(bx,1,0), [=] AMREX_GPU_DEVICE(int i, int , int k) noexcept
69  {
70  vel_arr(i,jhi+1,k,0) = mult*vel_arr(i,jhi,k,0); // u
71  vel_arr(i,jhi+1,k,2) = mult*-vel_arr(i,jhi,k,2); // w
72  });
73  }
74  } // !periodic
75 
76  if (!Geom(lev).isPeriodic(2)) {
77  // Low-z side
78  if (bx.smallEnd(2) <= domain.smallEnd(2)) {
79  Real mult = (phys_bc_type[2] == ERF_BC::no_slip_wall) ? -1. : 1.;
80  ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE(int i, int j, int) noexcept
81  {
82  vel_arr(i,j,-1,0) = mult*vel_arr(i,j,0,0); // u
83  vel_arr(i,j,-1,1) = mult*vel_arr(i,j,0,1); // v
84  });
85  }
86 
87  // High-z side
88  if (bx.bigEnd(2) >= domain.bigEnd(2)) {
89  Real mult = (phys_bc_type[5] == ERF_BC::no_slip_wall) ? -1. : 1.;
90  ParallelFor(makeSlab(bx,2,0), [=] AMREX_GPU_DEVICE(int i, int j, int) noexcept
91  {
92  vel_arr(i,j,khi+1,0) = mult*vel_arr(i,j,khi,0); // u
93  vel_arr(i,j,khi+1,1) = mult*vel_arr(i,j,khi,1); // v
94  });
95  }
96  } // !periodic
97  } // MFIter
98 
99  } // lev
100 }
@ no_slip_wall

◆ FillCoarsePatch()

void ERF::FillCoarsePatch ( int  lev,
amrex::Real  time 
)
private
22 {
23  BL_PROFILE_VAR("FillCoarsePatch()",FillCoarsePatch);
24  AMREX_ASSERT(lev > 0);
25 
26  //
27  //****************************************************************************************************************
28  // First fill velocities and density at the COARSE level so we can convert velocity to momenta at the COARSE level
29  //****************************************************************************************************************
30  //
31  bool cons_only = false;
32  if (lev == 1) {
33  FillPatch(lev-1, time, {&vars_new[lev-1][Vars::cons], &vars_new[lev-1][Vars::xvel],
34  &vars_new[lev-1][Vars::yvel], &vars_new[lev-1][Vars::zvel]},
35  cons_only);
36  } else {
37  FillPatch(lev-1, time, {&vars_new[lev-1][Vars::cons], &vars_new[lev-1][Vars::xvel],
38  &vars_new[lev-1][Vars::yvel], &vars_new[lev-1][Vars::zvel]},
39  {&vars_new[lev-1][Vars::cons],
40  &rU_new[lev-1], &rV_new[lev-1], &rW_new[lev-1]},
41  base_state[lev-1], base_state[lev-1],
42  false, cons_only);
43  }
44 
45  //
46  // ************************************************
47  // Convert velocity to momentum at the COARSE level
48  // ************************************************
49  //
50  VelocityToMomentum(vars_new[lev-1][Vars::xvel], IntVect{0},
51  vars_new[lev-1][Vars::yvel], IntVect{0},
52  vars_new[lev-1][Vars::zvel], IntVect{0},
53  vars_new[lev-1][Vars::cons],
54  rU_new[lev-1],
55  rV_new[lev-1],
56  rW_new[lev-1],
57  Geom(lev).Domain(),
59  //
60  // *****************************************************************
61  // Interpolate all cell-centered variables from coarse to fine level
62  // *****************************************************************
63  //
64  Interpolater* mapper_c = &cell_cons_interp;
65  Interpolater* mapper_f = &face_cons_linear_interp;
66 
67  //
68  //************************************************************************************************
69  // Interpolate cell-centered data from coarse to fine level
70  // with InterpFromCoarseLevel which ASSUMES that all ghost cells have already been filled
71  // ************************************************************************************************
72  IntVect ngvect_cons = vars_new[lev][Vars::cons].nGrowVect();
73  int ncomp_cons = vars_new[lev][Vars::cons].nComp();
74 
75  InterpFromCoarseLevel(vars_new[lev ][Vars::cons], ngvect_cons, IntVect(0,0,0),
76  vars_new[lev-1][Vars::cons], 0, 0, ncomp_cons,
77  geom[lev-1], geom[lev],
78  refRatio(lev-1), mapper_c, domain_bcs_type, BCVars::cons_bc);
79 
80  // ***************************************************************************
81  // Physical bc's for cell centered variables at domain boundary
82  // ***************************************************************************
83  (*physbcs_cons[lev])(vars_new[lev][Vars::cons],0,ncomp_cons,ngvect_cons,time,BCVars::cons_bc,true);
84 
85  //
86  //************************************************************************************************
87  // Interpolate x-momentum from coarse to fine level
88  // with InterpFromCoarseLevel which ASSUMES that all ghost cells have already been filled
89  // ************************************************************************************************
90  //
91  InterpFromCoarseLevel(rU_new[lev], IntVect{0}, IntVect{0}, rU_new[lev-1], 0, 0, 1,
92  geom[lev-1], geom[lev],
93  refRatio(lev-1), mapper_f, domain_bcs_type, BCVars::xvel_bc);
94 
95  //
96  //************************************************************************************************
97  // Interpolate y-momentum from coarse to fine level
98  // with InterpFromCoarseLevel which ASSUMES that all ghost cells have already been filled
99  // ************************************************************************************************
100  //
101  InterpFromCoarseLevel(rV_new[lev], IntVect{0}, IntVect{0}, rV_new[lev-1], 0, 0, 1,
102  geom[lev-1], geom[lev],
103  refRatio(lev-1), mapper_f, domain_bcs_type, BCVars::yvel_bc);
104 
105  //************************************************************************************************
106  // Interpolate z-momentum from coarse to fine level
107  // with InterpFromCoarseLevel which ASSUMES that all ghost cells have already been filled
108  // ************************************************************************************************
109  InterpFromCoarseLevel(rW_new[lev], IntVect{0}, IntVect{0}, rW_new[lev-1], 0, 0, 1,
110  geom[lev-1], geom[lev],
111  refRatio(lev-1), mapper_f, domain_bcs_type, BCVars::zvel_bc);
112  //
113  // *********************************************************
114  // After interpolation of momentum, convert back to velocity
115  // *********************************************************
116  //
117  for (int which_lev = lev-1; which_lev <= lev; which_lev++)
118  {
120  vars_new[which_lev][Vars::yvel],
121  vars_new[which_lev][Vars::zvel],
122  vars_new[which_lev][Vars::cons],
123  rU_new[which_lev],
124  rV_new[which_lev],
125  rW_new[which_lev],
126  Geom(lev).Domain(),
128  }
129 
130  // ***************************************************************************
131  // Physical bc's at domain boundary
132  // ***************************************************************************
133  IntVect ngvect_vels = vars_new[lev][Vars::xvel].nGrowVect();
134 
135  ( *physbcs_u[lev])(vars_new[lev][Vars::xvel],0,1 ,ngvect_vels,time,BCVars::xvel_bc,true);
136  ( *physbcs_v[lev])(vars_new[lev][Vars::yvel],0,1 ,ngvect_vels,time,BCVars::yvel_bc,true);
138  ngvect_vels,time,BCVars::zvel_bc,true);
139 
140  // ***************************************************************************
141  // Since lev > 0 here we don't worry about m_r2d or wrfbdy data
142  // ***************************************************************************
143 }
void FillCoarsePatch(int lev, amrex::Real time)
Definition: ERF_FillCoarsePatch.cpp:21
Here is the call graph for this function:

◆ FillIntermediatePatch()

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

◆ FillPatch() [1/2]

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

◆ FillPatch() [2/2]

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

◆ get_projection_bc()

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

◆ getAdvFluxReg()

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

◆ getCPUTime()

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

◆ GotoNextLine()

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

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

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

◆ init1DArrays()

void ERF::init1DArrays ( )
private

◆ init_bcs()

void ERF::init_bcs ( )
private

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

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

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

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

◆ init_custom()

void ERF::init_custom ( int  lev)
private

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

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

Parameters
levInteger specifying the current level
27 {
28  auto& lev_new = vars_new[lev];
29 
30  MultiFab r_hse(base_state[lev], make_alias, BaseState::r0_comp, 1);
31  MultiFab p_hse(base_state[lev], make_alias, BaseState::p0_comp, 1);
32 
33  MultiFab cons_pert(lev_new[Vars::cons].boxArray(), lev_new[Vars::cons].DistributionMap(),
34  lev_new[Vars::cons].nComp() , lev_new[Vars::cons].nGrow());
35  MultiFab xvel_pert(lev_new[Vars::xvel].boxArray(), lev_new[Vars::xvel].DistributionMap(), 1, lev_new[Vars::xvel].nGrowVect());
36  MultiFab yvel_pert(lev_new[Vars::yvel].boxArray(), lev_new[Vars::yvel].DistributionMap(), 1, lev_new[Vars::yvel].nGrowVect());
37  MultiFab zvel_pert(lev_new[Vars::zvel].boxArray(), lev_new[Vars::zvel].DistributionMap(), 1, lev_new[Vars::zvel].nGrowVect());
38 
39  // Default all perturbations to zero
40  cons_pert.setVal(0.);
41  xvel_pert.setVal(0.);
42  yvel_pert.setVal(0.);
43  zvel_pert.setVal(0.);
44 
45 #ifdef _OPENMP
46 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
47 #endif
48  for (MFIter mfi(lev_new[Vars::cons], TileNoZ()); mfi.isValid(); ++mfi)
49  {
50  const Box &bx = mfi.tilebox();
51  const Box &xbx = mfi.tilebox(IntVect(1,0,0));
52  const Box &ybx = mfi.tilebox(IntVect(0,1,0));
53  const Box &zbx = mfi.tilebox(IntVect(0,0,1));
54 
55  const auto &cons_pert_arr = cons_pert.array(mfi);
56  const auto &xvel_pert_arr = xvel_pert.array(mfi);
57  const auto &yvel_pert_arr = yvel_pert.array(mfi);
58  const auto &zvel_pert_arr = zvel_pert.array(mfi);
59 
60  Array4<Real const> cons_arr = lev_new[Vars::cons].const_array(mfi);
61  Array4<Real const> z_nd_arr = (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
79  MultiFab::Add(lev_new[Vars::cons], cons_pert, Rho_comp, Rho_comp, 1, cons_pert.nGrow());
80  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoTheta_comp, RhoTheta_comp, 1, cons_pert.nGrow());
81  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoScalar_comp,RhoScalar_comp,NSCALARS, cons_pert.nGrow());
82 
83  // RhoKE is relevant if using Deardorff with LES, k-equation for RANS, or MYNN with PBL
84  if ((solverChoice.turbChoice[lev].les_type == LESType::Deardorff) ||
85  (solverChoice.turbChoice[lev].rans_type == RANSType::kEqn) ||
86  (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNN25)) {
87  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoKE_comp, RhoKE_comp, 1, cons_pert.nGrow());
88  }
89 
90  if (solverChoice.moisture_type != MoistureType::None) {
91  int qstate_size = micro->Get_Qstate_Size();
92  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoQ1_comp, RhoQ1_comp, 1, cons_pert.nGrow());
93  MultiFab::Add(lev_new[Vars::cons], cons_pert, RhoQ2_comp, RhoQ2_comp, 1, cons_pert.nGrow());
94  for (int q_offset(2); q_offset<qstate_size; ++q_offset) {
95  int q_idx = RhoQ1_comp+q_offset;
96  MultiFab::Add(lev_new[Vars::cons], cons_pert, q_idx, q_idx, 1, cons_pert.nGrow());
97  }
98  }
99 
100  MultiFab::Add(lev_new[Vars::xvel], xvel_pert, 0, 0, 1, xvel_pert.nGrowVect());
101  MultiFab::Add(lev_new[Vars::yvel], yvel_pert, 0, 0, 1, yvel_pert.nGrowVect());
102  MultiFab::Add(lev_new[Vars::zvel], zvel_pert, 0, 0, 1, zvel_pert.nGrowVect());
103 }
Here is the call graph for this function:

◆ init_Dirichlet_bc_data()

void ERF::init_Dirichlet_bc_data ( const std::string  input_file)
private
601 {
602  const bool use_terrain = (solverChoice.terrain_type != TerrainType::None);
603 
604  // Read the dirichlet_input file
605  Print() << "dirichlet_input file location : " << input_file << std::endl;
606  std::ifstream input_reader(input_file);
607  if (!input_reader.is_open()) {
608  amrex::Abort("Error opening the dirichlet_input file.\n");
609  }
610 
611  Print() << "Successfully opened the dirichlet_input file. Now reading... " << std::endl;
612  std::string line;
613 
614  // Size of Ninp (number of z points in input file)
615  Vector<Real> z_inp_tmp, u_inp_tmp, v_inp_tmp, w_inp_tmp;
616 
617  const int klo = geom[0].Domain().smallEnd()[2];
618  const int khi = geom[0].Domain().bigEnd()[2];
619 
620  const Real zbot = (use_terrain) ? zlevels_stag[0][klo] : geom[0].ProbLo(2);
621  const Real ztop = (use_terrain) ? zlevels_stag[0][khi+1] : geom[0].ProbHi(2);
622 
623  // Add surface
624  z_inp_tmp.push_back(zbot); // height above sea level [m]
625  u_inp_tmp.push_back(0.);
626  v_inp_tmp.push_back(0.);
627  w_inp_tmp.push_back(0.);
628 
629  // Read the vertical profile at each given height
630  Real z, u, v, w;
631  while(std::getline(input_reader, line)) {
632  std::istringstream iss_z(line);
633  iss_z >> z >> u >> v >> w;
634  if (z == zbot) {
635  u_inp_tmp[0] = u;
636  v_inp_tmp[0] = v;
637  w_inp_tmp[0] = w;
638  } else {
639  AMREX_ALWAYS_ASSERT(z > z_inp_tmp[z_inp_tmp.size()-1]); // sounding is increasing in height
640  z_inp_tmp.push_back(z);
641  u_inp_tmp.push_back(u);
642  v_inp_tmp.push_back(v);
643  w_inp_tmp.push_back(w);
644  if (z >= ztop) break;
645  }
646  }
647 
648  amrex::Print() << "Successfully read and interpolated the dirichlet_input file..." << std::endl;
649  input_reader.close();
650 
651  for (int lev = 0; lev <= max_level; lev++) {
652 
653  const int Nz = geom[lev].Domain().size()[2];
654  const Real dz = geom[lev].CellSize()[2];
655 
656  // Size of Nz (domain grid)
657  Vector<Real> zcc_inp(Nz );
658  Vector<Real> znd_inp(Nz+1);
659  Vector<Real> u_inp(Nz ); xvel_bc_data[lev].resize(Nz ,0.0);
660  Vector<Real> v_inp(Nz ); yvel_bc_data[lev].resize(Nz ,0.0);
661  Vector<Real> w_inp(Nz+1); zvel_bc_data[lev].resize(Nz+1,0.0);
662 
663  // At this point, we have an input from zbot up to
664  // z_inp_tmp[N-1] >= ztop. Now, interpolate to grid level 0 heights
665  const int Ninp = z_inp_tmp.size();
666  for (int k(0); k<Nz; ++k) {
667  zcc_inp[k] = (use_terrain) ? 0.5 * (zlevels_stag[0][k] + zlevels_stag[0][k+1])
668  : zbot + (k + 0.5) * dz;
669  znd_inp[k] = (use_terrain) ? zlevels_stag[0][k+1] : zbot + (k) * dz;
670  u_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), u_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
671  v_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), v_inp_tmp.dataPtr(), zcc_inp[k], Ninp);
672  w_inp[k] = interpolate_1d(z_inp_tmp.dataPtr(), w_inp_tmp.dataPtr(), znd_inp[k], Ninp);
673  }
674  znd_inp[Nz] = ztop;
675  w_inp[Nz] = interpolate_1d(z_inp_tmp.dataPtr(), w_inp_tmp.dataPtr(), ztop, Ninp);
676 
677  // Copy host data to the device
678  Gpu::copy(Gpu::hostToDevice, u_inp.begin(), u_inp.end(), xvel_bc_data[lev].begin());
679  Gpu::copy(Gpu::hostToDevice, v_inp.begin(), v_inp.end(), yvel_bc_data[lev].begin());
680  Gpu::copy(Gpu::hostToDevice, w_inp.begin(), w_inp.end(), zvel_bc_data[lev].begin());
681 
682  // NOTE: These device vectors are passed to the PhysBC constructors when that
683  // class is instantiated in ERF_MakeNewArrays.cpp.
684  } // lev
685 }
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real interpolate_1d(const amrex::Real *alpha, const amrex::Real *beta, const amrex::Real alpha_interp, const int alpha_size)
Definition: ERF_Interpolation_1D.H:12
Here is the call graph for this function:

◆ init_from_hse()

void ERF::init_from_hse ( int  lev)

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

ERF::initHSE(lev)

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

◆ init_from_input_sounding()

void ERF::init_from_input_sounding ( int  lev)

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

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

◆ init_geo_wind_profile()

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

◆ init_only()

void ERF::init_only ( int  lev,
amrex::Real  time 
)
1287 {
1288  // Map the words in the inputs file to BC types, then translate
1289  // those types into what they mean for each variable
1290  // This must be called before initHSE (where the base state is initialized)
1291  if (lev == 0 && init_type != InitType::Ideal) {
1292  init_bcs();
1293  }
1294 
1295  t_new[lev] = time;
1296  t_old[lev] = time - 1.e200;
1297 
1298  auto& lev_new = vars_new[lev];
1299  auto& lev_old = vars_old[lev];
1300 
1301  // Loop over grids at this level to initialize our grid data
1302  lev_new[Vars::cons].setVal(0.0); lev_old[Vars::cons].setVal(0.0);
1303  lev_new[Vars::xvel].setVal(0.0); lev_old[Vars::xvel].setVal(0.0);
1304  lev_new[Vars::yvel].setVal(0.0); lev_old[Vars::yvel].setVal(0.0);
1305  lev_new[Vars::zvel].setVal(0.0); lev_old[Vars::zvel].setVal(0.0);
1306 
1307  // Initialize background flow (optional)
1308  if (init_type == InitType::Input_Sounding) {
1309  // The base state is initialized by integrating vertically through the
1310  // input sounding, if the init_sounding_ideal flag is set; otherwise
1311  // it is set by initHSE()
1312 
1313  // The physbc's need the terrain but are needed for initHSE
1314  // We have already made the terrain in the call to init_zphys
1315  // in MakeNewLevelFromScratch
1316  make_physbcs(lev);
1317 
1318  // Now init the base state and the data itself
1320 
1321  if (init_sounding_ideal) {
1322  AMREX_ALWAYS_ASSERT_WITH_MESSAGE(solverChoice.use_gravity,
1323  "Gravity should be on to be consistent with sounding initialization.");
1324  } else {
1325  initHSE();
1326  }
1327 
1328 #ifdef ERF_USE_NETCDF
1329  } else if (init_type == InitType::Ideal || init_type == InitType::Real) {
1330  // The base state is initialized from WRF wrfinput data, output by
1331  // ideal.exe or real.exe
1332  init_from_wrfinput(lev);
1333 
1334  // The physbc's need the terrain but are needed for initHSE
1335  if (init_type == InitType::Ideal) {
1336  make_physbcs(lev);
1337  initHSE(lev);
1338  }
1339 
1340  } else if (init_type == InitType::Metgrid) {
1341  // The base state is initialized from data output by WPS metgrid;
1342  // we will rebalance after interpolation
1343  init_from_metgrid(lev);
1344 #endif
1345  } else if (init_type == InitType::Uniform) {
1346  // Initialize a uniform background field and base state based on the
1347  // problem-specified reference density and temperature
1348 
1349  // The physbc's need the terrain but are needed for initHSE
1350  make_physbcs(lev);
1351 
1352  init_uniform(lev);
1353  initHSE(lev);
1354  } else {
1355  // No background flow initialization specified, initialize the
1356  // background field to be equal to the base state, calculated from the
1357  // problem-specific erf_init_dens_hse
1358 
1359  // The bc's need the terrain but are needed for initHSE
1360  make_physbcs(lev);
1361 
1362  // We will initialize the state from the background state so must set that first
1363  initHSE(lev);
1364  init_from_hse(lev);
1365  }
1366 
1367  // Add problem-specific flow features
1368  //
1369  // Notes:
1370  // - This calls init_custom_pert that is defined for each problem
1371  // - This may modify the base state
1372  // - The fields set by init_custom_pert are **perturbations** to the
1373  // background flow set based on init_type
1374  init_custom(lev);
1375 
1376  // Ensure that the face-based data are the same on both sides of a periodic domain.
1377  // The data associated with the lower grid ID is considered the correct value.
1378  lev_new[Vars::xvel].OverrideSync(geom[lev].periodicity());
1379  lev_new[Vars::yvel].OverrideSync(geom[lev].periodicity());
1380  lev_new[Vars::zvel].OverrideSync(geom[lev].periodicity());
1381 
1382  if(solverChoice.spongeChoice.sponge_type == "input_sponge"){
1383  input_sponge(lev);
1384  }
1385 
1386  // Initialize turbulent perturbation
1387  if (solverChoice.pert_type == PerturbationType::Source ||
1388  solverChoice.pert_type == PerturbationType::Direct) {
1389  if (lev == 0) {
1390  turbPert_update(lev, 0.);
1391  turbPert_amplitude(lev);
1392  }
1393  }
1394 }
void init_from_input_sounding(int lev)
Definition: ERF_InitFromInputSounding.cpp:50
static InitType init_type
Definition: ERF.H:1059
void init_custom(int lev)
Definition: ERF_InitCustom.cpp:26
void init_bcs()
Definition: ERF_InitBCs.cpp:20
void init_from_hse(int lev)
Definition: ERF_InitFromHSE.cpp:32
void initHSE()
Initialize HSE.
Definition: ERF_Init1D.cpp:140
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:611
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:614

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

◆ init_thin_body()

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

◆ init_uniform()

void ERF::init_uniform ( int  lev)
private

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

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

◆ init_zphys()

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

◆ InitData()

void ERF::InitData ( )
623 {
624  BL_PROFILE_VAR("ERF::InitData()", InitData);
625  InitData_pre();
626  InitData_post();
627  BL_PROFILE_VAR_STOP(InitData);
628 }
void InitData_pre()
Definition: ERF.cpp:631
void InitData_post()
Definition: ERF.cpp:677
void InitData()
Definition: ERF.cpp:622

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

Here is the caller graph for this function:

◆ InitData_post()

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

◆ InitData_pre()

void ERF::InitData_pre ( )
632 {
633  // Initialize the start time for our CPU-time tracker
634  startCPUTime = ParallelDescriptor::second();
635 
636  // Create the ReadBndryPlanes object so we can read boundary plane data
637  // m_r2d is used by init_bcs so we must instantiate this class before
638  if (input_bndry_planes) {
639  Print() << "Defining r2d for the first time " << std::endl;
640  m_r2d = std::make_unique<ReadBndryPlanes>(geom[0], solverChoice.rdOcp);
641  }
642 
646 
647  if (restart_chkfile.empty()) {
648  // start simulation from the beginning
649 
650  const Real time = start_time;
651  InitFromScratch(time);
652  } else {
653  // For initialization this is done in init_only; it is done here for restart
654  init_bcs();
655  }
656 
657  // Verify BCs are compatible with solver choice
658  for (int lev(0); lev <= max_level; ++lev) {
659  if ( ( (solverChoice.turbChoice[lev].pbl_type == PBLType::MYNN25) ||
660  (solverChoice.turbChoice[lev].pbl_type == PBLType::YSU) ) &&
661  phys_bc_type[Orientation(Direction::z,Orientation::low)] != ERF_BC::MOST ) {
662  Abort("MYNN2.5/YSU PBL Model requires MOST at lower boundary");
663  }
664 
665  if ( (solverChoice.turbChoice[lev].les_type == LESType::Deardorff) &&
666  (solverChoice.turbChoice[lev].Ce_wall > 0) &&
667  (phys_bc_type[Orientation(Direction::z,Orientation::low)] != ERF_BC::MOST) &&
668  (phys_bc_type[Orientation(Direction::z,Orientation::low)] != ERF_BC::slip_wall) &&
669  (phys_bc_type[Orientation(Direction::z,Orientation::low)] != ERF_BC::no_slip_wall) ) {
670  Warning("Deardorff LES assumes wall at zlo when applying Ce_wall");
671  }
672 
673  }
674 }
amrex::Real start_time
Definition: ERF.H:920

◆ initHSE() [1/2]

void ERF::initHSE ( )
private

Initialize HSE.

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

◆ initHSE() [2/2]

void ERF::initHSE ( int  lev)
private

Initialize density and pressure base state in hydrostatic equilibrium.

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

◆ 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
1232 {
1233  if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Eulerian) {
1234 
1235  micro = std::make_unique<EulerianMicrophysics>(a_nlevsmax, solverChoice.moisture_type);
1236 
1237  } else if (Microphysics::modelType(solverChoice.moisture_type) == MoistureModelType::Lagrangian) {
1238 #ifdef ERF_USE_PARTICLES
1239 
1240  micro = std::make_unique<LagrangianMicrophysics>(a_nlevsmax, solverChoice.moisture_type);
1241  /* Lagrangian microphysics models will have a particle container; it needs to be added
1242  to ERF::particleData */
1243  const auto& pc_name( dynamic_cast<LagrangianMicrophysics&>(*micro).getName() );
1244  /* The particle container has not yet been constructed and initialized, so just add
1245  its name here for now (so that functions to set plotting variables can see it). */
1246  particleData.addName( pc_name );
1247 
1248 #else
1249  Abort("Lagrangian microphysics can be used when compiled with ERF_USE_PARTICLES");
1250 #endif
1251  }
1252 
1253  qmoist.resize(a_nlevsmax);
1254  return;
1255 }
amrex::Vector< amrex::Vector< amrex::MultiFab * > > qmoist
Definition: ERF.H:771
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:1142
amrex::Real rayleigh_zdamp
Definition: ERF_DataStruct.H:623
amrex::Real rayleigh_ztop
Definition: ERF_DataStruct.H:624

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

◆ 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:689
void read_from_file(const amrex::Geometry &geom, const amrex::Vector< amrex::Real > &zlevels_stag)
Definition: ERF_InputSpongeData.H:28
std::string input_sponge_file
Definition: ERF_InputSpongeData.H:111

◆ is_it_time_for_action()

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

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

Parameters
nstepTimestep number
timeCurrent time
dtlevTimestep for the current level
action_intervalInterval in number of timesteps for taking action
action_perInterval in simulation time for taking action
467 {
468  bool int_test = (action_interval > 0 && nstep % action_interval == 0);
469 
470  bool per_test = false;
471  if (action_per > 0.0) {
472  const int num_per_old = static_cast<int>(amrex::Math::floor((time - dtlev) / action_per));
473  const int num_per_new = static_cast<int>(amrex::Math::floor((time) / action_per));
474 
475  if (num_per_old != num_per_new) {
476  per_test = true;
477  }
478  }
479 
480  return int_test || per_test;
481 }

◆ make_eb_box()

void ERF::make_eb_box ( )

◆ make_eb_regular()

void ERF::make_eb_regular ( )

◆ make_physbcs()

void ERF::make_physbcs ( int  lev)
private
612 {
613  if (SolverChoice::mesh_type == MeshType::VariableDz) {
614  AMREX_ALWAYS_ASSERT(z_phys_nd[lev] != nullptr);
615  }
616 
617  physbcs_cons[lev] = std::make_unique<ERFPhysBCFunct_cons> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
619  z_phys_nd[lev], use_real_bcs);
620  physbcs_u[lev] = std::make_unique<ERFPhysBCFunct_u> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
622  z_phys_nd[lev], use_real_bcs, xvel_bc_data[lev].data());
623  physbcs_v[lev] = std::make_unique<ERFPhysBCFunct_v> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
625  z_phys_nd[lev], use_real_bcs, yvel_bc_data[lev].data());
626  physbcs_w[lev] = std::make_unique<ERFPhysBCFunct_w> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
629  use_real_bcs, zvel_bc_data[lev].data());
630  physbcs_base[lev] = std::make_unique<ERFPhysBCFunct_base> (lev, geom[lev], domain_bcs_type, domain_bcs_type_d,
631  (solverChoice.terrain_type == TerrainType::MovingFittedMesh));
632 }

◆ MakeDiagnosticAverage()

void ERF::MakeDiagnosticAverage ( amrex::Vector< amrex::Real > &  h_havg,
amrex::MultiFab &  S,
int  n 
)
1854 {
1855  // Get the number of cells in z at level 0
1856  int dir_z = AMREX_SPACEDIM-1;
1857  auto domain = geom[0].Domain();
1858  int size_z = domain.length(dir_z);
1859  int start_z = domain.smallEnd()[dir_z];
1860  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
1861 
1862  // resize the level 0 horizontal average vectors
1863  h_havg.resize(size_z, 0.0_rt);
1864 
1865  // Get the cell centered data and construct sums
1866 #ifdef _OPENMP
1867 #pragma omp parallel if (Gpu::notInLaunchRegion())
1868 #endif
1869  for (MFIter mfi(S); mfi.isValid(); ++mfi) {
1870  const Box& box = mfi.validbox();
1871  const IntVect& se = box.smallEnd();
1872  const IntVect& be = box.bigEnd();
1873 
1874  auto fab_arr = S[mfi].array();
1875 
1876  FArrayBox fab_reduce(box, 1, The_Async_Arena());
1877  auto arr_reduce = fab_reduce.array();
1878 
1879  ParallelFor(box, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
1880  arr_reduce(i, j, k, 0) = fab_arr(i,j,k,n);
1881  });
1882 
1883  for (int k=se[dir_z]; k <= be[dir_z]; ++k) {
1884  Box kbox(box); kbox.setSmall(dir_z,k); kbox.setBig(dir_z,k);
1885  h_havg[k-start_z] += fab_reduce.sum<RunOn::Device>(kbox,0);
1886  }
1887  }
1888 
1889  // combine sums from different MPI ranks
1890  ParallelDescriptor::ReduceRealSum(h_havg.dataPtr(), h_havg.size());
1891 
1892  // divide by the total number of cells we are averaging over
1893  for (int k = 0; k < size_z; ++k) {
1894  h_havg[k] /= area_z;
1895  }
1896 }

◆ MakeEBGeometry()

void ERF::MakeEBGeometry ( )

◆ MakeHorizontalAverages()

void ERF::MakeHorizontalAverages ( )
1748 {
1749  int lev = 0;
1750 
1751  // First, average down all levels (if doing two-way coupling)
1752  if (solverChoice.coupling_type == CouplingType::TwoWay) {
1753  AverageDown();
1754  }
1755 
1756  MultiFab mf(grids[lev], dmap[lev], 5, 0);
1757 
1758  int zdir = 2;
1759  auto domain = geom[0].Domain();
1760 
1761  bool use_moisture = (solverChoice.moisture_type != MoistureType::None);
1762  bool is_anelastic = (solverChoice.anelastic[lev] == 1);
1763 
1764  for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
1765  const Box& bx = mfi.validbox();
1766  auto fab_arr = mf.array(mfi);
1767  auto const hse_arr = base_state[lev].const_array(mfi);
1768  auto const cons_arr = vars_new[lev][Vars::cons].const_array(mfi);
1769  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
1770  Real dens = cons_arr(i, j, k, Rho_comp);
1771  fab_arr(i, j, k, 0) = dens;
1772  fab_arr(i, j, k, 1) = cons_arr(i, j, k, RhoTheta_comp) / dens;
1773  if (!use_moisture) {
1774  if (is_anelastic) {
1775  fab_arr(i,j,k,2) = hse_arr(i,j,k,BaseState::p0_comp);
1776  } else {
1777  fab_arr(i,j,k,2) = getPgivenRTh(cons_arr(i,j,k,RhoTheta_comp));
1778  }
1779  }
1780  });
1781  }
1782 
1783  if (use_moisture)
1784  {
1785  for (MFIter mfi(mf); mfi.isValid(); ++mfi) {
1786  const Box& bx = mfi.validbox();
1787  auto fab_arr = mf.array(mfi);
1788  auto const hse_arr = base_state[lev].const_array(mfi);
1789  auto const cons_arr = vars_new[lev][Vars::cons].const_array(mfi);
1790  int ncomp = vars_new[lev][Vars::cons].nComp();
1791 
1792  ParallelFor(bx, [=] AMREX_GPU_DEVICE (int i, int j, int k) {
1793  Real dens = cons_arr(i, j, k, Rho_comp);
1794  if (is_anelastic) {
1795  fab_arr(i,j,k,2) = hse_arr(i,j,k,BaseState::p0_comp);
1796  } else {
1797  Real qv = cons_arr(i, j, k, RhoQ1_comp) / dens;
1798  fab_arr(i, j, k, 2) = getPgivenRTh(cons_arr(i, j, k, RhoTheta_comp), qv);
1799  }
1800  fab_arr(i, j, k, 3) = (ncomp > RhoQ1_comp ? cons_arr(i, j, k, RhoQ1_comp) / dens : 0.0);
1801  fab_arr(i, j, k, 4) = (ncomp > RhoQ2_comp ? cons_arr(i, j, k, RhoQ2_comp) / dens : 0.0);
1802  });
1803  }
1804 
1805  Gpu::HostVector<Real> h_avg_qv = sumToLine(mf,3,1,domain,zdir);
1806  Gpu::HostVector<Real> h_avg_qc = sumToLine(mf,4,1,domain,zdir);
1807  }
1808 
1809  // Sum in the horizontal plane
1810  Gpu::HostVector<Real> h_avg_density = sumToLine(mf,0,1,domain,zdir);
1811  Gpu::HostVector<Real> h_avg_temperature = sumToLine(mf,1,1,domain,zdir);
1812  Gpu::HostVector<Real> h_avg_pressure = sumToLine(mf,2,1,domain,zdir);
1813 
1814  // Divide by the total number of cells we are averaging over
1815  int size_z = domain.length(zdir);
1816  Real area_z = static_cast<Real>(domain.length(0)*domain.length(1));
1817  int klen = static_cast<int>(h_avg_density.size());
1818 
1819  for (int k = 0; k < klen; ++k) {
1820  h_havg_density[k] /= area_z;
1821  h_havg_temperature[k] /= area_z;
1822  h_havg_pressure[k] /= area_z;
1823  if (solverChoice.moisture_type != MoistureType::None)
1824  {
1825  h_havg_qc[k] /= area_z;
1826  h_havg_qv[k] /= area_z;
1827  }
1828  } // k
1829 
1830  // resize device vectors
1831  d_havg_density.resize(size_z, 0.0_rt);
1832  d_havg_temperature.resize(size_z, 0.0_rt);
1833  d_havg_pressure.resize(size_z, 0.0_rt);
1834 
1835  // copy host vectors to device vectors
1836  Gpu::copy(Gpu::hostToDevice, h_havg_density.begin(), h_havg_density.end(), d_havg_density.begin());
1837  Gpu::copy(Gpu::hostToDevice, h_havg_temperature.begin(), h_havg_temperature.end(), d_havg_temperature.begin());
1838  Gpu::copy(Gpu::hostToDevice, h_havg_pressure.begin(), h_havg_pressure.end(), d_havg_pressure.begin());
1839 
1840  if (solverChoice.moisture_type != MoistureType::None)
1841  {
1842  d_havg_qv.resize(size_z, 0.0_rt);
1843  d_havg_qc.resize(size_z, 0.0_rt);
1844  Gpu::copy(Gpu::hostToDevice, h_havg_qv.begin(), h_havg_qv.end(), d_havg_qv.begin());
1845  Gpu::copy(Gpu::hostToDevice, h_havg_qc.begin(), h_havg_qc.end(), d_havg_qc.begin());
1846  }
1847 }
amrex::Gpu::DeviceVector< amrex::Real > d_havg_temperature
Definition: ERF.H:1160
amrex::Gpu::DeviceVector< amrex::Real > d_havg_qv
Definition: ERF.H:1162
amrex::Vector< amrex::Real > h_havg_pressure
Definition: ERF.H:1155
amrex::Vector< amrex::Real > h_havg_qc
Definition: ERF.H:1157
amrex::Vector< amrex::Real > h_havg_density
Definition: ERF.H:1153
amrex::Gpu::DeviceVector< amrex::Real > d_havg_qc
Definition: ERF.H:1163
amrex::Gpu::DeviceVector< amrex::Real > d_havg_density
Definition: ERF.H:1159
amrex::Vector< amrex::Real > h_havg_temperature
Definition: ERF.H:1154
amrex::Gpu::DeviceVector< amrex::Real > d_havg_pressure
Definition: ERF.H:1161
amrex::Vector< amrex::Real > h_havg_qv
Definition: ERF.H:1156
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
211 {
212  AMREX_ALWAYS_ASSERT(lev > 0);
213 
214  if (verbose) {
215  amrex::Print() <<" NEW BA FROM COARSE AT LEVEL " << lev << " " << ba << std::endl;
216  }
217 
218  //********************************************************************************************
219  // This allocates all kinds of things, including but not limited to: solution arrays,
220  // terrain arrays, metric terms and base state.
221  // *******************************************************************************************
222  init_stuff(lev, ba, dm, vars_new[lev], vars_old[lev], base_state[lev], z_phys_nd[lev]);
223 
224  t_new[lev] = time;
225  t_old[lev] = time - 1.e200;
226 
227  // ********************************************************************************************
228  // Build the data structures for metric quantities used with terrain-fitted coordinates
229  // ********************************************************************************************
230  init_zphys(lev, time);
232 
233  //
234  // Make sure that detJ and z_phys_cc are the average of the data on a finer level if there is one
235  //
236  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
237  for (int crse_lev = lev-1; crse_lev >= 0; crse_lev--) {
238  average_down( *detJ_cc[crse_lev+1], *detJ_cc[crse_lev], 0, 1, refRatio(crse_lev));
239  average_down(*z_phys_cc[crse_lev+1], *z_phys_cc[crse_lev], 0, 1, refRatio(crse_lev));
240  }
241  }
242 
243  // ********************************************************************************************
244  // Build the data structures for canopy model (depends upon z_phys)
245  // ********************************************************************************************
247  m_forest_drag[lev]->define_drag_field(ba, dm, geom[lev], z_phys_nd[lev].get());
248  }
249 
250  //********************************************************************************************
251  // Microphysics
252  // *******************************************************************************************
253  int q_size = micro->Get_Qmoist_Size(lev);
254  qmoist[lev].resize(q_size);
255  micro->Define(lev, solverChoice);
256  if (solverChoice.moisture_type != MoistureType::None)
257  {
258  micro->Init(lev, vars_new[lev][Vars::cons],
259  grids[lev], Geom(lev), 0.0,
260  z_phys_nd[lev], detJ_cc[lev]); // dummy dt value
261  }
262  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
263  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
264  }
265 
266  // *****************************************************************************************************
267  // Initialize the boundary conditions (after initializing the terrain but before calling
268  // initHSE or FillCoarsePatch)
269  // *****************************************************************************************************
270  make_physbcs(lev);
271 
272  // ********************************************************************************************
273  // Update the base state at this level by interpolation from coarser level (inside initHSE)
274  // ********************************************************************************************
275  initHSE(lev);
276 
277  // ********************************************************************************************
278  // Build the data structures for calculating diffusive/turbulent terms
279  // ********************************************************************************************
280  update_diffusive_arrays(lev, ba, dm);
281 
282  // ********************************************************************************************
283  // Fill data at the new level by interpolation from the coarser level
284  // Note that internal to FillCoarsePatch we will convert velocity to momentum,
285  // then interpolate momentum, then convert momentum back to velocity
286  // Also note that FillCoarsePatch is hard-wired to act only on lev_new at coarse and fine
287  // ********************************************************************************************
288  FillCoarsePatch(lev, time);
289 
290  // ********************************************************************************************
291  // Initialize the integrator class
292  // ********************************************************************************************
293  dt_mri_ratio[lev] = dt_mri_ratio[lev-1];
295 
296  // ********************************************************************************************
297  // If we are making a new level then the FillPatcher for this level hasn't been allocated yet
298  // ********************************************************************************************
299  if (lev > 0 && cf_width >= 0) {
302  }
303 
304 #ifdef ERF_USE_PARTICLES
305  // particleData.Redistribute();
306 #endif
307 }
void update_diffusive_arrays(int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm)
Definition: ERF_MakeNewArrays.cpp:380
void initialize_integrator(int lev, amrex::MultiFab &cons_mf, amrex::MultiFab &vel_mf)
Definition: ERF_MakeNewArrays.cpp:589
void update_terrain_arrays(int lev)
Definition: ERF_MakeNewArrays.cpp:578
void init_zphys(int lev, amrex::Real time)
Definition: ERF_MakeNewArrays.cpp:471
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:1925
bool do_forest_drag
Definition: ERF_DataStruct.H:710

◆ 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  m_factory[lev] = makeEBFabFactory(geom[lev], grids[lev], dmap[lev],
60  {nghost_eb_basic(),
62  nghost_eb_full()},
63  EBSupport::full);
64  } else {
65  // m_factory[lev] = std::make_unique<FabFactory<FArrayBox>>();
66  }
67 
68  auto& lev_new = vars_new[lev];
69  auto& lev_old = vars_old[lev];
70 
71  //********************************************************************************************
72  // This allocates all kinds of things, including but not limited to: solution arrays,
73  // terrain arrays, metric terms and base state.
74  // *******************************************************************************************
75  init_stuff(lev, ba, dm, lev_new, lev_old, base_state[lev], z_phys_nd[lev]);
76 
77  //********************************************************************************************
78  // Land Surface Model
79  // *******************************************************************************************
80  int lsm_size = lsm.Get_Data_Size();
81  lsm_data[lev].resize(lsm_size);
82  lsm_flux[lev].resize(lsm_size);
83  lsm.Define(lev, solverChoice);
84  if (solverChoice.lsm_type != LandSurfaceType::None)
85  {
86  lsm.Init(lev, vars_new[lev][Vars::cons], Geom(lev), 0.0); // dummy dt value
87  }
88  for (int mvar(0); mvar<lsm_data[lev].size(); ++mvar) {
89  lsm_data[lev][mvar] = lsm.Get_Data_Ptr(lev,mvar);
90  lsm_flux[lev][mvar] = lsm.Get_Flux_Ptr(lev,mvar);
91  }
92 
93  // ********************************************************************************************
94  // Build the data structures for calculating diffusive/turbulent terms
95  // ********************************************************************************************
96  update_diffusive_arrays(lev, ba, dm);
97 
98  // ********************************************************************************************
99  // Build the data structures for holding sea surface temps
100  // ********************************************************************************************
101  sst_lev[lev].resize(1); sst_lev[lev][0] = nullptr;
102 
103  // ********************************************************************************************
104  // Thin immersed body
105  // *******************************************************************************************
106  init_thin_body(lev, ba, dm);
107 
108  // ********************************************************************************************
109  // Initialize the integrator class
110  // ********************************************************************************************
111  initialize_integrator(lev, lev_new[Vars::cons],lev_new[Vars::xvel]);
112 
113  // ********************************************************************************************
114  // Initialize the data itself
115  // If (init_type == InitType::Real) then we are initializing terrain and the initial data in
116  // the same call so we must call init_only before update_terrain_arrays
117  // If (init_type != InitType::Real) then we want to initialize the terrain before the initial data
118  // since we may need to use the grid information before constructing
119  // initial idealized data
120  // ********************************************************************************************
121  if (restart_chkfile.empty()) {
122  if ((init_type == InitType::Real) || (init_type == InitType::Metgrid)) {
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::Real or InitType::Metgrid,
131  // make_physbcs is called inside init_only
132  init_only(lev, start_time);
133  }
134  }
135 
136  // Read in tables needed for windfarm simulations
137  // fill in Nturb multifab - number of turbines in each mesh cell
138  // write out the vtk files for wind turbine location and/or
139  // actuator disks
140  #ifdef ERF_USE_WINDFARM
141  init_windfarm(lev);
142  #endif
143 
144  // ********************************************************************************************
145  // Build the data structures for canopy model (depends upon z_phys)
146  // ********************************************************************************************
148  m_forest_drag[lev]->define_drag_field(ba, dm, geom[lev], z_phys_nd[lev].get());
149  }
150 
151  //********************************************************************************************
152  // Create wall distance field for RANS model (depends upon z_phys)
153  // *******************************************************************************************
154  if (solverChoice.turbChoice[lev].rans_type != RANSType::None) {
155  // Handle bottom boundary
156  poisson_wall_dist(lev);
157 
158  // Correct the wall distance for immersed bodies
164  geom[lev],
165  z_phys_cc[lev]);
166  }
167  }
168 
169  //********************************************************************************************
170  // Microphysics
171  // *******************************************************************************************
172  int q_size = micro->Get_Qmoist_Size(lev);
173  qmoist[lev].resize(q_size);
174  micro->Define(lev, solverChoice);
175  if (solverChoice.moisture_type != MoistureType::None)
176  {
177  micro->Init(lev, vars_new[lev][Vars::cons],
178  grids[lev], Geom(lev), 0.0,
179  z_phys_nd[lev], detJ_cc[lev]); // dummy dt value
180  }
181  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
182  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
183  }
184 
185  // ********************************************************************************************
186  // If we are making a new level then the FillPatcher for this level hasn't been allocated yet
187  // ********************************************************************************************
188  if (lev > 0 && cf_width >= 0) {
191  }
192 
193 #ifdef ERF_USE_PARTICLES
194  if (restart_chkfile.empty()) {
195  if (lev == 0) {
196  initializeTracers((ParGDBBase*)GetParGDB(),z_phys_nd);
197  } else {
198  particleData.Redistribute();
199  }
200  }
201 #endif
202 }
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
static int nghost_eb_basic()
Definition: ERF.H:1408
void init_only(int lev, amrex::Real time)
Definition: ERF.cpp:1286
void poisson_wall_dist(int lev)
Definition: ERF_PoissonWallDist.cpp:20
static int nghost_eb_volume()
Definition: ERF.H:1412
static int nghost_eb_full()
Definition: ERF.H:1415
void init_thin_body(int lev, const amrex::BoxArray &ba, const amrex::DistributionMapping &dm)
Definition: ERF_MakeNewLevel.cpp:512
int Get_Data_Size()
Definition: ERF_LandSurface.H:78
amrex::MultiFab * Get_Flux_Ptr(const int &lev, const int &varIdx)
Definition: ERF_LandSurface.H:72
void Init(const int &lev, const amrex::MultiFab &cons_in, const amrex::Geometry &geom, const amrex::Real &dt_advance)
Definition: ERF_LandSurface.H:42
void Define(const int &lev, SolverChoice &sc)
Definition: ERF_LandSurface.H:35
amrex::MultiFab * Get_Data_Ptr(const int &lev, const int &varIdx)
Definition: ERF_LandSurface.H:69
Here is the call graph for this function:

◆ nghost_eb_basic()

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

◆ nghost_eb_full()

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

◆ nghost_eb_volume()

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

◆ NumDataLogs()

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

◆ NumSampleLineLogs()

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

◆ NumSampleLines()

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

◆ NumSamplePointLogs()

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

◆ NumSamplePoints()

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

◆ operator=() [1/2]

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

◆ operator=() [2/2]

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

◆ ParameterSanityChecks()

void ERF::ParameterSanityChecks ( )
private
1682 {
1683  AMREX_ALWAYS_ASSERT(cfl > 0. || fixed_dt[0] > 0.);
1684 
1685  // We don't allow use_real_bcs to be true if init_type is not either InitType::Real or InitType::Metgrid
1686  AMREX_ALWAYS_ASSERT(!use_real_bcs || ((init_type == InitType::Real) || (init_type == InitType::Metgrid)) );
1687 
1688  AMREX_ALWAYS_ASSERT(real_width >= 0);
1689  AMREX_ALWAYS_ASSERT(real_set_width >= 0);
1690  AMREX_ALWAYS_ASSERT(real_width >= real_set_width);
1691 
1692  if (cf_width < 0 || cf_set_width < 0 || cf_width < cf_set_width) {
1693  Abort("You must set cf_width >= cf_set_width >= 0");
1694  }
1695  if (max_level > 0 && cf_set_width > 0) {
1696  for (int lev = 1; lev <= max_level; lev++) {
1697  if (cf_set_width%ref_ratio[lev-1][0] != 0 ||
1698  cf_set_width%ref_ratio[lev-1][1] != 0 ||
1699  cf_set_width%ref_ratio[lev-1][2] != 0 ) {
1700  Abort("You must set cf_width to be a multiple of ref_ratio");
1701  }
1702  }
1703  }
1704 
1705  // If fixed_mri_dt_ratio is set, it must be even
1706  if (fixed_mri_dt_ratio > 0 && (fixed_mri_dt_ratio%2 != 0) )
1707  {
1708  Abort("If you specify fixed_mri_dt_ratio, it must be even");
1709  }
1710 
1711  for (int lev = 0; lev <= max_level; lev++)
1712  {
1713  // We ignore fixed_fast_dt if not substepping
1714  if (solverChoice.substepping_type[lev] == SubsteppingType::None) {
1715  fixed_fast_dt[lev] = -1.0;
1716  }
1717 
1718  // If both fixed_dt and fast_dt are specified, their ratio must be an even integer
1719  if (fixed_dt[lev] > 0. && fixed_fast_dt[lev] > 0. && fixed_mri_dt_ratio <= 0)
1720  {
1721  Real eps = 1.e-12;
1722  int ratio = static_cast<int>( ( (1.0+eps) * fixed_dt[lev] ) / fixed_fast_dt[lev] );
1723  if (fixed_dt[lev] / fixed_fast_dt[lev] != ratio)
1724  {
1725  Abort("Ratio of fixed_dt to fixed_fast_dt must be an even integer");
1726  }
1727  }
1728 
1729  // If all three are specified, they must be consistent
1730  if (fixed_dt[lev] > 0. && fixed_fast_dt[lev] > 0. && fixed_mri_dt_ratio > 0)
1731  {
1732  if (fixed_dt[lev] / fixed_fast_dt[lev] != fixed_mri_dt_ratio)
1733  {
1734  Abort("Dt is over-specfied");
1735  }
1736  }
1737  } // lev
1738 
1739  if (solverChoice.coupling_type == CouplingType::TwoWay && cf_width > 0) {
1740  Abort("For two-way coupling you must set cf_width = 0");
1741  }
1742 }
int real_width
Definition: ERF.H:1074
int real_set_width
Definition: ERF.H:1075

◆ PlotFileName()

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

◆ PlotFileVarNames()

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

◆ poisson_wall_dist()

void ERF::poisson_wall_dist ( int  lev)

Calculate wall distances using the Poisson equation

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  MLNodeLaplacian mlpoisson(geom_tmp, ba_tmp, dm_tmp, info, {m_factory[lev].get()}, sigma);
238 
239  mlpoisson.setDomainBC(bc3d_lo, bc3d_hi);
240 
241  if (lev > 0) {
242  mlpoisson.setCoarseFineBC(nullptr, ref_ratio[lev-1], LinOpBCType::Neumann);
243  }
244 
245  mlpoisson.setLevelBC(0, nullptr);
246 
247  mlpoisson.setOversetMask(0, mask);
248 
249  // Solve
250  MLMG mlmg(mlpoisson);
251  int max_iter = 100;
252  mlmg.setMaxIter(max_iter);
253 
254  mlmg.setVerbose(mg_verbose);
255  mlmg.setBottomVerbose(0);
256 
257  mlmg.solve(GetVecOfPtrs(phi),
258  GetVecOfConstPtrs(rhs),
259  reltol, abstol);
260 
261  // Now overwrite with periodic fill outside domain and fine-fine fill inside
262  phi[0].FillBoundary(geom[lev].periodicity());
263 
264  // ****************************************************************************
265  // Compute grad(phi) to get distances
266  // - Note that phi is nodal and walldist is cell-centered
267  // - TODO: include terrain metrics for dphi/dz
268  // ****************************************************************************
269  for (MFIter mfi(*walldist[lev]); mfi.isValid(); ++mfi) {
270  const Box& bx = mfi.validbox();
271 
272  const auto invCellSize = geomdata.InvCellSizeArray();
273 
274  auto const& phi_arr = phi[0].const_array(mfi);
275  auto dist_arr = walldist[lev]->array(mfi);
276 
277  ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) {
278  Real dpdx{0}, dpdy{0}, dpdz{0};
279 
280  // dphi/dx
281  if (dom_lo.x != dom_hi.x) {
282  dpdx = 0.25 * invCellSize[0] * (
283  (phi_arr(i+1, j , k ) - phi_arr(i, j , k ))
284  + (phi_arr(i+1, j , k+1) - phi_arr(i, j , k+1))
285  + (phi_arr(i+1, j+1, k ) - phi_arr(i, j+1, k ))
286  + (phi_arr(i+1, j+1, k+1) - phi_arr(i, j+1, k+1)) );
287  }
288 
289  // dphi/dy
290  if (dom_lo.y != dom_hi.y) {
291  dpdy = 0.25 * invCellSize[1] * (
292  (phi_arr(i , j+1, k ) - phi_arr(i , j, k ))
293  + (phi_arr(i , j+1, k+1) - phi_arr(i , j, k+1))
294  + (phi_arr(i+1, j+1, k ) - phi_arr(i+1, j, k ))
295  + (phi_arr(i+1, j+1, k+1) - phi_arr(i+1, j, k+1)) );
296  }
297 
298  // dphi/dz
299  if (dom_lo.z != dom_hi.z) {
300  dpdz = 0.25 * invCellSize[2] * (
301  (phi_arr(i , j , k+1) - phi_arr(i , j , k))
302  + (phi_arr(i , j+1, k+1) - phi_arr(i , j+1, k))
303  + (phi_arr(i+1, j , k+1) - phi_arr(i+1, j , k))
304  + (phi_arr(i+1, j+1, k+1) - phi_arr(i+1, j+1, k)) );
305  }
306 
307  Real dp_dot_dp = dpdx*dpdx + dpdy*dpdy + dpdz*dpdz;
308  Real phi_avg = 0.125 * (
309  phi_arr(i , j , k ) + phi_arr(i , j , k+1) + phi_arr(i , j+1, k ) + phi_arr(i , j+1, k+1)
310  + 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) );
311  dist_arr(i, j, k) = -std::sqrt(dp_dot_dp) + std::sqrt(dp_dot_dp + 2*phi_avg);
312 
313  // DEBUG: output phi instead
314  //dist_arr(i, j, k) = phi_arr(i, j, k);
315  });
316  }
317 }
static int mg_verbose
Definition: ERF.H:1047
amrex::Real poisson_reltol
Definition: ERF_DataStruct.H:607
amrex::Real poisson_abstol
Definition: ERF_DataStruct.H:606

◆ post_timestep()

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

◆ project_velocities_tb()

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

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

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

◆ projection_has_dirichlet()

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

◆ ReadCheckpointFile()

void ERF::ReadCheckpointFile ( )

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

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

◆ ReadCheckpointFileMOST()

void ERF::ReadCheckpointFileMOST ( )

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

This is called after the ABLMost object is instantiated.

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

◆ ReadParameters()

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

◆ redistribute_term() [1/2]

void ERF::redistribute_term ( amrex::MFIter const &  mfi,
int  lev,
int  ncomp,
amrex::MultiFab &  result,
amrex::MultiFab &  result_tmp,
amrex::MultiFab const &  state,
amrex::BCRec const *  bc,
amrex::Real const  dt 
)

◆ redistribute_term() [2/2]

void ERF::redistribute_term ( int  lev,
int  ncomp,
amrex::MultiFab &  result,
amrex::MultiFab &  result_tmp,
amrex::MultiFab const &  state,
amrex::BCRec const *  bc,
amrex::Real const  dt 
)

◆ refinement_criteria_setup()

void ERF::refinement_criteria_setup ( )
private

Function to define the refinement criteria based on user input

128 {
129  if (max_level > 0)
130  {
131  ParmParse pp(pp_prefix);
132  Vector<std::string> refinement_indicators;
133  pp.queryarr("refinement_indicators",refinement_indicators,0,pp.countval("refinement_indicators"));
134 
135  for (int i=0; i<refinement_indicators.size(); ++i)
136  {
137  std::string ref_prefix = pp_prefix + "." + refinement_indicators[i];
138 
139  ParmParse ppr(ref_prefix);
140  RealBox realbox;
141  int lev_for_box;
142 
143  int num_real_lo = ppr.countval("in_box_lo");
144  int num_indx_lo = ppr.countval("in_box_lo_indices");
145 
146  if ( !((num_real_lo == AMREX_SPACEDIM && num_indx_lo == 0) ||
147  (num_indx_lo == AMREX_SPACEDIM && num_real_lo == 0) ||
148  (num_indx_lo == 0 && num_real_lo == 0)) )
149  {
150  amrex::Abort("Must only specify box for refinement using real OR index space");
151  }
152 
153  if (num_real_lo > 0) {
154  std::vector<Real> rbox_lo(3), rbox_hi(3);
155  ppr.get("max_level",lev_for_box);
156  if (lev_for_box <= max_level)
157  {
158  if (n_error_buf[0] != IntVect::TheZeroVector()) {
159  amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
160  }
161 
162  const Real* plo = geom[lev_for_box].ProbLo();
163  const Real* phi = geom[lev_for_box].ProbHi();
164 
165  ppr.getarr("in_box_lo",rbox_lo,0,AMREX_SPACEDIM);
166  ppr.getarr("in_box_hi",rbox_hi,0,AMREX_SPACEDIM);
167 
168  if (rbox_lo[0] < plo[0]) rbox_lo[0] = plo[0];
169  if (rbox_lo[1] < plo[1]) rbox_lo[1] = plo[1];
170  if (rbox_hi[0] > phi[0]) rbox_hi[0] = phi[0];
171  if (rbox_hi[1] > phi[1]) rbox_hi[1] = phi[1];
172 
173  realbox = RealBox(&(rbox_lo[0]),&(rbox_hi[0]));
174 
175  Print() << "Realbox read in and intersected laterally with domain is " << realbox << std::endl;
176 
177  num_boxes_at_level[lev_for_box] += 1;
178 
179  int ilo, jlo, klo;
180  int ihi, jhi, khi;
181  const auto* dx = geom[lev_for_box].CellSize();
182  ilo = static_cast<int>((rbox_lo[0] - plo[0])/dx[0]);
183  jlo = static_cast<int>((rbox_lo[1] - plo[1])/dx[1]);
184  ihi = static_cast<int>((rbox_hi[0] - plo[0])/dx[0]-1);
185  jhi = static_cast<int>((rbox_hi[1] - plo[1])/dx[1]-1);
186  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
187  // Search for k indices corresponding to nominal grid
188  // AGL heights
189  const Box& domain = geom[lev_for_box].Domain();
190  klo = domain.smallEnd(2) - 1;
191  khi = domain.smallEnd(2) - 1;
192 
193  if (rbox_lo[2] < zlevels_stag[lev_for_box][domain.smallEnd(2)])
194  {
195  klo = domain.smallEnd(2);
196  }
197  else
198  {
199  for (int k=domain.smallEnd(2); k<=domain.bigEnd(2)+1; ++k) {
200  if (zlevels_stag[lev_for_box][k] > rbox_lo[2]) {
201  klo = k-1;
202  break;
203  }
204  }
205  }
206  AMREX_ASSERT(klo >= domain.smallEnd(2));
207 
208  if (rbox_hi[2] > zlevels_stag[lev_for_box][domain.bigEnd(2)+1])
209  {
210  khi = domain.bigEnd(2);
211  }
212  else
213  {
214  for (int k=klo+1; k<=domain.bigEnd(2)+1; ++k) {
215  if (zlevels_stag[lev_for_box][k] > rbox_hi[2]) {
216  khi = k-1;
217  break;
218  }
219  }
220  }
221  AMREX_ASSERT((khi <= domain.bigEnd(2)) && (khi > klo));
222 
223  // Need to update realbox because tagging is based on
224  // the initial _un_deformed grid
225  realbox = RealBox(plo[0]+ ilo *dx[0], plo[1]+ jlo *dx[1], plo[2]+ klo *dx[2],
226  plo[0]+(ihi+1)*dx[0], plo[1]+(jhi+1)*dx[1], plo[2]+(khi+1)*dx[2]);
227  } else {
228  klo = static_cast<int>((rbox_lo[2] - plo[2])/dx[2]);
229  khi = static_cast<int>((rbox_hi[2] - plo[2])/dx[2]-1);
230  }
231 
232  Box bx(IntVect(ilo,jlo,klo),IntVect(ihi,jhi,khi));
233  if ( (ilo%ref_ratio[lev_for_box-1][0] != 0) || ((ihi+1)%ref_ratio[lev_for_box-1][0] != 0) ||
234  (jlo%ref_ratio[lev_for_box-1][1] != 0) || ((jhi+1)%ref_ratio[lev_for_box-1][1] != 0) ||
235  (klo%ref_ratio[lev_for_box-1][2] != 0) || ((khi+1)%ref_ratio[lev_for_box-1][2] != 0) )
236  {
237  amrex::Print() << "Box : " << bx << std::endl;
238  amrex::Print() << "RealBox : " << realbox << std::endl;
239  amrex::Print() << "ilo, ihi+1, jlo, jhi+1, klo, khi+1 by ref_ratio : "
240  << ilo%ref_ratio[lev_for_box-1][0] << " " << (ihi+1)%ref_ratio[lev_for_box-1][0] << " "
241  << jlo%ref_ratio[lev_for_box-1][1] << " " << (jhi+1)%ref_ratio[lev_for_box-1][1] << " "
242  << klo%ref_ratio[lev_for_box-1][2] << " " << (khi+1)%ref_ratio[lev_for_box-1][2] << std::endl;
243  amrex::Error("Fine box is not legit with this ref_ratio");
244  }
245  boxes_at_level[lev_for_box].push_back(bx);
246  Print() << "Saving in 'boxes at level' as " << bx << std::endl;
247  } // lev
248  if (init_type == InitType::Real || init_type == InitType::Metgrid) {
249  if (num_boxes_at_level[lev_for_box] != num_files_at_level[lev_for_box]) {
250  amrex::Error("Number of boxes doesn't match number of input files");
251 
252  }
253  }
254 
255  } else if (num_indx_lo > 0) {
256 
257  std::vector<int> box_lo(3), box_hi(3);
258  ppr.get("max_level",lev_for_box);
259  if (lev_for_box <= max_level)
260  {
261  if (n_error_buf[0] != IntVect::TheZeroVector()) {
262  amrex::Abort("Don't use n_error_buf > 0 when setting the box explicitly");
263  }
264 
265  ppr.getarr("in_box_lo_indices",box_lo,0,AMREX_SPACEDIM);
266  ppr.getarr("in_box_hi_indices",box_hi,0,AMREX_SPACEDIM);
267 
268  Box bx(IntVect(box_lo[0],box_lo[1],box_lo[2]),IntVect(box_hi[0],box_hi[1],box_hi[2]));
269  amrex::Print() << "BOX " << bx << std::endl;
270 
271  const auto* dx = geom[lev_for_box].CellSize();
272  const Real* plo = geom[lev_for_box].ProbLo();
273  realbox = RealBox(plo[0]+ box_lo[0] *dx[0], plo[1]+ box_lo[1] *dx[1], plo[2]+ box_lo[2] *dx[2],
274  plo[0]+(box_hi[0]+1)*dx[0], plo[1]+(box_hi[1]+1)*dx[1], plo[2]+(box_hi[2]+1)*dx[2]);
275 
276  Print() << "Reading " << bx << " at level " << lev_for_box << std::endl;
277  num_boxes_at_level[lev_for_box] += 1;
278 
279  if ( (box_lo[0]%ref_ratio[lev_for_box-1][0] != 0) || ((box_hi[0]+1)%ref_ratio[lev_for_box-1][0] != 0) ||
280  (box_lo[1]%ref_ratio[lev_for_box-1][1] != 0) || ((box_hi[1]+1)%ref_ratio[lev_for_box-1][1] != 0) ||
281  (box_lo[2]%ref_ratio[lev_for_box-1][2] != 0) || ((box_hi[2]+1)%ref_ratio[lev_for_box-1][2] != 0) )
282  amrex::Error("Fine box is not legit with this ref_ratio");
283  boxes_at_level[lev_for_box].push_back(bx);
284  Print() << "Saving in 'boxes at level' as " << bx << std::endl;
285  } // lev
286  if (init_type == InitType::Real || init_type == InitType::Metgrid) {
287  if (num_boxes_at_level[lev_for_box] != num_files_at_level[lev_for_box]) {
288  amrex::Error("Number of boxes doesn't match number of input files");
289 
290  }
291  }
292  }
293 
294  AMRErrorTagInfo info;
295 
296  if (realbox.ok()) {
297  info.SetRealBox(realbox);
298  }
299  if (ppr.countval("start_time") > 0) {
300  Real ref_min_time; ppr.get("start_time",ref_min_time);
301  info.SetMinTime(ref_min_time);
302  }
303  if (ppr.countval("end_time") > 0) {
304  Real ref_max_time; ppr.get("end_time",ref_max_time);
305  info.SetMaxTime(ref_max_time);
306  }
307  if (ppr.countval("max_level") > 0) {
308  int ref_max_level; ppr.get("max_level",ref_max_level);
309  info.SetMaxLevel(ref_max_level);
310  }
311 
312  if (ppr.countval("value_greater")) {
313  int num_val = ppr.countval("value_greater");
314  Vector<Real> value(num_val);
315  ppr.getarr("value_greater",value,0,num_val);
316  std::string field; ppr.get("field_name",field);
317  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::GREATER,field,info));
318  }
319  else if (ppr.countval("value_less")) {
320  int num_val = ppr.countval("value_less");
321  Vector<Real> value(num_val);
322  ppr.getarr("value_less",value,0,num_val);
323  std::string field; ppr.get("field_name",field);
324  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::LESS,field,info));
325  }
326  else if (ppr.countval("adjacent_difference_greater")) {
327  int num_val = ppr.countval("adjacent_difference_greater");
328  Vector<Real> value(num_val);
329  ppr.getarr("adjacent_difference_greater",value,0,num_val);
330  std::string field; ppr.get("field_name",field);
331  ref_tags.push_back(AMRErrorTag(value,AMRErrorTag::GRAD,field,info));
332  }
333  else if (realbox.ok())
334  {
335  ref_tags.push_back(AMRErrorTag(info));
336  } else {
337  Abort(std::string("Unrecognized refinement indicator for " + refinement_indicators[i]).c_str());
338  }
339  } // loop over criteria
340  } // if max_level > 0
341 }
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 
)
544 {
545  if (lev > 0 && SolverChoice::mesh_type == MeshType::VariableDz)
546  {
547  //
548  // First interpolate from coarser level
549  // NOTE: this interpolater assumes that ALL ghost cells of the coarse MultiFab
550  // have been pre-filled - this includes ghost cells both inside and outside
551  // the domain
552  //
553  InterpFromCoarseLevel(*temp_zphys_nd, z_phys_nd[lev]->nGrowVect(),
554  IntVect(0,0,0), // do not fill ghost cells outside the domain
555  *z_phys_nd[lev-1], 0, 0, 1,
556  geom[lev-1], geom[lev],
557  refRatio(lev-1), &node_bilinear_interp,
559 
560  // This recomputes the fine values using the bottom terrain at the fine resolution,
561  // and also fills values of z_phys_nd outside the domain
563 
564  std::swap(temp_zphys_nd, z_phys_nd[lev]);
565 
566  } // use_terrain && lev > 0
567 
568  if (solverChoice.terrain_type == TerrainType::ImmersedForcing) {
569  //
570  // This assumes we have already remade the EBGeometry
571  //
572  terrain_blanking[lev]->setVal(1.0);
573  MultiFab::Subtract(*terrain_blanking[lev], EBFactory(lev).getVolFrac(), 0, 0, 1, 0);
574  }
575 }
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
315 {
316  if (verbose) {
317  amrex::Print() <<" REMAKING WITH NEW BA AT LEVEL " << lev << " " << ba << std::endl;
318  }
319 
320  AMREX_ALWAYS_ASSERT(lev > 0);
321  AMREX_ALWAYS_ASSERT(solverChoice.terrain_type != TerrainType::MovingFittedMesh);
322 
323  BoxArray ba_old(vars_new[lev][Vars::cons].boxArray());
324  DistributionMapping dm_old(vars_new[lev][Vars::cons].DistributionMap());
325 
326  if (verbose) {
327  amrex::Print() <<" OLD BA AT LEVEL " << lev << " " << ba_old << std::endl;
328  }
329 
330  int ncomp_cons = vars_new[lev][Vars::cons].nComp();
331  IntVect ngrow_state = vars_new[lev][Vars::cons].nGrowVect();
332 
334 
335  Vector<MultiFab> temp_lev_new(Vars::NumTypes);
336  Vector<MultiFab> temp_lev_old(Vars::NumTypes);
337  MultiFab temp_base_state;
338 
339  std::unique_ptr<MultiFab> temp_zphys_nd;
340 
341  //********************************************************************************************
342  // This allocates all kinds of things, including but not limited to: solution arrays,
343  // terrain arrays and metrics, and base state.
344  // *******************************************************************************************
345  init_stuff(lev, ba, dm, temp_lev_new, temp_lev_old, temp_base_state, temp_zphys_nd);
346 
347  // ********************************************************************************************
348  // Build the data structures for terrain-related quantities
349  // ********************************************************************************************
350  remake_zphys(lev, time, temp_zphys_nd);
352 
353  //
354  // Make sure that detJ and z_phys_cc are the average of the data on a finer level if there is one
355  //
356  if (SolverChoice::mesh_type != MeshType::ConstantDz) {
357  for (int crse_lev = lev-1; crse_lev >= 0; crse_lev--) {
358  average_down( *detJ_cc[crse_lev+1], *detJ_cc[crse_lev], 0, 1, refRatio(crse_lev));
359  average_down(*z_phys_cc[crse_lev+1], *z_phys_cc[crse_lev], 0, 1, refRatio(crse_lev));
360  }
361  }
362 
363  // ********************************************************************************************
364  // Build the data structures for canopy model (depends upon z_phys)
365  // ********************************************************************************************
367  m_forest_drag[lev]->define_drag_field(ba, dm, geom[lev], z_phys_nd[lev].get());
368  }
369 
370  // *****************************************************************************************************
371  // Create the physbcs objects (after initializing the terrain but before calling FillCoarsePatch
372  // *****************************************************************************************************
373  make_physbcs(lev);
374 
375  // ********************************************************************************************
376  // Update the base state at this level by interpolation from coarser level AND copy
377  // from previous (pre-regrid) base_state array
378  // ********************************************************************************************
379  Interpolater* mapper = &cell_cons_interp;
380 
381  Vector<MultiFab*> fmf = {&base_state[lev ], &base_state[lev ]};
382  Vector<MultiFab*> cmf = {&base_state[lev-1], &base_state[lev-1]};
383  Vector<Real> ftime = {time, time};
384  Vector<Real> ctime = {time, time};
385 
386  // Call FillPatch which ASSUMES that all ghost cells at lev-1 have already been filled
387  FillPatchTwoLevels(temp_base_state, temp_base_state.nGrowVect(), IntVect(0,0,0),
388  time, cmf, ctime, fmf, ftime,
389  0, 0, temp_base_state.nComp(), geom[lev-1], geom[lev],
390  refRatio(lev-1), mapper, domain_bcs_type,
392 
393  // Impose bc's outside the domain
394  (*physbcs_base[lev])(temp_base_state,0,temp_base_state.nComp(),base_state[lev].nGrowVect());
395 
396  // *************************************************************************************************
397  // This will fill the temporary MultiFabs with data from vars_new
398  // NOTE: the momenta here are only used as scratch space, the momenta themselves are not fillpatched
399  // NOTE: we must create the new base state before calling FillPatch because we will
400  // interpolate perturbational quantities
401  // *************************************************************************************************
402  FillPatch(lev, time, {&temp_lev_new[Vars::cons],&temp_lev_new[Vars::xvel],
403  &temp_lev_new[Vars::yvel],&temp_lev_new[Vars::zvel]},
404  {&temp_lev_new[Vars::cons],&rU_new[lev],&rV_new[lev],&rW_new[lev]},
405  base_state[lev], temp_base_state, false);
406 
407  // Now swap the pointers since we needed both old and new in the FillPatch
408  std::swap(temp_base_state, base_state[lev]);
409 
410  // ********************************************************************************************
411  // Copy from new into old just in case
412  // ********************************************************************************************
413  MultiFab::Copy(temp_lev_old[Vars::cons],temp_lev_new[Vars::cons],0,0,ncomp_cons,ngrow_state);
414  MultiFab::Copy(temp_lev_old[Vars::xvel],temp_lev_new[Vars::xvel],0,0, 1,ngrow_vels);
415  MultiFab::Copy(temp_lev_old[Vars::yvel],temp_lev_new[Vars::yvel],0,0, 1,ngrow_vels);
416  MultiFab::Copy(temp_lev_old[Vars::zvel],temp_lev_new[Vars::zvel],0,0, 1,IntVect(ngrow_vels,ngrow_vels,0));
417 
418  // ********************************************************************************************
419  // Now swap the pointers
420  // ********************************************************************************************
421  for (int var_idx = 0; var_idx < Vars::NumTypes; ++var_idx) {
422  std::swap(temp_lev_new[var_idx], vars_new[lev][var_idx]);
423  std::swap(temp_lev_old[var_idx], vars_old[lev][var_idx]);
424  }
425 
426  t_new[lev] = time;
427  t_old[lev] = time - 1.e200;
428 
429  // ********************************************************************************************
430  // Build the data structures for calculating diffusive/turbulent terms
431  // ********************************************************************************************
432  update_diffusive_arrays(lev, ba, dm);
433 
434  //********************************************************************************************
435  // Microphysics
436  // *******************************************************************************************
437  int q_size = micro->Get_Qmoist_Size(lev);
438  qmoist[lev].resize(q_size);
439  micro->Define(lev, solverChoice);
440  if (solverChoice.moisture_type != MoistureType::None)
441  {
442  micro->Init(lev, vars_new[lev][Vars::cons],
443  grids[lev], Geom(lev), 0.0,
444  z_phys_nd[lev], detJ_cc[lev]); // dummy dt value
445  }
446  for (int mvar(0); mvar<qmoist[lev].size(); ++mvar) {
447  qmoist[lev][mvar] = micro->Get_Qmoist_Ptr(lev,mvar);
448  }
449 
450  // ********************************************************************************************
451  // Initialize the integrator class
452  // ********************************************************************************************
454 
455  // We need to re-define the FillPatcher if the grids have changed
456  if (lev > 0 && cf_width >= 0) {
457  bool ba_changed = (ba != ba_old);
458  bool dm_changed = (dm != dm_old);
459  if (ba_changed || dm_changed) {
461  }
462  }
463 
464 #ifdef ERF_USE_PARTICLES
465  particleData.Redistribute();
466 #endif
467 }
void remake_zphys(int lev, amrex::Real time, std::unique_ptr< amrex::MultiFab > &temp_zphys_nd)
Definition: ERF_MakeNewArrays.cpp:543

◆ restart()

void ERF::restart ( )
1267 {
1268 #ifdef ERF_USE_NETCDF
1269  if (restart_type == "netcdf") {
1270  ReadNCCheckpointFile();
1271  }
1272 #endif
1273  if (restart_type == "native") {
1275  }
1276 
1277  // We set this here so that we don't over-write the checkpoint file we just started from
1279 }
void ReadCheckpointFile()
Definition: ERF_Checkpoint.cpp:273

◆ sample_lines()

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

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

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

◆ sample_points()

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

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

Parameters
levLevel for the associated MultiFab data
timeCurrent time
cellIntVect containing the indexes for the cell where we want to sample
mfMultiFab from which we wish to sample data
250 {
251  int datwidth = 14;
252 
253  int ifile = 0;
254 
255  //
256  // Sample the data at a single point in space
257  //
258  int ncomp = mf.nComp();
259  Vector<Real> my_point = get_cell_data(mf, cell);
260 
261  if (!my_point.empty()) {
262 
263  // HERE DO WHATEVER YOU WANT TO THE DATA BEFORE WRITING
264 
265  std::ostream& sample_log = SamplePointLog(ifile);
266  if (sample_log.good()) {
267  sample_log << std::setw(datwidth) << time;
268  for (int i = 0; i < ncomp; ++i)
269  {
270  sample_log << std::setw(datwidth) << my_point[i];
271  }
272  sample_log << std::endl;
273  } // if good
274  } // only write from processor that holds the cell
275 }
AMREX_FORCE_INLINE std::ostream & SamplePointLog(int i)
Definition: ERF.H:1256

◆ SampleLine()

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

◆ SampleLineLog()

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

◆ SampleLineLogName()

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

The filename of the ith samplelinelog file.

1396 { return samplelinelogname[i]; }

◆ SamplePoint()

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

◆ SamplePointLog()

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

◆ SamplePointLogName()

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

The filename of the ith sampleptlog file.

1393 { return sampleptlogname[i]; }

◆ setPlotVariables()

void ERF::setPlotVariables ( const std::string &  pp_plot_var_names,
amrex::Vector< std::string > &  plot_var_names 
)
private
18 {
19  ParmParse pp(pp_prefix);
20 
21  if (pp.contains(pp_plot_var_names.c_str()))
22  {
23  std::string nm;
24 
25  int nPltVars = pp.countval(pp_plot_var_names.c_str());
26 
27  for (int i = 0; i < nPltVars; i++)
28  {
29  pp.get(pp_plot_var_names.c_str(), nm, i);
30 
31  // Add the named variable to our list of plot variables
32  // if it is not already in the list
33  if (!containerHasElement(plot_var_names, nm)) {
34  plot_var_names.push_back(nm);
35  }
36  }
37  } else {
38  //
39  // The default is to add none of the variables to the list
40  //
41  plot_var_names.clear();
42  }
43 
44  // Get state variables in the same order as we define them,
45  // since they may be in any order in the input list
46  Vector<std::string> tmp_plot_names;
47 
48  for (int i = 0; i < cons_names.size(); ++i) {
49  if ( containerHasElement(plot_var_names, cons_names[i]) ) {
50  if ( (solverChoice.moisture_type == MoistureType::SAM) || (cons_names[i] != "rhoQ4" &&
51  cons_names[i] != "rhoQ5" &&
52  cons_names[i] != "rhoQ6") )
53  {
54  tmp_plot_names.push_back(cons_names[i]);
55  } // moisture_type
56  }
57  }
58 
59  // check for velocity since it's not in cons_names
60  // if we are asked for any velocity component, we will need them all
61  if (containerHasElement(plot_var_names, "x_velocity") ||
62  containerHasElement(plot_var_names, "y_velocity") ||
63  containerHasElement(plot_var_names, "z_velocity")) {
64  tmp_plot_names.push_back("x_velocity");
65  tmp_plot_names.push_back("y_velocity");
66  tmp_plot_names.push_back("z_velocity");
67  }
68 
69  //
70  // If the model we are running doesn't have the variable listed in the inputs file,
71  // just ignore it rather than aborting
72  //
73  for (int i = 0; i < derived_names.size(); ++i) {
74  if ( containerHasElement(plot_var_names, derived_names[i]) ) {
75  if ( SolverChoice::mesh_type != MeshType::ConstantDz ||
76  (derived_names[i] != "z_phys" && derived_names[i] != "detJ") ) {
77  if ( (solverChoice.moisture_type == MoistureType::SAM ||
78  solverChoice.moisture_type == MoistureType::SAM_NoIce) ||
79  (derived_names[i] != "qi" &&
80  derived_names[i] != "qsnow" &&
81  derived_names[i] != "qgraup" &&
82  derived_names[i] != "snow_accum" &&
83  derived_names[i] != "graup_accum") )
84  {
85  if ( (solverChoice.moisture_type != MoistureType::None) ||
86  (derived_names[i] != "qv" && derived_names[i] != "qc" and
87  derived_names[i] != "num_turb" and derived_names[i] != "SMark0" and
88  derived_names[i] != "SMark1") ) {
89  tmp_plot_names.push_back(derived_names[i]);
90  }
91  } // moisture_type
92  } // use_terrain?
93  } // hasElement
94  }
95 
96 #ifdef ERF_USE_WINDFARM
97  for (int i = 0; i < derived_names.size(); ++i) {
98  if ( containerHasElement(plot_var_names, derived_names[i]) ) {
99  if(solverChoice.windfarm_type == WindFarmType::Fitch or solverChoice.windfarm_type == WindFarmType::EWP) {
100  if(derived_names[i] == "num_turb" or derived_names[i] == "SMark0") {
101  tmp_plot_names.push_back(derived_names[i]);
102  }
103  }
104  if( solverChoice.windfarm_type == WindFarmType::SimpleAD or
105  solverChoice.windfarm_type == WindFarmType::GeneralAD ) {
106  if(derived_names[i] == "num_turb" or derived_names[i] == "SMark0" or derived_names[i] == "SMark1") {
107  tmp_plot_names.push_back(derived_names[i]);
108  }
109  }
110  }
111  }
112 #endif
113 
114 #ifdef ERF_USE_PARTICLES
115  const auto& particles_namelist( particleData.getNamesUnalloc() );
116  for (auto it = particles_namelist.cbegin(); it != particles_namelist.cend(); ++it) {
117  std::string tmp( (*it)+"_count" );
118  if (containerHasElement(plot_var_names, tmp) ) {
119  tmp_plot_names.push_back(tmp);
120  }
121  }
122 #endif
123 
124  plot_var_names = tmp_plot_names;
125 }
const amrex::Vector< std::string > derived_names
Definition: ERF.H:973
const amrex::Vector< std::string > cons_names
Definition: ERF.H:968
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
1327  {
1328  if (amrex::ParallelDescriptor::IOProcessor())
1329  {
1330  datalog[i] = std::make_unique<std::fstream>();
1331  datalog[i]->open(filename.c_str(),std::ios::out|std::ios::app);
1332  if (!datalog[i]->good()) {
1333  amrex::FileOpenFailed(filename);
1334  }
1335  }
1336  amrex::ParallelDescriptor::Barrier("ERF::setRecordDataInfo");
1337  }

◆ setRecordSampleLineInfo()

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

◆ setRecordSamplePointInfo()

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

◆ 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(), *m_factory[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_integrated_quantities()

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

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

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

◆ timeStep()

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

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

Parameters
[in]levlevel of refinement (coarsest level is 0)
[in]timestart time for time advance
[in]iterationtime step counter
17 {
18  //
19  // We need to FillPatch the coarse level before assessing whether to regrid
20  // We have not done the swap yet so we fill the "new" which will become the "old"
21  //
22  MultiFab& S_new = vars_new[lev][Vars::cons];
23  MultiFab& U_new = vars_new[lev][Vars::xvel];
24  MultiFab& V_new = vars_new[lev][Vars::yvel];
25  MultiFab& W_new = vars_new[lev][Vars::zvel];
26 
27  //
28  // NOTE: the momenta here are not fillpatched (they are only used as scratch space)
29  //
30  if (lev == 0) {
31  FillPatch(lev, time, {&S_new, &U_new, &V_new, &W_new});
32  } else if (lev < finest_level) {
33  FillPatch(lev, time, {&S_new, &U_new, &V_new, &W_new},
34  {&S_new, &rU_new[lev], &rV_new[lev], &rW_new[lev]},
35  base_state[lev], base_state[lev]);
36  }
37 
38  if (regrid_int > 0) // We may need to regrid
39  {
40  // help keep track of whether a level was already regridded
41  // from a coarser level call to regrid
42  static Vector<int> last_regrid_step(max_level+1, 0);
43 
44  // regrid changes level "lev+1" so we don't regrid on max_level
45  // also make sure we don't regrid fine levels again if
46  // it was taken care of during a coarser regrid
47  if (lev < max_level)
48  {
49  if ( (istep[lev] % regrid_int == 0) && (istep[lev] > last_regrid_step[lev]) )
50  {
51  // regrid could add newly refine levels (if finest_level < max_level)
52  // so we save the previous finest level index
53  int old_finest = finest_level;
54 
55  regrid(lev, time);
56 
57 #ifdef ERF_USE_PARTICLES
58  if (finest_level != old_finest) {
59  particleData.Redistribute();
60  }
61 #endif
62 
63  // mark that we have regridded this level already
64  for (int k = lev; k <= finest_level; ++k) {
65  last_regrid_step[k] = istep[k];
66  }
67 
68  // if there are newly created levels, set the time step
69  for (int k = old_finest+1; k <= finest_level; ++k) {
70  dt[k] = dt[k-1] / MaxRefRatio(k-1);
71  }
72  } // if
73  } // lev
74  }
75 
76  // Update what we call "old" and "new" time
77  t_old[lev] = t_new[lev];
78  t_new[lev] += dt[lev];
79 
80  if (Verbose()) {
81  amrex::Print() << "[Level " << lev << " step " << istep[lev]+1 << "] ";
82  amrex::Print() << "ADVANCE from time = " << t_old[lev] << " to " << t_new[lev]
83  << " with dt = " << dt[lev] << std::endl;
84  }
85 
86 #ifdef ERF_USE_WW3_COUPLING
87  amrex::Print() << " About to call send_to_ww3 from ERF_Timestep" << std::endl;
88  send_to_ww3(lev);
89  amrex::Print() << " About to call read_waves from ERF_Timestep" << std::endl;
90  read_waves(lev);
91  //send_to_ww3(lev);
92  //read_waves(lev);
93  //send_to_ww3(lev);
94 #endif
95 
96  // Advance a single level for a single time step
97  Advance(lev, time, dt[lev], istep[lev], nsubsteps[lev]);
98 
99  ++istep[lev];
100 
101  if (Verbose()) {
102  amrex::Print() << "[Level " << lev << " step " << istep[lev] << "] ";
103  amrex::Print() << "Advanced " << CountCells(lev) << " cells" << std::endl;
104  }
105 
106  if (lev < finest_level)
107  {
108  // recursive call for next-finer level
109  for (int i = 1; i <= nsubsteps[lev+1]; ++i)
110  {
111  Real strt_time_for_fine = time + (i-1)*dt[lev+1];
112  timeStep(lev+1, strt_time_for_fine, i);
113  }
114  }
115 
116  if (verbose && lev == 0) {
117  if (solverChoice.moisture_type != MoistureType::None) {
118  amrex::Print() << "Cloud fraction " << time << " " << cloud_fraction(time) << std::endl;
119  }
120  }
121 }
amrex::Real cloud_fraction(amrex::Real time)
Definition: ERF_WriteScalarProfiles.cpp:173
void Advance(int lev, amrex::Real time, amrex::Real dt_lev, int iteration, int ncycle)
Definition: ERF_Advance.cpp:20

◆ turbPert_amplitude()

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

◆ turbPert_update()

void ERF::turbPert_update ( const int  lev,
const amrex::Real  dt 
)
private
13 {
14  // Accessing data
15  auto& lev_new = vars_new[lev];
16 
17  // Create aliases to state data to pass to calc_tpi_update
18  int ncons = lev_new[Vars::cons].nComp();
19  MultiFab cons_data(lev_new[Vars::cons], make_alias, 0, ncons);
20  MultiFab xvel_data(lev_new[Vars::xvel], make_alias, 0, 1);
21  MultiFab yvel_data(lev_new[Vars::yvel], make_alias, 0, 1);
22 
23  // This logic is done once then stored within ERF_TurbPertStruct.H
24  turbPert.pt_type = -1;
25  if (solverChoice.pert_type == PerturbationType::Source) {
26  turbPert.pt_type = 0;
27  } else if (solverChoice.pert_type == PerturbationType::Direct) {
28  turbPert.pt_type = 1;
29  }
30  AMREX_ALWAYS_ASSERT(turbPert.pt_type >= 0);
31 
32  // Computing perturbation update time
33  turbPert.calc_tpi_update(lev, local_dt, xvel_data, yvel_data, cons_data);
34 
35  Print() << "Successfully initialized turbulent perturbation update time and amplitude with type: "<< turbPert.pt_type <<"\n";
36 }
int pt_type
Definition: ERF_TurbPertStruct.H:528

◆ update_diffusive_arrays()

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

◆ update_terrain_arrays()

void ERF::update_terrain_arrays ( int  lev)
579 {
580  if (SolverChoice::mesh_type == MeshType::StretchedDz ||
581  SolverChoice::mesh_type == MeshType::VariableDz) {
582  make_J(geom[lev],*z_phys_nd[lev],*detJ_cc[lev]);
583  make_areas(geom[lev],*z_phys_nd[lev],*ax[lev],*ay[lev],*az[lev]);
584  make_zcc(geom[lev],*z_phys_nd[lev],*z_phys_cc[lev]);
585  }
586 }
void make_areas(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &ax, MultiFab &ay, MultiFab &az)
Definition: ERF_TerrainMetrics.cpp:629
void make_J(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &detJ_cc)
Definition: ERF_TerrainMetrics.cpp:591
Here is the call graph for this function:

◆ volWgtSumMF()

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

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

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

◆ write_1D_profiles()

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

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

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

◆ write_1D_profiles_stag()

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

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

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

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

◆ writeBuildInfo()

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

Referenced by main().

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

◆ WriteCheckpointFile()

void ERF::WriteCheckpointFile ( ) const

ERF function for writing a checkpoint file.

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

◆ WriteGenericPlotfileHeaderWithTerrain()

void ERF::WriteGenericPlotfileHeaderWithTerrain ( std::ostream &  HeaderFile,
int  nlevels,
const amrex::Vector< amrex::BoxArray > &  bArray,
const amrex::Vector< std::string > &  varnames,
const amrex::Vector< amrex::Geometry > &  my_geom,
amrex::Real  time,
const amrex::Vector< int > &  level_steps,
const amrex::Vector< amrex::IntVect > &  my_ref_ratio,
const std::string &  versionName,
const std::string &  levelPrefix,
const std::string &  mfPrefix 
) const
1702 {
1703  AMREX_ALWAYS_ASSERT(nlevels <= bArray.size());
1704  AMREX_ALWAYS_ASSERT(nlevels <= my_ref_ratio.size()+1);
1705  AMREX_ALWAYS_ASSERT(nlevels <= level_steps.size());
1706 
1707  HeaderFile.precision(17);
1708 
1709  // ---- this is the generic plot file type name
1710  HeaderFile << versionName << '\n';
1711 
1712  HeaderFile << varnames.size() << '\n';
1713 
1714  for (int ivar = 0; ivar < varnames.size(); ++ivar) {
1715  HeaderFile << varnames[ivar] << "\n";
1716  }
1717  HeaderFile << AMREX_SPACEDIM << '\n';
1718  HeaderFile << my_time << '\n';
1719  HeaderFile << finest_level << '\n';
1720  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
1721  HeaderFile << my_geom[0].ProbLo(i) << ' ';
1722  }
1723  HeaderFile << '\n';
1724  for (int i = 0; i < AMREX_SPACEDIM; ++i) {
1725  HeaderFile << my_geom[0].ProbHi(i) << ' ';
1726  }
1727  HeaderFile << '\n';
1728  for (int i = 0; i < finest_level; ++i) {
1729  HeaderFile << my_ref_ratio[i][0] << ' ';
1730  }
1731  HeaderFile << '\n';
1732  for (int i = 0; i <= finest_level; ++i) {
1733  HeaderFile << my_geom[i].Domain() << ' ';
1734  }
1735  HeaderFile << '\n';
1736  for (int i = 0; i <= finest_level; ++i) {
1737  HeaderFile << level_steps[i] << ' ';
1738  }
1739  HeaderFile << '\n';
1740  for (int i = 0; i <= finest_level; ++i) {
1741  for (int k = 0; k < AMREX_SPACEDIM; ++k) {
1742  HeaderFile << my_geom[i].CellSize()[k] << ' ';
1743  }
1744  HeaderFile << '\n';
1745  }
1746  HeaderFile << (int) my_geom[0].Coord() << '\n';
1747  HeaderFile << "0\n";
1748 
1749  for (int level = 0; level <= finest_level; ++level) {
1750  HeaderFile << level << ' ' << bArray[level].size() << ' ' << my_time << '\n';
1751  HeaderFile << level_steps[level] << '\n';
1752 
1753  const IntVect& domain_lo = my_geom[level].Domain().smallEnd();
1754  for (int i = 0; i < bArray[level].size(); ++i)
1755  {
1756  // Need to shift because the RealBox ctor we call takes the
1757  // physical location of index (0,0,0). This does not affect
1758  // the usual cases where the domain index starts with 0.
1759  const Box& b = shift(bArray[level][i], -domain_lo);
1760  RealBox loc = RealBox(b, my_geom[level].CellSize(), my_geom[level].ProbLo());
1761  for (int n = 0; n < AMREX_SPACEDIM; ++n) {
1762  HeaderFile << loc.lo(n) << ' ' << loc.hi(n) << '\n';
1763  }
1764  }
1765 
1766  HeaderFile << MultiFabHeaderPath(level, levelPrefix, mfPrefix) << '\n';
1767  }
1768  HeaderFile << "1" << "\n";
1769  HeaderFile << "3" << "\n";
1770  HeaderFile << "amrexvec_nu_x" << "\n";
1771  HeaderFile << "amrexvec_nu_y" << "\n";
1772  HeaderFile << "amrexvec_nu_z" << "\n";
1773  std::string mf_nodal_prefix = "Nu_nd";
1774  for (int level = 0; level <= finest_level; ++level) {
1775  HeaderFile << MultiFabHeaderPath(level, levelPrefix, mf_nodal_prefix) << '\n';
1776  }
1777 }
Coord
Definition: ERF_DataStruct.H:64

◆ writeJobInfo()

void ERF::writeJobInfo ( const std::string &  dir) const
10 {
11  // job_info file with details about the run
12  std::ofstream jobInfoFile;
13  std::string FullPathJobInfoFile = dir;
14  FullPathJobInfoFile += "/job_info";
15  jobInfoFile.open(FullPathJobInfoFile.c_str(), std::ios::out);
16 
17  std::string PrettyLine = "==================================================="
18  "============================\n";
19  std::string OtherLine = "----------------------------------------------------"
20  "----------------------------\n";
21  std::string SkipSpace = " ";
22 
23  // job information
24  jobInfoFile << PrettyLine;
25  jobInfoFile << " ERF Job Information\n";
26  jobInfoFile << PrettyLine;
27 
28  jobInfoFile << "inputs file: " << inputs_name << "\n\n";
29 
30  jobInfoFile << "number of MPI processes: "
31  << ParallelDescriptor::NProcs() << "\n";
32 #ifdef _OPENMP
33  jobInfoFile << "number of threads: " << omp_get_max_threads() << "\n";
34 #endif
35 
36  jobInfoFile << "\n";
37  jobInfoFile << "CPU time used since start of simulation (CPU-hours): "
38  << getCPUTime() / 3600.0;
39 
40  jobInfoFile << "\n\n";
41 
42  // plotfile information
43  jobInfoFile << PrettyLine;
44  jobInfoFile << " Plotfile Information\n";
45  jobInfoFile << PrettyLine;
46 
47  time_t now = time(nullptr);
48 
49  // Convert now to tm struct for local timezone
50  tm* localtm = localtime(&now);
51  jobInfoFile << "output data / time: " << asctime(localtm);
52 
53  std::string currentDir = FileSystem::CurrentPath();
54  jobInfoFile << "output dir: " << currentDir << "\n";
55 
56  jobInfoFile << "\n\n";
57 
58  // build information
59  jobInfoFile << PrettyLine;
60  jobInfoFile << " Build Information\n";
61  jobInfoFile << PrettyLine;
62 
63  jobInfoFile << "build date: " << buildInfoGetBuildDate() << "\n";
64  jobInfoFile << "build machine: " << buildInfoGetBuildMachine() << "\n";
65  jobInfoFile << "build dir: " << buildInfoGetBuildDir() << "\n";
66  jobInfoFile << "AMReX dir: " << buildInfoGetAMReXDir() << "\n";
67 
68  jobInfoFile << "\n";
69 
70  jobInfoFile << "COMP: " << buildInfoGetComp() << "\n";
71  jobInfoFile << "COMP version: " << buildInfoGetCompVersion() << "\n";
72 
73  jobInfoFile << "\n";
74 
75  for (int n = 1; n <= buildInfoGetNumModules(); n++) {
76  jobInfoFile << buildInfoGetModuleName(n) << ": "
77  << buildInfoGetModuleVal(n) << "\n";
78  }
79 
80  jobInfoFile << "\n";
81 
82  const char* githash1 = buildInfoGetGitHash(1);
83  const char* githash2 = buildInfoGetGitHash(2);
84  if (strlen(githash1) > 0) {
85  jobInfoFile << "ERF git hash: " << githash1 << "\n";
86  }
87  if (strlen(githash2) > 0) {
88  jobInfoFile << "AMReX git hash: " << githash2 << "\n";
89  }
90 
91  const char* buildgithash = buildInfoGetBuildGitHash();
92  const char* buildgitname = buildInfoGetBuildGitName();
93  if (strlen(buildgithash) > 0) {
94  jobInfoFile << buildgitname << " git hash: " << buildgithash << "\n";
95  }
96 
97  jobInfoFile << "\n\n";
98 
99  // grid information
100  jobInfoFile << PrettyLine;
101  jobInfoFile << " Grid Information\n";
102  jobInfoFile << PrettyLine;
103 
104  int f_lev = finest_level;
105 
106  for (int i = 0; i <= f_lev; i++) {
107  jobInfoFile << " level: " << i << "\n";
108  jobInfoFile << " number of boxes = " << grids[i].size() << "\n";
109  jobInfoFile << " maximum zones = ";
110  for (int n = 0; n < AMREX_SPACEDIM; n++) {
111  jobInfoFile << geom[i].Domain().length(n) << " ";
112  }
113  jobInfoFile << "\n\n";
114  }
115 
116  jobInfoFile << " Boundary conditions\n";
117 
118  jobInfoFile << " -x: " << domain_bc_type[0] << "\n";
119  jobInfoFile << " +x: " << domain_bc_type[3] << "\n";
120  jobInfoFile << " -y: " << domain_bc_type[1] << "\n";
121  jobInfoFile << " +y: " << domain_bc_type[4] << "\n";
122  jobInfoFile << " -z: " << domain_bc_type[2] << "\n";
123  jobInfoFile << " +z: " << domain_bc_type[5] << "\n";
124 
125  jobInfoFile << "\n\n";
126 
127  // runtime parameters
128  jobInfoFile << PrettyLine;
129  jobInfoFile << " Inputs File Parameters\n";
130  jobInfoFile << PrettyLine;
131 
132  ParmParse::dumpTable(jobInfoFile, true);
133  jobInfoFile.close();
134 }
std::string inputs_name
Definition: main.cpp:14
static amrex::Real getCPUTime()
Definition: ERF.H:1312
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
1616 {
1617  BL_PROFILE("WriteMultiLevelPlotfileWithTerrain()");
1618 
1619  AMREX_ALWAYS_ASSERT(nlevels <= mf.size());
1620  AMREX_ALWAYS_ASSERT(nlevels <= rr.size()+1);
1621  AMREX_ALWAYS_ASSERT(nlevels <= level_steps.size());
1622  AMREX_ALWAYS_ASSERT(mf[0]->nComp() == varnames.size());
1623 
1624  bool callBarrier(false);
1625  PreBuildDirectorHierarchy(plotfilename, levelPrefix, nlevels, callBarrier);
1626  if (!extra_dirs.empty()) {
1627  for (const auto& d : extra_dirs) {
1628  const std::string ed = plotfilename+"/"+d;
1629  PreBuildDirectorHierarchy(ed, levelPrefix, nlevels, callBarrier);
1630  }
1631  }
1632  ParallelDescriptor::Barrier();
1633 
1634  if (ParallelDescriptor::MyProc() == ParallelDescriptor::NProcs()-1) {
1635  Vector<BoxArray> boxArrays(nlevels);
1636  for(int level(0); level < boxArrays.size(); ++level) {
1637  boxArrays[level] = mf[level]->boxArray();
1638  }
1639 
1640  auto f = [=]() {
1641  VisMF::IO_Buffer io_buffer(VisMF::IO_Buffer_Size);
1642  std::string HeaderFileName(plotfilename + "/Header");
1643  std::ofstream HeaderFile;
1644  HeaderFile.rdbuf()->pubsetbuf(io_buffer.dataPtr(), io_buffer.size());
1645  HeaderFile.open(HeaderFileName.c_str(), std::ofstream::out |
1646  std::ofstream::trunc |
1647  std::ofstream::binary);
1648  if( ! HeaderFile.good()) FileOpenFailed(HeaderFileName);
1649  WriteGenericPlotfileHeaderWithTerrain(HeaderFile, nlevels, boxArrays, varnames,
1650  my_geom, time, level_steps, rr, versionName,
1651  levelPrefix, mfPrefix);
1652  };
1653 
1654  if (AsyncOut::UseAsyncOut()) {
1655  AsyncOut::Submit(std::move(f));
1656  } else {
1657  f();
1658  }
1659  }
1660 
1661  std::string mf_nodal_prefix = "Nu_nd";
1662  for (int level = 0; level <= finest_level; ++level)
1663  {
1664  if (AsyncOut::UseAsyncOut()) {
1665  VisMF::AsyncWrite(*mf[level],
1666  MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mfPrefix),
1667  true);
1668  VisMF::AsyncWrite(*mf_nd[level],
1669  MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mf_nodal_prefix),
1670  true);
1671  } else {
1672  const MultiFab* data;
1673  std::unique_ptr<MultiFab> mf_tmp;
1674  if (mf[level]->nGrowVect() != 0) {
1675  mf_tmp = std::make_unique<MultiFab>(mf[level]->boxArray(),
1676  mf[level]->DistributionMap(),
1677  mf[level]->nComp(), 0, MFInfo(),
1678  mf[level]->Factory());
1679  MultiFab::Copy(*mf_tmp, *mf[level], 0, 0, mf[level]->nComp(), 0);
1680  data = mf_tmp.get();
1681  } else {
1682  data = mf[level];
1683  }
1684  VisMF::Write(*data , MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mfPrefix));
1685  VisMF::Write(*mf_nd[level], MultiFabFileFullPrefix(level, plotfilename, levelPrefix, mf_nodal_prefix));
1686  }
1687  }
1688 }
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:1691

◆ 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 
)
1977 {
1978  bool write_now = false;
1979 
1980  if ( plot_int > 0 && (nstep % plot_int == 0) ) {
1981  write_now = true;
1982 
1983  } else if (plot_per > 0.0) {
1984 
1985  // Check to see if we've crossed a plot_per interval by comparing
1986  // the number of intervals that have elapsed for both the current
1987  // time and the time at the beginning of this timestep.
1988 
1989  const Real eps = std::numeric_limits<Real>::epsilon() * Real(10.0) * std::abs(cur_time);
1990 
1991  int num_per_old = static_cast<int>(std::floor((cur_time-eps-dt_lev) / plot_per));
1992  int num_per_new = static_cast<int>(std::floor((cur_time-eps ) / plot_per));
1993 
1994  // Before using these, however, we must test for the case where we're
1995  // within machine epsilon of the next interval. In that case, increment
1996  // the counter, because we have indeed reached the next plot_per interval
1997  // at this point.
1998 
1999  const Real next_plot_time = (num_per_old + 1) * plot_per;
2000 
2001  if ((num_per_new == num_per_old) && std::abs(cur_time - next_plot_time) <= eps)
2002  {
2003  num_per_new += 1;
2004  }
2005 
2006  // Similarly, we have to account for the case where the old time is within
2007  // machine epsilon of the beginning of this interval, so that we don't double
2008  // count that time threshold -- we already plotted at that time on the last timestep.
2009 
2010  if ((num_per_new != num_per_old) && std::abs((cur_time - dt_lev) - next_plot_time) <= eps)
2011  num_per_old += 1;
2012 
2013  if (num_per_old != num_per_new)
2014  write_now = true;
2015  }
2016  return write_now;
2017 }

◆ WritePlotFile()

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

Member Data Documentation

◆ advflux_reg

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

Referenced by getAdvFluxReg().

◆ ax

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

◆ ax_new

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

◆ ax_src

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

◆ ay

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

◆ ay_new

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

◆ ay_src

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

◆ az

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

◆ az_new

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

◆ az_src

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

◆ base_state

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

◆ base_state_new

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

◆ bndry_output_planes_interval

int ERF::bndry_output_planes_interval = -1
staticprivate

◆ bndry_output_planes_per

Real ERF::bndry_output_planes_per = -1.0
staticprivate

◆ bndry_output_planes_start_time

Real ERF::bndry_output_planes_start_time = 0.0
staticprivate

◆ boxes_at_level

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

◆ cf_set_width

int ERF::cf_set_width {0}
private

◆ cf_width

int ERF::cf_width {0}
private

◆ cfl

Real ERF::cfl = 0.8
staticprivate

◆ change_max

Real ERF::change_max = 1.1
staticprivate

◆ check_file

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

◆ check_type

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

◆ column_file_name

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

◆ column_interval

int ERF::column_interval = -1
staticprivate

◆ column_loc_x

Real ERF::column_loc_x = 0.0
staticprivate

◆ column_loc_y

Real ERF::column_loc_y = 0.0
staticprivate

◆ column_per

Real ERF::column_per = -1.0
staticprivate

◆ cons_names

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

◆ d_havg_density

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

◆ d_havg_pressure

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

◆ d_havg_qc

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

◆ d_havg_qv

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

◆ d_havg_temperature

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

◆ d_rayleigh_ptrs

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

◆ d_rhoqt_src

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

◆ d_rhotheta_src

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

◆ d_sponge_ptrs

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

◆ d_u_geos

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

◆ d_v_geos

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

◆ d_w_subsid

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

◆ data_sampler

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

◆ datalog

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

◆ datalogname

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

Referenced by DataLogName().

◆ derived_names

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

◆ destag_profiles

bool ERF::destag_profiles = true
private

◆ detJ_cc

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

◆ detJ_cc_new

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

◆ detJ_cc_src

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

◆ domain_bc_type

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

◆ domain_bcs_type

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

◆ domain_bcs_type_d

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

◆ dt

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

◆ dt_max

Real ERF::dt_max = 1e9
staticprivate

◆ dt_max_initial

Real ERF::dt_max_initial = 1.0
staticprivate

◆ dt_mri_ratio

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

◆ dz_min

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

◆ eddyDiffs_lev

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

◆ fine_mask

amrex::MultiFab ERF::fine_mask
private

◆ finished_wave

bool ERF::finished_wave = false
private

◆ fixed_dt

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

◆ fixed_fast_dt

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

◆ fixed_mri_dt_ratio

int ERF::fixed_mri_dt_ratio = 0
staticprivate

◆ FPr_c

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

◆ FPr_u

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

◆ FPr_v

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

◆ FPr_w

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

◆ h_havg_density

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

◆ h_havg_pressure

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

◆ h_havg_qc

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

◆ h_havg_qv

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

◆ h_havg_temperature

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

◆ h_rayleigh_ptrs

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

◆ h_rhoqt_src

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

◆ h_rhotheta_src

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

◆ h_sponge_ptrs

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

◆ h_u_geos

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

◆ h_v_geos

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

◆ h_w_subsid

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

◆ Hwave

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

◆ Hwave_onegrid

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

◆ init_shrink

Real ERF::init_shrink = 1.0
staticprivate

◆ init_sounding_ideal

bool ERF::init_sounding_ideal = false
staticprivate

◆ init_type

InitType ERF::init_type
staticprivate

◆ input_bndry_planes

int ERF::input_bndry_planes = 0
staticprivate

◆ input_sounding_data

InputSoundingData ERF::input_sounding_data
private

◆ input_sponge_data

InputSpongeData ERF::input_sponge_data
private

◆ interpolation_type

StateInterpType ERF::interpolation_type
staticprivate

◆ istep

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

◆ last_check_file_step

int ERF::last_check_file_step
private

◆ last_plot_file_step_1

int ERF::last_plot_file_step_1
private

◆ last_plot_file_step_2

int ERF::last_plot_file_step_2
private

◆ lmask_lev

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

◆ lsm

LandSurface ERF::lsm
private

◆ lsm_data

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

◆ lsm_flux

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

◆ Lwave

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

◆ Lwave_onegrid

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

◆ m_bc_extdir_vals

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

◆ m_bc_neumann_vals

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

◆ m_check_int

int ERF::m_check_int = -1
private

◆ m_check_per

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

◆ m_expand_plotvars_to_unif_rr

bool ERF::m_expand_plotvars_to_unif_rr = false
private

◆ m_factory

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

Referenced by EBFactory(), and Factory().

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

◆ restart_chkfile

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

◆ restart_type

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

◆ rU_new

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

◆ rU_old

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

◆ rV_new

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

◆ rV_old

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

◆ rW_new

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

◆ rW_old

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

◆ sampleline

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

Referenced by NumSampleLines(), and SampleLine().

◆ samplelinelog

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

◆ samplelinelogname

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

Referenced by SampleLineLogName().

◆ samplepoint

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

Referenced by NumSamplePoints(), and SamplePoint().

◆ sampleptlog

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

◆ sampleptlogname

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

Referenced by SamplePointLogName().

◆ sampler_interval

int ERF::sampler_interval = -1
private

◆ sampler_per

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

◆ SFS_diss_lev

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

◆ SFS_hfx1_lev

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

◆ SFS_hfx2_lev

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

◆ SFS_hfx3_lev

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

◆ SFS_q1fx1_lev

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

◆ SFS_q1fx2_lev

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

◆ SFS_q1fx3_lev

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

◆ SFS_q2fx3_lev

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

◆ SmnSmn_lev

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

◆ solverChoice

SolverChoice ERF::solverChoice
staticprivate

◆ sponge_type

std::string ERF::sponge_type
staticprivate

◆ sst_lev

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

◆ start_time

amrex::Real ERF::start_time = 0.0
private

◆ startCPUTime

Real ERF::startCPUTime = 0.0
staticprivate

Referenced by getCPUTime().

◆ stop_time

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

◆ stretched_dz_d

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

◆ stretched_dz_h

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

◆ sub_cfl

Real ERF::sub_cfl = 1.0
staticprivate

◆ sum_interval

int ERF::sum_interval = -1
staticprivate

◆ sum_per

Real ERF::sum_per = -1.0
staticprivate

◆ t_avg_cnt

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

◆ t_new

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

◆ t_old

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

◆ Tau11_lev

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

◆ Tau12_lev

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

◆ Tau13_lev

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

◆ Tau21_lev

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

◆ Tau22_lev

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

◆ Tau23_lev

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

◆ Tau31_lev

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

◆ Tau32_lev

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

◆ Tau33_lev

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

◆ terrain_blanking

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

◆ Theta_prim

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

◆ thin_xforce

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

◆ thin_yforce

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

◆ thin_zforce

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

◆ turbPert

TurbulentPerturbation ERF::turbPert
private

◆ use_fft

bool ERF::use_fft = false
staticprivate

◆ use_real_bcs

bool ERF::use_real_bcs
staticprivate

◆ vars_new

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

◆ vars_old

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

◆ vel_t_avg

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

◆ verbose

int ERF::verbose = 0
staticprivate

◆ walldist

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

◆ xflux_imask

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

◆ xvel_bc_data

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

◆ yflux_imask

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

◆ yvel_bc_data

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

◆ z_phys_cc

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

◆ z_phys_nd

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

◆ z_phys_nd_new

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

◆ z_phys_nd_src

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

◆ z_t_rk

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

◆ zflux_imask

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

◆ zlevels_stag

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

◆ zmom_crse_rhs

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

◆ zvel_bc_data

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

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