Esempio n. 1
0
def get_output_wavevector(kin, crystal, grating_order=None):
    if crystal.type is "Crystal: Bragg Reflection":
        kout = util.get_bragg_kout(kin=kin,
                                   h=crystal.h,
                                   normal=crystal.normal,
                                   compare_length=False)
        return kout
    if crystal.type is "Transmissive Grating":
        kout = kin + grating_order * crystal.base_wave_vector
        return kout
Esempio n. 2
0
def get_point_with_definite_path(kin_vec, path_sections, crystal_list,
                                 init_point):
    """
    Provide the crystals, calculate teh corresponding intersection points.

    :param kin_vec:
    :param path_sections:
    :param crystal_list:
    :param init_point:
    :return:
    """
    # Get the number of crystals
    num = len(crystal_list)

    # Prepare holders for the calculation
    intersect_list = np.zeros((num, 3), dtype=np.float64)
    kout_list = np.zeros((num, 3), dtype=np.float64)

    # Copy the initial point
    init = np.copy(init_point)
    kin = np.copy(kin_vec)

    for idx in range(num):
        # Get the reflected wavevector
        kout = util.get_bragg_kout(kin=kin,
                                   h=crystal_list[idx].h,
                                   normal=crystal_list[idx].normal,
                                   compare_length=False)

        # Get the next intersection point
        intersect = init + kout * path_sections[idx] / util.l2_norm(kout)

        # Update the intersection list and the kout list
        kout_list[idx, :] = kout[:]
        intersect_list[idx, :] = intersect[:]

        # Update the kin and init
        init = np.copy(intersect)
        kin = np.copy(kout)

    return intersect_list, kout_list
Esempio n. 3
0
def get_lightpath(device_list, kin, initial_point, final_plane_point, final_plane_normal):
    """
    This function is used to generate the light path of the incident wave vector in the series of
    devices.

    This function correctly handles the light path through the telescopes.

    :param device_list:
    :param kin:
    :param initial_point:
    :param final_plane_normal:
    :param final_plane_point:
    :return:
    """

    # Create a holder for kout vectors
    kout_list = [np.copy(kin), ]

    # Create a list for the intersection points
    intersection_list = [np.copy(initial_point)]

    # Path length
    path_length = 0.

    # Loop through all the devices.
    for idx in range(len(device_list)):

        ###############################################################
        # Step 1: Get the device
        device = device_list[idx]

        ###############################################################
        # Step 2: Find the intersection and kout
        if device.type == "Crystal: Bragg Reflection":
            intersection_list.append(util.get_intersection(s=intersection_list[-1],
                                                           k=kout_list[-1],
                                                           n=device.normal,
                                                           x0=device.surface_point))
            # Find the path length
            displacement = intersection_list[-1] - intersection_list[-2]
            path_length += np.dot(displacement, kout_list[-1]) / util.l2_norm(kout_list[-1])

            # Find the output k vector
            kout_list.append(util.get_bragg_kout(kin=kout_list[-1],
                                                 h=device.h,
                                                 normal=device.normal))

        if device.type == "Transmissive Grating":
            intersection_list.append(util.get_intersection(s=intersection_list[-1],
                                                           k=kout_list[-1],
                                                           n=device.normal,
                                                           x0=device.surface_point))
            # Find the path length
            displacement = intersection_list[-1] - intersection_list[-2]
            path_length += np.dot(displacement, kout_list[-1]) / util.l2_norm(kout_list[-1])

            # Find the wave vecotr
            kout_list.append(kout_list[-1] + device.momentum_transfer)

    ################################################################
    # Step 3: Find the output position on the observation plane
    intersection_list.append(util.get_intersection(s=intersection_list[-1],
                                                   k=kout_list[-1],
                                                   x0=final_plane_point,
                                                   n=final_plane_normal))
    # Update the path length
    displacement = intersection_list[-1] - intersection_list[-2]
    path_length += np.dot(displacement, kout_list[-1]) / util.l2_norm(kout_list[-1])

    return intersection_list, kout_list, path_length
Esempio n. 4
0
def get_light_trajectory_with_total_path(kin_vec, init_point, total_path,
                                         crystal_list, g_orders):
    """
    Get the light path for one of the branch.

    :param kin_vec: The incident wave vector with a shape of (3,)
    :param init_point:
    :param total_path:
    :param crystal_list:
    :param g_orders: The diffraction orders of the gratings
    :return:
    """
    # Create holder for the calculation
    num = len(crystal_list) + 1
    intersect_array = np.zeros((num, 3), dtype=np.float64)
    kout_array = np.zeros((num, 3), dtype=np.float64)

    intersect_array[0, :] = np.copy(init_point)
    kout_array[0, :] = np.copy(kin_vec)

    # Create auxiliary variables for the calculation
    g_idx = 0  # The index for grating
    remain_path = np.copy(total_path)

    # Loop through all the crystals to get the path
    for idx in range(1, num):
        crystal_obj = crystal_list[idx - 1]
        # Get the output wave vector
        if crystal_obj.type == "Crystal: Bragg Reflection":
            kout_array[idx, :] = util.get_bragg_kout(kin=kout_array[idx - 1],
                                                     h=crystal_obj.h,
                                                     normal=crystal_obj.normal,
                                                     compare_length=False)
        if crystal_obj.type == "Transmissive Grating":
            kout_array[idx, :] = (
                kout_array[idx - 1] +
                g_orders[g_idx] * crystal_obj.base_wave_vector)
            # Update the index of the grating
            g_idx += 1

        # The last intersection point need to be calculated individually
        if idx == num - 1:
            break

        # Get the new intersection point
        intersect_array[idx] = util.get_intersection(
            s=intersect_array[idx - 1],
            k=kout_array[idx],
            n=crystal_list[idx].normal,
            x0=crystal_list[idx].surface_point)
        # Get the remaining path
        path_tmp = util.l2_norm(intersect_array[idx] -
                                intersect_array[idx - 1])

        # If the path length is not long enough to cover the whole device, then stop early.
        if path_tmp > remain_path:
            intersect_array[idx] = (
                intersect_array[idx - 1] +
                kout_array[idx] * remain_path / util.l2_norm(kout_array[idx]))
            return intersect_array, kout_array
        else:
            remain_path -= path_tmp

    # If the path length is long though to cover the whole path, then calculate the final point
    intersect_array[-1] = (
        intersect_array[-2] +
        kout_array[-1] * remain_path / util.l2_norm(kout_array[-1]))

    return intersect_array, kout_array