Exemplo n.º 1
0
def qdht(r: np.ndarray, f: np.ndarray, order: int = 0) -> Tuple[np.ndarray, np.ndarray]:
    """Perform a quasi-discrete Hankel transform of the function ``f`` (sampled at points
    ``r``) and return the transformed function and its sample points in :math:`k`-space.

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

    .. warning::
        This method is a convenience wrapper for :meth:`.HankelTransform.qdht`, 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.qdht` multiple times.

    :param r: The radial coordinates at which the function is sampled
    :type r: :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 k coordinates of the transformed function and its values
    :rtype: (:class:`numpy.ndarray`, :class:`numpy.ndarray`)
    """
    transformer = HankelTransform(order=order, radial_grid=r)
    f_transform = transformer.to_transform_r(f)
    ht = transformer.qdht(f_transform)
    return transformer.kr, ht
Exemplo n.º 2
0
def test_round_trip_r_interpolation(radius: np.ndarray, order: int, shape: Callable):
    transformer = HankelTransform(order=order, radial_grid=radius)

    # the function must be smoothish for interpolation
    # to work. Random every point doesn't work
    func = shape(radius)
    transform_func = transformer.to_transform_r(func)
    reconstructed_func = transformer.to_original_r(transform_func)
    assert np.allclose(func, reconstructed_func, rtol=1e-4)
Exemplo n.º 3
0
def test_1_over_r2_plus_z2_equivalence(a: float):
    r = np.linspace(0, 50, 1024)
    f = 1 / (r ** 2 + a ** 2)
    transformer = HankelTransform(order=0, radial_grid=r)
    f_transformer = 1 / (transformer.r**2 + a**2)
    assert np.allclose(transformer.to_transform_r(f), f_transformer, rtol=1e-2, atol=1e-6)

    kr, one_shot_ht = qdht(r, f)
    assert np.allclose(kr, transformer.kr)
    standard_ht = transformer.qdht(f_transformer)
    assert np.allclose(one_shot_ht, standard_ht, rtol=1e-3, atol=1e-2)
Exemplo n.º 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)
Exemplo n.º 5
0
def test_round_trip_r_interpolation_2d(radius: np.ndarray, order: int,
                                       shape: Callable, axis: int):
    transformer = HankelTransform(order=order, radial_grid=radius)

    # the function must be smoothish for interpolation
    # to work. Random every point doesn't work
    dims_amplitude = np.ones(2, np.int)
    dims_amplitude[1 - axis] = 10
    amplitude = np.random.random(dims_amplitude)
    dims_radius = np.ones(2, np.int)
    dims_radius[axis] = len(radius)
    func = np.reshape(shape(radius), dims_radius) * np.reshape(
        amplitude, dims_amplitude)
    transform_func = transformer.to_transform_r(func, axis=axis)
    reconstructed_func = transformer.to_original_r(transform_func, axis=axis)
    assert np.allclose(func, reconstructed_func, rtol=1e-4)
Exemplo n.º 6
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
Exemplo n.º 7
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
Exemplo n.º 8
0
# %%
# Set up beam parameters
Dr = 100e-6  # Beam radius (100um)
lambda_ = 488e-9  # wavelength 488nm
k0 = 2 * np.pi / lambda_  # Vacuum k vector

# %%
# Set up a :class:`.HankelTransform` object, telling it the order (``0``) and
# the radial grid.
H = HankelTransform(order=0, radial_grid=r)

# %%
# Set up the electric field profile at :math:`z = 0`, and resample onto the correct radial grid
# (``transformer.r``) as required for the QDHT.
Er = gauss1d(r, 0, Dr)  # Initial field
ErH = H.to_transform_r(Er)  # Resampled field

# %%
# Perform Hankel Transform
# ------------------------

# 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)