"""
1D wave-optics propagators.
"""
import numpy
from srxraylib import deprecated
from srxraylib.util.data_structures import ScaledArray
from srxraylib.waveoptics.wavefront import Wavefront1D
[docs]@deprecated("use wofry and wofrylib, instead")
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())
[docs]@deprecated("use wofry and wofrylib, instead")
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()))
[docs]@deprecated("use wofry and wofrylib, instead")
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()))
[docs]@deprecated("use wofry and wofrylib, instead")
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()))
[docs]@deprecated("use wofry and wofrylib, instead")
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] ))
[docs]@deprecated("use wofry and wofrylib, instead")
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()))