import numpy as np from scipy.optimize import root_scalar import xraylib """ pyDevice TO DO: WHAT inputs change the focal size arrays? Energy, what else? WHAT inputs change the search through the arrays? desired focal size, what else? IOC init functions -get lens stack parameters (# of lenses in each stack, radius, location, thickness, thickness error) -- from substitution file but put into PVs? Update with autosave? -get source info -energy from from ID IOC -hor/vert sizes and divergence (also energy dependent) -lens diameter table? What is it doing? -desired focal size is changed --> what needs updating? --> nothing, just need to search focal size array again -multiple flags: is focal size achievable? is it achievable at sample? recalc function -- should probably be same as init function -energy is updated --> what needs updating? -what else could user/staff change? sample position? """ # Beamline input block energy = 15000.0 # Energy in eV energy_keV = energy/1000.0 # Energy in keV wl = 1239.84 / (energy * 10**9) d_StoL1 = 51.9 # Source-to-CRL1 distance, in m d_StoL2 = 62.1 # Source-to-CRL2 distance, in m d_Stof = 66.2 # Source-to-focus distance, in m #slit1_H = 500.0e-6 # H slit size before CRL 1 #slit1_V = 300.0e-6 # V slit size before CRL 1 # CRL input block d_min = 3.0e-5 # Minimum thickness at the apex in m stack_d = 50.0e-3 # Stack thickness in m L1_n = np.array([1, 1, 1, 1, 1, 1, 2, 4, 8, 16]) # CRL1 number of lenses in each stack L1_R = np.array([2.0e-3, 1.0e-3, 5.0e-4, 3.0e-4, 2.0e-4, 1.0e-4, 1.0e-4, 1.0e-4, 1.0e-4, 1.0e-4]) # CRL1 lens radius in each stack L1_mater= np.array(["Be", "Be", "Be", "Be", "Be", "Be", "Be", "Be", "Be", "Be"]) # CRL1 lens material in each stack L1_loc = np.array([4.5, 3.5, 2.5, 1.5, 0.5, -0.5, -1.5, -2.5, -3.5, -4.5])*stack_d # CRL1 lens stack location relative to center stack, positive means upstream L1_HE = np.array([1.0e-6, 1.0e-6, 1.0e-6, 1.0e-6, 1.0e-6, 1.0e-6, 1.4e-6, 2.0e-6, 2.8e-6, 4.0e-6]) # CRL1 lens RMS thickness error # Source size input block L_und = 4.7 # undulator length sigmaH_e = 14.8e-6 # Sigma electron source size in H direction in m sigmaV_e = 3.7e-6 # Sigma electron source size in V direction in m sigmaHp_e = 2.8e-6 # Sigma electron divergence in H direction in rad sigmaVp_e = 1.5e-6 # Sigma electron divergence in V direction in rad sigmaH = (sigmaH_e**2 + wl*L_und/2/np.pi/np.pi)**0.5 sigmaV = (sigmaV_e**2 + wl*L_und/2/np.pi/np.pi)**0.5 sigmaHp = (sigmaHp_e**2 + wl/L_und/2)**0.5 sigmaVp = (sigmaVp_e**2 + wl/L_und/2)**0.5 # Lookup table where each entry is a tuple (column1, column2) Lens_diameter_table = [ (50, 450.0), (100, 632.0), (200, 894.0), (300, 1095.0), (500, 1414.0), (1000, 2000.0), (1500, 2450.0), ] # Convert the lookup table to a dictionary for faster lookup Lens_diameter_dict = {int(col1): col2 for col1, col2 in Lens_diameter_table} def lookup_diameter(lens_radius): # Convert the input float to an integer input_int = int(round(lens_radius*1.0e6)) return Lens_diameter_dict.get(input_int, (lens_radius*1.0e6)**0.5*63.222+ 0.73)/1.0e6 def index_to_binary_list(index, length): """ Converts an index number to its binary representation as a list of digits, and pads the list with zeros in front to achieve the desired length. Parameters: index (int): The index number to be converted. length (int): The desired length of the binary list. Returns: list: A list of digits representing the binary representation of the index. """ # Convert the index to a binary string and remove the '0b' prefix binary_str = bin(index)[2:] # Pad the binary string with zeros in front to achieve the desired length #padded_binary_str = binary_str.zfill(length) # Reverse the binary string reversed_binary_str = binary_str[::-1] # Convert the reversed binary string to a list of integers binary_list = [int(digit) for digit in reversed_binary_str] # Pad the list with zeros at the end to achieve the desired length while len(binary_list) < length: binary_list.append(0) return binary_list def binary_list_to_index(binary_list, length): """ Converts a list of binary digits in reverse order to its integer representation, padding the list with zeros at the end to have a fixed number of elements. Parameters: binary_list (list): A list of digits representing the binary number in reverse order. length (int): The fixed number of elements the list should have. Returns: int: The integer representation of the binary number. """ # Pad the list with zeros at the end to achieve the desired length while len(binary_list) < length: binary_list.append(0) # Convert the binary list to an integer index = 0 for i, digit in enumerate(binary_list): index += digit * 2**i return index def materials_to_deltas(material_list, energy): """ Convert a list of material names to a list of delta values at a given energy. Parameters: material_list (list): A list of material names. energy (float): The energy in keV. Returns: list: A list of delta values for the given materials at the given energy. """ # The list to store delta values delta_list = [] # Iterate through each material in the input list for material in material_list: # Compute the delta value for the current material at the given energy Z = xraylib.SymbolToAtomicNumber(material) density = xraylib.ElementDensity(Z) delta = 1.0-xraylib.Refractive_Index_Re(material, energy, density) # Add the delta value to the delta list delta_list.append(delta) return delta_list def materials_to_linear_attenuation(material_list, energy): """ Convert a list of material names to a list of linear attenuation coefficients at a given energy. Parameters: material_list (list): A list of material names. energy (float): The energy in keV. Returns: list: A list of linear attenuation coefficient values (in m^-1) for the given materials at the given energy. """ # The list to store linear attenuation coefficient values mu_list = [] # Iterate through each material in the input list for material in material_list: # Compute the delta value for the current material at the given energy Z = xraylib.SymbolToAtomicNumber(material) density = xraylib.ElementDensity(Z) # Compute the mass attenuation coefficient in cm^2/g #mass_attenuation = xraylib.CS_Photo(Z, energy) mass_attenuation = xraylib.CS_Total(Z, energy) # Convert mass attenuation coefficient to linear attenuation coefficient in m^-1 mu = mass_attenuation * density * 100.0 # Add the linear attenuation coefficient value to the list mu_list.append(mu) return mu_list def absorptionaperture(x, n1mud, sigma, n1mur): numerator = np.exp(-(x**2/(2*sigma**2))) * np.exp(-n1mur*(x**2) - n1mud) denominator = np.exp(-n1mud) return numerator / denominator - 0.5 def find_levels(array, levels, direction='forward'): """ Find the first indices at which the array crosses specified levels and the corresponding crossed values. Parameters: array (numpy.ndarray): An array of numbers. levels (float or numpy.ndarray): A number or an array of levels to find crossings. direction (str, optional): The searching direction. Defaults to 'forward'. Can be either 'forward' or 'backward'. Returns: tuple: A tuple containing two arrays: - An array of first indices at which the array crosses the specified levels. - An array of first crossed values at the corresponding indices. """ # Convert a single level to a numpy array if isinstance(levels, (int, float)): levels = np.array([levels]) indices = [] values = [] # Compute the max and min of the array ignoring NaNs max_val = np.nanmax(array) min_val = np.nanmin(array) for level in levels: # If level is out of bounds if level > max_val or level < min_val: indices.append(-1) values.append(np.nan) continue crossings = [] if direction == 'forward': for i in range(1, len(array)): if np.isnan(array[i - 1]) or np.isnan(array[i]): continue if (array[i - 1] < level <= array[i]) or (array[i - 1] > level >= array[i]): crossings.append(i - 1) break elif direction == 'backward': for i in range(len(array) - 2, -1, -1): if np.isnan(array[i + 1]) or np.isnan(array[i]): continue if (array[i + 1] < level <= array[i]) or (array[i + 1] > level >= array[i]): crossings.append(i) break else: raise ValueError("Invalid direction. It should be either 'forward' or 'backward'.") if len(crossings) > 0: idx = crossings[0] indices.append(idx) values.append(array[idx]) else: # In case no crossing is found within the range indices.append(-1) values.append(np.nan) return np.array(indices), np.array(values) def Single_CRL2D_control(fsize): L1_D = np.zeros(L1_R.size) # CRL1 diameters for each stack for i in range(L1_R.size): L1_D[i] = lookup_diameter(L1_R[i]) L1_delta = materials_to_deltas(L1_mater, energy_keV) # delta values for CRL1 stacks L1_mu = materials_to_linear_attenuation(L1_mater, energy_keV) # mu values for CRL1 stacks L1_Feq = L1_R/(2*L1_n*L1_delta) + L1_loc # CRL1 equivalent f in m for each stack L1_index_n = 2**L1_Feq.size # Total number of combinations for CRL1 L1_invF_list= np.zeros(L1_index_n) # List of equivalent 1/f in m^-1 for CRL1 for i in range(L1_index_n): L1_invF_list[i] = np.sum(index_to_binary_list(i, L1_Feq.size)/L1_Feq) # Sort the L1_invF list (to avoid zigzagging) L1_invF_list_sort_indices = np.argsort(L1_invF_list) L1_invF_list_sorted = L1_invF_list[L1_invF_list_sort_indices] q1_list = 1/(L1_invF_list_sorted - 1/d_StoL1) # focal position of CRL1 for all configurations (sorted) dq1_list = q1_list - (d_Stof - d_StoL1) # Start generating focal size list as a function of CRL1 setting sigma1H = (sigmaH**2 + (sigmaHp*d_StoL1)**2)**0.5 # sigma beam size before CRL1 sigma1V = (sigmaV**2 + (sigmaVp*d_StoL1)**2)**0.5 # sigma beam size before CRL1 L1_n1mud_list = np.zeros(L1_index_n) # List of n1*mu*d_min for all possible CRL1 configurations L1_n1muR_list = np.zeros(L1_index_n) # List of n1*mu/R for all possible CRL1 configurations aperL1H_list = np.zeros(L1_index_n) # absorption H aperture of CRL1 for all configurations aperL1V_list = np.zeros(L1_index_n) # absorption V aperture of CRL1 for all configurations diameter1_list = np.zeros(L1_index_n) # CRL1 diameter for all possible configurations FWHM1H_list = np.zeros(L1_index_n) # H focal size at the focus of CRL1 FWHM1V_list = np.zeros(L1_index_n) # V focal size at the focus of CRL1 Strehl_list = np.zeros(L1_index_n) # Strehl ratio based on lens thickness error for i in range(L1_index_n): # absorption aperture is a function of CRL absorption/physical aperture, incident beam size, and physical slits L1_n1mud_list[i] = np.sum(index_to_binary_list(L1_invF_list_sort_indices[i], L1_Feq.size)*np.array(L1_mu*L1_n*d_min)) L1_n1muR_list[i] = np.sum(index_to_binary_list(L1_invF_list_sort_indices[i], L1_Feq.size)*np.array(L1_mu*L1_n/L1_R)) solution = root_scalar(absorptionaperture, args=(L1_n1mud_list[i], sigma1H, L1_n1muR_list[i]), bracket=[0.0, 2*sigma1H], method='bisect') aperL1H_list[i] = solution.root*2.0 solution = root_scalar(absorptionaperture, args=(L1_n1mud_list[i], sigma1V, L1_n1muR_list[i]), bracket=[0.0, 2*sigma1V], method='bisect') aperL1V_list[i] = solution.root*2.0 mask = (np.array(index_to_binary_list(L1_invF_list_sort_indices[i], L1_Feq.size)) == 1) if np.all(mask == False): diameter1_list[i] = np.inf else: diameter1_list[i] = np.min(L1_D[mask]) aperL1H_list[i] = min(aperL1H_list[i], diameter1_list[i], slit1_H) aperL1V_list[i] = min(aperL1V_list[i], diameter1_list[i], slit1_V) phase_error_tmp = np.linalg.norm(index_to_binary_list(L1_invF_list_sort_indices[i], L1_Feq.size)*np.array(L1_HE*L1_delta)*2*np.pi/wl) Strehl_list[i] = np.exp(-phase_error_tmp**2) # FWHMbeam size at CRL1 focus FWHM1H_list = ((0.88*wl*q1_list/aperL1H_list)**2 + (2.355*sigmaH*q1_list/d_StoL1)**2)**0.5 FWHM1V_list = ((0.88*wl*q1_list/aperL1V_list)**2 + (2.355*sigmaV*q1_list/d_StoL1)**2)**0.5 if flag_HE: FWHM1H_list *= (Strehl_list)**(-0.5) FWHM1V_list *= (Strehl_list)**(-0.5) FWHM_list = (FWHM1H_list*FWHM1V_list)**0.5 indices, values = find_levels(FWHM_list, fsize, direction='backward') index = indices[0] if index == -1: print(f"Cannot achieve the focal size {fsize*1.0e6:.2f} μm") else: print("======== Find size at focus ========================================") print(f"Energy: {energy_keV} keV") print(f"CRL1 configuration index in sorted list is {index}") print(f"CRL1 configuration index is {L1_invF_list_sort_indices[index]} or {index_to_binary_list(L1_invF_list_sort_indices[index], L1_Feq.size)}") print(f"CRL1 f is {1/L1_invF_list_sorted[index]:.2f} m, focus at q1 = {q1_list[index]:.2f} m") print(f"Focal size is {FWHM1H_list[index]*1.0e6:.2f} μm x {FWHM1V_list[index]*1.0e6:.2f} μm at the focal point ({dq1_list[index]*1e3:.1f} mm from sample)") FWHM1H_atsample_list = (FWHM1H_list**2 + (aperL1H_list*dq1_list/q1_list)**2)**0.5 FWHM1V_atsample_list = (FWHM1V_list**2 + (aperL1V_list*dq1_list/q1_list)**2)**0.5 FWHM_atsample_list = (FWHM1H_atsample_list*FWHM1V_atsample_list)**0.5 indices, values = find_levels(FWHM_atsample_list, fsize, direction='forward') index2 = indices[0] if index2 == -1: print(f"Cannot achieve the bame size {fsize*1.0e6:.2f} μm at sample") else: print("======== Find size at sample =======================================") print(f"CRL1 configuration index in sorted list is {index2}") print(f"CRL1 configuration index is {L1_invF_list_sort_indices[index2]} or {index_to_binary_list(L1_invF_list_sort_indices[index2], L1_Feq.size)}") print(f"CRL1 f is {1/L1_invF_list_sorted[index2]:.2f} m, focus at q1 = {q1_list[index2]:.2f} m ({dq1_list[index2]*1e3:.1f} mm from sample)") print(f"Beam size is {FWHM1H_atsample_list[index2]*1.0e6:.2f} μm x {FWHM1V_atsample_list[index2]*1.0e6:.2f} μm at the sample position)") indices, values = find_levels(dq1_list, 0.0, direction='backward') index3 = indices[0] if index == -1: print(f"Cannot find combination to focus close to sample") else: print("======== Find configuration focus close to the sample ==============") print(f"CRL1 configuration index in sorted list is {index3}") print(f"CRL1 configuration index is {L1_invF_list_sort_indices[index3]} or {index_to_binary_list(L1_invF_list_sort_indices[index3], L1_Feq.size)}") print(f"CRL1 f is {1/L1_invF_list_sorted[index3]:.2f} m, focus at q1 = {q1_list[index3]:.2f} m ({dq1_list[index3]*1e3:.1f} mm from sample)") print(f"Beam size is {FWHM1H_atsample_list[index3]*1.0e6:.2f} μm x {FWHM1V_atsample_list[index3]*1.0e6:.2f} μm at the sample position)") return if __name__ == "__main__": flag_HE = True fsize = 50.0e-6 # Desired focal size in m (area average of h and v size) #Single_CRL2D_control(fsize) # Find the best configuration for a single transfocator system ''' Update the following to accommodate XS code ''' class singleTF(): def __init__(self): # Initialize beamline layout variables self.d_StoL = 51.9 # Source-to-CRL1 distance, in m self.d_Stof = 66.2 # Source-to-focus distance, in m # Initialize source variables self.L_und = 4.7 self.energy = 15000.0 # Energy in eV self.energy_keV = self.energy/1000.0 # Energy in keV self.wl = 1239.84 / (self.energy * 10**9) #Wavelength in nm(?) self.sigmaH_e = 14.8e-6 # Sigma electron source size in H direction in m self.sigmaV_e = 3.7e-6 # Sigma electron source size in V direction in m self.sigmaHp_e = 2.8e-6 # Sigma electron divergence in H direction in rad self.sigmaVp_e = 1.5e-6 # Sigma electron divergence in V direction in rad self.sigmaH = (self.sigmaH_e**2 + self.wl*self.L_und/2/np.pi/np.pi)**0.5 self.sigmaV = (self.sigmaV_e**2 + self.wl*self.L_und/2/np.pi/np.pi)**0.5 self.sigmaHp = (self.sigmaHp_e**2 + self.wl/self.L_und/2)**0.5 self.sigmaVp = (self.sigmaVp_e**2 + self.wl/self.L_und/2)**0.5 # Initialize lens variables self.d_min = 3.0e-5 # Minimum thickness at the apex in m self.stack_d = 50.0e-3 # Stack thickness in m self.L1_n = np.array([1, 1, 1, 1, 1, 1, 2, 4, 8, 16]) # CRL1 number of lenses in each stack self.L1_R = np.array([2.0e-3, 1.0e-3, 5.0e-4, 3.0e-4, 2.0e-4, 1.0e-4, 1.0e-4, 1.0e-4, 1.0e-4, 1.0e-4]) # CRL1 lens radius in each stack self.L1_mater= np.array(["Be", "Be", "Be", "Be", "Be", "Be", "Be", "Be", "Be", "Be"]) # CRL1 lens material in each stack self.L1_loc = np.array([4.5, 3.5, 2.5, 1.5, 0.5, -0.5, -1.5, -2.5, -3.5, -4.5])*stack_d # CRL1 lens stack location relative to center stack, positive means upstream self.L1_HE = np.array([1.0e-6, 1.0e-6, 1.0e-6, 1.0e-6, 1.0e-6, 1.0e-6, 1.4e-6, 2.0e-6, 2.8e-6, 4.0e-6]) # CRL1 lens RMS thickness error self.Lens_diameter_table = [ (50, 450.0), (100, 632.0), (200, 894.0), (300, 1095.0), (500, 1414.0), (1000, 2000.0), (1500, 2450.0), ] # Convert the lookup table to a dictionary for faster lookup self.Lens_diameter_dict = {int(col1): col2 for col1, col2 in Lens_diameter_table} # Initialize pre-CRL slit size self.slit1_H = 500.0e-6 # H slit size before CRL 1 self.slit1_V = 300.0e-6 # V slit size before CRL 1 #Calc lookup table self.lookup_table=calc_lookup_table(self, ...) self.energy = 0 # gets value from an ao (incoming beam energy) self.focalSize = 0 # get value from an ao (desired focal length) self.lenses = 0 # sets integer (2^12) whose binary representation indicates which lenses are in or out def setSource(self): self.L_und = 4.7 self.energy = 15000.0 # Energy in eV self.energy_keV = self.energy/1000.0 # Energy in keV self.wl = 1239.84 / (self.energy * 10**9) #Wavelength in nm(?) self.sigmaH_e = 14.8e-6 # Sigma electron source size in H direction in m self.sigmaV_e = 3.7e-6 # Sigma electron source size in V direction in m self.sigmaHp_e = 2.8e-6 # Sigma electron divergence in H direction in rad self.sigmaVp_e = 1.5e-6 # Sigma electron divergence in V direction in rad self.sigmaH = (self.sigmaH_e**2 + self.wl*self.L_und/2/np.pi/np.pi)**0.5 self.sigmaV = (self.sigmaV_e**2 + self.wl*self.L_und/2/np.pi/np.pi)**0.5 self.sigmaHp = (self.sigmaHp_e**2 + self.wl/self.L_und/2)**0.5 self.sigmaVp = (self.sigmaVp_e**2 + self.wl/self.L_und/2)**0.5 #any update calcs to be called? def setBeamline(self): self.d_StoL = # Source-to-CRL1 distance, in m self.d_Stof = # Source-to-focus distance, in m def setLenses(self, propertyType, propertyVal, lensNum): self.d_min = 3.0e-5 # Minimum thickness at the apex in m self.stack_d = 50.0e-3 # Stack thickness in m self.L1_n = np.array([1, 1, 1, 1, 1, 1, 2, 4, 8, 16]) # CRL1 number of lenses in each stack self.L1_R = np.array([2.0e-3, 1.0e-3, 5.0e-4, 3.0e-4, 2.0e-4, 1.0e-4, 1.0e-4, 1.0e-4, 1.0e-4, 1.0e-4]) # CRL1 lens radius in each stack self.L1_mater= np.array(["Be", "Be", "Be", "Be", "Be", "Be", "Be", "Be", "Be", "Be"]) # CRL1 lens material in each stack self.L1_loc = np.array([4.5, 3.5, 2.5, 1.5, 0.5, -0.5, -1.5, -2.5, -3.5, -4.5])*stack_d # CRL1 lens stack location relative to center stack, positive means upstream self.L1_HE = np.array([1.0e-6, 1.0e-6, 1.0e-6, 1.0e-6, 1.0e-6, 1.0e-6, 1.4e-6, 2.0e-6, 2.8e-6, 4.0e-6]) # CRL1 lens RMS thickness error #any update calcs to be called? def setLensCount(self, lensCount): pass def calc_lookup_table(self): #------------------> Needs refactoring <-------------------------------- L1_D = np.zeros(L1_R.size) # CRL1 diameters for each stack for i in range(L1_R.size): L1_D[i] = lookup_diameter(L1_R[i]) L1_delta = materials_to_deltas(L1_mater, energy_keV) # delta values for CRL1 stacks L1_mu = materials_to_linear_attenuation(L1_mater, energy_keV) # mu values for CRL1 stacks L1_Feq = L1_R/(2*L1_n*L1_delta) + L1_loc # CRL1 equivalent f in m for each stack L1_index_n = 2**L1_Feq.size # Total number of combinations for CRL1 L1_invF_list= np.zeros(L1_index_n) # List of equivalent 1/f in m^-1 for CRL1 for i in range(L1_index_n): L1_invF_list[i] = np.sum(index_to_binary_list(i, L1_Feq.size)/L1_Feq) # Sort the L1_invF list (to avoid zigzagging) L1_invF_list_sort_indices = np.argsort(L1_invF_list) L1_invF_list_sorted = L1_invF_list[L1_invF_list_sort_indices] q1_list = 1/(L1_invF_list_sorted - 1/d_StoL1) # focal position of CRL1 for all configurations (sorted) dq1_list = q1_list - (d_Stof - d_StoL1) # Start generating focal size list as a function of CRL1 setting sigma1H = (sigmaH**2 + (sigmaHp*d_StoL1)**2)**0.5 # sigma beam size before CRL1 sigma1V = (sigmaV**2 + (sigmaVp*d_StoL1)**2)**0.5 # sigma beam size before CRL1 L1_n1mud_list = np.zeros(L1_index_n) # List of n1*mu*d_min for all possible CRL1 configurations L1_n1muR_list = np.zeros(L1_index_n) # List of n1*mu/R for all possible CRL1 configurations aperL1H_list = np.zeros(L1_index_n) # absorption H aperture of CRL1 for all configurations aperL1V_list = np.zeros(L1_index_n) # absorption V aperture of CRL1 for all configurations diameter1_list = np.zeros(L1_index_n) # CRL1 diameter for all possible configurations FWHM1H_list = np.zeros(L1_index_n) # H focal size at the focus of CRL1 FWHM1V_list = np.zeros(L1_index_n) # V focal size at the focus of CRL1 Strehl_list = np.zeros(L1_index_n) # Strehl ratio based on lens thickness error for i in range(L1_index_n): # absorption aperture is a function of CRL absorption/physical aperture, incident beam size, and physical slits L1_n1mud_list[i] = np.sum(index_to_binary_list(L1_invF_list_sort_indices[i], L1_Feq.size)*np.array(L1_mu*L1_n*d_min)) L1_n1muR_list[i] = np.sum(index_to_binary_list(L1_invF_list_sort_indices[i], L1_Feq.size)*np.array(L1_mu*L1_n/L1_R)) solution = root_scalar(absorptionaperture, args=(L1_n1mud_list[i], sigma1H, L1_n1muR_list[i]), bracket=[0.0, 2*sigma1H], method='bisect') aperL1H_list[i] = solution.root*2.0 solution = root_scalar(absorptionaperture, args=(L1_n1mud_list[i], sigma1V, L1_n1muR_list[i]), bracket=[0.0, 2*sigma1V], method='bisect') aperL1V_list[i] = solution.root*2.0 mask = (np.array(index_to_binary_list(L1_invF_list_sort_indices[i], L1_Feq.size)) == 1) if np.all(mask == False): diameter1_list[i] = np.inf else: diameter1_list[i] = np.min(L1_D[mask]) aperL1H_list[i] = min(aperL1H_list[i], diameter1_list[i], slit1_H) aperL1V_list[i] = min(aperL1V_list[i], diameter1_list[i], slit1_V) phase_error_tmp = np.linalg.norm(index_to_binary_list(L1_invF_list_sort_indices[i], L1_Feq.size)*np.array(L1_HE*L1_delta)*2*np.pi/wl) Strehl_list[i] = np.exp(-phase_error_tmp**2) # FWHMbeam size at CRL1 focus FWHM1H_list = ((0.88*wl*q1_list/aperL1H_list)**2 + (2.355*sigmaH*q1_list/d_StoL1)**2)**0.5 FWHM1V_list = ((0.88*wl*q1_list/aperL1V_list)**2 + (2.355*sigmaV*q1_list/d_StoL1)**2)**0.5 if flag_HE: FWHM1H_list *= (Strehl_list)**(-0.5) FWHM1V_list *= (Strehl_list)**(-0.5) FWHM_list = (FWHM1H_list*FWHM1V_list)**0.5 #------------------> End refactoring <-------------------------------- def find_config(self): # match desired fsize to lookup table pass def updateSlitSize(self, size, slit): if slit = 'hor': self.slit1_H = float(size) # H slit size before CRL 1 elif slit == 'vert': self.slit1_V = float(size) # V slit size before CRL 1 else # Need error handling break self.calc_lookup_table() def updateE(self, energy): # Energy variable sent from IOC as a string self.energy = float(energy) self.calc_lookup_table() def updateFsize(self, focalSize): # focalPoint variable sent from IOC as a string self.focalSize = float(focalSize) self.find_config() def calc_lenses(self): self.lenses = (self.energy * self.focalPoint) % 4096 pydev.iointr('new_lens_config', self.lenses)