def _functionio_for_numpy(self, function_io_guy): """ This method simply takes a swig proxy to a FunctionIO, and returns the data as a numpy array. """ # create input function just so we can process using query inputfn = _function.input() # create function_io iterator func_io_it = _cfn.FunctionIOIter(function_io_guy) # process return _cfn.Query(inputfn._fncself).query(func_io_it)
def evaluate(self,inputData=None,inputType=None): """ This method performs evaluate of a function at the given input(s). It accepts floats, lists, tuples, numpy arrays, or any object which is of class `FunctionInput`. lists/tuples must contain floats only. `FunctionInput` class objects are shortcuts to their underlying data, often with performance advantages, and sometimes they are the only valid input type (such as using `Swarm` objects as an inputs to `SwarmVariable` evaluation). Objects of class `FeMesh`, `Swarm`, `FeMesh_IndexSet` and `VoronoiIntegrationSwarm` are also of class `FunctionInput`. See the Function section of the user guide for more information. Results are returned as numpy array. Parameters ---------- inputData: float, list, tuple, ndarray, underworld.function.FunctionInput The input to the function. The form of this input must be appropriate for the function being evaluated, or an exception will be thrown. Note that if no input is provided, function will be evaluated at `0.` inputType: str Specifies the type the provided data represents. Acceptable values are 'scalar', 'vector', 'symmetrictensor', 'tensor', 'array'. Returns ------- ndarray: array of results Examples -------- >>> import math as sysmath >>> import underworld.function.math as fnmath >>> sinfn = fnmath.sin() Single evaluation: >>> np.allclose( sinfn.evaluate(sysmath.pi/4.), [[ 0.5*sysmath.sqrt(2.)]] ) True Multiple evaluations >>> input = (0.,sysmath.pi/4.,2.*sysmath.pi) >>> np.allclose( sinfn.evaluate(input), [[ 0., 0.5*sysmath.sqrt(2.), 0.]] ) True Single MeshVariable evaluations >>> mesh = uw.mesh.FeMesh_Cartesian() >>> var = uw.mesh.MeshVariable(mesh,1) >>> import numpy as np >>> var.data[:,0] = np.linspace(0,1,len(var.data)) >>> result = var.evaluate( (0.2,0.5 ) ) >>> np.allclose( result, np.array([[ 0.45]]) ) True Numpy input MeshVariable evaluation >>> # evaluate at a set of locations.. provide these as a numpy array. >>> count = 10 >>> # create an empty array >>> locations = np.zeros( (count,2)) >>> # specify evaluation coodinates >>> locations[:,0] = 0.5 >>> locations[:,1] = np.linspace(0.,1.,count) >>> # evaluate >>> result = var.evaluate(locations) >>> np.allclose( result, np.array([[ 0.08333333], \ [ 0.17592593], \ [ 0.26851852], \ [ 0.36111111], \ [ 0.4537037 ], \ [ 0.5462963 ], \ [ 0.63888889], \ [ 0.73148148], \ [ 0.82407407], \ [ 0.91666667]]) ) True Using the mesh object as a FunctionInput >>> np.allclose( var.evaluate(mesh), var.evaluate(mesh.data)) True Also note that if evaluating across an empty input, an empty output is returned. Note that the shape and type of the output is always fixed and may differ from the shape/type returned for an actual (non-empty) evaluation. Usually this should not be an issue. >>> var.evaluate(np.zeros((0,2))) array([], shape=(0, 1), dtype=float64) >>> var.evaluate(mesh.specialSets["Empty"]) array([], shape=(0, 1), dtype=float64) """ if inputData is None: inputData = 0. if inputType != None and inputType not in types.keys(): raise ValueError("Provided input type does not appear to be valid.") if isinstance(inputData, FunctionInput): if inputType != None: raise ValueError("'inputType' specification not supported for this input class.") return _cfn.Query(self._fncself).query(inputData._get_iterator()) elif isinstance(inputData, np.ndarray): if inputType != None: if inputType == ScalarType: if inputData.shape[1] != 1: raise ValueError("You have specified ScalarType input, but your input size is {}.\n".format(inputData.shape[1]) \ +"ScalarType inputs must be of size 1.") if inputType == VectorType: if inputData.shape[1] not in (2,3): raise ValueError("You have specified VectorType input, but your input size is {}.\n".format(inputData.shape[1]) \ +"VectorType inputs must be of size 2 or 3 (for 2d or 3d).") if inputType == SymmetricTensorType: if inputData.shape[1] not in (3,6): raise ValueError("You have specified SymmetricTensorType input, but your input size is {}.\n".format(inputData.shape[1]) \ +"SymmetricTensorType inputs must be of size 3 or 6 (for 2d or 3d).") if inputType == TensorType: if inputData.shape[1] not in (4,9): raise ValueError("You have specified TensorType input, but your input size is {}.\n".format(inputData.shape[1]) \ +"TensorType inputs must be of size 4 or 9 (for 2d or 3d).") else: inputType = ArrayType # lets check if this array owns its data.. process directly if it does, otherwise take a copy.. # this is to avoid a bug in the way we parse non-trivial numpy arrays. will fix in future. #152 # Note, we also added the check for 'F_CONTIGUOUS' as we also don't handle this correctly it seems. if (not (inputData.base is None)) or inputData.flags['F_CONTIGUOUS']: inputData = inputData.copy() return _cfn.Query(self._fncself).query(_cfn.NumpyInput(inputData,inputType)) else: # try convert and recurse return self.evaluate( self._evaluate_data_convert_to_ndarray(inputData), inputType )