예제 #1
0
파일: profiles.py 프로젝트: draustin/otk
    def plot_r_q_polar(self, flat=False, tilt=False, show=True):
        """Plot amplitude and phase in real and angular space.

        To see self.Er and its transform exactly, set flat=False and tilt=True.

        Args:
            flat (bool): Plot Er_flat instead of Er (both domains).
            tilt (bool): Include the central tilt in the real and angular space phase plots.
            show:

        Returns:
            GraphicsLayoutWidget: Contains the four plots and a heading.
            plots (RQ tuple of AbsPhi tuples): The AlignedPlotItems.
        """
        Er = self.Er_flat if flat else self.Er
        Eq = math.fft2(Er)
        if not tilt:
            Er = Er * mathx.expj(-(self.qs_center[0] * self.x +
                                   self.qs_center[1] * self.y))
            Eq = Eq * mathx.expj(self.rs_center[0] * self.kx +
                                 self.rs_center[1] * self.ky)
        glw = pg.GraphicsLayoutWidget()
        glw.addLabel(self.title_str)
        glw.nextRow()
        gl = glw.addLayout()
        plots = plotting.plot_r_q_polar(self.rs_support, Er, self.rs_center,
                                        self.qs_center, gl, Eq)
        glw.resize(830, 675)
        if show:
            glw.show()
        return glw, plots
예제 #2
0
파일: math.py 프로젝트: draustin/otk
def calc_plane_to_curved_flat_arbitrary_factors(k,
                                                rs_support,
                                                num_pointss,
                                                z,
                                                xo,
                                                yo,
                                                qs_center=(0, 0),
                                                kz_mode='local_xy'):
    """Calculate factors for propagation from plane to arbitrarily sampled curved surface.

    Args:
        k (scalar): Wavenumber.
        rs_support (scalar or pair of): Input aperture along x and y.
        num_pointss (int or tuple of): Number of input samples along x and y. Referred to as K and L below.
        z (M*N array): Propagation distances.
        xo (Mx1 array): Output x values.
        yo (M array): Output y values.
        qs_center (tuple or pair of): Center of transverse wavenumber support.
        kz_mode (str): 'paraxial' or 'local_xy'.

    Returns:
        invTx (M*K array): Inverse transform factor.
        gradxinvTx (M*K array): X-derivative of inverse transform factor.
        invTy (L*N array): Y inverse transform factor.
        gradyinvTy (L*N array): Y-derivative of inverse transform factor.
        Px (M*N*K array): X propagation.
        Py (M*N*L array): Y propagation.
        Tx (K*K array): X transform factor.
        Ty (L*L array): Y transform factor.
    """
    assert kz_mode in ('local_xy', 'paraxial')
    Tx = make_fft_matrix(num_pointss[0])
    if num_pointss[1] == num_pointss[0]:
        Ty = Tx
    else:
        Ty = make_fft_matrix(num_pointss[1])
    if kz_mode == 'local_xy':
        fx, fy, delta_kz, delta_gxkz, delta_gykz = calc_quadratic_kz_correction(
            k, *qs_center)
        zx = z * fx
        zy = z * fy
    else:
        zx = z
        zy = z
        delta_kz = k
    kx, ky = sa.calc_kxky(rs_support, num_pointss, qs_center)
    # kx & ky are the right-most indices of the propagators.
    Px = calc_propagator_quadratic_1d(
        k, kx[:, 0], zx[:, :, None]) * mathx.expj(delta_kz * z[:, :, None])
    Py = calc_propagator_quadratic_1d(k, ky, zy[:, :, None])
    if kz_mode == 'local_xy':
        Px *= mathx.expj(delta_gxkz * kx[:, 0] * z[:, :, None])
        Py *= mathx.expj(delta_gykz * ky * z[:, :, None])
    invTx = make_ifft_arbitrary_matrix(rs_support[0], num_pointss[0],
                                       qs_center[0], xo[:, 0])
    invTy = make_ifft_arbitrary_matrix(rs_support[1], num_pointss[1],
                                       qs_center[1], yo)
    gradxinvTx = 1j * kx[:, 0] * invTx
    gradyinvTy = 1j * ky * invTy
    return invTx, gradxinvTx, invTy, gradyinvTy, Px, Py, Tx, Ty
예제 #3
0
파일: profiles.py 프로젝트: draustin/otk
    def plot_r_q_polar(self, flat=False, tilt=False, show=True):
        """Plot approximate plane profile and surface z relative to z_mean."""
        app = self.app
        Er = app.Er_flat if flat else app.Er
        Eq = math.fft2(Er)
        if not tilt:
            Er = Er * mathx.expj(-(app.qs_center[0] * app.x +
                                   app.qs_center[1] * app.y))
            Eq = Eq * mathx.expj(app.rs_center[0] * app.kx +
                                 app.rs_center[1] * app.ky)

        glw = pg.GraphicsLayoutWidget()
        glw.addLabel(self.title_str)
        glw.nextRow()
        gl = glw.addLayout()
        plot = gl.addAlignedPlot(labels={'left': 'y (mm)', 'bottom': 'x (mm)'})
        x, y, zu = sa.unroll_r(self.rs_support, self.z, self.rs_center)
        image = plot.image((zu - self.mean_z) * 1e3,
                           rect=pg.axes_to_rect(x * 1e3, y * 1e3),
                           lut=pg.get_colormap_lut('bipolar'))
        gl.addHorizontalSpacer(10)
        gl.addColorBar(image=image, rel_row=2, label='Relative z (mm)')
        glw.nextRow()

        glw.addLabel('Approximate planar profile')
        glw.nextRow()
        gl = glw.addLayout()
        plots = plotting.plot_r_q_polar(app.rs_support, Er, app.rs_center,
                                        app.qs_center, gl, Eq)

        glw.resize(830, 675)
        if show:
            glw.show()
        return glw, plots
예제 #4
0
파일: fsq.py 프로젝트: draustin/otk
def prepare_curved_paraxial_propagation_1d(k,
                                           r_support,
                                           Er,
                                           z,
                                           m,
                                           r_center=0,
                                           q_center=0,
                                           axis=-1,
                                           carrier=True):
    """Modifies Er."""
    assert not (np.isclose(z, 0) ^ np.isclose(m, 1))
    if np.isclose(z, 0):
        return 1, 1, r_center
    num_points = Er.shape[axis]
    roc = z / (m - 1)
    r = sa.calc_r(r_support, num_points, r_center, axis)
    q = sa.calc_q(r_support, num_points, q_center, axis)  #-q_center
    Er *= math.calc_quadratic_phase_1d(-k, r - r_center, roc)
    propagator = math.calc_propagator_quadratic_1d(k * m,
                                                   q - k * r_center / roc, z)

    ro_center = r_center + q_center / k * z
    ro = sa.calc_r(r_support * m, num_points, ro_center, axis)
    post_factor = math.calc_quadratic_phase_1d(k, ro, roc + z) * mathx.expj(
        k * (r_center**2 / (2 * roc) - r_center * ro / (roc * m))) / m**0.5
    if carrier:
        post_factor *= mathx.expj(k * z)

    return propagator, post_factor, ro_center
