So I decided to run through the regridding script ancil_general_regrid.py for this particular case.
After the load_data function has completed we have
a) The target cube (which is the land-sea mask)
target_cube
<iris 'Cube' of land_binary_mask / (1) (latitude: 50; longitude: 50)>
b) The source cubes (which is the monthly chlorophyll in sea water climatology)
source_cubes
[<iris 'Cube' of mass_concentration_of_chlorophyll_a_in_sea_water / (kg m-3) (time: 12; latitude: 481; longitude: 640)>]
The target cube values are read with the correct precision, e.g.
print(target_cube.dim_coords[1][0:10])
DimCoord : longitude / (degrees)
points: [
151. , 151.1, 151.2, 151.3, 151.4, 151.5, 151.6, 151.7, 151.8,
151.9]
shape: (10,)
dtype: float32
standard_name: 'longitude'
coord_system: GeogCS(6371229.0)
print(target_cube.dim_coords[0][0:10])
DimCoord : latitude / (degrees)
points: [
-31. , -30.9, -30.8, -30.7, -30.6, -30.5, -30.4, -30.3, -30.2,
-30.1]
shape: (10,)
dtype: float32
standard_name: 'latitude'
coord_system: GeogCS(6371229.0)
The source cubes lat/lons are as follows:
print(source_cubes[0].dim_coords[1][:10])
DimCoord : latitude / (degrees)
points: [
-90. , -89.625, -89.25 , -88.875, -88.5 , -88.125, -87.75 ,
-87.375, -87. , -86.625]
shape: (10,)
dtype: float32
standard_name: 'latitude'
var_name: 'latitude'
coord_system: GeogCS(6371229.0)
print(source_cubes[0].dim_coords[2][:10])
DimCoord : longitude / (degrees)
points: [
0. , 0.5625, 1.125 , 1.6875, 2.25 , 2.8125, 3.375 , 3.9375,
4.5 , 5.0625]
shape: (10,)
dtype: float32
standard_name: 'longitude'
var_name: 'longitude'
coord_system: GeogCS(6371229.0)
Letās now step over the regrid step to see what the regridded_cubes dimensions are:
print(regridded_cubes[0])
mass_concentration_of_chlorophyll_a_in_sea_water / (kg m-3) (time: 12; latitude: 50; longitude: 50)
Dimension coordinates:
time x - -
latitude - x -
longitude - - x
Cell methods:
0 time: mean
Attributes:
Conventions 'CF-1.7'
STASH m01s00i096
grid_staggering 6
history '2019-02-08T12:33:57: chlorophyll.py\nhttps://code.metoffice.gov.uk/tra ...'
source 'GLOBCOLOR, http://www.globcolour.info/, see http://fcm1/projects/ANCIL ...'
regridded_cubes[0].dim_coords[1].points
array([-31. , -30.9, -30.8, -30.7, -30.6, -30.5, -30.4, -30.3, -30.2,
-30.1, -30. , -29.9, -29.8, -29.7, -29.6, -29.5, -29.4, -29.3,
-29.2, -29.1, -29. , -28.9, -28.8, -28.7, -28.6, -28.5, -28.4,
-28.3, -28.2, -28.1, -28. , -27.9, -27.8, -27.7, -27.6, -27.5,
-27.4, -27.3, -27.2, -27.1, -27. , -26.9, -26.8, -26.7, -26.6,
-26.5, -26.4, -26.3, -26.2, -26.1], dtype=float32)
regridded_cubes[0].dim_coords[2].points
array([151. , 151.1, 151.2, 151.3, 151.4, 151.5, 151.6, 151.7, 151.8,
151.9, 152. , 152.1, 152.2, 152.3, 152.4, 152.5, 152.6, 152.7,
152.8, 152.9, 153. , 153.1, 153.2, 153.3, 153.4, 153.5, 153.6,
153.7, 153.8, 153.9, 154. , 154.1, 154.2, 154.3, 154.4, 154.5,
154.6, 154.7, 154.8, 154.9, 155. , 155.1, 155.2, 155.3, 155.4,
155.5, 155.6, 155.7, 155.8, 155.9], dtype=float32)
So far so good - although we note that the bounds of latitude are showing some variation in precision. But not longitude
regridded_cubes[0].dim_coords[1].bounds
array([[-31.05 , -30.95 ],
[-30.95 , -30.849998],
[-30.849998, -30.75 ],
[-30.75 , -30.650002],
[-30.650002, -30.55 ],
[-30.55 , -30.45 ],
[-30.45 , -30.349998],
[-30.349998, -30.25 ],
[-30.25 , -30.150002],
[-30.150002, -30.05 ],
[-30.05 , -29.95 ],
[-29.95 , -29.849998],
...
regridded_cubes[0].dim_coords[2].bounds
array([[150.95 , 151.05 ],
[151.05 , 151.15 ],
[151.15 , 151.25 ],
[151.25 , 151.35 ],
[151.35 , 151.45 ],
[151.45 , 151.55 ],
[151.55 , 151.65 ],
[151.65 , 151.75 ],
[151.75 , 151.85 ],
[151.85 , 151.95 ],
[151.95 , 152.05 ],
[152.05 , 152.15 ],
[152.15 , 152.25 ],
[152.25 , 152.35 ],
[152.35 , 152.45 ],
[152.45 , 152.55 ],
[152.55 , 152.65 ],
[152.65 , 152.75 ],
[152.75 , 152.85 ],
[152.85 , 152.95 ],
....
Because target_lsm_path is defined, we now call ants.analysis.make_consistent_with_lsm.
What is the value of regridded_cubes dimension after this?
print(regridded_cubes[0].dim_coords[1][:10])
DimCoord : latitude / (degrees)
points: [
-31. , -30.9, -30.8, -30.7, -30.6, -30.5, -30.4, -30.3, -30.2,
-30.1]
bounds: [
[-31.05 , -30.95 ],
[-30.95 , -30.849998],
...,
[-30.25 , -30.150002],
[-30.150002, -30.05 ]]
shape: (10,) bounds(10, 2)
dtype: float32
standard_name: 'latitude'
var_name: 'latitude'
coord_system: GeogCS(6371229.0)
print(regridded_cubes[0].dim_coords[2][:10])
DimCoord : longitude / (degrees)
points: [
151. , 151.1, 151.2, 151.3, 151.4, 151.5, 151.6, 151.7, 151.8,
151.9]
bounds: [
[150.95, 151.05],
[151.05, 151.15],
...,
[151.75, 151.85],
[151.85, 151.95]]
shape: (10,) bounds(10, 2)
dtype: float32
standard_name: 'longitude'
var_name: 'longitude'
coord_system: GeogCS(6371229.0)
At this point the regridded cubes are then saved and the script exits.
Letās read in the saved data from disk to check it is consistent with what was computed.
a = ants.load(output_path)
print(a[0].dim_coords[1])
DimCoord : latitude / (degrees)
points: [-31. , -30.9, ..., -26.2, -26.1]
shape: (50,)
dtype: float32
standard_name: 'latitude'
coord_system: GeogCS(6371229.0)
print(a[0].dim_coords[2])
DimCoord : longitude / (degrees)
points: [151. , 151.1 , ..., 155.79999, 155.9 ]
shape: (50,)
dtype: float32
standard_name: 'longitude'
coord_system: GeogCS(6371229.0)
We can convert this to a data array.
da = xr.DataArray.from_iris(a[0])
In [12]: da.latitude
Out[12]:
<xarray.DataArray 'latitude' (latitude: 50)> Size: 200B
array([-31. , -30.9, -30.8, -30.7, -30.6, -30.5, -30.4, -30.3, -30.2, -30.1,
-30. , -29.9, -29.8, -29.7, -29.6, -29.5, -29.4, -29.3, -29.2, -29.1,
-29. , -28.9, -28.8, -28.7, -28.6, -28.5, -28.4, -28.3, -28.2, -28.1,
-28. , -27.9, -27.8, -27.7, -27.6, -27.5, -27.4, -27.3, -27.2, -27.1,
-27. , -26.9, -26.8, -26.7, -26.6, -26.5, -26.4, -26.3, -26.2, -26.1],
dtype=float32)
Coordinates:
* latitude (latitude) float32 200B -31.0 -30.9 -30.8 ... -26.3 -26.2 -26.1
Attributes:
standard_name: latitude
units: degrees
In [13]: da.longitude
Out[13]:
<xarray.DataArray 'longitude' (longitude: 50)> Size: 200B
array([151. , 151.1 , 151.2 , 151.3 , 151.4 , 151.5 ,
151.6 , 151.7 , 151.8 , 151.9 , 152. , 152.1 ,
152.2 , 152.3 , 152.4 , 152.5 , 152.59999, 152.7 ,
152.8 , 152.9 , 153. , 153.09999, 153.2 , 153.3 ,
153.4 , 153.5 , 153.59999, 153.7 , 153.8 , 153.9 ,
154. , 154.09999, 154.2 , 154.3 , 154.4 , 154.5 ,
154.59999, 154.7 , 154.79999, 154.9 , 155. , 155.09999,
155.2 , 155.29999, 155.4 , 155.5 , 155.59999, 155.7 ,
155.79999, 155.9 ], dtype=float32)
Coordinates:
* longitude (longitude) float32 200B 151.0 151.1 151.2 ... 155.7 155.8 155.9
Attributes:
standard_name: longitude
units: degrees
So it seems the regridded latitude values lose precision after being written to disk, or being read from disk.
But can we be sure about the internal representation? These are the full longitude values read from disk
In [16]: print(a[0].dim_coords[2].points)
[151. 151.1 151.2 151.3 151.4 151.5 151.6
151.7 151.8 151.9 152. 152.1 152.2 152.3
152.4 152.5 152.59999 152.7 152.8 152.9 153.
153.09999 153.2 153.3 153.4 153.5 153.59999 153.7
153.8 153.9 154. 154.09999 154.2 154.3 154.4
154.5 154.59999 154.7 154.79999 154.9 155. 155.09999
155.2 155.29999 155.4 155.5 155.59999 155.7 155.79999
155.9 ]
versus the regridded cube in memory
regridded_cubes[0].dim_coords[2].points
array([151. , 151.1, 151.2, 151.3, 151.4, 151.5, 151.6, 151.7, 151.8,
151.9, 152. , 152.1, 152.2, 152.3, 152.4, 152.5, 152.6, 152.7,
152.8, 152.9, 153. , 153.1, 153.2, 153.3, 153.4, 153.5, 153.6,
153.7, 153.8, 153.9, 154. , 154.1, 154.2, 154.3, 154.4, 154.5,
154.6, 154.7, 154.8, 154.9, 155. , 155.1, 155.2, 155.3, 155.4,
155.5, 155.6, 155.7, 155.8, 155.9], dtype=float32)
Iām pretty stumped.