From 074350c93adbf3070cfc329ebf344b70fdee3f74 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Keck <Jean-Baptiste.Keck@imag.fr> Date: Fri, 12 Apr 2019 11:05:29 +0200 Subject: [PATCH] working polynomial filters --- examples/multiresolution/scalar_advection.py | 15 ++- .../opencl/operator/spatial_filtering.py | 52 +++++++- .../host/python/operator/spatial_filtering.py | 38 +++++- hysop/numerics/interpolation/polynomial.py | 111 +++++++++++++----- hysop/operator/base/spatial_filtering.py | 35 +++++- hysop/operator/spatial_filtering.py | 29 +++-- hysop/symbolic/array.py | 3 +- 7 files changed, 229 insertions(+), 54 deletions(-) diff --git a/examples/multiresolution/scalar_advection.py b/examples/multiresolution/scalar_advection.py index 885d756dd..6b68a8a7e 100644 --- a/examples/multiresolution/scalar_advection.py +++ b/examples/multiresolution/scalar_advection.py @@ -30,6 +30,7 @@ def compute(args): npts = args.npts # coarse resolution snpts = args.snpts # fine resolution fnpts = tuple(3*_ for _ in snpts) # finest resolution + cnpts = tuple(_//2 for _ in npts) # coarsest resolution lboundaries = (BoxBoundaryCondition.PERIODIC,)*dim rboundaries = (BoxBoundaryCondition.PERIODIC,)*dim box = Box(origin=args.box_origin, length=args.box_length, dim=dim, @@ -118,9 +119,9 @@ def compute(args): filtering_method=args.interpolation_filter, implementation=impl, **extra_op_kwds) - #> Restriction filter - restriction_filter = SpatialFilter(input_variables={scalar: snpts}, - output_variables={scalar: npts}, + #> Restriction filter + restriction_filter = SpatialFilter(input_variables={scalar: npts}, + output_variables={scalar: cnpts}, filtering_method=args.restriction_filter, implementation=impl, **extra_op_kwds) @@ -141,9 +142,15 @@ def compute(args): io_params=io_params, variables={scalar: npts}, **extra_op_kwds) + io_params = IOParams(filename='coarsest', frequency=args.dump_freq) + df3 = HDF_Writer(name='S_coarsest', + io_params=io_params, + variables={scalar: cnpts}, + **extra_op_kwds) # Add a writer of input field at given frequency. - problem.insert(interpolation_filter, df0, df1, df2) + problem.insert(interpolation_filter, restriction_filter, + df0, df1, df2, df3) problem.build(args) # If a visu_rank was provided, and show_graph was set, diff --git a/hysop/backend/device/opencl/operator/spatial_filtering.py b/hysop/backend/device/opencl/operator/spatial_filtering.py index 0b4271c79..1501c1b29 100644 --- a/hysop/backend/device/opencl/operator/spatial_filtering.py +++ b/hysop/backend/device/opencl/operator/spatial_filtering.py @@ -11,7 +11,7 @@ from hysop.fields.continuous_field import Field from hysop.parameters.parameter import Parameter from hysop.topology.cartesian_descriptor import CartesianTopologyDescriptors from hysop.operator.base.spatial_filtering import RemeshRestrictionFilterBase, SpectralRestrictionFilterBase, \ - SubgridRestrictionFilterBase, PolynomialInterpolationFilterBase + SubgridRestrictionFilterBase, PolynomialInterpolationFilterBase, PolynomialRestrictionFilterBase from hysop.backend.device.opencl.opencl_symbolic import OpenClSymbolic from hysop.backend.device.opencl.opencl_copy_kernel_launchers import OpenClCopyBufferRectLauncher from hysop.backend.device.opencl.opencl_kernel_launcher import OpenClKernelListLauncher @@ -57,7 +57,7 @@ class OpenClPolynomialInterpolationFilter(PolynomialInterpolationFilterBase, Ope exchange_ghosts = self.dFout.exchange_ghosts(build_launcher=True) - kl = OpenClKernelListLauncher(name='lowpass_filter') + kl = OpenClKernelListLauncher(name=kname) kl += interpolate_grid_kernel kl += exchange_ghosts @@ -69,6 +69,54 @@ class OpenClPolynomialInterpolationFilter(PolynomialInterpolationFilterBase, Ope evt = self.execute_kernels() +class OpenClPolynomialRestrictionFilter(PolynomialRestrictionFilterBase, OpenClOperator): + + @debug + def discretize(self): + if self.discretized: + return + super(OpenClPolynomialRestrictionFilter, self).discretize() + dFin = self.dFin + dFout = self.dFout + gr = self.grid_ratio + dim = dFin.dim + assert dFin.is_scalar + assert dFout.is_scalar + assert self.subgrid_restrictor.gr == gr + + ekg = self.elementwise_kernel_generator + Rr = self.subgrid_restrictor.Rr / self.subgrid_restrictor.GR + ghosts = np.asarray(self.subgrid_restrictor.ghosts) + + I = np.asarray(local_indices_symbols[:dim][::-1]) + fin, fout = ekg.dfields_to_ndbuffers(dFin, dFout) + + def gen_inputs(*idx): + return fin(gr*I+idx-ghosts) + input_values = np.asarray(tuple(map(gen_inputs, np.ndindex(*Rr.shape)))).reshape(Rr.shape) + output_value = (Rr*input_values).sum() + + e = Assignment(fout(I), output_value) + exprs = (e,) + + kname='restrict_grid_{}'.format(self.polynomial_interpolation_method).lower() + restriction_grid_kernel, _ = ekg.elementwise_kernel(kname, + *exprs, compute_resolution=self.iter_shape, debug=False) + + exchange_ghosts = self.dFout.exchange_ghosts(build_launcher=True) + + kl = OpenClKernelListLauncher(name=kname) + kl += restriction_grid_kernel + kl += exchange_ghosts + + self.execute_kernels = functools.partial(kl, queue=self.cl_env.default_queue) + + @op_apply + def apply(self, **kwds): + super(OpenClPolynomialRestrictionFilter, self).apply(**kwds) + evt = self.execute_kernels() + + class OpenClSubgridRestrictionFilter(SubgridRestrictionFilterBase, OpenClSymbolic): """ OpenCL implementation for lowpass spatial filtering: small grid -> coarse grid diff --git a/hysop/backend/host/python/operator/spatial_filtering.py b/hysop/backend/host/python/operator/spatial_filtering.py index a82688827..811384d31 100644 --- a/hysop/backend/host/python/operator/spatial_filtering.py +++ b/hysop/backend/host/python/operator/spatial_filtering.py @@ -7,8 +7,12 @@ from hysop.core.graph.graph import op_apply from hysop.fields.continuous_field import Field from hysop.parameters.parameter import Parameter from hysop.topology.cartesian_descriptor import CartesianTopologyDescriptors -from hysop.operator.base.spatial_filtering import RemeshRestrictionFilterBase, SpectralRestrictionFilterBase, \ - SubgridRestrictionFilterBase, PolynomialInterpolationFilterBase +from hysop.operator.base.spatial_filtering import ( + PolynomialInterpolationFilterBase, + RemeshRestrictionFilterBase, + SpectralRestrictionFilterBase, + SubgridRestrictionFilterBase, + PolynomialRestrictionFilterBase) class PythonPolynomialInterpolationFilter(PolynomialInterpolationFilterBase, HostOperator): @@ -24,20 +28,42 @@ class PythonPolynomialInterpolationFilter(PolynomialInterpolationFilterBase, Hos super(PythonPolynomialInterpolationFilter, self).apply(**kwds) fin = self.fin fout = self.fout - ishape = self.dFin.compute_resolution - oshape = self.dFout.compute_resolution periodicity = self.dFin.periodicity - gr = self.grid_ratio gr, n = self.subgrid_interpolator.gr, self.subgrid_interpolator.n Wr = self.Wr for idx in np.ndindex(*self.iter_shape): oslc = tuple(slice(j*gr[i], (j+1)*gr[i], 1) for i,j in enumerate(idx)) - islc = tuple(slice(periodicity[i]+j, periodicity[i]+j+n[i], 1) for i,j in enumerate(idx)) + islc = tuple(slice(periodicity[i]+j, periodicity[i]+j+n[i], 1) + for i,j in enumerate(idx)) fout[oslc] = Wr.dot(fin[islc].ravel()).reshape(gr) self.dFout.exchange_ghosts() +class PythonPolynomialRestrictionFilter(PolynomialRestrictionFilterBase, HostOperator): + def discretize(self, **kwds): + if self.discretized: + return + super(PythonPolynomialRestrictionFilter, self).discretize(**kwds) + SR = self.subgrid_restrictor + self.Rr = SR.Rr.astype(self.dtype) / SR.GR + assert (self.Rr.shape == tuple(2*gi+1 for gi in SR.ghosts)), Rr.shape + + @op_apply + def apply(self, **kwds): + """Apply analytic formula.""" + super(PythonPolynomialRestrictionFilter, self).apply(**kwds) + fin = self.fin + fout = self.fout + gr = self.subgrid_restrictor.gr + Rr = self.Rr + rshape = Rr.shape + + for idx in np.ndindex(*self.iter_shape): + islc = tuple(slice(j*gr[i], j*gr[i]+rshape[i], 1) for i,j in enumerate(idx)) + fout[idx] = (Rr*fin[islc]).sum() + self.dFout.exchange_ghosts() + class PythonRemeshRestrictionFilter(RemeshRestrictionFilterBase, HostOperator): """ Python implementation for lowpass spatial filtering: small grid -> coarse grid diff --git a/hysop/numerics/interpolation/polynomial.py b/hysop/numerics/interpolation/polynomial.py index b1a27c2aa..70e83e44b 100644 --- a/hysop/numerics/interpolation/polynomial.py +++ b/hysop/numerics/interpolation/polynomial.py @@ -116,14 +116,16 @@ class PolynomialInterpolator(object): Polynomial degree (1=linear, 3=cubic, 5=quintic, 7=septic, ...) Degree should be odd: deg=2k+1 fd: tuple of ints - Order of centered finite differences stencils used to compute derivatives for each direction. + Order of centered finite differences stencils used to compute derivatives for + each direction. p: tuple of ints Corresponds to deg+1. The total number of polynomial coefficients corresponds to P=p0*p1*...*p(dim-1). P: int The total number of polynomial coefficients P=p0*p1*...*p(dim-1) k: tuple of ints - Max derivative order required to compute the polynomial interpolator coefficients in each direction. + Max derivative order required to compute the polynomial interpolator coefficients + in each direction. Also the regularity of the resulting interpolant. Corresponds to (deg-1)/2. ghosts: tuple of ints Return the number of ghosts required by the interpolator on each axis. @@ -166,7 +168,8 @@ class PolynomialInterpolator(object): See Also -------- - :class:`PolynomialSubgridInterpolator`: Precompute weights for fixed subgrid interpolation. + :class:`PolynomialSubgridInterpolator`: Precompute weights for fixed subgrid + interpolation. """ assert dim>0, 'dim<=0' @@ -365,7 +368,8 @@ class PolynomialInterpolator(object): if verbose: print ' {}'.format(eq) - # Build system such that A*c = B*f where c are the polynomial coefficients and f the node values + # Build system such that A*c = B*f where c are the polynomial coefficients and + # f the node values dtype = (np.float64 if approximative else object) A = np.empty((self.P,self.P), dtype=dtype) B = np.empty((self.P,self.N), dtype=dtype) @@ -408,13 +412,15 @@ class PolynomialInterpolator(object): return sm.utilities.lambdify(self.xvars, P0) def generate_subgrid_interpolator(self, grid_ratio, dtype=None): - return PolynomialSubgridInterpolator(interpolator=self, grid_ratio=grid_ratio, dtype=dtype) + return PolynomialSubgridInterpolator(interpolator=self, + grid_ratio=grid_ratio, dtype=dtype) class PolynomialSubgridInterpolator(object): def __init__(self, interpolator, grid_ratio, dtype=None): """ - Create a PolynomialSubgridInterpolator from a PolynomialInterpolator and a number of subrid points. + Create a PolynomialSubgridInterpolator from a PolynomialInterpolator and a number of + subrid points. Parameters ---------- @@ -439,7 +445,8 @@ class PolynomialSubgridInterpolator(object): N = n0*n1*...*n[dim-1] s: tuple of int Corresponds to grid_ratio + 1, number of points of the subgrid in each directions. - Example for a grid ratio=(3,3), we have s=(4,4): O=coarse grid nodes, X=fine grid nodes + Example for a grid ratio=(3,3), we have s=(4,4): + O=coarse grid nodes, X=fine grid nodes Coarse grid: Fine grid: @@ -453,7 +460,8 @@ class PolynomialSubgridInterpolator(object): Represents the number of fine grid points contained in a coarse grid cell. S = s0*s1*...*s[dim-1] gr: tuple of int - Corresponds to grid_ratio, number of points of the subgrid in each directions, minus one. + Corresponds to grid_ratio, number of points of the subgrid in each directions, + minus one. Example for a grid ratio=(3,3), we have gr=(3,3) and s=(4,4): O=coarse grid nodes, X=fine grid nodes, -=excluded find grid nodes @@ -466,11 +474,13 @@ class PolynomialSubgridInterpolator(object): <-----> <---> 1 gr1 GR: int - Represents the number of fine grid points contained in a coarse grid cell exluding right most points. + Represents the number of fine grid points contained in a coarse grid cell exluding + right most points. GR = gr0*gr1*...*gr[dim-1] W: np.ndarray Pre computed weights to interpolate directly from coarse to fine grid. - Let F be the vector of N known coarse grid node values (including required ghosts). + Let F be the vector of N known coarse grid node values (including required + ghosts). Let G be the vector of S unknown fine grid node values. N @@ -604,39 +614,63 @@ class PolynomialSubgridRestrictor(object): Attributes ---------- - g: int + g: tuple of int Corresponds to (n+1)*s G: int Corresponds to g[0]*g[1]*...g[dim-1] + R: np.ndarray + Restrictor weights. + origin: tuple of int + Origin of the generated stencil. + Rr: np.ndarray + Restrictor weights excluding leftmost and rightmost points. + ghosts: + Corresponds to origin - 1, which is also Rr origin. """ check_instance(subgrid_interpolator, PolynomialSubgridInterpolator) - s = subgrid_interpolator.s - n = subgrid_interpolator.n - gr = tuple(si-1 for si in s) - g = tuple(n*gri+1 for gri in gr) + dim = subgrid_interpolator.dim + n = subgrid_interpolator.n + s = subgrid_interpolator.s + gr = subgrid_interpolator.gr + GR = subgrid_interpolator.GR + W = subgrid_interpolator.W + g = tuple(ni*gri+1 for (ni,gri) in zip(n,gr)) + G = np.prod(g, dtype=np.int64) assert all(gi%2==1 for gi in g) origin = tuple(gi/2 for gi in g) - G = np.prod(g, dtype=np.int64) - gvals, gvars = tensor_symbol('g',g,origin) I = 0 for idx in np.ndindex(*gr): - mask = tuple(slice(i, max(2,i+n*gri), gri) for (i,gri) in zip(idx, gr)) + mask = tuple(slice(i, max(2,i+ni*gri), gri) for (i,ni,gri) in zip(idx, n, gr)) target = tuple(gri-i for (i,gri) in zip(idx,gr)) F = gvals[mask] - Ii = subgrid_interpolator.W.dot(F.ravel()).reshape(s)[target] + Ii = W.dot(F.ravel()).reshape(s)[target] I += Ii R = np.ndarray(shape=g, dtype=object) for idx in np.ndindex(*g): R[idx] = I.coeff(gvals[idx]) - print R.astype(np.float32) - print R.sum() + + view = (slice(1,-1,None),)*dim + Rr = R[view] + ghosts = tuple(oi-1 for oi in origin) + + self.g = g + self.G = G + self.R = R + self.Rr = Rr + self.origin = origin + self.ghosts = ghosts + self.n = n + self.s = s + self.GR = GR + self.gr = gr + self.subgrid_interpolator = subgrid_interpolator if __name__ == '__main__': np.set_printoptions(precision=4, linewidth=1e8, threshold=1e8, formatter={'float': lambda x: "{0:+0.3f}".format(x)}) - + # 2D tests grid_ratio = (2,2) F = [[1,1], @@ -722,28 +756,32 @@ if __name__ == '__main__': print print 'Solving biseptic2...' - PI2 = PolynomialInterpolator(dim=2, deg=7, fd=2, verbose=False, approximative=(not has_flint)) + PI2 = PolynomialInterpolator(dim=2, deg=7, fd=2, verbose=False, + approximative=(not has_flint)) GI2 = PI2.generate_subgrid_interpolator(grid_ratio=grid_ratio, dtype=np.float64) print 'Biseptic (FDC2)' print GI2(F) print print 'Solving binonic2...' - PI3 = PolynomialInterpolator(dim=2, deg=9, fd=2, verbose=False, approximative=(not has_flint)) + PI3 = PolynomialInterpolator(dim=2, deg=9, fd=2, verbose=False, + approximative=(not has_flint)) GI3 = PI3.generate_subgrid_interpolator(grid_ratio=grid_ratio, dtype=np.float64) print 'Binonic (FDC2)' print GI3(F) print print 'Solving septic2/nonic2 ...' - PI4 = PolynomialInterpolator(dim=2, deg=(7,9), fd=2, verbose=False, approximative=(not has_flint)) + PI4 = PolynomialInterpolator(dim=2, deg=(7,9), fd=2, verbose=False, + approximative=(not has_flint)) GI4 = PI4.generate_subgrid_interpolator(grid_ratio=grid_ratio, dtype=np.float64) print 'septic/nonic (FDC2)' print GI4(F) print print 'Solving septic2/quintic4 ...' - PI5 = PolynomialInterpolator(dim=2, deg=(7,5), fd=(2,4), verbose=False, approximative=(not has_flint)) + PI5 = PolynomialInterpolator(dim=2, deg=(7,5), fd=(2,4), verbose=False, + approximative=(not has_flint)) GI5 = PI5.generate_subgrid_interpolator(grid_ratio=grid_ratio, dtype=np.float64) print 'septic/nonic (FDC2/FDC4)' print GI5(F) @@ -762,8 +800,25 @@ if __name__ == '__main__': print print 'Solving triquintic2...' - PI0 = PolynomialInterpolator(dim=3, deg=5, fd=2, verbose=False, approximative=(not has_flint)) + PI0 = PolynomialInterpolator(dim=3, deg=5, fd=2, verbose=False, + approximative=(not has_flint)) GI0 = PI0.generate_subgrid_interpolator(grid_ratio=grid_ratio, dtype=np.float64) print - + # Delaurier-Dubuc interpolating wavelets + from matplotlib import pyplot as plt + grid_ratio = (32,) + fig, axes = plt.subplots(ncols=2, nrows=2) + #for k,(deg, sdeg) in enumerate(zip((3,5,7,9),('cubic','quintic','septic','nonic'))): + for k,(deg, sdeg) in enumerate(zip((3,5,),('cubic','quintic'))): + ax = axes[k/2, k%2] + for fd in (2,4,6): + PI = PolynomialInterpolator(dim=1, deg=deg, fd=fd, verbose=False) + SI = PI.generate_subgrid_interpolator(grid_ratio=grid_ratio) + SR = SI.generate_subgrid_restrictor() + X = np.linspace(-SR.n[0]/2, +SR.n[0]/2, SR.g[0]) + ax.plot(X, SR.R, label='{}_fdc{}'.format(sdeg, fd)) + ax.legend() + ax.plot(X, np.zeros(SR.g[0]), '--') + plt.show() + diff --git a/hysop/operator/base/spatial_filtering.py b/hysop/operator/base/spatial_filtering.py index 793fb86e4..30db42947 100644 --- a/hysop/operator/base/spatial_filtering.py +++ b/hysop/operator/base/spatial_filtering.py @@ -65,7 +65,6 @@ class SpatialFilterBase(object): self.dFin = dFin self.dFout = dFout self.grid_ratio = grid_ratio - self.iter_shape = self.dFin.compute_resolution + 1 - self.dFin.periodicity @classmethod def supports_multiple_field_topologies(cls): @@ -401,8 +400,40 @@ class PolynomialInterpolationFilterBase(PolynomialInterpolationMethod, Interpola super(PolynomialInterpolationFilterBase, self).discretize() dFin, dFout = self.dFin, self.dFout ghosts = self.dFin.topology_state.transposed(self.required_input_ghosts) - psi = self.polynomial_interpolator.generate_subgrid_interpolator(grid_ratio=self.grid_ratio) + psi = self.polynomial_interpolator.generate_subgrid_interpolator( + grid_ratio=self.grid_ratio) self.subgrid_interpolator = psi self.fin = dFin.sdata[dFin.local_slices(ghosts=ghosts)].handle self.fout = dFout.sdata[dFout.compute_slices].handle + self.iter_shape = self.dFin.compute_resolution + 1 - self.dFin.periodicity + + +class PolynomialRestrictionFilterBase(PolynomialInterpolationMethod, RestrictionFilterBase): + """ + Base implementation for polynomial interpolation. + """ + @debug + def get_field_requirements(self): + reqs = super(PolynomialRestrictionFilterBase, self).get_field_requirements() + iratio = self.iratio + pghosts = self.polynomial_interpolator.ghosts + ghosts = np.add(np.multiply(iratio, np.add(pghosts,1)), -1) + Fin_topo, Fin_requirements = reqs.get_input_requirement(self.Fin) + Fin_requirements.min_ghosts = ghosts + self.required_input_ghosts = ghosts + return reqs + + def discretize(self): + if self.discretized: + return + super(PolynomialRestrictionFilterBase, self).discretize() + dFin, dFout = self.dFin, self.dFout + ghosts = self.dFin.topology_state.transposed(self.required_input_ghosts) + psr = self.polynomial_interpolator.generate_subgrid_interpolator( + grid_ratio=self.grid_ratio).generate_subgrid_restrictor() + assert all(psr.ghosts == ghosts) + self.subgrid_restrictor = psr + self.fin = dFin.sdata[dFin.local_slices(ghosts=ghosts)].handle + self.fout = dFout.sdata[dFout.compute_slices].handle + self.iter_shape = self.dFout.compute_resolution diff --git a/hysop/operator/spatial_filtering.py b/hysop/operator/spatial_filtering.py index 38d2f4e58..f485aec69 100644 --- a/hysop/operator/spatial_filtering.py +++ b/hysop/operator/spatial_filtering.py @@ -77,20 +77,26 @@ class RestrictionFilterFrontend(SpatialFilterFrontend): @classmethod def all_implementations(cls): from hysop.backend.host.python.operator.spatial_filtering import \ - PythonRemeshRestrictionFilter, PythonSpectralRestrictionFilter, PythonSubgridRestrictionFilter + PythonRemeshRestrictionFilter, PythonSpectralRestrictionFilter, \ + PythonSubgridRestrictionFilter, PythonPolynomialRestrictionFilter from hysop.backend.device.opencl.operator.spatial_filtering import \ - OpenClSpectralRestrictionFilter, OpenClSubgridRestrictionFilter + OpenClSpectralRestrictionFilter, OpenClSubgridRestrictionFilter, \ + OpenClPolynomialRestrictionFilter ai = { + FilteringMethod.SUBGRID: { + Implementation.PYTHON: PythonSubgridRestrictionFilter, + Implementation.OPENCL: OpenClSubgridRestrictionFilter, + }, + FilteringMethod.POLYNOMIAL: { + Implementation.PYTHON: PythonPolynomialRestrictionFilter, + Implementation.OPENCL: OpenClPolynomialRestrictionFilter, + }, FilteringMethod.SPECTRAL: { Implementation.PYTHON: PythonSpectralRestrictionFilter, - Implementation.OPENCL: OpenClSpectralRestrictionFilter + Implementation.OPENCL: OpenClSpectralRestrictionFilter, }, FilteringMethod.REMESH: { - Implementation.PYTHON: PythonRemeshRestrictionFilter - }, - FilteringMethod.SUBGRID: { - Implementation.PYTHON: PythonSubgridRestrictionFilter, - Implementation.OPENCL: OpenClSubgridRestrictionFilter + Implementation.PYTHON: PythonRemeshRestrictionFilter, }, } return ai @@ -98,9 +104,10 @@ class RestrictionFilterFrontend(SpatialFilterFrontend): @classmethod def all_default_implementations(cls): adi = { - FilteringMethod.REMESH: Implementation.PYTHON, - FilteringMethod.SPECTRAL: Implementation.PYTHON, - FilteringMethod.SUBGRID: Implementation.PYTHON + FilteringMethod.SUBGRID: Implementation.PYTHON, + FilteringMethod.POLYNOMIAL: Implementation.PYTHON, + FilteringMethod.SPECTRAL: Implementation.PYTHON, + FilteringMethod.REMESH: Implementation.PYTHON, } return adi diff --git a/hysop/symbolic/array.py b/hysop/symbolic/array.py index 4c28c0765..a1ae050f0 100644 --- a/hysop/symbolic/array.py +++ b/hysop/symbolic/array.py @@ -257,7 +257,8 @@ class SymbolicNdBuffer(SymbolicBuffer): def __call__(self, *idx): if len(idx)==1 and isinstance(idx[0], npw.ndarray): - idx = tuple(idx[0].tolist()) + assert idx[0].size==self._dim, idx[0].shape + idx = tuple(idx[0].ravel().tolist()) assert len(idx) == self._dim, idx offset = npw.dot(self._symbolic_strides, npw.add(idx, self._symbolic_ghosts)) return self.__getitem__(key=offset) -- GitLab