예제 #5
0
def test_curved_interface_collimate_offset():
    lamb = 587.6e-9
    waist0 = 30e-6
    num_points = 2**7
    k = 2 * np.pi / lamb
    r0_support = (np.pi * num_points)**0.5 * waist0
    # Define x lateral offset of beam.
    r_offsets = np.asarray((4e-3, -2e-3))
    # We center the numerical window on the beam.
    rs_center = r_offsets
    x0, y0 = asbp.calc_xy(r0_support, num_points, rs_center)
    # Create input beam.
    Er0 = asbp.calc_gaussian(k, x0, y0, waist0, r0s=r_offsets)
    # We will propagate it a distance f.
    f = 100e-3
    z_R = np.pi * waist0**2 / lamb
    m = (1 + (f / z_R)**2)**0.5
    # We collimate it with a spherical interface.
    n = 1.5
    roc = f * (n - 1)
    # At the interface,  support is expanded by the curved wavefront propagation.
    r1_support = m * r0_support
    x1, y1 = asbp.calc_xy(r1_support, num_points, rs_center)
    # Calculate and plot interface sag.
    sag = functions.calc_sphere_sag_xy(roc, x1, y1)
    xu, yu, sagu = asbp.unroll_r(r1_support, sag)
    # Propagate to curved surface.
    Er1, _ = asbp.propagate_plane_to_curved_spherical(k, r0_support, Er0,
                                                      f + sag, m, rs_center)
    xu, yu, Er1u = asbp.unroll_r(r1_support, Er1)
    #
    # x2, y2=asbp.calc_xy(r1_support, num_points)
    qs_centers2 = -r_offsets / f * k
    Er2, propagator = asbp.invert_plane_to_curved_spherical(
        k * n,
        r1_support,
        Er1,
        -f * n + sag,
        1, (0, 0),
        qs_centers2,
        max_iterations=10)  # -x_offset/f*k
    xu, yu, Er2u = asbp.unroll_r(r1_support, Er2)
    tilt_factor = mathx.expj(-(xu * r_offsets[0] + yu * r_offsets[1]) / f * k)
    ##
    waist2 = f * lamb / (np.pi * waist0)
    Er2_theory = asbp.calc_gaussian(k, x1, y1, waist2) * tilt_factor
    Er2_theory *= mathx.expj(np.angle(Er2[0, 0] / Er2_theory[0, 0]))
    assert mathx.allclose(abs(Er2), abs(Er2_theory), 2e-2)
    if 0:
        ##
        Er2_fig = asbp.plot_r_q_polar(r1_support, Er2, qs_center=qs_centers2)
        Er2_theory_fig = asbp.plot_r_q_polar(r1_support,
                                             Er2_theory,
                                             qs_center=qs_centers2)
예제 #6
0
파일: math.py 프로젝트: draustin/otk
def calc_plane_to_curved_flat_factors(k,
                                      rs_support,
                                      num_pointss,
                                      z,
                                      qs_center=(0, 0),
                                      kz_mode='local_xy'):
    """Calculate factors for propagation from plane to uniformly sampled curved surface.

    Args:
        k:
        rs_support:
        num_pointss:
        z:
        qs_center:
        kz_mode (str): 'paraxial' or 'local_xy'.

    Returns:
        invTx (2D array):
        gradxinvTx (2D array):
        invTy (2D array):
        gradyinvTy (2D array):
        Px (3D array):
        Py (3D array):
        Tx (2D array):
        Ty (2D array):
    """
    assert kz_mode in ('local_xy', 'paraxial')
    Tx = make_fft_matrix(num_pointss[0])
    if num_pointss[1] == num_pointss[0]:
        Ty = Tx
    else:
        Ty = make_fft_matrix(num_pointss[1])
    if kz_mode == 'local_xy':
        fx, fy, delta_kz, delta_gxkz, delta_gykz = calc_quadratic_kz_correction(
            k, *qs_center)
        zx = z * fx
        zy = z * fy
    else:
        zx = z
        zy = z
        delta_kz = k
    kx, ky = sa.calc_kxky(rs_support, num_pointss, qs_center)
    # kx & ky are the right-most indices of the propagators.
    Px = calc_propagator_quadratic_1d(
        k, kx[:, 0], zx[:, :, None]) * mathx.expj(delta_kz * z[:, :, None])
    Py = calc_propagator_quadratic_1d(k, ky, zy[:, :, None])
    if kz_mode == 'local_xy':
        Px *= mathx.expj(delta_gxkz * kx[:, 0] * z[:, :, None])
        Py *= mathx.expj(delta_gykz * ky * z[:, :, None])
    invTx = Tx.conj()
    invTy = Ty.conj()
    gradxinvTx = 1j * kx[:, 0] * invTx
    gradyinvTy = 1j * ky * invTy
    return invTx, gradxinvTx, invTy, gradyinvTy, Px, Py, Tx, Ty
예제 #7
0
파일: test_pbg.py 프로젝트: draustin/otk
def test_pbg_calc_field():
    origin = v4hb.stack_xyzw(0, 0, 0, 1)
    vector = v4hb.stack_xyzw(0, 0, 1, 0)
    axis1 = v4hb.normalize(v4hb.stack_xyzw(1, 1j, 0.5j, 0))
    lamb = 860e-9
    k = 2*np.pi/lamb
    waist = 100e-6
    z_R = np.pi*waist**2/lamb
    z_waist = 1*z_R
    mode = pbg.Mode.make(rt1.Line(origin, vector), axis1, lamb, waist, z_waist)[0]

    z = np.linspace(-z_R*16, z_R*16, 200)[:, None]
    x = np.arange(3)[:, None, None]*waist
    #zv, xv = [array.ravel() for array in np.broadcast_arrays(zs, xs)]
    points = v4hb.concatenate_xyzw(x, 0, z, 1)
    field, phi_axis, grad_phi = mode.calc_field(k, points, calc_grad_phi=True)
    psis = field*mathx.expj(-z*k)
    psis_true = beams.FundamentalGaussian(lamb, w_0=waist, flux=1).E(z - z_waist, x)*np.exp(
        -1j*np.arctan(z_waist/z_R))

    assert np.allclose(psis, psis_true)



    if 0: # Useful for testing in IPython.
        glw = pg.GraphicsLayoutWidget()
        absz_plot = glw.addAlignedPlot()
        glw.nextRows()
        phase_plot = glw.addAlignedPlot()
        for x, color, psi, psi_true in zip(xs, pg.tableau10, psis.T, psis_true.T):
            absz_plot.plot(zs[:, 0]*1e3, abs(psi), pen=color)
            absz_plot.plot(zs[:, 0]*1e3, abs(psi_true), pen=pg.mkPen(color, style=pg.DashLine))
            phase_plot.plot(zs[:, 0]*1e3, np.angle(psi), pen=color)
            phase_plot.plot(zs[:, 0]*1e3, np.angle(psi_true), pen=pg.mkPen(color, style=pg.DashLine))
        glw.show()
