ERF
Energy Research and Forecasting: An Atmospheric Modeling Code
ERF_LatLonMap.H
Go to the documentation of this file.
1 /**
2  * \file ERF_LatLonMap.H
3  */
4 #ifndef ERF_LATLONMAP_H_
5 #define ERF_LATLONMAP_H_
6 
7 #include <AMReX_Array.H>
8 #include <AMReX_Array4.H>
9 #include <AMReX_Box.H>
10 #include <AMReX_BoxArray.H>
11 #include <AMReX_DistributionMapping.H>
12 #include <AMReX_Geometry.H>
13 #include <AMReX_MultiFab.H>
14 #include <AMReX_REAL.H>
15 
16 #include <algorithm>
17 #include <cmath>
18 #include <limits>
19 
20 //
21 // Placing a point given by latitude and longitude on the model grid.
22 //
23 // The model has no map projection of its own: a run initialized from a WRF or
24 // metgrid file carries the latitude and longitude of every level-0 mass point
25 // (lat_m / lon_m), whatever projection produced them. A requested point is
26 // found by searching those arrays for the nearest mass point and then inverting
27 // the map locally with one linear solve, which is exact for a map that is
28 // linear over a cell and well under a cell width in error for any smooth one.
29 // Longitude differences are taken the short way round, so a grid that crosses
30 // the antimeridian is handled like any other.
31 //
32 // The same arrays give the orientation of the grid: the direction in which the
33 // i index grows, measured counterclockwise from true east, is the angle alpha
34 // by which an earth-relative (east, north) wind has to be rotated to become a
35 // grid-relative (u, v) wind.
36 //
37 
38 //
39 // Invert the latitude/longitude map locally. Given the difference between the
40 // requested lat/lon and the lat/lon of a grid point, and the gradients of
41 // latitude and longitude with respect to the two horizontal index directions at
42 // that point, return the offset in cells from the grid point to the request.
43 //
44 // Returns false when the two gradients are parallel and the map is therefore not
45 // locally invertible. "Parallel" is judged relative to the gradients' size and
46 // to the precision: in single precision the determinant of an exactly
47 // degenerate map comes out of rounding at about 1e-8 of its scale squared, far
48 // above a fixed 1e-12, so the threshold is at least 64 machine epsilons (which
49 // leaves double precision at 1e-12).
50 //
51 inline bool
53  amrex::Real dlat_di, amrex::Real dlon_di,
54  amrex::Real dlat_dj, amrex::Real dlon_dj,
56 {
57  const amrex::Real scale = std::max(std::max(std::abs(dlat_di), std::abs(dlon_di)),
58  std::max(std::abs(dlat_dj), std::abs(dlon_dj)));
59  const amrex::Real det = dlat_di*dlon_dj - dlat_dj*dlon_di;
60  const amrex::Real rel = std::max(amrex::Real(1.0e-12),
62  if (scale <= amrex::Real(0.0) || std::abs(det) <= rel*scale*scale) {
63  return false;
64  }
65  di = ( dlat*dlon_dj - dlon*dlat_dj) / det;
66  dj = (-dlat*dlon_di + dlon*dlat_di) / det;
67  return true;
68 }
69 
70 //
71 // A longitude difference in degrees, brought into [-180, 180] so that two
72 // points either side of the antimeridian are close rather than 360 degrees apart.
73 //
74 inline amrex::Real
76 {
77  if (dlon > amrex::Real(180.0)) { return dlon - amrex::Real(360.0); }
78  if (dlon < -amrex::Real(180.0)) { return dlon + amrex::Real(360.0); }
79  return dlon;
80 }
81 
82 //
83 // The result of placing a latitude/longitude on the grid.
84 //
86 {
87  // Domain coordinates of the point
90 
91  // The lat/lon actually reached by (x,y): equals the request to within the
92  // accuracy of the local inverse
95 
96  // The nearest mass point, reported when the request cannot be placed
99 
100  // Orientation of the grid x axis, counterclockwise from true east
103 };
104 
105 enum class LatLonStatus {
106  Ok, // placed
107  Degenerate, // the lat/lon gradients are parallel near the point
108  TooFar // more than one cell from the nearest mass point: outside the domain
109 };
110 
111 //
112 // The orientation of the grid at mass point (i,j) of a lat/lon array ll
113 // (component 0 latitude, component 1 longitude, both in degrees) over the 2D
114 // domain dom: the direction of increasing i, counterclockwise from true east.
115 //
116 void grid_rotation_from_latlon (const amrex::Array4<const amrex::Real>& ll,
117  const amrex::Box& dom, int i, int j,
119 
120 //
121 // Place (req_lat, req_lon) on the grid described by the lat/lon array ll over
122 // the 2D domain dom, whose cell (i,j) is centred at problo + (i+1/2) dx. Host
123 // code; the whole array must be addressable.
124 //
125 LatLonStatus locate_latlon_on_grid (const amrex::Array4<const amrex::Real>& ll,
126  const amrex::Box& dom,
127  const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& problo,
128  const amrex::GpuArray<amrex::Real, AMREX_SPACEDIM>& dx,
129  amrex::Real req_lat, amrex::Real req_lon,
130  LatLonLocation& loc);
131 
132 // Copy lat and lon (2D, one component each) into the two components of latlon,
133 // all three on the same BoxArray and DistributionMapping
134 void pack_latlon (amrex::MultiFab& latlon, const amrex::MultiFab& lat, const amrex::MultiFab& lon);
135 
136 //
137 // The level-0 lat/lon arrays gathered onto the I/O rank, with the two
138 // questions asked of them answered there and broadcast. Every member function
139 // is collective: call it on every rank with the same arguments.
140 //
142 {
143 public:
144  // lat and lon are the level-0 mass-point arrays (lat_m[0], lon_m[0]),
145  // defined on ba2d/dm; geom0 is the level-0 geometry.
146  LatLonMap (const amrex::MultiFab& lat, const amrex::MultiFab& lon,
147  const amrex::BoxArray& ba2d, const amrex::DistributionMapping& dm,
148  const amrex::Geometry& geom0);
149 
150  // Place a latitude/longitude on the grid
151  LatLonStatus locate (amrex::Real req_lat, amrex::Real req_lon, LatLonLocation& loc) const;
152 
153  // Orientation of the grid at domain coordinates (x, y), from the cell that contains it
156 
157 private:
158  amrex::MultiFab m_ll; // one box on the I/O rank, lat and lon
159  amrex::Box m_dom; // the 2D level-0 domain
160  amrex::GpuArray<amrex::Real, AMREX_SPACEDIM> m_problo;
161  amrex::GpuArray<amrex::Real, AMREX_SPACEDIM> m_dx;
162 };
163 
164 #endif
auto problo
Definition: ERF_InitCustomPertVels_ABL.H:36
const Real dx
Definition: ERF_InitCustomPert_ABL.H:44
LatLonStatus
Definition: ERF_LatLonMap.H:105
LatLonStatus locate_latlon_on_grid(const amrex::Array4< const amrex::Real > &ll, const amrex::Box &dom, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &problo, const amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > &dx, amrex::Real req_lat, amrex::Real req_lon, LatLonLocation &loc)
amrex::Real wrap_longitude_difference(amrex::Real dlon)
Definition: ERF_LatLonMap.H:75
bool invert_latlon_offset(amrex::Real dlat, amrex::Real dlon, amrex::Real dlat_di, amrex::Real dlon_di, amrex::Real dlat_dj, amrex::Real dlon_dj, amrex::Real &di, amrex::Real &dj)
Definition: ERF_LatLonMap.H:52
void pack_latlon(amrex::MultiFab &latlon, const amrex::MultiFab &lat, const amrex::MultiFab &lon)
void grid_rotation_from_latlon(const amrex::Array4< const amrex::Real > &ll, const amrex::Box &dom, int i, int j, amrex::Real &cos_alpha, amrex::Real &sin_alpha)
Real sin_alpha
Definition: ERF_Plotfile2DInterpolator.cpp:28
Real cos_alpha
Definition: ERF_Plotfile2DInterpolator.cpp:27
amrex::Real Real
Definition: ERF_ShocInterface.H:19
Definition: ERF_LatLonMap.H:142
void rotation_at(amrex::Real x, amrex::Real y, amrex::Real &cos_alpha, amrex::Real &sin_alpha) const
Definition: ERF_LatLonMap.cpp:206
LatLonStatus locate(amrex::Real req_lat, amrex::Real req_lon, LatLonLocation &loc) const
Definition: ERF_LatLonMap.cpp:180
amrex::Box m_dom
Definition: ERF_LatLonMap.H:159
amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > m_dx
Definition: ERF_LatLonMap.H:161
amrex::GpuArray< amrex::Real, AMREX_SPACEDIM > m_problo
Definition: ERF_LatLonMap.H:160
LatLonMap(const amrex::MultiFab &lat, const amrex::MultiFab &lon, const amrex::BoxArray &ba2d, const amrex::DistributionMapping &dm, const amrex::Geometry &geom0)
Definition: ERF_LatLonMap.cpp:150
amrex::MultiFab m_ll
Definition: ERF_LatLonMap.H:158
real(c_double), parameter epsilon
Definition: ERF_module_model_constants.F90:12
real(c_double), private di
Definition: ERF_module_mp_morr_two_moment.F90:203
Definition: ERF_LatLonMap.H:86
amrex::Real cos_alpha
Definition: ERF_LatLonMap.H:101
amrex::Real lat
Definition: ERF_LatLonMap.H:93
amrex::Real x
Definition: ERF_LatLonMap.H:88
amrex::Real near_lat
Definition: ERF_LatLonMap.H:97
amrex::Real y
Definition: ERF_LatLonMap.H:89
amrex::Real sin_alpha
Definition: ERF_LatLonMap.H:102
amrex::Real near_lon
Definition: ERF_LatLonMap.H:98
amrex::Real lon
Definition: ERF_LatLonMap.H:94