Source code for underworld.function.exception

##~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~##
##                                                                                   ##
##  This file forms part of the Underworld geophysics modelling application.         ##
##                                                                                   ##
##  For full license and copyright information, please refer to the LICENSE.md file  ##
##  located at the project root, or contact the authors.                             ##
##                                                                                   ##
##~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~##
"""
This module provides functions which raise an exception when given conditions
are encountered during function evaluations. Exception functions never modify
query data.
"""

import underworld.libUnderworld.libUnderworldPy.Function as _cfn
from ._function import Function as _Function

[docs]class SafeMaths(_Function): """ This function checks if any of the following have been encountered during the evaluation of its argument function: * Divide by zero * Invalid domain was used for evaluation * Value overflow errors * Value underflow errors If any of the above are encountered, an exception is thrown at the conclusion of the argument function evaluation. Parameters ---------- fn: underworld.function.Function The function that is subject to the testing. Example ------- >>> import underworld as uw >>> import underworld.function as fn >>> one = fn.misc.constant(1.) >>> zero = fn.misc.constant(0.) >>> fn_dividebyzero = one/zero >>> safedividebyzero = fn.exception.SafeMaths(fn_dividebyzero) >>> safedividebyzero.evaluate() Traceback (most recent call last): ... RuntimeError: Issue utilising function of class 'SafeMaths' constructed at: <BLANKLINE> --- CONSTRUCTION TIME STACK --- Error message: Floating point exception(s) encountered while evaluating SafeMaths argument function: Divide by zero """ def __init__(self, fn, *args, **kwargs): _fn = _Function.convert(fn) if _fn == None: raise ValueError( "provided 'fn' must a 'Function' or convertible.") self._fn = _fn # create instance self._fncself = _cfn.SafeMaths( self._fn._fncself ) # build parent super(SafeMaths,self).__init__(argument_fns=[_fn,],**kwargs)
[docs]class CustomException(_Function): """ This function allows you to set custom exceptions within your model. You must pass it two functions: the first function is the pass through function, the second function is the required condition. You may also pass in a optional third function whose output will be printed if the condition evaluates to False. A CustomException function will perform the following logic: 1. Evaluate the condition function. 2. If it evaluates to False, an exception is thrown and the simulation is halted. If a print function is provided, it will be evaluated and its results will be included in the exception message. 3. If it evaluates to True, the pass through function is evaluated with the result then being return. Parameters ---------- fn_passthrough: underworld.function.Function The pass through function fn_condition: underworld.function.Function The condition function fn_print: underworld.function.Function The print function (optional). Example ------- >>> import underworld as uw >>> import underworld.function as fn >>> one = fn.misc.constant(1.) >>> passing_one = fn.exception.CustomException( one, (one < 2.) ) >>> passing_one.evaluate() array([[ 1.]]) >>> failing_one = fn.exception.CustomException( one, (one > 2.) ) >>> failing_one.evaluate() Traceback (most recent call last): ... RuntimeError: Issue utilising function of class 'CustomException' constructed at: <BLANKLINE> --- CONSTRUCTION TIME STACK --- Error message: CustomException condition function has evaluated to False for current input! Now with printing >>> failing_one_by_five = fn.exception.CustomException( one, (one*5. > 20.), one*5. ) >>> failing_one_by_five.evaluate() Traceback (most recent call last): ... RuntimeError: Issue utilising function of class 'CustomException' constructed at: <BLANKLINE> --- CONSTRUCTION TIME STACK --- Error message: CustomException condition function has evaluated to False for current input! Print function returns the following values (cast to double precision): ( 5 ) """ def __init__(self, fn_input, fn_condition, fn_print=None, *args, **kwargs): _fn_input = _Function.convert(fn_input) if _fn_input == None: raise ValueError( "provided 'fn_input' must a 'Function' or convertible.") self._fn_input = _fn_input _fn_condition = _Function.convert(fn_condition) if _fn_condition == None: raise ValueError( "provided 'fn_condition' must a 'Function' or convertible.") self._fn_condition = _fn_condition if fn_print != None: _fn_print = _Function.convert(fn_print) if _fn_print == None: raise ValueError( "provided 'fn_print' must a 'Function' or convertible.") self._fn_print = _fn_print # create instance if not fn_print: self._fncself = _cfn.CustomException( self._fn_input._fncself, self._fn_condition._fncself ) else: self._fncself = _cfn.CustomException( self._fn_input._fncself, self._fn_condition._fncself, self._fn_print._fncself ) # build parent # note that we only pass in _fn_input as the argument_fns, as _fn_condition & _fn_print are # not dynamically relevant... it is only used for performing the exception check. super(CustomException,self).__init__(argument_fns=[_fn_input,],**kwargs)