ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_TI_utils.H
Go to the documentation of this file.
1 /**
2  * Define the Exner pressure at this RK stage
3  */
4  auto make_pi_stage = [&](const MultiFab& cons_state)
5  {
6  BL_PROFILE("make_pi_stage()");
7 
8 #ifdef _OPENMP
9 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
10 #endif
11  for (MFIter mfi(cons_state,TilingIfNotGPU()); mfi.isValid(); ++mfi)
12  {
13  //
14  // We only use one ghost cell of pi_stage so we only fill one here
15  //
16  const Box& gbx1 = mfi.growntilebox(1);
17 
18  const Array4<const Real>& cons_arr = cons_state.const_array(mfi);
19  const Array4< Real>& pi_stage_arr = pi_stage.array(mfi);
20  const Real rdOcp = solverChoice.rdOcp;
21  const bool l_use_moisture = (solverChoice.moisture_type != MoistureType::None);
22 
23  amrex::ParallelFor(gbx1, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
24  {
25  auto qv_for_p = (l_use_moisture) ? cons_arr(i,j,k,RhoQ1_comp)/cons_arr(i,j,k,Rho_comp) : zero;
26  pi_stage_arr(i,j,k) = getExnergivenRTh(cons_arr(i,j,k,RhoTheta_comp), rdOcp, qv_for_p);
27  });
28  } // mfi
29  };
30 
31 /**
32  * This routine is called after the scalars are updated for each RK stage
33  */
34  auto apply_bcs = [&](Vector<MultiFab>& S_data,
35  const double time_for_fp, int ng_cons, int ng_vel,
36  bool fast_only, bool vel_and_mom_synced)
37  {
38  BL_PROFILE("apply_bcs()");
39 
40  int scomp_cons;
41  int ncomp_cons;
42  bool cons_only;
43 
44  int ng_cons_to_use;
45 
46  // **********************************************************************************
47  // Because momentum is updated in the time-stepping routine, but boundary conditions
48  // are imposed on velocities, we must first update the velocity from the momentum
49  // before applying bcs.
50  // **********************************************************************************
51  if (!vel_and_mom_synced) {
52 
53  // **********************************************************************************
54  // Call FillPatch routines for the density only because we need it to convert between
55  // momentum and velocity
56  // This fills ghost cells/faces from
57  // 1) coarser level if lev > 0
58  // 2) physical boundaries
59  // 3) other grids at the same level
60  // **********************************************************************************
61 
62  // We must have at least one ghost cell of density to convert from momentum to velocity
63  // on the valid region
64  AMREX_ALWAYS_ASSERT (ng_cons >= 1);
65 
66  // We must have at least one extra ghost cell of density to convert from velocity to momentum
67  // on the valid region
68  ng_cons_to_use = std::max(ng_cons, ng_vel+1);
69 
70  scomp_cons = 0;
71  ncomp_cons = 1;
72  cons_only = true;
73  // **********************************************************************************
74  // Fill ghost cells of density only
75  // **********************************************************************************
76  FillIntermediatePatch(level, time_for_fp,
77  {&S_data[IntVars::cons], &xvel_new, &yvel_new, &zvel_new},
78  {&S_data[IntVars::cons], &S_data[IntVars::xmom],
79  &S_data[IntVars::ymom], &S_data[IntVars::zmom]},
80  ng_cons_to_use, 0, cons_only, scomp_cons, ncomp_cons);
81  }
82 
83  // ***************************************************************************************
84  // Call FillPatch routines for all data except rho which was filled above
85  // This fills ghost cells/faces from
86  // 1) coarser level if lev > 0
87  // 2) physical boundaries
88  // 3) other grids at the same level
89  // ***************************************************************************************
90  if (vel_and_mom_synced) {
91  if (fast_only) {
92  scomp_cons = 0;
93  ncomp_cons = 2; // rho and (rho theta) only
94  } else {
95  scomp_cons = 0;
96  ncomp_cons = S_data[IntVars::cons].nComp();
97  }
98  // We must have at least one extra ghost cell of density to convert from velocity to momentum
99  // on the valid region
100  ng_cons_to_use = std::max(ng_cons, ng_vel+1);
101 
102  } else {
103  if (fast_only) {
104  scomp_cons = 1;
105  ncomp_cons = 1; // (rho theta) only since we filled rho above
106  } else {
107  scomp_cons = 1;
108  ncomp_cons = S_data[IntVars::cons].nComp()-1; // since we filled rho above
109  }
110  ng_cons_to_use = ng_cons;
111  }
112 
113  // **********************************************************************************
114  // NOTE: FillIntermediatePatch takes momenta at the new time, and returns
115  // BOTH updated velocities and momenta
116  // **********************************************************************************
117  cons_only = false;
118  FillIntermediatePatch(level, time_for_fp,
119  {&S_data[IntVars::cons], &xvel_new, &yvel_new, &zvel_new},
120  {&S_data[IntVars::cons], &S_data[IntVars::xmom],
121  &S_data[IntVars::ymom], &S_data[IntVars::zmom]},
122  ng_cons_to_use, ng_vel, cons_only, scomp_cons, ncomp_cons);
123  };
124 
125  auto update_terrain_stage = [&,one_d=one](int lev, const double old_step_time,
126  const double old_stage_time,
127  const double new_stage_time,
128  const double slow_dt)
129  {
130  // Note that the "old" and "new" metric terms correspond to
131  // t^n and the RK stage (either t^*, t^** or t^{n+1} that this source
132  // will be used to advance to
133 
134  // The "src" metric terms correspond to the time at which we are evaluating the source here,
135  // aka old_stage_time
136 
137  if (verbose) Print() << "Re-making old geometry at old time : " << old_step_time << std::endl;
138 
139  //
140  // Make a temporary MF to fill the terrain -- on this level's domain: one made from
141  // the level 0 domain would cover only part of a fine level
142  //
143  Box terrain_bx(surroundingNodes(fine_geom.Domain())); terrain_bx.grow(z_phys_nd[lev]->nGrow());
144  FArrayBox terrain_fab_old(makeSlab(terrain_bx,2,0),1);
145  FArrayBox terrain_fab_src(makeSlab(terrain_bx,2,0),1);
146  FArrayBox terrain_fab_new(makeSlab(terrain_bx,2,0),1);
147 
148  prob->init_terrain_surface(fine_geom,terrain_fab_old,old_step_time);
149  prob->init_terrain_surface(fine_geom,terrain_fab_src,old_stage_time);
150  prob->init_terrain_surface(fine_geom,terrain_fab_new,new_stage_time);
151 
152  // Copy on intersection
153  for (MFIter mfi(*z_phys_nd[lev],false); mfi.isValid(); ++mfi)
154  {
155  Box isect = terrain_fab_old.box() & (*z_phys_nd[lev])[mfi].box();
156  ( *z_phys_nd[lev])[mfi].template copy<RunOn::Device>(terrain_fab_old,isect,0,isect,0,1);
157  (*z_phys_nd_src[lev])[mfi].template copy<RunOn::Device>(terrain_fab_src,isect,0,isect,0,1);
158  (*z_phys_nd_new[lev])[mfi].template copy<RunOn::Device>(terrain_fab_new,isect,0,isect,0,1);
159  }
160 
161  make_terrain_fitted_coords(lev,fine_geom,*z_phys_nd[lev], zlevels_stag[lev], phys_bc_type);
162  make_J (fine_geom, *z_phys_nd[lev], *detJ_cc[lev]);
163  make_areas (fine_geom, *z_phys_nd[lev], *ax[lev], *ay[lev], *az[lev]);
164 
165  if (verbose) Print() << "Making src geometry at old_stage_time: "
166  << std::setprecision(timeprecision) << old_stage_time << std::endl;
167  make_terrain_fitted_coords(lev,fine_geom,*z_phys_nd_src[lev], zlevels_stag[lev], phys_bc_type);
168  make_J (fine_geom, *z_phys_nd_src[lev], *detJ_cc_src[lev]);
169  make_areas (fine_geom, *z_phys_nd_src[lev], *ax_src[lev], *ay_src[lev], *az_src[lev]);
170  make_zcc (fine_geom, *z_phys_nd_src[lev], *z_phys_cc_src[lev]);
171 
172  if (verbose) Print() << "Making new geometry at new_stage_time: "
173  << std::setprecision(timeprecision) << new_stage_time << std::endl;
174  make_terrain_fitted_coords(lev,fine_geom,*z_phys_nd_new[lev], zlevels_stag[lev], phys_bc_type);
175  make_J (fine_geom, *z_phys_nd_new[lev], *detJ_cc_new[lev]);
176 
177  Real inv_dt = one_d/static_cast<Real>(slow_dt);
178 
179 #ifdef _OPENMP
180 #pragma omp parallel if (amrex::Gpu::notInLaunchRegion())
181 #endif
182  for (MFIter mfi(*z_t_rk[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
183  {
184  Box gbx = mfi.growntilebox(IntVect(1,1,0));
185 
186  const Array4<Real >& z_t_arr = z_t_rk[lev]->array(mfi);
187  const Array4<Real const>& z_nd_new_arr = z_phys_nd_new[lev]->const_array(mfi);
188  const Array4<Real const>& z_nd_old_arr = z_phys_nd[lev]->const_array(mfi);
189 
190  // Loop over horizontal plane
191  amrex::ParallelFor(gbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
192  {
193  // Evaluate between RK stages assuming the geometry is linear between old and new time
194  z_t_arr(i,j,k) = fourth * inv_dt * (z_nd_new_arr(i+1,j+1,k) - z_nd_old_arr(i+1,j+1,k)
195  +z_nd_new_arr(i ,j+1,k) - z_nd_old_arr( i,j+1,k)
196  +z_nd_new_arr(i+1,j ,k) - z_nd_old_arr(i+1,j ,k)
197  +z_nd_new_arr(i ,j ,k) - z_nd_old_arr(i ,j ,k));
198  });
199 
200  } // mfi
201  };
202 
203  auto update_terrain_substep = [&,one_d=one](int lev, const double old_substep_time, const double new_substep_time, const double dtau,
204  Vector<MultiFab>& S_data, std::unique_ptr<MultiFab>& z_t_pert)
205  {
206  // Make "old" fast geom -- store in z_phys_nd for convenience
207  Box terrain_bx(surroundingNodes(fine_geom.Domain())); terrain_bx.grow(z_phys_nd[lev]->nGrow());
208 
209  if (verbose) Print() << "Making geometry at start of substep time: "
210  << std::setprecision(timeprecision) << old_substep_time << std::endl;
211  FArrayBox terrain_fab_old(makeSlab(terrain_bx,2,0),1);
212  prob->init_terrain_surface(fine_geom,terrain_fab_old,old_substep_time);
213 
214  // Make "new" fast geom
215  if (verbose) Print() << "Making geometry for end of substep time :"
216  << std::setprecision(timeprecision) << new_substep_time << std::endl;
217  FArrayBox terrain_fab_new(makeSlab(terrain_bx,2,0),1);
218  prob->init_terrain_surface(fine_geom,terrain_fab_new,new_substep_time);
219 
220  // Copy on intersection
221  for (MFIter mfi(*z_phys_nd[lev],false); mfi.isValid(); ++mfi)
222  {
223  Box isect = terrain_fab_old.box() & (*z_phys_nd[lev])[mfi].box();
224  ( *z_phys_nd[lev])[mfi].template copy<RunOn::Device>(terrain_fab_old,isect,0,isect,0,1);
225  (*z_phys_nd_new[lev])[mfi].template copy<RunOn::Device>(terrain_fab_new,isect,0,isect,0,1);
226  }
227 
228  make_terrain_fitted_coords(lev,fine_geom,*z_phys_nd[lev], zlevels_stag[lev], phys_bc_type);
229  make_J (fine_geom,*z_phys_nd[lev], *detJ_cc[lev]);
230 
231  make_terrain_fitted_coords(lev,fine_geom,*z_phys_nd_new[lev], zlevels_stag[lev], phys_bc_type);
232  make_J (fine_geom,*z_phys_nd_new[lev], *detJ_cc_new[lev]);
233 
234  Real inv_dt = one_d/static_cast<Real>(dtau);
235 
236  z_t_pert = std::make_unique<MultiFab>(S_data[IntVars::zmom].boxArray(), S_data[IntVars::zmom].DistributionMap(), 1, 1);
237 
238  for (MFIter mfi(*z_t_rk[lev],TilingIfNotGPU()); mfi.isValid(); ++mfi)
239  {
240  Box gbx = mfi.growntilebox(IntVect(1,1,0));
241 
242  const Array4<Real >& z_t_arr = z_t_rk[lev]->array(mfi);
243  const Array4<Real >& zp_t_arr = z_t_pert->array(mfi);
244 
245  const Array4<Real const>& z_nd_new_arr = z_phys_nd_new[lev]->const_array(mfi);
246  const Array4<Real const>& z_nd_old_arr = z_phys_nd[lev]->const_array(mfi);
247 
248  // Loop over horizontal plane
249  amrex::ParallelFor(gbx, [=] AMREX_GPU_DEVICE (int i, int j, int k) noexcept
250  {
251  // Evaluate between RK stages assuming the geometry is linear between old and new time
252  zp_t_arr(i,j,k) = fourth * inv_dt * (z_nd_new_arr(i+1,j+1,k) - z_nd_old_arr(i+1,j+1,k)
253  +z_nd_new_arr(i ,j+1,k) - z_nd_old_arr( i,j+1,k)
254  +z_nd_new_arr(i+1,j ,k) - z_nd_old_arr(i+1,j ,k)
255  +z_nd_new_arr(i ,j ,k) - z_nd_old_arr(i ,j ,k));
256  // Convert to perturbation: z"_t(t) = z_t(t) - z_t^{RK}
257  zp_t_arr(i,j,k) -= z_t_arr(i,j,k);
258  });
259  } // mfi
260  };
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real getExnergivenRTh(const amrex::Real rhotheta, const amrex::Real rdOcp, const amrex::Real qv=amrex::Real(0))
Definition: ERF_EOS.H:156
#define Rho_comp
Definition: ERF_IndexDefines.H:53
#define RhoTheta_comp
Definition: ERF_IndexDefines.H:54
#define RhoQ1_comp
Definition: ERF_IndexDefines.H:66
const Real rdOcp
Definition: ERF_InitCustomPert_ABL.H:72
AMREX_ALWAYS_ASSERT(bx.length()[2]==khi+1)
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 one
Definition: ERF_NumericalConstants.H:37
constexpr amrex::Real fourth
Definition: ERF_NumericalConstants.H:42
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:36
amrex::Real Real
Definition: ERF_ShocInterface.H:19
auto make_pi_stage
Definition: ERF_TI_utils.H:4
auto apply_bcs
Definition: ERF_TI_utils.H:34
auto update_terrain_substep
Definition: ERF_TI_utils.H:203
auto update_terrain_stage
Definition: ERF_TI_utils.H:125
void make_areas(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &ax, MultiFab &ay, MultiFab &az)
Definition: ERF_TerrainMetrics.cpp:1170
void make_J(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &detJ_cc)
Definition: ERF_TerrainMetrics.cpp:1132
void make_zcc(const Geometry &geom, MultiFab &z_phys_nd, MultiFab &z_phys_cc)
Definition: ERF_TerrainMetrics.cpp:1237
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, FineTerrain fine_terrain, MultiFab const *z_phys_interp)
Definition: ERF_TerrainMetrics.cpp:324
@ ymom
Definition: ERF_IndexDefines.H:274
@ cons
Definition: ERF_IndexDefines.H:272
@ zmom
Definition: ERF_IndexDefines.H:275
@ xmom
Definition: ERF_IndexDefines.H:273
@ None
Definition: ERF_LSM_Types.H:6