ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_ObsNudgingKernel.H
Go to the documentation of this file.
1 /**
2  * \file ERF_ObsNudgingKernel.H
3  */
4 #ifndef ERF_OBSNUDGINGKERNEL_H_
5 #define ERF_OBSNUDGINGKERNEL_H_
6 
7 #include <AMReX_Extension.H>
8 #include <AMReX_GpuQualifiers.H>
9 #include <AMReX_Math.H>
10 #include <AMReX_REAL.H>
11 
12 #include <cmath>
13 
14 namespace obs_nudging {
15 
16 //
17 // Everything the nudging tendency reads, as plain device pointers and numbers
18 // so that it can be captured by value in a device lambda.
19 //
20 // The measured profiles of every station are stored back to back: component c
21 // of station s has count[c*nstations + s] heights, starting at offset
22 // [c*nstations + s] in z, mean and sigma. A count of zero means the station
23 // does not measure c at this moment (or is inactive), and it is skipped.
24 //
26 {
27  int nstations = 0;
28  const amrex::Real* x = nullptr; // station position, domain coordinates
29  const amrex::Real* y = nullptr;
30  const int* agl = nullptr; // 1: heights above the local terrain
31  const int* offset = nullptr;
32  const int* count = nullptr;
33  const amrex::Real* z = nullptr;
34  const amrex::Real* mean = nullptr;
35  const amrex::Real* sigma = nullptr;
36 
37  amrex::Real inv_rh2 = amrex::Real(0.0); // 1 / R_h^2
38  amrex::Real inv_rz2 = amrex::Real(0.0); // 1 / R_z^2
39  amrex::Real qmax = amrex::Real(0.0); // stations with q above this are skipped
41  amrex::Real inv_tau = amrex::Real(0.0); // 1 / tau
42  amrex::Real max_rate = amrex::Real(0.0); // 1 / dt
43 
44  // Domain length in a periodic horizontal direction, 0 in one that is not
47 };
48 
49 //
50 // The separation d of two points along a direction of period L: the nearest
51 // periodic image when L > 0, so that the two copies of a face on a periodic
52 // boundary are equally far from every station.
53 //
54 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
57 {
58  if (L > amrex::Real(0.0)) {
59  d -= L * amrex::Math::round(d / L);
60  }
61  return d;
62 }
63 
64 //
65 // The nudging tendency of one component, d(phi)/dt, at a point.
66 //
67 // Station s has the weight
68 //
69 // w_s = exp(-q_s / 4), q_s = r_s^2 / R_h^2 + d_s^2 / R_z^2,
70 //
71 // where r_s is the horizontal distance to the station (to its nearest image in
72 // a periodic direction) and d_s the vertical distance outside the measured
73 // height range (zero inside it). Its target is the measured mean, interpolated
74 // linearly in height (held at the end values outside the range) and widened to
75 // the band mean +- alpha sigma: the local value is left alone inside the band
76 // and pulled to its nearer edge outside it,
77 //
78 // t_s = min(max(phi, mean - alpha sigma), mean + alpha sigma).
79 //
80 // The stations are combined into one relaxation,
81 //
82 // S = -min(W / tau, 1 / dt) (phi - tbar),
83 // W = min(1, sum_s w_s), tbar = sum_s w_s t_s / sum_s w_s,
84 //
85 // so that a point never relaxes faster than 1/tau however many stations are
86 // near it, and never overshoots its target within a step.
87 //
88 // x, y and z are the coordinates of the point, z_ground the terrain height
89 // under it.
90 //
91 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
95  amrex::Real phi) noexcept
96 {
97  amrex::Real sum_w = amrex::Real(0.0);
98  amrex::Real sum_wt = amrex::Real(0.0);
99 
100  for (int s = 0; s < v.nstations; ++s)
101  {
102  const int idx = comp*v.nstations + s;
103  const int n = v.count[idx];
104  if (n == 0) { continue; }
105  const int o = v.offset[idx];
106 
107  const amrex::Real h = (v.agl[s] != 0) ? (z - z_ground) : z;
108  const amrex::Real zlo = v.z[o];
109  const amrex::Real zhi = v.z[o+n-1];
110  const amrex::Real d = (h < zlo) ? (zlo - h) : ((h > zhi) ? (h - zhi) : amrex::Real(0.0));
111  const amrex::Real dxs = periodic_separation(x - v.x[s], v.period_x);
112  const amrex::Real dys = periodic_separation(y - v.y[s], v.period_y);
113  const amrex::Real q = (dxs*dxs + dys*dys) * v.inv_rh2 + d*d * v.inv_rz2;
114  if (q > v.qmax) { continue; }
115  const amrex::Real w = std::exp(amrex::Real(-0.25) * q);
116 
117  amrex::Real mean, sig;
118  if (h <= zlo) {
119  mean = v.mean[o];
120  sig = v.sigma[o];
121  } else if (h >= zhi) {
122  mean = v.mean[o+n-1];
123  sig = v.sigma[o+n-1];
124  } else {
125  int k = o;
126  while (v.z[k+1] < h) { ++k; }
127  const amrex::Real f = (h - v.z[k]) / (v.z[k+1] - v.z[k]);
128  mean = (amrex::Real(1.0) - f) * v.mean[k] + f * v.mean[k+1];
129  sig = (amrex::Real(1.0) - f) * v.sigma[k] + f * v.sigma[k+1];
130  }
131 
132  const amrex::Real band = v.sigma_factor * sig;
133  const amrex::Real target = amrex::min(amrex::max(phi, mean - band), mean + band);
134 
135  sum_w += w;
136  sum_wt += w * target;
137  }
138 
139  if (sum_w <= amrex::Real(0.0)) { return amrex::Real(0.0); }
140 
141  const amrex::Real tbar = sum_wt / sum_w;
142  const amrex::Real rate = amrex::min(amrex::min(sum_w, amrex::Real(1.0)) * v.inv_tau, v.max_rate);
143  return -rate * (phi - tbar);
144 }
145 
146 } // namespace obs_nudging
147 
148 #endif
if(KE_decay_height > 0 &&state_pert.nComp() > RhoKE_comp)
Definition: ERF_InitCustomPert_ABL.H:76
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int idx(int i, int j, int k, int nx, int ny)
Definition: ERF_InitForEnsemble.cpp:396
Real w
Definition: ERF_Plotfile2DInterpolator.cpp:22
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ q
Definition: ERF_WSM6.H:273
Definition: ERF_ObsNudging.cpp:22
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real periodic_separation(amrex::Real d, amrex::Real L) noexcept
Definition: ERF_ObsNudgingKernel.H:56
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real obs_nudging_tendency(const ObsNudgingView &v, int comp, amrex::Real x, amrex::Real y, amrex::Real z, amrex::Real z_ground, amrex::Real phi) noexcept
Definition: ERF_ObsNudgingKernel.H:93
Definition: ERF_ObsNudgingKernel.H:26
amrex::Real period_x
Definition: ERF_ObsNudgingKernel.H:45
const amrex::Real * x
Definition: ERF_ObsNudgingKernel.H:28
amrex::Real inv_rh2
Definition: ERF_ObsNudgingKernel.H:37
const int * count
Definition: ERF_ObsNudgingKernel.H:32
const amrex::Real * z
Definition: ERF_ObsNudgingKernel.H:33
const amrex::Real * y
Definition: ERF_ObsNudgingKernel.H:29
const amrex::Real * sigma
Definition: ERF_ObsNudgingKernel.H:35
const amrex::Real * mean
Definition: ERF_ObsNudgingKernel.H:34
amrex::Real qmax
Definition: ERF_ObsNudgingKernel.H:39
amrex::Real sigma_factor
Definition: ERF_ObsNudgingKernel.H:40
const int * agl
Definition: ERF_ObsNudgingKernel.H:30
int nstations
Definition: ERF_ObsNudgingKernel.H:27
amrex::Real period_y
Definition: ERF_ObsNudgingKernel.H:46
amrex::Real inv_tau
Definition: ERF_ObsNudgingKernel.H:41
const int * offset
Definition: ERF_ObsNudgingKernel.H:31
amrex::Real max_rate
Definition: ERF_ObsNudgingKernel.H:42
amrex::Real inv_rz2
Definition: ERF_ObsNudgingKernel.H:38