ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_ImmersedBuildingMasks.H
Go to the documentation of this file.
1 /**
2  * \file ERF_ImmersedBuildingMasks.H
3  *
4  * How the buildings immersed forcing reads a momentum face and which forcing it applies there,
5  * shared by the source kernels (ImmersedForcingBuildings_{X,Y,Z}mom) and the implicit projection
6  * (ERF::make_if_projection_sigma, erf.if_implicit_projection, erf-model/ERF#4887), so the two
7  * agree face by face on the blanking, on which faces carry the MOST wall law and on which the
8  * linear drag toward zero.
9  */
10 #ifndef ERF_IMMERSED_BUILDING_MASKS_H_
11 #define ERF_IMMERSED_BUILDING_MASKS_H_
12 
13 #include <AMReX_Array4.H>
14 #include <AMReX_REAL.H>
15 #include <AMReX_GpuQualifiers.H>
16 
17 #include "ERF_NumericalConstants.H"
18 
19 namespace if_bld {
20 
21 /** Cell blanking snapped to solid (1) or fluid (0) at half (erf.if_snap_partial_cells), else as is */
22 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
23 amrex::Real snapped (amrex::Real b, bool snap) noexcept
24 {
25  return snap ? ((b >= myhalf) ? amrex::Real(one) : amrex::Real(zero)) : b;
26 }
27 
28 /**
29  * The face blanking the explicit path zeroes on after the projection (ERF_SlowRhsPost.cpp): the
30  * face-centred fraction when the build has it, else the mean of the two cells the face joins.
31  * (io, jo, ko) is the unit vector of the face's direction.
32  */
33 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
34 amrex::Real raw_face_blank (const amrex::Array4<const amrex::Real>& t, const amrex::Array4<const amrex::Real>& tf,
35  int i, int j, int k, int io, int jo, int ko) noexcept
36 {
37  return (tf) ? tf(i,j,k) : myhalf * (t(i,j,k) + t(i-io,j-jo,k-ko));
38 }
39 
40 /**
41  * The face blanking as the building kernels read it: with the snap, from the snapped cells (solid
42  * when either is), so both EB builds give the same staircase; otherwise raw_face_blank; then
43  * thresholded at small (eb2.small_volfrac), below which the face counts as fluid.
44  */
45 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
46 amrex::Real face_blank (const amrex::Array4<const amrex::Real>& t, const amrex::Array4<const amrex::Real>& tf,
47  int i, int j, int k, int io, int jo, int ko, bool snap, amrex::Real small) noexcept
48 {
49  const amrex::Real b = snap ? amrex::max(snapped(t(i,j,k), snap), snapped(t(i-io,j-jo,k-ko), snap))
50  : raw_face_blank(t, tf, i, j, k, io, jo, ko);
51  return (b < small) ? amrex::Real(zero) : b;
52 }
53 
54 /**
55  * A horizontal-momentum face (x or y) and its neighbours as the kernels read them. lo/hi are the
56  * neighbouring faces across the other horizontal direction: south/north for an x-face, west/east
57  * for a y-face. raw is the unthresholded blanking of the face (raw_face_blank); normal is true
58  * when, with the snap, the face joins a solid and a fluid cell (wall-normal).
59  */
60 struct HorizFace {
62  bool normal;
63 };
64 
65 /**
66  * @param t Cell blanking (with at least one ghost cell in each direction)
67  * @param tf Face-centred blanking of this direction, or an empty Array4
68  * @param klo Lowest cell index of the domain (the face below the domain bottom counts as fluid)
69  * @param snap erf.if_snap_partial_cells
70  * @param small eb2.small_volfrac
71  */
72 template <int dir>
73 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
74 HorizFace horiz_face (const amrex::Array4<const amrex::Real>& t, const amrex::Array4<const amrex::Real>& tf,
75  int i, int j, int k, int klo, bool snap, amrex::Real small) noexcept
76 {
77  static_assert(dir == 0 || dir == 1, "horiz_face: x- or y-faces only");
78  constexpr int io = (dir == 0) ? 1 : 0;
79  constexpr int jo = (dir == 1) ? 1 : 0;
80  HorizFace f;
81  f.t = face_blank(t, tf, i, j, k, io, jo, 0, snap, small);
82  f.below = (k == klo) ? amrex::Real(zero) : face_blank(t, tf, i, j, k-1, io, jo, 0, snap, small);
83  f.above = face_blank(t, tf, i, j, k+1, io, jo, 0, snap, small);
84  f.lo = (dir == 0) ? face_blank(t, tf, i, j-1, k, io, jo, 0, snap, small)
85  : face_blank(t, tf, i-1, j, k, io, jo, 0, snap, small);
86  f.hi = (dir == 0) ? face_blank(t, tf, i, j+1, k, io, jo, 0, snap, small)
87  : face_blank(t, tf, i+1, j, k, io, jo, 0, snap, small);
88  f.raw = raw_face_blank(t, tf, i, j, k, io, jo, 0);
89  f.normal = snap && (snapped(t(i,j,k), snap) != snapped(t(i-io,j-jo,k), snap));
90  return f;
91 }
92 
93 /** A z-face and its neighbours as the kernels read them (see HorizFace) */
94 struct VertFace {
96  bool normal;
97 };
98 
99 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
100 VertFace vert_face (const amrex::Array4<const amrex::Real>& t, const amrex::Array4<const amrex::Real>& tf,
101  int i, int j, int k, bool snap, amrex::Real small) noexcept
102 {
103  VertFace f;
104  f.t = face_blank(t, tf, i, j, k, 0, 0, 1, snap, small);
105  f.above = face_blank(t, tf, i, j, k+1, 0, 0, 1, snap, small);
106  f.south = face_blank(t, tf, i, j-1, k, 0, 0, 1, snap, small);
107  f.north = face_blank(t, tf, i, j+1, k, 0, 0, 1, snap, small);
108  f.west = face_blank(t, tf, i-1, j, k, 0, 0, 1, snap, small);
109  f.east = face_blank(t, tf, i+1, j, k, 0, 0, 1, snap, small);
110  f.raw = raw_face_blank(t, tf, i, j, k, 0, 0, 1);
111  f.normal = snap && (snapped(t(i,j,k), snap) != snapped(t(i,j,k-1), snap));
112  return f;
113 }
114 
115 /**
116  * Masks of a horizontal-momentum face (x or y). lo/hi are the neighbouring faces across the
117  * other horizontal direction: south/north for an x-face, west/east for a y-face.
118  */
119 struct HorizMasks {
121  //! faces carrying the MOST wall law (a target velocity from the log law)
122  [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
123  amrex::Real most () const noexcept { return roof + lo + hi; }
124  //! weight of the linear drag CdM |u| toward zero on this face, with t its blanking
125  [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
126  amrex::Real linear (amrex::Real t) const noexcept { return (wall + side) * t + interior; }
127 };
128 
129 /**
130  * @param t Blanking of the face
131  * @param below Blanking of the face below (zero at the domain bottom)
132  * @param above Blanking of the face above
133  * @param lo Blanking of the neighbouring face on the low side across the other direction
134  * @param hi Blanking of the neighbouring face on the high side across the other direction
135  * @param normal_face With the snap, a face joining a solid and a fluid cell (wall-normal)
136  * @param use_most erf.if_use_most
137  * @param snap erf.if_snap_partial_cells
138  */
139 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
141  amrex::Real lo, amrex::Real hi,
142  bool normal_face, bool use_most, bool snap) noexcept
143 {
144  HorizMasks m{};
145  // With the snap every solid face has t = 1: a roof face lies in the top solid row
146  // (t <= below, the face above fluid), and a face carrying a wall law is not also an
147  // interior face. A wall-normal face gets the interior drag (no penetration), not a wall law.
148  m.roof = (!normal_face && t > zero && (snap ? t <= below : t < below) && above == zero && use_most) ? one : zero;
149  m.lo = (!normal_face && t > zero && t <= hi && lo == zero && use_most) ? one : zero;
150  m.hi = (!normal_face && t > zero && t <= lo && hi == zero && use_most) ? one : zero;
151  m.wall = (t > zero && t < one && !use_most) ? one : zero; // all walls without MOST
152  m.side = (t > zero && t < one && use_most && m.most() == zero) ? one : zero; // partial faces not under MOST
153  m.interior = (t == one && !(snap && m.most() > zero)) ? one : zero;
154  return m;
155 }
156 
157 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
158 HorizMasks horiz_masks (const HorizFace& f, bool use_most, bool snap) noexcept
159 {
160  return horiz_masks(f.t, f.below, f.above, f.lo, f.hi, f.normal, use_most, snap);
161 }
162 
163 /**
164  * Masks of a z-face. The roof face takes the linear drag (weighted by its blanking), not a
165  * wall law; the four sides carry the wall law of the vertical walls.
166  */
167 struct VertMasks {
169  [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
170  amrex::Real most () const noexcept { return south + north + west + east; }
171  [[nodiscard]] AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
172  amrex::Real linear (amrex::Real t) const noexcept { return (wall + roof) * t + interior; }
173 };
174 
175 /**
176  * @param t Blanking of the face
177  * @param above Blanking of the face above
178  * @param south,north,west,east Blanking of the neighbouring z-faces
179  * @param above_floor The face is not the domain bottom (k >= 1)
180  * @param normal_face With the snap, a face joining a solid and a fluid cell (wall-normal)
181  * @param use_most erf.if_use_most
182  * @param snap erf.if_snap_partial_cells
183  */
184 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
186  amrex::Real south, amrex::Real north, amrex::Real west, amrex::Real east,
187  bool above_floor, bool normal_face, bool use_most, bool snap) noexcept
188 {
189  VertMasks m{};
190  m.south = (!normal_face && t > zero && t <= north && south == zero && use_most && above_floor) ? one : zero;
191  m.north = (!normal_face && t > zero && t <= south && north == zero && use_most && above_floor) ? one : zero;
192  m.west = (!normal_face && t > zero && t <= east && west == zero && use_most && above_floor) ? one : zero;
193  m.east = (!normal_face && t > zero && t <= west && east == zero && use_most && above_floor) ? one : zero;
194  m.wall = (t > zero && t < one && !use_most) ? one : zero;
195  m.roof = (!normal_face && t > zero && above == zero && use_most) ? one : zero;
196  // with the snap a face carrying a wall law or the roof drag is not also an interior face
197  m.interior = (t == one && !(snap && (m.most() + m.roof) > zero)) ? one : zero;
198  return m;
199 }
200 
201 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
202 VertMasks vert_masks (const VertFace& f, bool above_floor, bool use_most, bool snap) noexcept
203 {
204  return vert_masks(f.t, f.above, f.south, f.north, f.west, f.east, above_floor, f.normal, use_most, snap);
205 }
206 
207 /**
208  * Weight of the drag the implicit projection applies on a face (erf.if_implicit_projection):
209  * the linear-drag weight of the kernel, and the full rate on every face the explicit path zeroes
210  * after the projection (raw blanking 1, which the kernels leave without a wall law). The latter
211  * also caps the vertical roof face of an exact box without the snap, where the explicit kernel
212  * adds the roof and the interior drag together (weight 2 t), at one.
213  */
214 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
216 {
217  return (raw == one) ? amrex::Real(one) : linear;
218 }
219 
220 } // namespace if_bld
221 
222 #endif
const int klo
Definition: ERF_InitCustomPert_KE.H:9
Dimensionless numeric literals and pure mathematical constants.
constexpr amrex::Real one
Definition: ERF_NumericalConstants.H:37
constexpr amrex::Real zero
Definition: ERF_NumericalConstants.H:36
constexpr amrex::Real myhalf
Definition: ERF_NumericalConstants.H:41
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ t
Definition: ERF_WSM6.H:293
Definition: ERF_ImmersedBuildingMasks.H:19
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE HorizMasks horiz_masks(amrex::Real t, amrex::Real below, amrex::Real above, amrex::Real lo, amrex::Real hi, bool normal_face, bool use_most, bool snap) noexcept
Definition: ERF_ImmersedBuildingMasks.H:140
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real snapped(amrex::Real b, bool snap) noexcept
Definition: ERF_ImmersedBuildingMasks.H:23
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real face_blank(const amrex::Array4< const amrex::Real > &t, const amrex::Array4< const amrex::Real > &tf, int i, int j, int k, int io, int jo, int ko, bool snap, amrex::Real small) noexcept
Definition: ERF_ImmersedBuildingMasks.H:46
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE VertMasks vert_masks(amrex::Real t, amrex::Real above, amrex::Real south, amrex::Real north, amrex::Real west, amrex::Real east, bool above_floor, bool normal_face, bool use_most, bool snap) noexcept
Definition: ERF_ImmersedBuildingMasks.H:185
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real raw_face_blank(const amrex::Array4< const amrex::Real > &t, const amrex::Array4< const amrex::Real > &tf, int i, int j, int k, int io, int jo, int ko) noexcept
Definition: ERF_ImmersedBuildingMasks.H:34
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE HorizFace horiz_face(const amrex::Array4< const amrex::Real > &t, const amrex::Array4< const amrex::Real > &tf, int i, int j, int k, int klo, bool snap, amrex::Real small) noexcept
Definition: ERF_ImmersedBuildingMasks.H:74
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE VertFace vert_face(const amrex::Array4< const amrex::Real > &t, const amrex::Array4< const amrex::Real > &tf, int i, int j, int k, bool snap, amrex::Real small) noexcept
Definition: ERF_ImmersedBuildingMasks.H:100
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real implicit_weight(amrex::Real linear, amrex::Real raw) noexcept
Definition: ERF_ImmersedBuildingMasks.H:215
Definition: ERF_ImmersedBuildingMasks.H:60
amrex::Real t
Definition: ERF_ImmersedBuildingMasks.H:61
bool normal
Definition: ERF_ImmersedBuildingMasks.H:62
amrex::Real raw
Definition: ERF_ImmersedBuildingMasks.H:61
amrex::Real below
Definition: ERF_ImmersedBuildingMasks.H:61
amrex::Real lo
Definition: ERF_ImmersedBuildingMasks.H:61
amrex::Real hi
Definition: ERF_ImmersedBuildingMasks.H:61
amrex::Real above
Definition: ERF_ImmersedBuildingMasks.H:61
Definition: ERF_ImmersedBuildingMasks.H:119
amrex::Real lo
Definition: ERF_ImmersedBuildingMasks.H:120
amrex::Real hi
Definition: ERF_ImmersedBuildingMasks.H:120
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real linear(amrex::Real t) const noexcept
weight of the linear drag CdM |u| toward zero on this face, with t its blanking
Definition: ERF_ImmersedBuildingMasks.H:126
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real most() const noexcept
faces carrying the MOST wall law (a target velocity from the log law)
Definition: ERF_ImmersedBuildingMasks.H:123
amrex::Real roof
Definition: ERF_ImmersedBuildingMasks.H:120
amrex::Real wall
Definition: ERF_ImmersedBuildingMasks.H:120
amrex::Real side
Definition: ERF_ImmersedBuildingMasks.H:120
amrex::Real interior
Definition: ERF_ImmersedBuildingMasks.H:120
Definition: ERF_ImmersedBuildingMasks.H:94
amrex::Real north
Definition: ERF_ImmersedBuildingMasks.H:95
amrex::Real south
Definition: ERF_ImmersedBuildingMasks.H:95
amrex::Real t
Definition: ERF_ImmersedBuildingMasks.H:95
amrex::Real above
Definition: ERF_ImmersedBuildingMasks.H:95
amrex::Real raw
Definition: ERF_ImmersedBuildingMasks.H:95
bool normal
Definition: ERF_ImmersedBuildingMasks.H:96
amrex::Real west
Definition: ERF_ImmersedBuildingMasks.H:95
amrex::Real east
Definition: ERF_ImmersedBuildingMasks.H:95
Definition: ERF_ImmersedBuildingMasks.H:167
amrex::Real interior
Definition: ERF_ImmersedBuildingMasks.H:168
amrex::Real east
Definition: ERF_ImmersedBuildingMasks.H:168
amrex::Real north
Definition: ERF_ImmersedBuildingMasks.H:168
amrex::Real wall
Definition: ERF_ImmersedBuildingMasks.H:168
amrex::Real roof
Definition: ERF_ImmersedBuildingMasks.H:168
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real linear(amrex::Real t) const noexcept
Definition: ERF_ImmersedBuildingMasks.H:172
amrex::Real south
Definition: ERF_ImmersedBuildingMasks.H:168
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real most() const noexcept
Definition: ERF_ImmersedBuildingMasks.H:170
amrex::Real west
Definition: ERF_ImmersedBuildingMasks.H:168