blob: de01d79ad8eef616a11f5eec401cca82d10b8849 [file] [log] [blame]
"""
An experiment to try and break the coordinate system functionality out of the Field class
"""
from variable import Variable
cf_dimensions = {'degree_east': 'longitude',
'degree east': 'longitude',
'degrees_east': 'longitude',
'degree_north': 'latitude',
'degrees_north': 'latitude',
'degree north': 'latitude'}
def cf_units2coordinates(units):
# For spatial coordinates
if units in cf_dimensions:
return cf_dimensions[units]
# Time coordinates
try:
netCDF4.num2date(0,units)
except:
return None
return 'time'
class CoordSystem(object):
"""
Encapsulates a coordinate system. Constructor can take a Variable instance and attempt to
auto construct the coordinate system parameters.
"""
def __init__(self, variable=None, coordsystem=None):
"""
Takes either a Variable instance or a coordsystem dict (produced by another CoordSystem instance)
In the case of a variable instance, interogate the variable and auxilary variables in the parent
group in order to construct the coordsystem parameters
Coordinate systems can be of types: ['cartesian', 'discrete']
Cartesian coordinate systems have an x-dimension and a y-dimension whereas discrete systems only
have an id-dimension as an index into the grid positions.
"""
# If we have a variable instance
if variable and type(variable) == Variable:
# Keep a handle on the associated variable
self.variable = variable
# Initialise dimensions
x_dimension = None
y_dimension = None
z_dimension = None
t_dimension = None
id_dimension = None
# Keep track of variable dimensions we have mapped
mapped = []
# First just step through the variables dimensions
for dimension in self.variable.dimensions:
# See if the dimension name is also a variable name
if dimension.name in self.variable.group.variables:
# Grab the coordinate variable
coordinate_variable = self.variable.group.variables[dimension.name]
# Try and convert the variable into a CF coordinate
cf_coordinate = cf_units2coordinates(coordinate_variable.get_attribute('units'))
# Get the axis attribute
axis = coordinate_variable.get_attribute('axis')
# Now, if we have a cf_coordinate we can add this variable to the coordinate system
# and mark it as mapped
if cf_coordinate:
self.coordsystem[cf_coordinate] = {'variable':coordinate_variable.name, 'map':[self.variable.dimensions.index(dimension)]}
mapped.append(self.variable.dimensions.index(dimension))
# We can also use cf_coordinates or axis attributes to figure out cartesian axis
if cf_coordinate == 'latitude' or axis == 'Y':
y_dimension = self.variable.dimensions.index(dimension)
if cf_coordinate == 'longitude' or axis == 'X':
x_dimension = self.variable.dimensions.index(dimension)
if cf_coordinate == 'vertical' or axis == 'Z':
z_dimension = self.variable.dimensions.index(dimension)
if cf_coordinate == 'time' or axis == 'T':
t_dimension = self.variable.dimensions.index(dimension)
# Check how we are doing, have we mapped all dimensions?
if len(mapped) < len(self.variable.dimensions):
# Check for a coordinates attribute
if self.variable.get_attribute('coordinates'):
self.coordinates_names = self.variable.get_attribute('coordinates').split()
# Find each associated variable
for varname in self.coordinates_names:
# See if we can find the corresponding variable
if varname in self.variable.group.variables.keys():
# Grab the coordinate variable
coordinate_variable = self.variable.group.variables[varname]
# Try and convert the variable into a CF coordinate
cf_coordinate = cf_units2coordinates(coordinate_variable.get_attribute('units'))
# Get the axis attribute
axis = coordinate_variable.get_attribute('axis')
# If we have a cf_coordinate we can create the mapping
if cf_coordinate:
# Create the coordinates_mapping entry but with an empty map for now
self.coordinates_mapping[cf_coordinate] = {'variable':name, 'map':[], 'coordinates': self.coordinates_names}
# Add each coordinates variable dimension to the mappable list and generate the map
for dimension in self.variable.group.variables[varname].dimensions:
self.coordinates_mapping[coordinate_name]['map'].append(self.variable.dimensions.index(dimension))
if not dimension in mapped:
mapped.append(dimension)
# By now we should have mapped all the dimensions, we can now figure out what time of coordinate system we have
# If we have x_dimension and y_dimension then we have a cartesian system
if x_dimension and y_dimension:
self.type = 'cartesian'
# If the map for latitude and longitude is of length one and the same value then we can mark this as the id_dimension
if self.coordinates_mapping['latitude']['map'] == self.coordinates_mapping['longitude']['map']:
if len(self.coordinates_mapping['latitude']['map']) == 1:
self.id_dimension = self.coordinates_mapping['latitude']['map'][0]