ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_TI_slow_rhs_post.H
Go to the documentation of this file.
1 #include "ERF_SrcHeaders.H"
2 
3  auto slow_rhs_fun_post = [&,bogus_large_value_d=bogus_large_value](Vector<MultiFab>& S_rhs,
4  Vector<MultiFab>& S_old,
5  Vector<MultiFab>& S_new,
6  Vector<MultiFab>& S_data,
7  const double old_step_time,
8  const double old_stage_time,
9  const double new_stage_time,
10  const int nrk)
11  {
12  // Note that the "old" and "new" metric terms correspond to
13  // t^n and the RK stage (either t^*, t^** or t^{n+1} that this source
14  // will be used to advance to
15  double slow_dt = new_stage_time - old_step_time;
16 
17  if (verbose) amrex::Print() << "Time integration of scalars at level " << level
18  << std::setprecision(timeprecision)
19  << " from " << old_step_time << " to " << new_stage_time
20  << " with dt = " << slow_dt
21  << " using RHS created at " << old_stage_time << std::endl;
22 
23  const GpuArray<Real, AMREX_SPACEDIM> dxInv = fine_geom.InvCellSizeArray();
24 
25  // *************************************************************************
26  // Set up flux registers if using two_way coupling
27  // *************************************************************************
28  YAFluxRegister* fr_as_crse = nullptr;
29  YAFluxRegister* fr_as_fine = nullptr;
30  if (solverChoice.coupling_type == CouplingType::TwoWay && finest_level > 0)
31  {
32  if (level < finest_level) {
33  fr_as_crse = getAdvFluxReg(level+1);
34  }
35  if (level > 0) {
36  fr_as_fine = getAdvFluxReg(level);
37  }
38  }
39 
40  MultiFab* new_detJ =
41  (solverChoice.terrain_type == TerrainType::MovingFittedMesh) ? (detJ_cc_new[level].get()) : (detJ_cc[level].get());
42 
43  // Immersed Forcing
44  MultiFab* terrain_blank = (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
45  solverChoice.buildings_type == BuildingsType::ImmersedForcing) ?
46  terrain_blanking[level].get() : nullptr;
47  MultiFab* terrain_blank_xface = (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
48  solverChoice.buildings_type == BuildingsType::ImmersedForcing) ?
49  terrain_blanking_xface[level].get() : nullptr;
50  MultiFab* terrain_blank_yface = (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
51  solverChoice.buildings_type == BuildingsType::ImmersedForcing) ?
52  terrain_blanking_yface[level].get() : nullptr;
53  MultiFab* terrain_blank_zface = (solverChoice.terrain_type == TerrainType::ImmersedForcing ||
54  solverChoice.buildings_type == BuildingsType::ImmersedForcing) ?
55  terrain_blanking_zface[level].get() : nullptr;
56 
57  erf_slow_rhs_post(level, finest_level, nrk,
58  old_step_time, old_stage_time, new_stage_time, slow_dt,
59  micro->Get_Qstate_Moist_Size(),
60  S_rhs, S_old, S_new, S_data, S_prim, avg_xmom[level], avg_ymom[level], avg_zmom[level],
61  xvel_new, yvel_new, zvel_new, cc_src, terrain_blank,
62  terrain_blank_xface, terrain_blank_yface, terrain_blank_zface,
63  SmnSmn, eddyDiffs,
64  Hfx1, Hfx2, Hfx3, Q1fx1, Q1fx2, Q1fx3, Q2fx3, Diss,
65  Tau[level][TauType::tau13].get(), Tau[level][TauType::tau23].get(),
66  fine_geom, solverChoice, m_SurfaceLayer, domain_bcs_type_d, domain_bcs_type,
67  z_phys_nd[level], z_phys_cc[level], ax[level], ay[level], az[level],
68  detJ_cc[level], new_detJ, stretched_dz_d[level], mapfac[level], get_eb(level),
69 #ifdef ERF_USE_EAMXX_SHOC
70  eamxx_shoc_interface[level].get(),
71 #endif
72  native_shoc_driver[level].get(),
73  fr_as_crse, fr_as_fine,
74  m_r2d, &base_state[level],
75  cloud_chamber_config.active ? &cloud_chamber_config : nullptr,
76  cloud_chamber_budget.get(), auxiliary_inert_tracer.get(),
77  sbm_state_manager.get(), sbm_transport.get(),
78  ib_wall_face33[level].get(), ib_wall_ktarget[level].get());
79 
80  // One component list for the solve, stage ghosts and implicit reflux.
81  Vector<int> implicit_post_comps;
82  if (solverChoice.vert_implicit_fac[level][nrk] > zero) {
83  if (solverChoice.implicit_ke_diffusion && solverChoice.turbChoice[level].use_tke) {
84  implicit_post_comps.push_back(RhoKE_comp);
85  }
86  if (solverChoice.implicit_moisture_diffusion && solverChoice.moisture_type != MoistureType::None) {
87  const int q_end = (solverChoice.moisture_type == MoistureType::SBM) ?
88  RhoQ1_comp + 1 : S_new[IntVars::cons].nComp();
89  for (int n = RhoQ1_comp; n < q_end; ++n) {
90  if (solverChoice.diffChoice.implicit_q(n)) {
91  implicit_post_comps.push_back(n);
92  }
93  }
94  }
95  }
96 
97  // The ghost cells of S_new still hold the previous stage (S_old at the first stage): only
98  // its valid region has been advanced. At a coarse/fine boundary fill them with the coarse
99  // data at the time we are advancing to, since a column that ends there is closed with the
100  // value on the other side (as for the scratch state in slow_rhs_fun_pre)
101  if (level > 0 && !implicit_post_comps.empty()) {
102  FillCoarseFineGhostsForImplicit(level, new_stage_time, S_new[IntVars::cons], implicit_post_comps,
103  {nullptr, nullptr, nullptr});
104  }
105 
106  // Implicit diffusion of moisture
107  #include "ERF_ImplicitPost.H"
108 
109  // In the stage whose fluxes are refluxed, add the implicit part of the vertical diffusive
110  // fluxes the solves above applied to the flux registers. erf_slow_rhs_post has added the
111  // advective fluxes and the explicit part of the diffusive ones.
112  if (IsRefluxStage(solverChoice, level, finest_level, nrk) && !implicit_post_comps.empty() &&
113  solverChoice.terrain_type != TerrainType::EB)
114  {
115  const Real l_fac = solverChoice.vert_implicit_fac[level][nrk];
116  // weighted as in the step's update (RefluxStageWeight)
117  const Real l_dt = RefluxStageWeight(solverChoice, level, finest_level, nrk) *
118  static_cast<Real>(slow_dt);
119  const bool l_stretched = (solverChoice.mesh_type == MeshType::StretchedDz);
120  const bool l_implicit_metric = solverChoice.implicit_terrain_metric &&
121  l_use_terrain_fitted_coords;
122  const bool l_turb_post = solverChoice.turbChoice[level].use_kturb;
123  // As in ERF_ImplicitPost.H: the moisture solve adds the MRF countergradient flux for q1
124  const bool l_mrf_cg = solverChoice.turbChoice[level].enable_mrf_countergradient &&
125  (solverChoice.turbChoice[level].pbl_type == PBLType::MRF);
126  const Real* l_dx = fine_geom.CellSize();
127  const GpuArray<Real, AMREX_SPACEDIM> l_dxInv = fine_geom.InvCellSizeArray();
128 
129  // The fluxes hold only the components solved for, packed in the order of
130  // implicit_post_comps; each run of consecutive state components goes to the
131  // registers in one call
132  const int l_ncomp = static_cast<int>(implicit_post_comps.size());
133 
134  for (MFIter mfi(S_new[IntVars::cons], false); mfi.isValid(); ++mfi)
135  {
136  const Box& bx = mfi.validbox();
137 
138  // The solves are vertical, so the x and y fluxes are zero
139  FArrayBox fx(surroundingNodes(bx,0), l_ncomp, The_Async_Arena());
140  FArrayBox fy(surroundingNodes(bx,1), l_ncomp, The_Async_Arena());
141  FArrayBox fz(surroundingNodes(bx,2), l_ncomp, The_Async_Arena());
142  fx.setVal<RunOn::Device>(zero);
143  fy.setVal<RunOn::Device>(zero);
144 
145  const Array4<const Real>& cell_data = S_new[IntVars::cons].const_array(mfi);
146  const Array4<const Real>& mu_turb = l_turb_post ? eddyDiffs->const_array(mfi)
147  : Array4<const Real>{};
148  const Array4<const Real>& mf_mx = mapfac[level][MapFacType::m_x]->const_array(mfi);
149  const Array4<const Real>& mf_my = mapfac[level][MapFacType::m_y]->const_array(mfi);
150 
151  for (int m = 0; m < l_ncomp; ++m) {
152  const int c = implicit_post_comps[m];
153  const bool use_cg = l_mrf_cg && (c == RhoQ1_comp);
154  const Array4<Real> fz_arr(fz.array(), m, 1);
155  if (l_stretched) {
156  ImplicitVerticalFluxForReflux_S(bx, fine_geom.Domain(), level, c, l_fac, cell_data,
157  stretched_dz_d[level], mu_turb, solverChoice,
158  mf_mx, mf_my, use_cg, fz_arr);
159  } else if (l_use_terrain_fitted_coords) {
160  ImplicitVerticalFluxForReflux_T(bx, fine_geom.Domain(), level, c, l_fac, cell_data,
161  z_phys_nd[level]->const_array(mfi), l_dxInv, mu_turb,
162  solverChoice, mf_mx, mf_my, l_implicit_metric, use_cg,
163  fz_arr);
164  } else {
165  ImplicitVerticalFluxForReflux_N(bx, fine_geom.Domain(), level, c, l_fac, cell_data,
166  l_dxInv, mu_turb, solverChoice, mf_mx, mf_my, use_cg,
167  fz_arr);
168  }
169  }
170 
171  for (int m = 0; m < l_ncomp; ) {
172  int len = 1;
173  while (m + len < l_ncomp && implicit_post_comps[m+len] == implicit_post_comps[m] + len) {
174  ++len;
175  }
176  if (fr_as_crse) {
177  fr_as_crse->CrseAdd(mfi, {{AMREX_D_DECL(&fx, &fy, &fz)}}, l_dx, l_dt,
178  m, implicit_post_comps[m], len, RunOn::Device);
179  }
180  if (fr_as_fine) {
181  fr_as_fine->FineAdd(mfi, {{AMREX_D_DECL(&fx, &fy, &fz)}}, l_dx, l_dt,
182  m, implicit_post_comps[m], len, RunOn::Device);
183  }
184  m += len;
185  }
186  // The FArrayBoxes come from The_Async_Arena, which frees them only once the
187  // kernels queued on the stream above have finished with them
188  }
189  }
190 
191  // Apply state redistribution for cons states
192 
193  if (solverChoice.terrain_type == TerrainType::EB)
194  {
195  Vector<int> is_valid_slow_var; is_valid_slow_var.resize(RhoQ1_comp+1,0);
196  if (solverChoice.turbChoice[level].use_tke) {is_valid_slow_var[ RhoKE_comp] = 1;}
197  is_valid_slow_var[RhoScalar_comp] = 1;
198  if (solverChoice.moisture_type != MoistureType::None) {
199  is_valid_slow_var[RhoQ1_comp] = 1;
200  }
201  const int num_comp_total = S_rhs[IntVars::cons].nComp();
202  const int num_grow = S_rhs[IntVars::cons].nGrow();
203  const int nvars = S_data[IntVars::cons].nComp();
204  const DiffChoice l_diff_choice = solverChoice.diffChoice;
205 
206  MultiFab dUdt_tmp(ba, dm, num_comp_total, num_grow, MFInfo(), EBFactory(level));
207  dUdt_tmp.setVal(0, 0, num_comp_total, num_grow);
208 
209  int start_comp;
210  int num_comp;
211 
212  for (int ivar(RhoKE_comp); ivar<= RhoQ1_comp; ++ivar)
213  {
214  if (is_valid_slow_var[ivar])
215  {
216  start_comp = ivar;
217  num_comp = 1;
218  if (ivar == RhoQ1_comp) {
219  num_comp = nvars - RhoQ1_comp;
220  } else if (ivar == RhoScalar_comp) {
221  num_comp = NSCALARS;
222  }
223  MultiFab::Copy(dUdt_tmp, S_rhs[IntVars::cons], start_comp, start_comp, num_comp, 0);
224  }
225  }
226  dUdt_tmp.FillBoundary(fine_geom.periodicity());
227  dUdt_tmp.setDomainBndry(bogus_large_value_d, 0, num_comp_total, fine_geom);
228 
229  const BCRec* bc_ptr_d = domain_bcs_type_d.data();
230 
231  // Update S_rhs by Redistribution.
232  // To-do: Currently, redistributing all the scalar variables.
233  // This needs to be redistributed only for num_comp variables starting from ivar, for efficiency.
234  redistribute_term ( num_comp_total, fine_geom, S_rhs[IntVars::cons], dUdt_tmp,
235  S_old[IntVars::cons], EBFactory(level), bc_ptr_d, slow_dt);
236 
237  // Update state using the updated S_rhs. (NOTE: redistribute_term returns RHS not state variables.)
238  for ( MFIter mfi(S_new[IntVars::cons],TilingIfNotGPU()); mfi.isValid(); ++mfi)
239  {
240  Box tbx = mfi.tilebox();
241  const Array4<Real>& snew = S_new[IntVars::cons].array(mfi);
242  const Array4<Real>& sold = S_old[IntVars::cons].array(mfi);
243  const Array4<Real>& srhs = S_rhs[IntVars::cons].array(mfi);
244  Array4<const Real> detJ_arr = EBFactory(level).getVolFrac().const_array(mfi);
245 
246  for (int ivar(RhoKE_comp); ivar<= RhoQ1_comp; ++ivar)
247  {
248  if (is_valid_slow_var[ivar])
249  {
250  start_comp = ivar;
251  num_comp = 1;
252  if (ivar == RhoQ1_comp) {
253  num_comp = nvars - RhoQ1_comp;
254  } else if (ivar == RhoScalar_comp) {
255  num_comp = NSCALARS;
256  }
257  Real sdt = static_cast<Real>(slow_dt);
258  ParallelFor(tbx, num_comp, [=] AMREX_GPU_DEVICE (int i, int j, int k, int nn)
259  {
260  if (detJ_arr(i,j,k) > zero) {
261  const int n = start_comp + nn;
263  snew(i,j,k,n) = sold(i,j,k,n) + sdt * srhs(i,j,k,n);
264  }
265  }
266  });
267  }
268  }
269  }
270  } // EB
271 
272  // Limit KE and Q now that the explicit update, implicit diffusion and
273  // redistribution have all been applied
274  #include "ERF_ScalarLimitPost.H"
275 
276  // Apply boundary conditions on all the state variables that have been updated
277  // in both the fast and slow integrators
278  apply_bcs(S_new, new_stage_time, S_new[IntVars::cons].nGrow(), S_new[IntVars::xmom].nGrow(),
279  fast_only=false, vel_and_mom_synced=false);
280 
281  if (solverChoice.moisture_tight_coupling) {
282  // TODO: need iteration var for lagrangian microphysics
283  // call signature in ERF::Advance() is
284  //advance_microphysics(lev, S_new, dt_lev, iteration, time);
285  advance_microphysics(level, S_new[0], slow_dt, 123456789, old_step_time);
286  }
287  }; // end slow_rhs_fun_post
constexpr amrex::Real bogus_large_value
Definition: ERF_Constants.H:19
@ tau23
Definition: ERF_DataStruct.H:49
@ tau13
Definition: ERF_DataStruct.H:49
@ nvars
Definition: ERF_DataStruct.H:207
@ m_y
Definition: ERF_DataStruct.H:39
@ m_x
Definition: ERF_DataStruct.H:38
void ImplicitVerticalFluxForReflux_T(const amrex::Box &bx, const amrex::Box &domain, const int level, const int n, const amrex::Real implicit_fac, const amrex::Array4< const amrex::Real > &cell_data, const amrex::Array4< const amrex::Real > &z_nd, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &mu_turb, const SolverChoice &solverChoice, const amrex::Array4< const amrex::Real > &mf_mx, const amrex::Array4< const amrex::Real > &mf_my, const bool implicit_metric, const bool use_mrf_countergradient, const amrex::Array4< amrex::Real > &zflux)
As ImplicitVerticalFluxForReflux_N, on a terrain-following mesh.
void ImplicitVerticalFluxForReflux_N(const amrex::Box &bx, const amrex::Box &domain, const int level, const int n, const amrex::Real implicit_fac, const amrex::Array4< const amrex::Real > &cell_data, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &cellSizeInv, const amrex::Array4< const amrex::Real > &mu_turb, const SolverChoice &solverChoice, const amrex::Array4< const amrex::Real > &mf_mx, const amrex::Array4< const amrex::Real > &mf_my, const bool use_mrf_countergradient, const amrex::Array4< amrex::Real > &zflux)
The implicit part of the vertical diffusive flux of one component, for refluxing (flat mesh).
void ImplicitVerticalFluxForReflux_S(const amrex::Box &bx, const amrex::Box &domain, const int level, const int n, const amrex::Real implicit_fac, const amrex::Array4< const amrex::Real > &cell_data, const amrex::Gpu::DeviceVector< amrex::Real > &stretched_dz_d, const amrex::Array4< const amrex::Real > &mu_turb, const SolverChoice &solverChoice, const amrex::Array4< const amrex::Real > &mf_mx, const amrex::Array4< const amrex::Real > &mf_my, const bool use_mrf_countergradient, const amrex::Array4< amrex::Real > &zflux)
As ImplicitVerticalFluxForReflux_N, on a vertically stretched mesh.
void redistribute_term(int ncomp, const Geometry &geom, MultiFab &result, MultiFab &result_tmp, MultiFab const &state, EBFactType const &ebfact, BCRec const *bc, double local_dt_d, int const igrid)
Apply EB state redistribution to result_tmp and write the redistributed result.
Definition: ERF_EBRedistribute.cpp:21
#define RhoScalar_comp
Definition: ERF_IndexDefines.H:57
#define NSCALARS
Definition: ERF_IndexDefines.H:26
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:66
#define RhoKE_comp
Definition: ERF_IndexDefines.H:55
pp_for_pert_vels get("prob_type", prob_type)
amrex::GpuArray< Real, AMREX_SPACEDIM > dxInv
Definition: ERF_InitCustomPertVels_ParticleTests.H:17
ParallelFor(fab_box, [=] AMREX_GPU_DEVICE(int i, int j, int k) { qrcuten_arr(i, j, k)=Real(0);qscuten_arr(i, j, k)=Real(0);qicuten_arr(i, j, k)=Real(0);})
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:36
const DiffChoice l_diff_choice
Definition: ERF_ScalarLimitPost.H:17
amrex::Real Real
Definition: ERF_ShocInterface.H:19
void erf_slow_rhs_post(int level, int finest_level, int nrk, double step_old_time, double input_time, double target_time, double dt_d, int n_qstate, Vector< MultiFab > &S_rhs, Vector< MultiFab > &S_old, Vector< MultiFab > &S_new, Vector< MultiFab > &S_data, const MultiFab &S_prim, MultiFab &avg_xmom, MultiFab &avg_ymom, MultiFab &avg_zmom, const MultiFab &xvel, const MultiFab &yvel, const MultiFab &zvel, const MultiFab &source, MultiFab *terrain_blank, MultiFab *terrain_blank_xface, MultiFab *terrain_blank_yface, MultiFab *terrain_blank_zface, const MultiFab *SmnSmn, const MultiFab *eddyDiffs, MultiFab *Hfx1, MultiFab *Hfx2, MultiFab *Hfx3, MultiFab *Q1fx1, MultiFab *Q1fx2, MultiFab *Q1fx3, MultiFab *Q2fx3, MultiFab *Diss, MultiFab *Tau13, MultiFab *Tau23, const Geometry geom, const SolverChoice &solverChoice, const Vector< std::unique_ptr< SurfaceLayer >> &SurfLayer, const Gpu::DeviceVector< BCRec > &domain_bcs_type_d, const Vector< BCRec > &domain_bcs_type_h, std::unique_ptr< MultiFab > &z_phys_nd, std::unique_ptr< MultiFab > &z_phys_cc, std::unique_ptr< MultiFab > &ax, std::unique_ptr< MultiFab > &ay, std::unique_ptr< MultiFab > &az, std::unique_ptr< MultiFab > &detJ, MultiFab *detJ_new, Gpu::DeviceVector< Real > &stretched_dz_d, Vector< std::unique_ptr< MultiFab >> &mapfac, const eb_ &ebfact, ShocDriver *native_shoc_lev, YAFluxRegister *fr_as_crse, YAFluxRegister *fr_as_fine, std::unique_ptr< ReadBndryPlanes > &m_r2d, const MultiFab *cloud_chamber_base_state, const erf_cloud_chamber::Config *cloud_chamber_config, CloudChamberBudget *cloud_budget, erf_auxiliary::AuxiliaryInertTracer *auxiliary_inert_tracer, erf_sbm::SBMStateManager *sbm_state_manager, erf_sbm::SBMTransport *sbm_transport, const MultiFab *ib_wall_face33, const MultiFab *ib_wall_ktarget)
Definition: ERF_SlowRhsPost.cpp:59
bool IsRefluxStage(const SolverChoice &solverChoice, int level, int finest_level, int nrk)
Definition: ERF_TI_slow_headers.H:85
amrex::Real RefluxStageWeight(const SolverChoice &solverChoice, int level, int finest_level, int nrk)
Definition: ERF_TI_slow_headers.H:72
auto slow_rhs_fun_post
Definition: ERF_TI_slow_rhs_post.H:3
auto apply_bcs
Definition: ERF_TI_utils.H:34
@ cons
Definition: ERF_IndexDefines.H:272
@ xmom
Definition: ERF_IndexDefines.H:273
@ None
Definition: ERF_LSM_Types.H:6
@ nn
Definition: ERF_WDM6.H:33
Definition: ERF_DiffStruct.H:24
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool host_transports(int n) const noexcept
Definition: ERF_DiffStruct.H:121