Skip to content

Commit 12653be

Browse files
cyschneckjukent
andauthored
GC: css2c (#152)
--------- Co-authored-by: Julia Kent <[email protected]>
1 parent 796b294 commit 12653be

File tree

5 files changed

+151
-31
lines changed

5 files changed

+151
-31
lines changed

environment.yml

+1
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@ channels:
33
- conda-forge
44
dependencies:
55
# Content
6+
- astropy
67
- cartopy
78
- geocat-comp
89
- geocat-datafiles

ncl/ncl_entries/great_circle.ipynb

+38-2
Original file line numberDiff line numberDiff line change
@@ -15,15 +15,16 @@
1515
"\n",
1616
"This section covers great circle functions from NCL:\n",
1717
"\n",
18-
"- [area_poly_sphere](https://www.ncl.ucar.edu/Document/Functions/Built-in/area_poly_sphere.shtml)"
18+
"- [area_poly_sphere](https://www.ncl.ucar.edu/Document/Functions/Built-in/area_poly_sphere.shtml)\n",
19+
"- [css2c](https://www.ncl.ucar.edu/Document/Functions/Built-in/css2c.shtml)"
1920
]
2021
},
2122
{
2223
"cell_type": "markdown",
2324
"metadata": {},
2425
"source": [
2526
"## area_poly_sphere\n",
26-
"NCL's `area_poly_sphere` calculates the area enclosed by an arbitrary polygon on the sphere\n",
27+
"NCL's `area_poly_sphere` calculates the area enclosed by an arbitrary polygon on the sphere\n",
2728
"\n",
2829
"<div class=\"admonition alert alert-info\">\n",
2930
" <p class=\"admonition-title\" style=\"font-weight:bold\">Important Note</p>\n",
@@ -58,6 +59,40 @@
5859
"poly_area_km2"
5960
]
6061
},
62+
{
63+
"cell_type": "markdown",
64+
"metadata": {},
65+
"source": [
66+
"## css2c\n",
67+
"NCL's `css2c` converts spherical (latitude/longitude) coordinates to Cartesian coordinates on a unit sphere"
68+
]
69+
},
70+
{
71+
"cell_type": "markdown",
72+
"metadata": {},
73+
"source": [
74+
"### Grab and Go"
75+
]
76+
},
77+
{
78+
"cell_type": "code",
79+
"execution_count": null,
80+
"metadata": {},
81+
"outputs": [],
82+
"source": [
83+
"from astropy.coordinates.representation import UnitSphericalRepresentation\n",
84+
"from astropy import units\n",
85+
"\n",
86+
"lat = 40.0150\n",
87+
"lon = -105.2705\n",
88+
"\n",
89+
"spherical_coords = UnitSphericalRepresentation(lat=lat * units.deg, lon=lon * units.deg)\n",
90+
"cart_coords = spherical_coords.to_cartesian()\n",
91+
"print(f\"X = {cart_coords.x.value}\")\n",
92+
"print(f\"Y = {cart_coords.y.value}\")\n",
93+
"print(f\"Z = {cart_coords.z.value}\")"
94+
]
95+
},
6196
{
6297
"cell_type": "markdown",
6398
"metadata": {},
@@ -71,6 +106,7 @@
71106
"source": [
72107
"## Python Resources\n",
73108
"- [pyroj.geod() great circle computations](https://pyproj4.github.io/pyproj/stable/api/geod.html)\n",
109+
"- [Astropy Coordinate Systems](https://docs.astropy.org/en/stable/coordinates/representations.html)\n",
74110
"\n",
75111
"## Additional Reading\n",
76112
"- [Aviation Formulary for working with great circles](https://www.edwilliams.org/avform147.htm)"

ncl/ncl_index/ncl-index-table.csv

+1
Original file line numberDiff line numberDiff line change
@@ -46,4 +46,5 @@ NCL Function,Description,Python Equivalent,Notes
4646
`daylight_fao56 <https://www.ncl.ucar.edu/Document/Functions/Crop/daylight_fao56.shtml>`__," Compute maximum number of daylight hours as described in FAO 56","``geocat.comp.meteorology.max_daylight()``",`example notebook <../ncl_entries/meteorology.ipynb#daylight-fao56>`__
4747
`dewtemp_trh <https://www.ncl.ucar.edu/Document/Functions/Built-in/dewtemp_trh.shtml>`__,"Calculates the dew point temperature given temperature and relative humidity","``geocat.comp.dewtemp()``",`example notebook <../ncl_entries/meteorology.ipynb#dewtemp-trh>`__
4848
`area_poly_sphere <https://www.ncl.ucar.edu/Document/Functions/Built-in/area_poly_sphere.shtml>`__,"Calculates the area enclosed by an arbitrary polygon on the sphere","``pyproj.Geod()`` and ``shapely.geometry.polygon.Polygon()``",`example notebook <../ncl_entries/great_circle.ipynb#area-poly-sphere>`__
49+
`css2c <https://www.ncl.ucar.edu/Document/Functions/Built-in/css2c.shtml>`__,"Converts spherical coordinates (lat/lon) to Cartesian coordinates on a unit sphere","``astropy.UnitSphericalRepresentation()``",`example notebook <../ncl_entries/great_circle.ipynb#css2c>`__
4950
`satvpr_temp_fao56 <https://www.ncl.ucar.edu/Document/Functions/Crop/satvpr_temp_fao56.shtml>`__," Compute saturation vapor pressure using temperature as described in FAO 56","``geocat.comp.saturation_vapor_pressure()``",`example notebook <../ncl_entries/meteorology.ipynb#satvpr-temp-fao56>`__

ncl/ncl_raw/great_circle.ncl

+15
Original file line numberDiff line numberDiff line change
@@ -68,3 +68,18 @@ print(gc_clkwise(lat7, lon7))
6868
; (0) True
6969
print(area_poly_sphere(lat7, lon7, 6370.997))
7070
;(0) 9401.705
71+
72+
; css2c
73+
; Adapted from https://www.ncl.ucar.edu/Document/Functions/Built-in/css2c.shtml
74+
75+
; ncl -n css2c.ncl >> css2c_output.txt
76+
77+
print("Latitude (Degree), Longitude (Degree), Cartesian X, Cartesian Y, Cartesian Z")
78+
do lat=-90,90
79+
do lon=-180,180
80+
begin
81+
cart = css2c(lat, lon)
82+
print (lat + "," + lon + "," + cart(0,0) + "," + cart(1,0) + "," + cart(2,0))
83+
end
84+
end do
85+
end do

ncl/receipts/great_circle.ipynb

+96-29
Original file line numberDiff line numberDiff line change
@@ -24,7 +24,8 @@
2424
"metadata": {},
2525
"source": [
2626
"## Functions covered\n",
27-
"- [area_poly_sphere](https://www.ncl.ucar.edu/Document/Functions/Built-in/area_poly_sphere.shtml)"
27+
"- [area_poly_sphere](https://www.ncl.ucar.edu/Document/Functions/Built-in/area_poly_sphere.shtml)\n",
28+
"- [css2c](https://www.ncl.ucar.edu/Document/Functions/Built-in/css2c.shtml)"
2829
]
2930
},
3031
{
@@ -53,10 +54,18 @@
5354
"## Python Functionality"
5455
]
5556
},
57+
{
58+
"cell_type": "markdown",
59+
"id": "6dc1d6c4-ac26-4346-9aa3-2c73182a7511",
60+
"metadata": {},
61+
"source": [
62+
"### area_poly_sphere"
63+
]
64+
},
5665
{
5766
"cell_type": "code",
5867
"execution_count": null,
59-
"id": "95225429-62d5-4d38-b170-850526c28107",
68+
"id": "2ba99b37-a743-4776-bc7b-d5a08b977642",
6069
"metadata": {},
6170
"outputs": [],
6271
"source": [
@@ -73,24 +82,8 @@
7382
" \"Half of the World\",\n",
7483
" \"Single Point -> Invalid NCL\",\n",
7584
" \"Single Degree\",\n",
76-
"]"
77-
]
78-
},
79-
{
80-
"cell_type": "markdown",
81-
"id": "6dc1d6c4-ac26-4346-9aa3-2c73182a7511",
82-
"metadata": {},
83-
"source": [
84-
"### area_poly_sphere"
85-
]
86-
},
87-
{
88-
"cell_type": "code",
89-
"execution_count": null,
90-
"id": "2ba99b37-a743-4776-bc7b-d5a08b977642",
91-
"metadata": {},
92-
"outputs": [],
93-
"source": [
85+
"]\n",
86+
"\n",
9487
"ncl_lat = [\n",
9588
" [40.0150, 42.3601, 29.5518],\n",
9689
" [41.00488, 41.00203, 37.00540, 37.00051],\n",
@@ -118,24 +111,68 @@
118111
"ncl_results[poly_name[4]] = 54450.39\n",
119112
"ncl_results[poly_name[5]] = 255032000\n",
120113
"ncl_results[poly_name[6]] = -127516000\n",
121-
"ncl_results[poly_name[7]] = 9401.705"
114+
"ncl_results[poly_name[7]] = 9401.705\n",
115+
"\n",
116+
"from pyproj import Geod\n",
117+
"\n",
118+
"python_results = {}\n",
119+
"geod = Geod(ellps=\"sphere\") # radius = 6370997 m\n",
120+
"for i in range(len(poly_name)):\n",
121+
" poly_area_m, _ = geod.polygon_area_perimeter(ncl_lon[i], ncl_lat[i])\n",
122+
" poly_area_km2 = abs(poly_area_m) * 1e-6\n",
123+
" python_results[poly_name[i]] = poly_area_km2"
124+
]
125+
},
126+
{
127+
"cell_type": "markdown",
128+
"id": "c0e65c3e-2377-47ec-b94c-e7eb753966d9",
129+
"metadata": {},
130+
"source": [
131+
"### css2c"
122132
]
123133
},
124134
{
125135
"cell_type": "code",
126136
"execution_count": null,
127-
"id": "35803c5d-bf83-4a35-b61c-50466d9d5095",
137+
"id": "35abde81-5843-4504-8e32-a137ee1aa094",
128138
"metadata": {},
129139
"outputs": [],
130140
"source": [
131-
"from pyproj import Geod\n",
141+
"import geocat.datafiles as gdf\n",
142+
"import numpy as np\n",
143+
"from astropy.coordinates.representation import UnitSphericalRepresentation\n",
144+
"from astropy import units\n",
132145
"\n",
133-
"python_results = {}\n",
134-
"geod = Geod(ellps=\"sphere\") # radius = 6370997 m\n",
135-
"for i in range(len(poly_name)):\n",
136-
" poly_area_m, _ = geod.polygon_area_perimeter(ncl_lon[i], ncl_lat[i])\n",
137-
" poly_area_km2 = abs(poly_area_m) * 1e-6\n",
138-
" python_results[poly_name[i]] = poly_area_km2"
146+
"css2c_data = gdf.get('applications_files/ncl_outputs/css2c_output.txt')\n",
147+
"css2c_data = np.loadtxt(css2c_data, delimiter=',', skiprows=6)\n",
148+
"\n",
149+
"lat_lon = tuple(map(tuple, (css2c_data[::, 0:2])))\n",
150+
"cart_values = css2c_data[::, 2:]\n",
151+
"ncl_css2c = dict(zip(lat_lon, cart_values))"
152+
]
153+
},
154+
{
155+
"cell_type": "code",
156+
"execution_count": null,
157+
"id": "ee104ea1-e287-4635-b404-5b06ccfb6949",
158+
"metadata": {},
159+
"outputs": [],
160+
"source": [
161+
"## Collect Latitude and Longtiude Pairs\n",
162+
"lat_lon = []\n",
163+
"for lat in range(-90, 90 + 1):\n",
164+
" for lon in range(-180, 180 + 1):\n",
165+
" lat_lon.append((lat, lon))\n",
166+
"\n",
167+
"## Calculate Cartesian coordinates\n",
168+
"astropy_css2c = {}\n",
169+
"for i, pair in enumerate(lat_lon):\n",
170+
" lat, lon = pair\n",
171+
" spherical_coords = UnitSphericalRepresentation(\n",
172+
" lat=lat * units.deg, lon=lon * units.deg\n",
173+
" )\n",
174+
" cart_coords = spherical_coords.to_cartesian()\n",
175+
" astropy_css2c[pair] = cart_coords.xyz.value"
139176
]
140177
},
141178
{
@@ -146,6 +183,14 @@
146183
"## Comparison"
147184
]
148185
},
186+
{
187+
"cell_type": "markdown",
188+
"id": "384790de-53f9-45d7-8bc1-fef86df21b57",
189+
"metadata": {},
190+
"source": [
191+
"### area_poly_sphere"
192+
]
193+
},
149194
{
150195
"cell_type": "markdown",
151196
"id": "cb61d4f0-bd10-4034-bfe8-b0c6e9137ec3",
@@ -180,6 +225,28 @@
180225
" if key != \"Single Point -> Invalid NCL\":\n",
181226
" assert False"
182227
]
228+
},
229+
{
230+
"cell_type": "markdown",
231+
"id": "57251c09-ef8c-438f-b3cf-cf798e7f4028",
232+
"metadata": {},
233+
"source": [
234+
"### css2c"
235+
]
236+
},
237+
{
238+
"cell_type": "code",
239+
"execution_count": null,
240+
"id": "d5738d2d-5abe-4ed4-8e90-c42881c2bfb0",
241+
"metadata": {},
242+
"outputs": [],
243+
"source": [
244+
"for key in ncl_css2c.keys():\n",
245+
" if key in astropy_css2c.keys():\n",
246+
" assert abs(ncl_css2c[key][0] - astropy_css2c[key][0]) < 0.000005\n",
247+
" assert abs(ncl_css2c[key][1] - astropy_css2c[key][1]) < 0.000005\n",
248+
" assert abs(ncl_css2c[key][2] - astropy_css2c[key][2]) < 0.000005"
249+
]
183250
}
184251
],
185252
"metadata": {

0 commit comments

Comments
 (0)