def smooth(f, g, axis=None): """ Smooth a Function through simple moving average. Parameters ---------- f : Function The left-hand side of the smoothing kernel, that is the smoothed Function. g : Function The right-hand side of the smoothing kernel, that is the Function being smoothed. axis : Dimension or list of Dimensions, optional The Dimension along which the smoothing operation is performed. Defaults to ``f``'s innermost Dimension. Notes ----- More info about simple moving average available at: :: https://en.wikipedia.org/wiki/Moving_average#Simple_moving_average """ if g.is_Constant: # Return a scaled version of the input if it's a Constant f.data[:] = .9 * g.data else: if axis is None: axis = g.dimensions[-1] dv.Operator(dv.Eq(f, g.avg(dims=axis)), name='smoother')()
def norm(f, order=2): """ Compute the norm of a Function. Parameters ---------- f : Function Input Function. order : int, optional The order of the norm. Defaults to 2. """ kwargs = {} if f.is_TimeFunction and f._time_buffering: kwargs[f.time_dim.max_name] = f._time_size - 1 # Protect SparseFunctions from accessing duplicated (out-of-domain) data, # otherwise we would eventually be summing more than expected p, eqns = f.guard() if f.is_SparseFunction else (f, []) with MPIReduction(f) as mr: op = dv.Operator(eqns + [dv.Inc(mr.n[0], Abs(Pow(p, order)))], name='norm%d' % order) op.apply(**kwargs) v = Pow(mr.v, 1 / order) return np.float(v)
def sumall(f): """ Compute the sum of all Function data. Parameters ---------- f : Function Input Function. """ kwargs = {} if f.is_TimeFunction and f._time_buffering: kwargs[f.time_dim.max_name] = f._time_size - 1 # Protect SparseFunctions from accessing duplicated (out-of-domain) data, # otherwise we would eventually be summing more than expected p, eqns = f.guard() if f.is_SparseFunction else (f, []) s = dv.types.Scalar(name='sum', dtype=f.dtype) with MPIReduction(f) as mr: op = dv.Operator([dv.Eq(s, 0.0)] + eqns + [dv.Inc(s, p), dv.Eq(mr.n[0], s)], name='sum') op.apply(**kwargs) return f.dtype(mr.v)
def first_touch(array): """Uses the Propagator low-level API to initialize the given array(in Devito types) in the same pattern that would later be used to access it. """ exp_init = [Eq(array.indexed[array.indices], 0)] op = devito.Operator(exp_init) op.apply()
def assign(f, rhs=0, options=None, name='assign', **kwargs): """ Assign a list of RHSs to a list of Functions. Parameters ---------- f : Function or list of Functions The left-hand side of the assignment. rhs : expr-like or list of expr-like, optional The right-hand side of the assignment. options : dict or list of dict, optional Dictionary or list (of len(f)) of dictionaries containing optional arguments to be passed to Eq. name : str, optional Name of the operator. Examples -------- >>> from devito import Grid, Function, assign >>> grid = Grid(shape=(4, 4)) >>> f = Function(name='f', grid=grid, dtype=np.int32) >>> g = Function(name='g', grid=grid, dtype=np.int32) >>> h = Function(name='h', grid=grid, dtype=np.int32) >>> functions = [f, g, h] >>> scalars = [1, 2, 3] >>> assign(functions, scalars) >>> f.data Data([[1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1], [1, 1, 1, 1]], dtype=int32) >>> g.data Data([[2, 2, 2, 2], [2, 2, 2, 2], [2, 2, 2, 2], [2, 2, 2, 2]], dtype=int32) >>> h.data Data([[3, 3, 3, 3], [3, 3, 3, 3], [3, 3, 3, 3], [3, 3, 3, 3]], dtype=int32) """ if not isinstance(rhs, list): rhs = len(as_list(f)) * [ rhs, ] eqs = [] if options: for i, j, k in zip(as_list(f), rhs, options): if k is not None: eqs.append(dv.Eq(i, j, **k)) else: eqs.append(dv.Eq(i, j)) else: for i, j in zip(as_list(f), rhs): eqs.append(dv.Eq(i, j)) dv.Operator(eqs, name=name, **kwargs)()
def assign(f, v=0): """ Assign a value to a Function. Parameters ---------- f : Function The left-hand side of the assignment. v : scalar, optional The right-hand side of the assignment. """ dv.Operator(dv.Eq(f, v), name='assign')()
def inner(f, g): """ Inner product of two Functions. Parameters ---------- f : Function First input operand g : Function Second input operand Raises ------ ValueError If the two input Functions are defined over different grids, or have different dimensionality, or their dimension-wise sizes don't match. If in input are two SparseFunctions and their coordinates don't match, the exception is raised. Notes ----- The inner product is the sum of all dimension-wise products. For 1D Functions, the inner product corresponds to the dot product. """ # Input check if f.is_TimeFunction and f._time_buffering != g._time_buffering: raise ValueError( "Cannot compute `inner` between save/nosave TimeFunctions") if f.shape != g.shape: raise ValueError("`f` and `g` must have same shape") if f._data is None or g._data is None: raise ValueError("Uninitialized input") if f.is_SparseFunction and not np.all( f.coordinates_data == g.coordinates_data): raise ValueError("Non-matching coordinates") kwargs = {} if f.is_TimeFunction and f._time_buffering: kwargs[f.time_dim.max_name] = f._time_size - 1 # Protect SparseFunctions from accessing duplicated (out-of-domain) data, # otherwise we would eventually be summing more than expected rhs, eqns = f.guard(f * g) if f.is_SparseFunction else (f * g, []) s = dv.types.Scalar(name='sum', dtype=f.dtype) with MPIReduction(f, g) as mr: op = dv.Operator([dv.Eq(s, 0.0)] + eqns + [dv.Inc(s, rhs), dv.Eq(mr.n[0], s)], name='inner') op.apply(**kwargs) return f.dtype(mr.v)
def sumall(f): """ Compute the sum of the values in a :class:`Function`. Parameters ---------- f : Function Input Function. """ kwargs = {} if f.is_TimeFunction and f._time_buffering: kwargs[f.time_dim.max_name] = f._time_size - 1 # Protect SparseFunctions from accessing duplicated (out-of-domain) data, # otherwise we would eventually be summing more than expected p, eqns = f.guard() if f.is_SparseFunction else (f, []) with MPIReduction(f) as mr: op = dv.Operator(eqns + [dv.Inc(mr.n[0], p)], name='sum') op.apply(**kwargs) return np.float(mr.v)
def first_touch(array): """ Uses an Operator to initialize the given array in the same pattern that would later be used to access it. """ devito.Operator(Eq(array, 0.))()