Greenland surface runoff is repackaged from:
- Paper: Mankoff (2020) http://doi.org/10.5194/essd-12-2811-2020.
- Code (original): https://github.com/GEUS-Glaciology-and-Climate/freshwater
- Data: http://doi.org/10.22008/promice/freshwater
<xarray.Dataset> Size: 203kB Dimensions: (region: 7, time: 876) Coordinates: * region (region) int32 28B 1 2 3 4 5 6 7 * time (time) datetime64[ns] 7kB 1950-01-01 ... ... Data variables: subglacial_discharge_from_land (region, time) float64 49kB ... surface_runoff_from_land (region, time) float64 49kB ... subglacial_discharge_from_ice (region, time) float64 49kB ... surface_runoff_from_ice (region, time) float64 49kB ... min_discharge_depth (region) float32 28B ... region_name (region) <U2 56B ... Attributes: title: Ice sheet runoff by Mougniot region history: TBD Conventions: CF-1.8 DOI: https://doi.org/10.5281/zenodo.14020895
import xarray as xr
ds = xr.open_dataset('dat/GL_runoff.nc')
ds['min_discharge_depth'].to_dataframe()
region | min_discharge_depth |
---|---|
1 | -661 |
2 | -824 |
3 | -1341 |
4 | -1094 |
5 | -1158 |
6 | -643 |
7 | -243 |
Example showing annual data for
- Land runoff that enters the ocean subglacially (at depth)
- Land runoff that enters the ocean at the surface
- Ice runoff that enters the ocean subglacially
- Ice runoff that enters the ocean at the surface
import xarray as xr
ds = xr.open_dataset('dat/GL_runoff.nc').load()
df = ds.sum(dim='region')\
.drop_vars(['min_discharge_depth'])\
.sel({'time':slice('1950-01-01','2021-01-01')})\
.resample({'time':'YS'})\
.sum()\
.to_dataframe()
df = df * 86400 / 1E9 # convert from m^3/s -> ~ Gt/year
ax = df.plot(drawstyle='steps-post')
_ = ax.set_ylabel('Runoff [Gt$^{3}$ year^{-1}$]')
import xarray as xr
ds = xr.open_dataset('dat/GL_runoff.nc')
df = ds.drop_vars(['min_discharge_depth'])\
.sel({'time':slice('2017-01-01','2021-01-01')})\
['subglacial_discharge_from_ice']\
.to_dataframe()['subglacial_discharge_from_ice']
df = df.unstack().T
df.columns = ds['region_name'].values
ax = df.plot(drawstyle='steps-post')
_ = ax.set_ylabel('Runoff [m$^{3}$ s$^{-1}$]')
import xarray as xr
ds = xr.open_dataset('dat/GL_runoff.nc').load()
df = ds\
.drop_vars(['min_discharge_depth'])\
.sel({'time':slice('2000-01-01','2099-12-31')})\
.resample({'time':'YS'})\
.sum()\
.to_dataframe()
df = df[['subglacial_discharge_from_ice','surface_runoff_from_ice']].sum(axis='columns')
df = df * 86400 / 1E9 # convert from m^3/s -> ~ Gt/year
df = df.unstack()
df.columns = [str(_[0]) + ' ['+_[1]+']' for _ in zip(ds['region'].values, ds['region_name'].values)]
df['GL'] = df.sum(axis='columns')
df.loc['Mean'] = df.mean(axis='rows')
df.index = [str(_)[0:4] for _ in df.index]
df.round()
1 [CE] | 2 [CW] | 3 [NE] | 4 [NO] | 5 [NW] | 6 [SE] | 7 [SW] | GL | |
---|---|---|---|---|---|---|---|---|
2000 | 48 | 37 | 36 | 33 | 39 | 75 | 128 | 395 |
2001 | 37 | 36 | 41 | 40 | 49 | 72 | 103 | 377 |
2002 | 71 | 40 | 68 | 46 | 42 | 74 | 105 | 446 |
2003 | 58 | 54 | 75 | 60 | 66 | 83 | 168 | 565 |
2004 | 70 | 49 | 48 | 31 | 44 | 81 | 127 | 449 |
2005 | 61 | 51 | 65 | 57 | 59 | 96 | 123 | 511 |
2006 | 53 | 43 | 36 | 30 | 54 | 77 | 118 | 412 |
2007 | 65 | 58 | 49 | 34 | 58 | 85 | 162 | 511 |
2008 | 68 | 38 | 80 | 67 | 66 | 85 | 112 | 516 |
2009 | 54 | 38 | 56 | 49 | 55 | 63 | 84 | 398 |
2010 | 85 | 72 | 58 | 46 | 74 | 128 | 204 | 668 |
2011 | 51 | 56 | 58 | 65 | 76 | 70 | 139 | 514 |
2012 | 74 | 86 | 88 | 82 | 100 | 111 | 254 | 794 |
2013 | 54 | 38 | 52 | 28 | 39 | 58 | 94 | 364 |
2014 | 64 | 51 | 53 | 47 | 63 | 89 | 135 | 502 |
2015 | 55 | 42 | 68 | 72 | 68 | 61 | 95 | 460 |
2016 | 71 | 56 | 81 | 63 | 64 | 94 | 159 | 588 |
2017 | 58 | 36 | 68 | 41 | 45 | 80 | 117 | 446 |
2018 | 50 | 40 | 34 | 33 | 37 | 66 | 103 | 363 |
2019 | 84 | 80 | 104 | 90 | 90 | 89 | 170 | 707 |
2020 | 59 | 41 | 77 | 75 | 54 | 83 | 138 | 526 |
2021 | 82 | 54 | 72 | 52 | 66 | 106 | 158 | 590 |
2022 | 53 | 45 | 45 | 49 | 58 | 92 | 145 | 488 |
Mean | 62 | 50 | 61 | 52 | 59 | 83 | 137 | 504 |
df.describe().round()
1 [CE] | 2 [CW] | 3 [NE] | 4 [NO] | 5 [NW] | 6 [SE] | 7 [SW] | GL | |
---|---|---|---|---|---|---|---|---|
count | 23 | 23 | 23 | 23 | 23 | 23 | 23 | 23 |
mean | 62 | 50 | 61 | 52 | 59 | 83 | 137 | 504 |
std | 12 | 14 | 18 | 18 | 16 | 17 | 39 | 111 |
min | 37 | 36 | 34 | 28 | 37 | 58 | 84 | 363 |
25% | 53 | 39 | 49 | 37 | 47 | 73 | 109 | 429 |
50% | 59 | 45 | 58 | 49 | 58 | 83 | 128 | 502 |
75% | 70 | 55 | 74 | 64 | 66 | 91 | 158 | 546 |
max | 85 | 86 | 104 | 90 | 100 | 128 | 254 | 794 |
- Warning: ~20 GB
mkdir -p tmp/greenland_runoff
pushd tmp/greenland_runoff
wget -r -e robots=off -nH --cut-dirs=3 --content-disposition "https://dataverse.geus.dk/api/datasets/:persistentId/dirindex?persistentId=doi:10.22008/FK2/XKQVL7"
popd
Create one dataset that includes
- Land runoff (melted snow, and rain on land)
- Ice runoff (melted snow, melted ice, and rain on the ice sheet that does not refreeze)
Note that land runoff can enter fjords via streams at their surface, or route subglacially and then mix with subglacial discharge at depth in fjords at the grounding line of marine-terminating glaciers. Ice runoff can also enter fjords at depth at the grounding line of marine-terminating glaciers, or at the surface from sub-aerial streams from land terminating glaciers. Metadata will be used to track each of these sources and destinations.
Runoff will be binned by Mouginot regions in Greenland. See Mouginot (2019) https://doi.org/10.7280/d1wt11. This metadata is already include in the product downloaded above.
import xarray as xr
import numpy as np
ds_land = xr.open_mfdataset('tmp/greenland_runoff/freshwater/land/MAR.nc', chunks='auto')
ds_ice = xr.open_mfdataset('tmp/greenland_runoff/freshwater/ice/MAR.nc', chunks='auto')
ds_land = ds_land.reset_coords('alt')
ds_ice = ds_ice.reset_coords('alt')
# Land runoff by destination (use alt metadata = BedMachine depth at outlet location)
land_sub = ds_land.where(ds_land['alt'] < 0).groupby('M2019_region').sum()['discharge'].resample({'time':'MS'}).sum()
land_surf = ds_land.where(ds_land['alt'] >= 0).groupby('M2019_region').sum()['discharge'].resample({'time':'MS'}).sum()
# Max depth of discharge within each region
sub_depth = ds_land.where(ds_land['alt'] < 0).groupby('M2019_region').min()['alt']
# Ice runoff by destination
ice_sub = ds_ice.where(ds_ice['coast_alt'] < 0).groupby('M2019_region').sum()['discharge'].resample({'time':'MS'}).sum()
ice_surf = ds_ice.where(ds_ice['coast_alt'] >= 0).groupby('M2019_region').sum()['discharge'].resample({'time':'MS'}).sum()
ds = xr.Dataset({'subglacial_discharge_from_land':land_sub,
'surface_runoff_from_land':land_surf,
'subglacial_discharge_from_ice':ice_sub,
'surface_runoff_from_ice':ice_surf,
'min_discharge_depth':sub_depth})
# # scale from m^3/s -> km^3/sample_period
# scale = 86400 / 1E9
# # /1E9: m^3 -> km^3
# # 86400: nuber of seconds in a day. Because sum() used above, works for month or year or any resample period
# scale_items = ['subglacial_discharge_from_land','surface_runoff_from_land',
# 'subglacial_discharge_from_ice','surface_runoff_from_ice']
# ds[scale_items] = ds[scale_items] * scale
print(ds)
<xarray.Dataset> Size: 203kB Dimensions: (M2019_region: 7, time: 876) Coordinates: * M2019_region (M2019_region) object 56B 'CE' 'CW' ... 'SW' * time (time) datetime64[ns] 7kB 1950-01-01 ... ... Data variables: subglacial_discharge_from_land (M2019_region, time) float64 49kB dask.array<chunksize=(7, 19), meta=np.ndarray> surface_runoff_from_land (M2019_region, time) float64 49kB dask.array<chunksize=(7, 19), meta=np.ndarray> subglacial_discharge_from_ice (M2019_region, time) float64 49kB dask.array<chunksize=(7, 46), meta=np.ndarray> surface_runoff_from_ice (M2019_region, time) float64 49kB dask.array<chunksize=(7, 46), meta=np.ndarray> min_discharge_depth (M2019_region) float32 28B dask.array<chunksize=(7,), meta=np.ndarray>
Write it out using Dask so it works on lightweight machines. This takes a few hours.
delayed_obj = ds.to_netcdf('tmp/GL_runoff.nc', compute=False)
from dask.diagnostics import ProgressBar
with ProgressBar():
results = delayed_obj.compute()
[########################################] | 100% Completed | 110.26 s
Add metadata, extend back to 1840, etc.
ds = xr.open_dataset('tmp/GL_runoff.nc')
ds = ds.rename({'M2019_region':'region'})
ds['region_name'] = ds['region']
ds['region'] = np.arange(7).astype(np.int32) + 1
items = ['subglacial_discharge_from_land','surface_runoff_from_land',
'subglacial_discharge_from_ice','surface_runoff_from_ice']
for i in items:
ds[i].attrs['standard_name'] = 'water_volume_transport_into_sea_water_from_rivers'
ds[i].attrs['units'] = 'm3 s-1'
ds['time'].attrs['long_name'] = 'time'
ds['region'].attrs['long_name'] = 'Mougniot (2019) region'
ds.attrs['title'] = 'Ice sheet runoff by Mougniot region'
ds.attrs['history'] = 'TBD'
ds.attrs['Conventions'] = 'CF-1.8'
ds.attrs['DOI'] = 'https://doi.org/10.5281/zenodo.14020895'
comp = dict(zlib=True, complevel=5)
encoding = {var: comp for var in items}
encoding['time'] = {'dtype': 'i4'}
!rm dat/GL_runoff.nc
ds.to_netcdf('dat/GL_runoff.nc', encoding=encoding)
!ncdump -h dat/GL_runoff.nc
netcdf GL_runoff { dimensions: region = 7 ; time = 876 ; variables: int region(region) ; region:long_name = "Mougniot (2019) region" ; int time(time) ; time:long_name = "time" ; time:units = "days since 1950-01-01 00:00:00" ; time:calendar = "proleptic_gregorian" ; double subglacial_discharge_from_land(region, time) ; subglacial_discharge_from_land:_FillValue = NaN ; subglacial_discharge_from_land:long_name = "MAR discharge" ; subglacial_discharge_from_land:standard_name = "water_volume_transport_into_sea_water_from_rivers" ; subglacial_discharge_from_land:units = "m3 s-1" ; double surface_runoff_from_land(region, time) ; surface_runoff_from_land:_FillValue = NaN ; surface_runoff_from_land:long_name = "MAR discharge" ; surface_runoff_from_land:standard_name = "water_volume_transport_into_sea_water_from_rivers" ; surface_runoff_from_land:units = "m3 s-1" ; double subglacial_discharge_from_ice(region, time) ; subglacial_discharge_from_ice:_FillValue = NaN ; subglacial_discharge_from_ice:long_name = "MAR discharge" ; subglacial_discharge_from_ice:standard_name = "water_volume_transport_into_sea_water_from_rivers" ; subglacial_discharge_from_ice:units = "m3 s-1" ; double surface_runoff_from_ice(region, time) ; surface_runoff_from_ice:_FillValue = NaN ; surface_runoff_from_ice:long_name = "MAR discharge" ; surface_runoff_from_ice:standard_name = "water_volume_transport_into_sea_water_from_rivers" ; surface_runoff_from_ice:units = "m3 s-1" ; float min_discharge_depth(region) ; min_discharge_depth:_FillValue = NaNf ; min_discharge_depth:long_name = "height_above_mean_sea_level" ; min_discharge_depth:standard_name = "altitude" ; min_discharge_depth:units = "m" ; min_discharge_depth:positive = "up" ; min_discharge_depth:axis = "Z" ; string region_name(region) ; // global attributes: :title = "Ice sheet runoff by Mougniot region" ; :history = "TBD" ; :Conventions = "CF-1.8" ; :DOI = "https://doi.org/10.5281/zenodo.14020895" ; }