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