예제 #8
0
파일: profiles.py 프로젝트: draustin/otk
 def __init__(self,
              lamb,
              n,
              zfun,
              rs_support,
              Er,
              gradxyE,
              rs_center=(0, 0),
              qs_center=(0, 0),
              polarizationxy=(1, 0)):
     z_center = zfun(*rs_center)
     Profile.__init__(self, lamb, n, z_center, rs_support, Er, gradxyE,
                      rs_center, qs_center, polarizationxy)
     self.zfun = zfun
     self.z = zfun(self.x, self.y)
     self.valid = np.isfinite(self.z)
     self.z[~self.valid] = self.z[self.valid].mean()
     assert np.allclose(Er[~self.valid], 0)
     sumIr = self.Ir.sum()
     self.mean_z = (self.z * self.Ir).sum() / sumIr
     app_propagator = mathx.expj(
         (self.mean_z - self.z) * mathx.divide0(self.Igradphi[2], self.Ir))
     app_propagator[np.isnan(self.z)] = 0
     Er_plane = Er * app_propagator
     gradxyE_plane = tuple(c * app_propagator for c in gradxyE)
     # Approximate plane profile.
     self.app = PlaneProfile(lamb, n, self.mean_z, rs_support, Er_plane,
                             gradxyE_plane, rs_center, qs_center)
예제 #9
0
파일: fsq.py 프로젝트: draustin/otk
def propagate_plane_to_plane_spherical(k,
                                       rs_support,
                                       Er,
                                       z,
                                       ms,
                                       rs_center=(0, 0),
                                       qs_center=(0, 0),
                                       ro_centers=None,
                                       kz_mode='local_xy'):
    """Propagate from one plane to another using Sziklas-Siegman.

    Args:
        k (scalar): Wavenumber.
        rs_support (scalar or pair): Real space full support in x and y.
        Er (2D array): Input field.
        z (scalar): Propagation distance.
        ms (scalar or pair): Sziklas-Siegman magnification in x and y.
        rs_center (pair): Center of domain and center of wavefront curvature.
        qs_center (pair): Center of transverse wavenumber domain.
        ro_centers (pair): Center of output domain. Default is what follows from rs_center, qs_center and z.
        kz_mode (str): 'paraxial' or 'local_xy'.

    Returns:
        2D array: Output field.
    """
    assert kz_mode in ('local_xy', 'paraxial')
    rs_support = sa.to_scalar_pair(rs_support)
    ms = sa.to_scalar_pair(ms)
    if kz_mode == 'paraxial':
        zx = z
        zy = z
    elif kz_mode == 'local_xy':
        fx, fy, delta_kz, delta_gxkz, delta_gykz = math.calc_quadratic_kz_correction(
            k, *qs_center)
        zx = fx * z
        zy = fy * z
    else:
        raise ValueError('Unknown kz_mode %s.' % kz_mode)
    x, y = sa.calc_xy(rs_support, Er.shape, rs_center)
    roc_x = zx / (ms[0] - 1)
    roc_y = zy / (ms[1] - 1)
    kx, ky = sa.calc_kxky(rs_support, Er.shape, qs_center)
    kxp = kx - k * rs_center[0] / roc_x
    kyp = ky - k * rs_center[1] / roc_y
    Er = Er * math.calc_quadratic_phase_1d(
        -k, x - rs_center[0], roc_x) * math.calc_quadratic_phase_1d(
            -k, y - rs_center[1], roc_y)
    Eq = math.fft2(Er)
    Eq *= math.calc_propagator_quadratic_1d(
        k * ms[0], kxp, zx) * math.calc_propagator_quadratic_1d(
            k * ms[1], kyp, zy)
    # If local_xy mode, need translation correction factor.
    if kz_mode == 'local_xy':
        Eq *= mathx.expj(delta_gxkz * kx / ms[0] * z +
                         delta_gykz * ky / ms[1] * z)

    Er = math.ifft2(Eq) * math.calc_spherical_post_factor(
        k, rs_support, Er.shape, z, ms, rs_center, qs_center, ro_centers,
        kz_mode)
    return Er
예제 #10
0
파일: fsq.py 프로젝트: draustin/otk
def propagate_plane_to_plane_spherical_1d(k,
                                          r_support,
                                          Er,
                                          z,
                                          r_center=0,
                                          q_center=0,
                                          roc=np.inf,
                                          axis=-1):
    num_points = Er.shape[axis]
    Er_flat, z_flat, m_flat, m, r_center_flat = propagate_plane_to_waist_spherical_paraxial_1d(
        k, r_support, Er, z, r_center, q_center, roc)
    r_support_flat = r_support / m_flat
    z_paraxial = z / (1 - (q_center / k)**2)**1.5
    q_flat = sa.calc_q(r_support_flat, num_points, q_center, axis)
    extra_propagator = mathx.expj((k**2 - q_flat**2)**0.5 * z -
                                  (k - q_flat**2 / (2 * k)) * z_paraxial)

    Eq_flat = math.fft(Er_flat, axis)
    Eq_flat *= extra_propagator
    Er_flat = math.ifft(Eq_flat, axis)

    Er, _ = propagate_plane_to_plane_spherical_paraxial_1d(
        k, r_support_flat, Er_flat, z_paraxial + z_flat, m * m_flat,
        r_center_flat, q_center)

    rp_center = r_center + z * q_center / (k**2 - q_center**2)**0.5

    return Er, m, rp_center
