Source code for nes.nc_projections.points_nes_ghost
#!/usr/bin/env python
import sys
import warnings
import numpy as np
from netCDF4 import stringtochar, date2num
from copy import deepcopy
from .points_nes import PointsNes
[docs]
class PointsNesGHOST(PointsNes):
"""
Attributes
----------
_qa : dict
Quality flags (GHOST checks) dictionary with the complete 'data' key for all the values and the rest of the
attributes.
_flag : dict
Data flags (given by data provider) dictionary with the complete 'data' key for all the values and the rest of
the attributes.
_qa : dict
Quality flags (GHOST checks) dictionary with the portion of 'data' corresponding to the rank values.
_flag : dict
Data flags (given by data provider) dictionary with the portion of 'data' corresponding to the rank values.
"""
def __init__(self, comm=None, path=None, info=False, dataset=None, xarray=False, parallel_method='X',
avoid_first_hours=0, avoid_last_hours=0, first_level=0, last_level=None, create_nes=False,
balanced=False, times=None, **kwargs):
"""
Initialize the PointsNesGHOST class.
Parameters
----------
comm: MPI.COMM
MPI Communicator.
path: str
Path to the NetCDF to initialize the object.
info: bool
Indicates if you want to get reading/writing info.
dataset: Dataset
NetCDF4-python Dataset to initialize the class.
xarray: bool:
(Not working) Indicates if you want to use xarray as default.
parallel_method : str
Indicates the parallelization method that you want. Default: 'X'.
Accepted values: ['X'].
avoid_first_hours : int
Number of hours to remove from first time steps.
avoid_last_hours : int
Number of hours to remove from last time steps.
first_level : int
Index of the first level to use.
last_level : int, None
Index of the last level to use. None if it is the last.
create_nes : bool
Indicates if you want to create the object from scratch (True) or through an existing file.
balanced : bool
Indicates if you want a balanced parallelization or not.
Balanced dataset cannot be written in chunking mode.
times : list, None
List of times to substitute the current ones while creation.
"""
super(PointsNesGHOST, self).__init__(comm=comm, path=path, info=info, dataset=dataset,
xarray=xarray, parallel_method=parallel_method,
avoid_first_hours=avoid_first_hours, avoid_last_hours=avoid_last_hours,
first_level=first_level, last_level=last_level, create_nes=create_nes,
times=times, **kwargs)
# Complete dimensions
self._flag = self._get_coordinate_dimension(['flag'])
self._qa = self._get_coordinate_dimension(['qa'])
# Dimensions screening
self.flag = self._get_coordinate_values(self._flag, 'X')
self.qa = self._get_coordinate_values(self._qa, 'X')
[docs]
@staticmethod
def new(comm=None, path=None, info=False, dataset=None, xarray=False, parallel_method='X',
avoid_first_hours=0, avoid_last_hours=0, first_level=0, last_level=None, create_nes=False,
balanced=False, times=None, **kwargs):
"""
Initialize the PointsNesGHOST class.
Parameters
----------
comm: MPI.COMM
MPI Communicator.
path: str
Path to the NetCDF to initialize the object.
info: bool
Indicates if you want to get reading/writing info.
dataset: Dataset
NetCDF4-python Dataset to initialize the class.
xarray: bool:
(Not working) Indicates if you want to use xarray as default.
parallel_method : str
Indicates the parallelization method that you want. Default: 'X'.
Accepted values: ['X'].
avoid_first_hours : int
Number of hours to remove from first time steps.
avoid_last_hours : int
Number of hours to remove from last time steps.
first_level : int
Index of the first level to use.
last_level : int, None
Index of the last level to use. None if it is the last.
create_nes : bool
Indicates if you want to create the object from scratch (True) or through an existing file.
balanced : bool
Indicates if you want a balanced parallelization or not.
Balanced dataset cannot be written in chunking mode.
times : list, None
List of times to substitute the current ones while creation.
"""
new = PointsNesGHOST(comm=comm, path=path, info=info, dataset=dataset, xarray=xarray,
parallel_method=parallel_method, avoid_first_hours=avoid_first_hours,
avoid_last_hours=avoid_last_hours, first_level=first_level, last_level=last_level,
create_nes=create_nes, balanced=balanced, times=times, **kwargs)
return new
def _create_dimensions(self, netcdf):
"""
Create 'N_flag_codes' and 'N_qa_codes' dimensions and the super dimensions
'time', 'time_nv', 'station', and 'strlen'.
Parameters
----------
netcdf : Dataset
NetCDF object.
"""
super(PointsNesGHOST, self)._create_dimensions(netcdf)
# Create N_flag_codes and N_qa_codes dimensions
netcdf.createDimension('N_flag_codes', self._flag['data'].shape[2])
netcdf.createDimension('N_qa_codes', self._qa['data'].shape[2])
return None
def _create_dimension_variables(self, netcdf):
"""
Create the 'time', 'time_bnds', 'station', 'lat', 'lat_bnds', 'lon' and 'lon_bnds' variables.
Parameters
----------
netcdf : Dataset
NetCDF object.
"""
# TIMES
time_var = netcdf.createVariable('time', np.float64, ('time',), zlib=self.zip_lvl > 0, complevel=self.zip_lvl)
time_var.units = 'hours since {0}'.format(
self._time[self.get_time_id(self.hours_start, first=True)].strftime('%Y-%m-%d %H:%M:%S'))
time_var.standard_name = 'time'
time_var.calendar = 'standard'
time_var.long_name = 'time'
if self._time_bnds is not None:
time_var.bounds = 'time_bnds'
if self.size > 1:
time_var.set_collective(True)
time_var[:] = date2num(self._time[self.get_time_id(self.hours_start, first=True):
self.get_time_id(self.hours_end, first=False)],
time_var.units, time_var.calendar)
# TIME BOUNDS
if self._time_bnds is not None:
time_bnds_var = netcdf.createVariable('time_bnds', np.float64, ('time', 'time_nv',), zlib=self.zip_lvl,
complevel=self.zip_lvl)
if self.size > 1:
time_bnds_var.set_collective(True)
time_bnds_var[:] = date2num(self._time_bnds, time_var.units, calendar='standard')
# STATIONS
stations = netcdf.createVariable('station', np.float64, ('station',), zlib=self.zip_lvl > 0,
complevel=self.zip_lvl)
stations.units = ''
stations.axis = 'X'
stations.long_name = ''
stations.standard_name = 'station'
if self.size > 1:
stations.set_collective(True)
stations[:] = self._station['data']
# LATITUDES
lat = netcdf.createVariable('latitude', np.float64, self._lat_dim,
zlib=self.zip_lvl > 0, complevel=self.zip_lvl)
lat.units = 'degrees_north'
lat.axis = 'Y'
lat.long_name = 'latitude coordinate'
lat.standard_name = 'latitude'
if self._lat_bnds is not None:
lat.bounds = 'lat_bnds'
if self.size > 1:
lat.set_collective(True)
lat[:] = self._lat['data']
# LONGITUDES
lon = netcdf.createVariable('longitude', np.float64, self._lon_dim,
zlib=self.zip_lvl > 0, complevel=self.zip_lvl)
lon.units = 'degrees_east'
lon.axis = 'X'
lon.long_name = 'longitude coordinate'
lon.standard_name = 'longitude'
if self._lon_bnds is not None:
lon.bounds = 'lon_bnds'
if self.size > 1:
lon.set_collective(True)
lon[:] = self._lon['data']
[docs]
def erase_flags(self):
first_time_idx = self.get_time_id(self.hours_start, first=True)
last_time_idx = self.get_time_id(self.hours_end, first=False)
t_len = last_time_idx - first_time_idx
self._qa['data'] = np.empty((len(self._lon['data']), t_len, 0))
self._flag['data'] = np.empty((len(self._lon['data']), t_len, 0))
return None
def _get_coordinate_values(self, coordinate_info, coordinate_axis, bounds=False):
"""
Get the coordinate data of the current portion.
Parameters
----------
coordinate_info : dict, list
Dictionary with the 'data' key with the coordinate variable values. and the attributes as other keys.
coordinate_axis : str
Name of the coordinate to extract. Accepted values: ['X'].
bounds : bool
Boolean variable to know if there are coordinate bounds.
Returns
-------
values : dict
Dictionary with the portion of data corresponding to the rank.
"""
if coordinate_info is None:
return None
if not isinstance(coordinate_info, dict):
values = {'data': deepcopy(coordinate_info)}
else:
values = deepcopy(coordinate_info)
coordinate_len = len(values['data'].shape)
if bounds:
coordinate_len -= 1
if coordinate_axis == 'X':
if coordinate_len == 1:
values['data'] = values['data'][self.read_axis_limits['x_min']:self.read_axis_limits['x_max']]
elif coordinate_len == 2:
values['data'] = values['data'][self.read_axis_limits['x_min']:self.read_axis_limits['x_max'],
self.read_axis_limits['t_min']:self.read_axis_limits['t_max']]
elif coordinate_len == 3:
values['data'] = values['data'][self.read_axis_limits['x_min']:self.read_axis_limits['x_max'],
self.read_axis_limits['t_min']:self.read_axis_limits['t_max'], :]
else:
raise NotImplementedError("The coordinate has wrong dimensions: {dim}".format(
dim=values['data'].shape))
return values
def _read_variable(self, var_name):
"""
Read the corresponding variable data according to the current rank.
Parameters
----------
var_name : str
Name of the variable to read.
Returns
-------
data: np.array
Portion of the variable data corresponding to the rank.
"""
nc_var = self.netcdf.variables[var_name]
var_dims = nc_var.dimensions
# Read data in 1 or 2 dimensions
if len(var_dims) < 2:
data = nc_var[self.read_axis_limits['x_min']:self.read_axis_limits['x_max']]
elif len(var_dims) == 2:
data = nc_var[self.read_axis_limits['x_min']:self.read_axis_limits['x_max'],
self.read_axis_limits['t_min']:self.read_axis_limits['t_max']]
elif len(var_dims) == 3:
data = nc_var[self.read_axis_limits['x_min']:self.read_axis_limits['x_max'],
self.read_axis_limits['t_min']:self.read_axis_limits['t_max'],
:]
else:
raise NotImplementedError('Error with {0}. Only can be read netCDF with 3 dimensions or less'.format(
var_name))
# Unmask array
data = self._unmask_array(data)
return data
def _create_variables(self, netcdf, chunking=False):
"""
Create the netCDF file variables.
Parameters
----------
netcdf : Dataset
netcdf4-python open Dataset.
chunking : bool
Indicates if you want to chunk the output netCDF.
"""
if self.variables is not None:
for i, (var_name, var_dict) in enumerate(self.variables.items()):
# Get data type
if 'dtype' in var_dict.keys():
var_dtype = var_dict['dtype']
if (var_dict['data'] is not None) and (var_dtype != var_dict['data'].dtype):
msg = "WARNING!!! "
msg += "Different data types for variable {0}. ".format(var_name)
msg += "Input dtype={0}. Data dtype={1}.".format(var_dtype, var_dict['data'].dtype)
warnings.warn(msg)
sys.stderr.flush()
try:
var_dict['data'] = var_dict['data'].astype(var_dtype)
except Exception as e: # TODO: Detect exception
raise e("It was not possible to cast the data to the input dtype.")
else:
var_dtype = var_dict['data'].dtype
if var_dtype is np.object:
raise TypeError("Data dtype is np.object. Define dtype explicitly as dictionary key 'dtype'")
# Get dimensions when reading datasets
if 'dimensions' in var_dict.keys():
var_dims = var_dict['dimensions']
# Get dimensions when creating new datasets
else:
if len(var_dict['data'].shape) == 1:
# For data that depends only on station (e.g. station_code)
var_dims = self._var_dim
else:
# For data that is dependent on time and station (e.g. PM10)
var_dims = self._var_dim + ('time',)
if var_dict['data'] is not None:
# Ensure data is of type numpy array (to create NES)
if not isinstance(var_dict['data'], (np.ndarray, np.generic)):
try:
var_dict['data'] = np.array(var_dict['data'])
except AttributeError:
raise AttributeError("Data for variable {0} must be a numpy array.".format(var_name))
# Convert list of strings to chars for parallelization
if np.issubdtype(var_dtype, np.character):
var_dict['data_aux'] = self.str2char(var_dict['data'])
var_dims += ('strlen',)
var_dtype = 'S1'
if self.info:
print("Rank {0:03d}: Writing {1} var ({2}/{3})".format(self.rank, var_name, i + 1,
len(self.variables)))
if not chunking:
var = netcdf.createVariable(var_name, var_dtype, var_dims,
zlib=self.zip_lvl > 0, complevel=self.zip_lvl)
else:
if self.master:
chunk_size = var_dict['data'].shape
else:
chunk_size = None
chunk_size = self.comm.bcast(chunk_size, root=0)
var = netcdf.createVariable(var_name, var_dtype, var_dims, zlib=self.zip_lvl > 0,
complevel=self.zip_lvl, chunksizes=chunk_size)
if self.info:
print("Rank {0:03d}: Var {1} created ({2}/{3})".format(
self.rank, var_name, i + 1, len(self.variables)))
if self.size > 1:
var.set_collective(True)
if self.info:
print("Rank {0:03d}: Var {1} collective ({2}/{3})".format(
self.rank, var_name, i + 1, len(self.variables)))
for att_name, att_value in var_dict.items():
if att_name == 'data':
if self.info:
print("Rank {0:03d}: Filling {1})".format(self.rank, var_name))
if 'data_aux' in var_dict.keys():
att_value = var_dict['data_aux']
if len(att_value.shape) == 1:
try:
var[self.write_axis_limits['x_min']:self.write_axis_limits['x_max']] = att_value
except IndexError:
raise IndexError("Different shapes. out_shape={0}, data_shp={1}".format(
var[self.write_axis_limits['x_min']:self.write_axis_limits['x_max']].shape,
att_value.shape))
except ValueError:
raise ValueError("Axis limits cannot be accessed. out_shape={0}, data_shp={1}".format(
var[self.write_axis_limits['x_min']:self.write_axis_limits['x_max']].shape,
att_value.shape))
elif len(att_value.shape) == 2:
if 'strlen' in var_dims:
try:
var[self.write_axis_limits['x_min']:self.write_axis_limits['x_max'], :] = att_value
except IndexError:
raise IndexError("Different shapes. out_shape={0}, data_shp={1}".format(
var[self.write_axis_limits['x_min']:self.write_axis_limits['x_max'], :].shape,
att_value.shape))
except ValueError:
raise ValueError("Axis limits cannot be accessed. out_shape={0}, data_shp={1}".format(
var[self.write_axis_limits['x_min']:self.write_axis_limits['x_max'], :].shape,
att_value.shape))
else:
try:
var[self.write_axis_limits['x_min']:self.write_axis_limits['x_max'],
self.write_axis_limits['t_min']:self.write_axis_limits['t_max']] = att_value
except IndexError:
raise IndexError("Different shapes. out_shape={0}, data_shp={1}".format(
var[self.write_axis_limits['x_min']:self.write_axis_limits['x_max'],
self.write_axis_limits['t_min']:self.write_axis_limits['t_max']].shape,
att_value.shape))
except ValueError:
raise ValueError("Axis limits cannot be accessed. out_shape={0}, data_shp={1}".format(
var[self.write_axis_limits['x_min']:self.write_axis_limits['x_max'],
self.write_axis_limits['t_min']:self.write_axis_limits['t_max']].shape,
att_value.shape))
elif len(att_value.shape) == 3:
try:
var[self.write_axis_limits['x_min']:self.write_axis_limits['x_max'],
self.write_axis_limits['t_min']:self.write_axis_limits['t_max'],
:] = att_value
except IndexError:
raise IndexError("Different shapes. out_shape={0}, data_shp={1}".format(
var[self.write_axis_limits['x_min']:self.write_axis_limits['x_max'],
self.write_axis_limits['t_min']:self.write_axis_limits['t_max'],
:].shape,
att_value.shape))
except ValueError:
raise ValueError("Axis limits cannot be accessed. out_shape={0}, data_shp={1}".format(
var[self.write_axis_limits['x_min']:self.write_axis_limits['x_max'],
self.write_axis_limits['t_min']:self.write_axis_limits['t_max'],
:].shape,
att_value.shape))
if self.info:
print("Rank {0:03d}: Var {1} data ({2}/{3})".format(self.rank, var_name, i + 1,
len(self.variables)))
elif att_name not in ['chunk_size', 'var_dims', 'dimensions', 'dtype', 'data_aux']:
var.setncattr(att_name, att_value)
if 'data_aux' in var_dict.keys():
del var_dict['data_aux']
self._set_var_crs(var)
if self.info:
print("Rank {0:03d}: Var {1} completed ({2}/{3})".format(self.rank, var_name, i + 1,
len(self.variables)))
return None
def _gather_data(self, data_to_gather):
"""
Gather all the variable data into the MPI rank 0 to perform a serial write.
Returns
-------
data_to_gather: dict
Variables to gather.
"""
data_list = deepcopy(data_to_gather)
for var_name, var_info in data_list.items():
try:
# noinspection PyArgumentList
data_aux = self.comm.gather(data_list[var_name]['data'], root=0)
if self.rank == 0:
shp_len = len(data_list[var_name]['data'].shape)
# concatenate over station
if self.parallel_method == 'X':
if shp_len == 1:
# dimensions = (station)
axis = 0
elif shp_len == 2:
# dimensions = (station, strlen) or
# dimensions = (station, time)
axis = 0
else:
msg = 'The points NetCDF must have '
msg += 'surface values (without levels).'
raise NotImplementedError(msg)
elif self.parallel_method == 'T':
# concatenate over time
if shp_len == 1:
# dimensions = (station)
axis = None
continue
elif shp_len == 2:
if 'strlen' in var_info['dimensions']:
# dimensions = (station, strlen)
axis = None
continue
else:
# dimensions = (station, time)
axis = 1
else:
msg = 'The points NetCDF must have '
msg += 'surface values (without levels).'
raise NotImplementedError(msg)
else:
raise NotImplementedError(
"Parallel method '{meth}' is not implemented. Use one of these: {accept}".format(
meth=self.parallel_method, accept=['X', 'T']))
data_list[var_name]['data'] = np.concatenate(data_aux, axis=axis)
except Exception as e:
print("**ERROR** an error has occurred while gathering the '{0}' variable.\n".format(var_name))
sys.stderr.write("**ERROR** an error has occurred while gathering the '{0}' variable.\n".format(var_name))
print(e)
sys.stderr.write(str(e))
# print(e, file=sys.stderr)
sys.stderr.flush()
self.comm.Abort(1)
raise e
return data_list
def _create_metadata(self, netcdf):
"""
Create metadata variables.
Parameters
----------
netcdf : Dataset
NetCDF object.
"""
# N FLAG CODES
flag = netcdf.createVariable('flag', np.int64, ('station', 'time', 'N_flag_codes',),
zlib=self.zip_lvl > 0, complevel=self.zip_lvl)
flag.units = ''
flag.axis = ''
flag.long_name = ''
flag.standard_name = 'flag'
if self.size > 1:
flag.set_collective(True)
flag[:] = self._flag['data']
# N QA CODES
qa = netcdf.createVariable('qa', np.int64, ('station', 'time', 'N_qa_codes',),
zlib=self.zip_lvl > 0, complevel=self.zip_lvl)
qa.units = ''
qa.axis = ''
qa.long_name = ''
qa.standard_name = 'N_qa_codes'
if self.size > 1:
qa.set_collective(True)
qa[:] = self._qa['data']
return None
[docs]
def to_netcdf(self, path, compression_level=0, serial=False, info=False, chunking=False):
"""
Write the netCDF output file.
Parameters
----------
path : str
Path to the output netCDF file.
compression_level : int
Level of compression (0 to 9) Default: 0 (no compression).
serial : bool
Indicates if you want to write in serial or not. Default: False.
info : bool
Indicates if you want to print the information of each writing step by stdout Default: False.
chunking : bool
Indicates if you want a chunked netCDF output. Only available with non serial writes. Default: False.
"""
if (not serial) and (self.size > 1):
msg = 'WARNING!!! '
msg += 'GHOST datasets cannot be written in parallel yet. '
msg += 'Changing to serial mode.'
warnings.warn(msg)
sys.stderr.flush()
super(PointsNesGHOST, self).to_netcdf(path, compression_level=compression_level,
serial=True, info=info, chunking=chunking)
return None
[docs]
def to_points(self):
"""
Transform a PointsNesGHOST into a PointsNes object
Returns
----------
points_nes : nes.Nes
Points Nes Object (without GHOST metadata variables)
"""
points_nes = PointsNes(comm=self.comm,
info=self.info,
balanced=self.balanced,
parallel_method=self.parallel_method,
avoid_first_hours=self.hours_start,
avoid_last_hours=self.hours_end,
first_level=self.first_level,
last_level=self.last_level,
create_nes=True,
lat=self.lat['data'],
lon=self.lon['data'],
times=self.time
)
# The version attribute in GHOST files prior to 1.3.3 is called data_version, after it is version
if 'version' in self.global_attrs:
GHOST_version = self.global_attrs['version']
elif 'data_version' in self.global_attrs:
GHOST_version = self.global_attrs['data_version']
metadata_variables = self.get_standard_metadata(GHOST_version)
self.free_vars(metadata_variables)
self.free_vars('station')
points_nes.variables = deepcopy(self.variables)
return points_nes
[docs]
def get_standard_metadata(self, GHOST_version):
"""
Get all possible GHOST variables for each version.
Parameters
----------
GHOST_version : str
Version of GHOST file.
Returns
----------
metadata_variables[GHOST_version] : list
List of metadata variables for a certain GHOST version
"""
# This metadata variables are
metadata_variables = {'1.4': ['GHOST_version', 'station_reference', 'station_timezone', 'latitude', 'longitude',
'altitude', 'sampling_height', 'measurement_altitude', 'ellipsoid',
'horizontal_datum', 'vertical_datum', 'projection', 'distance_to_building',
'distance_to_kerb', 'distance_to_junction', 'distance_to_source', 'street_width',
'street_type', 'daytime_traffic_speed', 'daily_passing_vehicles', 'data_level',
'climatology', 'station_name', 'city', 'country',
'administrative_country_division_1', 'administrative_country_division_2',
'population', 'representative_radius', 'network', 'associated_networks',
'area_classification', 'station_classification', 'main_emission_source',
'land_use', 'terrain', 'measurement_scale',
'ESDAC_Iwahashi_landform_classification',
'ESDAC_modal_Iwahashi_landform_classification_5km',
'ESDAC_modal_Iwahashi_landform_classification_25km',
'ESDAC_Meybeck_landform_classification',
'ESDAC_modal_Meybeck_landform_classification_5km',
'ESDAC_modal_Meybeck_landform_classification_25km',
'GHSL_settlement_model_classification',
'GHSL_modal_settlement_model_classification_5km',
'GHSL_modal_settlement_model_classification_25km',
'Joly-Peuch_classification_code', 'Koppen-Geiger_classification',
'Koppen-Geiger_modal_classification_5km',
'Koppen-Geiger_modal_classification_25km',
'MODIS_MCD12C1_v6_IGBP_land_use', 'MODIS_MCD12C1_v6_modal_IGBP_land_use_5km',
'MODIS_MCD12C1_v6_modal_IGBP_land_use_25km', 'MODIS_MCD12C1_v6_UMD_land_use',
'MODIS_MCD12C1_v6_modal_UMD_land_use_5km',
'MODIS_MCD12C1_v6_modal_UMD_land_use_25km', 'MODIS_MCD12C1_v6_LAI',
'MODIS_MCD12C1_v6_modal_LAI_5km', 'MODIS_MCD12C1_v6_modal_LAI_25km',
'WMO_region', 'WWF_TEOW_terrestrial_ecoregion', 'WWF_TEOW_biogeographical_realm',
'WWF_TEOW_biome', 'UMBC_anthrome_classification',
'UMBC_modal_anthrome_classification_5km',
'UMBC_modal_anthrome_classification_25km',
'EDGAR_v4.3.2_annual_average_BC_emissions',
'EDGAR_v4.3.2_annual_average_CO_emissions',
'EDGAR_v4.3.2_annual_average_NH3_emissions',
'EDGAR_v4.3.2_annual_average_NMVOC_emissions',
'EDGAR_v4.3.2_annual_average_NOx_emissions',
'EDGAR_v4.3.2_annual_average_OC_emissions',
'EDGAR_v4.3.2_annual_average_PM10_emissions',
'EDGAR_v4.3.2_annual_average_biogenic_PM2.5_emissions',
'EDGAR_v4.3.2_annual_average_fossilfuel_PM2.5_emissions',
'EDGAR_v4.3.2_annual_average_SO2_emissions', 'ASTER_v3_altitude',
'ETOPO1_altitude', 'ETOPO1_max_altitude_difference_5km',
'GHSL_built_up_area_density', 'GHSL_average_built_up_area_density_5km',
'GHSL_average_built_up_area_density_25km', 'GHSL_max_built_up_area_density_5km',
'GHSL_max_built_up_area_density_25km', 'GHSL_population_density',
'GHSL_average_population_density_5km', 'GHSL_average_population_density_25km',
'GHSL_max_population_density_5km', 'GHSL_max_population_density_25km',
'GPW_population_density', 'GPW_average_population_density_5km',
'GPW_average_population_density_25km', 'GPW_max_population_density_5km',
'GPW_max_population_density_25km',
'NOAA-DMSP-OLS_v4_nighttime_stable_lights',
'NOAA-DMSP-OLS_v4_average_nighttime_stable_lights_5km',
'NOAA-DMSP-OLS_v4_average_nighttime_stable_lights_25km',
'NOAA-DMSP-OLS_v4_max_nighttime_stable_lights_5km',
'NOAA-DMSP-OLS_v4_max_nighttime_stable_lights_25km',
'OMI_level3_column_annual_average_NO2',
'OMI_level3_column_cloud_screened_annual_average_NO2',
'OMI_level3_tropospheric_column_annual_average_NO2',
'OMI_level3_tropospheric_column_cloud_screened_annual_average_NO2',
'GSFC_coastline_proximity', 'primary_sampling_type',
'primary_sampling_instrument_name',
'primary_sampling_instrument_documented_flow_rate',
'primary_sampling_instrument_reported_flow_rate',
'primary_sampling_process_details', 'primary_sampling_instrument_manual_name',
'primary_sampling_further_details', 'sample_preparation_types',
'sample_preparation_techniques', 'sample_preparation_process_details',
'sample_preparation_further_details', 'measurement_methodology',
'measuring_instrument_name', 'measuring_instrument_sampling_type',
'measuring_instrument_documented_flow_rate',
'measuring_instrument_reported_flow_rate', 'measuring_instrument_process_details',
'measuring_instrument_process_details', 'measuring_instrument_manual_name',
'measuring_instrument_further_details', 'measuring_instrument_reported_units',
'measuring_instrument_reported_lower_limit_of_detection',
'measuring_instrument_documented_lower_limit_of_detection',
'measuring_instrument_reported_upper_limit_of_detection',
'measuring_instrument_documented_upper_limit_of_detection',
'measuring_instrument_reported_uncertainty',
'measuring_instrument_documented_uncertainty',
'measuring_instrument_reported_accuracy',
'measuring_instrument_documented_accuracy',
'measuring_instrument_reported_precision',
'measuring_instrument_documented_precision',
'measuring_instrument_reported_zero_drift',
'measuring_instrument_documented_zero_drift',
'measuring_instrument_reported_span_drift',
'measuring_instrument_documented_span_drift',
'measuring_instrument_reported_zonal_drift',
'measuring_instrument_documented_zonal_drift',
'measuring_instrument_reported_measurement_resolution',
'measuring_instrument_documented_measurement_resolution',
'measuring_instrument_reported_absorption_cross_section',
'measuring_instrument_documented_absorption_cross_section',
'measuring_instrument_inlet_information',
'measuring_instrument_calibration_scale',
'network_provided_volume_standard_temperature',
'network_provided_volume_standard_pressure', 'retrieval_algorithm',
'principal_investigator_name', 'principal_investigator_institution',
'principal_investigator_email_address', 'contact_name',
'contact_institution', 'contact_email_address', 'meta_update_stamp',
'data_download_stamp', 'data_revision_stamp', 'network_sampling_details',
'network_uncertainty_details', 'network_maintenance_details',
'network_qa_details', 'network_miscellaneous_details', 'data_licence',
'process_warnings', 'temporal_resolution',
'reported_lower_limit_of_detection_per_measurement',
'reported_upper_limit_of_detection_per_measurement',
'reported_uncertainty_per_measurement', 'derived_uncertainty_per_measurement',
'day_night_code', 'weekday_weekend_code', 'season_code',
'hourly_native_representativity_percent', 'hourly_native_max_gap_percent',
'daily_native_representativity_percent', 'daily_representativity_percent',
'daily_native_max_gap_percent', 'daily_max_gap_percent',
'monthly_native_representativity_percent', 'monthly_representativity_percent',
'monthly_native_max_gap_percent', 'monthly_max_gap_percent',
'annual_native_representativity_percent', 'annual_native_max_gap_percent',
'all_representativity_percent', 'all_max_gap_percent'],
}
return metadata_variables[GHOST_version]
[docs]
def add_variables_to_shapefile(self, var_list, idx_lev=0, idx_time=0):
"""
Add variables data to shapefile.
var_list : list, str
List (or single string) of the variables to be loaded and saved in the shapefile.
idx_lev : int
Index of vertical level for which the data will be saved in the shapefile.
idx_time : int
Index of time for which the data will be saved in the shapefile.
"""
if idx_lev != 0:
msg = 'Error: Points dataset has no level (Level: {0}).'.format(idx_lev)
raise ValueError(msg)
for var_name in var_list:
# station as dimension
if len(self.variables[var_name]['dimensions']) == 1:
self.shapefile[var_name] = self.variables[var_name]['data'][:].ravel()
# station and time as dimensions
else:
self.shapefile[var_name] = self.variables[var_name]['data'][:, idx_time].ravel()
return None
@staticmethod
def _get_axis_index_(axis):
if axis == 'T':
value = 1
elif axis == 'X':
value = 0
else:
raise ValueError("Unknown axis: {0}".format(axis))
return value
@staticmethod
def _set_var_crs(var):
"""
Set the grid_mapping
Parameters
----------
var : Variable
netCDF4-python variable object.
"""
return None