Default land/ocean mask¶
When crunching data with netCDF-SCM, we want to cut files into (at least) Northern/Southern Hemisphere, land/ocean boxes. However, we don’t always have access to land-surface fraction information from the raw model output. In these cases, we simply apply a default land/ocean mask instead. In this notebook, we show how this mask looks and how it was derived.
Imports¶
[1]:
import iris
import numpy as np
[2]:
from matplotlib import pyplot as plt
import iris.plot as iplt
import iris.quickplot as qplt
Default mask¶
Our default mask lives in netcdf_scm.masks
. We can access it using netcdf_scm.masks.get_default_sftlf_cube
.
[3]:
from netcdf_scm.weights import get_default_sftlf_cube
[4]:
default_sftlf = get_default_sftlf_cube()
[5]:
# NBVAL_IGNORE_OUTPUT
fig = plt.figure(figsize=(16, 9))
qplt.pcolormesh(default_sftlf,);
/data/ubuntu-znicholls/miniconda3/envs/netcdf-scm/lib/python3.9/site-packages/iris/coords.py:1192: UserWarning: Coordinate 'longitude' is not bounded, guessing contiguous bounds.
warnings.warn('Coordinate {!r} is not bounded, guessing '
/data/ubuntu-znicholls/miniconda3/envs/netcdf-scm/lib/python3.9/site-packages/iris/coords.py:1192: UserWarning: Coordinate 'latitude' is not bounded, guessing contiguous bounds.
warnings.warn('Coordinate {!r} is not bounded, guessing '

[6]:
zoomed = default_sftlf.extract(
iris.Constraint(latitude=lambda cell: -45 < cell < -25)
& iris.Constraint(longitude=lambda cell: 120 < cell < 160)
)
[7]:
# NBVAL_IGNORE_OUTPUT
fig = plt.figure(figsize=(16, 9))
qplt.pcolormesh(zoomed,);
/data/ubuntu-znicholls/miniconda3/envs/netcdf-scm/lib/python3.9/site-packages/iris/coords.py:1192: UserWarning: Coordinate 'longitude' is not bounded, guessing contiguous bounds.
warnings.warn('Coordinate {!r} is not bounded, guessing '
/data/ubuntu-znicholls/miniconda3/envs/netcdf-scm/lib/python3.9/site-packages/iris/coords.py:1192: UserWarning: Coordinate 'latitude' is not bounded, guessing contiguous bounds.
warnings.warn('Coordinate {!r} is not bounded, guessing '

Deriving the mask¶
To derive the mask, we simply use the mask from the IPSL-CM6A-LR model in CMIP6.
[8]:
source_file = "../../../tests/test-data/cmip6output/CMIP6/CMIP/IPSL/IPSL-CM6A-LR/historical/r1i1p1f1/fx/sftlf/gr/v20180803/sftlf_fx_IPSL-CM6A-LR_historical_r1i1p1f1_gr.nc"
[9]:
comp_cube = iris.load_cube(source_file)
/data/ubuntu-znicholls/miniconda3/envs/netcdf-scm/lib/python3.9/site-packages/iris/fileformats/cf.py:803: UserWarning: Missing CF-netCDF measure variable 'areacella', referenced by netCDF variable 'sftlf'
warnings.warn(message % (variable_name, nc_var_name))
[10]:
# NBVAL_IGNORE_OUTPUT
fig = plt.figure(figsize=(16, 9))
qplt.pcolormesh(comp_cube);
/data/ubuntu-znicholls/miniconda3/envs/netcdf-scm/lib/python3.9/site-packages/iris/coords.py:1192: UserWarning: Coordinate 'longitude' is not bounded, guessing contiguous bounds.
warnings.warn('Coordinate {!r} is not bounded, guessing '
/data/ubuntu-znicholls/miniconda3/envs/netcdf-scm/lib/python3.9/site-packages/iris/coords.py:1192: UserWarning: Coordinate 'latitude' is not bounded, guessing contiguous bounds.
warnings.warn('Coordinate {!r} is not bounded, guessing '

[11]:
sample_points = [
("longitude", np.arange(0.5, 360, 1)),
("latitude", np.arange(-89.5, 90, 1)),
]
[12]:
comp_cube_interp = comp_cube.interpolate(sample_points, iris.analysis.Linear())
comp_cube_interp.attributes[
"history"
] = "Interpolated to a 1deg x 1deg grid using iris.interpolate with linear interpolation"
comp_cube_interp.attributes[
"title"
] = "Default land area fraction assumption in netcdf-scm. Base on {}".format(
comp_cube_interp.attributes["title"]
)
[13]:
iris.save(comp_cube_interp, "default_weights.nc")
!ncdump -h default_weights.nc
netcdf default_weights {
dimensions:
lat = 180 ;
lon = 360 ;
string8 = 8 ;
variables:
float sftlf(lat, lon) ;
sftlf:standard_name = "land_area_fraction" ;
sftlf:long_name = "Land Area Fraction" ;
sftlf:units = "%" ;
sftlf:cell_methods = "area: mean" ;
sftlf:coordinates = "type" ;
double lat(lat) ;
lat:axis = "Y" ;
lat:units = "degrees_north" ;
lat:standard_name = "latitude" ;
lat:long_name = "Latitude" ;
double lon(lon) ;
lon:axis = "X" ;
lon:units = "degrees_east" ;
lon:standard_name = "longitude" ;
lon:long_name = "Longitude" ;
char type(string8) ;
type:units = "1" ;
type:standard_name = "area_type" ;
type:long_name = "Land area type" ;
// global attributes:
:CMIP6_CV_version = "cv=6.2.3.5-2-g63b123e" ;
:EXPID = "historical" ;
:NCO = "\"4.6.0\"" ;
:activity_id = "CMIP" ;
:branch_method = "standard" ;
:branch_time_in_child = 0. ;
:branch_time_in_parent = 21914. ;
:contact = "ipsl-cmip6@listes.ipsl.fr" ;
:creation_date = "2018-07-11T07:27:04Z" ;
:data_specs_version = "01.00.21" ;
:description = "Land Area Fraction" ;
:dr2xml_md5sum = "f1e40c1fc5d8281f865f72fbf4e38f9d" ;
:dr2xml_version = "1.11" ;
:experiment = "all-forcing simulation of the recent past" ;
:experiment_id = "historical" ;
:forcing_index = 1 ;
:frequency = "fx" ;
:further_info_url = "https://furtherinfo.es-doc.org/CMIP6.IPSL.IPSL-CM6A-LR.historical.none.r1i1p1f1" ;
:grid = "LMDZ grid" ;
:grid_label = "gr" ;
:history = "Interpolated to a 1deg x 1deg grid using iris.interpolate with linear interpolation" ;
:initialization_index = 1 ;
:institution = "Institut Pierre Simon Laplace, Paris 75252, France" ;
:institution_id = "IPSL" ;
:license = "CMIP6 model data produced by IPSL is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License (https://creativecommons.org/licenses). Consult https://pcmdi.llnl.gov/CMIP6/TermsOfUse for terms of use governing CMIP6 output, including citation requirements and proper acknowledgment. Further information about this data, including some limitations, can be found via the further_info_url (recorded as a global attribute in this file) and at https://cmc.ipsl.fr/. The data producers and data providers make no warranty, either express or implied, including, but not limited to, warranties of merchantability and fitness for a particular purpose. All liabilities arising from the supply of the information (including any liability arising in negligence) are excluded to the fullest extent permitted by law." ;
:mip_era = "CMIP6" ;
:model_version = "6.1.5" ;
:name = "/ccc/work/cont003/gencmip6/p86caub/IGCM_OUT/IPSLCM6/PROD/historical/CM61-LR-hist-03.1910/CMIP6/ATM/sftlf_fx_IPSL-CM6A-LR_historical_r1i1p1f1_gr" ;
:nominal_resolution = "250 km" ;
:online_operation = "once" ;
:parent_activity_id = "CMIP" ;
:parent_experiment_id = "piControl" ;
:parent_mip_era = "CMIP6" ;
:parent_source_id = "IPSL-CM6A-LR" ;
:parent_time_units = "days since 1850-01-01 00:00:00" ;
:parent_variant_label = "r1i1p1f1" ;
:physics_index = 1 ;
:product = "model-output" ;
:realization_index = 1 ;
:realm = "atmos" ;
:source = "IPSL-CM6A-LR (2017): atmos: LMDZ (NPv6, N96; 144 x 143 longitude/latitude; 79 levels; top level 40000 m) land: ORCHIDEE (v2.0, Water/Carbon/Energy mode) ocean: NEMO-OPA (eORCA1.3, tripolar primarily 1deg; 362 x 332 longitude/latitude; 75 levels; top grid cell 0-2 m) ocnBgchem: NEMO-PISCES seaIce: NEMO-LIM3" ;
:source_id = "IPSL-CM6A-LR" ;
:source_type = "AOGCM BGC" ;
:sub_experiment = "none" ;
:sub_experiment_id = "none" ;
:table_id = "fx" ;
:title = "Default land area fraction assumption in netcdf-scm. Base on IPSL-CM6A-LR model output prepared for CMIP6 / CMIP historical" ;
:tracking_id = "hdl:21.14100/cc6c4852-271d-4c5a-adc3-42530ef19550" ;
:variable_id = "sftlf" ;
:variant_label = "r1i1p1f1" ;
:Conventions = "CF-1.7" ;
}
[14]:
# NBVAL_IGNORE_OUTPUT
fig = plt.figure(figsize=(16, 9))
qplt.pcolormesh(comp_cube_interp);
/data/ubuntu-znicholls/miniconda3/envs/netcdf-scm/lib/python3.9/site-packages/iris/coords.py:1192: UserWarning: Coordinate 'longitude' is not bounded, guessing contiguous bounds.
warnings.warn('Coordinate {!r} is not bounded, guessing '
/data/ubuntu-znicholls/miniconda3/envs/netcdf-scm/lib/python3.9/site-packages/iris/coords.py:1192: UserWarning: Coordinate 'latitude' is not bounded, guessing contiguous bounds.
warnings.warn('Coordinate {!r} is not bounded, guessing '

[15]:
comp_cube_regrid = comp_cube.regrid(default_sftlf, iris.analysis.Linear())
As expected, the default mask is more or less identical to the IPSL mask, even with regridding.
[16]:
# NBVAL_IGNORE_OUTPUT
fig = plt.figure(figsize=(16, 9))
qplt.pcolormesh((default_sftlf - comp_cube_regrid));
