NOTE: Multilevel is not yet working for either of these terrain-following coordinates, but (we think) the issue is deep in ERF and this code will work once the deeper problem is fixed. For now, make sure to run on a single level. -mmsanders
79 const Box& domain = geom.Domain();
80 int domlo_x = domain.smallEnd(0);
int domhi_x = domain.bigEnd(0) + 1;
81 int domlo_y = domain.smallEnd(1);
int domhi_y = domain.bigEnd(1) + 1;
82 int domlo_z = domain.smallEnd(2);
int domhi_z = domain.bigEnd(2) + 1;
83 int nz = domain.length(2)+1;
85 Real z_top = z_levels_h[nz-1];
89 int terrain_smoothing = 0;
90 pp.query(
"terrain_smoothing", terrain_smoothing);
92 if (lev > 0 && terrain_smoothing != 0) {
93 Abort(
"Must use terrain_smoothing = 0 when doing multilevel");
96 Gpu::DeviceVector<Real> z_levels_d;
97 z_levels_d.resize(nz);
98 Gpu::copy(Gpu::hostToDevice, z_levels_h.begin(), z_levels_h.end(), z_levels_d.begin());
101 int ngrow = z_phys_nd.nGrow();
102 IntVect ngrowVect = z_phys_nd.nGrowVect();
104 int imin = domlo_x;
if (geom.isPeriodic(0)) imin -= z_phys_nd.nGrowVect()[0];
105 int jmin = domlo_y;
if (geom.isPeriodic(1)) jmin -= z_phys_nd.nGrowVect()[1];
107 int imax = domhi_x;
if (geom.isPeriodic(0)) imax += z_phys_nd.nGrowVect()[0];
108 int jmax = domhi_y;
if (geom.isPeriodic(1)) jmax += z_phys_nd.nGrowVect()[1];
110 switch(terrain_smoothing) {
113 for ( MFIter mfi(z_phys_nd, TilingIfNotGPU()); mfi.isValid(); ++mfi )
116 const Box& bx = mfi.validbox();
118 int k0 = bx.smallEnd()[2];
121 Box gbx = mfi.growntilebox(ngrowVect);
123 if (bx.smallEnd(2) > domlo_z) {
126 if (bx.bigEnd(2) < domhi_z) {
130 Array4<Real>
const& z_arr = z_phys_nd.array(mfi);
131 auto const& z_lev = z_levels_d.data();
136 ParallelFor(gbx, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
138 int ii = amrex::max(amrex::min(i,imax),imin);
139 int jj = amrex::max(amrex::min(j,jmax),jmin);
147 Real z_sfc = z_arr(ii,jj,k0);
148 Real z_lev_sfc = z_lev[k0];
150 z_arr(i,j,k) = ( (z_sfc - z_lev_sfc) * z_top +
151 (z_top - z_sfc ) *
z ) / (z_top - z_lev_sfc);
156 ParallelFor(makeSlab(gbx,2,0), [=] AMREX_GPU_DEVICE (
int i,
int j,
int)
158 z_arr(i,j,-1) = 2.0*z_arr(i,j,0) - z_arr(i,j,1);
169 MultiFab h_mf( z_phys_nd.boxArray(), z_phys_nd.DistributionMap(), 1, ngrow+1);
170 MultiFab h_mf_old(z_phys_nd.boxArray(), z_phys_nd.DistributionMap(), 1, ngrow+1);
178 BoxList bl2d = h_mf.boxArray().boxList();
179 for (
auto& b : bl2d) {
182 BoxArray ba2d(std::move(bl2d));
183 mf2d = MultiFab(ba2d, h_mf.DistributionMap(), 1, ngrow, MFInfo().SetAlloc(
false));
187 MultiArray4<Real>
const& ma_h_s = h_mf.arrays();
188 MultiArray4<Real>
const& ma_h_s_old = h_mf_old.arrays();
189 MultiArray4<Real>
const& ma_z_phys = z_phys_nd.arrays();
195 max_h = ParReduce(TypeList<ReduceOpMax>{}, TypeList<Real>{}, mf2d, IntVect(ngrow,ngrow,0),
196 [=] AMREX_GPU_DEVICE (
int box_no,
int i,
int j,
int) noexcept
200 const auto & h = ma_h_s[box_no];
201 const auto & z_arr = ma_z_phys[box_no];
203 int ii = amrex::max(amrex::min(i,imax),imin);
204 int jj = amrex::max(amrex::min(j,jmax),jmin);
207 z_arr(i,j,k0) = z_arr(ii,jj,k0);
210 h(i,j,k0) = z_arr(i,j,k0);
213 return { z_arr(i,j,k0) };
217 h_mf.FillBoundary(geom.periodicity());
220 MultiFab::Copy(h_mf_old, h_mf,0,0,1,h_mf_old.nGrow());
223 for (
int k = domlo_z+1; k <= domhi_z; k++)
225 auto const& z_lev_h = z_levels_h.data();
227 Real zz = z_lev_h[k];
228 Real zz_minus = z_lev_h[k-1];
231 Real z_H = 2.44/(1-gamma_m);
234 Real foo = cos((
PI/2)*(zz/z_H));
235 if(zz < z_H) { A = foo*foo*foo*foo*foo*foo; }
237 Real foo_minus = cos((
PI/2)*(zz_minus/z_H));
239 if(zz_minus < z_H) { A_minus = foo_minus*foo_minus*foo_minus*foo_minus*foo_minus*foo_minus; }
240 else { A_minus = 0; }
242 unsigned maxIter = 50;
244 Real threshold = gamma_m;
246 while (iter < maxIter && diff > threshold)
249 diff = ParReduce(TypeList<ReduceOpMin>{}, TypeList<Real>{}, mf2d, IntVect(ngrow,ngrow,0),
250 [=] AMREX_GPU_DEVICE (
int box_no,
int i,
int j,
int) noexcept
253 const auto & h_s = ma_h_s[box_no];
254 const auto & h_s_old = ma_h_s_old[box_no];
257 Real beta_k = 0.2*std::min(zz/(2*h_m),1.0);
260 int ii = amrex::min(amrex::max(i,domlo_x),domhi_x);
261 int jj = amrex::min(amrex::max(j,domlo_y),domhi_y);
264 h_s(i,j,k) = h_s_old(i,j,k-1) + beta_k*(h_s_old(ii+1,jj ,k-1)
265 + h_s_old(ii-1,jj ,k-1)
266 + h_s_old(ii ,jj+1,k-1)
267 + h_s_old(ii ,jj-1,k-1) - 4*h_s_old(ii,jj,k-1));
270 h_s(i,j,k) = h_s_old(i,j,k ) + beta_k*(h_s_old(ii+1,jj ,k )
271 + h_s_old(ii-1,jj ,k )
272 + h_s_old(ii ,jj+1,k )
273 + h_s_old(ii ,jj-1,k ) - 4*h_s_old(ii,jj,k ));
276 return { (zz + A * h_s(i,j,k) - (zz_minus + A_minus * h_s(i,j,k-1))) / (zz - zz_minus) };
280 MultiFab::Copy(h_mf_old, h_mf,0,0,1,h_mf_old.nGrow());
282 ParallelDescriptor::ReduceRealMin(diff);
287 h_mf_old.FillBoundary(geom.periodicity());
291 auto const& z_lev_d = z_levels_d.data();
294 for ( MFIter mfi(z_phys_nd, TilingIfNotGPU()); mfi.isValid(); ++mfi )
297 Box xybx = mfi.growntilebox(ngrow);
300 Array4<Real>
const& h_s = h_mf_old.array(mfi);
301 Array4<Real>
const& z_arr = z_phys_nd.array(mfi);
303 ParallelFor(xybx, [=] AMREX_GPU_DEVICE (
int i,
int j,
int) {
309 z_arr(i,j,k) =
z + A*h_s(i,j,k);
313 z_arr(i,j,k0-1) = 2.0*z_arr(i,j,k0) - z_arr(i,j,k);
318 Gpu::streamSynchronize();
327 for ( MFIter mfi(z_phys_nd, TilingIfNotGPU()); mfi.isValid(); ++mfi )
330 Box gbx = mfi.growntilebox(ngrow);
331 gbx.setRange(2,domlo_z,domhi_z+1);
333 Array4<Real>
const& z_arr = z_phys_nd.array(mfi);
334 auto const& z_lev = z_levels_d.data();
336 ParallelFor(gbx, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
341 int ii = amrex::max(amrex::min(i,imax),imin);
342 int jj = amrex::max(amrex::min(j,jmax),jmin);
346 z_arr(i,j,k) =
z + (std::pow((1. - (z/z_top)),
omega) * z_arr(ii,jj,k0));
350 z_arr(i,j,k0 ) = z_arr(ii,jj,k0);
352 z_arr(i,j,k0-1) = 2.0*z_arr(ii,jj,k0) - z_arr(i,j,k);
362 for ( MFIter mfi(z_phys_nd, TilingIfNotGPU()); mfi.isValid(); ++mfi )
365 Box gbx = mfi.growntilebox(ngrow);
366 gbx.setRange(2,domlo_z,domhi_z+1);
368 Array4<Real>
const& z_arr = z_phys_nd.array(mfi);
369 auto const& z_lev = z_levels_d.data();
371 ParallelFor(gbx, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
376 int ii = amrex::max(amrex::min(i,imax),imin);
377 int jj = amrex::max(amrex::min(j,jmax),jmin);
381 z_arr(i,j,k) =
z + z_arr(ii,jj,k0);
385 z_arr(i,j,k) =
z + (std::pow((1. - (z/z_top)),
omega) * z_arr(ii,jj,k0));
389 ParallelFor(gbx, [=] AMREX_GPU_DEVICE (
int i,
int j,
int k)
392 z_arr(i,j,k-1) = -z_arr(i,j,k+1);
401 z_phys_nd.FillBoundary(geom.periodicity());
407 for ( MFIter mfi(z_phys_nd, TilingIfNotGPU()); mfi.isValid(); ++mfi )
410 Box nd_bx = mfi.tilebox();
413 if (nd_bx.bigEnd(2) >= domhi_z) {
415 Box xybx = mfi.growntilebox(ngrow);
417 Array4<Real>
const& z_arr = z_phys_nd.array(mfi);
420 ParallelFor(xybx, [=] AMREX_GPU_DEVICE (
int i,
int j,
int ) {
421 z_arr(i,j,domhi_z+1) = 2.0*z_arr(i,j,domhi_z) - z_arr(i,j,domhi_z-1);
constexpr amrex::Real PI
Definition: ERF_Constants.H:6
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real pp(amrex::Real y)
Definition: Microphysics_Utils.H:183
@ omega
Definition: SAM.H:49