예제 #11
0
파일: fsq.py 프로젝트: draustin/otk
def propagate_plane_to_plane_flat_1d(k,
                                     r_support,
                                     Er,
                                     z,
                                     q_center=0,
                                     axis=-1,
                                     paraxial=False):
    num_points = Er.shape[axis]
    Eq = math.fft(Er, axis)
    q = sa.calc_q(r_support, num_points, q_center, axis)
    if paraxial:
        Eq *= mathx.expj((k - q**2 / (2 * k)) * z)
    else:
        Eq *= mathx.expj((k**2 - q**2)**0.5 * z)
    Er = math.ifft(Eq, axis)
    return Er
예제 #12
0
파일: fsq.py 프로젝트: draustin/otk
def shift_r_center_1d(r_support,
                      num_points,
                      Er,
                      delta_r_center,
                      q_center,
                      k_on_roc=0,
                      axis=-1):
    r = sa.calc_r(r_support, num_points, axis=axis)
    q = sa.calc_q(r_support, num_points, q_center, axis=axis)
    # Remove quadratic phase and tilt.
    Er *= mathx.expj(-(q[0] * r + k_on_roc * r**2 / 2))
    Ek = math.fft(Er, axis)
    Ek *= mathx.expj(delta_r_center * q)
    Er = math.ifft(Ek, axis)
    Er *= mathx.expj(q[0] * r + k_on_roc * (r + delta_r_center)**2 / 2)
    return Er
예제 #13
0
def test_curved_interface_collimate():
    lamb = 587.6e-9
    waist0 = 150e-6
    num_points = 2**7
    k = 2 * np.pi / lamb
    r0_support = (np.pi * num_points)**0.5 * waist0
    x0, y0 = asbp.calc_xy(r0_support, num_points)
    Er0 = asbp.calc_gaussian(k, x0, y0, waist0)
    f = 100e-3
    n = 1.5
    roc = f * (n - 1)
    z_R = np.pi * waist0**2 / lamb
    m = (1 + (f / z_R)**2)**0.5
    r1_support = m * r0_support
    x1, y1 = asbp.calc_xy(r1_support, num_points)
    sag = functions.calc_sphere_sag_xy(roc, x1, y1)
    Er1, _ = asbp.propagate_plane_to_curved_spherical(k, r0_support, Er0,
                                                      f + sag, m)
    Er2, propagator = asbp.invert_plane_to_curved_spherical(
        k * n, r1_support, Er1, -f * n + sag, 1)
    ##
    waist2 = f * lamb / (np.pi * waist0)
    Er2_theory = asbp.calc_gaussian(k, x1, y1, waist2)
    Er2_theory *= mathx.expj(np.angle(Er2[0, 0] / Er2_theory[0, 0]))
    assert mathx.allclose(Er2, Er2_theory, 1e-3)
예제 #14
0
 def plot_q_(images, r_support, Eq, qs_center, rs_center):
     kxu, kyu, Equ = asbp.unroll_q(r_support, Eq, qs_center)
     Equ = Equ * mathx.expj((rs_center[0] * kxu + rs_center[1] * kyu))
     images[0].setImage(abs(Equ))
     images[0].setRect(pg.axes_to_rect(kxu / 1e3, kyu / 1e3))
     images[1].setImage(np.angle(Equ) / (2 * np.pi))
     images[1].setRect(pg.axes_to_rect(kxu / 1e3, kyu / 1e3))
예제 #15
0
파일: profiles.py 프로젝트: draustin/otk
 def interpolate(self, rs_support, num_pointss, rs_center=None):
     assert self.zfun is not None
     appi = self.app.interpolate(rs_support, num_pointss, rs_center)
     z = self.zfun(appi.x, appi.y)
     # Propagate from interpolated planar profile to resampled z.
     Ir = appi.Ir
     propagator = mathx.expj(
         (z - appi.z) * mathx.divide0(appi.Igradphi[2], Ir))
     Er = appi.Er * propagator
     gradxyE = tuple(c * propagator for c in appi.gradxyE)
     return type(self)(self.lamb, self.n, self.zfun, appi.rs_support, Er,
                       gradxyE, appi.rs_center, appi.qs_center)
예제 #16
0
파일: fsq.py 프로젝트: draustin/otk
def propagate_plane_to_plane_flat(k,
                                  rs_support,
                                  Er,
                                  z,
                                  qs_center=(0, 0),
                                  kz_mode='local_xy'):
    """Regularly (non-Sziklas-Siegman) propagate a field between two flat planes.

    Args:
        k (scalar): Wavenumber.
        rs_support (scalar or pair): Real space support.
        Er (2D array): Initial field.
        z (scalar): Propagation distance.
        qs_center (pair): Center of transverse wavenumber space.
        kz_mode (str): 'paraxial', 'local_xy', or 'exact'.

    Returns:
        2D array: Propagated field.
    """
    rs_support = sa.to_scalar_pair(rs_support)
    qs_center = sa.to_scalar_pair(qs_center)
    Eq = math.fft2(Er)
    kx, ky = sa.calc_kxky(rs_support, Eq.shape, qs_center)
    if kz_mode == 'paraxial':
        propagator = math.calc_propagator_paraxial(k, kx, ky, z)
    elif kz_mode in ('local_xy', 'local'):
        kxp = kx - qs_center[0]
        kyp = ky - qs_center[1]
        kz, gxkz, gykz, gxxkz, gyykz, gxykz = math.expand_kz(k, *qs_center)
        propagator = mathx.expj((kz + gxkz * kxp + gykz * kyp +
                                 gxxkz * kxp**2 / 2 + gyykz * kyp**2 / 2) * z)
        if kz_mode == 'local':
            propagator *= mathx.expj(gxykz * kxp * kyp * z)
    elif kz_mode == 'exact':
        propagator = math.calc_propagator_exact(k, kx, ky, z)
    else:
        raise ValueError('Unknown kz_mode %s.' % kz_mode)
    Eq *= propagator
    Er = math.ifft2(Eq)
    return Er
