Skip to content

Commit

Permalink
Adding AverageShape to daops (#114)
Browse files Browse the repository at this point in the history
* Added average_shape to daops/ops

* Added tests in daops/test_average.py for average_shape

* Updated AUTHORS.rst and HISTORY.rst

* Update Docstrings

---------

Co-authored-by: charlesgauthier-udm <charlles.gauthier.1@umontreal.ca>
  • Loading branch information
charlesgauthier-udm and charlesgauthier-udm committed Feb 19, 2024
1 parent 841c650 commit ac85cb8
Show file tree
Hide file tree
Showing 4 changed files with 123 additions and 0 deletions.
1 change: 1 addition & 0 deletions AUTHORS.rst
Expand Up @@ -17,3 +17,4 @@ Contributors
------------

* Trevor James Smith smith.trevorj@ouranos.ca
* Charles Gauthier gauthier.charles@ouranos.ca
9 changes: 9 additions & 0 deletions HISTORY.rst
@@ -1,5 +1,14 @@
Version History
===============
v0.10.1 (unreleased)
-------------------

New Features
^^^^^^^^^^^^

* Add clisops.ops.average_shape to daops.ops.average



v0.10.0 (2023-11-27)
-------------------
Expand Down
67 changes: 67 additions & 0 deletions daops/ops/average.py
@@ -1,4 +1,5 @@
from clisops.ops.average import average_over_dims as clisops_average_over_dims
from clisops.ops.average import average_shape as clisops_average_shape
from clisops.ops.average import average_time as clisops_average_time
from roocs_utils.parameter import collection_parameter
from roocs_utils.parameter import dimension_parameter
Expand All @@ -7,6 +8,8 @@

__all__ = [
"average_over_dims",
"average_time",
"average_shape"
]


Expand Down Expand Up @@ -74,7 +77,71 @@ def average_over_dims(
"""

result_set = Average(**locals()).calculate()
return result_set


class AverageShape(Operation):
def _resolve_params(self, collection, **params):
"""
Resolve the input parameters to `self.params` and parameterise
collection parameter and set to `self.collection`.
"""
shape = params.get("shape")
collection = collection_parameter.CollectionParameter(collection)

self.collection = collection
self.params = {
"shape": shape,
"variable": params.get("variable"),
}

def get_operation_callable(self):
return clisops_average_shape


def average_shape(
collection,
shape,
variable=None,
output_dir=None,
output_type="netcdf",
split_method="time:auto",
file_namer="standard",
apply_fixes=True,
):
"""
Average input dataset over indicated shape.
Parameters
----------
collection: Collection of datasets to process, sequence or string of comma separated dataset identifiers.
shape: Path to shape file, or directly a geodataframe to perform average within.
variable: Variables to average. If None, average over all data variables.
output_dir: str or path like object describing output directory for output files.
output_type: {"netcdf", "nc", "zarr", "xarray"}
split_method: {"time:auto"}
file_namer: {"standard", "simple"}
apply_fixes: Boolean. If True fixes will be applied to datasets if needed. Default is True.
Returns
-------
List of outputs in the selected type: a list of xarray Datasets or file paths.
Examples
--------
| collection: ("cmip6.cmip..cas.fgoals-g3.historical.r1i1p1fi.Amon.tas.gn.v20190818",)
| shape: "path_to_shape"
| ignore_undetected_dims: (-5.,49.,10.,65)
| output_type: "netcdf"
| output_dir: "/cache/wps/procs/req0111"
| split_method: "time:auto"
| file_namer: "standard"
| apply_fixes: True
"""
a = AverageShape(**locals())
result_set = AverageShape(**locals()).calculate()
return result_set


Expand Down
46 changes: 46 additions & 0 deletions tests/test_operations/test_average.py
Expand Up @@ -2,11 +2,14 @@

import pytest
import xarray as xr
import geopandas as gpd
from shapely import Polygon, MultiPolygon
from roocs_utils.exceptions import InvalidParameterValue

from daops import CONFIG
from daops.ops.average import average_over_dims
from daops.ops.average import average_time
from daops.ops.average import average_shape
from tests._common import CMIP5_DAY
from tests._common import CMIP6_MONTH

Expand All @@ -15,6 +18,17 @@
"cmip5.output1.MOHC.HadGEM2-ES.rcp85.mon.atmos.Amon.r1i1p1.latest.tas",
"cmip5.output1.MOHC.HadGEM2-ES.historical.mon.land.Lmon.r1i1p1.latest.rh",
]
CMIP6_IDS = [
"CMIP6.CMIP.CAS.FGOALS-g3.historical.r1i1p1f1.Amon.tas.gn.v20190818"
]

POLY = Polygon([[5.8671874999999996, 57.326521225217064],
[-15.468749999999998, 48.45835188280866],
[-16.171875, 24.84656534821976],
[-3.8671874999999996, 13.581920900545844],
[21.796875, 25.799891182088334],
[22.8515625, 52.482780222078226],
[5.8671874999999996, 57.326521225217064]])


def _check_output_nc(result, fname="output_001.nc"):
Expand Down Expand Up @@ -94,6 +108,38 @@ def test_average_level(tmpdir):
)


@pytest.mark.online
def test_average_shape(tmpdir):
# Save POLY to tmpdir
tmp_poly_path = os.path.join(tmpdir,"tmppoly.json")
gpd.GeoDataFrame([{'geometry': POLY}]).to_file(tmp_poly_path)

result = average_shape(
CMIP6_IDS[0],
shape=tmp_poly_path,
variable=None,
output_dir=tmpdir,
file_namer='simple',
apply_fixes=False
)
_check_output_nc(result)
ds = xr.open_dataset(result.file_uris[0], use_cftime=True)
assert "geom" in ds.dims


@pytest.mark.online
def test_average_shape_none(tmpdir):
with pytest.raises(InvalidParameterValue) as exc:
result = average_shape(
CMIP6_IDS[0],
shape=None,
variable=None,
output_dir=tmpdir,
file_namer='simple',
apply_fixes=False)
assert str(exc.value) == "At least one area for averaging must be provided"


@pytest.mark.online
def test_average_time_month(tmpdir):
ds = xr.open_mfdataset(CMIP5_DAY, use_cftime=True, combine="by_coords")
Expand Down

0 comments on commit ac85cb8

Please sign in to comment.