def get_Wavefront1D_from_profile(self, axis, coordinate): # swap axis - changed giovanni+manuel if axis == 1: # fixed X index = numpy.argmin(numpy.abs(self._electric_field_matrix.x_coord - coordinate)) return GenericWavefront1D(wavelength=self._wavelength, electric_field_array=ScaledArray(scale=self._electric_field_matrix.y_coord, np_array=self._electric_field_matrix.z_values[index, :])) elif axis == 0: index = numpy.argmin(numpy.abs(self._electric_field_matrix.y_coord - coordinate)) return GenericWavefront1D(wavelength=self._wavelength, electric_field_array=ScaledArray(scale=self._electric_field_matrix.x_coord, np_array=self._electric_field_matrix.z_values[:, index]))
def initialize_wavefront(cls, wavelength=1e-10, number_of_points=1000, polarization=Polarization.SIGMA): sA = ScaledArray.initialize( np_array=numpy.full(number_of_points, (1.0 + 0.0j), dtype=complex)) if ((polarization == Polarization.PI) or (polarization == Polarization.TOTAL)): sA_pi = ScaledArray.initialize(np_array=numpy.full( number_of_points, (0.0 + 0.0j), dtype=complex)) else: sA_pi = None return GenericWavefront1D(wavelength, sA, sA_pi)
def duplicate(self): if self.is_polarized(): return GenericWavefront1D( wavelength=self._wavelength, electric_field_array=ScaledArray( np_array=copy.copy(self._electric_field_array.np_array), scale=copy.copy(self._electric_field_array.scale)), electric_field_array_pi=ScaledArray( np_array=copy.copy(self._electric_field_array_pi.np_array), scale=copy.copy(self._electric_field_array_pi.scale))) else: return GenericWavefront1D( wavelength=self._wavelength, electric_field_array=ScaledArray( np_array=copy.copy(self._electric_field_array.np_array), scale=copy.copy(self._electric_field_array.scale)))
def propagate_1D_fresnel_radius(wavefront, propagation_distance, eta): """ 1D Fresnel propagator using convolution via Fourier transform :param wavefront: :param propagation_distance: propagation distance :return: a new 1D wavefront object with propagated wavefront """ fft_scale = numpy.fft.fftfreq(wavefront.size()) / wavefront.delta() fft = numpy.fft.fft(wavefront.get_complex_amplitude()) fft *= numpy.exp(1.0j * numpy.pi * wavefront.get_wavelength() * propagation_distance * (-fft_scale**2 + eta * fft_scale**2)) H = numpy.fft.ifft(fft) H *= -1.0j * eta * propagation_distance / wavefront.get_wavelength( ) * numpy.exp(1.0j * numpy.pi / eta / propagation_distance / wavefront.get_wavelength() * wavefront.get_abscissas()**2) ifft = numpy.fft.fft(H) ifft *= numpy.exp(1.0j * numpy.pi / eta / propagation_distance / wavefront.get_wavelength() * wavefront.get_abscissas()**2) return Wavefront1D( wavefront.get_wavelength(), ScaledArray.initialize_from_steps(ifft, wavefront.offset(), wavefront.delta()))
def propagator1d_fourier_rescaling(wavefront, propagation_distance, m=1): wf = wavefront.duplicate() # todo: cambiato da giovanni, controllare shape = wf.size() delta = wf.delta() wavenumber = wf.get_wavenumber() wavelength = wf.get_wavelength() fft_scale = numpy.fft.fftfreq(shape, d=delta) x = wf.get_abscissas() x_rescaling = wf.get_abscissas() * m r1sq = x**2 * (1 - m) r2sq = x_rescaling**2 * ((m - 1) / m) fsq = (fft_scale**2 / m) Q1 = wavenumber / 2 / propagation_distance * r1sq Q2 = numpy.exp(-1.0j * numpy.pi * wavelength * propagation_distance * fsq) Q3 = numpy.exp(1.0j * wavenumber / 2 / propagation_distance * r2sq) wf.add_phase_shift(Q1) fft = numpy.fft.fft(wf.get_complex_amplitude()) ifft = numpy.fft.ifft(fft * Q2) * Q3 / numpy.sqrt(m) return Wavefront1D( wf.get_wavelength(), ScaledArray.initialize_from_steps(ifft, m * wf.offset(), m * wf.delta()))
def propagate_1D_integral(wavefront, propagation_distance, detector_abscissas=[None]): """ 1D Fresnel-Kirchhoff propagator via simplified integral :param wavefront: :param propagation_distance: propagation distance :param detector_abscissas: a numpy array with the anscissas at the image position. If undefined ([None]) it uses the same abscissas present in input wavefront. :return: a new 1D wavefront object with propagated wavefront """ if detector_abscissas[0] == None: detector_abscissas = wavefront.get_abscissas() # calculate via outer product, it spreads over a lot of memory, but it is OK for 1D x1 = numpy.outer(wavefront.get_abscissas(),numpy.ones(detector_abscissas.size)) x2 = numpy.outer(numpy.ones(wavefront.size()),detector_abscissas) r = numpy.sqrt( numpy.power(x1-x2,2) + numpy.power(propagation_distance,2) ) wavenumber = numpy.pi*2/wavefront.get_wavelength() distances_matrix = numpy.exp(1.j * wavenumber * r) fieldComplexAmplitude = numpy.dot(wavefront.get_complex_amplitude(),distances_matrix) return Wavefront1D(wavefront.get_wavelength(), ScaledArray.initialize_from_steps(fieldComplexAmplitude, \ detector_abscissas[0], detector_abscissas[1]-detector_abscissas[0] ))
def propagate_wavefront(cls, wavefront, propagation_distance, magnification_x=1.0, magnification_N=1.0): method = 0 wavenumber = numpy.pi * 2 / wavefront.get_wavelength() x = wavefront.get_abscissas() if magnification_N != 1.0: npoints_exit = int(magnification_N * x.size) else: npoints_exit = x.size detector_abscissas = numpy.linspace(magnification_x * x[0], magnification_x * x[-1], npoints_exit) if method == 0: # calculate via loop pver detector coordinates x1 = wavefront.get_abscissas() x2 = detector_abscissas fieldComplexAmplitude = numpy.zeros_like(x2, dtype=complex) for ix, x in enumerate(x2): r = numpy.sqrt( numpy.power(x1 - x, 2) + numpy.power(propagation_distance, 2)) distances_array = numpy.exp(1.j * wavenumber * r) fieldComplexAmplitude[ix] = ( wavefront.get_complex_amplitude() * distances_array).sum() elif method == 1: # calculate via outer product, it spreads over a lot of memory, but it is OK for 1D x1 = numpy.outer(wavefront.get_abscissas(), numpy.ones(detector_abscissas.size)) x2 = numpy.outer(numpy.ones(wavefront.size()), detector_abscissas) r = numpy.sqrt( numpy.power(x1 - x2, 2) + numpy.power(propagation_distance, 2)) distances_matrix = numpy.exp(1.j * wavenumber * r) fieldComplexAmplitude = numpy.dot( wavefront.get_complex_amplitude(), distances_matrix) wavefront_out = GenericWavefront1D( wavefront.get_wavelength(), ScaledArray.initialize_from_steps( fieldComplexAmplitude, detector_abscissas[0], detector_abscissas[1] - detector_abscissas[0])) # added [email protected] 2018-03-23 to conserve energy - TODO: review method! # wavefront_out.rescale_amplitude( numpy.sqrt(wavefront.get_intensity().sum() / # wavefront_out.get_intensity().sum() # / magnification_x)) wavefront_out.rescale_amplitude( (1/numpy.sqrt(1j*wavefront.get_wavelength()*propagation_distance))*(x1[1]-x1[0]) * \ numpy.exp(1j * wavenumber * propagation_distance)) return wavefront_out
def sh_readsurface(filename, dimension): if dimension == 1: values = np.loadtxt(congruence.checkFile(filename)) return ScaledArray(values[:, 1], values[:, 0]) elif dimension == 2: x_coords, y_coords, z_values = ShadowPreProcessor.read_surface_error_file(filename) return ScaledMatrix(x_coords, y_coords, z_values)
def initialize_wavefront_from_range(cls, x_min=0.0, x_max=0.0, number_of_points=1000, wavelength=1e-10): return Wavefront1D( wavelength, ScaledArray.initialize_from_range( np_array=numpy.full(number_of_points, (1.0 + 0.0j), dtype=complex), min_scale_value=x_min, max_scale_value=x_max, ), )
def initialize_wavefront_from_steps(cls, x_start=0.0, x_step=0.0, number_of_points=1000, wavelength=1e-10): return Wavefront1D( wavelength, ScaledArray.initialize_from_steps( np_array=numpy.full(number_of_points, (1.0 + 0.0j), dtype=complex), initial_scale_value=x_start, scale_step=x_step, ), )
def initialize_wavefront_from_arrays(cls, x_array, y_array, wavelength=1e-10): if x_array.size != y_array.size: raise Exception("Unmatched shapes for x and y") return Wavefront1D( wavelength, ScaledArray.initialize_from_steps( np_array=y_array, initial_scale_value=x_array[0], scale_step=numpy.abs(x_array[1] - x_array[0]) ), )
def propagate_1D_integral(wavefront, propagation_distance, detector_abscissas=[None], method=0, magnification=1.0, npoints_exit=None): """ 1D Fresnel-Kirchhoff propagator via integral implemented as sum :param wavefront: :param propagation_distance: propagation distance :param detector_abscissas: a numpy array with the abscissas at the image position. If undefined ([None]) it uses the same abscissas present in input wavefront. :param method: 0 (default_ makes a loop over detector coordinates, 1: makes matrices (outer products) so it is more memory hungry. :param magnification: if detector_abscissas is [None], the detector abscissas range is the input wavefront range times this magnification factor. Default =1 :param npoints_exit: if detector_abscissas is [None], the number of points of detector abscissas. Default=None meaning that the same number of points than wavefront are used. :return: a new 1D wavefront object with propagated wavefront """ if detector_abscissas[0] == None: x = wavefront.get_abscissas() if npoints_exit is None: npoints_exit = x.size detector_abscissas = numpy.linspace(magnification * x[0], magnification * x[-1], npoints_exit) wavenumber = numpy.pi * 2 / wavefront.get_wavelength() if method == 0: x1 = wavefront.get_abscissas() x2 = detector_abscissas fieldComplexAmplitude = numpy.zeros_like(x2, dtype=complex) for ix, x in enumerate(x2): r = numpy.sqrt( numpy.power(x1 - x, 2) + numpy.power(propagation_distance, 2)) distances_array = numpy.exp(1.j * wavenumber * r) fieldComplexAmplitude[ix] = (wavefront.get_complex_amplitude() * distances_array).sum() elif method == 1: # calculate via outer product, it spreads over a lot of memory, but it is OK for 1D x1 = numpy.outer(wavefront.get_abscissas(), numpy.ones(detector_abscissas.size)) x2 = numpy.outer(numpy.ones(wavefront.size()), detector_abscissas) r = numpy.sqrt( numpy.power(x1 - x2, 2) + numpy.power(propagation_distance, 2)) distances_matrix = numpy.exp(1.j * wavenumber * r) fieldComplexAmplitude = numpy.dot(wavefront.get_complex_amplitude(), distances_matrix) return Wavefront1D(wavefront.get_wavelength(), ScaledArray.initialize_from_steps(fieldComplexAmplitude, \ detector_abscissas[0], detector_abscissas[1]-detector_abscissas[0] ))
def initialize_wavefront_from_steps(cls, x_start=0.0, x_step=0.0, number_of_points=1000, wavelength=1e-10): return Wavefront1D( wavelength, ScaledArray.initialize_from_steps(np_array=numpy.full( number_of_points, (1.0 + 0.0j), dtype=complex), initial_scale_value=x_start, scale_step=x_step))
def initialize_wavefront_from_range(cls, x_min=0.0, x_max=0.0, number_of_points=1000, wavelength=1e-10): return Wavefront1D( wavelength, ScaledArray.initialize_from_range(np_array=numpy.full( number_of_points, (1.0 + 0.0j), dtype=complex), min_scale_value=x_min, max_scale_value=x_max))
def initialize_wavefront_from_range(cls, x_min=0.0, x_max=0.0, number_of_points=1000, wavelength=1e-10, polarization=Polarization.SIGMA): sA = ScaledArray.initialize_from_range(np_array=numpy.full( number_of_points, (1.0 + 0.0j), dtype=complex), min_scale_value=x_min, max_scale_value=x_max) if ((polarization == Polarization.PI) or (polarization == Polarization.TOTAL)): sA_pi = ScaledArray.initialize_from_range(np_array=numpy.full( number_of_points, (0.0 + 0.0j), dtype=complex), min_scale_value=x_min, max_scale_value=x_max) else: sA_pi = None return GenericWavefront1D(wavelength, sA, sA_pi)
def initialize_wavefront_from_arrays(cls, x_array, y_array, y_array_pi=None, wavelength=1e-10): if x_array.size != y_array.size: raise Exception("Unmatched shapes for x and y") sA = ScaledArray.initialize_from_steps( np_array=y_array, initial_scale_value=x_array[0], scale_step=numpy.abs(x_array[1] - x_array[0])) if y_array_pi is not None: sA_pi = ScaledArray.initialize_from_steps( np_array=y_array_pi, initial_scale_value=x_array[0], scale_step=numpy.abs(x_array[1] - x_array[0])) else: sA_pi = None return GenericWavefront1D(wavelength, sA, sA_pi)
def initialize_wavefront_from_steps(cls, x_start=-1.0, x_step=0.002, number_of_points=1000, wavelength=1e-10, polarization=Polarization.SIGMA): sA = ScaledArray.initialize_from_steps(np_array=numpy.full( number_of_points, (1.0 + 0.0j), dtype=complex), initial_scale_value=x_start, scale_step=x_step) if ((polarization == Polarization.PI) or (polarization == Polarization.TOTAL)): sA_pi = ScaledArray.initialize_from_steps( np_array=numpy.full(number_of_points, (0.0 + 0.0j), dtype=complex), initial_scale_value=x_start, scale_step=x_step) else: sA_pi = None return GenericWavefront1D(wavelength, sA, sA_pi)
def propagate_wavefront(cls, wavefront, propagation_distance): fft_scale = numpy.fft.fftfreq(wavefront.size()) / wavefront.delta() fft = numpy.fft.fft(wavefront.get_complex_amplitude()) fft *= numpy.exp((-1.0j) * numpy.pi * wavefront.get_wavelength() * propagation_distance * fft_scale**2) ifft = numpy.fft.ifft(fft) return GenericWavefront1D( wavefront.get_wavelength(), ScaledArray.initialize_from_steps(ifft, wavefront.offset(), wavefront.delta()))
def propagate_1D_fresnel(wavefront, propagation_distance): """ 1D Fresnel propagator using convolution via Fourier transform :param wavefront: :param propagation_distance: propagation distance :return: a new 1D wavefront object with propagated wavefront """ fft_scale = numpy.fft.fftfreq(wavefront.size())/wavefront.delta() fft = numpy.fft.fft(wavefront.get_complex_amplitude()) fft *= numpy.exp((-1.0j) * numpy.pi * wavefront.get_wavelength() * propagation_distance * fft_scale**2) ifft = numpy.fft.ifft(fft) return Wavefront1D(wavefront.get_wavelength(), ScaledArray.initialize_from_steps(ifft, wavefront.offset(), wavefront.delta()))
def initialize_wavefront_from_arrays( cls, x_array, y_array, wavelength=1e-10, ): if x_array.size != y_array.size: raise Exception("Unmatched shapes for x and y") return Wavefront1D( wavelength, ScaledArray.initialize_from_steps( np_array=y_array, initial_scale_value=x_array[0], scale_step=numpy.abs(x_array[1] - x_array[0])))
def propagate_1D_fresnel_convolution(wavefront, propagation_distance): """ 1D Fresnel propagator using direct convolution :param wavefront: :param propagation_distance: :return: """ # instead of numpy.convolve, this can be used: # from scipy.signal import fftconvolve kernel = numpy.exp(1j*2*numpy.pi/wavefront.get_wavelength() * wavefront.get_abscissas()**2 / 2 / propagation_distance) kernel *= numpy.exp(1j*2*numpy.pi/wavefront.get_wavelength() * propagation_distance) kernel /= 1j * wavefront.get_wavelength() * propagation_distance tmp = numpy.convolve(wavefront.get_complex_amplitude(),kernel,mode='same') return Wavefront1D(wavefront.get_wavelength(), ScaledArray.initialize_from_steps(tmp, wavefront.offset(), wavefront.delta()))
def propagate_wavefront(cls, wavefront, propagation_distance): kernel = numpy.exp(1j * 2 * numpy.pi / wavefront.get_wavelength() * wavefront.get_abscissas()**2 / 2 / propagation_distance) kernel *= numpy.exp(1j * 2 * numpy.pi / wavefront.get_wavelength() * propagation_distance) kernel /= 1j * wavefront.get_wavelength() * propagation_distance tmp = numpy.convolve(wavefront.get_complex_amplitude(), kernel, mode='same') wavefront_out = GenericWavefront1D( wavefront.get_wavelength(), ScaledArray.initialize_from_steps(tmp, wavefront.offset(), wavefront.delta())) # added [email protected] 2018-03-23 to conserve energy - TODO: review method! wavefront_out.rescale_amplitude( numpy.sqrt(wavefront.get_intensity().sum() / wavefront_out.get_intensity().sum())) return wavefront_out
def propagate_1D_fresnel_convolution(wavefront, propagation_distance): """ 1D Fresnel propagator using direct convolution :param wavefront: :param propagation_distance: :return: """ # instead of numpy.convolve, this can be used: # from scipy.signal import fftconvolve kernel = numpy.exp(1j * 2 * numpy.pi / wavefront.get_wavelength() * wavefront.get_abscissas()**2 / 2 / propagation_distance) kernel *= numpy.exp(1j * 2 * numpy.pi / wavefront.get_wavelength() * propagation_distance) kernel /= 1j * wavefront.get_wavelength() * propagation_distance tmp = numpy.convolve(wavefront.get_complex_amplitude(), kernel, mode='same') return Wavefront1D( wavefront.get_wavelength(), ScaledArray.initialize_from_steps(tmp, wavefront.offset(), wavefront.delta()))
def initialize_wavefront(cls, wavelength=1e-10, number_of_points=1000): return Wavefront1D( wavelength, ScaledArray.initialize(np_array=numpy.full(number_of_points, (1.0 + 0.0j), dtype=complex)) )
def calculate_function_average_value(function, x_min, x_max, sampling=100): sampled_function = ScaledArray.initialize_from_range(np.zeros(sampling), x_min, x_max) sampled_function.np_array = function(sampled_function.scale) return np.average(sampled_function.np_array)
def propagate_1D_x_direction(calculation_parameters, input_parameters): scale_factor = 1.0 shadow_oe = calculation_parameters.shadow_oe_end global_phase_shift_profile = None if shadow_oe._oe.F_MOVE == 1 and shadow_oe._oe.Y_ROT != 0.0: if input_parameters.ghy_calcType == 3 or input_parameters.ghy_calcType == 4: global_phase_shift_profile = calculation_parameters.w_mirror_lx elif input_parameters.ghy_calcType == 2: global_phase_shift_profile = ScaledArray.initialize_from_range(numpy.zeros(3), shadow_oe._oe.RWIDX2, shadow_oe._oe.RWIDX1) global_phase_shift_profile.set_values(global_phase_shift_profile.get_values() + global_phase_shift_profile.get_abscissas()*numpy.sin(numpy.radians(-shadow_oe._oe.Y_ROT))) elif input_parameters.ghy_calcType == 3 or input_parameters.ghy_calcType == 4: global_phase_shift_profile = calculation_parameters.w_mirror_lx if input_parameters.ghy_calcType == 3 or input_parameters.ghy_calcType == 4: rms_slope = hy_findrmsslopefromheight(global_phase_shift_profile) print("Using RMS slope = " + str(rms_slope)) average_incident_angle = numpy.radians(90-calculation_parameters.shadow_oe_end._oe.T_INCIDENCE)*1e3 average_reflection_angle = numpy.radians(90-calculation_parameters.shadow_oe_end._oe.T_REFLECTION)*1e3 if calculation_parameters.beam_not_cut_in_x: dp_image = numpy.std(calculation_parameters.xx_focal_ray)/input_parameters.ghy_focallength dp_se = 2 * rms_slope * numpy.sin(average_incident_angle/1e3) # different in x and z dp_error = calculation_parameters.gwavelength/2/(calculation_parameters.ghy_x_max-calculation_parameters.ghy_x_min) scale_factor = max(1, 5*min(dp_error/dp_image, dp_error/dp_se)) # ------------------------------------------ # far field calculation # ------------------------------------------ if calculation_parameters.do_ff_x: focallength_ff = calculate_focal_length_ff(calculation_parameters.ghy_x_min, calculation_parameters.ghy_x_max, input_parameters.ghy_npeak, calculation_parameters.gwavelength) if input_parameters.ghy_calcType == 3: if not (rms_slope == 0.0 or average_incident_angle == 0.0): focallength_ff = min(focallength_ff,(calculation_parameters.ghy_x_max-calculation_parameters.ghy_x_min) / 16 / rms_slope / numpy.sin(average_incident_angle / 1e3))#xshi changed elif input_parameters.ghy_calcType == 4: if not (rms_slope == 0.0 or average_incident_angle == 0.0): focallength_ff = min(focallength_ff,(calculation_parameters.ghy_x_max-calculation_parameters.ghy_x_min) / 8 / rms_slope / (numpy.sin(average_incident_angle / 1e3) + numpy.sin(average_reflection_angle / 1e3)))#xshi changed elif input_parameters.ghy_calcType == 2 and not global_phase_shift_profile is None: focallength_ff = min(focallength_ff, input_parameters.ghy_distance*4) #TODO: PATCH to be found with a formula fftsize = int(scale_factor * calculate_fft_size(calculation_parameters.ghy_x_min, calculation_parameters.ghy_x_max, calculation_parameters.gwavelength, focallength_ff, input_parameters.ghy_fftnpts)) print("FF: creating plane wave begin, fftsize = " + str(fftsize)) wavefront = Wavefront1D.initialize_wavefront_from_range(wavelength=calculation_parameters.gwavelength, number_of_points=fftsize, x_min=scale_factor * calculation_parameters.ghy_x_min, x_max=scale_factor * calculation_parameters.ghy_x_max) if scale_factor == 1.0: try: wavefront.set_plane_wave_from_complex_amplitude(numpy.sqrt(calculation_parameters.wIray_x.interpolate_values(wavefront.get_abscissas()))) except IndexError: raise Exception("Unexpected Error during interpolation: try reduce Number of bins for I(Sagittal) histogram") wavefront.apply_ideal_lens(focallength_ff) if input_parameters.ghy_calcType == 3 or \ (input_parameters.ghy_calcType == 2 and not global_phase_shift_profile is None): wavefront.add_phase_shifts(get_mirror_phase_shift(wavefront.get_abscissas(), calculation_parameters.gwavelength, calculation_parameters.wangle_x, calculation_parameters.wl_x, global_phase_shift_profile)) elif input_parameters.ghy_calcType == 4: wavefront.add_phase_shifts(get_grating_phase_shift(wavefront.get_abscissas(), calculation_parameters.gwavelength, calculation_parameters.wangle_x, calculation_parameters.wangle_ref_x, calculation_parameters.wl_x, global_phase_shift_profile)) print("calculated plane wave: begin FF propagation (distance = " + str(focallength_ff) + ")") propagated_wavefront = propagator.propagate_1D_fresnel(wavefront, focallength_ff) print("dif_xp: begin calculation") shadow_oe = calculation_parameters.shadow_oe_end imagesize = min(abs(calculation_parameters.ghy_x_max), abs(calculation_parameters.ghy_x_min)) * 2 # 2017-01 Luca Rebuffi imagesize = min(imagesize, input_parameters.ghy_npeak*2*0.88*calculation_parameters.gwavelength*focallength_ff/abs(calculation_parameters.ghy_x_max-calculation_parameters.ghy_x_min)) # TODO: this is a patch: to be rewritten if shadow_oe._oe.F_MOVE==1 and not shadow_oe._oe.Y_ROT==0: imagesize = max(imagesize, 8*(focallength_ff*numpy.tan(numpy.radians(numpy.abs(shadow_oe._oe.Y_ROT))) + numpy.abs(shadow_oe._oe.OFFX))) imagenpts = int(round(imagesize / propagated_wavefront.delta() / 2) * 2 + 1) dif_xp = ScaledArray.initialize_from_range(numpy.ones(propagated_wavefront.size()), -(imagenpts - 1) / 2 * propagated_wavefront.delta(), (imagenpts - 1) / 2 * propagated_wavefront.delta()) dif_xp.np_array = numpy.absolute(propagated_wavefront.get_interpolated_complex_amplitudes(dif_xp.scale))**2 dif_xp.set_scale_from_range(-(imagenpts - 1) / 2 * propagated_wavefront.delta() / focallength_ff, (imagenpts - 1) / 2 * propagated_wavefront.delta() / focallength_ff) calculation_parameters.dif_xp = dif_xp # ------------------------------------------ # near field calculation # ------------------------------------------ if input_parameters.ghy_nf >= 1 and input_parameters.ghy_calcType > 1: # near field calculation focallength_nf = input_parameters.ghy_focallength fftsize = int(scale_factor * calculate_fft_size(calculation_parameters.ghy_x_min, calculation_parameters.ghy_x_max, calculation_parameters.gwavelength, numpy.abs(focallength_nf), input_parameters.ghy_fftnpts)) print("NF: creating plane wave begin, fftsize = " + str(fftsize)) wavefront = Wavefront1D.initialize_wavefront_from_range(wavelength=calculation_parameters.gwavelength, number_of_points=fftsize, x_min=scale_factor*calculation_parameters.ghy_x_min, x_max=scale_factor*calculation_parameters.ghy_x_max) if scale_factor == 1.0: try: wavefront.set_plane_wave_from_complex_amplitude(numpy.sqrt(calculation_parameters.wIray_x.interpolate_values(wavefront.get_abscissas()))) except IndexError: raise Exception("Unexpected Error during interpolation: try reduce Number of bins for I(Sagittal) histogram") wavefront.apply_ideal_lens(focallength_nf) if input_parameters.ghy_calcType == 3 or \ (input_parameters.ghy_calcType == 2 and not global_phase_shift_profile is None): wavefront.add_phase_shifts(get_mirror_phase_shift(wavefront.get_abscissas(), calculation_parameters.gwavelength, calculation_parameters.wangle_x, calculation_parameters.wl_x, global_phase_shift_profile)) elif input_parameters.ghy_calcType == 4: wavefront.add_phase_shifts(get_grating_phase_shift(wavefront.get_abscissas(), calculation_parameters.gwavelength, calculation_parameters.wangle_x, calculation_parameters.wangle_ref_x, calculation_parameters.wl_x, global_phase_shift_profile)) print("calculated plane wave: begin NF propagation (distance = " + str(input_parameters.ghy_distance) + ")") propagated_wavefront = propagator.propagate_1D_fresnel(wavefront, input_parameters.ghy_distance) # ghy_npeak in the wavefront propagation image imagesize = (input_parameters.ghy_npeak * 2 * 0.88 * calculation_parameters.gwavelength * numpy.abs(focallength_nf) / abs(calculation_parameters.ghy_x_max - calculation_parameters.ghy_x_min)) imagesize = max(imagesize, 2 * abs((calculation_parameters.ghy_x_max - calculation_parameters.ghy_x_min) * (input_parameters.ghy_distance - numpy.abs(focallength_nf))) / numpy.abs(focallength_nf)) if input_parameters.ghy_calcType == 3: imagesize = max(imagesize, 16 * rms_slope * numpy.abs(focallength_nf) * numpy.sin(average_incident_angle / 1e3)) elif input_parameters.ghy_calcType == 4: imagesize = max(imagesize, 8 * rms_slope * numpy.abs(focallength_nf) * (numpy.sin(average_incident_angle / 1e3) + numpy.sin(average_reflection_angle / 1e3))) # TODO: this is a patch: to be rewritten if shadow_oe._oe.F_MOVE==1 and not shadow_oe._oe.Y_ROT==0: imagesize = max(imagesize, 8*(input_parameters.ghy_distance*numpy.tan(numpy.radians(numpy.abs(shadow_oe._oe.Y_ROT))) + numpy.abs(shadow_oe._oe.OFFX))) imagenpts = int(round(imagesize / propagated_wavefront.delta() / 2) * 2 + 1) print("dif_x: begin calculation") dif_x = ScaledArray.initialize_from_range(numpy.ones(imagenpts), -(imagenpts - 1) / 2 * propagated_wavefront.delta(), (imagenpts - 1) / 2 * propagated_wavefront.delta()) dif_x.np_array *= numpy.absolute(propagated_wavefront.get_interpolated_complex_amplitudes(dif_x.scale))**2 calculation_parameters.dif_x = dif_x
def propagate_2D(calculation_parameters, input_parameters): shadow_oe = calculation_parameters.shadow_oe_end if calculation_parameters.do_ff_z and calculation_parameters.do_ff_x: global_phase_shift_profile = None if shadow_oe._oe.F_MOVE == 1 and shadow_oe._oe.X_ROT != 0.0: if input_parameters.ghy_calcType == 3 or input_parameters.ghy_calcType == 4: global_phase_shift_profile = calculation_parameters.w_mirr_2D_values elif input_parameters.ghy_calcType == 2: global_phase_shift_profile = ScaledMatrix.initialize_from_range(numpy.zeros((3, 3)), shadow_oe._oe.RWIDX2, shadow_oe._oe.RWIDX1, shadow_oe._oe.RLEN2, shadow_oe._oe.RLEN1) for x_index in range(global_phase_shift_profile.size_x()): global_phase_shift_profile.z_values[x_index, :] += global_phase_shift_profile.get_y_values()*numpy.sin(numpy.radians(-shadow_oe._oe.X_ROT)) elif input_parameters.ghy_calcType == 3 or input_parameters.ghy_calcType == 4: global_phase_shift_profile = calculation_parameters.w_mirr_2D_values # only tangential slopes if input_parameters.ghy_calcType == 3 or input_parameters.ghy_calcType == 4: rms_slope = hy_findrmsslopefromheight(ScaledArray(np_array=global_phase_shift_profile.z_values[int(global_phase_shift_profile.size_x()/2), :], scale=global_phase_shift_profile.get_y_values())) print("Using RMS slope = " + str(rms_slope)) # ------------------------------------------ # far field calculation # ------------------------------------------ focallength_ff = calculate_focal_length_ff_2D(calculation_parameters.ghy_x_min, calculation_parameters.ghy_x_max, calculation_parameters.ghy_z_min, calculation_parameters.ghy_z_max, input_parameters.ghy_npeak, calculation_parameters.gwavelength) if (input_parameters.ghy_calcType == 3 or input_parameters.ghy_calcType == 4) and rms_slope != 0: focallength_ff = min(focallength_ff,(calculation_parameters.ghy_z_max-calculation_parameters.ghy_z_min) / 16 / rms_slope ) #xshi changed elif input_parameters.ghy_calcType == 2 and not global_phase_shift_profile is None: focallength_ff = min(focallength_ff, input_parameters.ghy_distance*4) #TODO: PATCH to be found with a formula print("FF: calculated focal length: " + str(focallength_ff)) fftsize_x = int(calculate_fft_size(calculation_parameters.ghy_x_min, calculation_parameters.ghy_x_max, calculation_parameters.gwavelength, focallength_ff, input_parameters.ghy_fftnpts, factor=20)) fftsize_z = int(calculate_fft_size(calculation_parameters.ghy_z_min, calculation_parameters.ghy_z_max, calculation_parameters.gwavelength, focallength_ff, input_parameters.ghy_fftnpts, factor=20)) print("FF: creating plane wave begin, fftsize_x = " + str(fftsize_x) + ", fftsize_z = " + str(fftsize_z)) wavefront = Wavefront2D.initialize_wavefront_from_range(wavelength=calculation_parameters.gwavelength, number_of_points=(fftsize_x, fftsize_z), x_min=calculation_parameters.ghy_x_min, x_max=calculation_parameters.ghy_x_max, y_min=calculation_parameters.ghy_z_min, y_max=calculation_parameters.ghy_z_max) try: for i in range(0, len(wavefront.electric_field_array.x_coord)): for j in range(0, len(wavefront.electric_field_array.y_coord)): interpolated = calculation_parameters.wIray_2d.interpolate_value(wavefront.electric_field_array.x_coord[i], wavefront.electric_field_array.y_coord[j]) wavefront.electric_field_array.set_z_value(i, j, numpy.sqrt(0.0 if interpolated < 0 else interpolated)) except IndexError: raise Exception("Unexpected Error during interpolation: try reduce Number of bins for I(Tangential) histogram") wavefront.apply_ideal_lens(focallength_ff, focallength_ff) shadow_oe = calculation_parameters.shadow_oe_end if input_parameters.ghy_calcType == 3 or \ (input_parameters.ghy_calcType == 2 and not global_phase_shift_profile is None): print("FF: calculating phase shift due to Height Error Profile") phase_shifts = numpy.zeros(wavefront.size()) for index in range(0, phase_shifts.shape[0]): np_array = numpy.zeros(global_phase_shift_profile.shape()[1]) for j in range(0, len(np_array)): np_array[j] = global_phase_shift_profile.interpolate_value(wavefront.get_coordinate_x()[index], calculation_parameters.w_mirr_2D_values.get_y_value(j)) global_phase_shift_profile_z = ScaledArray.initialize_from_steps(np_array, global_phase_shift_profile.y_coord[0], global_phase_shift_profile.y_coord[1] - global_phase_shift_profile.y_coord[0]) phase_shifts[index, :] = get_mirror_phase_shift(wavefront.get_coordinate_y(), calculation_parameters.gwavelength, calculation_parameters.wangle_z, calculation_parameters.wl_z, global_phase_shift_profile_z) wavefront.add_phase_shifts(phase_shifts) elif input_parameters.ghy_calcType == 4: print("FF: calculating phase shift due to Height Error Profile") phase_shifts = numpy.zeros(wavefront.size()) for index in range(0, phase_shifts.shape[0]): global_phase_shift_profile_z = ScaledArray.initialize_from_steps(global_phase_shift_profile.z_values[index, :], global_phase_shift_profile.y_coord[0], global_phase_shift_profile.y_coord[1] - global_phase_shift_profile.y_coord[0]) phase_shifts[index, :] = get_grating_phase_shift(wavefront.get_coordinate_y(), calculation_parameters.gwavelength, calculation_parameters.wangle_z, calculation_parameters.wangle_ref_z, calculation_parameters.wl_z, global_phase_shift_profile_z) wavefront.add_phase_shifts(phase_shifts) elif input_parameters.ghy_calcType == 6: for w_mirr_2D_values in calculation_parameters.w_mirr_2D_values: phase_shift = get_crl_phase_shift(w_mirr_2D_values, input_parameters, calculation_parameters, [wavefront.get_coordinate_x(), wavefront.get_coordinate_y()]) wavefront.add_phase_shift(phase_shift) print("calculated plane wave: begin FF propagation (distance = " + str(focallength_ff) + ")") propagated_wavefront = propagator2D.propagate_2D_fresnel(wavefront, focallength_ff) print("dif_zp: begin calculation") imagesize_x = min(abs(calculation_parameters.ghy_x_max), abs(calculation_parameters.ghy_x_min)) * 2 imagesize_x = min(imagesize_x, input_parameters.ghy_npeak*2*0.88*calculation_parameters.gwavelength*focallength_ff/abs(calculation_parameters.ghy_x_max-calculation_parameters.ghy_x_min)) # TODO: this is a patch: to be rewritten if shadow_oe._oe.F_MOVE==1 and not shadow_oe._oe.Y_ROT==0: imagesize_x = max(imagesize_x, 8*(focallength_ff*numpy.tan(numpy.radians(numpy.abs(shadow_oe._oe.Y_ROT))) + numpy.abs(shadow_oe._oe.OFFX))) delta_x = propagated_wavefront.delta()[0] imagenpts_x = int(round(imagesize_x/delta_x/2) * 2 + 1) imagesize_z = min(abs(calculation_parameters.ghy_z_max), abs(calculation_parameters.ghy_z_min)) * 2 imagesize_z = min(imagesize_z, input_parameters.ghy_npeak*2*0.88*calculation_parameters.gwavelength*focallength_ff/abs(calculation_parameters.ghy_z_max-calculation_parameters.ghy_z_min)) # TODO: this is a patch: to be rewritten if shadow_oe._oe.F_MOVE==1 and not shadow_oe._oe.X_ROT==0: imagesize_z = max(imagesize_z, 8*(focallength_ff*numpy.tan(numpy.radians(numpy.abs(shadow_oe._oe.X_ROT))) + numpy.abs(shadow_oe._oe.OFFZ))) delta_z = propagated_wavefront.delta()[1] imagenpts_z = int(round(imagesize_z/delta_z/2) * 2 + 1) dif_xpzp = ScaledMatrix.initialize_from_range(numpy.ones((imagenpts_x, imagenpts_z)), min_scale_value_x = -(imagenpts_x - 1) / 2 * delta_x, max_scale_value_x =(imagenpts_x - 1) / 2 * delta_x, min_scale_value_y = -(imagenpts_z - 1) / 2 * delta_z, max_scale_value_y =(imagenpts_z - 1) / 2 * delta_z) for i in range(0, dif_xpzp.shape()[0]): for j in range(0, dif_xpzp.shape()[1]): dif_xpzp.set_z_value(i, j, numpy.absolute(propagated_wavefront.get_interpolated_complex_amplitude( dif_xpzp.x_coord[i], dif_xpzp.y_coord[j]))**2 ) dif_xpzp.set_scale_from_range(0, -(imagenpts_x - 1) / 2 * delta_x / focallength_ff, (imagenpts_x - 1) / 2 * delta_x / focallength_ff) dif_xpzp.set_scale_from_range(1, -(imagenpts_z - 1) / 2 * delta_z / focallength_ff, (imagenpts_z - 1) / 2 * delta_z / focallength_ff) calculation_parameters.dif_xpzp = dif_xpzp
def test_ScaledArray(self,do_plot=do_plot): # # ScaledArray.initialize + set_scale_from_steps # test_array = numpy.arange(15.0, 18.8, 0.2) print("\nTesting ScaledArray.initialize + set_scale_from_steps...") scaled_array = ScaledArray.initialize(test_array) scaled_array.set_scale_from_steps(test_array[0],0.2) print("Using array: ",test_array) print("Stored array: ",scaled_array.get_values()) print("Using array: ",test_array) print("Stored abscissas: ",scaled_array.get_abscissas()) numpy.testing.assert_almost_equal(test_array,scaled_array.get_values(),11) numpy.testing.assert_almost_equal(test_array,scaled_array.get_abscissas(),11) self.assertAlmostEqual(0.2,scaled_array.delta(),11) self.assertAlmostEqual(15.0,scaled_array.offset(),11) x_in = (18.80,16.22,22.35) x_good = (18.80,16.22,18.8) for i,x in enumerate(x_in): print("interpolated at %3.2f is: %3.2f (must give %3.2f)"%( x,scaled_array.interpolate_value(x), x_good[i] )) self.assertAlmostEqual(scaled_array.interpolate_value(x), x_good[i], 2) # # ScaledArray.initialize + set_scale_from_range ; interpolate vectorized # print("\nTesting ScaledArray.initialize + set_scale_from_range ; interpolate vectorized...") scaled_array = ScaledArray.initialize(test_array) scaled_array.set_scale_from_range(test_array[0],test_array[-1]) x_in = (18.80,16.22,22.35) x_good = (18.80,16.22,18.8) for i,x in enumerate(x_in): print("interpolated at %3.2f is: %3.2f (must give %3.2f)"%( x,scaled_array.interpolate_value(x), x_good[i] )) self.assertAlmostEqual(scaled_array.interpolate_value(x), x_good[i], 2) # # ScaledArray.initialize_from_steps # print("\nTesting ScaledArray.initialize_from_steps...") scaled_array = ScaledArray.initialize_from_steps(test_array, test_array[0], 0.2) x_in = (18.80,16.22,22.35) x_good = (18.80,16.22,18.8) for i,x in enumerate(x_in): print("interpolated at %3.2f is: %3.2f (must give %3.2f)"%( x,scaled_array.interpolate_value(x), x_good[i] )) self.assertAlmostEqual(scaled_array.interpolate_value(x), x_good[i], 2) # # ScaledArray.initialize_from_steps # print("\nTesting ScaledArray.initialize_from_range...") scaled_array = ScaledArray.initialize_from_range(test_array,test_array[0], test_array[-1]) x_in = (18.80,16.22,22.35) x_good = (18.80,16.22,18.8) for i,x in enumerate(x_in): print("interpolated at %3.2f is: %3.2f (must give %3.2f)"%( x,scaled_array.interpolate_value(x), x_good[i] )) self.assertAlmostEqual(scaled_array.interpolate_value(x), x_good[i], 2) # # interpolator # print("\nTesting interpolator...") x = numpy.arange(-5.0, 18.8, 3) y = x**2 scaled_array = ScaledArray.initialize_from_range(y,x[0],x[-1]) print("for interpolation; x=",x) print("for interpolation; offset, delta:=",scaled_array.offset(),scaled_array.delta()) print("for interpolation; abscissas:=",scaled_array.get_abscissas()) x1 = numpy.concatenate( ( numpy.arange(-6, -4, 0.1) , [0], numpy.arange(11, 20.0, 0.1) ) ) y1 = scaled_array.interpolate_values(x1) if do_plot: from srxraylib.plot.gol import plot plot(x,y,x1,y1,legend=["Data",'Interpolated'],legend_position=[0.4,0.8], marker=['','o'],linestyle=['-',''],xrange=[-6,21],yrange=[-5,375]) for i in range(len(x1)): y2 = x1[i]**2 if x1[i] <= x[0]: y2 = y[0] if x1[i] >= x[-1]: y2 = y[-1] print(" interpolated at x=%g is: %g (expected: %g)"%(x1[i],y1[i],y2)) self.assertAlmostEqual(1e-3*y1[i], 1e-3*y2, 2) # interpolate on same grid print("\nTesting interpolation on the same grid...") y1 = scaled_array.interpolate_values(scaled_array.get_abscissas()) if do_plot: from srxraylib.plot.gol import plot plot(scaled_array.get_abscissas(),scaled_array.get_values(), scaled_array.get_abscissas(),y1,legend=["Data",'Interpolated on same grid'],legend_position=[0.4,0.8], marker=['','o'],linestyle=['-','']) numpy.testing.assert_almost_equal(scaled_array.get_values(),y1,5)
def hy_findrmsslopefromheight(wmirror_l): array_first_derivative = np.gradient(wmirror_l.np_array, wmirror_l.delta()) return hy_findrmserror(ScaledArray(array_first_derivative, wmirror_l.scale))
def initialize_wavefront(cls, wavelength=1e-10, number_of_points=1000): return Wavefront1D( wavelength, ScaledArray.initialize(np_array=numpy.full( number_of_points, (1.0 + 0.0j), dtype=complex)))