Source code for underworld.function.misc

##~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~##
##                                                                                   ##
##  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.                             ##
##                                                                                   ##
##~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~#~##
"""
Miscellaneous functions.
"""
import underworld.libUnderworld.libUnderworldPy.Function as _cfn
from ._function import Function as _Function

[docs]class constant(_Function): """ This function returns a constant value. Parameters ---------- value: int,float,bool, iterable The value the function should return. Note that iterable objects which contain valid types are permitted, but must be homogeneous in their type. Example ------- >>> import underworld as uw >>> import underworld.function as fn >>> fn_const = fn.misc.constant( 3 ) >>> fn_const.evaluate(0.) # eval anywhere for constant array([[3]], dtype=int32) >>> fn_const = fn.misc.constant( (3,2,1) ) >>> fn_const.evaluate(0.) # eval anywhere for constant array([[3, 2, 1]], dtype=int32) >>> fn_const = fn.misc.constant( 3. ) >>> fn_const.evaluate(0.) # eval anywhere for constant array([[ 3.]]) >>> fn_const = fn.misc.constant( (3.,2.,1.) ) >>> fn_const.evaluate(0.) # eval anywhere for constant array([[ 3., 2., 1.]]) >>> fn_const = fn.misc.constant( True ) >>> fn_const.evaluate(0.) # eval anywhere for constant array([[ True]], dtype=bool) >>> fn_const = fn.misc.constant( (True,False,True) ) >>> fn_const.evaluate(0.) # eval anywhere for constant array([[ True, False, True]], dtype=bool) """ def __init__(self, value, *args, **kwargs): # lets try and convert self._ioguy = self._GetIOForPyInput(value) self._value = value self._fncself = _cfn.Constant(self._ioguy) # build parent super(constant,self).__init__(argument_fns=None,**kwargs) @property def value(self): """ value: constant value this function returns """ return self._value @value.setter def value(self,value): newioguy = self._GetIOForPyInput(value) if not isinstance(newioguy,type(self._ioguy)): raise TypeError("'value' object passed in must be of identical type to that used in construction of this function.") if newioguy.size() != self._ioguy.size(): raise TypeError("'value' object passed in must be of identical size to that used in construction of this function.") self._ioguy = newioguy self._fncself.set_value(self._ioguy) self._value = value def _GetIOForPyInput(self, value): if isinstance(value, (int,float,bool) ): if isinstance(value,bool): ioguy = _cfn.IO_bool(1,_cfn.FunctionIO.Scalar) elif isinstance(value, int): ioguy = _cfn.IO_int(1,_cfn.FunctionIO.Scalar) elif isinstance(value,float): ioguy = _cfn.IO_double(1,_cfn.FunctionIO.Scalar) else: raise RuntimeError("Failure during object creation. Please contact developers.") # now set val ioguy.value(value,0) else: try: iterator = iter(value) except TypeError: raise ValueError("'value' object provided to Constant Function constructor does not appear to be valid. " +"Only python types 'int', 'float' and 'bool' are acceptable, or iterable objects " +"homogeneous in these types. Provided object was of type '{}'.".format(value.__class__.__name__) ) else: # iterable tupleGuy = tuple(iterator) try: lenTupleGuy = len(tupleGuy) except: raise ValueError("'value' object provided to Constant function appears to be an iterable, but " +"does not appear to have a known length.") if lenTupleGuy == 0: raise ValueError("'value' object provided to Constant function appears to be an iterable, but " +"seems to be of zero size. Iterable values must be of non-zero size.") firstFella = tupleGuy[0] if isinstance(firstFella,bool): ioguy = _cfn.IO_bool(lenTupleGuy,_cfn.FunctionIO.Array) elif isinstance(firstFella, int): ioguy = _cfn.IO_int(lenTupleGuy,_cfn.FunctionIO.Array) elif isinstance(firstFella,float): ioguy = _cfn.IO_double(lenTupleGuy,_cfn.FunctionIO.Array) else: raise ValueError("'value' object provided to Constant function appears to be an iterable, but " +"does not appear to contain objects of python type 'int', 'float' or 'bool'.") # right, now load in ze data ii = 0 for val in tupleGuy: if not isinstance(val,type(firstFella)): raise ValueError("'value' object provided to Constant function appears to be an iterable, but " +"does not appear to be homogeneous in type. Objects in iterable must all be " +"of python type 'int', 'float' or 'bool'.") ioguy.value(val,ii) ii+=1; return ioguy
[docs]class max(_Function): """ Returns the maximum of the results returned from its two argument function. Parameters ---------- fn1: underworld.function.Function First argument function. Function must return a float type. fn2: underworld.function.Function Second argument function. Function must return a float type. Example ------- >>> import underworld as uw >>> import underworld.function as fn >>> import numpy as np >>> testpoints = np.array(([[ 0.0], [0.2], [0.4], [0.6], [0.8], [1.01], [1.2], [1.4], [1.6], [1.8], [2.0],])) Create which return identical results via different paths: >>> fn_x = fn.input()[0] >>> fn_x_minus_one = fn_x - 1. >>> fn_one_minus_x = 1. - fn_x Here we use 'max' and 'min' functions: >>> fn_max = fn.misc.max(fn_one_minus_x,fn_x_minus_one) >>> fn_min = fn.misc.min(fn_one_minus_x,fn_x_minus_one) Here we use the conditional functions: >>> fn_conditional_max = fn.branching.conditional( ( ( fn_x <= 1., fn_one_minus_x ), ( fn_x > 1., fn_x_minus_one ) )) >>> fn_conditional_min = fn.branching.conditional( ( ( fn_x >= 1., fn_one_minus_x ), ( fn_x < 1., fn_x_minus_one ) )) They should return identical results: >>> np.allclose(fn_max.evaluate(testpoints),fn_conditional_max.evaluate(testpoints)) True >>> np.allclose(fn_min.evaluate(testpoints),fn_conditional_min.evaluate(testpoints)) True """ def __init__(self, fn1, fn2, **kwargs): fn1fn = _Function.convert( fn1 ) if not isinstance( fn1fn, _Function ): raise TypeError("Functions must be of type (or convertible to) 'Function'.") fn2fn = _Function.convert( fn2 ) if not isinstance( fn2fn, _Function ): raise TypeError("Functions must be of type (or convertible to) 'Function'.") self._fn1 = fn1fn self._fn2 = fn2fn # ok finally lets create the fn self._fncself = _cfn.Max(self._fn1._fncself, self._fn2._fncself ) # build parent super(max,self).__init__(argument_fns=[fn1fn,fn2fn],**kwargs)
[docs]class min(_Function): """ Returns the minimum of the results returned from its two argument function. Parameters ---------- fn1: underworld.function.Function First argument function. Function must return a float type. fn2: underworld.function.Function Second argument function. Function must return a float type. Example ------- See the example provided for 'max' function. """ def __init__(self, fn1, fn2, **kwargs): fn1fn = _Function.convert( fn1 ) if not isinstance( fn1fn, _Function ): raise TypeError("Functions must be of type (or convertible to) 'Function'.") fn2fn = _Function.convert( fn2 ) if not isinstance( fn2fn, _Function ): raise TypeError("Functions must be of type (or convertible to) 'Function'.") self._fn1 = fn1fn self._fn2 = fn2fn # ok finally lets create the fn self._fncself = _cfn.Min(self._fn1._fncself, self._fn2._fncself ) # build parent super(min,self).__init__(argument_fns=[fn1fn,fn2fn],**kwargs)