예제 #17
0
파일: test_pbg.py 프로젝트: draustin/otk
def test_pbg_simple():
    waist = 100e-6
    n = 1
    lamb = 800e-9
    k = 2*np.pi*n/lamb
    # Totally arbitrary origin and axes.
    origin = np.asarray([1, 2, 3, 1])
    vector = v4hb.normalize(np.asarray([1, -2, -1, 0]))
    axis_x = v4hb.normalize(np.asarray([1, 1, 0, 0]))

    mode, (axis_x, axis_y) = pbg.Mode.make(otk.rt1._lines.Line(origin, vector), axis_x, lamb / n, waist)

    z_R = waist**2*k/2
    z = np.asarray([-10, 1, 0, 1, 10])[:, None]*z_R*0
    x = np.arange(3)[:, None, None]*waist
    y = np.arange(3)[:, None, None, None]*waist
    #z = np.asarray([[z_R]])
    #x = np.asarray([[waist]])
    #y = np.asarray([[waist]])
    rho = (x**2 + y**2)**0.5
    xhat = np.asarray([1, 0, 0, 0])
    yhat = np.asarray([0, 1, 0, 0])
    rhohat = mathx.divide0(xhat*x + yhat*y, rho)
    mode_matrix = np.stack([axis_x, axis_y, vector, origin], 0)
    points = v4hb.concatenate_xyzw(x, y, z, 1).dot(mode_matrix)

    field, phi_axis, grad_phi = mode.calc_field(k, points, calc_grad_phi=True)

    beam = beams.FundamentalGaussian(lamb/n, w_0=waist, flux=1)
    field_true = beam.E(z, rho)*mathx.expj(z*k)
    field_true_axis = beam.E(z, 0)*mathx.expj(z*k)
    grad_phi_true = (beam.dphidz(z, rho) + k)*vector + beam.dphidrho(z, rho)*rhohat.dot(mode_matrix)

    testing.assert_allclose(abs(field), abs(field_true))
    testing.assert_allclose(field, field_true)

    testing.assert_allclose(abs(mathx.wrap_to_pm(phi_axis - np.angle(field_true_axis), np.pi)), 0, atol=1e-6)

    testing.assert_allclose(grad_phi, grad_phi_true, atol=1e-6)
예제 #18
0
파일: fsq.py 프로젝트: draustin/otk
def propagate_plane_to_plane_spherical_paraxial_1dE(k,
                                                    r_support,
                                                    Eri,
                                                    z,
                                                    m,
                                                    r_center=0,
                                                    q_center=0):
    """Propagate field with spherical wavefront from plane to plane.

    kz is included.

    Args:
        k:
        rs_support:
        Eri:
        z (2D array): propagation distance vs (x, y)
        m:
        rs_center:
        qs_center:

    Returns:

    """
    assert Eri.ndim == 1
    num_points = len(Eri)
    ri = sa.calc_r(r_support, num_points, r_center)
    qi = sa.calc_q(r_support, num_points, q_center)
    roc = z / (m - 1)
    Qir = mathx.expj(-k * ri**2 / (2 * roc[:, None]))
    T = math.make_fft_matrix(num_points)
    P = mathx.expj((k - qi**2 / (2 * k * m)) * z[:, None])
    invT = T.conj()
    ro = ri * m
    Qor = mathx.expj(k * ro**2 / (2 * (roc + z))) / m**0.5
    # ro: i,  qi: j,  ri: k
    Ero = opt_einsum.contract('i, ij, ij, jk, ik, k->i', Qor, invT, P, T, Qir,
                              Eri)
    return Ero
예제 #19
0
파일: profiles.py 프로젝트: draustin/otk
    def fourier_transform(self, f, rs0=(0, 0), z=None):
        if z is None:
            z = self.z + 2 * f
        # I *think* that there is an efficient implementation for highly curved wavefronts, analagous to
        # https://doi.org/10.1364/OE.24.025974

        # Derivation of normalization factor Dane's logbook 3 p81.
        norm_fac = self.delta_x * self.delta_y * self.k / (
            2 * np.pi * f) * np.prod(self.Er.shape)**0.5
        Er = math.fft2(self.Er) * mathx.expj(rs0[0] * self.kx +
                                             rs0[1] * self.ky) * norm_fac
        rs_support = self.qs_support * f / self.k
        rs_center = self.qs_center * f / self.k
        qs_center = (self.rs_center - rs0) * self.k / f
        gradxyE = fsq.calc_gradxyE(rs_support, Er, qs_center)
        return PlaneProfile(self.lamb, self.n, z, rs_support, Er, gradxyE,
                            rs_center, qs_center)
예제 #20
0
파일: math.py 프로젝트: draustin/otk
def make_ifft_arbitrary_matrix(r_support0, num_points0, q_center0, r1):
    """
    Warning: The matrix does not enforce a particular subset of the infinite periodic r1 domain. So if the range of r1
    is greater than 2*pi/r_support0, then the output will be repeated.


    Args:
        r_support0:
        num_points0:
        q_center0:
        r1:

    Returns:

    """
    assert r1.ndim == 1
    q0 = sa.calc_q(r_support0, num_points0, q_center0)
    return mathx.expj(q0 * r1[:, None]) / len(q0)**0.5
예제 #21
0
파일: math.py 프로젝트: draustin/otk
def calc_spherical_post_factor(k,
                               rs_support,
                               num_pointss,
                               z,
                               ms,
                               rs_center=(0, 0),
                               qs_center=(0, 0),
                               ro_centers=None,
                               kz_mode='local_xy'):
    assert np.isscalar(z)
    ro_supports = rs_support * ms
    qs_center = sa.to_scalar_pair(qs_center)
    if kz_mode == 'paraxial':
        zx = z
        zy = z
        kz_center = k
        delta_kz = k
    elif kz_mode == 'local_xy':
        fx, fy, delta_kz, delta_gxkz, delta_gykz = calc_quadratic_kz_correction(
            k, *qs_center)
        zx = fx * z
        zy = fy * z
        kz_center = (k**2 - (qs_center**2).sum())**0.5
    else:
        raise ValueError('Unknown kz_   mode %s.', kz_mode)
    if ro_centers is None:
        ro_centers = rs_center + qs_center / kz_center * z
    xo, yo = sa.calc_xy(ro_supports, num_pointss, ro_centers)
    if kz_mode == 'local_xy':
        xo += delta_gxkz * z
        yo += delta_gykz * z
    roc_x = zx / (ms[0] - 1)
    roc_y = zy / (ms[1] - 1)
    roc_xo = roc_x + zx
    roc_yo = roc_y + zy
    # See derivation page 114 Dane's logbook 2.
    Qo = calc_quadratic_phase_1d(k, xo, roc_xo) * calc_quadratic_phase_1d(
        k, yo, roc_yo) * mathx.expj(delta_kz * z + k *
                                    (rs_center[0]**2 /
                                     (2 * roc_x) + rs_center[1]**2 /
                                     (2 * roc_y) - rs_center[0] * xo /
                                     (roc_x * ms[0]) - rs_center[1] * yo /
                                     (roc_y * ms[1]))) / (ms[0] * ms[1])**0.5
    return Qo
