ModuleTolerancing
Provides functions for analysing the alignment tolerance of a system.
Mostly it consists in mis-aligning the optical elements of the system and checking the impact on the focal spot and delays.
There are two parts to this module:
- Misaligning/deteriorating the optical elements of the system
- Analysing the impact of these misalignments on the focal spot and delays
The end goal is to have a simple function "GetTolerance" that will return the tolerance of the system to misalignments of each optical element.
Created in Nov 2024
@author: Andre Kalouguine
1""" 2Provides functions for analysing the alignment tolerance of a system. 3 4Mostly it consists in mis-aligning the optical elements of the system and checking the impact on the focal spot and delays. 5 6There are two parts to this module: 7- Misaligning/deteriorating the optical elements of the system 8- Analysing the impact of these misalignments on the focal spot and delays 9 10The end goal is to have a simple function "GetTolerance" that will return the tolerance of the system to misalignments of each optical element. 11 12Created in Nov 2024 13 14@author: Andre Kalouguine 15""" 16import numpy as np 17import matplotlib.pyplot as plt 18from copy import copy 19from scipy.stats import linregress 20 21import ARTcore.ModuleOpticalChain as moc 22 23 24def GetTolerance(OpticalChain, 25 time_error=1.0, 26 Detector = "Focus", 27 n_iter = 5, 28 elements_to_misalign = None): 29 """ 30 Returns the tolerance of the system to misalignments of each optical element. 31 It first constructs a normalisation vector: 32 For each optical element, for each degree of freedom, it iteratively calculates the required amplitude of misalignment to reach the time_error. 33 This gives a n-dimensional vector. The smaller the value, the more sensitive the system is to misalignments of this axis. 34 """ 35 # Define the normalisation vector 36 normalisation_vector = np.zeros(len(OpticalChain.optical_elements) * 6)*np.nan 37 durations = np.zeros(len(OpticalChain.optical_elements) * 6)*np.nan 38 misalignments = ["rotate_roll_by", "rotate_pitch_by", "rotate_yaw_by", "shift_along_normal", "shift_along_major", "shift_along_cross"] 39 if elements_to_misalign is None: 40 elements_to_misalign = range(len(OpticalChain.optical_elements)) 41 if isinstance(Detector, str): 42 Det = OpticalChain.detectors[Detector] 43 else: 44 Det = Detector 45 for i in elements_to_misalign: 46 for j in range(6): 47 # Misalign the optical element 48 amplitude = 1e-3 49 for k in range(n_iter): 50 try: 51 misaligned_optical_chain = copy(OpticalChain) 52 r_before = misaligned_optical_chain[i].r 53 q_before = misaligned_optical_chain[i].q 54 misaligned_optical_chain[i].__getattribute__(misalignments[j])(amplitude) 55 r_after = misaligned_optical_chain[i].r 56 q_after = misaligned_optical_chain[i].q 57 rays = misaligned_optical_chain.get_output_rays() 58 Det.optimise_distance(rays[Det.index], [Det.distance-100, Det.distance+100], Det._spot_size, maxiter=10, tol=1e-10) 59 except: 60 print(f"OE {i} failed to misalign {misalignments[j]} by {amplitude}") 61 amplitude /= 10 62 continue 63 rays = misaligned_optical_chain.get_output_rays(force=True) 64 duration = np.std(Det.get_Delays(rays[Det.index])) 65 if len(rays[Det.index]) <= 50: 66 amplitude /= 2 67 continue 68 if duration > time_error: 69 amplitude /= 3 70 elif duration < time_error / 10: 71 amplitude *= 3 72 elif duration < time_error / 1.5: 73 amplitude *= 1.2 74 else: 75 break 76 if not (time_error/2 < duration < time_error*2): 77 print(f"OE {i} failed to misalign {misalignments[j]} by {amplitude}: duration = {duration}") 78 if duration > time_error: 79 amplitude = np.nan 80 else: 81 amplitude = 0.1 82 normalisation_vector[i*6+j] = amplitude 83 durations[i*6+j] = duration 84 return normalisation_vector, durations
25def GetTolerance(OpticalChain, 26 time_error=1.0, 27 Detector = "Focus", 28 n_iter = 5, 29 elements_to_misalign = None): 30 """ 31 Returns the tolerance of the system to misalignments of each optical element. 32 It first constructs a normalisation vector: 33 For each optical element, for each degree of freedom, it iteratively calculates the required amplitude of misalignment to reach the time_error. 34 This gives a n-dimensional vector. The smaller the value, the more sensitive the system is to misalignments of this axis. 35 """ 36 # Define the normalisation vector 37 normalisation_vector = np.zeros(len(OpticalChain.optical_elements) * 6)*np.nan 38 durations = np.zeros(len(OpticalChain.optical_elements) * 6)*np.nan 39 misalignments = ["rotate_roll_by", "rotate_pitch_by", "rotate_yaw_by", "shift_along_normal", "shift_along_major", "shift_along_cross"] 40 if elements_to_misalign is None: 41 elements_to_misalign = range(len(OpticalChain.optical_elements)) 42 if isinstance(Detector, str): 43 Det = OpticalChain.detectors[Detector] 44 else: 45 Det = Detector 46 for i in elements_to_misalign: 47 for j in range(6): 48 # Misalign the optical element 49 amplitude = 1e-3 50 for k in range(n_iter): 51 try: 52 misaligned_optical_chain = copy(OpticalChain) 53 r_before = misaligned_optical_chain[i].r 54 q_before = misaligned_optical_chain[i].q 55 misaligned_optical_chain[i].__getattribute__(misalignments[j])(amplitude) 56 r_after = misaligned_optical_chain[i].r 57 q_after = misaligned_optical_chain[i].q 58 rays = misaligned_optical_chain.get_output_rays() 59 Det.optimise_distance(rays[Det.index], [Det.distance-100, Det.distance+100], Det._spot_size, maxiter=10, tol=1e-10) 60 except: 61 print(f"OE {i} failed to misalign {misalignments[j]} by {amplitude}") 62 amplitude /= 10 63 continue 64 rays = misaligned_optical_chain.get_output_rays(force=True) 65 duration = np.std(Det.get_Delays(rays[Det.index])) 66 if len(rays[Det.index]) <= 50: 67 amplitude /= 2 68 continue 69 if duration > time_error: 70 amplitude /= 3 71 elif duration < time_error / 10: 72 amplitude *= 3 73 elif duration < time_error / 1.5: 74 amplitude *= 1.2 75 else: 76 break 77 if not (time_error/2 < duration < time_error*2): 78 print(f"OE {i} failed to misalign {misalignments[j]} by {amplitude}: duration = {duration}") 79 if duration > time_error: 80 amplitude = np.nan 81 else: 82 amplitude = 0.1 83 normalisation_vector[i*6+j] = amplitude 84 durations[i*6+j] = duration 85 return normalisation_vector, durations
Returns the tolerance of the system to misalignments of each optical element. It first constructs a normalisation vector: For each optical element, for each degree of freedom, it iteratively calculates the required amplitude of misalignment to reach the time_error. This gives a n-dimensional vector. The smaller the value, the more sensitive the system is to misalignments of this axis.