ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_TI_slow_rhs_pre.H
Go to the documentation of this file.
1 #include "ERF_SrcHeaders.H"
2 
3 /**
4  * Wrapper for calling the routine that creates the slow RHS
5  */
6  auto slow_rhs_fun_pre = [&](Vector<MultiFab>& S_rhs,
7  Vector<MultiFab>& S_old,
8  Vector<MultiFab>& S_data,
9  const Real old_step_time,
10  const Real old_stage_time,
11  const Real new_stage_time,
12  const int nrk)
13  {
14  //
15  // Define primitive variables for all later RK stages
16  // (We have already done this for the first RK step)
17  // Note that it is essential this happen before the call to make_mom_sources
18  // because some of the buoyancy routines use the primitive variables
19  //
20  if (nrk > 0) {
21  int ng_cons = S_data[IntVars::cons].nGrow();
22  cons_to_prim(S_data[IntVars::cons], ng_cons);
23  }
24 
25  BL_PROFILE("slow_rhs_fun_pre");
26  if (verbose) Print() << std::setprecision(timeprecision)
27  << "Making slow rhs at time " << old_stage_time
28  << " for fast variables advancing from " << old_step_time
29  << " to " << new_stage_time << std::endl;
30 
31  Real slow_dt = new_stage_time - old_step_time;
32 
33  // *************************************************************************
34  // Set up flux registers if using two_way coupling
35  // *************************************************************************
36  YAFluxRegister* fr_as_crse = nullptr;
37  YAFluxRegister* fr_as_fine = nullptr;
38  if (solverChoice.coupling_type == CouplingType::TwoWay && finest_level > 0) {
39  if (level < finest_level) {
40  fr_as_crse = getAdvFluxReg(level+1);
41  fr_as_crse->reset();
42  }
43  if (level > 0) {
44  fr_as_fine = getAdvFluxReg(level);
45  }
46  }
47 
48  // Canopy data for mom sources
49  MultiFab* forest_drag = (solverChoice.do_forest_drag) ?
50  m_forest_drag[level]->get_drag_field() : nullptr;
51 
52  // Immersed Forcing
53  MultiFab* terrain_blank = (solverChoice.terrain_type == TerrainType::ImmersedForcing) ?
54  terrain_blanking[level].get() : nullptr;
55 
56  // Update the total moisture variable *before* computing sources since this is used in
57  // the buoyancy calculation
58  if (solverChoice.moisture_type != MoistureType::None) {
59  make_qt(S_data[IntVars::cons], qt);
60  }
61 
62  MultiFab p0_to_use, base_to_use;
63  MultiFab *zpn_to_use, *zpc_to_use, *ax_to_use, *ay_to_use, *az_to_use, *dJ_to_use;
64 
65  // Moving terrain
66  std::unique_ptr<MultiFab> z_t_pert;
67  if ( solverChoice.terrain_type == TerrainType::MovingFittedMesh )
68  {
69  z_t_pert = std::make_unique<MultiFab>(S_data[IntVars::zmom].boxArray(), S_data[IntVars::zmom].DistributionMap(), 1, 1);
70  update_terrain_stage(level, old_step_time, old_stage_time, new_stage_time, slow_dt);
71 
72  p0_to_use = MultiFab(base_state_new[level], make_alias, BaseState::p0_comp, 1);
73  base_to_use = MultiFab(base_state_new[level], make_alias, 0, BaseState::num_comps);
74  zpn_to_use = z_phys_nd_src[level].get();
75  zpc_to_use = z_phys_cc_src[level].get();
76  ax_to_use = ax_src[level].get();
77  ay_to_use = ay_src[level].get();
78  az_to_use = az_src[level].get();
79  dJ_to_use = detJ_cc_src[level].get();
80 
81  } else {
82  p0_to_use = MultiFab(base_state[level], make_alias, BaseState::p0_comp, 1);
83  base_to_use = MultiFab(base_state[level], make_alias, 0, BaseState::num_comps);
84  zpn_to_use = z_phys_nd[level].get();
85  zpc_to_use = z_phys_cc[level].get();
86  ax_to_use = ax[level].get();
87  ay_to_use = ay[level].get();
88  az_to_use = az[level].get();
89  dJ_to_use = detJ_cc[level].get();
90  }
91 
92  // *****************************************************************************
93  // Construct the source terms for the cell-centered (conserved) variables
94  // *****************************************************************************
95  make_sources(level, nrk, slow_dt, old_stage_time,
96  S_data, S_prim, cc_src, base_state[level], zpc_to_use,
97  qheating_rates[level].get(),
98  terrain_blank, fine_geom, solverChoice,
99  mapfac[level],
100  dptr_rhotheta_src, dptr_rhoqt_src,
101  dptr_wbar_sub, d_rayleigh_ptrs_at_lev,
102  input_sounding_data, turbPert, true);
103 
104  // *****************************************************************************
105  // Define the pressure gradient
106  // *****************************************************************************
107  make_gradp_pert(level, solverChoice, fine_geom, S_data,
108  p0_to_use, *zpn_to_use, *zpc_to_use, get_eb(level), gradp[level]);
109 
110  // *****************************************************************************
111  // Define the buoyancy forcing term in the z-direction
112  // *****************************************************************************
113  make_buoyancy(S_data, S_prim, qt, buoyancy, fine_geom, solverChoice, base_to_use,
114  micro->Get_Qstate_Moist_Size(), get_eb(level), solverChoice.anelastic[level]);
115 
116  // *****************************************************************************
117  // Make remaining (not gradp or buoyancy) momentum sources
118  // *****************************************************************************
119  make_mom_sources(old_stage_time, slow_dt,
120  S_data, *zpn_to_use, *zpc_to_use, stretched_dz_h[level],
121  xvel_new, yvel_new, zvel_new,
122  xmom_src, ymom_src, zmom_src,
123  base_to_use, forest_drag, terrain_blank,
124  cosPhi_m[level].get(), sinPhi_m[level].get(), fine_geom, solverChoice,
125  mapfac[level],
126  (solverChoice.have_geo_wind_profile) ? d_u_geos[level].data(): nullptr,
127  (solverChoice.have_geo_wind_profile) ? d_v_geos[level].data(): nullptr,
128  dptr_wbar_sub, d_rayleigh_ptrs_at_lev, d_sponge_ptrs_at_lev,
129  (solverChoice.hindcast_lateral_forcing? &forecast_state_interp[level] : nullptr),
130  input_sounding_data, true);
131 
132  // *****************************************************************************
133  // Add body sources if doing flow around a body
134  // *****************************************************************************
135  add_thin_body_sources(xmom_src, ymom_src, zmom_src,
136  xflux_imask[level], yflux_imask[level], zflux_imask[level],
137  thin_xforce[level], thin_yforce[level], thin_zforce[level]);
138 
139  // *****************************************************************************
140  // Define RHS for rho, rho_theta and momenta
141  // *****************************************************************************
142  erf_slow_rhs_pre(level, finest_level, nrk, slow_dt, S_rhs, S_old, S_data,
143  S_prim, qt, avg_xmom[level], avg_ymom[level], avg_zmom[level],
144  xvel_new, yvel_new, zvel_new,
145  z_t_rk[level], cc_src, xmom_src, ymom_src, zmom_src, buoyancy,
146  (level > 0) ? &zmom_crse_rhs[level] : nullptr,
147  Tau[level], SmnSmn, eddyDiffs, Hfx1, Hfx2, Hfx3, Q1fx1, Q1fx2, Q1fx3, Q2fx3, Diss,
148  fine_geom, solverChoice, m_SurfaceLayer, domain_bcs_type_d, domain_bcs_type,
149  *zpn_to_use, *zpc_to_use, *ax_to_use, *ay_to_use, *az_to_use, *dJ_to_use,
150  stretched_dz_d[level], gradp[level],
151  mapfac[level], get_eb(level), fr_as_crse, fr_as_fine);
152 
153  // *****************************************************************************
154  // Update for moving terrain
155  // *****************************************************************************
156  if ( solverChoice.terrain_type == TerrainType::MovingFittedMesh )
157  {
158  MultiFab r_hse_new (base_state_new[level], make_alias, BaseState::r0_comp, 1);
159  MultiFab p_hse_new (base_state_new[level], make_alias, BaseState::p0_comp, 1);
160  MultiFab pi_hse_new (base_state_new[level], make_alias, BaseState::pi0_comp, 1);
161  MultiFab th_hse_new (base_state_new[level], make_alias, BaseState::th0_comp, 1);
162 
163  MultiFab* r0_new = &r_hse_new;
164  MultiFab* p0_new = &p_hse_new;
165  MultiFab* pi0_new = &pi_hse_new;
166  MultiFab* th0_new = &th_hse_new;
167 
168  // We define and evolve (rho theta)_0 in order to re-create p_0 in a way that is consistent
169  // with our update of (rho theta) but does NOT maintain dp_0 / dz = -rho_0 g. This is why
170  // we no longer discretize the vertical pressure gradient in perturbational form.
171  MultiFab rt0(p0->boxArray(),p0->DistributionMap(),1,1);
172  MultiFab rt0_new(p0->boxArray(),p0->DistributionMap(),1,1);
173  MultiFab r0_temp(p0->boxArray(),p0->DistributionMap(),1,1);
174 
175  // Remember this does NOT maintain dp_0 / dz = -rho_0 g, so we can no longer
176  // discretize the vertical pressure gradient in perturbational form.
177  AMREX_ALWAYS_ASSERT(solverChoice.advChoice.dycore_horiz_adv_type == AdvType::Centered_2nd);
178  AMREX_ALWAYS_ASSERT(solverChoice.advChoice.dycore_vert_adv_type == AdvType::Centered_2nd);
179 
180  Real dt_base = (new_stage_time - old_step_time);
181 
182  const GpuArray<Real, AMREX_SPACEDIM> dxInv = fine_geom.InvCellSizeArray();
183 
184  const Real l_rdOcp = solverChoice.rdOcp;
185 
186 #ifdef _OPENMP
187 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
188 #endif
189  for ( MFIter mfi(*p0,TilingIfNotGPU()); mfi.isValid(); ++mfi)
190  {
191  const Array4<Real > rt0_arr = rt0.array(mfi);
192  const Array4<Real > rt0_tmp_arr = rt0_new.array(mfi);
193 
194  const Array4<Real const> r0_arr = r0->const_array(mfi);
195  const Array4<Real > r0_new_arr = r0_new->array(mfi);
196  const Array4<Real > r0_tmp_arr = r0_temp.array(mfi);
197 
198  const Array4<Real const> p0_arr = p0->const_array(mfi);
199  const Array4<Real > p0_new_arr = p0_new->array(mfi);
200  const Array4<Real > pi0_new_arr = pi0_new->array(mfi);
201  const Array4<Real > th0_new_arr = th0_new->array(mfi);
202 
203  const Array4<Real >& z_t_arr = z_t_rk[level]->array(mfi);
204 
205  const Array4<Real const>& dJ_old_arr = detJ_cc[level]->const_array(mfi);
206  const Array4<Real const>& dJ_new_arr = detJ_cc_new[level]->const_array(mfi);
207  const Array4<Real const>& dJ_src_arr = detJ_cc_src[level]->const_array(mfi);
208 
209  Box gbx = mfi.growntilebox({1,1,1});
210  amrex::ParallelFor(gbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
211  {
212  rt0_arr(i,j,k) = getRhoThetagivenP(p0_arr(i,j,k));
213  rt0_tmp_arr(i,j,k) = getRhoThetagivenP(p0_new_arr(i,j,k));
214  r0_tmp_arr(i,j,k) = r0_new_arr(i,j,k);
215  });
216 
217  Box gbx2 = mfi.growntilebox({1,1,0});
218  amrex::ParallelFor(gbx2, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
219  {
220  Real zflux_r_lo = -z_t_arr(i,j,k ) * 0.5 * (r0_tmp_arr(i,j,k) + r0_tmp_arr(i,j,k-1));
221  Real zflux_r_hi = -z_t_arr(i,j,k+1) * 0.5 * (r0_tmp_arr(i,j,k) + r0_tmp_arr(i,j,k+1));
222 
223  Real zflux_rt_lo = zflux_r_lo * 0.5 * (rt0_tmp_arr(i,j,k)/r0_tmp_arr(i,j,k) + rt0_tmp_arr(i,j,k-1)/r0_tmp_arr(i,j,k-1));
224  Real zflux_rt_hi = zflux_r_hi * 0.5 * (rt0_tmp_arr(i,j,k)/r0_tmp_arr(i,j,k) + rt0_tmp_arr(i,j,k+1)/r0_tmp_arr(i,j,k+1));
225 
226  Real invdetJ = 1.0 / dJ_src_arr(i,j,k);
227 
228  Real src_r = - invdetJ * ( zflux_r_hi - zflux_r_lo ) * dxInv[2];
229  Real src_rt = - invdetJ * ( zflux_rt_hi - zflux_rt_lo ) * dxInv[2];
230 
231  Real rho0_new = dJ_old_arr(i,j,k) * r0_arr(i,j,k) + dt_base * dJ_src_arr(i,j,k) * src_r;
232  Real rt0_tmp_new = dJ_old_arr(i,j,k) * rt0_arr(i,j,k) + dt_base * dJ_src_arr(i,j,k) * src_rt;
233 
234  r0_new_arr(i,j,k) = rho0_new / dJ_new_arr(i,j,k);
235  rt0_tmp_new /= dJ_new_arr(i,j,k);
236 
237  p0_new_arr(i,j,k) = getPgivenRTh(rt0_tmp_new);
238  pi0_new_arr(i,j,k) = getExnergivenRTh(rt0_tmp_new, l_rdOcp);
239  th0_new_arr(i,j,k) = rt0_tmp_new / r0_new_arr(i,j,k);
240  });
241  } // MFIter
242  r0_new->FillBoundary(fine_geom.periodicity());
243  p0_new->FillBoundary(fine_geom.periodicity());
244  th0_new->FillBoundary(fine_geom.periodicity());
245  }
246 
247 #ifdef ERF_USE_NETCDF
248  // Populate RHS for relaxation zones if using real bcs
249  if (solverChoice.use_real_bcs && (level == 0)) {
250  if (real_width>0) {
251  realbdy_compute_interior_ghost_rhs(bdy_time_interval,
252  new_stage_time, slow_dt, stop_time-start_time,
253  real_width, real_set_width, fine_geom,
254  S_rhs, S_old, S_data,
255  bdy_data_xlo, bdy_data_xhi,
256  bdy_data_ylo, bdy_data_yhi);
257  }
258  }
259 #endif
260  }; // end slow_rhs_fun_pre
void add_thin_body_sources(MultiFab &xmom_src, MultiFab &ymom_src, MultiFab &zmom_src, std::unique_ptr< iMultiFab > &xflux_imask_lev, std::unique_ptr< iMultiFab > &yflux_imask_lev, std::unique_ptr< iMultiFab > &zflux_imask_lev, std::unique_ptr< MultiFab > &thin_xforce_lev, std::unique_ptr< MultiFab > &thin_yforce_lev, std::unique_ptr< MultiFab > &thin_zforce_lev)
Definition: ERF_AddThinBodySources.cpp:27
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getPgivenRTh(const amrex::Real rhotheta, const amrex::Real qv=0.)
Definition: ERF_EOS.H:81
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getExnergivenRTh(const amrex::Real rhotheta, const amrex::Real rdOcp, const amrex::Real qv=0.0)
Definition: ERF_EOS.H:156
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getRhoThetagivenP(const amrex::Real p, const amrex::Real qv=0.0)
Definition: ERF_EOS.H:172
@ Centered_2nd
void realbdy_compute_interior_ghost_rhs(const Real &bdy_time_interval, const Real &time, const Real &delta_t, const Real &stop_time_elapsed, int width, int set_width, const Geometry &geom, Vector< MultiFab > &S_rhs, Vector< MultiFab > &S_old_data, Vector< MultiFab > &S_cur_data, Vector< Vector< FArrayBox >> &bdy_data_xlo, Vector< Vector< FArrayBox >> &bdy_data_xhi, Vector< Vector< FArrayBox >> &bdy_data_ylo, Vector< Vector< FArrayBox >> &bdy_data_yhi)
Definition: ERF_InteriorGhostCells.cpp:174
void make_buoyancy(const Vector< MultiFab > &S_data, const MultiFab &S_prim, const MultiFab &qt, MultiFab &buoyancy, const Geometry geom, const SolverChoice &solverChoice, const MultiFab &base_state, const int n_qstate, const eb_ &ebfact, const int anelastic)
Definition: ERF_MakeBuoyancy.cpp:32
void make_gradp_pert(int level, const SolverChoice &solverChoice, const Geometry &geom, Vector< MultiFab > &S_data, MultiFab &p0, MultiFab &z_phys_nd, MultiFab &z_phys_cc, const eb_ &ebfact, Vector< MultiFab > &gradp)
Definition: ERF_MakeGradP.cpp:28
void make_mom_sources(Real time, Real dt, const Vector< MultiFab > &S_data, MultiFab &z_phys_nd, MultiFab &z_phys_cc, Vector< Real > &stretched_dz_h, const MultiFab &xvel, const MultiFab &yvel, const MultiFab &wvel, MultiFab &xmom_src, MultiFab &ymom_src, MultiFab &zmom_src, const MultiFab &base_state, MultiFab *forest_drag, MultiFab *terrain_blank, MultiFab *cosPhi_mf, MultiFab *sinPhi_mf, const Geometry geom, const SolverChoice &solverChoice, Vector< std::unique_ptr< MultiFab >> &, const Real *dptr_u_geos, const Real *dptr_v_geos, const Real *dptr_wbar_sub, const Vector< Real * > d_rayleigh_ptrs_at_lev, const Vector< Real * > d_sponge_ptrs_at_lev, const Vector< MultiFab > *forecast_state_at_lev, InputSoundingData &input_sounding_data, bool is_slow_step)
Definition: ERF_MakeMomSources.cpp:35
void make_sources(int level, int, Real dt, Real time, const Vector< MultiFab > &S_data, const MultiFab &S_prim, MultiFab &source, const MultiFab &base_state, const MultiFab *z_phys_cc, const MultiFab *qheating_rates, MultiFab *terrain_blank, const Geometry geom, const SolverChoice &solverChoice, Vector< std::unique_ptr< MultiFab >> &mapfac, const Real *dptr_rhotheta_src, const Real *dptr_rhoqt_src, const Real *dptr_wbar_sub, const Vector< Real * > d_rayleigh_ptrs_at_lev, InputSoundingData &input_sounding_data, TurbulentPerturbation &turbPert, bool is_slow_step)
Definition: ERF_MakeSources.cpp:31
amrex::Real Real
Definition: ERF_ShocInterface.H:19
void erf_slow_rhs_pre(int level, int finest_level, int nrk, Real dt, Vector< MultiFab > &S_rhs, Vector< MultiFab > &S_old, Vector< MultiFab > &S_data, const MultiFab &S_prim, const MultiFab &qt, MultiFab &avg_xmom, MultiFab &avg_ymom, MultiFab &avg_zmom, const MultiFab &xvel, const MultiFab &yvel, const MultiFab &zvel, std::unique_ptr< MultiFab > &z_t_mf, const MultiFab &cc_src, const MultiFab &xmom_src, const MultiFab &ymom_src, const MultiFab &zmom_src, const MultiFab &buoyancy, const MultiFab *zmom_crse_rhs, Vector< std::unique_ptr< MultiFab >> &Tau_lev, MultiFab *SmnSmn, MultiFab *eddyDiffs, MultiFab *Hfx1, MultiFab *Hfx2, MultiFab *Hfx3, MultiFab *Q1fx1, MultiFab *Q1fx2, MultiFab *Q1fx3, MultiFab *Q2fx3, MultiFab *Diss, const Geometry geom, const SolverChoice &solverChoice, std::unique_ptr< SurfaceLayer > &SurfLayer, const Gpu::DeviceVector< BCRec > &domain_bcs_type_d, const Vector< BCRec > &domain_bcs_type_h, const MultiFab &z_phys_nd, const MultiFab &z_phys_cc, const MultiFab &ax, const MultiFab &ay, const MultiFab &az, const MultiFab &detJ, Gpu::DeviceVector< Real > &stretched_dz_d, Vector< MultiFab > &gradp, Vector< std::unique_ptr< MultiFab >> &mapfac, const eb_ &ebfact, YAFluxRegister *fr_as_crse, YAFluxRegister *fr_as_fine)
Definition: ERF_SlowRhsPre.cpp:65
auto slow_rhs_fun_pre
Definition: ERF_TI_slow_rhs_pre.H:6
auto cons_to_prim
Definition: ERF_TI_utils.H:4
auto make_qt
Definition: ERF_TI_utils.H:52
auto update_terrain_stage
Definition: ERF_TI_utils.H:164
@ num_comps
Definition: ERF_IndexDefines.H:68
@ pi0_comp
Definition: ERF_IndexDefines.H:65
@ p0_comp
Definition: ERF_IndexDefines.H:64
@ th0_comp
Definition: ERF_IndexDefines.H:66
@ r0_comp
Definition: ERF_IndexDefines.H:63
@ cons
Definition: ERF_IndexDefines.H:158
@ zmom
Definition: ERF_IndexDefines.H:161
@ qt
Definition: ERF_Kessler.H:27
real(c_double), parameter p0
Definition: ERF_module_model_constants.F90:40