Skip to content

Commit e429501

Browse files
authored
Merge pull request #160 from xylar/add_ismip6_regions
Add ISMIP6 Antarctic ocean regions
2 parents 24dce0a + 3ce5d30 commit e429501

File tree

12 files changed

+44690
-2
lines changed

12 files changed

+44690
-2
lines changed
Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
# ISMIP6 Antarctic Ocean Regions
2+
3+
Features used to compute regional and temporal mean temperature and salinity
4+
for comparison with the model selection process in
5+
[Barthel et al. (2020)](https://doi.org/10.5194/tc-14-855-2020), which was
6+
used to select CMIP5 models for
7+
[ISMIP6](http://www.climate-cryosphere.org/mips/ismip6).
Lines changed: 285 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,285 @@
1+
#!/usr/bin/env python
2+
3+
import shapely.geometry
4+
import shapely.ops
5+
import numpy
6+
import xarray
7+
import os
8+
import matplotlib.pyplot as plt
9+
import pyproj
10+
import zipfile
11+
import shutil
12+
13+
from geometric_features import GeometricFeatures, FeatureCollection
14+
from geometric_features.feature_collection import _round_coords
15+
16+
from geometric_features.download import download_files
17+
from geometric_features.utils import write_feature_names_and_tags
18+
19+
20+
def bedmap2_bin_to_netcdf(outFileName):
21+
22+
if os.path.exists(outFileName):
23+
return
24+
25+
fields = ['bed', 'surface', 'thickness', 'coverage', 'rockmask',
26+
'grounded_bed_uncertainty', 'icemask_grounded_and_shelves']
27+
28+
allExist = True
29+
for field in fields:
30+
fileName = 'bedmap2/bedmap2_bin/bedmap2_{}.flt'.format(field)
31+
if not os.path.exists(fileName):
32+
allExist = False
33+
break
34+
35+
if not allExist:
36+
# download
37+
baseURL = 'https://secure.antarctica.ac.uk/data/bedmap2'
38+
fileNames = ['bedmap2_bin.zip']
39+
40+
download_files(fileNames, baseURL, 'bedmap2')
41+
42+
print('Decompressing Bedmap2 data...')
43+
# unzip
44+
with zipfile.ZipFile('bedmap2/bedmap2_bin.zip', 'r') as f:
45+
f.extractall('bedmap2/')
46+
print(' Done.')
47+
48+
print('Converting Bedmap2 to NetCDF...')
49+
ds = xarray.Dataset()
50+
x = numpy.linspace(-3333000., 3333000., 6667)
51+
y = x
52+
ds['x'] = ('x', x)
53+
ds.x.attrs['units'] = 'meters'
54+
ds['y'] = ('y', y)
55+
ds.y.attrs['units'] = 'meters'
56+
ds.attrs['Grid'] = "Datum = WGS84, earth_radius = 6378137., " \
57+
"earth_eccentricity = 0.081819190842621, " \
58+
"falseeasting = -3333000., " \
59+
"falsenorthing = -3333000., " \
60+
"standard_parallel = -71., central_meridien = 0, " \
61+
"EPSG=3031"
62+
ds.attrs['proj'] = "+proj=stere +lat_0=-90 +lat_ts=-71 +lon_0=0 +k=1 " \
63+
"+x_0=0 +y_0=0 +datum=WGS84 +units=m +no_defs"
64+
ds.attrs['proj4'] = "+init=epsg:3031"
65+
66+
# Antarctic stereographic
67+
inProj = pyproj.Proj(init='epsg:3031')
68+
# lon/lat
69+
outProj = pyproj.Proj(init='epsg:4326')
70+
X, Y = numpy.meshgrid(x, y)
71+
Lon, Lat = pyproj.transform(inProj, outProj, X, Y)
72+
73+
ds['lon'] = (('y', 'x'), Lon)
74+
ds.lon.attrs['units'] = 'degrees east'
75+
ds['lat'] = (('y', 'x'), Lat)
76+
ds.lat.attrs['units'] = 'degrees north'
77+
78+
# add Bedmap2 data
79+
for fieldName in fields:
80+
fileName = 'bedmap2/bedmap2_bin/bedmap2_{}.flt'.format(fieldName)
81+
with open(fileName, 'r') as f:
82+
field = numpy.fromfile(f, dtype=numpy.float32).reshape(6667, 6667)
83+
# flip the y axis
84+
field = field[::-1, :]
85+
# switch invalid values to be NaN (as expected by xarray)
86+
field[field == -9999.] = numpy.nan
87+
if fieldName == 'rockmask':
88+
# rock mask is zero where rock and -9999 (now NaN) elsewhere
89+
field = numpy.array(numpy.isfinite(field), numpy.float32)
90+
if fieldName == 'icemask_grounded_and_shelves':
91+
# split into separate grounded and floating masks
92+
ds['icemask_grounded'] = \
93+
(('y', 'x'), numpy.array(field == 0, numpy.float32))
94+
ds['icemask_shelves'] = \
95+
(('y', 'x'), numpy.array(field == 1, numpy.float32))
96+
ds['open_ocean_mask'] = \
97+
(('y', 'x'), numpy.array(numpy.isnan(field), numpy.float32))
98+
else:
99+
ds[fieldName] = (('y', 'x'), field)
100+
101+
ds.to_netcdf(outFileName)
102+
print(' Done.')
103+
104+
105+
def get_longest_contour(contourValue, author):
106+
107+
def stereo_to_lon_lat(x, y):
108+
return pyproj.transform(inProj, outProj, x, y)
109+
110+
ds = xarray.open_dataset('bedmap2.nc')
111+
112+
# plot contours
113+
plt.figure()
114+
cs = plt.contour(ds.x.values, ds.y.values, ds.bed, (contourValue,))
115+
paths = cs.collections[0].get_paths()
116+
117+
pathLengths = [len(paths[i]) for i in range(len(paths))]
118+
iLongest = numpy.argmax(pathLengths)
119+
120+
p = paths[iLongest]
121+
v = p.vertices
122+
x = v[:, 0]
123+
y = v[:, 1]
124+
125+
# Antarctic stereographic
126+
inProj = pyproj.Proj(init='epsg:3031')
127+
# lon/lat
128+
outProj = pyproj.Proj(init='epsg:4326')
129+
130+
poly = shapely.geometry.Polygon([(i[0], i[1]) for i in zip(x, y)])
131+
132+
epsilon = 1e-14
133+
minY = numpy.amin(y)
134+
wedge = shapely.geometry.Polygon([(epsilon, minY),
135+
(epsilon**2, -epsilon),
136+
(0, epsilon),
137+
(-epsilon**2, -epsilon),
138+
(-epsilon, minY),
139+
(epsilon, minY)])
140+
141+
difference = poly.difference(wedge)
142+
143+
difference = shapely.ops.transform(stereo_to_lon_lat, difference)
144+
145+
fc = FeatureCollection()
146+
147+
geometry = shapely.geometry.mapping(difference)
148+
# get rid of the wedge again by rounding the coordinates
149+
geometry['coordinates'] = _round_coords(geometry['coordinates'])
150+
151+
fc.add_feature(
152+
{"type": "Feature",
153+
"properties": {"name": "Contour {}".format(contourValue),
154+
"author": author,
155+
"object": 'region',
156+
"component": 'ocean'},
157+
"geometry": geometry})
158+
159+
return fc
160+
161+
162+
def make_polygon(lons, lats, name, author, tags):
163+
fc = FeatureCollection()
164+
165+
coords = list()
166+
for index in range(len(lons)):
167+
coords.append([lons[index], lats[index]])
168+
coords.append([lons[0], lats[0]])
169+
170+
fc.add_feature(
171+
{"type": "Feature",
172+
"properties": {"name": name,
173+
"author": author,
174+
"object": 'region',
175+
"component": 'ocean',
176+
"tags": tags,
177+
"zmin": -1500.,
178+
"zmax": -200.},
179+
"geometry": {
180+
"type": "Polygon",
181+
"coordinates": [coords]}})
182+
return fc
183+
184+
185+
def shelf_polygon(lons, lats, name, author, tags, fcContour):
186+
fc = make_polygon(lons, lats, name, author, tags)
187+
188+
lons = [-180., -180., 180., 180.]
189+
lats = [-90., 90., 90., -90.]
190+
fc_world = make_polygon(lons, lats, name, author, tags)
191+
192+
fcContour = fc_world.difference(fcContour)
193+
194+
fcShelf = fc.difference(fcContour)
195+
196+
props = fcShelf.features[0]['properties']
197+
props['name'] = props['name'] + ' Shelf'
198+
props['tags'] = props['tags'] + ';Shelf'
199+
props['zmin'] = -1500.
200+
props['zmax'] = -200.
201+
202+
return fcShelf
203+
204+
205+
def main():
206+
author = 'Xylar Asay-Davis, Alice Barthel, Nicolas Jourdain'
207+
tags = 'Antarctic;ISMIP6'
208+
209+
# make a geometric features object that knows about the geometric data
210+
# cache up a couple of directories
211+
gf = GeometricFeatures('../../geometric_data')
212+
213+
bedmap2_bin_to_netcdf('bedmap2.nc')
214+
215+
fcContour1500 = get_longest_contour(contourValue=-1500., author=author)
216+
217+
fc = FeatureCollection()
218+
219+
lons = [-65., -25., -25., -65.]
220+
lats = [-80., -80., -77., -71.]
221+
fc.merge(shelf_polygon(
222+
lons, lats, name='ISMIP6 Weddell Sea', author=author, tags=tags,
223+
fcContour=fcContour1500))
224+
225+
lons = [-128., -128., -90., -90.]
226+
lats = [-76., -69., -69., -76.]
227+
fc.merge(shelf_polygon(
228+
lons, lats, name='ISMIP6 Amundsen Sea', author=author, tags=tags,
229+
fcContour=fcContour1500))
230+
231+
lons = [45., 45., 90., 90.]
232+
lats = [-70., -60., -60., -70.]
233+
fc.merge(shelf_polygon(
234+
lons, lats, name='ISMIP6 Amery Sector', author=author, tags=tags,
235+
fcContour=fcContour1500))
236+
237+
lons = [-22.5, -22.5, 22.5, 22.5]
238+
lats = [-75., -65., -65., -75.]
239+
fc.merge(shelf_polygon(
240+
lons, lats, name='ISMIP6 Dronning Maud Land', author=author, tags=tags,
241+
fcContour=fcContour1500))
242+
243+
lons = [110., 110., 130., 130.]
244+
lats = [-70., -60., -60., -70.]
245+
fc.merge(shelf_polygon(
246+
lons, lats, name='ISMIP6 Totten Region', author=author, tags=tags,
247+
fcContour=fcContour1500))
248+
249+
lons = [165., 165., 180., 180.]
250+
lats = [-80., -71., -73., -80.]
251+
fc_ross = shelf_polygon(
252+
lons, lats, name='ISMIP6 Western Ross Sea', author=author, tags=tags,
253+
fcContour=fcContour1500)
254+
255+
lons = [-180., -180., -150., -150.]
256+
lats = [-80., -73., -77., -80.]
257+
fc_ross.merge(shelf_polygon(
258+
lons, lats, name='ISMIP6 Eastern Ross Sea', author=author, tags=tags,
259+
fcContour=fcContour1500))
260+
261+
old_props = fc_ross.features[0]['properties']
262+
fc_ross = fc_ross.combine('ISMIP6 Ross Sea')
263+
props = fc_ross.features[0]['properties']
264+
for prop in ['tags', 'zmin', 'zmax']:
265+
props[prop] = old_props[prop]
266+
267+
fc.merge(fc_ross)
268+
269+
fc.plot(projection='southpole')
270+
fc.to_geojson('ismip6_antarctic_ocean_regions.geojson')
271+
272+
# "split" these features into individual files in the geometric data cache
273+
gf.split(fc)
274+
275+
# update the database of feature names and tags
276+
write_feature_names_and_tags(gf.cacheLocation)
277+
# move the resulting file into place
278+
shutil.copyfile('features_and_tags.json',
279+
'../../geometric_features/features_and_tags.json')
280+
281+
plt.show()
282+
283+
284+
if __name__ == '__main__':
285+
main()

0 commit comments

Comments
 (0)