From 3fa0e1ba9826cd89909bb757bf27cd9021c33028 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Keck <Jean-Baptiste.Keck@imag.fr> Date: Wed, 10 Apr 2019 17:06:25 +0200 Subject: [PATCH] opencl interpolation --- .../backend/device/opencl/opencl_symbolic.py | 140 +++++------------- .../opencl/operator/spatial_filtering.py | 28 +++- hysop/numerics/interpolation/polynomial.py | 6 +- hysop/symbolic/array.py | 18 ++- hysop/tools/sympy_utils.py | 36 +++-- 5 files changed, 100 insertions(+), 128 deletions(-) diff --git a/hysop/backend/device/opencl/opencl_symbolic.py b/hysop/backend/device/opencl/opencl_symbolic.py index f0939dca0..d0d414e62 100644 --- a/hysop/backend/device/opencl/opencl_symbolic.py +++ b/hysop/backend/device/opencl/opencl_symbolic.py @@ -9,9 +9,10 @@ expressions. used to provide a common interface to all discrete operators working with the opencl backend and using kernels generated on the fly from symbolic expressions. """ +import numpy as np from abc import ABCMeta from hysop.tools.decorators import debug -from hysop.tools.types import check_instance, first_not_None, InstanceOf +from hysop.tools.types import check_instance, first_not_None, InstanceOf, to_tuple from hysop.tools.numpywrappers import npw from hysop.fields.continuous_field import ScalarField, TensorField, Field from hysop.parameters.tensor_parameter import Parameter, TensorParameter @@ -80,124 +81,65 @@ class OpenClSymbolic(OpenClOperator): self.extra_kwds[name] = extra_kwds @classmethod - def symbolic_ndbuffers(cls, *names, **kwds): - from hysop.symbolic.array import OpenClSymbolicNdBuffer - buffers = () - if ('count' in kwds): - count = kwds.pop('count') + def __symbolic_variables(cls, *names, **kwds): + scls = kwds.pop('scls') + + arrays = () + shape = to_tuple(kwds.get('shape', kwds.get('count', ()))) + if shape: assert len(names)==1 - snames = tuple(names[0]+subscript(i) for i in xrange(count)) - varnames = tuple('{}{}'.format(names[0], i) for i in xrange(count)) - latexnames = tuple('{}_{{{}}}'.format(names[0], i) for i in xrange(count)) + snames = tuple(names[0]+subscripts(idx,',',disable_unicode=False) for idx in np.ndindex(*shape)) + var_names = tuple(names[0]+subscripts(idx,'_',disable_unicode=True) for idx in np.ndindex(*shape)) else: - snames = names - varnames = names - latexnames = names - for (name, pname, var_name, latex_name) in zip(varnames, snames, varnames, latexnames): + snames = names + var_names = names + shape = len(names) + for (name, pname, var_name) in zip(var_names, snames, var_names): assert ',' not in name check_instance(name, str) - buf = OpenClSymbolicNdBuffer(name=name, - pretty_name=pname, - var_name=var_name, - latex_name=latex_name, - memory_object=None, **kwds) - buffers += (buf,) - return buffers + arr = scls(name=name, pretty_name=pname, var_name=var_name, **kwds) + arrays += (arr,) + return np.asarray(arrays).reshape(shape) + + @classmethod + def symbolic_ndbuffers(cls, *names, **kwds): + from hysop.symbolic.array import OpenClSymbolicNdBuffer + assert 'memory_object' not in kwds + assert 'scls' not in kwds + kwds['memory_object'] = None + kwds['scls'] = OpenClSymbolicNdBuffer + return cls.__symbolic_variables(*names, **kwds) @classmethod def symbolic_buffers(cls, *names, **kwds): from hysop.symbolic.array import OpenClSymbolicBuffer - buffers = () - if ('count' in kwds): - count = kwds.pop('count') - assert len(names)==1 - snames = tuple(names[0]+subscript(i) for i in xrange(count)) - varnames = tuple('{}{}'.format(names[0], i) for i in xrange(count)) - latexnames = tuple('{}_{{{}}}'.format(names[0], i) for i in xrange(count)) - else: - snames = names - varnames = names - latexnames = names - for (name, pname, var_name, latex_name) in zip(varnames, snames, varnames, latexnames): - assert ',' not in name - check_instance(name, str) - buf = OpenClSymbolicBuffer(name=name, - pretty_name=pname, - var_name=var_name, - latex_name=latex_name, - memory_object=None, **kwds) - buffers += (buf,) - return buffers + assert 'memory_object' not in kwds + assert 'scls' not in kwds + kwds['memory_object'] = None + kwds['scls'] = OpenClSymbolicBuffer + return cls.__symbolic_variables(*names, **kwds) @classmethod def symbolic_arrays(cls, *names, **kwds): from hysop.symbolic.array import OpenClSymbolicArray - arrays = () - if ('count' in kwds): - count = kwds.pop('count') - assert len(names)==1 - snames = tuple(names[0]+subscript(i) for i in xrange(count)) - var_names = tuple('{}{}'.format(names[0], i) for i in xrange(count)) - latex_names = tuple('{}_{{{}}}'.format(names[0], i) for i in xrange(count)) - else: - snames = names - var_names = names - latex_names = names - for (name, pname, var_name, latex_name) in zip(var_names, snames, var_names, latex_names): - assert ',' not in name - check_instance(name, str) - arr = OpenClSymbolicArray(name=name, pretty_name=pname, - var_name=var_name, latex_name=latex_name, - memory_object=None, **kwds) - arrays += (arr,) - return arrays + assert 'memory_object' not in kwds + assert 'scls' not in kwds + kwds['scls'] = OpenClSymbolicArray + return cls.__symbolic_variables(*names, **kwds) @classmethod def symbolic_tmp_scalars(cls, *names, **kwds): from hysop.symbolic.tmp import TmpScalar - scalars = () - if ('count' in kwds): - count = kwds.pop('count') - assert len(names)==1 - snames = tuple(names[0]+subscript(i) for i in xrange(count)) - var_names = tuple('{}{}'.format(names[0], i) for i in xrange(count)) - latex_names = tuple('{}_{{{}}}'.format(names[0], i) for i in xrange(count)) - else: - snames = names - var_names = names - latex_names = names - for (name, pname, var_name, latex_name) in zip(var_names, snames, var_names, latex_names): - assert ',' not in name - check_instance(name, str) - tmp = TmpScalar(name=name, pretty_name=pname, - var_name=var_name, latex_name=latex_name, - **kwds) - scalars += (tmp,) - return scalars + assert 'scls' not in kwds + kwds['scls'] = TmpScalar + return cls.__symbolic_variables(*names, **kwds) @classmethod def symbolic_constants(cls, *names, **kwds): - # constants that may be specified up to the setup step from hysop.symbolic.constant import SymbolicConstant - constants = () - if ('count' in kwds): - count = kwds.pop('count') - assert len(names)==1 - snames = tuple(names[0]+subscript(i) for i in xrange(count)) - var_names = tuple('{}{}'.format(names[0], i) for i in xrange(count)) - latex_names = tuple('{}_{{{}}}'.format(names[0], i) for i in xrange(count)) - else: - snames = names - var_names = names - latex_names = names - for (name, pname, var_name, latex_name) in zip(var_names, snames, var_names, latex_names): - assert ',' not in name - check_instance(name, str) - tmp = SymbolicConstant(name=name, pretty_name=pname, - var_name=var_name, latex_name=latex_name, - **kwds) - constants += (tmp,) - return constants + assert 'scls' not in kwds + kwds['scls'] = SymbolicConstant + return cls.__symbolic_variables(*names, **kwds) @debug def handle_method(self, method): diff --git a/hysop/backend/device/opencl/operator/spatial_filtering.py b/hysop/backend/device/opencl/operator/spatial_filtering.py index 520b9f298..c01c11a2b 100644 --- a/hysop/backend/device/opencl/operator/spatial_filtering.py +++ b/hysop/backend/device/opencl/operator/spatial_filtering.py @@ -28,6 +28,7 @@ class OpenClPolynomialInterpolationFilter(PolynomialInterpolationFilterBase, Ope super(OpenClPolynomialInterpolationFilter, self).discretize() dFin = self.dFin dFout = self.dFout + gr = self.grid_ratio dim = dFin.dim assert dFin.is_scalar assert dFout.is_scalar @@ -35,24 +36,37 @@ class OpenClPolynomialInterpolationFilter(PolynomialInterpolationFilterBase, Ope ekg = self.elementwise_kernel_generator W = self.subgrid_interpolator.W s = self.subgrid_interpolator.s - gr = self.grid_ratio + n = (self.subgrid_interpolator.n,)*dim + ghosts = np.asarray((self.subgrid_interpolator.ghosts,)*dim) I = np.asarray(local_indices_symbols[:dim][::-1]) fin, fout = ekg.dfields_to_ndbuffers(dFin, dFout) + Fin = ekg.symbolic_tmp_scalars('F', shape=n, dtype=dFin.dtype) + Fout_values = W.dot(Fin.ravel()).reshape(s) exprs = () - for idx in np.ndindex(*s): - e = Assignment(fin(I+idx), fout(I+idx)) + for idx in np.ndindex(*n): + e = Assignment(Fin[idx], fin(I+idx-ghosts)) + exprs += (e,) + for idx in np.ndindex(*gr): + e = Assignment(fout(gr*I+idx), Fout_values[idx]) exprs += (e,) - ekg.elementwise_kernel('interpolate_grid', *exprs, - compute_resolution=dFin.compute_resolution, debug=True) - raise NotImplementedError + + interpolate_grid_kernel, _ = ekg.elementwise_kernel('interpolate_grid', + *exprs, compute_resolution=dFin.compute_resolution, debug=False) + exchange_ghosts = self.dFout.exchange_ghosts(build_launcher=True) + + kl = OpenClKernelListLauncher(name='lowpass_filter') + kl += interpolate_grid_kernel + kl += exchange_ghosts + + self.execute_kernels = functools.partial(kl, queue=self.cl_env.default_queue) @op_apply def apply(self, **kwds): super(OpenClPolynomialInterpolationFilter, self).apply(**kwds) - raise NotImplementedError + evt = self.execute_kernels() class OpenClSubgridRestrictionFilter(SubgridRestrictionFilterBase, OpenClSymbolic): diff --git a/hysop/numerics/interpolation/polynomial.py b/hysop/numerics/interpolation/polynomial.py index a57a2973a..8aa98499a 100644 --- a/hysop/numerics/interpolation/polynomial.py +++ b/hysop/numerics/interpolation/polynomial.py @@ -96,7 +96,7 @@ class PolynomialInterpolationMethod(SpaceDiscretizationMethod): Operator helper to handle polynomial interpolation method. """ __default_method = { - MultiScaleInterpolation: PolynomialInterpolation.CUBIC_FDC6, + MultiScaleInterpolation: PolynomialInterpolation.NONIC_FDC2, } __available_methods = { @@ -467,6 +467,8 @@ class PolynomialSubgridInterpolator(object): ---------- dim: int Number of dimensions to interpolate (same as interpolator.dim). + ghosts: int + Number of required ghosts. n: int Corresponds to 2*(ghosts+1), the number of required nodes to generate the polynomial coefficients (same as interpolator.n). @@ -519,6 +521,7 @@ class PolynomialSubgridInterpolator(object): P = interpolator.P n = interpolator.n N = interpolator.N + ghosts = interpolator.ghosts s = tuple(gr+1 for gr in grid_ratio) S = np.prod(s, dtype=np.int64) @@ -531,6 +534,7 @@ class PolynomialSubgridInterpolator(object): self.S = S self.n = n self.N = N + self.ghosts = interpolator.ghosts self.dim = dim self.interpolator = interpolator self.key = key diff --git a/hysop/symbolic/array.py b/hysop/symbolic/array.py index 9e99a8fe6..4c28c0765 100644 --- a/hysop/symbolic/array.py +++ b/hysop/symbolic/array.py @@ -192,7 +192,7 @@ class SymbolicBuffer(SymbolicMemoryObject): class SymbolicNdBuffer(SymbolicBuffer): """Same as a SymbolicBuffer, but with ndindex access and ghost support.""" - def __new__(cls, name, memory_object=None, dim=None, strides=None, ghosts=None, **kwds): + def __new__(cls, name, memory_object=None, dim=None, strides=None, dtype=None, ghosts=None, **kwds): obj = super(SymbolicNdBuffer, cls).__new__(cls, memory_object=memory_object, name=name, **kwds) msg='Dimension could not be deduced from memory_object, ' @@ -216,21 +216,25 @@ class SymbolicNdBuffer(SymbolicBuffer): pretty_name='g'+subscript(i), dtype=npw.int32) for i in xrange(dim)) obj._allow_update_symbolic_constants = True - obj.update_symbolic_constants(memory_object=memory_object, strides=strides, ghosts=ghosts, force=False) + obj.update_symbolic_constants(memory_object=memory_object, strides=strides, dtype=dtype, ghosts=ghosts, force=False) return obj - def bind_memory_object(self, memory_object, strides=None, ghosts=None, force=False, **kwds): + def bind_memory_object(self, memory_object, strides=None, dtype=None, ghosts=None, force=False, **kwds): super(SymbolicNdBuffer, self).bind_memory_object(memory_object=memory_object, force=force, **kwds) - self.update_symbolic_constants(memory_object=memory_object, strides=strides, ghosts=ghosts, force=force) + self.update_symbolic_constants(memory_object=memory_object, strides=strides, dtype=dtype, ghosts=ghosts, force=force) - def update_symbolic_constants(self, memory_object, strides, ghosts, force): + def update_symbolic_constants(self, memory_object, strides, dtype, ghosts, force): if hasattr(self, '_allow_update_symbolic_constants') and self._allow_update_symbolic_constants: - strides = first_not_None(strides, getattr(memory_object, 'strides', None)) + strides = first_not_None(strides, getattr(memory_object, 'strides', None)) + dtype = first_not_None(dtype, getattr(memory_object, 'dtype', None)) assert (strides is not None), 'Could not determine strides from memory_object.' + assert (dtype is not None), 'Could not determine dtype from memory_object.' + itemsize = dtype.itemsize strides = to_tuple(strides) check_instance(strides, tuple, values=(int,long), size=self._dim) for ss,si in zip(self._symbolic_strides, strides): - ss.bind_value(si, force=force) + assert si%itemsize == 0 + ss.bind_value(si//itemsize, force=force) ghosts = first_not_None(ghosts, getattr(memory_object, 'ghosts', None)) assert (ghosts is not None), 'Could not determine ghosts from memory_object.' diff --git a/hysop/tools/sympy_utils.py b/hysop/tools/sympy_utils.py index 6e4634f3c..d656de1e4 100644 --- a/hysop/tools/sympy_utils.py +++ b/hysop/tools/sympy_utils.py @@ -154,7 +154,7 @@ class AppliedUndef(sm.function.AppliedUndef): #return '{}({})'.format(self._pretty_name, #','.join(printer._print(a) for a in self.args)) -def subscript(i, with_sign=False): +def subscript(i, with_sign=False, disable_unicode=False): """ Generate an unicode subscript of value i, signs can be enforced. """ @@ -164,16 +164,19 @@ def subscript(i, with_sign=False): s0 = snumber[0] if s0 in decimals: snumber = '+'+snumber - out = u'' - for s in snumber: - if s in decimals: - out += decimal_subscripts[int(s)] - elif s=='+': - out += signs[0] - elif s=='-': - out += signs[1] - else: - out += s + if disable_unicode: + out = snumber + else: + out =u'' + for s in snumber: + if s in decimals: + out += decimal_subscripts[int(s)] + elif s=='+': + out += signs[0] + elif s=='-': + out += signs[1] + else: + out += s return out def exponent(i, with_sign=False): @@ -198,16 +201,21 @@ def exponent(i, with_sign=False): out += s return out -def subscripts(ids,sep,with_sign=False,with_parenthesis=False,prefix=''): +def subscripts(ids,sep,with_sign=False,with_parenthesis=False,prefix='',disable_unicode=False): """ Generate a unicode tuple subscript separated by sep, with or without parenthesis, prefix, and signs. """ ids = to_tuple(ids) if with_parenthesis: - return u'{}{}{}{}'.format(prefix,parenthesis[0],sep.join([subscript(i,with_sign) for i in ids]),parenthesis[1]) + lparen = '(' if disable_unicode else parenthesis[0] + rparen = ')' if disable_unicode else parenthesis[1] + base = '{}{}{}{}' if disable_unicode else u'{}{}{}{}' + return base.format(prefix,lparen,sep.join([subscript(i,with_sign,disable_unicode) + for i in ids]),rparen) else: - return u'{}{}'.format(prefix,sep.join([subscript(i,with_sign) for i in ids])) + base = '{}{}' if disable_unicode else u'{}{}' + return base.format(prefix,sep.join([subscript(i,with_sign,disable_unicode) for i in ids])) def exponents(ids,sep,with_sign=False,with_parenthesis=False,prefix=''): """ -- GitLab