Example #1
0
def wave_abr_pre_calc(fod, fld, wvl, foc, ray_pkg, chief_ray_pkg):
    """Pre-calculate the part of the OPD calc independent of focus."""
    cr, cr_exp_seg = chief_ray_pkg
    chief_ray, chief_ray_op, wvl = cr
    cr_exp_pt, cr_exp_dir, cr_exp_dist, ifc, cr_b4_pt, cr_b4_dir = cr_exp_seg

    ray, ray_op, wvl = ray_pkg

    k = -2  # last interface in sequence

    # eq 3.12
    e1 = eic_distance((ray[1][mc.p], ray[0][mc.d]),
                      (chief_ray[1][mc.p], chief_ray[0][mc.d]))
    # eq 3.13
    ekp = eic_distance((ray[k][mc.p], ray[k][mc.d]),
                       (chief_ray[k][mc.p], chief_ray[k][mc.d]))

    pre_opd = -abs(fod.n_obj) * e1 - ray_op + abs(
        fod.n_img) * ekp + chief_ray_op

    b4_pt, b4_dir = transform_after_surface(ifc, (ray[k][mc.p], ray[k][mc.d]))
    dst = ekp - cr_exp_dist
    eic_exp_pt = b4_pt - dst * b4_dir
    p_coord = eic_exp_pt - cr_exp_pt

    return pre_opd, p_coord, b4_pt, b4_dir
Example #2
0
def transfer_to_exit_pupil(interface, ray_seg, exp_dst_parax):
    """Given the exiting interface and chief ray data, return exit pupil ray coords.

    Args:
        interface: the exiting :class:'~.Interface' for the path sequence
        ray_seg: ray segment exiting from **interface**
        exp_dst_parax: z distance to the paraxial exit pupil

    Returns:
        (**exp_pt**, **exp_dir**, **exp_dst**)

        - **exp_pt** - ray intersection with exit pupil plane
        - **exp_dir** - direction cosine of the ray in exit pupil space
        - **exp_dst** - distance from interface to exit pupil pt
    """
    b4_pt, b4_dir = transform_after_surface(interface, ray_seg)

    # h = b4_pt[0]**2 + b4_pt[1]**2
    # u = b4_dir[0]**2 + b4_dir[1]**2
    # handle field points in the YZ plane
    h = b4_pt[1]
    u = b4_dir[1]
    if abs(u) < 1e-14:
        exp_dst = exp_dst_parax
    else:
        # exp_dst = -np.sign(b4_dir[2])*sqrt(h/u)
        exp_dst = -h/u

    exp_pt = b4_pt + exp_dst*b4_dir
    exp_dir = b4_dir

    return exp_pt, exp_dir, exp_dst, interface, b4_pt, b4_dir
