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