ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_IBSEBSolar.H
Go to the documentation of this file.
1 #ifndef ERF_IBSEB_SOLAR_H
2 #define ERF_IBSEB_SOLAR_H
3 
4 #include <AMReX_REAL.H>
5 #include <AMReX_GpuQualifiers.H>
6 #include <AMReX_Algorithm.H>
8 #include <cmath>
9 
10 /**
11  * \file ERF_IBSEBSolar.H
12  * \brief Sun position, clear-sky shortwave, and the ray cast that decides
13  * whether a building face is in shadow.
14  *
15  * The solar geometry (Spencer's declination and equation of time, the hour
16  * angle from UTC and the site longitude, the zenith, the clockwise-from-north
17  * azimuth, the Earth-Sun distance) is kept here: the radiation models use
18  * the CESM orbital formulation of ERF_OrbCosZenith.H, which gives no
19  * azimuth and has no equation of time; orbital_hour_angle() turns its
20  * calendar day into the hour angle these functions take, for
21  * erf.ibseb.sun_mode = two_stream. The clear-sky formulas follow Bird (1984) as used by the SLUCM
22  * branch. The ray cast is new here.
23  *
24  * **Sun vector convention.** ``ibseb_sun_vector()`` returns the unit vector
25  * from a surface toward the sun, with azimuth measured clockwise from north:
26  * east is +x, north is +y, so ``s = (sin z sin a, sin z cos a, cos z)`` with
27  * z the zenith angle and a the azimuth. A face with outward normal n receives
28  * direct beam only when ``n . s > 0``.
29  *
30  * References: Spencer (1971); Duffie and Beckman (1991); Iqbal (1983);
31  * Bird and Hulstrom (1981).
32  */
33 namespace ibseb {
34 
35 /** Solar declination [rad] from the day of year (Spencer 1971). */
36 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
38 {
39  const amrex::Real gamma = 2.0 * PI * (day_of_year - 1.0) / 365.25;
40  return 0.006918
41  - 0.399912 * std::cos(gamma) + 0.070257 * std::sin(gamma)
42  - 0.006758 * std::cos(2.0 * gamma) + 0.000907 * std::sin(2.0 * gamma)
43  - 0.00248 * std::cos(3.0 * gamma) + 0.00031 * std::sin(3.0 * gamma);
44 }
45 
46 /** Equation of time [minutes] from the day of year (Spencer 1971). */
47 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
49 {
50  const amrex::Real gamma = 2.0 * PI * (day_of_year - 1.0) / 365.25;
51  return 229.18 * (0.000075 + 0.001868 * std::cos(gamma) - 0.032077 * std::sin(gamma)
52  - 0.014615 * std::cos(2.0 * gamma) - 0.040849 * std::sin(2.0 * gamma));
53 }
54 
55 /**
56  * Hour angle [rad] from the UTC time of day and the site: solar time is UTC
57  * plus one hour per 15 degrees of longitude (east positive) plus the equation
58  * of time, and the hour angle is 15 degrees per hour from solar noon,
59  * negative in the morning. The time zone plays no part (it would cancel).
60  */
61 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
62 amrex::Real solar_hour_angle (amrex::Real time_utc_s, amrex::Real longitude_deg, amrex::Real day_of_year)
63 {
64  amrex::Real t_utc_h = std::fmod(time_utc_s / 3600.0, 24.0);
65  if (t_utc_h < 0.0) { t_utc_h += 24.0; }
66  const amrex::Real t_solar_h = t_utc_h + longitude_deg / 15.0 + equation_of_time(day_of_year) / 60.0;
67  return 15.0 * (t_solar_h - 12.0) * PI / 180.0;
68 }
69 
70 /**
71  * Hour angle [rad] of the orbital formula the radiation models use
72  * (orbital_cos_zenith_instant() of ERF_OrbCosZenith.H): its
73  * ``cos z = sin(lat) sin(decl) - cos(lat) cos(decl) cos(2 pi frac(calday) + lon)``
74  * is the usual form with the hour angle ``2 pi frac(calday) + lon - pi``. The
75  * fraction of the calendar day is the UTC time of day and there is no equation
76  * of time, so local solar time is UTC plus one hour per 15 degrees of
77  * longitude. Wrapped to [-pi, pi), negative in the morning.
78  */
79 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
80 amrex::Real orbital_hour_angle (double calday, amrex::Real longitude_rad)
81 {
82  const double two_pi = 2.0 * double(PI);
83  double h = two_pi * (calday - std::floor(calday)) + double(longitude_rad) - double(PI);
84  h = std::fmod(h + double(PI), two_pi);
85  if (h < 0.0) { h += two_pi; }
86  return static_cast<amrex::Real>(h - double(PI));
87 }
88 
89 /** Zenith angle [rad] from the latitude, declination and hour angle. */
90 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
92 {
93  const amrex::Real lat = latitude_deg * PI / 180.0;
94  amrex::Real cz = std::sin(lat) * std::sin(decl) + std::cos(lat) * std::cos(decl) * std::cos(hour_angle);
95  if (cz < -1.0) { cz = -1.0; }
96  if (cz > 1.0) { cz = 1.0; }
97  return std::acos(cz);
98 }
99 
100 /**
101  * Azimuth [rad] clockwise from north (east is pi/2) from the latitude,
102  * declination, hour angle and zenith; north when the sun is at the zenith or
103  * the site is at a pole, where the azimuth is undefined.
104  */
105 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
107  amrex::Real hour_angle, amrex::Real zenith)
108 {
109  const amrex::Real lat = latitude_deg * PI / 180.0;
110  const amrex::Real sz = std::sin(zenith);
111  const amrex::Real cz = std::cos(zenith);
112  if (sz < 1.0e-6) { return 0.0; }
113  const amrex::Real cos_lat = std::cos(lat);
114  if (std::abs(cos_lat) < 1.0e-6) { return 0.0; }
115  // The hour angle is negative before solar noon, when the sun is east of
116  // south, hence the sign for the clockwise-from-north convention.
117  const amrex::Real sin_az = -std::sin(hour_angle) * std::cos(decl) / sz;
118  const amrex::Real cos_az = (std::sin(decl) - cz * std::sin(lat)) / (sz * cos_lat);
119  amrex::Real az = std::atan2(sin_az, cos_az);
120  if (az < 0.0) { az += 2.0 * PI; }
121  return az;
122 }
123 
124 /**
125  * Earth-Sun distance factor (d0/d)^2 that scales the solar constant for the
126  * day of year (Spencer 1971): about 1.034 at perihelion in early January,
127  * 0.967 at aphelion in early July, annual mean 1.
128  */
129 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
131 {
132  const amrex::Real G = 2.0 * PI * (day_of_year - 1.0) / 365.0;
133  return 1.000110 + 0.034221 * std::cos(G) + 0.001280 * std::sin(G)
134  + 0.000719 * std::cos(2.0 * G) + 0.000077 * std::sin(2.0 * G);
135 }
136 
137 /** Unit vector toward the sun from zenith and azimuth (east +x, north +y). */
138 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
139 void sun_vector (amrex::Real zenith, amrex::Real azimuth,
140  amrex::Real& sx, amrex::Real& sy, amrex::Real& sz)
141 {
142  const amrex::Real s = std::sin(zenith);
143  sx = s * std::sin(azimuth);
144  sy = s * std::cos(azimuth);
145  sz = std::cos(zenith);
146 }
147 
148 /**
149  * Clear-sky direct-normal irradiance [W/m2] (Bird form): the solar constant,
150  * corrected for the Earth-Sun distance, attenuated by ``tau^(1/cos z)``.
151  * Zero when the sun is below the horizon.
152  */
153 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
155  amrex::Real distance_factor)
156 {
157  if (cos_zenith <= 1.0e-3) return 0.0;
158  return S0 * distance_factor * std::pow(tau, 1.0 / cos_zenith);
159 }
160 
161 /**
162  * Clear-sky diffuse irradiance on a horizontal surface [W/m2]: a fraction
163  * ``k_d`` of what the direct beam lost to the atmosphere reaches the ground
164  * as diffuse light (Liu and Jordan form).
165  */
166 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
168  amrex::Real distance_factor, amrex::Real k_d)
169 {
170  if (cos_zenith <= 1.0e-3) return 0.0;
171  const amrex::Real tr = std::pow(tau, 1.0 / cos_zenith);
172  return k_d * S0 * distance_factor * cos_zenith * (1.0 - tr);
173 }
174 
175 /**
176  * Top height of a column of the level. The column map covers the bounding box
177  * of the built columns only (origin ``i0, j0`` in 0-based domain columns,
178  * ``bw x bh`` values indexed ``(ci - i0) * bh + (cj - j0)``); every other
179  * column is open ground. An entry is the domain-relative k of the highest
180  * solid cell of its column, or -1 where the column is fluid, so the top is
181  * one cell above that index and a fluid column sits at the ground.
182  */
183 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
184 amrex::Real column_top (const int* col_top, int ci, int cj,
185  int i0, int j0, int bw, int bh,
186  amrex::Real z_ground, amrex::Real dz)
187 {
188  ci -= i0; cj -= j0;
189  if (ci < 0 || ci >= bw || cj < 0 || cj >= bh) { return z_ground; }
190  const int kt = col_top[ci * bh + cj];
191  return (kt < 0) ? z_ground : z_ground + (kt + 1) * dz;
192 }
193 
194 /**
195  * Whether the ray from a face toward the sun hits a building.
196  *
197  * Buildings are represented by the top height of the columns of the level
198  * (``col_top`` over the built bounding box, see column_top(), replicated on
199  * every rank), so a ray is blocked wherever its height on entering a
200  * column is below that column's top: buildings stand on the ground, so the
201  * lowest point of the ray inside a column is at its entry, and the height
202  * only grows along a ray toward a sun above the horizon. The walk over the
203  * columns is a 2D digital differential analyser. It stops when the ray
204  * rises above the tallest column, leaves the domain in a non-periodic
205  * direction, or has travelled ``max_path``.
206  *
207  * The start point is nudged a little along the ray so a face does not
208  * test its own column at its own height: a wall starts in its fluid cell's
209  * column, whose top is below the face (no overhangs), and a roof starts a
210  * hair above its own top.
211  *
212  * @return true when blocked (the face is in shadow).
213  */
214 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
217  const int* col_top, int nx, int ny, int i0, int j0, int bw, int bh,
219  bool per_x, bool per_y, amrex::Real z_ground, amrex::Real z_max, amrex::Real max_path)
220 {
221  if (sz <= 0.0) return true; // sun at or below the horizon
222  if (z0 >= z_max) return false; // nothing stands this high
223  const amrex::Real eps = 1.0e-6 * amrex::min(dx, dy);
224  const amrex::Real t0 = 1.0e-3 * amrex::min(dx, dy);
225  amrex::Real x = x0 + t0 * sx, y = y0 + t0 * sy, z = z0 + t0 * sz;
226  int ci = static_cast<int>(std::floor((x - x_lo) / dx));
227  int cj = static_cast<int>(std::floor((y - y_lo) / dy));
228  const int stepx = (sx > 0.0) ? 1 : ((sx < 0.0) ? -1 : 0);
229  const int stepy = (sy > 0.0) ? 1 : ((sy < 0.0) ? -1 : 0);
230  const amrex::Real big = 1.0e30;
231  const amrex::Real tdx = (stepx != 0) ? dx / std::abs(sx) : big;
232  const amrex::Real tdy = (stepy != 0) ? dy / std::abs(sy) : big;
233  // Distance along the ray to the next column boundary in x and in y.
234  amrex::Real tmx = big, tmy = big;
235  if (stepx > 0) tmx = ((x_lo + (ci + 1) * dx) - x) / sx;
236  else if (stepx < 0) tmx = ((x_lo + ci * dx) - x) / sx;
237  if (stepy > 0) tmy = ((y_lo + (cj + 1) * dy) - y) / sy;
238  else if (stepy < 0) tmy = ((y_lo + cj * dy) - y) / sy;
239  amrex::Real t = 0.0;
240  const int max_iter = 4 * (nx + ny) + 8;
241  for (int it = 0; it < max_iter; ++it) {
242  // Column (ci, cj) with the ray entering at height z.
243  if (ci < 0 || ci >= nx) {
244  if (!per_x) return false;
245  ci = (ci % nx + nx) % nx;
246  }
247  if (cj < 0 || cj >= ny) {
248  if (!per_y) return false;
249  cj = (cj % ny + ny) % ny;
250  }
251  if (z + eps < column_top(col_top, ci, cj, i0, j0, bw, bh, z_ground, dz)) return true;
252  // Step to the next column.
253  if (tmx < tmy) { t = tmx; tmx += tdx; ci += stepx; }
254  else { t = tmy; tmy += tdy; cj += stepy; }
255  z = z0 + t0 * sz + t * sz;
256  if (z >= z_max) return false;
257  if (t > max_path) return false;
258  }
259  return false;
260 }
261 
262 /// What a ray from a face ends on.
263 enum RayHit : int { RAY_SKY = 0, RAY_GROUND = 1, RAY_BUILDING = 2 };
264 
265 /**
266  * Where a ray from a face ends: sky, ground or a building, for any
267  * direction (the hemisphere sampling of the view fractions). The same column walk as
268  * ray_blocked(), with the height test made direction-aware:
269  *
270  * - rising or level rays (``sz >= 0``) are blocked by a column whose top is
271  * above the entry height; a level ray that crosses ``max_path`` without a
272  * hit ends at the horizon, which counts as sky;
273  * - falling rays (``sz < 0``) are blocked by a solid column whose top is
274  * above the exit height (the ray descends inside the column) and reach
275  * the ground where the exit height is at or below ``z_ground``.
276  *
277  * Solid columns are those with a top above the ground. The domain is
278  * wrapped in periodic directions; leaving it in a non-periodic direction
279  * counts as sky for a rising ray and as ground for a falling one.
280  */
281 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
284  const int* col_top, int nx, int ny, int i0, int j0, int bw, int bh,
286  bool per_x, bool per_y, amrex::Real z_ground, amrex::Real z_max,
287  amrex::Real max_path)
288 {
289  const amrex::Real eps = 1.0e-6 * amrex::min(dx, dy);
290  if (sz > 0.0 && z0 >= z_max) return RAY_SKY;
291  const amrex::Real t0 = 1.0e-3 * amrex::min(dx, dy);
292  amrex::Real x = x0 + t0 * sx, y = y0 + t0 * sy, z = z0 + t0 * sz;
293  int ci = static_cast<int>(std::floor((x - x_lo) / dx));
294  int cj = static_cast<int>(std::floor((y - y_lo) / dy));
295  const int stepx = (sx > 0.0) ? 1 : ((sx < 0.0) ? -1 : 0);
296  const int stepy = (sy > 0.0) ? 1 : ((sy < 0.0) ? -1 : 0);
297  const amrex::Real big = 1.0e30;
298  const amrex::Real tdx = (stepx != 0) ? dx / std::abs(sx) : big;
299  const amrex::Real tdy = (stepy != 0) ? dy / std::abs(sy) : big;
300  amrex::Real tmx = big, tmy = big;
301  if (stepx > 0) tmx = ((x_lo + (ci + 1) * dx) - x) / sx;
302  else if (stepx < 0) tmx = ((x_lo + ci * dx) - x) / sx;
303  if (stepy > 0) tmy = ((y_lo + (cj + 1) * dy) - y) / sy;
304  else if (stepy < 0) tmy = ((y_lo + cj * dy) - y) / sy;
305  if (stepx == 0 && stepy == 0) { // vertical ray
306  if (sz > 0.0) return RAY_SKY;
307  // straight down from a wall face never happens (the face is vertical);
308  // from a roof the hemisphere points up. Treat as ground for safety.
309  return RAY_GROUND;
310  }
311  amrex::Real t = 0.0;
312  const int max_iter = 4 * (nx + ny) + 8;
313  for (int it = 0; it < max_iter; ++it) {
314  if (ci < 0 || ci >= nx) {
315  if (!per_x) return (sz >= 0.0) ? RAY_SKY : RAY_GROUND;
316  ci = (ci % nx + nx) % nx;
317  }
318  if (cj < 0 || cj >= ny) {
319  if (!per_y) return (sz >= 0.0) ? RAY_SKY : RAY_GROUND;
320  cj = (cj % ny + ny) % ny;
321  }
322  const amrex::Real top = column_top(col_top, ci, cj, i0, j0, bw, bh, z_ground, dz);
323  const bool solid = (top > z_ground + eps);
324  const amrex::Real t_next = amrex::min(tmx, tmy);
325  const amrex::Real z_out = z0 + t0 * sz + t_next * sz;
326  if (sz >= 0.0) {
327  if (solid && z + eps < top) return RAY_BUILDING;
328  } else {
329  if (solid && z + eps < top) return RAY_BUILDING; // entered below the top
330  if (solid && z_out < top - eps) return RAY_BUILDING; // descends into it
331  if (z_out <= z_ground + eps) return RAY_GROUND;
332  }
333  if (tmx < tmy) { t = tmx; tmx += tdx; ci += stepx; }
334  else { t = tmy; tmy += tdy; cj += stepy; }
335  z = z_out;
336  if (sz > 0.0 && z >= z_max) return RAY_SKY;
337  if (t > max_path) return (sz >= 0.0) ? RAY_SKY : RAY_GROUND;
338  }
339  return (sz >= 0.0) ? RAY_SKY : RAY_GROUND;
340 }
341 
342 /**
343  * Direction of the ``(ia, ie)`` sample of a cosine-weighted hemisphere
344  * around the outward normal of a face with direction ``dir`` and normal
345  * sign ``nsign`` (+1 along the axis, -1 against it). Stratified in the
346  * azimuth ``phi = 2 pi (ia + 1/2) / n_az`` and in ``u = (ie + 1/2) / n_el``
347  * with ``theta = asin(sqrt(u))`` from the normal, so every sample carries
348  * the same weight and the counts are view factors.
349  */
350 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
351 void hemisphere_direction (int dir, int nsign, int ia, int ie, int n_az, int n_el,
352  amrex::Real& sx, amrex::Real& sy, amrex::Real& sz)
353 {
354  const amrex::Real u = (ie + 0.5) / n_el;
355  const amrex::Real theta = std::asin(std::sqrt(u));
356  const amrex::Real phi = 2.0 * PI * (ia + 0.5) / n_az;
357  const amrex::Real cn = std::cos(theta), ct = std::sin(theta) * std::cos(phi), st = std::sin(theta) * std::sin(phi);
358  // Normal and two tangents for each axis.
359  amrex::Real n[3] = {0.0, 0.0, 0.0}, t1[3] = {0.0, 0.0, 0.0}, t2[3] = {0.0, 0.0, 0.0};
360  n[dir] = nsign;
361  if (dir == 0) { t1[1] = 1.0; t2[2] = 1.0; }
362  else if (dir == 1) { t1[0] = 1.0; t2[2] = 1.0; }
363  else { t1[0] = 1.0; t2[1] = 1.0; }
364  sx = cn * n[0] + ct * t1[0] + st * t2[0];
365  sy = cn * n[1] + ct * t1[1] + st * t2[1];
366  sz = cn * n[2] + ct * t1[2] + st * t2[2];
367 }
368 
369 } // namespace ibseb
370 
371 #endif
const int nx
Definition: ERF_InitCustomPertVels_CloudChamber.H:14
const int ny
Definition: ERF_InitCustomPertVels_CloudChamber.H:15
Real z0
Definition: ERF_InitCustomPertVels_ScalarAdvDiff.H:8
const Real dy
Definition: ERF_InitCustomPert_ABL.H:45
const Real dx
Definition: ERF_InitCustomPert_ABL.H:44
amrex::Real gamma
Definition: ERF_InitCustomPert_DataAssimilation_ISV.H:9
Dimensionless numeric literals and pure mathematical constants.
constexpr amrex::Real PI
Definition: ERF_NumericalConstants.H:46
amrex::Real Real
Definition: ERF_ShocInterface.H:19
@ theta
Definition: ERF_Kessler.H:26
@ dz
Definition: ERF_AdvanceWDM6.cpp:272
@ t
Definition: ERF_WSM6.H:272
Definition: ERF_IBSEBBalance.H:51
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void hemisphere_direction(int dir, int nsign, int ia, int ie, int n_az, int n_el, amrex::Real &sx, amrex::Real &sy, amrex::Real &sz)
Definition: ERF_IBSEBSolar.H:351
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real solar_zenith(amrex::Real latitude_deg, amrex::Real decl, amrex::Real hour_angle)
Definition: ERF_IBSEBSolar.H:91
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE int ray_hit(amrex::Real x0, amrex::Real y0, amrex::Real z0, amrex::Real sx, amrex::Real sy, amrex::Real sz, const int *col_top, int nx, int ny, int i0, int j0, int bw, int bh, amrex::Real x_lo, amrex::Real y_lo, amrex::Real dx, amrex::Real dy, amrex::Real dz, bool per_x, bool per_y, amrex::Real z_ground, amrex::Real z_max, amrex::Real max_path)
Definition: ERF_IBSEBSolar.H:282
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real clear_sky_dni(amrex::Real cos_zenith, amrex::Real S0, amrex::Real tau, amrex::Real distance_factor)
Definition: ERF_IBSEBSolar.H:154
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real orbital_hour_angle(double calday, amrex::Real longitude_rad)
Definition: ERF_IBSEBSolar.H:80
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real column_top(const int *col_top, int ci, int cj, int i0, int j0, int bw, int bh, amrex::Real z_ground, amrex::Real dz)
Definition: ERF_IBSEBSolar.H:184
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real equation_of_time(amrex::Real day_of_year)
Definition: ERF_IBSEBSolar.H:48
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real earth_sun_distance_factor(amrex::Real day_of_year)
Definition: ERF_IBSEBSolar.H:130
RayHit
What a ray from a face ends on.
Definition: ERF_IBSEBSolar.H:263
@ RAY_GROUND
Definition: ERF_IBSEBSolar.H:263
@ RAY_SKY
Definition: ERF_IBSEBSolar.H:263
@ RAY_BUILDING
Definition: ERF_IBSEBSolar.H:263
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void sun_vector(amrex::Real zenith, amrex::Real azimuth, amrex::Real &sx, amrex::Real &sy, amrex::Real &sz)
Definition: ERF_IBSEBSolar.H:139
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE bool ray_blocked(amrex::Real x0, amrex::Real y0, amrex::Real z0, amrex::Real sx, amrex::Real sy, amrex::Real sz, const int *col_top, int nx, int ny, int i0, int j0, int bw, int bh, amrex::Real x_lo, amrex::Real y_lo, amrex::Real dx, amrex::Real dy, amrex::Real dz, bool per_x, bool per_y, amrex::Real z_ground, amrex::Real z_max, amrex::Real max_path)
Definition: ERF_IBSEBSolar.H:215
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real solar_azimuth(amrex::Real latitude_deg, amrex::Real decl, amrex::Real hour_angle, amrex::Real zenith)
Definition: ERF_IBSEBSolar.H:106
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real solar_declination(amrex::Real day_of_year)
Definition: ERF_IBSEBSolar.H:37
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real solar_hour_angle(amrex::Real time_utc_s, amrex::Real longitude_deg, amrex::Real day_of_year)
Definition: ERF_IBSEBSolar.H:62
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real clear_sky_diffuse_h(amrex::Real cos_zenith, amrex::Real S0, amrex::Real tau, amrex::Real distance_factor, amrex::Real k_d)
Definition: ERF_IBSEBSolar.H:167
real(c_double), parameter t0
Definition: ERF_module_model_constants.F90:39
real(c_double), private ci
Definition: ERF_module_mp_morr_two_moment.F90:203