ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_EarthRelativeWind.H
Go to the documentation of this file.
1 /**
2  * \file ERF_EarthRelativeWind.H
3  */
4 #ifndef ERF_EARTH_RELATIVE_WIND_H_
5 #define ERF_EARTH_RELATIVE_WIND_H_
6 
7 #include <AMReX_Array4.H>
8 #include <AMReX_GpuQualifiers.H>
9 #include <AMReX_REAL.H>
10 
11 #include "ERF_NumericalConstants.H"
12 
13 #include <cmath>
14 
15 //
16 // Earth-relative winds from grid-relative ones, shared by the 2D sampled-level
17 // fields and the station time series so that the two cannot disagree.
18 //
19 // (cos_alpha, sin_alpha) is the direction of the grid x axis (increasing i),
20 // counterclockwise from true east, as LatLonMap and grid_rotation_from_latlon
21 // return it. A grid-relative (u, v) wind is then
22 //
23 // u_east = u cos_alpha - v sin_alpha
24 // v_north = u sin_alpha + v cos_alpha
25 //
26 namespace erf_earth_wind {
27 
28 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
32 {
33  u_east = u * cos_alpha - v * sin_alpha;
34  v_north = u * sin_alpha + v * cos_alpha;
35 }
36 
37 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
39 {
40  return std::sqrt(u_east * u_east + v_north * v_north);
41 }
42 
43 //
44 // Meteorological wind direction in degrees, clockwise from north, of where the
45 // wind comes from, in [0, 360). A calm wind (speed <= 1e-12 m/s) has no
46 // direction, and missing_value is returned; the threshold catches an exactly
47 // zero wind, not a light one.
48 //
49 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
51  amrex::Real missing_value) noexcept
52 {
53  if (horizontal_speed(u_east, v_north) <= amrex::Real(1.0e-12)) {
54  return missing_value;
55  }
56  amrex::Real direction = amrex::Real(270.0)
57  - std::atan2(v_north, u_east) * amrex::Real(180.0) / PI;
58  while (direction < amrex::Real(0.0)) {
59  direction += amrex::Real(360.0);
60  }
61  while (direction >= amrex::Real(360.0)) {
62  direction -= amrex::Real(360.0);
63  }
64  return direction;
65 }
66 
67 //
68 // The orientation of the grid at mass point (i,j) of a lat/lon array ll
69 // (component 0 latitude, component 1 longitude, both in degrees): the
70 // direction of increasing i, counterclockwise from true east. The centred
71 // difference in i collapses to one side at ilo and ihi, the x extent of the
72 // domain; a domain one cell wide has no i direction, and gives (1, 0).
73 //
74 AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE
75 void grid_rotation_at (const amrex::Array4<const amrex::Real>& ll, int ilo, int ihi,
76  int i, int j, amrex::Real& cos_alpha, amrex::Real& sin_alpha) noexcept
77 {
78  const int im = (i - 1 > ilo) ? i - 1 : ilo;
79  const int ip = (i + 1 < ihi) ? i + 1 : ihi;
80  const amrex::Real inv_di = (ip > im) ? amrex::Real(1.0) / amrex::Real(ip - im)
81  : amrex::Real(0.0);
82 
83  // Displacement on the sphere per cell in i: east and north components, in
84  // degrees of latitude (the common factor, the Earth's radius, cancels).
85  // The longitude difference is taken the short way round the antimeridian.
86  amrex::Real dlon = ll(ip,j,0,1) - ll(im,j,0,1);
87  if (dlon > amrex::Real(180.0)) { dlon -= amrex::Real(360.0); }
88  if (dlon < -amrex::Real(180.0)) { dlon += amrex::Real(360.0); }
89  const amrex::Real lat = ll(i,j,0,0);
90  const amrex::Real north = (ll(ip,j,0,0) - ll(im,j,0,0)) * inv_di;
91  const amrex::Real east = dlon * inv_di * std::cos(lat * PI / amrex::Real(180.0));
92  const amrex::Real norm = std::sqrt(east*east + north*north);
93 
94  if (norm > amrex::Real(0.0)) {
95  cos_alpha = east / norm;
96  sin_alpha = north / norm;
97  } else {
98  cos_alpha = amrex::Real(1.0);
99  sin_alpha = amrex::Real(0.0);
100  }
101 }
102 
103 } // namespace erf_earth_wind
104 
105 #endif
Dimensionless numeric literals and pure mathematical constants.
constexpr amrex::Real PI
Definition: ERF_NumericalConstants.H:46
Real sin_alpha
Definition: ERF_Plotfile2DInterpolator.cpp:29
Real u_east
Definition: ERF_Plotfile2DInterpolator.cpp:21
Real v_north
Definition: ERF_Plotfile2DInterpolator.cpp:22
Real cos_alpha
Definition: ERF_Plotfile2DInterpolator.cpp:28
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_EarthRelativeWind.H:26
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void grid_to_earth(amrex::Real u, amrex::Real v, amrex::Real cos_alpha, amrex::Real sin_alpha, amrex::Real &u_east, amrex::Real &v_north) noexcept
Definition: ERF_EarthRelativeWind.H:29
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real horizontal_speed(amrex::Real u_east, amrex::Real v_north) noexcept
Definition: ERF_EarthRelativeWind.H:38
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE amrex::Real meteorological_direction(amrex::Real u_east, amrex::Real v_north, amrex::Real missing_value) noexcept
Definition: ERF_EarthRelativeWind.H:50
AMREX_GPU_HOST_DEVICE AMREX_FORCE_INLINE void grid_rotation_at(const amrex::Array4< const amrex::Real > &ll, int ilo, int ihi, int i, int j, amrex::Real &cos_alpha, amrex::Real &sin_alpha) noexcept
Definition: ERF_EarthRelativeWind.H:75