예제 #1
0
def iqdht(k: np.ndarray, f: np.ndarray, order: int = 0) -> Tuple[np.ndarray, np.ndarray]:
    """Perform a inverse quasi-discrete Hankel transform of the function ``f`` (sampled at points
    ``k``) and return the transformed function and its sample points in radial space.

    If you have the transform on a frequency axis (as opposed to a :math:`k`-axis), the
    :math:`k`-axis can be calculated using :math:`k = 2\\pi{}f`.

    .. warning::
        This method is a convenience wrapper for :meth:`.HankelTransform.iqdht`, but incurs a
        significant overhead in calculating the :class:`.HankelTransform` object. If you
        are performing multiple transforms on the same grid, it will be much quicker to
        construct a single :class:`.HankelTransform` object and call
        :meth:`.HankelTransform.iqdht` multiple times.

    :param k: The :math:`k` coordinates at which the function is sampled
    :type k: :class:`numpy.ndarray`
    :param f: The value of the function to be transformed.
    :type f: :class:`numpy.ndarray`
    :param order: The order of the Hankel Transform to perform. Defaults to 0.
    :return: A tuple containing the radial coordinates of the transformed function and its values
    :rtype: (:class:`numpy.ndarray`, :class:`numpy.ndarray`)
    """
    transformer = HankelTransform(order=order, k_grid=k)
    f_transform = transformer.to_transform_k(f)
    ht = transformer.iqdht(f_transform)
    return transformer.r, ht
예제 #2
0
def test_round_trip_3d(two_d_size: int, axis: int, radius: np.ndarray,
                       transformer: HankelTransform):
    dims = np.ones(3, np.int) * two_d_size
    dims[axis] = radius.size
    func = np.random.random(dims)
    ht = transformer.qdht(func, axis=axis)
    reconstructed = transformer.iqdht(ht, axis=axis)
    assert np.allclose(func, reconstructed)
예제 #3
0
파일: test_hankel.py 프로젝트: ng110/pyhank
def test_inverse_gaussian(a: float, radius: np.ndarray):
    # Note the definition in Guizar-Sicairos varies by 2*pi in
    # both scaling of the argument (so use kr rather than v) and
    # scaling of the magnitude.
    transformer = HankelTransform(order=0, radial_grid=radius)
    ht = 2*np.pi*(1 / (2 * a**2)) * np.exp(-transformer.kr**2 / (4 * a**2))
    actual_f = transformer.iqdht(ht)
    expected_f = np.exp(-a ** 2 * transformer.r ** 2)
    assert np.allclose(expected_f, actual_f)
예제 #4
0
def test_round_trip_with_interpolation(shape: Callable, radius: np.ndarray,
                                       transformer: HankelTransform):
    # the function must be smoothish for interpolation
    # to work. Random every point doesn't work
    func = shape(radius)
    func_hr = transformer.to_transform_r(func)
    ht = transformer.qdht(func_hr)
    reconstructed_hr = transformer.iqdht(ht)
    reconstructed = transformer.to_original_r(reconstructed_hr)

    assert np.allclose(func, reconstructed, rtol=2e-4)
예제 #5
0
def propagate_using_object(r: np.ndarray, field: np.ndarray) -> np.ndarray:
    transformer = HankelTransform(order=0, radial_grid=r)
    field_for_transform = transformer.to_transform_r(field)  # Resampled field
    hankel_transform = transformer.qdht(field_for_transform)

    propagated_field = np.zeros((nr, Nz), dtype=complex)
    kz = np.sqrt(k0**2 - transformer.kr**2)
    for n, z_loop in enumerate(z):
        phi_z = kz * z_loop  # Propagation phase
        hankel_transform_at_z = hankel_transform * np.exp(
            1j * phi_z)  # Apply propagation
        field_at_z_transform_grid = transformer.iqdht(
            hankel_transform_at_z)  # iQDHT
        propagated_field[:, n] = transformer.to_original_r(
            field_at_z_transform_grid)  # Interpolate output
    intensity = np.abs(propagated_field)**2
    return intensity
예제 #6
0
def test_inverse_gaussian_2d(axis: int, radius: np.ndarray):
    # Note the definition in Guizar-Sicairos varies by 2*pi in
    # both scaling of the argument (so use kr rather than v) and
    # scaling of the magnitude.
    transformer = HankelTransform(order=0, radial_grid=radius)
    a = np.linspace(2, 10)
    dims_a = np.ones(2, np.int)
    dims_a[1 - axis] = len(a)
    dims_r = np.ones(2, np.int)
    dims_r[axis] = len(transformer.r)
    a_reshaped = np.reshape(a, dims_a)
    r_reshaped = np.reshape(transformer.r, dims_r)
    kr_reshaped = np.reshape(transformer.kr, dims_r)
    ht = 2 * np.pi * (1 / (2 * a_reshaped**2)) * np.exp(-kr_reshaped**2 /
                                                        (4 * a_reshaped**2))
    actual_f = transformer.iqdht(ht, axis=axis)
    expected_f = np.exp(-a_reshaped**2 * r_reshaped**2)
    assert np.allclose(expected_f, actual_f)
