def putdefault(self, grid): """ Derive a key ``K`` from the :class:`Grid` ``grid``; if ``K`` in ``self``, return the existing :class:`YaskContext` ``self[K]``, otherwise create a new context ``C``, set ``self[K] = C`` and return ``C``. """ assert grid is not None key = self._getkey(grid, grid.dtype) # Does a YaskContext exist already corresponding to this key? if key in self: return self[key] # Functions declared with explicit dimensions (i.e., with no Grid) must be # able to retrieve the right context partial_keys = [ self._getkey(None, grid.dtype, i) for i in powerset(key[-1]) ] if any(i in self._partial_map for i in partial_keys if i[2]): warning( "Non-unique Dimensions found in different contexts; dumping " "all known contexts. Perhaps you're attempting to use multiple " "Grids, and some of them share identical Dimensions? ") self.dump() # Create a new YaskContext context = YaskContext('ctx%d' % self._ncontexts, grid) self._ncontexts += 1 self[key] = context self._partial_map.update({i: context for i in partial_keys}) log("Context successfully created!")
def guard(clusters): """ Return a new :class:`ClusterGroup` including new :class:`PartialCluster`s for each conditional expression encountered in ``clusters``. """ processed = ClusterGroup() for c in clusters: # Find out what expressions in /c/ should be guarded mapper = {} for e in c.exprs: for k, v in e.ispace.sub_iterators.items(): for i in v: if i.dim.is_Conditional: mapper.setdefault(i.dim, []).append(e) # Build conditional expressions to guard clusters conditions = {d: CondEq(d.parent % d.factor, 0) for d in mapper} negated = {d: CondNe(d.parent % d.factor, 0) for d in mapper} # Expand with guarded clusters combs = list(powerset(mapper)) for dims, ndims in zip(combs, reversed(combs)): banned = flatten(v for k, v in mapper.items() if k not in dims) exprs = [ e.xreplace({i: IntDiv(i.parent, i.factor) for i in mapper}) for e in c.exprs if e not in banned ] guards = [(i.parent, conditions[i]) for i in dims] guards.extend([(i.parent, negated[i]) for i in ndims]) cluster = PartialCluster(exprs, c.ispace, c.dspace, c.atomics, dict(guards)) processed.append(cluster) return processed
def putdefault(self, grid): """ Derive a unique key ``K`` from a Grid`; if ``K`` is in ``self``, return the pre-existing YaskContext ``self[K]``, otherwise create a new context ``C``, set ``self[K] = C`` and return ``C``. """ assert grid is not None key = self._getkey(grid, grid.dtype) # Does a YaskContext exist already corresponding to this key? if key in self: return self[key] # Functions declared with explicit dimensions (i.e., with no Grid) must be # able to retrieve the right context partial_keys = [self._getkey(None, grid.dtype, i) for i in powerset(key[-1])] if any(i in self._partial_map for i in partial_keys if i[2]): warning("Non-unique Dimensions found in different contexts; dumping " "all known contexts. Perhaps you're attempting to use multiple " "Grids, and some of them share identical Dimensions? ") self.dump() # Create a new YaskContext context = YaskContext('ctx%d' % self._ncontexts, grid) self._ncontexts += 1 self[key] = context self._partial_map.update({i: context for i in partial_keys}) log("Context successfully created!")
def _interpolation_coeffs(self): """ Symbolic expression for the coefficients for sparse point interpolation according to: https://en.wikipedia.org/wiki/Bilinear_interpolation. Returns ------- Matrix of coefficient expressions. """ # Grid indices corresponding to the corners of the cell ie x1, y1, z1 indices1 = tuple( sympy.symbols('%s1' % d) for d in self.grid.dimensions) indices2 = tuple( sympy.symbols('%s2' % d) for d in self.grid.dimensions) # 1, x1, y1, z1, x1*y1, ... indices = list(powerset(indices1)) indices[0] = (1, ) point_sym = list(powerset(self._point_symbols)) point_sym[0] = (1, ) # 1, px. py, pz, px*py, ... A = [] ref_A = [np.prod(ind) for ind in indices] # Create the matrix with the same increment order as the point increment for i in self._point_increments: # substitute x1 by x2 if increment in that dimension subs = dict( (indices1[d], indices2[d] if i[d] == 1 else indices1[d]) for d in range(len(i))) A += [[1] + [a.subs(subs) for a in ref_A[1:]]] A = sympy.Matrix(A) # Coordinate values of the sparse point p = sympy.Matrix([[np.prod(ind)] for ind in point_sym]) # reference cell x1:0, x2:h_x left = dict((a, 0) for a in indices1) right = dict( (b, dim.spacing) for b, dim in zip(indices2, self.grid.dimensions)) reference_cell = {**left, **right} # Substitute in interpolation matrix A = A.subs(reference_cell) return A.inv().T * p
def test_indices(ndim): """ Test that inidces are shifted by half a grid point for staggered Function """ grid = Grid(tuple([10] * ndim)) dims = grid.dimensions for d in list(powerset(dims))[1:]: f = Function(name="f", grid=grid, staggered=d) for dd in d: assert f.indices_ref[dd] == dd + dd.spacing / 2
def _interpolation_coeffs(self): """ Symbolic expression for the coefficients for sparse point interpolation according to: https://en.wikipedia.org/wiki/Bilinear_interpolation. Returns ------- Matrix of coefficient expressions. """ # Grid indices corresponding to the corners of the cell ie x1, y1, z1 indices1 = tuple(sympy.symbols('%s1' % d) for d in self.grid.dimensions) indices2 = tuple(sympy.symbols('%s2' % d) for d in self.grid.dimensions) # 1, x1, y1, z1, x1*y1, ... indices = list(powerset(indices1)) indices[0] = (1,) point_sym = list(powerset(self._point_symbols)) point_sym[0] = (1,) # 1, px. py, pz, px*py, ... A = [] ref_A = [np.prod(ind) for ind in indices] # Create the matrix with the same increment order as the point increment for i in self._point_increments: # substitute x1 by x2 if increment in that dimension subs = dict((indices1[d], indices2[d] if i[d] == 1 else indices1[d]) for d in range(len(i))) A += [[1] + [a.subs(subs) for a in ref_A[1:]]] A = sympy.Matrix(A) # Coordinate values of the sparse point p = sympy.Matrix([[np.prod(ind)] for ind in point_sym]) # reference cell x1:0, x2:h_x left = dict((a, 0) for a in indices1) right = dict((b, dim.spacing) for b, dim in zip(indices2, self.grid.dimensions)) reference_cell = {**left, **right} # Substitute in interpolation matrix A = A.subs(reference_cell) return A.inv().T * p
def test_is_param(ndim): """ Test that only parameter are evaluated at the variable anf Function and FD indices stay unchanged """ grid = Grid(tuple([10] * ndim)) dims = list(powerset(grid.dimensions))[1:] var = Function(name="f", grid=grid, staggered=NODE) for d in dims: f = Function(name="f", grid=grid, staggered=d) f2 = Function(name="f2", grid=grid, staggered=d, parameter=True) # Not a parameter stay untouched (or FD would be destroyed by _eval_at) assert f._eval_at(var).evaluate == f # Parameter, automatic averaging avg = f2 for dd in d: avg = .5 * (avg + avg.subs({dd: dd - dd.spacing})) assert f2._eval_at(var).evaluate == avg
def test_avg(ndim): """ Test automatic averaging of Function at undefined grid points """ grid = Grid(tuple([10] * ndim)) dims = list(powerset(grid.dimensions))[1:] for d in dims: f = Function(name="f", grid=grid, staggered=d) # f at nod (x, y, z) shifted = f for dd in d: shifted = shifted.subs({dd: dd - dd.spacing / 2}) assert all(i == dd for i, dd in zip(shifted.indices, grid.dimensions)) # Average automatically i.e.: # f not defined at x so f(x, y) = 0.5*f(x - h_x/2, y) + 0.5*f(x + h_x/2, y) avg = f for dd in d: avg = .5 * (avg + avg.subs({dd: dd - dd.spacing})) assert shifted.evaluate == avg