def propagate_1D_fraunhofer(wavefront, propagation_distance=0.0, shift_half_pixel=1): """ 1D Fraunhofer propagator using convolution via Fourier transform :param wavefront: :param propagation_distance: propagation distance. If set to zero, the abscissas of the returned wavefront are in angle (rad) :return: a new 1D wavefront object with propagated wavefront """ fft = numpy.fft.fft(wavefront.get_complex_amplitude()) fft2 = numpy.fft.fftshift(fft) # frequency for axis 1 freq_nyquist = 0.5/wavefront.delta() freq_n = numpy.linspace(-1.0,1.0,wavefront.size()) freq_x = freq_n * freq_nyquist freq_x *= wavefront.get_wavelength() if shift_half_pixel: freq_x = freq_x - 0.5 * numpy.abs(freq_x[1] - freq_x[0]) if propagation_distance == 0: wf = Wavefront1D.initialize_wavefront_from_arrays(freq_x,fft2,wavelength=wavefront.get_wavelength()) return wf else: wf = Wavefront1D.initialize_wavefront_from_arrays(freq_x*propagation_distance,fft2,wavelength=wavefront.get_wavelength()) return wf
def test_initializers(self,do_plot=do_plot): print("# ") print("# Tests for initializars (1D) ") print("# ") x = numpy.linspace(-100,100,50) y = numpy.abs(x)**1.5 + 1j*numpy.abs(x)**1.8 wf0 = Wavefront1D.initialize_wavefront_from_steps(x[0],numpy.abs(x[1]-x[0]),y.size) wf0.set_complex_amplitude(y) wf1 = Wavefront1D.initialize_wavefront_from_range(x[0],x[-1],y.size) wf1.set_complex_amplitude(y) wf2 = Wavefront1D.initialize_wavefront_from_arrays(x,y) print("wavefront sizes: ",wf1.size(),wf1.size(),wf2.size()) if do_plot: from srxraylib.plot.gol import plot plot(wf0.get_abscissas(),wf0.get_intensity(), title="initialize_wavefront_from_steps",show=0) plot(wf1.get_abscissas(),wf1.get_intensity(), title="initialize_wavefront_from_range",show=0) plot(wf2.get_abscissas(),wf2.get_intensity(), title="initialize_wavefront_from_arrays",show=1) numpy.testing.assert_almost_equal(wf0.get_intensity(),numpy.abs(y)**2,5) numpy.testing.assert_almost_equal(wf1.get_intensity(),numpy.abs(y)**2,5) numpy.testing.assert_almost_equal(x,wf1.get_abscissas(),11) numpy.testing.assert_almost_equal(x,wf2.get_abscissas(),11)
def test_spherical_wave(self, do_plot=do_plot): # # plane wave # print("# ") print("# Tests for a 1D spherical wave ") print("# ") wavelength = 1.24e-10 wavefront_length_x = 400e-6 npixels_x = 1024 wavefront_x = numpy.linspace(-0.5 * wavefront_length_x, 0.5 * wavefront_length_x, npixels_x) wf1 = Wavefront1D.initialize_wavefront_from_steps( x_start=wavefront_x[0], x_step=numpy.abs(wavefront_x[1] - wavefront_x[0]), number_of_points=npixels_x, wavelength=wavelength) wf2 = Wavefront1D.initialize_wavefront_from_steps( x_start=wavefront_x[0], x_step=numpy.abs(wavefront_x[1] - wavefront_x[0]), number_of_points=npixels_x, wavelength=wavelength) # an spherical wavefront is obtained 1) by creation, 2) focusing a planewave wf1.set_spherical_wave(-5.0, 3 + 0j) wf1.apply_slit(-50e-6, 10e-6) wf2.set_plane_wave_from_complex_amplitude(3 + 0j) wf2.apply_ideal_lens(5.0) wf2.apply_slit(-50e-6, 10e-6) if do_plot: from srxraylib.plot.gol import plot plot(wf1.get_abscissas(), wf1.get_phase(), title="Phase of spherical wavefront", show=0) plot(wf2.get_abscissas(), wf2.get_phase(), title="Phase of focused plane wavefront", show=0) plot(wf1.get_abscissas(), wf1.get_phase(from_minimum_intensity=0.1), title="Phase of spherical wavefront (for intensity > 0.1)", show=0) plot( wf2.get_abscissas(), wf2.get_phase(from_minimum_intensity=0.1), title="Phase of focused plane wavefront (for intensity > 0.1)", show=1) numpy.testing.assert_almost_equal(wf1.get_phase(), wf2.get_phase(), 5)
def propagate_1D(self,do_plot=do_plot,method='fft', wavelength=1.24e-10,aperture_type='square',aperture_diameter=40e-6, wavefront_length=100e-6,npoints=500, propagation_distance = 30.0,show=1): print("\n# ") print("# far field 1D (fraunhofer) diffraction from a %s aperture "%aperture_type) print("# ") wf = Wavefront1D.initialize_wavefront_from_range(x_min=-wavefront_length/2, x_max=wavefront_length/2, number_of_points=npoints,wavelength=wavelength) wf.set_plane_wave_from_complex_amplitude((2.0+1.0j)) # an arbitraty value if aperture_type == 'square': wf.apply_slit(-aperture_diameter/2, aperture_diameter/2) elif aperture_type == 'gaussian': X = wf.get_mesh_x() Y = wf.get_mesh_y() window = numpy.exp(- (X*X + Y*Y)/2/(aperture_diameter/2.35)**2) wf.rescale_amplitudes(window) else: raise Exception("Not implemented! (accepted: circle, square, gaussian)") if method == 'fft': wf1 = propagate_1D_fresnel(wf, propagation_distance) elif method == 'convolution': wf1 = propagate_1D_fresnel_convolution(wf, propagation_distance) elif method == 'integral': wf1 = propagate_1D_integral(wf, propagation_distance) elif method == 'fraunhofer': wf1 = propagate_1D_fraunhofer(wf, propagation_distance) else: raise Exception("Not implemented method: %s"%method) # get the theoretical value angle_x = wf1.get_abscissas() / propagation_distance intensity_theory = get_theoretical_diffraction_pattern(angle_x,aperture_type=aperture_type,aperture_diameter=aperture_diameter, wavelength=wavelength,normalization=True) intensity_calculated = wf1.get_intensity() intensity_calculated /= intensity_calculated.max() if do_plot: from srxraylib.plot.gol import plot plot(wf1.get_abscissas()*1e6/propagation_distance,intensity_calculated, angle_x*1e6,intensity_theory, legend=["%s "%method,"Theoretical (far field)"], legend_position=(0.95, 0.95), title="1D (%s) diffraction from a %s aperture of %3.1f um at wavelength of %3.1f A"% (method,aperture_type,aperture_diameter*1e6,wavelength*1e10), xtitle="X (urad)", ytitle="Intensity",xrange=[-20,20], show=show) return wf1.get_abscissas()/propagation_distance,intensity_calculated,intensity_theory
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 schmidt(self, pixelsize, npixels, wavelength, m, propagation_distance): wavefront = Wavefront1D.initialize_wavefront_from_range( x_min=-pixelsize * npixels / 2, x_max=pixelsize * npixels / 2, number_of_points=npixels, wavelength=wavelength) # wavefront.set_spherical_wave(radius=radius) wavefront.set_plane_wave_from_amplitude_and_phase() wavefront.apply_slit(-1e-3, 1e-3) print("Intensity after slit: ", wavefront.get_intensity().sum()) wavefront_propagated = propagator1d_fourier_rescaling( wavefront, propagation_distance=propagation_distance, m=m) print('Intensity after propagation: ', wavefront_propagated.get_intensity().sum()) intensity_theory = fresnel_prop_square_aperture_analitical( x2=wavefront_propagated.get_abscissas(), y2=0, aperture_diameter=2e-3, wavelength=wavelength, propagation_distance=propagation_distance) return wavefront_propagated, intensity_theory
def test_spherical_wave(self,do_plot=do_plot): # # plane wave # print("# ") print("# Tests for a 1D spherical wave ") print("# ") wavelength = 1.24e-10 wavefront_length_x = 400e-6 npixels_x = 1024 wavefront_x = numpy.linspace(-0.5*wavefront_length_x,0.5*wavefront_length_x,npixels_x) wf1 = Wavefront1D.initialize_wavefront_from_steps( x_start=wavefront_x[0],x_step=numpy.abs(wavefront_x[1]-wavefront_x[0]), number_of_points=npixels_x,wavelength=wavelength) wf2 = Wavefront1D.initialize_wavefront_from_steps( x_start=wavefront_x[0],x_step=numpy.abs(wavefront_x[1]-wavefront_x[0]), number_of_points=npixels_x,wavelength=wavelength) # an spherical wavefront is obtained 1) by creation, 2) focusing a planewave wf1.set_spherical_wave(-5.0, 3+0j) wf1.apply_slit(-50e-6,10e-6) wf2.set_plane_wave_from_complex_amplitude(3+0j) wf2.apply_ideal_lens(5.0) wf2.apply_slit(-50e-6,10e-6) if do_plot: from srxraylib.plot.gol import plot plot(wf1.get_abscissas(),wf1.get_phase(),title="Phase of spherical wavefront",show=0) plot(wf2.get_abscissas(),wf2.get_phase(),title="Phase of focused plane wavefront",show=0) plot(wf1.get_abscissas(),wf1.get_phase(from_minimum_intensity=0.1),title="Phase of spherical wavefront (for intensity > 0.1)",show=0) plot(wf2.get_abscissas(),wf2.get_phase(from_minimum_intensity=0.1),title="Phase of focused plane wavefront (for intensity > 0.1)",show=1) numpy.testing.assert_almost_equal(wf1.get_phase(),wf2.get_phase(),5)
def test_initializers(self, do_plot=do_plot): print("# ") print("# Tests for initializars (1D) ") print("# ") x = numpy.linspace(-100, 100, 50) y = numpy.abs(x)**1.5 + 1j * numpy.abs(x)**1.8 wf0 = Wavefront1D.initialize_wavefront_from_steps( x[0], numpy.abs(x[1] - x[0]), y.size) wf0.set_complex_amplitude(y) wf1 = Wavefront1D.initialize_wavefront_from_range(x[0], x[-1], y.size) wf1.set_complex_amplitude(y) wf2 = Wavefront1D.initialize_wavefront_from_arrays(x, y) print("wavefront sizes: ", wf1.size(), wf1.size(), wf2.size()) if do_plot: from srxraylib.plot.gol import plot plot(wf0.get_abscissas(), wf0.get_intensity(), title="initialize_wavefront_from_steps", show=0) plot(wf1.get_abscissas(), wf1.get_intensity(), title="initialize_wavefront_from_range", show=0) plot(wf2.get_abscissas(), wf2.get_intensity(), title="initialize_wavefront_from_arrays", show=1) numpy.testing.assert_almost_equal(wf0.get_intensity(), numpy.abs(y)**2, 5) numpy.testing.assert_almost_equal(wf1.get_intensity(), numpy.abs(y)**2, 5) numpy.testing.assert_almost_equal(x, wf1.get_abscissas(), 11) numpy.testing.assert_almost_equal(x, wf2.get_abscissas(), 11)
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 test_plane_wave(self,do_plot=do_plot): # # plane wave # print("# ") print("# Tests for a 1D plane wave ") print("# ") wavelength = 1.24e-10 wavefront_length_x = 400e-6 npixels_x = 1024 wavefront_x = numpy.linspace(-0.5*wavefront_length_x,0.5*wavefront_length_x,npixels_x) wavefront = Wavefront1D.initialize_wavefront_from_steps( x_start=wavefront_x[0],x_step=numpy.abs(wavefront_x[1]-wavefront_x[0]), number_of_points=npixels_x,wavelength=wavelength) numpy.testing.assert_almost_equal(wavefront_x,wavefront.get_abscissas(),9) # possible modifications wavefront.set_plane_wave_from_amplitude_and_phase(5.0,numpy.pi/2) numpy.testing.assert_almost_equal(wavefront.get_intensity(),25,5) wavefront.set_plane_wave_from_complex_amplitude(2.0+3j) numpy.testing.assert_almost_equal(wavefront.get_intensity(),13,5) phase_before = wavefront.get_phase() wavefront.add_phase_shift(numpy.pi/2) phase_after = wavefront.get_phase() numpy.testing.assert_almost_equal(phase_before+numpy.pi/2,phase_after,5) intensity_before = wavefront.get_intensity() wavefront.rescale_amplitude(10.0) intensity_after = wavefront.get_intensity() numpy.testing.assert_almost_equal(intensity_before*100,intensity_after,5) # interpolation wavefront.set_plane_wave_from_complex_amplitude(2.0+3j) test_value1 = wavefront.get_interpolated_complex_amplitude(0.01) self.assertAlmostEqual( (2.0+3j).real, test_value1.real, 5) self.assertAlmostEqual( (2.0+3j).imag, test_value1.imag, 5) if do_plot: from srxraylib.plot.gol import plot plot(wavefront.get_abscissas(),wavefront.get_intensity(),title="Intensity (plane wave)",show=0) plot(wavefront.get_abscissas(),wavefront.get_phase(),title="Phase (plane wave)",show=1)
def propagate_1D_fraunhofer( wavefront, propagation_distance=0.0, shift_half_pixel=0): # todo: modificato da giovanni """ 1D Fraunhofer propagator using convolution via Fourier transform :param shift_half_pixel: :param shift_half_pixel: :param wavefront: :param propagation_distance: propagation distance. If set to zero, the abscissas of the returned wavefront are in angle (rad) :return: a new 1D wavefront object with propagated wavefront """ shape = wavefront.size() delta = wavefront.delta() wavenumber = wavefront.get_wavenumber() wavelength = wavefront.get_wavelength() fft_scale = numpy.fft.fftfreq(shape, d=delta) fft_scale = numpy.fft.fftshift(fft_scale) x2 = fft_scale * propagation_distance * wavelength # freq_nyquist = 0.5 / delta # freq_n = numpy.linspace(-1.0, 1.0, shape) # freq_x = freq_n * freq_nyquist # freq_x *= wavelength * propagation_distance # x2 = freq_x P1 = numpy.exp(1.0j * wavenumber * propagation_distance) P2 = numpy.exp(1.0j * wavenumber / (2 * propagation_distance) * x2**2) P3 = 1.0j * wavelength * propagation_distance fft = numpy.fft.fft(wavefront.get_complex_amplitude()) fft *= P1 fft *= P2 fft /= P3 # fft *= P4 fft2 = numpy.fft.fftshift(fft) if shift_half_pixel: x2 = x2 - 0.5 * numpy.abs(x2[1] - x2[0]) return Wavefront1D.initialize_wavefront_from_arrays( x2, fft2, wavelength=wavefront.get_wavelength())
def test_interpolator(self, do_plot=do_plot): # # interpolator # print("# ") print("# Tests for 1D interpolator ") print("# ") x = numpy.linspace(-10, 10, 100) sigma = 3.0 Z = numpy.exp(-1.0 * x**2 / 2 / sigma**2) print("shape of Z", Z.shape) wf = Wavefront1D.initialize_wavefront_from_steps(x[0], numpy.abs(x[1] - x[0]), number_of_points=100) print("wf shape: ", wf.size()) wf.set_complex_amplitude(Z) x1 = 3.2 z1 = numpy.exp(x1**2 / -2 / sigma**2) print("complex ampl at (%g): %g+%gi (exact=%g)" % (x1, wf.get_interpolated_complex_amplitude(x1).real, wf.get_interpolated_complex_amplitude(x1).imag, z1)) self.assertAlmostEqual( wf.get_interpolated_complex_amplitude(x1).real, z1, 4) print("intensity at (%g): %g (exact=%g)" % (x1, wf.get_interpolated_intensity(x1), z1**2)) self.assertAlmostEqual(wf.get_interpolated_intensity(x1), z1**2, 4) if do_plot: from srxraylib.plot.gol import plot plot(wf.get_abscissas(), wf.get_intensity(), title="Original", show=1) xx = wf.get_abscissas() yy = wf.get_interpolated_intensities(wf.get_abscissas() - 1e-5) plot(xx, yy, title="interpolated on same grid", show=1)
def test_interpolator(self,do_plot=do_plot): # # interpolator # print("# ") print("# Tests for 1D interpolator ") print("# ") x = numpy.linspace(-10,10,100) sigma = 3.0 Z = numpy.exp(-1.0*x**2/2/sigma**2) print("shape of Z",Z.shape) wf = Wavefront1D.initialize_wavefront_from_steps(x[0],numpy.abs(x[1]-x[0]),number_of_points=100) print("wf shape: ",wf.size()) wf.set_complex_amplitude( Z ) x1 = 3.2 z1 = numpy.exp(x1**2/-2/sigma**2) print("complex ampl at (%g): %g+%gi (exact=%g)"%(x1, wf.get_interpolated_complex_amplitude(x1).real, wf.get_interpolated_complex_amplitude(x1).imag, z1)) self.assertAlmostEqual(wf.get_interpolated_complex_amplitude(x1).real,z1,4) print("intensity at (%g): %g (exact=%g)"%(x1,wf.get_interpolated_intensity(x1),z1**2)) self.assertAlmostEqual(wf.get_interpolated_intensity(x1),z1**2,4) if do_plot: from srxraylib.plot.gol import plot plot(wf.get_abscissas(),wf.get_intensity(),title="Original",show=1) xx = wf.get_abscissas() yy = wf.get_interpolated_intensities(wf.get_abscissas()-1e-5) plot(xx,yy,title="interpolated on same grid",show=1)
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_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 test_plane_wave(self, do_plot=do_plot): # # plane wave # print("# ") print("# Tests for a 1D plane wave ") print("# ") wavelength = 1.24e-10 wavefront_length_x = 400e-6 npixels_x = 1024 wavefront_x = numpy.linspace(-0.5 * wavefront_length_x, 0.5 * wavefront_length_x, npixels_x) wavefront = Wavefront1D.initialize_wavefront_from_steps( x_start=wavefront_x[0], x_step=numpy.abs(wavefront_x[1] - wavefront_x[0]), number_of_points=npixels_x, wavelength=wavelength) numpy.testing.assert_almost_equal(wavefront_x, wavefront.get_abscissas(), 9) # possible modifications wavefront.set_plane_wave_from_amplitude_and_phase(5.0, numpy.pi / 2) numpy.testing.assert_almost_equal(wavefront.get_intensity(), 25, 5) wavefront.set_plane_wave_from_complex_amplitude(2.0 + 3j) numpy.testing.assert_almost_equal(wavefront.get_intensity(), 13, 5) phase_before = wavefront.get_phase() wavefront.add_phase_shift(numpy.pi / 2) phase_after = wavefront.get_phase() numpy.testing.assert_almost_equal(phase_before + numpy.pi / 2, phase_after, 5) intensity_before = wavefront.get_intensity() wavefront.rescale_amplitude(10.0) intensity_after = wavefront.get_intensity() numpy.testing.assert_almost_equal(intensity_before * 100, intensity_after, 5) # interpolation wavefront.set_plane_wave_from_complex_amplitude(2.0 + 3j) test_value1 = wavefront.get_interpolated_complex_amplitude(0.01) self.assertAlmostEqual((2.0 + 3j).real, test_value1.real, 5) self.assertAlmostEqual((2.0 + 3j).imag, test_value1.imag, 5) if do_plot: from srxraylib.plot.gol import plot plot(wavefront.get_abscissas(), wavefront.get_intensity(), title="Intensity (plane wave)", show=0) plot(wavefront.get_abscissas(), wavefront.get_phase(), title="Phase (plane wave)", show=1)