예제 #7
0
def test_iqdht(engine):
    r_max = 5e-3
    nr = 512
    h = HankelTransform(0, r_max, nr)
    hm = engine.hankel_matrix(0., r_max, float(nr), nargout=1)

    dr = r_max / (nr - 1)  # Radial spacing
    nr = np.arange(0, nr)  # Radial pixels
    r = nr * dr  # Radial positions

    er = r < 1e-3
    # noinspection PyUnresolvedReferences
    er_m = matlab.double(er[np.newaxis, :].transpose().tolist())

    matlab_mode = float(3)

    matlab_value = engine.iqdht(er_m, hm, matlab_mode, nargout=1)
    python_value = h.iqdht(er)
    assert matlab_python_allclose(python_value, matlab_value)
예제 #8
0
def example():
    # Gaussian function
    def gauss1d(x, x0, fwhm):
        return np.exp(-2 * np.log(2) * ((x - x0) / fwhm) ** 2)

    nr = 1024  # Number of sample points
    r_max = .05  # Maximum radius (5cm)
    dr = r_max / (nr - 1)  # Radial spacing
    ri = np.arange(0, nr)  # Radial pixels
    r = ri * dr  # Radial positions
    beam_radius = 5e-3  # 5mm
    propagation_direction = 5000
    Nz = 200  # Number of z positions
    z_max = .25  # Maximum propagation distance
    dz = z_max / (Nz - 1)
    z = np.arange(0, Nz) * dz  # Propagation axis

    ht = HankelTransform(0, radial_grid=r)
    k_max = 2 * np.pi * ht.v_max  # Maximum K vector

    field = gauss1d(r, 0, beam_radius) * np.exp(1j * propagation_direction * r)  # Initial field
    ht_field = ht.to_transform_r(field)  # Resampled field

    transform = ht.qdht(ht_field)  # Convert from physical field to physical wavevector

    propagated_intensity = np.zeros((nr, Nz + 1))
    propagated_intensity[:, 0] = np.abs(field) ** 2
    for n in range(1, Nz):
        z_loop = z[n]
        propagation_phase = (np.sqrt(k_max ** 2 - ht.kr ** 2) - k_max) * z_loop  # Propagation phase
        propagated_transform = transform * np.exp(1j * propagation_phase)  # Apply propagation
        propagated_ht_field = ht.iqdht(propagated_transform)  # iQDHT
        propagated_field = _spline(ht.r, propagated_ht_field, r)  # Interpolate output
        propagated_intensity[:, n] = np.abs(propagated_field) ** 2

    return transform, propagated_intensity
예제 #9
0
파일: test_hankel.py 프로젝트: ng110/pyhank
def test_round_trip_2d(two_d_size: int, radius: np.ndarray, transformer: HankelTransform):
    func = np.random.random((radius.size, two_d_size))
    ht = transformer.qdht(func)
    reconstructed = transformer.iqdht(ht)
    assert np.allclose(func, reconstructed)
예제 #10
0
파일: test_hankel.py 프로젝트: ng110/pyhank
def test_round_trip(radius: np.ndarray, transformer: HankelTransform):
    func = np.random.random(radius.shape)
    ht = transformer.qdht(func)
    reconstructed = transformer.iqdht(ht)
    assert np.allclose(func, reconstructed)
예제 #11
0
# Convert from physical field to physical wavevector
EkrH = H.qdht(ErH)

# %%
# Propagate the beam - loop
# -------------------------
# Do the propagation in a loop over :math:`z`

# Pre-allocate an array for field as a function of r and z
Erz = np.zeros((nr, Nz), dtype=complex)
kz = np.sqrt(k0**2 - H.kr**2)
for i, z_loop in enumerate(z):
    phi_z = kz * z_loop  # Propagation phase
    EkrHz = EkrH * np.exp(1j * phi_z)  # Apply propagation
    ErHz = H.iqdht(EkrHz)  # iQDHT
    Erz[:, i] = H.to_original_r(ErHz)  # Interpolate output
Irz = np.abs(Erz)**2

# %%
# Plotting
# --------
# Plot the initial field and radial wavevector distribution (given by the
# Hankel transform)
plt.figure()
plt.plot(r * 1e3,
         np.abs(Er)**2, r * 1e3, np.unwrap(np.angle(Er)), H.r * 1e3,
         np.abs(ErH)**2, H.r * 1e3, np.unwrap(np.angle(ErH)), '+')
plt.title('Initial electric field distribution')
plt.xlabel('Radial co-ordinate (r) /mm')
plt.ylabel('Field intensity /arb.')
예제 #12
0
    assert np.all(dynamical_error[not_near_gamma] < -35)

# %%
# Now we will reproduce figure 3 and confirm we can replicate
# the errors in the top half of table 1.
p = 4
a = 1
transformer = HankelTransform(order=p, max_radius=2, n_points=1024)
top_hat = np.zeros_like(transformer.r)
top_hat[transformer.r <= a] = 1
func = transformer.r**p * top_hat
expected_ht = a**(p + 1) * scipybessel.jv(
    p + 1, 2 * np.pi * a * transformer.v) / transformer.v
ht = transformer.qdht(func)

retrieved_func = transformer.iqdht(ht)

# %%
# Plot the overlay as in figure 3 of |Guizar| `Guizar`_

plt.figure()
plt.subplot(2, 1, 1)
plt.plot(transformer.v, expected_ht, label='Analytical')
plt.plot(transformer.v, ht, marker='x', linestyle='None', label='QDHT')
plt.title(f'Hankel transform $f_2(v)$, order {p}')
plt.xlabel('Frequency /$v$')
plt.xlim([0, 10])
plt.legend()

plt.subplot(2, 1, 2)
plt.title('Round-trip QDHT vs analytical function')