Source code for climaf.operators_derive

#!/usr/bin/python3
# -*- coding: utf-8 -*-

"""
CliMAF derive operators tools.
"""
from __future__ import print_function, division, unicode_literals, absolute_import

from env.clogging import clogger
from env.environment import *
from climaf.utils import Climaf_Operator_Error


def is_derived_variable(variable, project):
    """ True if the variable is a derived variable, either in provided project
    or in wildcard project '*'
    """
    rep = (project in derived_variables and variable in derived_variables[project] or
           "*" in derived_variables and variable in derived_variables["*"])
    clogger.debug("Checking if variable %s is derived for project %s : %s" % (variable, project, rep))
    return rep


def derived_variable(variable, project):
    """ Returns the entry defining a derived variable in requested project or in wildcard project '*'
    """
    if project in derived_variables and variable in derived_variables[project]:
        rep = derived_variables[project][variable]
    elif "*" in derived_variables and variable in derived_variables["*"]:
        rep = derived_variables['*'][variable]
    else:
        rep = None
    clogger.debug("Derived variable %s for project %s is %s" % (variable, project, rep))
    return rep


[docs]def derive(project, derivedVar, Operator, *invars, **params): """ Define that 'derivedVar' is a derived variable in 'project', computed by applying 'Operator' to input streams which are datasets whose variable names take the values in ``*invars`` and the parameter/arguments of Operator take the values in ``**params`` 'project' may be the wildcard : '*' Example, assuming that operator 'minus' has been defined as :: >>> cscript('minus','cdo sub ${in_1} ${in_2} ${out}') which means that ``minus`` uses CDO for substracting the two datasets; you may define, for a given project 'CMIP5', a new variable e.g. for cloud radiative effect at the surface, named 'rscre', using the difference of values of all-sky and clear-sky net radiation at the surface by:: >>> derive('CMIP5', 'rscre','minus','rs','rscs') You may then use this variable name at any location you would use any other variable name Note : you may use wildcard '*' for the project Another example is rescaling or renaming some variable; here, let us define how variable 'ta' can be derived from ERAI variable 't' : >>> derive('erai', 'ta','rescale', 't', scale=1., offset=0.) **However, this is not the most efficient way to do that**. See :py:func:`~climaf.classes.calias()` Expert use : argument 'derivedVar' may be a dictionary, which keys are derived variable names and values are scripts outputs names; example :: >>> cscript('vertical_interp', 'vinterp.sh ${in} surface_pressure=${in_2} ${out_l500} ${out_l850} method=${opt}') >>> derive('*', {'z500' : 'l500' , 'z850' : 'l850'},'vertical_interp', 'zg', 'ps', opt='log') """ # Action : register the information in a dedicated dict which keys # are single derived variable names, and which will be used at the # object evaluation step # Also : some consistency checks w.r.t. script definition if Operator in cscripts: if not isinstance(derivedVar, dict): derivedVar = dict(out=derivedVar) for outname in derivedVar: if (outname != 'out' and (not getattr(Operator, "outvarnames", None) or outname not in Operator.outvarnames)): raise Climaf_Operator_Error("%s is not a named output for operator %s; type help(%s)" % (outname, Operator, Operator)) s = cscripts[Operator] if s.inputs_number() != len(invars): clogger.error("number of input variables for operator %s is %d, which is inconsistent with " "script declaration : %s" % (s.name, len(invars), s.command)) return # TBD : check parameters number ( need to build # its list in cscript.init() ) if project not in derived_variables: derived_variables[project] = dict() clogger.debug("Add derive variable %s obtained with operator %s, output variable %s, input variables %s " "and parameters %s" % (derivedVar[outname], str(Operator), derivedVar[outname], str(list(invars)), str(params))) derived_variables[project][derivedVar[outname]] = (Operator, derivedVar[outname], list(invars), params) elif Operator in operators: clogger.warning("Cannot yet handle derived variables based on internal operators") else: clogger.error("second argument (%s) must be a script or operator, already declared" % repr(Operator))