Commit 48be377a authored by BorjaEst's avatar BorjaEst
Browse files

Complete function/lclass documentation

parent a88a98a0
......@@ -2,8 +2,42 @@ o3skim package
==============
.. automodule:: o3skim
:members:
Source,
load,
cd
:members: loading, processing, grouping, saving
o3skim loads
--------------------------
.. automodule:: o3skim.loads
:members: tco3, vmro3
o3skim standardization
--------------------------
.. automodule:: o3skim.standardization
:members: tco3, vmro3
o3skim operations
--------------------------
.. automodule:: o3skim.loads
:members: run
o3skim extended_xarray
--------------------------
.. automodule:: o3skim.extended_xarray
:inherited-members:
:members: O3Accessor, TCO3Accessor, VMRO3Accessor
o3skim utils
--------------------------
.. automodule:: o3skim.utils
:inherited-members:
:members: cd, load, save, mergedicts
......@@ -56,7 +56,7 @@ def skim_process(name, operations, split_by, configuration):
# Data grouping
logging.info("Grouping processed model %s data", name)
years, datasets = o3skim.group(processed, split_by)
years, datasets = o3skim.grouping(processed, split_by)
# Create output directory saving
logging.info("Creating output directory %s", name)
......
"""
O3as package with classes and utilities to handle ozone data skimming.
"""
import logging
import xarray as xr
......@@ -13,6 +16,26 @@ logger = logging.getLogger('o3skim')
def loading(tco3_zm=None, vmro3_zm=None, metadata={}):
"""Function in charge of o3 variable data loading. The specifications
for the variables to load must follow this dict structure:
:paths: Regex expresion with paths to the datasets to load.
:name: Variable to retrieve after loading datasets.
:coordinates: Coordinates map translation from original datasets.
:metadata: Optional. Variable added metadata.
:param tco3_zm: Total Column Ozone data specifications.
:type tco3_zm: dict, {paths, name, coordinates, metadata}
:param vmro3_zm: Total Volume Mixing ratio data specifications.
:type vmro3_zm: dict, {paths, name, coordinates, metadata}
:param metadata: Model general metadata. Defaults to empty dict: {}.
:type metadata: dict, optional
:return: Xarray Dataset with specified variables and the metadata.
:rtype: tuple (:class:`xarray.Dataset`, metadata: dict)
"""
logger.debug("Loading ozone variables data")
dataset = xr.Dataset()
def raise_conflict(d1, d2): raise Exception(
......@@ -31,8 +54,29 @@ def loading(tco3_zm=None, vmro3_zm=None, metadata={}):
def processing(dataset, actions):
"""Function in charge of processing the list of o3skim operations
to the ozone variables dataset. The available list of operations
to perform are:
:lon_mean: Longitudinal mean accross the dataset.
:lat_mean: Latitudinal mean accross the dataset.
Note that multiple operations can be concatenated. For example
using the list ['lon_mean', 'lat_mean'] as actions parameter
input would perform a longitudinal mean followed afterwards by
a latitudinal mean before returning the result.
:param dataset: Original o3 dataset where to perform operations.
:type dataset: :class:`xarray.Dataset`
:param actions: List of operation names to perform.
:type actions: list
:return: Dataset after processing listed operations.
:rtype: :class:`xarray.Dataset`
"""
logger.debug("Processing queue: %s", actions)
actions = actions.copy() # Do not edit original
actions = actions.copy() # Do not edit original
operation = actions.pop()
processed = operations.run(operation, dataset)
if actions != []:
......@@ -40,7 +84,23 @@ def processing(dataset, actions):
return processed
def group(dataset, split_by):
def grouping(dataset, split_by):
"""Function in charge of splitting the input dataset into the
specified time range. The available list of split groups are:
:`None`: No splitting, returns ([None], [dataset])
:year: Split accross the dataset years.
:decade: Split accross the dataset decades.
:param dataset: Original o3 dataset where to perform splitting.
:type dataset: :class:`xarray.Dataset`
:param split_by: Type of split to apply.
:type split_by: str or None
:return: Dataset after splitting by the defined time.
:rtype: tuple ([year], [:class:`xarray.Dataset`])
"""
logger.debug("Splitting dataset by %s", split_by)
if not split_by:
return [None], [dataset]
......@@ -59,6 +119,22 @@ def group(dataset, split_by):
def saving(datasets, split_by=None, years=None):
"""Function in charge of saving the input dataset into the file
system using an specified time range. The available type of
output file formats are:
:`None`: Output file format is {var}.nc
:year: Output file format is {var}_{y}-{y+01}.nc
:decade: Output file format is {var}_{y}-{y+10}.nc
Note that dataset are saved in the current workspace directory.
:param datasets: List o3 datasets to save in the filesystem.
:type datasets: [:class:`xarray.Dataset`]
:param split_by: Type of saving format to apply.
:type split_by: str or None
"""
if not split_by:
def path(v, _): return "{}.nc".format(v)
elif split_by == 'year':
......
"""
xarray extension module to provide model class and functions to
Xarray extension module to provide model class and functions to
handle tco3 and vmro3 operations and data skimming.
"""
import logging
......@@ -10,6 +10,13 @@ logger = logging.getLogger('extended_xr')
@xr.register_dataset_accessor("o3")
class O3Accessor:
"""General accessor to access all possible ozone type accessor
using subscriptable syntax. For example:
- `dataset.o3['tco3_zm']` == `dataset.tco3`
- `dataset.o3['vmro3_zm']` == `dataset.vmro3`
"""
def __init__(self, xarray_obj):
self._model = xarray_obj
......@@ -27,6 +34,7 @@ class O3Variable:
@property
def dataset(self):
"""Returns variable as Dataset and conserving attributes."""
dataset = self._model[self._name].to_dataset()
dataset.attrs = self._model.attrs
return dataset
......@@ -34,11 +42,19 @@ class O3Variable:
@xr.register_dataset_accessor("tco3")
class TCO3Accessor(O3Variable):
"""Total Column of Ozone accessor.
(dataset.tco3 -acts_over-> tco3_zm variable).
"""
def __init__(self, xarray_obj):
O3Variable.__init__(self, xarray_obj, name='tco3_zm')
@xr.register_dataset_accessor("vmro3")
class VMO3Accessor(O3Variable):
class VMRO3Accessor(O3Variable):
"""Volume Mixing Ratio of Ozone accessor.
(dataset.vmro3 -acts_over-> vmro3_zm variable).
"""
def __init__(self, xarray_obj):
O3Variable.__init__(self, xarray_obj, name='vmro3_zm')
"""
Module in charge of data loading.
Module in charge of data loading and standardization.
"""
import logging
......@@ -12,6 +12,24 @@ logger = logging.getLogger('load')
def tco3(name, paths, coordinates, metadata={}):
"""Function to load data as standardized tco3_zm.
:param name: Variable to retrieve after loading datasets.
:type name: str
:param paths: Regex expresion with paths to the datasets to load.
:type paths: str
:param coordinates: Coordinates map translation from original datasets.
:type coordinates: dict
:param metadata: Variable specific metadata.
:type metadata: dict, optional
:return: Tuple with standardized tco3 data array, original dataset
attributes and variable specific metadata.
:rtype: tuple (:class:`xarray.DataArray`, dict, dict)
"""
logger.debug("Loading tco3 data from: %s", paths)
with xr.open_mfdataset(paths) as dataset:
datarray = standardization.tco3(
......@@ -22,6 +40,24 @@ def tco3(name, paths, coordinates, metadata={}):
def vmro3(name, paths, coordinates, metadata={}):
"""Function to load data as standardized vmro3_zm.
:param name: Variable to retrieve after loading datasets.
:type name: str
:param paths: Regex expresion with paths to the datasets to load.
:type paths: str
:param coordinates: Coordinates map translation from original datasets.
:type coordinates: dict
:param metadata: Variable specific metadata.
:type metadata: dict, optional
:return: Tuple with standardized vmro3 data array, original dataset
attributes and variable specific metadata.
:rtype: tuple (:class:`xarray.DataArray`, dict, dict)
"""
logger.debug("Loading vmro3 data from: %s", paths)
with xr.open_mfdataset(paths) as dataset:
datarray = standardization.vmro3(
......
"""
Module in charge of operations implementation.
Module in charge of implementing the o3skim operations.
"""
import logging
......@@ -7,6 +7,20 @@ logger = logging.getLogger('operations')
def run(name, dataset):
"""Main entry point for operation call on o3skimming functions:
:lon_mean: Longitudinal mean accross the dataset.
:lat_mean: Latitudinal mean accross the dataset.
:param name: Operation name to perform.
:type name: str
:param dataset: Original o3 dataset where to perform operations.
:type dataset: :class:`xarray.Dataset`
:return: Dataset after processing the specified operation.
:rtype: :class:`xarray.Dataset`
"""
if name == 'lon_mean':
return lon_mean(dataset)
elif name == 'lat_mean':
......
......@@ -9,13 +9,13 @@ def tco3(array, coord):
"""Standardizes a tco3 dataset.
:param array: DataArray to standardize.
:type array: xarray.DataArray
:type array: :class:`xarray.DataArray`
:param coord: Coordinates map for tco3 variable.
:type coord: {'lon':str, 'lat':str, 'time':str}
:return: Standardized DataArray.
:rtype: xarray.DataArray
:rtype: :class:`xarray.DataArray`
"""
array.name = 'tco3_zm'
array = squeeze(array)
......@@ -34,13 +34,13 @@ def vmro3(array, coord):
"""Standardizes a vmro3 dataset.
:param array: DataArray to standardize.
:type array: xarray.DataArray
:type array: :class:`xarray.DataArray`
:param coord: Coordinates map for vmro3 variable.
:type coord: {'lon':str, 'lat':str, 'plev':str, 'time':str}
:return: Standardized DataArray.
:rtype: xarray.DataArray
:rtype: :class:`xarray.DataArray`
"""
array.name = 'vmro3_zm'
array = squeeze(array)
......
......@@ -74,6 +74,11 @@ def mergedicts(d1, d2, if_conflict=lambda _, d: d):
:param d2: Dict to be recursively merged in d1.
:type d2: dict
:param if_conflict: Action to perform when key from d1 exists in d1.
Fun(d1,d2) which returns the value to store in d1.
Default action is to replace d1 key value by d2 key value.
:type if_conflict: function, optional
"""
for key in d2:
if key in d1:
......
......@@ -139,7 +139,7 @@ def groupby(request):
@pytest.fixture(scope='session')
def splitted(dataset, groupby):
return o3skim.group(dataset, split_by=groupby)
return o3skim.grouping(dataset, split_by=groupby)
@pytest.fixture(scope='session')
......
......@@ -50,4 +50,4 @@ class TestByDecade:
class TestExceptions:
def test_BadGroup(self, dataset, groupby):
pytest.raises(KeyError, o3skim.group, dataset, groupby)
pytest.raises(KeyError, o3skim.grouping, dataset, groupby)
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment