def test_beam(): """ Test that the convolution doesn't shift the center (at least when the kernel is constructed with gauss2d_kernel). Note this test fails if you use scipy.fftconvolve because the kernels are treated differently. """ n = 50 synth = beam.gauss2d_kernel(n, 3.) _synth = beam.convolve_fft(synth, synth) assert numpy.argmax(synth) == numpy.argmax(_synth), \ 'Beam kernel shifted the center for an even image size.' n = 51 synth = beam.gauss2d_kernel(n, 3.) _synth = beam.convolve_fft(synth, synth) assert numpy.argmax(synth) == numpy.argmax(_synth), \ 'Beam kernel shifted the center for an odd image size.'
def test_disk_derivative_nosig(): disk = AxisymmetricDisk() # Ensure that center is offset from 0,0 because of derivative calculation when r==0. disk.par[:2] = 0.1 # Use a slowly rising rotation curve. More quickly rising rotation curves # show a greater difference between the finite-difference and direct # derivative calculations after the convolution. disk.par[-1] = 20. # Finite difference test steps # x0 y0 pa inc vsys vinf hv dp = numpy.array([0.0001, 0.0001, 0.001, 0.001, 0.001, 0.001, 0.0001]) n = 101 x = numpy.arange(n, dtype=float)[::-1] - n//2 y = numpy.arange(n, dtype=float) - n//2 x, y = numpy.meshgrid(x, y) v, dv = disk.deriv_model(disk.par, x=x, y=y) vp = numpy.empty(v.shape+(disk.par.size,), dtype=float) p = disk.par.copy() for i in range(disk.par.size): _p = p.copy() _p[i] += dp[i] # These calls to `model` reuse the previously provided x and y vp[...,i] = disk.model(_p) disk._set_par(p) fd_dv = (vp - v[...,None])/dp[None,:] for i in range(disk.par.size): assert numpy.allclose(dv[...,i], fd_dv[...,i], rtol=0., atol=1e-4), \ f'Finite difference produced different derivative for parameter {i+1}!' # Now include the beam-smearing beam = gauss2d_kernel(n, 3.) try: cnvfftw = ConvolveFFTW(beam.shape) except: cnvfftw = None v, dv = disk.deriv_model(disk.par, x=x, y=y, beam=beam, cnvfftw=cnvfftw) vp = numpy.empty(v.shape+(disk.par.size,), dtype=float) p = disk.par.copy() for i in range(disk.par.size): _p = p.copy() _p[i] += dp[i] # These calls to `model` reuse the previously provided x, y, beam, and # cnvfftw vp[...,i] = disk.model(_p) disk._set_par(p) fd_dv = (vp - v[...,None])/dp[None,:] for i in range(disk.par.size): assert numpy.allclose(dv[...,i], fd_dv[...,i], rtol=0., atol=1e-4), \ f'Finite difference produced different derivative for parameter {i+1}!'
def test_convolve(): """ Test that the results of the convolution match astropy. """ synth = beam.gauss2d_kernel(73, 3.) astsynth = convolution.convolve_fft(synth, synth, fft_pad=False, psf_pad=False, boundary='wrap') intsynth = beam.convolve_fft(synth, synth) assert numpy.all(numpy.isclose( astsynth, intsynth)), 'Difference wrt astropy convolution'
def test_disk(): disk = AxisymmetricDisk() disk.par[:2] = 0. # Ensure that the center is at 0,0 disk.par[-1] = 1. # Put in a quickly rising RC n = 51 x = numpy.arange(n, dtype=float)[::-1] - n//2 y = numpy.arange(n, dtype=float) - n//2 x, y = numpy.meshgrid(x, y) vel = disk.model(disk.par, x=x, y=y) beam = gauss2d_kernel(n, 3.) _vel = disk.model(disk.par, x=x, y=y, beam=beam) assert numpy.isclose(vel[n//2,n//2], _vel[n//2,n//2]), 'Smearing moved the center.'
def test_fft(): synth = beam.gauss2d_kernel(73, 3.) synth_fft = numpy.fft.fftn(numpy.fft.ifftshift(synth)) _convolve_fft = beam.ConvolveFFTW(synth.shape) # Compare numpy with direct vs. FFT kernel input synth2 = beam.convolve_fft(synth, synth) _synth2 = beam.convolve_fft(synth, synth_fft, kernel_fft=True) assert numpy.allclose(synth2, _synth2), 'Difference if FFT is passed for numpy' # Compare numpy and FFTW with direct input _synth2 = _convolve_fft(synth, synth) assert numpy.allclose(synth2, _synth2), 'Difference between numpy and FFTW' # Compare FFTW with direct vs. FFT kernel input synth2 = _convolve_fft(synth, synth_fft, kernel_fft=True) assert numpy.allclose(synth2, _synth2), 'Difference if FFT is passed for FFTW' # Compare numpy and FFTW with direct input and FFT output synth2 = beam.convolve_fft(synth, synth, return_fft=True) _synth2 = _convolve_fft(synth, synth, return_fft=True) assert numpy.allclose(synth2, _synth2), 'Difference between numpy and FFTW'
def test_disk_derivative(): disk = AxisymmetricDisk(rc=HyperbolicTangent(), dc=Exponential()) # Ensure that center is offset from 0,0 because of derivative calculation when r==0. disk.par[:2] = 0.1 # Use a slowly rising rotation curve. More quickly rising rotation curves # show a greater difference between the finite-difference and direct # derivative calculations after the convolution. disk.par[-3] = 20. # Finite difference test steps # x0 y0 pa inc vsys vinf hv sig0 hsig dp = numpy.array([0.0001, 0.0001, 0.001, 0.001, 0.001, 0.001, 0.0001, 0.001, 0.0001]) n = 101 x = numpy.arange(n, dtype=float)[::-1] - n//2 y = numpy.arange(n, dtype=float) - n//2 x, y = numpy.meshgrid(x, y) v, sig, dv, dsig = disk.deriv_model(disk.par, x=x, y=y) vp = numpy.empty(v.shape+(disk.par.size,), dtype=float) sigp = numpy.empty(v.shape+(disk.par.size,), dtype=float) p = disk.par.copy() for i in range(disk.par.size): _p = p.copy() _p[i] += dp[i] # These calls to `model` reuse the previously provided x and y vp[...,i], sigp[...,i] = disk.model(_p) disk._set_par(p) fd_dv = (vp - v[...,None])/dp[None,:] fd_dsig = (sigp - sig[...,None])/dp[None,:] for i in range(disk.par.size): assert numpy.allclose(dv[...,i], fd_dv[...,i], rtol=0., atol=1e-4), \ f'Finite difference produced different velocity derivative for parameter {i+1}!' # The precision is worse for dsig/dx0 and dsig/dy0 at x=y=0.0. Not sure # why. The larger atol is to account for this. assert numpy.allclose(dsig[...,i], fd_dsig[...,i], rtol=0., atol=3e-3), \ f'Finite difference produced different sigma derivative for parameter {i+1}!' # Now include the beam-smearing beam = gauss2d_kernel(n, 3.) try: cnvfftw = ConvolveFFTW(beam.shape) except: cnvfftw = None v, sig, dv, dsig = disk.deriv_model(disk.par, x=x, y=y, beam=beam, cnvfftw=cnvfftw) vp = numpy.empty(v.shape+(disk.par.size,), dtype=float) sigp = numpy.empty(v.shape+(disk.par.size,), dtype=float) p = disk.par.copy() for i in range(disk.par.size): _p = p.copy() _p[i] += dp[i] # These calls to `model` reuse the previously provided x, y, beam, and # cnvfftw vp[...,i], sigp[...,i] = disk.model(_p) disk._set_par(p) fd_dv = (vp - v[...,None])/dp[None,:] fd_dsig = (sigp - sig[...,None])/dp[None,:] for i in range(disk.par.size): assert numpy.allclose(dv[...,i], fd_dv[...,i], rtol=0., atol=1e-4), \ f'Finite difference produced different derivative for parameter {i+1}!' # Apparently the convolution smooths out the difference seen in the test above assert numpy.allclose(dsig[...,i], fd_dsig[...,i], rtol=0., atol=1e-4), \ f'Finite difference produced different sigma derivative for parameter {i+1}!'
def test_smear(): n = 51 x = numpy.arange(n, dtype=float)[::-1] - n // 2 y = numpy.arange(n, dtype=float) - n // 2 x, y = numpy.meshgrid(x, y) r, theta = projected_polar(x, y, *numpy.radians([45., 30.])) rc = oned.HyperbolicTangent(par=numpy.array([100., 1.])) sig = oned.Exponential(par=numpy.array([100., 20.])) sb = oned.Sersic1D(par=numpy.array([1., 10., 1.])) sb_field = sb.sample(r) vel_field = rc.sample(r) * numpy.cos(theta) sig_field = sig.sample(r) cnvlv = beam.ConvolveFFTW(x.shape) synth = beam.gauss2d_kernel(n, 3.) synth_fft = cnvlv.fft(synth, shift=True) vel_smear = beam.smear(vel_field, synth)[1] _vel_smear = beam.smear(vel_field, synth, cnvfftw=cnvlv)[1] assert numpy.allclose( vel_smear, _vel_smear), 'Velocity-field-only convolution difference.' vel_smear = beam.smear(vel_field, synth)[1] _vel_smear = beam.smear(vel_field, synth_fft, beam_fft=True)[1] assert numpy.allclose(vel_smear, _vel_smear), \ 'Velocity-field difference w/ vs. w/o precomputing the beam FFT for numpy.' vel_smear = beam.smear(vel_field, synth, cnvfftw=cnvlv)[1] _vel_smear = beam.smear(vel_field, synth_fft, beam_fft=True, cnvfftw=cnvlv)[1] assert numpy.allclose(vel_smear, _vel_smear), \ 'Velocity-field difference w/ vs. w/o precomputing the beam FFT for ConvolveFFTW.' sb_smear, vel_smear, _ = beam.smear(vel_field, synth, sb=sb_field) _sb_smear, _vel_smear, _ = beam.smear(vel_field, synth, sb=sb_field, cnvfftw=cnvlv) assert numpy.allclose(sb_smear, _sb_smear), 'SB+Vel convolution difference in SB.' assert numpy.allclose(vel_smear, _vel_smear), 'SB+Vel convolution difference in Vel.' sb_smear, vel_smear, sig_smear = beam.smear(vel_field, synth, sb=sb_field, sig=sig_field) _sb_smear, _vel_smear, _sig_smear = beam.smear(vel_field, synth, sb=sb_field, sig=sig_field, cnvfftw=cnvlv) assert numpy.allclose( sb_smear, _sb_smear), 'SB+Vel+Sig convolution difference in SB.' assert numpy.allclose( vel_smear, _vel_smear), 'SB+Vel+Sig convolution difference in vel.' assert numpy.allclose( sig_smear, _sig_smear), 'SB+Vel+Sig convolution difference in sig.'