ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERFPCParticleToMesh.H
Go to the documentation of this file.
1 /*! \file ERFPCParticleToMesh.H
2  * \brief Template implementation of ERFPC::ERFPCParticleToMesh
3  *
4  * Separated from ERFPC.H to keep the header lightweight.
5  * Include this in .cpp files that call ERFPCParticleToMesh().
6  */
7 
8 #ifndef ERFPC_PARTICLE_TO_MESH_H_
9 #define ERFPC_PARTICLE_TO_MESH_H_
10 
11 #include <ERFPC.H>
12 
13 template<typename ValueFunc>
14 void ERFPC::ERFPCParticleToMesh(amrex::MultiFab& a_mf,
15  const amrex::MultiFab& a_z_phys_nd,
16  int a_lev, int a_comp,
17  ValueFunc&& value_func) const
18 {
19  using namespace amrex;
20 
21  AMREX_ASSERT(OK());
22  AMREX_ASSERT(numParticlesOutOfRange(*this, 0) == 0);
23 
24  const auto& geom = Geom(a_lev);
25  const auto plo = geom.ProbLoArray();
26  const auto dxi = geom.InvCellSizeArray();
27  const Real dx = geom.CellSize(0);
28  const Real dy = geom.CellSize(1);
29  const Box domain = geom.Domain();
30  const int k_max = domain.bigEnd(AMREX_SPACEDIM-1);
31 
32  a_mf.setVal(0.0);
33 
34 #ifdef AMREX_USE_OMP
35 #pragma omp parallel if (Gpu::notInLaunchRegion())
36 #endif
37  for (ParConstIterType pti(*this, a_lev); pti.isValid(); ++pti)
38  {
39  const int grid = pti.index();
40  const auto& ptile = ParticlesAt(a_lev, pti);
41  const auto& aos = ptile.GetArrayOfStructs();
42  const int np = aos.numParticles();
43  if (np == 0) { continue; }
44 
45  auto rho = a_mf[grid].array();
46  auto zheight = a_z_phys_nd[grid].array();
47 
48  const auto ptd = ptile.getConstParticleTileData();
49 
50  ParallelFor(np, [=] AMREX_GPU_DEVICE (int i)
51  {
52  const auto& p = ptd.m_aos[i];
53  if (p.id() <= 0) { return; }
54 
55  const Real pval = value_func(ptd, i);
56 
57  const Real lx = (p.pos(0) - plo[0]) * dxi[0] + Real(0.5);
58  const int ix = static_cast<int>(Math::floor(lx)) - 1;
59  const Real wx1 = lx - static_cast<Real>(ix + 1);
60  const Real wx0 = Real(1.0) - wx1;
61 
62  const Real ly = (p.pos(1) - plo[1]) * dxi[1] + Real(0.5);
63  const int iy = static_cast<int>(Math::floor(ly)) - 1;
64  const Real wy1 = ly - static_cast<Real>(iy + 1);
65  const Real wy0 = Real(1.0) - wy1;
66 
67  const int kz = p.idata(ERFParticlesIntIdxAoS::k);
68  const int ix_p = static_cast<int>(Math::floor((p.pos(0) - plo[0]) * dxi[0]));
69  const int iy_p = static_cast<int>(Math::floor((p.pos(1) - plo[1]) * dxi[1]));
70  const Real fx = (p.pos(0) - plo[0]) * dxi[0] - static_cast<Real>(ix_p);
71  const Real fy = (p.pos(1) - plo[1]) * dxi[1] - static_cast<Real>(iy_p);
72 
73  auto zface = [=] AMREX_GPU_DEVICE (int k_face) -> Real {
74  return zheight(ix_p , iy_p , k_face) * (Real(1.0)-fx) * (Real(1.0)-fy)
75  + zheight(ix_p+1, iy_p , k_face) * fx * (Real(1.0)-fy)
76  + zheight(ix_p , iy_p+1, k_face) * (Real(1.0)-fx) * fy
77  + zheight(ix_p+1, iy_p+1, k_face) * fx * fy;
78  };
79 
80  const Real z_lo_k = zface(kz);
81  const Real z_hi_k = zface(kz + 1);
82  const Real z_ctr_k = Real(0.5) * (z_lo_k + z_hi_k);
83 
84  // Vertical bracket: at k = 0 / k = k_max the bracket extends to
85  // k = -1 / k_max+1; SumBoundary wraps those in periodic-z, Copy
86  // discards them otherwise (matches old Linear CIC).
87  int kz_lo, kz_hi;
88  Real wz_lo, wz_hi;
89  if (p.pos(2) >= z_ctr_k) {
90  kz_lo = kz;
91  kz_hi = kz + 1;
92  Real span;
93  if (kz < k_max) {
94  const Real z_hi2 = zface(kz + 2);
95  const Real z_ctr_hi = Real(0.5) * (z_hi_k + z_hi2);
96  span = z_ctr_hi - z_ctr_k;
97  } else {
98  span = z_hi_k - z_lo_k;
99  }
100  wz_hi = (p.pos(2) - z_ctr_k) / span;
101  wz_lo = Real(1.0) - wz_hi;
102  } else {
103  kz_hi = kz;
104  kz_lo = kz - 1;
105  Real span;
106  if (kz > 0) {
107  const Real z_lo2 = zface(kz - 1);
108  const Real z_ctr_lo = Real(0.5) * (z_lo2 + z_lo_k);
109  span = z_ctr_k - z_ctr_lo;
110  } else {
111  span = z_hi_k - z_lo_k;
112  }
113  wz_lo = (z_ctr_k - p.pos(2)) / span;
114  wz_hi = Real(1.0) - wz_lo;
115  }
116 
117  // Per-corner node-averaged cell thickness for volume normalization.
118  auto dz_cell = [=] AMREX_GPU_DEVICE (int ic, int jc, int kc) -> Real {
119  const Real dz = Real(0.25) * (
120  zheight(ic , jc , kc+1) - zheight(ic , jc , kc)
121  + zheight(ic+1, jc , kc+1) - zheight(ic+1, jc , kc)
122  + zheight(ic , jc+1, kc+1) - zheight(ic , jc+1, kc)
123  + zheight(ic+1, jc+1, kc+1) - zheight(ic+1, jc+1, kc) );
124  return dz;
125  };
126 
127  const Real inv_dxdy = Real(1.0) / (dx * dy);
128 
129  auto deposit = [=] AMREX_GPU_DEVICE (int ic, int jc, int kc, Real w_horiz, Real w_z)
130  {
131  // Clamp kc only for dz lookup; still write to ghost rho cell.
132  const int kc_dz = amrex::max(0, amrex::min(k_max, kc));
133  const Real dz = dz_cell(ic, jc, kc_dz);
134  const Real contrib = pval * w_horiz * w_z * inv_dxdy / dz;
135  Gpu::Atomic::AddNoRet(&rho(ic, jc, kc, a_comp), contrib);
136  };
137 
138  deposit(ix , iy , kz_lo, wx0*wy0, wz_lo);
139  deposit(ix+1, iy , kz_lo, wx1*wy0, wz_lo);
140  deposit(ix , iy+1, kz_lo, wx0*wy1, wz_lo);
141  deposit(ix+1, iy+1, kz_lo, wx1*wy1, wz_lo);
142  deposit(ix , iy , kz_hi, wx0*wy0, wz_hi);
143  deposit(ix+1, iy , kz_hi, wx1*wy0, wz_hi);
144  deposit(ix , iy+1, kz_hi, wx0*wy1, wz_hi);
145  deposit(ix+1, iy+1, kz_hi, wx1*wy1, wz_hi);
146  });
147  }
148 
149  a_mf.SumBoundary(geom.periodicity());
150 }
151 
152 #endif
const Real dy
Definition: ERF_InitCustomPert_ABL.H:24
const Real dx
Definition: ERF_InitCustomPert_ABL.H:23
rho
Definition: ERF_InitCustomPert_Bubble.H:106
const Real dz
Definition: ERF_InitCustomPert_Bubble.H:25
ParallelFor(bx, [=] AMREX_GPU_DEVICE(int i, int j, int k) noexcept { const Real *dx=geomdata.CellSize();const Real x=(i+0.5) *dx[0];const Real y=(j+0.5) *dx[1];const Real Omg=erf_vortex_Gaussian(x, y, xc, yc, R, beta, sigma);const Real deltaT=-(gamma - 1.0)/(2.0 *sigma *sigma) *Omg *Omg;const Real rho_norm=std::pow(1.0+deltaT, inv_gm1);const Real T=(1.0+deltaT) *T_inf;const Real p=std::pow(rho_norm, Gamma)/Gamma *rho_0 *a_inf *a_inf;const Real rho_theta=rho_0 *rho_norm *(T *std::pow(p_0/p, rdOcp));state_pert(i, j, k, RhoTheta_comp)=rho_theta - getRhoThetagivenP(p_hse(i, j, k));const Real r2d_xy=std::sqrt((x-xc) *(x-xc)+(y-yc) *(y-yc));state_pert(i, j, k, RhoScalar_comp)=0.25 *(1.0+std::cos(PI *std::min(r2d_xy, R)/R));})
Real * p
Definition: ERF_InitCustomPert_SquallLine.H:61
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_ConsoleIO.cpp:12