예제 #22
0
 def plot_r(images, beam, scale=1):
     profile = beam.profile
     xu, yu, Eru = asbp.unroll_r(profile.rs_support, profile.Er * scale,
                                 profile.rs_center)
     tilt_mode = self.tilt_mode_widget.currentIndex()
     if not isinstance(beam.profile, asbp.PlaneProfile):
         q_profile = profile.app
     else:
         q_profile = profile
     if tilt_mode == 0:
         q0s = q_profile.centroid_qs_flat
     else:
         q0s = q_profile.peak_qs
     q0s += np.asarray(
         (self.tilt_nudge_x_widget.value(),
          self.tilt_nudge_y_widget.value())) / 1e3 * profile.k
     Eru = Eru * mathx.expj(-(q0s[0] *
                              (xu - profile.peak_rs[0]) + q0s[1] *
                              (yu - profile.peak_rs[1]) +
                              np.angle(profile.peak_Er)))
     images[0].setImage(abs(Eru))
     images[0].setRect(pg.axes_to_rect(xu * 1e3, yu * 1e3))
     images[1].setImage(np.angle(Eru) / (2 * np.pi))
     images[1].setRect(pg.axes_to_rect(xu * 1e3, yu * 1e3))
예제 #23
0
파일: math.py 프로젝트: draustin/otk
def calc_propagator_paraxial(k, kx, ky, l):
    return mathx.expj(calc_kz_paraxial(k, kx, ky) * l)
예제 #24
0
파일: math.py 프로젝트: draustin/otk
def calc_propagator_quadratic(k, kx, ky, l):
    return mathx.expj(calc_kz_quadratic(k, kx, ky) * l)
예제 #25
0
파일: math.py 프로젝트: draustin/otk
def calc_propagator_quadratic_1d(k, q, l):
    """kz not included."""
    return mathx.expj(calc_kz_quadratic_1d(k, q) * l)
예제 #26
0
파일: profiles.py 프로젝트: draustin/otk
def calc_quadratic_phase_mask(x, y, k_on_f):
    m = mathx.expj(-0.5 * (x**2 + y**2) * k_on_f)
    gradxm = -m * x * k_on_f
    gradym = -m * y * k_on_f
    return m, (gradxm, gradym)
예제 #27
0
파일: profiles.py 프로젝트: draustin/otk
 def calc_quadratic_phase_factor(self, x, y):
     rs_center = self.rs_center
     phi_cx, phi_cy = self.phi_cs
     var_x, var_y = self.var_rs
     return mathx.expj((x - rs_center[0])**2 * phi_cx / var_x) * mathx.expj(
         (y - rs_center[1])**2 * phi_cy / var_y)
예제 #28
0
파일: math.py 프로젝트: draustin/otk
def calc_plane_to_curved_spherical_arbitrary_factors(k,
                                                     rs_support,
                                                     num_pointss,
                                                     z,
                                                     xo,
                                                     yo,
                                                     roc_x,
                                                     roc_y,
                                                     ri_centers=(0, 0),
                                                     qs_center=(0, 0),
                                                     ro_centers=None,
                                                     kz_mode='local_xy'):
    """Calculate factors for 2D Sziklas-Siegman propagation (paraxial) from flat to curved surface(s).

    The zero-oth order phase (k_z) is (arbitrarily) included in QinvTPx.

    Compared to regular Sziklas-Siegman procedure, the factors are complicated by a transformation that allows nonzero
    real and angular space centers.  See derivation page 114 Dane's logbook 2.

    Possible optimizations: could probably shave 50% off by more aggressive use of numba to avoid calculation of intermediates.
    But typically the time is spent using (tensor contract) rather than calculating the factors, so it won't bring
    a great speedup.

    Args:
        k (scalar): Wavenumber.
        rs_support (scalar or pair): Real space support.
        num_pointss (scalar int or pair): Number of sampling points in input.
        z (M*N array): Propagation for distance.
        xo (M*1 array): Output x sample values.
        yo (N array): Output y sample values.
        roc_x (M*N array): Radius of curvature in x, at the input, but sampled at the output points.
        roc_y (M*N array): Radius of curvature in y, at the input, but sampled at the output points.
        ri_centers (pair of scalars): Center of initial real-space aperture.
        qs_center (pair of scalars): Center of angular space aperture.
        kz_mode (str): 'paraxial' or 'local_xy'.

    Returns:
        QinvTPx (3D array): Product propagator, inverse DFT and quadratic output factor along x. Axes are (xo, yo, kx).
        gradxQinvTPx (3D array): Derivative of above w.r.t output x. Note that z is constant - the derivative is along
            a transverse plane rather than the surface.
        QinvTPy (3D array): Product propagator, inverse DFT and quadratic output factor along x. Axes are (xo, yo, kx).
        gradyQinvTPy (3D array): Derivative of above w.r.t output x. As with gradxQinvTPx, z is constant.
        Tx (2D array): DFT factor. Axes are (kx, xi).
        Ty (2D array): DFT factor. Axes are (ky, yi).
        Qix (3D array): Input x quadratic phase factor vs x. Axes are (xo, yo, xi).
        Qiy (3D array): Input y quadratic phase factor. Axes are (xo, yo, yi).
    """
    assert np.isscalar(k)
    rs_support = sa.to_scalar_pair(rs_support)
    assert kz_mode in ('local_xy', 'paraxial')
    assert np.ndim(z) == 2
    assert np.shape(z) == np.shape(roc_x)
    assert np.shape(z) == np.shape(roc_y)
    assert np.shape(xo) == (np.shape(z)[0], 1)
    assert np.shape(yo) == (np.shape(z)[1], )
    num_pointss = sa.to_scalar_pair(num_pointss)
    qs_center = sa.to_scalar_pair(qs_center)

    if ro_centers is None:
        z_center = np.mean(z)
        ro_centers = adjust_r(k, ri_centers, z_center, qs_center, kz_mode)

    # If local_xy mode is requested then propagation distances must be scaled. Calculate scaled propagation distances
    # and required kz component.
    if kz_mode == 'paraxial':
        zx = z
        zy = z
        delta_kz = k
    else:
        fx, fy, delta_kz, delta_gxkz, delta_gykz = calc_quadratic_kz_correction(
            k, *qs_center)
        zx = fx * z
        zy = fy * z

    mx = zx / roc_x + 1
    my = zy / roc_y + 1

    xi, yi = sa.calc_xy(rs_support, num_pointss, ri_centers)
    kxi, kyi = sa.calc_kxky(rs_support, num_pointss,
                            qs_center)  # +q_curvatures)

    # Quadratic phase is centered at origin. Numerically, this requires evaluation of complex exponentials of size N^3.
    # Significant fraction of total cost of this function, but unavoidable.
    Qix = calc_quadratic_phase_1d(-k, xi[:, 0] - ri_centers[0], roc_x[:, :,
                                                                      None])
    Qiy = calc_quadratic_phase_1d(-k, yi - ri_centers[1], roc_y[:, :, None])

    Tx = make_fft_matrix(num_pointss[0])
    if num_pointss[1] == num_pointss[0]:
        Ty = Tx
    else:
        Ty = make_fft_matrix(num_pointss[1])

    roc_xo = roc_x + zx
    roc_yo = roc_y + zy

    # If in local_xy mode, then the result of the Sziklas-Siegman step needs to be translated. This means that the
    # factors which depend on xo and yo need to be translated too. (Note that the x and y factors in the inverse DFT
    # are not translated.) We define xop and yop as the translated output coordinates.
    if kz_mode == 'local_xy':
        xop = xo + delta_gxkz * z
        yop = yo + delta_gykz * z
    else:
        xop = xo
        yop = yo[None, :]

    # Effective kx and ky for propagation takes into account center of curvature.
    kxip = kxi[:, 0] - k * ri_centers[0] / roc_x[:, :, None]
    kyip = kyi - k * ri_centers[1] / roc_y[:, :, None]

    r2_support_x = mx * rs_support[0]
    r2_support_y = my * rs_support[1]
    valid_x = abs(xo - ro_centers[0]) < r2_support_x * 0.5
    valid_y = abs(yo - ro_centers[1]) < r2_support_y * 0.5

    # Calculate product of propagator and inverse transform along x axis. The x axis (arbitrarily) includes delta_kz.
    # Could combine all exponents before exponentiation? Won't help much because the time will be dominated by the propagator
    # which is N^3 - the others are N^2.
    phi = delta_kz * z + k * (ri_centers[0]**2 /
                              (2 * roc_x) - ri_centers[0] * xop / (roc_x * mx))
    QinvTPx = (
        calc_propagator_quadratic_1d(k * mx[:, :, None], kxip, zx[:, :, None])
        *  # Propagation phase scaled by magnification.
        calc_quadratic_phase_1d(k, xop, roc_xo)[:, :, None]
        *  # Normal Sziklas-Siegman final quadratic phase.
        mathx.expj(phi[:, :, None] + kxi[:, 0] * (xo / mx)[:, :, None]) /
        num_pointss[0]**0.5 /  # Correction phases and inverse DFT.
        abs(mx[:, :, None])**0.5 *  # Magnification correction to amplitude.
        valid_x[:, :, None])

    # Calculate product of propagator and inverse transform along x axis.
    phi = k * (ri_centers[1]**2 / (2 * roc_y) - ri_centers[1] * yop /
               (roc_y * my))
    QinvTPy = (
        calc_propagator_quadratic_1d(k * my[:, :, None], kyip, zy[:, :, None])
        *  # Propagation phase scaled by magnification.
        calc_quadratic_phase_1d(k, yop, roc_yo)[:, :, None]
        *  # Normal Sziklas-Siegman final quadratic phase.
        mathx.expj(phi[:, :, None] + kyi * (yo / my)[:, :, None]) /
        num_pointss[1]**0.5 /  # Correction phases and inverse DFT.
        abs(my[:, :, None])**0.5 *  # Magnification correction to amplitude.
        valid_y[:, :, None])

    # If local_xy mode, need translation correction factor. Could combine this with above to reduce number of N^3 expj
    # calls but this would only give a marginal performance improvement.
    if kz_mode == 'local_xy':
        QinvTPx *= mathx.expj(delta_gxkz * kxi[:, 0] * (z / mx)[:, :, None])
        QinvTPy *= mathx.expj(delta_gykz * kyi * (z / my)[:, :, None])

    # Evaluate derivatives of the invTP factors with respect to output x and y (but constant z - not along the curved
    # surface).
    gradxQinvTPx = 1j * (k * (xop / roc_xo - ri_centers[0] /
                              (roc_x * mx))[:, :, None] +
                         kxi[:, 0] / mx[:, :, None]) * QinvTPx
    gradyQinvTPy = 1j * (k * (yop / roc_yo - ri_centers[1] /
                              (roc_y * my))[:, :, None] +
                         kyi / my[:, :, None]) * QinvTPy

    factors = QinvTPx, gradxQinvTPx, QinvTPy, gradyQinvTPy, Tx, Ty, Qix, Qiy
    return factors
