from pyaerocom._lowlevel_helpers import dict_to_str
from pyaerocom.time_config import TS_TYPES
[docs]
class GridIO:
"""Global I/O settings for gridded data
This class includes options related to the import of gridded data. This
includes both options related to file search as well as preprocessing
options.
Attributes
----------
FILE_TYPE : str
file type of data files. Defaults to .nc
TS_TYPES : list
list of strings specifying temporal resolution options encrypted in
file names.
PERFORM_FMT_CHECKS : bool
perform formatting checks when reading netcdf data, using metadata
encoded in filenames (requires that NetCDF file follows a registered
naming convention)
DEL_TIME_BOUNDS : bool
if True, preexisting bounds on time are deleted when grid data is
loaded. Else, nothing is done. Aerocom default is True
SHIFT_LONS : bool
if True, longitudes are shifted to
-180 <= lon <= 180 when data is loaded (in case they are defined
0 <= lon <= 360. Aerocom default is True.
CHECK_TIME_FILENAME : bool
the times stored in NetCDF files may be wrong or not stored according
to the CF conventions. If True, the times are checked and if
:attr:`CORRECT_TIME_FILENAME`, corrected for on data import based what
is encrypted in the
file name. In case of Aerocom models, it is ensured that the filename
contains both the year and the temporal resolution in the filenames
(for details see :class:`pyaerocom.io.FileConventionRead`).
Aerocom default is True
CORRECT_TIME_FILENAME : bool
if True and time dimension in data is found to be different from
filename, it is attempted to be corrected
EQUALISE_METADATA : bool
if True (and if metadata varies between different NetCDF files that are
supposed to be merged in time), the metadata in all loaded objects is
unified based on the metadata of the first grid (otherwise,
concatenating them in time might not work using the Iris interface).
This might need to be reviewed and should be used with care if
specific metadata aspects of individual files need to be accessed.
Aerocom default is True
USE_FILECONVENTION : bool
if True, file names are strictly required to follow one of the file
naming conventions that can be specified in the file
`file_conventions.ini <https://github.com/metno/pyaerocom/tree/master/
pyaerocom/data>`__. Aerocom default is True.
INCLUDE_SUBDIRS : bool
if True, search for files is expanded to all subdirecories included in
data directory. Aerocom default is False.
INFER_SURFACE_LEVEL : bool
if True then surface level for 4D gridded data is inferred automatically
when necessary (e.g. when extracting surface time series from 4D
gridded data object that does not contain sufficient information about
vertical dimension)
"""
UNITS_ALIASES = {"/m": "m-1"}
_AEROCOM = {
"FILE_TYPE": ".nc",
"PERFORM_FMT_CHECKS": True,
"DEL_TIME_BOUNDS": True,
"SHIFT_LONS": True,
"CHECK_TIME_FILENAME": True,
"CORRECT_TIME_FILENAME": True,
"CHECK_DIM_COORDS": True,
"EQUALISE_METADATA": True,
"INCLUDE_SUBDIRS": False,
}
_DEFAULT = {
"FILE_TYPE": ".nc",
"PERFORM_FMT_CHECKS": True,
"DEL_TIME_BOUNDS": True,
"SHIFT_LONS": True,
"CHECK_TIME_FILENAME": True,
"CORRECT_TIME_FILENAME": True,
"CHECK_DIM_COORDS": True,
"EQUALISE_METADATA": True,
"INCLUDE_SUBDIRS": False,
}
def __init__(self, **kwargs):
self.FILE_TYPE = ".nc"
# it is important to keep them in the order from highest to lowest
# resolution
self.TS_TYPES = TS_TYPES
self.PERFORM_FMT_CHECKS = True
# delete time bounds if they exist in netCDF files
self.DEL_TIME_BOUNDS = True
# shift longitudes to -180 -> 180 repr (if applicable)
self.SHIFT_LONS = True
self.CHECK_TIME_FILENAME = True
self.CORRECT_TIME_FILENAME = True
self.CHECK_DIM_COORDS = False
# check and update metadata dictionary on Cube load since
# iris concatenate of Cubes only works if metadata is equal
self.EQUALISE_METADATA = True
self.INCLUDE_SUBDIRS = False
self.INFER_SURFACE_LEVEL = True
self.load_default()
[docs]
def load_aerocom_default(self):
self.from_dict(self._AEROCOM)
[docs]
def load_default(self):
self.from_dict(self._DEFAULT)
[docs]
def to_dict(self):
"""Convert object to dictionary
Returns
-------
dict
settings dictionary
"""
return self.__dict__
[docs]
def from_dict(self, dictionary=None, **settings):
"""Import settings from dictionary"""
if not dictionary:
dictionary = {}
dictionary.update(settings)
for key, val in dictionary.items():
self[key] = val
def __setitem__(self, key, value):
"""Set item
GridIO["<key>"] = value <=> GridIO.<key> = value
<=> GridIO.__setitem__(<key>, value)
Raises
------
IOError
if key is not a valid setting
"""
if not key in self.__dict__:
raise OSError("Could not update IO setting: Invalid key")
self.__dict__[key] = value
def __getitem__(self, key):
"""Get item using curly brackets
GridIO["<key>"] => value
"""
if not key in self.__dict__:
raise OSError("Invalid attribute")
return self.__dict__[key]
def __str__(self):
head = f"Pyaerocom {type(self).__name__}"
return "\n{}\n{}\n{}".format(head, len(head) * "-", dict_to_str(self.to_dict()))