def interpolate_to_points(self, ff, x, y, fix_r=False): key = self.get_interpolation_key(x, y, fix_r) p = self.registered_partitions[key] # get the category numbers c1n, c2n, c3n = p.get_Ns() # initialize output vector output = np.empty(x.size) # interpolate appropriate portion with grid (polynomial, for now...) if c1n > 0: zone1 = p.zone1 funch = np.fft.fft2(ff.get_smoothed_grid_value()) out = np.zeros(p.zone1_N, dtype=complex) diagnostic = finufft.nufft2d2(p.x_transf, p.y_transf, funch, out, isign=1, eps=1e-14, modeord=1) out.real/np.prod(funch.shape) output[zone1] = out.real/np.prod(funch.shape) if c2n > 0: for ind in range(self.N): ebdy = self[ind] z2l = p.zone2l[ind] z2transfr = p.zone2_transfr[ind] z2t = p.zone2t[ind] fr = ff[ind] output[z2l] = ebdy.interpolate_radial_to_points(fr, z2transfr, z2t) # fill in those that are exterior with nan if c3n > 0: for z3 in p.zone3l: output[z3] = np.nan return output
def interpolate_to_points(self, ff, x, y, fix_r=False, dzl=None, gil=None): key = self.get_interpolation_key(x, y, fix_r, dzl, gil) p = self.registered_partitions[key] # get the category numbers c1n, c2n, c3n = p.get_Ns() # initialize output vector output = np.empty(x.size) # interpolate appropriate portion with grid (polynomial, for now...) if c1n > 0: if False: zone1 = p.zone1 f = ff.get_grid_value() grid = self.grid lbds = [self.grid.x_bounds[0], self.grid.y_bounds[0]] ubds = [self.grid.x_bounds[1], self.grid.y_bounds[1]] hs = [self.grid.xh, self.grid.yh] interp = fast_interp.interp2d(lbds, ubds, hs, f, k=7, p=[True, True]) output[zone1] = interp(x[zone1], y[zone1]) else: # HERE zone1 = p.zone1 funch = np.fft.fft2(ff.get_smoothed_grid_value()) out = np.zeros(p.zone1_N, dtype=complex) if old_nufft: diagnostic = finufftpy.nufft2d2(p.x_transf, p.y_transf, out, 1, 1e-14, funch, modeord=1) else: diagnostic = finufft.nufft2d2(p.x_transf, p.y_transf, funch, out, isign=1, eps=1e-14, modeord=1) out.real / np.prod(funch.shape) output[zone1] = out.real / np.prod(funch.shape) if c2n > 0: for ind in range(self.N): ebdy = self[ind] z2l = p.zone2l[ind] z2transfr = p.zone2_transfr[ind] z2t = p.zone2t[ind] fr = ff[ind] output[z2l] = ebdy.interpolate_radial_to_points( fr, z2transfr, z2t) # fill in those that are exterior with nan if c3n > 0: for z3 in p.zone3l: output[z3] = np.nan return output
def interpolate_radial_to_points(self, fr, transf_r, t): """ Interpolate the radial function fr defined on this annulus to points with coordinates (r, t) given by transf_r, t """ self.interpolation_hold[:self.M, :] = fr self.interpolation_hold[self.M:, :] = fr[::-1] funch = np.fft.fft2( self.interpolation_hold) * self.interpolation_modifier funch[self.M] = 0.0 out = np.empty(t.size, dtype=complex) if old_nufft: diagnostic = finufftpy.nufft2d2(transf_r, t, out, 1, 1e-14, funch, modeord=1) else: diagnostic = finufft.nufft2d2(transf_r, t, funch, out, isign=1, eps=1e-14, modeord=1) vals = out.real / np.prod(funch.shape) return vals
def nufft_interpolate_grid_to_interface(self, f): """ Call through interpolate_grid_to_interface """ funch = np.fft.fft2(f) out = np.zeros(self.interfaces_x_transf.size, dtype=complex) diagnostic = finufft.nufft2d2(self.interfaces_x_transf, self.interfaces_y_transf, funch, out, isign=1, eps=1e-14, modeord=1) return out.real/np.prod(funch.shape)
def test_nufft2d2(seed=42, iflag=1): np.random.seed(seed) ms = 100 mt = 89 n = int(1e3) tol = 1.0e-9 x = np.random.uniform(-np.pi, np.pi, n) y = np.random.uniform(-np.pi, np.pi, n) c = np.random.uniform(-1.0, 1.0, n) + 1.0j * np.random.uniform(-1.0, 1.0, n) f = finufft.nufft2d1(x, y, c, ms, mt, eps=tol, iflag=iflag) c = finufft.nufft2d2(x, y, f, eps=tol, iflag=iflag) c0 = interface.dirft2d2(x, y, f, iflag=iflag) assert np.all(np.abs((c - c0) / c0) < 1e-6)
def nuifft2(field, fx, fy, sign=1, eps=10**(-12)): """ """ if np.__name__ == 'cupy': fx = np.asnumpy(fx).astype(np.float64) fy = np.asnumpy(fy).astype(np.float64) image = np.asnumpy(np.copy(field)).astype(np.complex128) else: image = np.copy(field).astype(np.complex128) result = finufft.nufft2d2(fx.flatten(), fy.flatten(), image, eps=eps, isign=sign) result = result.reshape(field.shape) if np.__name__ == 'cupy': result = np.asarray(result) return result
def interpolate_radial_to_points(self, fr, transf_r, t): """ Interpolate the radial function fr defined on this annulus to points with coordinates (r, t) given by transf_r, t """ # should i define a 2D NUFFT Interpolater using the plan functions? # this might be useful if this is interpolated over and over again... # will think about self.interpolation_hold[:self.M,:] = fr self.interpolation_hold[self.M:,:] = fr[::-1] funch = np.fft.fft2(self.interpolation_hold)*self.interpolation_modifier funch[self.M] = 0.0 out = np.empty(t.size, dtype=complex) diagnostic = finufft.nufft2d2(transf_r, t, funch, out, isign=1, eps=1e-14, modeord=1) vals = out.real/np.prod(funch.shape) return vals
def nufft2(field, fx, fy, size=None, sign=1, eps=10**(-12)): """ A definition to take 2D Non-Uniform Fast Fourier Transform (NUFFT). Parameters ---------- field : ndarray Input field. fx : ndarray Frequencies along x axis. fy : ndarray Frequencies along y axis. size : list Size. sign : float Sign of the exponential used in NUFFT kernel. eps : float Accuracy of NUFFT. Returns ---------- result : ndarray Inverse NUFFT of the input field. """ if np.__name__ == 'cupy': fx = np.asnumpy(fx).astype(np.float64) fy = np.asnumpy(fy).astype(np.float64) image = np.asnumpy(np.copy(field)).astype(np.complex128) else: image = np.copy(field).astype(np.complex128) result = finufft.nufft2d2(fx.flatten(), fy.flatten(), image, eps=eps, isign=sign) if type(size) == type(None): result = result.reshape(field.shape) else: result = result.reshape(size) if np.__name__ == 'cupy': result = np.asarray(result) return result
def accuracy_speed_tests(num_nonuniform_points, num_uniform_points, eps): nj, nk = int(num_nonuniform_points), int(num_nonuniform_points) iflag = 1 num_samples = int( np.minimum(5, num_uniform_points * 0.5 + 1) ) # number of outputs used for estimating accuracy; is small for speed print( 'Accuracy and speed tests for %d nonuniform points and eps=%g (error estimates use %d samples per run)' % (num_nonuniform_points, eps, num_samples)) # for doing the error estimates Xest = np.zeros(num_samples, dtype=np.complex128) Xtrue = np.zeros(num_samples, dtype=np.complex128) ###### 1-d cases ........................................................ ms = int(num_uniform_points) xj = np.random.rand(nj) * 2 * math.pi - math.pi cj = np.random.rand(nj) + 1j * np.random.rand(nj) fk = np.zeros([ms], dtype=np.complex128) timer = time.time() ret = finufft.nufft1d1(xj, cj, ms, fk, eps, iflag) elapsed = time.time() - timer k = np.arange(-np.floor(ms / 2), np.floor((ms - 1) / 2 + 1)) for ii in np.arange(0, num_samples): Xest[ii] = np.sum(cj * np.exp(1j * k[ii] * xj)) Xtrue[ii] = fk[ii] print_report('finufft1d1', elapsed, Xest, Xtrue, nj) xj = np.random.rand(nj) * 2 * math.pi - math.pi cj = np.zeros([nj], dtype=np.complex128) fk = np.random.rand(ms) + 1j * np.random.rand(ms) timer = time.time() ret = finufft.nufft1d2(xj, fk, cj, eps, iflag) elapsed = time.time() - timer k = np.arange(-np.floor(ms / 2), np.floor((ms - 1) / 2 + 1)) for ii in np.arange(0, num_samples): Xest[ii] = np.sum(fk * np.exp(1j * k * xj[ii])) Xtrue[ii] = cj[ii] print_report('finufft1d2', elapsed, Xest, Xtrue, nj) x = np.random.rand(nj) * 2 * math.pi - math.pi c = np.random.rand(nj) + 1j * np.random.rand(nj) s = np.random.rand(nk) * 2 * math.pi - math.pi f = np.zeros([nk], dtype=np.complex128) timer = time.time() ret = finufft.nufft1d3(x, c, s, f, eps, iflag) elapsed = time.time() - timer for ii in np.arange(0, num_samples): Xest[ii] = np.sum(c * np.exp(1j * s[ii] * x)) Xtrue[ii] = f[ii] print_report('finufft1d3', elapsed, Xest, Xtrue, nj + nk) ###### 2-d cases .................................................... ms = int(np.ceil(np.sqrt(num_uniform_points))) mt = ms xj = np.random.rand(nj) * 2 * math.pi - math.pi yj = np.random.rand(nj) * 2 * math.pi - math.pi cj = np.random.rand(nj) + 1j * np.random.rand(nj) fk = np.zeros([ms, mt], dtype=np.complex128) timer = time.time() ret = finufft.nufft2d1(xj, yj, cj, (ms, mt), fk, eps, iflag) elapsed = time.time() - timer Ks, Kt = np.mgrid[-np.floor(ms / 2):np.floor((ms - 1) / 2 + 1), -np.floor(mt / 2):np.floor((mt - 1) / 2 + 1)] for ii in np.arange(0, num_samples): Xest[ii] = np.sum( cj * np.exp(1j * (Ks.ravel()[ii] * xj + Kt.ravel()[ii] * yj))) Xtrue[ii] = fk.ravel()[ii] print_report('finufft2d1', elapsed, Xest, Xtrue, nj) ## 2d1many: ndata = 8 # how many vectors to do cj = np.array(np.random.rand(ndata, nj) + 1j * np.random.rand(ndata, nj)) fk = np.zeros([ndata, ms, mt], dtype=np.complex128) timer = time.time() ret = finufft.nufft2d1(xj, yj, cj, ms, fk, eps, iflag) elapsed = time.time() - timer dtest = ndata - 1 # which of the ndata to test (in 0,..,ndata-1) for ii in np.arange(0, num_samples): Xest[ii] = np.sum( cj[dtest, :] * np.exp(1j * (Ks.ravel()[ii] * xj + Kt.ravel()[ii] * yj)) ) # note fortran-ravel-order needed throughout - mess. Xtrue[ii] = fk.ravel()[ ii + dtest * ms * mt] # hack the offset in fk array - has to be better way print_report('finufft2d1many', elapsed, Xest, Xtrue, ndata * nj) # 2d2 xj = np.random.rand(nj) * 2 * math.pi - math.pi yj = np.random.rand(nj) * 2 * math.pi - math.pi cj = np.zeros([nj], dtype=np.complex128) fk = np.random.rand(ms, mt) + 1j * np.random.rand(ms, mt) timer = time.time() ret = finufft.nufft2d2(xj, yj, fk, cj, eps, iflag) elapsed = time.time() - timer Ks, Kt = np.mgrid[-np.floor(ms / 2):np.floor((ms - 1) / 2 + 1), -np.floor(mt / 2):np.floor((mt - 1) / 2 + 1)] for ii in np.arange(0, num_samples): Xest[ii] = np.sum(fk * np.exp(1j * (Ks * xj[ii] + Kt * yj[ii]))) Xtrue[ii] = cj[ii] print_report('finufft2d2', elapsed, Xest, Xtrue, nj) # 2d2many (using same ndata and dtest as 2d1many; see above) cj = np.zeros([ndata, nj], dtype=np.complex128) fk = np.array( np.random.rand(ndata, ms, mt) + 1j * np.random.rand(ndata, ms, mt)) timer = time.time() ret = finufft.nufft2d2(xj, yj, fk, cj, eps, iflag) elapsed = time.time() - timer for ii in np.arange(0, num_samples): Xest[ii] = np.sum(fk[dtest, :, :] * np.exp(1j * (Ks * xj[ii] + Kt * yj[ii]))) Xtrue[ii] = cj[dtest, ii] print_report('finufft2d2many', elapsed, Xest, Xtrue, ndata * nj) # 2d3 x = np.random.rand(nj) * 2 * math.pi - math.pi y = np.random.rand(nj) * 2 * math.pi - math.pi c = np.random.rand(nj) + 1j * np.random.rand(nj) s = np.random.rand(nk) * 2 * math.pi - math.pi t = np.random.rand(nk) * 2 * math.pi - math.pi f = np.zeros([nk], dtype=np.complex128) timer = time.time() ret = finufft.nufft2d3(x, y, c, s, t, f, eps, iflag) elapsed = time.time() - timer for ii in np.arange(0, num_samples): Xest[ii] = np.sum(c * np.exp(1j * (s[ii] * x + t[ii] * y))) Xtrue[ii] = f[ii] print_report('finufft2d3', elapsed, Xest, Xtrue, nj + nk) ###### 3-d cases ............................................................ ms = int(np.ceil(num_uniform_points**(1.0 / 3))) mt = ms mu = ms xj = np.random.rand(nj) * 2 * math.pi - math.pi yj = np.random.rand(nj) * 2 * math.pi - math.pi zj = np.random.rand(nj) * 2 * math.pi - math.pi cj = np.random.rand(nj) + 1j * np.random.rand(nj) fk = np.zeros([ms, mt, mu], dtype=np.complex128) timer = time.time() ret = finufft.nufft3d1(xj, yj, zj, cj, fk.shape, fk, eps, iflag) elapsed = time.time() - timer Ks, Kt, Ku = np.mgrid[-np.floor(ms / 2):np.floor((ms - 1) / 2 + 1), -np.floor(mt / 2):np.floor((mt - 1) / 2 + 1), -np.floor(mu / 2):np.floor((mu - 1) / 2 + 1)] for ii in np.arange(0, num_samples): Xest[ii] = np.sum(cj * np.exp( 1j * (Ks.ravel()[ii] * xj + Kt.ravel()[ii] * yj + Ku.ravel()[ii] * zj))) Xtrue[ii] = fk.ravel()[ii] print_report('finufft3d1', elapsed, Xest, Xtrue, nj) xj = np.random.rand(nj) * 2 * math.pi - math.pi yj = np.random.rand(nj) * 2 * math.pi - math.pi zj = np.random.rand(nj) * 2 * math.pi - math.pi cj = np.zeros([nj], dtype=np.complex128) fk = np.random.rand(ms, mt, mu) + 1j * np.random.rand(ms, mt, mu) timer = time.time() ret = finufft.nufft3d2(xj, yj, zj, fk, cj, eps, iflag) elapsed = time.time() - timer Ks, Kt, Ku = np.mgrid[-np.floor(ms / 2):np.floor((ms - 1) / 2 + 1), -np.floor(mt / 2):np.floor((mt - 1) / 2 + 1), -np.floor(mu / 2):np.floor((mu - 1) / 2 + 1)] for ii in np.arange(0, num_samples): Xest[ii] = np.sum( fk * np.exp(1j * (Ks * xj[ii] + Kt * yj[ii] + Ku * zj[ii]))) Xtrue[ii] = cj[ii] print_report('finufft3d2', elapsed, Xest, Xtrue, nj) x = np.random.rand(nj) * 2 * math.pi - math.pi y = np.random.rand(nj) * 2 * math.pi - math.pi z = np.random.rand(nj) * 2 * math.pi - math.pi c = np.random.rand(nj) + 1j * np.random.rand(nj) s = np.random.rand(nk) * 2 * math.pi - math.pi t = np.random.rand(nk) * 2 * math.pi - math.pi u = np.random.rand(nk) * 2 * math.pi - math.pi f = np.zeros([nk], dtype=np.complex128) timer = time.time() ret = finufft.nufft3d3(x, y, z, c, s, t, u, f, eps, iflag) elapsed = time.time() - timer for ii in np.arange(0, num_samples): Xest[ii] = np.sum(c * np.exp(1j * (s[ii] * x + t[ii] * y + u[ii] * z))) Xtrue[ii] = f[ii] print_report('finufft3d3', elapsed, Xest, Xtrue, nj + nk)
def __init__(self, gf, fs, ifs, h, spread_width, kernel_kwargs=None, funcgen_tol=1e-10, inline_core=True): """ Backend class for re-usable 'ewald' sum grid evaluation for reusability, the grid must have the same h and the ewald sum must use the same spread width gf: numba callable greens function, gf(r) fs: Fourier symbol for operator, fs(kx, ky) ifs: Inverse Fourier symbol for operator, ifs(kx, ky) h: grid spacing spread_width: width to do spreading on for Laplace, 15 gives ~7 digits 20 gives ~10 digits can't seem to do much better than that, right now kernel_kwargs: dict of arguments to be passed to gf, fs, ifs, tsgf functions funcgen_tol: tolerance for function generator representation of functions used in interior spread funciton. can't seem to beat ~10 digits overall now, so no real reason to do more than that inline_core: whether to inline the function generator functions into the compiled ewald functions (inlining may speed things up but slows compilation time, sometimes dramatically) """ self.kernel_kwargs = {} if kernel_kwargs is None else kernel_kwargs self.gf = lambda r: gf(r, **self.kernel_kwargs) self.fourier_symbol = lambda kx, ky: fs(kx, ky, **self.kernel_kwargs) self.inverse_fourier_symbol = lambda kx, ky: ifs( kx, ky, **self.kernel_kwargs) self.h = h self.spread_width = spread_width self.funcgen_tol = funcgen_tol self.inline_core = inline_core # construct mollifier self.mollifier = SlepianMollifier(2 * self.spread_width) self.ssw = self.spread_width * self.h # screened greens function _excisor_gf = lambda d: excisor(d, 0.0, self.ssw, self.mollifier ) * self.gf(d) try: self.ex_funcgen = FunctionGenerator(_excisor_gf, 0.0, self.ssw, tol=self.funcgen_tol, inline_core=self.inline_core) self.excisor_gf = self.ex_funcgen.get_base_function(check=False) except: raise Exception( 'Failed constructing FunctionGenerator function for mollifier') # construct differential operator applied to residual of screened greens function _sn = 4 * self.spread_width _sgv = np.linspace(0, 4 * self.ssw, _sn, endpoint=False) _sgx, _sgy = np.meshgrid(_sgv, _sgv, indexing='ij') _skv = np.fft.fftfreq(_sn, self.h / (2 * np.pi)) _skx, _sky = np.meshgrid(_skv, _skv, indexing='ij') _slap = self.fourier_symbol(_skx, _sky) pt = np.array([[2 * self.ssw], [2 * self.ssw]]) targ = np.row_stack([_sgx.ravel(), _sgy.ravel()]) u = gf_apply(self.gf, pt[0], pt[1], targ[0], targ[1], np.array([ 1.0, ])).reshape(_sn, _sn) u[_sn // 2, _sn // 2] = 0.0 dist = np.hypot(_sgx - 2 * self.ssw, _sgy - 2 * self.ssw) dec1 = excisor(dist, 0.0, self.ssw, self.mollifier) dec2 = excisor(dist, self.ssw, 2 * self.ssw, self.mollifier) uf = u * (1 - dec1) * dec2 self.do_ufd = ifft2(fft2(uf) * _slap).real # get an interpolater for this _ax = np.linspace(np.pi, 1.5 * np.pi, 1000) _ay = np.repeat(np.pi, _ax.size) _ar = np.linspace(0, self.ssw, _ax.size) _fh = fft2(self.do_ufd) / (_sn * _sn) out = finufft.nufft2d2(_ax, _ay, _fh, isign=1, eps=1e-15, modeord=1) self._do_ufd_interpolater = sp.interpolate.InterpolatedUnivariateSpline( _ar, out.real, k=5, bbox=[0, self.ssw], ext=1) try: self.do_ufd_funcgen = FunctionGenerator( self._do_ufd_interpolater, 0.0, self.ssw, tol=self.funcgen_tol, inline_core=self.inline_core) self.do_ufd_interpolater = self.do_ufd_funcgen.get_base_function( check=False) except: raise Exception( 'Failed constructing FunctionGenerator function for laplacian of greens function times mollifier' )