Example #3
0
def wave_abr_full_calc(fod, fld, wvl, foc, ray_pkg, chief_ray_pkg, ref_sphere):
    """Given a ray, a chief ray and an image pt, evaluate the OPD.

    The main references for the calculations are in the H. H. Hopkins paper
    `Calculation of the Aberrations and Image Assessment for a General Optical
    System <https://doi.org/10.1080/713820605>`_

    Args:
        fod: :class:`~.FirstOrderData` for object and image space refractive
             indices
        fld: :class:`~.Field` point for wave aberration calculation
        wvl: wavelength of ray (nm)
        foc: defocus amount
        ray_pkg: input tuple of ray, ray_op, wvl
        chief_ray_pkg: input tuple of chief_ray, cr_exp_seg
        ref_sphere: input tuple of image_pt, ref_dir, ref_sphere_radius

    Returns:
        opd: OPD of ray wrt chief ray at **fld**
    """
    image_pt, ref_dir, ref_sphere_radius = ref_sphere
    cr, cr_exp_seg = chief_ray_pkg
    chief_ray, chief_ray_op, wvl = cr
    cr_exp_pt, cr_exp_dir, cr_exp_dist, ifc, cr_b4_pt, cr_b4_dir = cr_exp_seg

    ray, ray_op, wvl = ray_pkg

    k = -2  # last interface in sequence

    # eq 3.12
    e1 = eic_distance((ray[1][mc.p], ray[0][mc.d]),
                      (chief_ray[1][mc.p], chief_ray[0][mc.d]))
    # eq 3.13
    ekp = eic_distance((ray[k][mc.p], ray[k][mc.d]),
                       (chief_ray[k][mc.p], chief_ray[k][mc.d]))

    b4_pt, b4_dir = transform_after_surface(ifc, (ray[k][mc.p], ray[k][mc.d]))
    dst = ekp - cr_exp_dist
    eic_exp_pt = b4_pt - dst * b4_dir
    p_coord = eic_exp_pt - cr_exp_pt

    F = ref_dir.dot(b4_dir) - b4_dir.dot(p_coord) / ref_sphere_radius
    J = p_coord.dot(p_coord) / ref_sphere_radius - 2.0 * ref_dir.dot(p_coord)

    sign_soln = -1 if ref_dir[2] * cr.ray[-1][mc.d][2] < 0 else 1
    denom = F + sign_soln * sqrt(F**2 + J / ref_sphere_radius)
    ep = 0 if denom == 0 else J / denom

    n_obj = abs(fod.n_obj)
    n_img = abs(fod.n_img)
    opd = -n_obj * e1 - ray_op + n_img * ekp + chief_ray_op - n_img * ep

    return opd
Example #4
0
def calc_delta_op_via_eic(ray, path):
    """ computes equally inclined chords and path info for ray

    Args:
        ray: ray data for traced ray
        path: an iterator containing interfaces and gaps to be traced.
              for each iteration, the sequence or generator should return a
              list containing: **Intfc, Gap, Trfm, Index, Z_Dir**

    Returns:
        (**eic**, **op_delta**)

        - **eic** - list of [n_before, eic_dst_before, n_after, eic_dst_after,
          dW]
        - **op_delta** - optical path wrt equally inclined chords to the
          optical axis
    """
    eic = []

    ray_seq_iter = zip(ray, path)
    before = next(ray_seq_iter)
    before_ray_seg, obj_surf = before

    z_dir_before = obj_surf[Zdir]
    n_before = obj_surf[Indx]

    before_dir = before_ray_seg[mc.d]

    for i, item in enumerate(ray_seq_iter):
        after_ray_seg, surf = item

        inc_pt = after_ray_seg[mc.p]
        after_dir = after_ray_seg[mc.d]

        b4_pt, b4_dir = transform_before_surface(surf[Intfc],
                                                 (inc_pt, before_dir))
        e = eic_distance_from_axis((b4_pt, before_dir), z_dir_before)

        z_dir_after = surf[Zdir]
        aft_pt, aft_dir = transform_after_surface(surf[Intfc],
                                                  (inc_pt, after_dir))
        ep = eic_distance_from_axis((aft_pt, aft_dir), z_dir_after)

        # eic_dst_before = ((inc_pt.dot(b4_dir) + z_dir_before*inc_pt[2]) /
        #                   (1.0 + z_dir_before*b4_dir[2]))

        # Per `Hopkins, 1981 <https://dx.doi.org/10.1080/713820605>`_, the
        #  propagation direction is given by the direction cosines of the ray
        #  and therefore doesn't require the use of a negated refractive index
        #  following a reflection. Thus we use the (positive) refractive indices
        #  from the seq_model.rndx array.
        n_after = surf[Indx]
        dW = n_after*ep - n_before*e

        eic.append([n_before, e, n_after, ep, dW])
        print("e{}= {:12.5g} e{}'= {:12.5g} dW={:10.8g} n={:8.5g}"
              " n'={:8.5g}".format(i, e, i, ep, dW, n_before, n_after))

        n_before = n_after
        before_dir = after_dir
        z_dir_before = z_dir_after

    P, P1k, Ps = calc_path_length(eic, offset=1)
    return eic, P, P1k, Ps