예제 #29
0
파일: math.py 프로젝트: draustin/otk
def calc_plane_to_curved_spherical_factors(k,
                                           rs_support,
                                           num_pointss,
                                           z,
                                           ms,
                                           ri_centers=(0, 0),
                                           qs_center=(0, 0),
                                           ro_centers=(0, 0),
                                           kz_mode='local_xy'):
    """Calculate factors for 2D Sziklas-Siegman propagation (paraxial) from flat to curved surface(s).

    The magnifications must be the same for all output points, but can be different for the x and y planes.

    The zero-oth order phase (k_z) is (arbitrarily) included in QinvTPx.

    Compared to regular Sziklas-Siegman procedure, the factors are complicated by a transformation that allows nonzero
    real and angular space centers.  See derivation page 114 Dane's logbook 2.

    Possible optimizations: could probably shave 50% off by more aggressive use of numba to avoid calculation of intermediates.
    But typically the time is spent using (tensor contract) rather than calculating the factors, so it won't bring
    a great speedup.

    Args:
        k (scalar): Wavenumber.
        rs_support (scalar or pair): Real space support.
        num_pointss (scalar int or pair): Number of sampling points.
        z (array of size num_pointss): Propagation for distance.
        ms (scalar or pair): Magnification(s).
        ri_centers (pair of scalars): Center of initial real-space aperture.
        qs_center (pair of scalars): Center of angular space aperture.
        ro_centers (pair of scalars): Center of final real-space aperture. If not given, the shift from ri_centers is
            inferred from the propagation distance and qs_center.
        kz_mode (str): 'paraxial' or 'local_xy'.

    Returns:
        QinvTPx (3D array): Product propagator, inverse DFT and quadratic output factor along x. Axes are (xo, yo, kx).
        gradxQinvTPx (3D array): Derivative of above w.r.t output x. Note that z is constant - the derivative is along
            a transverse plane rather than the surface.
        QinvTPy (3D array): Product propagator, inverse DFT and quadratic output factor along x. Axes are (xo, yo, kx).
        gradyQinvTPy (3D array): Derivative of above w.r.t output x. As with gradxQinvTPx, z is constant.
        Tx (2D array): DFT factor. Axes are (kx, xi).
        Ty (2D array): DFT factor. Axes are (ky, yi).
        Qix (3D array): Input x quadratic phase factor vs x. Axes are (xo, yo, xi).
        Qiy (3D array): Input y quadratic phase factor. Axes are (xo, yo, yi).
    """
    assert kz_mode in ('local_xy', 'paraxial')
    num_pointss = sa.to_scalar_pair(num_pointss)
    ms = sa.to_scalar_pair(ms)
    if np.isclose(ms, 1).any():
        logger.debug('At least one magnification (%g, %g) close to 1.', ms)
    qs_center = sa.to_scalar_pair(qs_center)
    # TODO (maybe) factor out adjust_r.
    if kz_mode == 'paraxial':
        kz_center = k
    else:
        kz_center = (k**2 - (qs_center**2).sum())**0.5
    z_center = np.mean(z)
    if ro_centers is None:
        ro_centers = ri_centers + qs_center / kz_center * z_center

    # If local_xy mode is requested then propagation distances must be scaled. Calculate scaled propagation distances
    # and required kz component.
    if kz_mode == 'paraxial':
        zx = z
        zy = z
        delta_kz = k
    else:
        fx, fy, delta_kz, delta_gxkz, delta_gykz = calc_quadratic_kz_correction(
            k, *qs_center)
        zx = fx * z
        zy = fy * z

    ro_supports = rs_support * ms
    xi, yi = sa.calc_xy(rs_support, num_pointss, ri_centers)
    kxi, kyi = sa.calc_kxky(rs_support, num_pointss,
                            qs_center)  # +q_curvatures)
    roc_x = mathx.divide0(zx, ms[0] - 1, np.inf)
    roc_y = mathx.divide0(zy, ms[1] - 1, np.inf)
    # Quadratic phase is centered at origin. Numerically, this requires evaluation of complex exponentials of size N^3.
    # Significant fraction of total cost of this function, but unavoidable.
    Qix = calc_quadratic_phase_1d(-k, xi[:, 0] - ri_centers[0], roc_x[:, :,
                                                                      None])
    Qiy = calc_quadratic_phase_1d(-k, yi - ri_centers[1], roc_y[:, :, None])

    Tx = make_fft_matrix(num_pointss[0])
    if num_pointss[1] == num_pointss[0]:
        Ty = Tx
    else:
        Ty = make_fft_matrix(num_pointss[1])

    if 0:
        # This was an experiment - we calculate where a given pencil beam lands based on initial position and
        # momentum. It didn't improve the stability of the algorithm. In a ray picture, clip factor should be 0.5. But
        # I found that anything below 3 gave unacceptable artefacts.
        clip_factor = 3
        mean_rocs = z_centers / (ms - 1)
        xo_kx_xi = xi[:, 0] * ms[0] + (
            kxi - k * ri_centers[0] / mean_rocs[0]) * z_centers[0] / k
        yo_ky_yi = yi * ms[1] + (
            kyi[:, None] - k * ri_centers[1] / mean_rocs[1]) * z_centers[1] / k
        in_xo = abs(xo_kx_xi - ro_centers[0]) < ro_supports[0] * clip_factor
        in_yo = abs(yo_ky_yi - ro_centers[1]) < ro_supports[1] * clip_factor
        Txp = Tx * in_xo
        Typ = Ty * in_yo

    xo, yo = sa.calc_xy(ro_supports, num_pointss, ro_centers)
    roc_xo = roc_x + zx
    roc_yo = roc_y + zy

    # If in local_xy mode, then the factors which depend on xo and yo use transformed quantities, which we subsitute here.
    if kz_mode == 'local_xy':
        xo = xo + delta_gxkz * z
        yo = yo + delta_gykz * z

    # Effective kx and ky for propagation takes into account center of curvature.
    kxip = kxi[:, 0] - k * ri_centers[0] / roc_x[:, :, None]
    kyip = kyi - k * ri_centers[1] / roc_y[:, :, None]

    # Calculate product of propagator and inverse transform along x axis. The x axis (arbitrarily) includes delta_kz.
    # Could combine all exponents before exponentiation? Won't help much because the time will be dominated by the propagator
    # which is N^3 - the others are N^2.
    phi = delta_kz * z + k * (ri_centers[0]**2 /
                              (2 * roc_x) - ri_centers[0] * xo /
                              (roc_x * ms[0]))
    QinvTPx = (
        calc_propagator_quadratic_1d(k * ms[0], kxip, zx[:, :, None])
        *  # Propagation phase scaled by magnification.
        calc_quadratic_phase_1d(k, xo, roc_xo)[:, :, None]
        *  # Normal Sziklas-Siegman final quadratic phase.
        mathx.expj(phi[:, :, None]) * Tx.conj()[:, None, :] /  # Inverse DFT.
        abs(ms[0])**0.5)  # Magnification correction to amplitude.

    # Calculate product of propagator and inverse transform along x axis. Result depends on
    phi = k * (ri_centers[1]**2 / (2 * roc_y) - ri_centers[1] * yo /
               (roc_y * ms[1]))
    QinvTPy = (
        calc_propagator_quadratic_1d(k * ms[1], kyip, zy[:, :, None])
        *  # Propagation phase scaled by magnification.
        calc_quadratic_phase_1d(k, yo, roc_yo)[:, :, None]
        *  # Normal Sziklas-Siegman final quadratic phase.
        mathx.expj(phi[:, :, None]) * Ty.conj() /  # Inverse DFT.
        abs(ms[1])**0.5)  # Magnification correction to amplitude.

    # If local_xy mode, need translation correction factor. Could combine this with above to reduce number of N^3 expj
    # calls.
    if kz_mode == 'local_xy':
        QinvTPx *= mathx.expj(delta_gxkz * kxi[:, 0] / ms[0] * z[:, :, None])
        QinvTPy *= mathx.expj(delta_gykz * kyi / ms[1] * z[:, :, None])

    # Evaluate derivatives of the invTP factors with respect to output x and y (but constant z - not along the curved
    # surface).
    gradxQinvTPx = 1j * (k * (xo / roc_xo)[:, :, None] - ri_centers[0] * k /
                         (roc_x[:, :, None] * ms[0]) +
                         kxi[:, 0] / ms[0]) * QinvTPx
    gradyQinvTPy = 1j * (k * (yo / roc_yo)[:, :, None] - ri_centers[1] * k /
                         (roc_y[:, :, None] * ms[1]) + kyi / ms[1]) * QinvTPy

    # Won't use z gradients for now - will keep for future.
    # gradzPx=1j*calc_kz_paraxial_1d(k*ms[0], kxip)*Px

    factors = QinvTPx, gradxQinvTPx, QinvTPy, gradyQinvTPy, Tx, Ty, Qix, Qiy
    return factors
예제 #30
0
파일: math.py 프로젝트: draustin/otk
def calc_quadratic_phase_1d(k, r, roc):
    return mathx.expj(k * r**2 / (2 * roc))