Reprojection
Coordinate-transform template fragments (longitude-latitude, Lambert conformal, …) for use inside regridding and coupling expressions.
Coordinate-transform template fragments (longitude-latitude, Lambert conformal, …) for use inside regridding and coupling expressions.
These are forward/inverse scalar templates over the evaluable core — but they also apply in-model over coordinate arrays: invoke them inside a faq node whose bindings mix indexed reads, literals, and parameter references, and every apply_expression_template inlines (esm-spec §9.6.2 Option A) into a closed scalar AST at each cell. The tests/conformance/reprojection/lcc_grid_roundtrip case pins exactly this faq-mapped lowering: byte-identical expanded AST across all five bindings, and a working round-trip simulation on Julia + Python + Rust.
lambert_conformal
Source: reprojection/lambert_conformal.esm
Spherical Lambert Conformal Conic (PROJ +proj=lcc +R=…), as a template library (esm-spec 9.7) following the reprojection signature convention established by reprojection/longlat.esm: four public scalar templates lambert_conformal_forward_x / _forward_y (inputs lon, lat in DEGREES plus the projection constants; outputs easting/northing x, y in METRES) and lambert_conformal_inverse_lon / _inverse_lat (inputs x, y in metres plus the same constants; outputs degrees), plus five stem-prefixed helper templates (_t, _n, _F, _rho, _theta) that factor Snyder’s intermediate quantities – helper invocations inline at registration time by pure substitution (9.7.3), so every public template lowers to a closed scalar AST over the evaluable core (tan, atan, atan2, log, ^, sqrt, sign, sin, cos; all esm-spec 4.2 elementary functions). The projection constants {lat_1, lat_2 (standard parallels, deg), lat_0 (origin latitude, deg), lon_0 (central meridian, deg), R (sphere radius, m)} are TEMPLATE PARAMETERS, not metaparameters: metaparameters are load-time integers (9.7.6) while these are real-valued, and template parameters bind arbitrary expressions at each apply site – numeric literals for a fixed CRS, or parameter references so one document drives several parameter sets (the WRF CONUS and NEI2016 sets of the conformance manifest flow through this ONE library with different bindings). THE MATH (Snyder 1987, PP 1395, pp. 104-110, sphere; the same closed form as archive/reprojection/lambert_conformal.esm, re-expressed in the 0.8.0 library form): with phi = latpi/180 etc., cone constant n = ln(cos phi_1 / cos phi_2) / ln(tan(pi/4 + phi_2/2) / tan(pi/4 + phi_1/2)) (eq. 15-3), F = cos phi_1 * tan(pi/4 + phi_1/2)^n / n (15-2), rho = RF / tan(pi/4 + phi/2)^n (15-1, and rho_0 = rho at phi_0), theta = n*(lambda - lambda_0) (14-4); FORWARD x = rhosin(theta) (14-1), y = rho_0 - rhocos(theta) (14-2); INVERSE rho = sign(n)sqrt(x^2 + (rho_0 - y)^2) (14-10), theta = atan2(x, rho_0 - y) (14-11, n > 0 branch: for n < 0 Snyder reverses the signs of x, y, and rho_0 - y first – both documented parameter sets have n > 0, approx. 0.7156 for WRF 30/60 and 0.6305 for NEI2016 33/45), lat = (2atan((R*F/rho)^(1/n)) - pi/2)*180/pi (15-5), lon = lon_0 + (theta/n)*180/pi (14-9). inverse(forward(…)) is the algebraic identity wherever the forward map is defined (singular only at the far pole phi = -90 deg for n > 0). Radian-degree conversions are inlined as the double-precision literals pi/180 = 0.017453292519943295, 180/pi = 57.29577951308232, pi/4 = 0.7853981633974483, pi/360 = 0.008726646259971648, pi/2 = 1.5707963267948966. Independent analytic reference points (both parameter sets, forward + inverse + round-trip) live in tests/conformance/reprojection/lambert_conformal/golden/points.json.
Templates (9)
lambert_conformal_t(lat)
Helper: the conformal tangent t(lat) = tan(pi/4 + phi/2) with phi = latpi/180 (so the half-angle is latpi/360). The building block of Snyder eqs. 15-1..15-3.
lambert_conformal_n(lat_1, lat_2)
Helper: cone constant n = ln(cos phi_1 / cos phi_2) / ln(t(lat_2)/t(lat_1)) (Snyder eq. 15-3). Depends only on the standard parallels: approx. 0.715567 for WRF (30/60), 0.630478 for NEI2016 (33/45). Requires lat_1 != lat_2 (for equal parallels Snyder’s limit is n = sin phi_1, eq. 15-4 – not expressed here).
lambert_conformal_F(lat_1, lat_2)
Helper: F = cos phi_1 * t(lat_1)^n / n (Snyder eq. 15-2), the constant tying the cone to the unit sphere.
lambert_conformal_rho(lat, lat_1, lat_2, R)
Helper: rho = R*F / t(lat)^n (Snyder eq. 15-1), the cone radius of the parallel at lat (metres). rho_0 is this template invoked with lat bound to lat_0. Singular at the far pole (t -> 0 for n > 0 as lat -> -90).
lambert_conformal_theta(lon, lon_0, lat_1, lat_2)
Helper: theta = n * (lon - lon_0) * pi/180 (Snyder eq. 14-4), the polar angle on the developed cone (radians).
lambert_conformal_forward_x(lon, lat, lat_1, lat_2, lat_0, lon_0, R)
FORWARD, easting (metres): x = rho(lat) * sin(theta) (Snyder eq. 14-1). At lon = lon_0, theta = 0 so x = 0 (the central meridian is the y-axis). lat_0 is unused (x is independent of the origin latitude; uniform reprojection signature).
lambert_conformal_forward_y(lon, lat, lat_1, lat_2, lat_0, lon_0, R)
FORWARD, northing (metres): y = rho_0 - rho(lat) * cos(theta) (Snyder eq. 14-2), with rho_0 = rho at the origin latitude (the _rho helper invoked with lat bound to lat_0). At (lon_0, lat_0): theta = 0 and rho = rho_0, so y = 0 – the projection origin maps to the false origin (0, 0).
lambert_conformal_inverse_lon(x, y, lat_1, lat_2, lat_0, lon_0, R)
INVERSE, longitude (degrees): lon = lon_0 + (theta/n)180/pi with theta = atan2(x, rho_0 - y) (Snyder eqs. 14-11, 14-9; n > 0 branch of 14-11 – for n < 0 Snyder reverses the signs of x, y, rho_0 - y first, a case no documented parameter set exercises). atan2(rhosin theta, rho*cos theta) = theta for rho > 0, so this inverts the forward polar angle exactly.
lambert_conformal_inverse_lat(x, y, lat_1, lat_2, lat_0, lon_0, R)
INVERSE, latitude (degrees): lat = (2atan((RF/rho)^(1/n)) - pi/2)*180/pi (Snyder eq. 15-5), with rho = sign(n)sqrt(x^2 + (rho_0 - y)^2) (14-10, taking the sign of n) and rho_0 = rho(lat_0). Since RF/rho = t(lat)^n on the forward image, this recovers the input latitude: the round-trip identity. lon_0 is unused (uniform reprojection signature).
References
- Snyder, J. P. (1987). Map Projections – A Working Manual. U.S. Geological Survey Professional Paper 1395, pp. 104-110: Lambert Conformal Conic, sphere. Forward eqs. 14-1, 14-2, 14-4, 15-1, 15-2, 15-3; inverse eqs. 14-9, 14-10, 14-11, 15-5; numerical check example pp. 295-296.
longlat
Source: reprojection/longlat.esm
Geographic lon-lat ‘projection’ (PROJ +proj=longlat; identity / plate carree in degrees), as a template library (esm-spec 9.7). This is the CONVENTION-ESTABLISHING degenerate base case for the reprojection/ family: every esd:reproject library declares four match-less scalar templates –
Templates (4)
longlat_forward_x(lon, lat, lon_0)
FORWARD, x component (degrees): x = lon - lon_0. lat is unused (uniform reprojection signature).
longlat_forward_y(lon, lat, lon_0)
FORWARD, y component (degrees): y = lat. lon and lon_0 are unused (uniform reprojection signature).
longlat_inverse_lon(x, y, lon_0)
INVERSE, longitude (degrees): lon = x + lon_0. Composes with longlat_forward_x to the identity: (lon - lon_0) + lon_0 = lon.
longlat_inverse_lat(x, y, lon_0)
INVERSE, latitude (degrees): lat = y. x and lon_0 are unused (uniform reprojection signature).
References
- Snyder, J. P. (1987). Map Projections – A Working Manual. U.S. Geological Survey Professional Paper 1395, pp. 90-91 (Equirectangular projection, eqs. 12-1..12-6 with phi_1 = 0: the degenerate plate carree case, here kept in degrees).