From 1727b0775f40b3c796420aa5785d29bca903ff64 Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Keck <Jean-Baptiste.Keck@imag.fr> Date: Wed, 10 Apr 2019 22:17:53 +0200 Subject: [PATCH] more interpolation mode support, working opencl and python interpolation --- examples/multiresolution/scalar_advection.py | 6 +- .../opencl/operator/spatial_filtering.py | 12 +- .../host/python/operator/spatial_filtering.py | 20 +- hysop/numerics/interpolation/polynomial.py | 437 +++++++++++------- hysop/operator/base/spatial_filtering.py | 23 +- hysop/tools/warning.py | 6 + 6 files changed, 314 insertions(+), 190 deletions(-) diff --git a/examples/multiresolution/scalar_advection.py b/examples/multiresolution/scalar_advection.py index fa9d3a586..9acfdebc2 100644 --- a/examples/multiresolution/scalar_advection.py +++ b/examples/multiresolution/scalar_advection.py @@ -26,9 +26,9 @@ def compute(args): # Define domain dim = args.ndim - npts = args.npts - snpts = args.snpts - fnpts = tuple(2*_ for _ in snpts) + npts = args.npts # coarse resolution + snpts = args.snpts # fine resolution + fnpts = tuple(3*_ for _ in snpts) # finest resolution lboundaries = (BoxBoundaryCondition.PERIODIC,)*dim rboundaries = (BoxBoundaryCondition.PERIODIC,)*dim box = Box(origin=args.box_origin, length=args.box_length, dim=dim, diff --git a/hysop/backend/device/opencl/operator/spatial_filtering.py b/hysop/backend/device/opencl/operator/spatial_filtering.py index c01c11a2b..d6f168e6e 100644 --- a/hysop/backend/device/opencl/operator/spatial_filtering.py +++ b/hysop/backend/device/opencl/operator/spatial_filtering.py @@ -32,17 +32,17 @@ class OpenClPolynomialInterpolationFilter(PolynomialInterpolationFilterBase, Ope dim = dFin.dim assert dFin.is_scalar assert dFout.is_scalar + assert self.subgrid_interpolator.gr == gr ekg = self.elementwise_kernel_generator - W = self.subgrid_interpolator.W - s = self.subgrid_interpolator.s - n = (self.subgrid_interpolator.n,)*dim - ghosts = np.asarray((self.subgrid_interpolator.ghosts,)*dim) + Wr = self.subgrid_interpolator.Wr + n = self.subgrid_interpolator.n + ghosts = np.asarray(self.subgrid_interpolator.ghosts) 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) + Fout_values = Wr.dot(Fin.ravel()).reshape(gr) exprs = () for idx in np.ndindex(*n): @@ -53,7 +53,7 @@ class OpenClPolynomialInterpolationFilter(PolynomialInterpolationFilterBase, Ope exprs += (e,) interpolate_grid_kernel, _ = ekg.elementwise_kernel('interpolate_grid', - *exprs, compute_resolution=dFin.compute_resolution, debug=False) + *exprs, compute_resolution=self.iter_shape, debug=False) exchange_ghosts = self.dFout.exchange_ghosts(build_launcher=True) diff --git a/hysop/backend/host/python/operator/spatial_filtering.py b/hysop/backend/host/python/operator/spatial_filtering.py index 24a2fd065..a82688827 100644 --- a/hysop/backend/host/python/operator/spatial_filtering.py +++ b/hysop/backend/host/python/operator/spatial_filtering.py @@ -16,8 +16,7 @@ class PythonPolynomialInterpolationFilter(PolynomialInterpolationFilterBase, Hos if self.discretized: return super(PythonPolynomialInterpolationFilter, self).discretize(**kwds) - self.W = self.subgrid_interpolator.W.astype(self.dtype) - self.iter_shape = self.dFin.compute_resolution + self.Wr = self.subgrid_interpolator.Wr.astype(self.dtype) @op_apply def apply(self, **kwds): @@ -25,16 +24,17 @@ class PythonPolynomialInterpolationFilter(PolynomialInterpolationFilterBase, Hos super(PythonPolynomialInterpolationFilter, self).apply(**kwds) fin = self.fin fout = self.fout - shape = self.iter_shape + ishape = self.dFin.compute_resolution + oshape = self.dFout.compute_resolution + periodicity = self.dFin.periodicity gr = self.grid_ratio - s, n = self.subgrid_interpolator.s, self.subgrid_interpolator.n - oshape = fout.shape + gr, n = self.subgrid_interpolator.gr, self.subgrid_interpolator.n + Wr = self.Wr - for idx in np.ndindex(*shape): - oslc = tuple(slice(j*gr[i], (j+1)*gr[i]+1, 1) for i,j in enumerate(idx)) - islc = tuple(slice(1+j, 1+j+n, 1) for i,j in enumerate(idx)) - rslc = tuple(slice(0, min(s[i], oshape[i]-j*gr[i]), 1) for i,j in enumerate(idx)) - fout[oslc] = self.W.dot(fin[islc].ravel()).reshape(s)[rslc] + 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)) + fout[oslc] = Wr.dot(fin[islc].ravel()).reshape(gr) self.dFout.exchange_ghosts() diff --git a/hysop/numerics/interpolation/polynomial.py b/hysop/numerics/interpolation/polynomial.py index 8aa98499a..2e49a40aa 100644 --- a/hysop/numerics/interpolation/polynomial.py +++ b/hysop/numerics/interpolation/polynomial.py @@ -2,6 +2,7 @@ import itertools as it import numpy as np import scipy as sp import sympy as sm +import warnings try: import flint @@ -16,11 +17,12 @@ except ImportError: has_flint = False from hysop.tools.enum import EnumFactory -from hysop.tools.types import check_instance, InstanceOf +from hysop.tools.types import check_instance, InstanceOf, to_tuple from hysop.tools.cache import update_cache, load_data_from_cache from hysop.tools.io_utils import IO from hysop.tools.sympy_utils import tensor_xreplace, tensor_symbol from hysop.tools.decorators import debug +from hysop.tools.warning import HysopCacheWarning from hysop.numerics.stencil.stencil_generator import CenteredStencilGenerator, MPQ from hysop.numerics.interpolation.interpolation import MultiScaleInterpolation @@ -96,7 +98,7 @@ class PolynomialInterpolationMethod(SpaceDiscretizationMethod): Operator helper to handle polynomial interpolation method. """ __default_method = { - MultiScaleInterpolation: PolynomialInterpolation.NONIC_FDC2, + MultiScaleInterpolation: PolynomialInterpolation.CUBIC_FDC2, } __available_methods = { @@ -168,11 +170,11 @@ class PolynomialInterpolator(object): ---------- dim: int Number of dimensions to interpolate. - deg: int + deg: int or tuple of ints Polynomial degree (1=linear, 3=cubic, 5=quintic, 7=septic, ...) - Degree should be odd. - fd: int - Order of centered finite differences used to compute derivatives. + Degree should be odd on each axis. + fd: int or tuple of ints + Order of centered finite differences used to compute derivatives in each direction. Will affect the number of ghosts of the method. Should be even because this interpolator only use centered dinite differences. approximative: bool @@ -184,20 +186,20 @@ class PolynomialInterpolator(object): ---------- dim: int Number of dimensions to interpolate. - deg: int + deg: tuple of ints Polynomial degree (1=linear, 3=cubic, 5=quintic, 7=septic, ...) Degree should be odd: deg=2k+1 - fd: int - Order of centered finite differences stencils used to compute derivatives. - p: int + fd: tuple of ints + 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=p**dim. + The total number of polynomial coefficients corresponds to P=p0*p1*...*p(dim-1). P: int - The total number of polynomial coefficients P=p**dim. - k: int - Max derivative order required to compute the polynomial interpolator coefficients. + 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. Also the regularity of the resulting interpolant. Corresponds to (deg-1)/2. - ghosts: int + ghosts: tuple of ints Return the number of ghosts required by the interpolator on each axis. Corresponds to (k>0)*[fd//2 - 1 + (k+1)//2] deg k (k+1)/2 | FDC2 FDC4 FDC6 @@ -206,29 +208,29 @@ class PolynomialInterpolator(object): quintic: 5 2 1 | 1 2 3 septic: 7 3 2 | 2 3 4 nonic: 9 4 2 | 2 3 4 - n: int + n: tuple of ints Corresponds to 2*(ghosts+1), the number of required nodes to generate the polynomial coefficients (in each direction). - In total we have N=n**dim input nodes. + In total we have N=n0*n1*...*n(dim-1) input nodes. - G G + G1 G1 <-> <-> X X X X X P P X X P P X X X X X <-----> - n + n1 N: int - Total number of input nodes N=n**dim. + Total number of input nodes N=n0*n1*...*n(dim-1). M: np.ndarray Grid values to polynomial coefficient matrix: M.dot(F.ravel()) will give C.ravel(), coefficients of P(x0,x1,...) - N = n**dim + N <---------> X X X X X X ^ |f0| ^ |c0| ^ X X X X X X | |f1| | |c1| | - M = X X X X X X | P = p**dim F = |f2| | N C = M*F = |c2| | P + M = X X X X X X | P F = |f2| | N C = M*F = |c2| | P X X X X X X | |f3| | |c3| | X X X X X X v |f4| | |c4| v |f5| v @@ -242,23 +244,44 @@ class PolynomialInterpolator(object): """ assert dim>0, 'dim<=0' - assert deg%2==1, 'deg % 2 != 1' - assert fd%2==0, 'fd % 2 != 0' - dim = dim - k = (deg-1)/2 - - if (k>0): - required_ghosts = (k+1)/2 - ghosts = (fd/2) - 1 + required_ghosts - else: - ghosts = 0 - - p = deg+1 - n = 2*(ghosts+1) + deg = to_tuple(deg) + if len(deg)==1: + deg*=dim + check_instance(deg, tuple, values=int, size=dim) - P = p**dim - N = n**dim + fd = to_tuple(fd) + if len(fd)==1: + fd*=dim + check_instance(fd, tuple, values=int, size=dim) + + p = tuple(degi+1 for degi in deg) + k = tuple((degi-1)/2 for degi in deg) + + ghosts = () + n = () + for (fdi,ki) in zip(fd,k): + if (ki>0): + gi = (fdi/2) - 1 + (ki+1)/2 + else: + gi = 0 + ni = 2*(gi+1) + ghosts += (gi,) + n += (ni,) + + check_instance(deg, tuple, values=int, size=dim) + check_instance(fd, tuple, values=int, size=dim) + check_instance(p, tuple, values=int, size=dim) + check_instance(k, tuple, values=int, size=dim) + check_instance(n, tuple, values=int, size=dim) + check_instance(ghosts,tuple, values=int, size=dim) + assert all(fdi%2==0 for fdi in fd), 'fd % 2 != 0' + assert all(degi%2==1 for degi in deg), 'deg % 2 != 1' + assert all(pi%2==0 for pi in p), 'p % 2 != 0' + assert all(ni%2==0 for ni in n), 'n % 2 != 0' + + P = np.prod(p, dtype=np.int32) + N = np.prod(n, dtype=np.int32) self.dim = dim self.deg = deg @@ -278,7 +301,7 @@ class PolynomialInterpolator(object): dim = self.dim ghosts = self.ghosts verbose = self.verbose - order = self.fd + fd = self.fd approximative = self.approximative k = self.k @@ -289,76 +312,89 @@ class PolynomialInterpolator(object): print '\nCollecting 1D stencils:' SG = CenteredStencilGenerator() - SG.configure(dim=1, dtype=np.float64, order=order) - S = [] - for i in xrange(k+1): - msg='Failed to compute stencil derivative={}, order={}, origin={}' - msg=msg.format(i, order, ghosts) - try: - if approximative: - Si = SG.generate_approximative_stencil(derivative=i) - else: - Si = SG.generate_exact_stencil(derivative=i) - Si.replace_symbols({Si.dx:1}) - except: - print msg - raise - msg+=' got {}.'.format(Si.coeffs) - assert (not Si.is_symbolic()), msg - Si = Si.reshape((self.n-1,)) - assert Si.origin == ghosts - Si = Si.coeffs - S.append(Si) + SG.configure(dim=1, dtype=np.float64) + S = {} + for direction in xrange(dim): if verbose: - print ' {}-th derivative: {}'.format(i,Si) - self.S = S + print ' Direction {}'.format(direction) + Sd = S.setdefault(direction, []) + nd = n[direction] + kd = k[direction] + fdd = fd[direction] + gd = ghosts[direction] + for i in xrange(kd+1): + msg='Failed to compute stencil derivative={}, order={}, origin={}' + msg=msg.format(i, fdd, gd) + try: + if approximative: + Si = SG.generate_approximative_stencil(order=fdd, derivative=i) + else: + Si = SG.generate_exact_stencil(order=fdd, derivative=i) + Si.replace_symbols({Si.dx:1}) + except: + print msg + raise + msg+=' got {}.'.format(Si.coeffs) + assert (not Si.is_symbolic()), msg + Si = Si.reshape((nd-1,)) + assert Si.origin == gd + Si = Si.coeffs + Sd.append(Si) + if verbose: + print ' {}-th derivative: {}'.format(i,Si) + return S def _build_stencil(self, dvec): dvec = np.asarray(dvec) + k = self.k + S = self.S assert dvec.size == self.dim, 'dvec.size != dim' - assert (dvec>=0).all(), 'dvec < 0 => {}'.format(dvec) - assert (dvec<=self.k).all(), 'dvec > dmax => {}'.format(dvec) + assert all(dvec>=0), 'dvec < 0 => {}'.format(dvec) + assert all(di<=ki for (di,ki) in zip(dvec,k)), 'dvec > dmax => {}'.format(dvec) - Sd = self.S[dvec[0]].copy() - for di in dvec[1:]: - Sdi = self.S[di] - Sd = np.tensordot(Sd, Sdi, axes=0) + Sd = S[0][dvec[0]].copy() + for (d,i) in enumerate(dvec[1:],1): + Sd = np.tensordot(Sd, S[d][i], axes=0) return Sd def _build_interpolator(self): - dim = self.dim - deg = self.deg - maxd = self.k + dim = self.dim + deg = self.deg + k = self.k + n = self.n + p = self.p ghosts = self.ghosts approximative = self.approximative verbose = self.verbose - forigin = (ghosts,)*dim - fshape = (2*(ghosts+1),)*dim - pshape = (deg+1,)*dim - - xvals, xvars = tensor_symbol('x',shape=(dim,)) - fvals, fvars = tensor_symbol('F',fshape,forigin) - pvals, pvars = tensor_symbol('C',pshape) + xvals, xvars = tensor_symbol('x', shape=(dim,)) + fvals, fvars = tensor_symbol('F', n, ghosts) + pvals, pvars = tensor_symbol('C', p) self.xvals, self.xvars = xvals, xvars self.fvals, self.fvars = fvals, fvars self.pvals, self.pvars = pvals, pvars + try: + data = load_data_from_cache(self.cache_file(), self.key) + if (data is not None): + (P0, S, M) = data + if _check_matrix(M): + self.P0 = P0 + self.S = S + self.M = M + return + except Exception as e: + msg='Failed to load data from cache because:\n{}'.format(e) + warnings.warn(msg, HysopCacheWarning) + P0 = 0 - for idx in it.product(range(0,deg+1), repeat=dim): - val = pvals[idx] - for i in xrange(dim): - val*= pow(xvals[i],idx[i]) - P0 += val + for idx in it.product(*tuple(range(0,pi) for pi in p)): + P0 += pvals[idx] * np.prod(np.power(xvals, idx)) self.P0 = P0 - self._collect_stencils() - - M = load_data_from_cache(self.cache_file(), self.key) - if (M is not None) and _check_matrix(M): - self.M = M - return + S = self._collect_stencils() + self.S = S if verbose: print '\nGenerating variables:' @@ -373,7 +409,7 @@ class PolynomialInterpolator(object): print '\nBuilding system...' eqs = [] - for dvec in it.product( range(0,maxd+1), repeat=dim ): + for dvec in it.product(*tuple(range(0,ki+1) for ki in k)): if verbose: print ' => derivative {}'.format(dvec) @@ -386,17 +422,17 @@ class PolynomialInterpolator(object): print ' stencil:' print stencil - for idx in it.product( range(ghosts,ghosts+2), repeat=dim): + for idx in it.product(*tuple(range(gi,gi+2) for gi in ghosts)): if verbose: print ' -> point {}'.format(idx) pos = np.asarray(idx)-ghosts pos = dict(zip(xvals, pos)) eq = dP0.xreplace(pos) - - for offset in it.product( range(-ghosts, ghosts+1), repeat=dim): - fidx = tuple(np.asarray(idx)+np.asarray(offset)) - sidx = tuple(np.asarray(offset)+ghosts) + + for offset in it.product(*tuple(range(-gi, gi+1) for gi in ghosts)): + fidx = tuple(np.add(idx, offset)) + sidx = tuple(np.add(offset, ghosts)) eq -= fvals[fidx]*stencil[sidx] eqs.append(eq) @@ -434,7 +470,7 @@ class PolynomialInterpolator(object): print '\nBuilding matrix...' M = Ainv.dot(B) self.M = M - update_cache(self.cache_file(), self.key, M) + update_cache(self.cache_file(), self.key, (P0,S,M)) def interpolate(self, fvals): @@ -458,7 +494,7 @@ class PolynomialSubgridInterpolator(object): ---------- interpolator: PolynomialInterpolator Interpolant used to compute weights. - grid_ratio: tuple of integers + grid_ratio: tuple of int Tuple of integers representing the ratio between the coarse and the fine grid. dtype: np.dtype Force to cast dtype for all matrices (interpolator.M may contain rationals). @@ -467,14 +503,15 @@ class PolynomialSubgridInterpolator(object): ---------- dim: int Number of dimensions to interpolate (same as interpolator.dim). - ghosts: int + ghosts: tuple of int Number of required ghosts. - n: int + n: tuple of int Corresponds to 2*(ghosts+1), the number of required nodes to generate the polynomial coefficients (same as interpolator.n). N: int Total number of input nodes N including ghosts (same as interpolator.N). - s: int + 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 @@ -489,10 +526,48 @@ class PolynomialSubgridInterpolator(object): S: int 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. + 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 + + Coarse grid: Fine grid: + + ^ O-----O ^ O X X O ^ + | | | gr0 | X X X - | s0 + 1 | | | v X X X - | + v O-----O O - - O v + <-----> <---> + 1 gr1 + GR: int + 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. + 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 G be the vector of S unknown fine grid node values. + + N + <---------> + X X X X X X ^ |g0| ^ + X X X X X X | |f0| ^ |g1| | + X X X X X X | |f1| | |g2| | + X X X X X X | |f2| | |g3| | + W = X X X X X X | S F= |f3| | N G = W*F = |g4| | S + X X X X X X | |f4| | |g5| | + X X X X X X | |f5| v |g6| | + X X X X X X | |g7| | + X X X X X X v |g8| v + + Will contain the same data type as intepolator.M if dtype is not passed, + else W will be computed from user given dtype. + + Wr: np.ndarray + Reduced W that exludes rightmost output points of ndimensional output vector. + + Pre computed weights to interpolate directly from coarse to inner fine grid. 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. + Let G be the vector of GR unknown fine inner grid node values (see gr attribute). N <---------> @@ -500,33 +575,33 @@ class PolynomialSubgridInterpolator(object): X X X X X X | |f0| ^ |g1| | X X X X X X | |f1| | |g2| | X X X X X X | |f2| | |g3| | - W = X X X X X X | S F= |f3| | N G = W*F = |g3| | S - X X X X X X | |f4| | |g3| | - X X X X X X | |f5| v |g3| | - X X X X X X | |g3| | - X X X X X X v |g4| v - - Will contain the same data type as intepolator.M if dtype is not passed, - else W will be computed from user given dtype. - - U: tuple - Contains unique values contained in W. - I: np.ndarray of np.int8 or np.int16 - Represents W as integers indexed into U. + Wr = X X X X X X | GR F= |f3| | N G = W*F = |g4| | GR + X X X X X X | |f4| | |g5| | + X X X X X X | |f5| v |g6| | + X X X X X X | |g7| | + X X X X X X v |g8| v + + Same data type as W. """ check_instance(interpolator, PolynomialInterpolator) check_instance(grid_ratio, tuple, size=interpolator.dim, minval=1) p = interpolator.p - P = interpolator.P n = interpolator.n + P = interpolator.P N = interpolator.N + M = interpolator.M ghosts = interpolator.ghosts + + gr = grid_ratio + GR = np.prod(gr, dtype=np.int32) + del grid_ratio - s = tuple(gr+1 for gr in grid_ratio) - S = np.prod(s, dtype=np.int64) + s = tuple(gri+1 for gri in gr) + S = np.prod(s, dtype=np.int32) + dim = interpolator.dim - key = ('PolynomialSubgridInterpolator', interpolator.key, grid_ratio, str(dtype)) + key = ('PolynomialSubgridInterpolator', interpolator.key, gr, str(dtype)) self.p = p self.P = p @@ -534,60 +609,48 @@ class PolynomialSubgridInterpolator(object): self.S = S self.n = n self.N = N + self.gr = gr + self.GR = GR self.ghosts = interpolator.ghosts self.dim = dim self.interpolator = interpolator self.key = key cache_file = interpolator.cache_file() - data = load_data_from_cache(cache_file, key) - if (data is not None) and _check_matrices(*data): - (W,U,I) = data - else: - X = tuple(np.asarray(tuple(sm.Rational(j,gr) for j in xrange(0,si))) for i,(gr,si) in enumerate(zip(grid_ratio, s))) - M = interpolator.M - V = np.vander(X[0], N=p, increasing=True) - for i in xrange(1, dim): - Vi = np.vander(X[i], N=p, increasing=True) - V = np.multiply.outer(V,Vi) - - even_axes = range(0,V.ndim,2) - odd_axes = range(1,V.ndim,2) - axes = even_axes + odd_axes - - V = np.transpose(V, axes=axes).copy() - assert V.shape[:dim] == s - assert V.shape[dim:] == (p,)*dim - V = V.reshape((S,P)) - W = V.dot(M) - assert W.shape == (S,N) - - if interpolator.approximative: - U = None - I = None - else: - U = list(sorted(set(W.ravel().tolist()))) - U.remove(0) - U.remove(1) - U = (0,1,)+tuple(U) - - if len(U)<np.iinfo(np.uint8).max: - itype = np.uint8 - elif len(U)<np.iinfo(np.uint16).max: - itype = np.uint16 - else: - raise NotImplementedError(len(U)) - - I = np.empty(shape=W.shape, dtype=itype) - for idx in np.ndindex(*W.shape): - I[idx] = U.index(W[idx]) - - if (dtype is not None): - W = W.astype(dtype) - update_cache(cache_file, key, (W,U,I)) + try: + data = load_data_from_cache(cache_file, key) + if (data is not None): + W = data + if _check_matrix(W): + self.W = data + return + except Exception as e: + msg='Failed to load data from cache because:\n{}'.format(e) + warnings.warn(msg, HysopCacheWarning) + + X = tuple(np.asarray(tuple(sm.Rational(j,gr) for j in xrange(0,si))) + for i,(gr,si) in enumerate(zip(gr, s))) + V = np.vander(X[0], N=p[0], increasing=True) + for i in xrange(1, dim): + Vi = np.vander(X[i], N=p[i], increasing=True) + V = np.multiply.outer(V,Vi) + + even_axes = range(0,V.ndim,2) + odd_axes = range(1,V.ndim,2) + axes = even_axes + odd_axes + + V = np.transpose(V, axes=axes).copy() + assert V.shape[:dim] == s + assert V.shape[dim:] == p + V = V.reshape((S,P)) + W = V.dot(M) + assert W.shape == (S,N) + + if (dtype is not None): + W = W.astype(dtype) + + update_cache(cache_file, key, W) self.W = W - self.U = U - self.I = I def __call__(self, F): return self.W.dot(F.ravel()).reshape(self.s) @@ -595,6 +658,13 @@ class PolynomialSubgridInterpolator(object): def generate_subgrid_restrictor(self): return PolynomialSubgridRestrictor(subgrid_interpolator=self) + @property + def Wr(self): + assert self.W.shape == (self.S, self.N) + view = (slice(0,-1,None),)*self.dim + (slice(None, None, None),)*self.dim + Wr = self.W.reshape(self.s+self.n)[view].reshape(self.GR, self.N).copy() + return Wr + class PolynomialSubgridRestrictor(object): def __init__(self, subgrid_interpolator): @@ -677,6 +747,31 @@ if __name__ == '__main__': print 'Biquintic (FDC2)' print GI1(F) print + + F = [[0,1,1,0], + [0,1,1,0]] + F = np.asarray(F) + + print 'Solving linear/cubic...' + PI0 = PolynomialInterpolator(dim=2, deg=(1,3), fd=2, verbose=False) + GI0 = PI0.generate_subgrid_interpolator(grid_ratio=grid_ratio, dtype=np.float64) + print 'Linear/Cubic (FDC2)' + print GI0(F) + print + + F = [[0,0], + [1,1], + [1,1], + [0,0]] + F = np.asarray(F) + + print 'Solving cubic/linear...' + PI0 = PolynomialInterpolator(dim=2, deg=(3,1), fd=2, verbose=False) + GI0 = PI0.generate_subgrid_interpolator(grid_ratio=grid_ratio, dtype=np.float64) + print 'Cubic/Linear (FDC2)' + print GI0(F) + print + F = [[0,0,0,0,0,0], [0,0,0,0,0,0], @@ -714,6 +809,20 @@ if __name__ == '__main__': print GI3(F) print + print 'Solving septic2/nonic2 ...' + 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)) + GI5 = PI5.generate_subgrid_interpolator(grid_ratio=grid_ratio, dtype=np.float64) + print 'septic/nonic (FDC2/FDC4)' + print GI5(F) + print + # 3D test grid_ratio = (2,2,2) print 'Solving trilinear...' diff --git a/hysop/operator/base/spatial_filtering.py b/hysop/operator/base/spatial_filtering.py index 401a02e1c..a73b8e975 100644 --- a/hysop/operator/base/spatial_filtering.py +++ b/hysop/operator/base/spatial_filtering.py @@ -2,6 +2,7 @@ @file advection.py RestrictionFilter operator generator. """ +import numpy as np from hysop.constants import Implementation from hysop.methods import Remesh from hysop.numerics.remesh.remesh import RemeshKernel @@ -39,11 +40,17 @@ class SpatialFilterBase(object): input_fields={input_field: input_topo}, output_fields={output_field: output_topo}, **kwds) - assert (input_field.dim == output_field.dim) - self.Fin = input_field - self.Fout = output_field - self.dim = input_field.dim - self.dtype = find_common_dtype(input_field.dtype, output_field.dtype) + + Fin = input_field + Fout = output_field + assert (Fin.dim == Fout.dim) + assert (Fin.lboundaries == Fout.lboundaries).all() + assert (Fin.rboundaries == Fout.rboundaries).all() + assert (Fin.periodicity == Fout.periodicity).all() + self.Fin = Fin + self.Fout = Fout + self.dim = Fin.dim + self.dtype = find_common_dtype(Fin.dtype, Fout.dtype) self.iratio = None # will be set in get_field_requirements self.grid_ratio = None # will be set in discretize @@ -58,6 +65,7 @@ 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): @@ -381,7 +389,7 @@ class PolynomialInterpolationFilterBase(PolynomialInterpolationMethod, Interpola @debug def get_field_requirements(self): reqs = super(PolynomialInterpolationFilterBase, self).get_field_requirements() - required_input_ghosts = (self.polynomial_interpolator.ghosts+1,)*self.dim + required_input_ghosts = np.add(self.polynomial_interpolator.ghosts, self.Fin.periodicity) Fin_topo, Fin_requirements = reqs.get_input_requirement(self.Fin) Fin_requirements.min_ghosts = required_input_ghosts self.required_input_ghosts = required_input_ghosts @@ -392,8 +400,9 @@ class PolynomialInterpolationFilterBase(PolynomialInterpolationMethod, Interpola return 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) self.subgrid_interpolator = psi - self.fin = dFin.sdata[dFin.local_slices(ghosts=self.required_input_ghosts)].handle + self.fin = dFin.sdata[dFin.local_slices(ghosts=ghosts)].handle self.fout = dFout.sdata[dFout.compute_slices].handle diff --git a/hysop/tools/warning.py b/hysop/tools/warning.py index 18da7991b..cb040bf5b 100644 --- a/hysop/tools/warning.py +++ b/hysop/tools/warning.py @@ -17,6 +17,12 @@ class HysopPerformanceWarning(HysopWarning): """ pass +class HysopCacheWarning(HysopWarning): + """ + Custom warning class for hysop caching. + """ + pass + def configure_hysop_warnings(action): """ Configure hysop warnings. -- GitLab