Finch usage

Finch is a WPS server for climate indicators, but also has a few utilities to facilitate data handling. To get started, first instantiate the client. Here, the client will try to connect to a local or remote finch instance, depending on whether the environment variable WPS_URL is defined.

[1]:
import os

import xarray as xr
from birdy import WPSClient

pavics_url = "https://pavics.ouranos.ca/twitcher/ows/proxy/finch/wps"
url = os.environ.get("WPS_URL", pavics_url)
verify_ssl = True if "DISABLE_VERIFY_SSL" not in os.environ else False
wps = WPSClient(url, verify=verify_ssl)

The list of available processes can be displayed using the magic ? command (wps?). Similarly, help about any individual process is available using ? or the help command.

[2]:
# NBVAL_IGNORE_OUTPUT

help(wps.frost_days)
Help on method frost_days in module birdy.client.base:

frost_days(tasmin=None, thresh='0 degC', freq='YS', month=None, season=None, check_missing='any', missing_options=None, cf_compliance='warn', data_validation='raise', variable=None, output_name=None, output_format='netcdf', csv_precision=None, output_formats=None) method of birdy.client.base.WPSClient instance
    Number of days where the daily minimum temperature is below a given threshold.

    Parameters
    ----------
    tasmin : ComplexData:mimetype:`application/x-netcdf`, :mimetype:`application/x-ogc-dods`
        NetCDF Files or archive (tar/zip) containing netCDF files. Minimum surface temperature.
    thresh : string
        Freezing temperature.
    freq : {'YS', 'MS', 'QS-DEC', 'AS-JUL'}string
        Resampling frequency.
    month : {'1', '2', '3', '4', '5', '6', '7', '8', '9', '10', ...}integer
        Months of the year over which to compute indicator.
    season : {'DJF', 'MAM', 'JJA', 'SON'}string
        Climatological season over which to compute indicator.
    check_missing : {'any', 'wmo', 'pct', 'at_least_n', 'skip', 'from_context'}string
        Method used to determine which aggregations should be considered missing.
    missing_options : ComplexData:mimetype:`application/json`
        JSON representation of dictionary of missing method parameters.
    cf_compliance : {'log', 'warn', 'raise'}string
        Whether to log, warn or raise when inputs have non-CF-compliant attributes.
    data_validation : {'log', 'warn', 'raise'}string
        Whether to log, warn or raise when inputs fail data validation checks.
    variable : string
        Name of the variable in the input files.
    output_name : string
        Filename of the output (no extension).
    output_format : {'netcdf', 'csv'}string
        Choose in which format you want to receive the result. CSV actually means a zip file of two csv files.
    csv_precision : integer
        Only valid if output_format is CSV. If not set, all decimal places of a 64 bit floating precision number are printed. If negative, rounds before the decimal point.

    Returns
    -------
    output : ComplexData:mimetype:`application/x-netcdf`, :mimetype:`application/zip`
        The format depends on the 'output_format' input parameter.
    output_log : ComplexData:mimetype:`text/plain`
        Collected logs during process run.
    ref : ComplexData:mimetype:`application/metalink+xml; version=4.0`
        Metalink file storing all references to output files.

To actually compute an indicator, we need to specify the path to the netCDF file used as input for the calculation of the indicator. To compute frost_days, we need a time series of daily minimum temperature. Here we’ll use a small test file. Note that here we’re using an OPeNDAP link, but it could also be an url to a netCDF file, or the path to a local file on disk. We then simply call the indicator. The response is an object that can poll the server to inquire about the status of the process. This object can use two modes: - synchronous: it will wait for the server’s response before returning; or - asynchronous: it will return immediately, but without the actual output from the process.

Here, since we’re applying the process on a small test file, we’re using the default synchronous mode. For long computations, use the asynchronous mode to avoid time-out errors. The asynchronous mode is activated by setting the progress attribute of the WPS client to True.

[3]:
tasmin = "https://pavics.ouranos.ca/twitcher/ows/proxy/thredds/dodsC/birdhouse/testdata/flyingpigeon/cmip3/tasmin.sresa2.miub_echo_g.run1.atm.da.nc"
resp = wps.frost_days(tasmin)
[4]:
print("Process status: ", resp.status)
urls = resp.get()
print("Link to process output: ", urls.output)
Process status:  ProcessSucceeded
Link to process output:  https://pavics.ouranos.ca/wpsoutputs/finch/16a77b02-e616-11ee-aab6-484d7ef8da38/frost_days_sres_a2_experiment_20460101_20650101.nc

The get method returns a NamedTuple object with all the WPS outputs, either as references to files or actual content. To copy the file to the local disk, use the getOutput method.

[5]:
# NBVAL_IGNORE_OUTPUT

import tempfile

fn = tempfile.NamedTemporaryFile()
resp.getOutput(fn.name, identifier="output")
ds = xr.open_dataset(fn.name, decode_timedelta=False)
ds.frost_days
[5]:
<xarray.DataArray 'frost_days' (time: 20, lat: 6, lon: 7)>
[840 values with dtype=float64]
Coordinates:
    height   float64 ...
  * lat      (lat) float64 42.68 46.39 50.1 53.81 57.52 61.23
  * lon      (lon) float64 281.2 285.0 288.8 292.5 296.2 300.0 303.8
  * time     (time) object 2046-01-01 00:00:00 ... 2065-01-01 00:00:00
Attributes:
    units:          days
    cell_methods:   time: minimum (interval: 30 minutes) time: sum over days
    history:        tas=max(195,tas) applied to raw data; min of 194.73 detec...
    standard_name:  days_with_air_temperature_below_threshold
    long_name:      Number of days where the daily minimum temperature is bel...
    description:    Annual number of days where the daily minimum temperature...

birdy’s get function has a more user-friendly solution: setting the asobj argument to True will directly download all the output files and return outputs as python objects. This mechanims however does not allow for additional keyword arguments, such as the decode_timedelta needed here.

[6]:
# NBVAL_IGNORE_OUTPUT

out = resp.get(asobj=True)
out.output
[6]:
<xarray.Dataset>
Dimensions:     (lat: 6, lon: 7, time: 20)
Coordinates:
    height      float64 ...
  * lat         (lat) float64 42.68 46.39 50.1 53.81 57.52 61.23
  * lon         (lon) float64 281.2 285.0 288.8 292.5 296.2 300.0 303.8
  * time        (time) object 2046-01-01 00:00:00 ... 2065-01-01 00:00:00
Data variables:
    frost_days  (time, lat, lon) timedelta64[ns] ...
Attributes: (12/20)
    comment:                  Spinup: restart files from end of experiment 20...
    title:                    MIUB  model output prepared for IPCC Fourth Ass...
    cmor_version:             0.96
    institution:              Canadian Centre for Climate Services (CCCS)
    source:                   ECHO-G(1999): atmosphere: ECHAM4 (T30L19) with ...
    contact:                  Canadian Centre for Climate Services
    ...                       ...
    id:                       pcmdi.ipcc4.miub_echo_g.sresa2.run1.atm.da
    history:                  Mon Aug  1 11:43:58 2011: ncks -4 -L 7 -d lat,4...
    NCO:                      4.0.9
    climateindex_package_id:  https://github.com/Ouranosinc/xclim
    product:                  derived climate index
    institute_id:             CCCS