From 2f851888742789af972aa27297ff96cb1bebc077 Mon Sep 17 00:00:00 2001 From: J-K Date: Tue, 24 Sep 2024 16:46:02 +1000 Subject: [PATCH 01/10] Create fresnel_diffract.py Code for wave diffraction in the Fresnel regime was missing from the algorithms list and has been added. --- physics/fresnel_diffract.py | 124 ++++++++++++++++++++++++++++++++++++ 1 file changed, 124 insertions(+) create mode 100644 physics/fresnel_diffract.py diff --git a/physics/fresnel_diffract.py b/physics/fresnel_diffract.py new file mode 100644 index 000000000000..76f727e3e6a6 --- /dev/null +++ b/physics/fresnel_diffract.py @@ -0,0 +1,124 @@ +""" +Title: Fresnel Diffraction for Coherent and Monochromatic + Wave Fields + +Fresnel Diffraction describes the behavior of a wave field as it +moves through free space or interacts with an object under the +small angle approximation. It is particularly useful for near +field diffraction. + +The following algorithm is an adaptation of the 'transfer function' +based approach contained in the reference. It is critically +sampled when: +pixel_size = wavelength * prop_dist / side_length + +Or equivalently: +pixel_size = sqrt(wavelength * prop_dist / pixel_num) + +Under and oversampling occur when the left-hand side is less +than or greater than the right-hand side, respectively. + +This code is adapted and modified from: +Computational Fourier Optics: A MATLAB Tutorial by David Voelz +""" +import numpy as np +from math import pi +from scipy.fft import fft, fftshift, ifft, ifftshift, fft2, ifft2 + +def fresnel_diffract(wavefunc0, pixel_size, wavelength, prop_dist): + """ + Fresnel Diffraction of 1D or 2D Wave Fields. + + This function calculates the Fresnel diffraction of a + given wave field, suitable for near field diffraction. The + wave field is assumed to be coherent and monochromatic. + + Args: + wavefunc0 (np.ndarray): The initial wave field at the unpropagated plane. + pixel_size (float): The physical size of a pixel (or data point) at the unpropagated plane. + wavelength (float): The wavelength of the wave field. + prop_dist (float): The desired propagation distance. + + Raises: + ValueError: If the input wave field is not 1D or 2D. + + Returns: + np.ndarray: The wave field at the propagated plane. + """ + + if len(wavefunc0.shape) == 1: + return _fresnel_diffract_1D( + wavefunc0, pixel_size, wavelength, prop_dist) + elif len(wavefunc0.shape) == 2: + return _fresnel_diffract_2D( + wavefunc0, pixel_size, wavelength, prop_dist) + else: + raise ValueError( + f'Expected a 1D or 2D wavefield, but got {wavefunc0.shape}') + +def _fresnel_diffract_2D(wavefunc0, pixel_size, wavelength, prop_dist): + """ + Fresnel Diffraction of 2D Wave Fields. + + This private function is called by 'fresnel_diffract' to handle the + fresnel diffraction of 2D wave fields specifically. + + Args: + wavefunc0 (np.ndarray): The initial 2D wave field at the unpropagated plane. + pixel_size (float): The physical size of a pixel (or data point) at the unpropagated plane. + wavelength (float): The wavelength of the wave field. + prop_dist (float): The desired propagation distance. + + Returns: + np.ndarray: The 2D wave field at the propagated plane. + """ + pixel_num, _ = wavefunc0.shape + side_length = pixel_num * pixel_size + + # Coordinates in Fourier space are proportionate to 1 / pixel_size + f_x = np.arange( + -1 / (2 * pixel_size), 1 / ( 2 * pixel_size), 1 / side_length + ) + + F_X, F_Y = np.meshgrid(f_x, f_x) + + # Transfer function which models diffraction + transferf = np.exp(-1j*np.pi*wavelength*prop_dist*(F_X**2 + F_Y**2)) + transferf = fftshift(transferf) + + # Fourier space wave function at the unpropagated plane + f_wavefunc0 = fft2(fftshift(wavefunc0)) + # Wave function at the propagated, or 'z' plane + wavefuncz = ifftshift(ifft2(transferf * f_wavefunc0)) + + return wavefuncz + +def _fresnel_diffract_1D(wavefunc_0, pixel_size, wavelength, prop_dist): + """ + Fresnel Diffraction of 1D Wave Fields. + + This private function is called by 'fresnel_diffract' to handle the + fresnel diffraction of 1D wave fields specifically. + + Args: + wavefunc0 (np.ndarray): The initial 1D wave field at the unpropagated plane. + pixel_size (float): The physical size of a pixel (or data point) at the unpropagated plane. + wavelength (float): The wavelength of the wave field. + prop_dist (float): The desired propagation distance. + + Returns: + np.ndarray: The 1D wave field at the propagated plane. + """ + pixel_num = len(wavefunc_0) + side_length = pixel_num * pixel_size + fx = np.arange( + -1 / (2 * pixel_size), 1 / (2 * pixel_size), 1 / side_length + ) + transferf = np.exp(-1j * pi * wavelength * prop_dist * (fx**2)) + transferf = fftshift(transferf) + + f_wavefunc_0 = fft(fftshift(wavefunc_0)) + + wavefunc_z = ifftshift(ifft(transferf * f_wavefunc_0)) + + return wavefunc_z \ No newline at end of file From 490b0e66007d42d16650a35fbb5567ada7602a00 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 07:01:44 +0000 Subject: [PATCH 02/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- physics/fresnel_diffract.py | 81 ++++++++++++++++++------------------- 1 file changed, 39 insertions(+), 42 deletions(-) diff --git a/physics/fresnel_diffract.py b/physics/fresnel_diffract.py index 76f727e3e6a6..f4d95573cfab 100644 --- a/physics/fresnel_diffract.py +++ b/physics/fresnel_diffract.py @@ -2,36 +2,38 @@ Title: Fresnel Diffraction for Coherent and Monochromatic Wave Fields -Fresnel Diffraction describes the behavior of a wave field as it -moves through free space or interacts with an object under the -small angle approximation. It is particularly useful for near +Fresnel Diffraction describes the behavior of a wave field as it +moves through free space or interacts with an object under the +small angle approximation. It is particularly useful for near field diffraction. The following algorithm is an adaptation of the 'transfer function' -based approach contained in the reference. It is critically +based approach contained in the reference. It is critically sampled when: pixel_size = wavelength * prop_dist / side_length Or equivalently: pixel_size = sqrt(wavelength * prop_dist / pixel_num) -Under and oversampling occur when the left-hand side is less +Under and oversampling occur when the left-hand side is less than or greater than the right-hand side, respectively. This code is adapted and modified from: Computational Fourier Optics: A MATLAB Tutorial by David Voelz """ -import numpy as np + +import numpy as np from math import pi from scipy.fft import fft, fftshift, ifft, ifftshift, fft2, ifft2 + def fresnel_diffract(wavefunc0, pixel_size, wavelength, prop_dist): """ Fresnel Diffraction of 1D or 2D Wave Fields. - - This function calculates the Fresnel diffraction of a - given wave field, suitable for near field diffraction. The - wave field is assumed to be coherent and monochromatic. + + This function calculates the Fresnel diffraction of a + given wave field, suitable for near field diffraction. The + wave field is assumed to be coherent and monochromatic. Args: wavefunc0 (np.ndarray): The initial wave field at the unpropagated plane. @@ -43,24 +45,22 @@ def fresnel_diffract(wavefunc0, pixel_size, wavelength, prop_dist): ValueError: If the input wave field is not 1D or 2D. Returns: - np.ndarray: The wave field at the propagated plane. + np.ndarray: The wave field at the propagated plane. """ - + if len(wavefunc0.shape) == 1: - return _fresnel_diffract_1D( - wavefunc0, pixel_size, wavelength, prop_dist) + return _fresnel_diffract_1D(wavefunc0, pixel_size, wavelength, prop_dist) elif len(wavefunc0.shape) == 2: - return _fresnel_diffract_2D( - wavefunc0, pixel_size, wavelength, prop_dist) + return _fresnel_diffract_2D(wavefunc0, pixel_size, wavelength, prop_dist) else: - raise ValueError( - f'Expected a 1D or 2D wavefield, but got {wavefunc0.shape}') + raise ValueError(f"Expected a 1D or 2D wavefield, but got {wavefunc0.shape}") + def _fresnel_diffract_2D(wavefunc0, pixel_size, wavelength, prop_dist): """ Fresnel Diffraction of 2D Wave Fields. - - This private function is called by 'fresnel_diffract' to handle the + + This private function is called by 'fresnel_diffract' to handle the fresnel diffraction of 2D wave fields specifically. Args: @@ -70,34 +70,33 @@ def _fresnel_diffract_2D(wavefunc0, pixel_size, wavelength, prop_dist): prop_dist (float): The desired propagation distance. Returns: - np.ndarray: The 2D wave field at the propagated plane. + np.ndarray: The 2D wave field at the propagated plane. """ - pixel_num, _ = wavefunc0.shape - side_length = pixel_num * pixel_size - - # Coordinates in Fourier space are proportionate to 1 / pixel_size - f_x = np.arange( - -1 / (2 * pixel_size), 1 / ( 2 * pixel_size), 1 / side_length - ) + pixel_num, _ = wavefunc0.shape + side_length = pixel_num * pixel_size + + # Coordinates in Fourier space are proportionate to 1 / pixel_size + f_x = np.arange(-1 / (2 * pixel_size), 1 / (2 * pixel_size), 1 / side_length) F_X, F_Y = np.meshgrid(f_x, f_x) - + # Transfer function which models diffraction - transferf = np.exp(-1j*np.pi*wavelength*prop_dist*(F_X**2 + F_Y**2)) + transferf = np.exp(-1j * np.pi * wavelength * prop_dist * (F_X**2 + F_Y**2)) transferf = fftshift(transferf) # Fourier space wave function at the unpropagated plane f_wavefunc0 = fft2(fftshift(wavefunc0)) # Wave function at the propagated, or 'z' plane wavefuncz = ifftshift(ifft2(transferf * f_wavefunc0)) - + return wavefuncz + def _fresnel_diffract_1D(wavefunc_0, pixel_size, wavelength, prop_dist): """ Fresnel Diffraction of 1D Wave Fields. - - This private function is called by 'fresnel_diffract' to handle the + + This private function is called by 'fresnel_diffract' to handle the fresnel diffraction of 1D wave fields specifically. Args: @@ -107,18 +106,16 @@ def _fresnel_diffract_1D(wavefunc_0, pixel_size, wavelength, prop_dist): prop_dist (float): The desired propagation distance. Returns: - np.ndarray: The 1D wave field at the propagated plane. + np.ndarray: The 1D wave field at the propagated plane. """ - pixel_num = len(wavefunc_0) - side_length = pixel_num * pixel_size - fx = np.arange( - -1 / (2 * pixel_size), 1 / (2 * pixel_size), 1 / side_length - ) + pixel_num = len(wavefunc_0) + side_length = pixel_num * pixel_size + fx = np.arange(-1 / (2 * pixel_size), 1 / (2 * pixel_size), 1 / side_length) transferf = np.exp(-1j * pi * wavelength * prop_dist * (fx**2)) transferf = fftshift(transferf) f_wavefunc_0 = fft(fftshift(wavefunc_0)) - + wavefunc_z = ifftshift(ifft(transferf * f_wavefunc_0)) - - return wavefunc_z \ No newline at end of file + + return wavefunc_z From 00b567d3afd8024668dd6a9c04d3b6caf05792c3 Mon Sep 17 00:00:00 2001 From: J-K Date: Tue, 24 Sep 2024 17:16:14 +1000 Subject: [PATCH 03/10] Altered Styling for Ruff --- physics/fresnel_diffract.py | 54 ++++++++++++++++++++----------------- 1 file changed, 30 insertions(+), 24 deletions(-) diff --git a/physics/fresnel_diffract.py b/physics/fresnel_diffract.py index 76f727e3e6a6..1ddf37c12436 100644 --- a/physics/fresnel_diffract.py +++ b/physics/fresnel_diffract.py @@ -21,9 +21,11 @@ This code is adapted and modified from: Computational Fourier Optics: A MATLAB Tutorial by David Voelz """ -import numpy as np from math import pi -from scipy.fft import fft, fftshift, ifft, ifftshift, fft2, ifft2 + +import numpy as np +from scipy.fft import fft, fft2, fftshift, ifft, ifft2, ifftshift + def fresnel_diffract(wavefunc0, pixel_size, wavelength, prop_dist): """ @@ -35,7 +37,8 @@ def fresnel_diffract(wavefunc0, pixel_size, wavelength, prop_dist): Args: wavefunc0 (np.ndarray): The initial wave field at the unpropagated plane. - pixel_size (float): The physical size of a pixel (or data point) at the unpropagated plane. + pixel_size (float): The physical size of a pixel (or data point) at the + unpropagated plane. wavelength (float): The wavelength of the wave field. prop_dist (float): The desired propagation distance. @@ -45,18 +48,19 @@ def fresnel_diffract(wavefunc0, pixel_size, wavelength, prop_dist): Returns: np.ndarray: The wave field at the propagated plane. """ - + if len(wavefunc0.shape) == 1: - return _fresnel_diffract_1D( + return _fresnel_diffract_1d( wavefunc0, pixel_size, wavelength, prop_dist) elif len(wavefunc0.shape) == 2: - return _fresnel_diffract_2D( + return _fresnel_diffract_2d( wavefunc0, pixel_size, wavelength, prop_dist) else: + err_shape = wavefunc0.shape raise ValueError( - f'Expected a 1D or 2D wavefield, but got {wavefunc0.shape}') + f'Expected a 1D or 2D wavefield, but got {err_shape}') -def _fresnel_diffract_2D(wavefunc0, pixel_size, wavelength, prop_dist): +def _fresnel_diffract_2d(wavefunc0, pixel_size, wavelength, prop_dist): """ Fresnel Diffraction of 2D Wave Fields. @@ -65,35 +69,36 @@ def _fresnel_diffract_2D(wavefunc0, pixel_size, wavelength, prop_dist): Args: wavefunc0 (np.ndarray): The initial 2D wave field at the unpropagated plane. - pixel_size (float): The physical size of a pixel (or data point) at the unpropagated plane. + pixel_size (float): The physical size of a pixel (or data point) at the + unpropagated plane. wavelength (float): The wavelength of the wave field. prop_dist (float): The desired propagation distance. Returns: np.ndarray: The 2D wave field at the propagated plane. """ - pixel_num, _ = wavefunc0.shape - side_length = pixel_num * pixel_size - - # Coordinates in Fourier space are proportionate to 1 / pixel_size + pixel_num, _ = wavefunc0.shape + side_length = pixel_num * pixel_size + + # Coordinates in Fourier space are proportionate to 1 / pixel_size f_x = np.arange( -1 / (2 * pixel_size), 1 / ( 2 * pixel_size), 1 / side_length ) - F_X, F_Y = np.meshgrid(f_x, f_x) - + f_x2d, f_y2d = np.meshgrid(f_x, f_x) + # Transfer function which models diffraction - transferf = np.exp(-1j*np.pi*wavelength*prop_dist*(F_X**2 + F_Y**2)) + transferf = np.exp(-1j*np.pi*wavelength*prop_dist*(f_x2d**2 + f_y2d**2)) transferf = fftshift(transferf) # Fourier space wave function at the unpropagated plane f_wavefunc0 = fft2(fftshift(wavefunc0)) # Wave function at the propagated, or 'z' plane wavefuncz = ifftshift(ifft2(transferf * f_wavefunc0)) - + return wavefuncz -def _fresnel_diffract_1D(wavefunc_0, pixel_size, wavelength, prop_dist): +def _fresnel_diffract_1d(wavefunc_0, pixel_size, wavelength, prop_dist): """ Fresnel Diffraction of 1D Wave Fields. @@ -102,15 +107,16 @@ def _fresnel_diffract_1D(wavefunc_0, pixel_size, wavelength, prop_dist): Args: wavefunc0 (np.ndarray): The initial 1D wave field at the unpropagated plane. - pixel_size (float): The physical size of a pixel (or data point) at the unpropagated plane. + pixel_size (float): The physical size of a pixel (or data point) at the + unpropagated plane. wavelength (float): The wavelength of the wave field. prop_dist (float): The desired propagation distance. Returns: np.ndarray: The 1D wave field at the propagated plane. """ - pixel_num = len(wavefunc_0) - side_length = pixel_num * pixel_size + pixel_num = len(wavefunc_0) + side_length = pixel_num * pixel_size fx = np.arange( -1 / (2 * pixel_size), 1 / (2 * pixel_size), 1 / side_length ) @@ -118,7 +124,7 @@ def _fresnel_diffract_1D(wavefunc_0, pixel_size, wavelength, prop_dist): transferf = fftshift(transferf) f_wavefunc_0 = fft(fftshift(wavefunc_0)) - + wavefunc_z = ifftshift(ifft(transferf * f_wavefunc_0)) - - return wavefunc_z \ No newline at end of file + + return wavefunc_z From 9ea5697c635e8cd872d77c6df7503616ec13919f Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 07:17:58 +0000 Subject: [PATCH 04/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- physics/fresnel_diffract.py | 29 ++++++++++++----------------- 1 file changed, 12 insertions(+), 17 deletions(-) diff --git a/physics/fresnel_diffract.py b/physics/fresnel_diffract.py index 647b5ea69265..9e49e9c472ac 100644 --- a/physics/fresnel_diffract.py +++ b/physics/fresnel_diffract.py @@ -21,13 +21,13 @@ This code is adapted and modified from: Computational Fourier Optics: A MATLAB Tutorial by David Voelz """ + from math import pi import numpy as np from scipy.fft import fft, fft2, fftshift, ifft, ifft2, ifftshift - def fresnel_diffract(wavefunc0, pixel_size, wavelength, prop_dist): """ Fresnel Diffraction of 1D or 2D Wave Fields. @@ -38,7 +38,7 @@ def fresnel_diffract(wavefunc0, pixel_size, wavelength, prop_dist): Args: wavefunc0 (np.ndarray): The initial wave field at the unpropagated plane. - pixel_size (float): The physical size of a pixel (or data point) at the + pixel_size (float): The physical size of a pixel (or data point) at the unpropagated plane. wavelength (float): The wavelength of the wave field. prop_dist (float): The desired propagation distance. @@ -51,15 +51,13 @@ def fresnel_diffract(wavefunc0, pixel_size, wavelength, prop_dist): """ if len(wavefunc0.shape) == 1: - return _fresnel_diffract_1d( - wavefunc0, pixel_size, wavelength, prop_dist) + return _fresnel_diffract_1d(wavefunc0, pixel_size, wavelength, prop_dist) elif len(wavefunc0.shape) == 2: - return _fresnel_diffract_2d( - wavefunc0, pixel_size, wavelength, prop_dist) + return _fresnel_diffract_2d(wavefunc0, pixel_size, wavelength, prop_dist) else: err_shape = wavefunc0.shape - raise ValueError( - f'Expected a 1D or 2D wavefield, but got {err_shape}') + raise ValueError(f"Expected a 1D or 2D wavefield, but got {err_shape}") + def _fresnel_diffract_2d(wavefunc0, pixel_size, wavelength, prop_dist): """ @@ -70,7 +68,7 @@ def _fresnel_diffract_2d(wavefunc0, pixel_size, wavelength, prop_dist): Args: wavefunc0 (np.ndarray): The initial 2D wave field at the unpropagated plane. - pixel_size (float): The physical size of a pixel (or data point) at the + pixel_size (float): The physical size of a pixel (or data point) at the unpropagated plane. wavelength (float): The wavelength of the wave field. prop_dist (float): The desired propagation distance. @@ -82,14 +80,12 @@ def _fresnel_diffract_2d(wavefunc0, pixel_size, wavelength, prop_dist): side_length = pixel_num * pixel_size # Coordinates in Fourier space are proportionate to 1 / pixel_size - f_x = np.arange( - -1 / (2 * pixel_size), 1 / ( 2 * pixel_size), 1 / side_length - ) + f_x = np.arange(-1 / (2 * pixel_size), 1 / (2 * pixel_size), 1 / side_length) f_x2d, f_y2d = np.meshgrid(f_x, f_x) # Transfer function which models diffraction - transferf = np.exp(-1j*np.pi*wavelength*prop_dist*(f_x2d**2 + f_y2d**2)) + transferf = np.exp(-1j * np.pi * wavelength * prop_dist * (f_x2d**2 + f_y2d**2)) transferf = fftshift(transferf) # Fourier space wave function at the unpropagated plane @@ -99,6 +95,7 @@ def _fresnel_diffract_2d(wavefunc0, pixel_size, wavelength, prop_dist): return wavefuncz + def _fresnel_diffract_1d(wavefunc_0, pixel_size, wavelength, prop_dist): """ Fresnel Diffraction of 1D Wave Fields. @@ -108,7 +105,7 @@ def _fresnel_diffract_1d(wavefunc_0, pixel_size, wavelength, prop_dist): Args: wavefunc0 (np.ndarray): The initial 1D wave field at the unpropagated plane. - pixel_size (float): The physical size of a pixel (or data point) at the + pixel_size (float): The physical size of a pixel (or data point) at the unpropagated plane. wavelength (float): The wavelength of the wave field. prop_dist (float): The desired propagation distance. @@ -118,9 +115,7 @@ def _fresnel_diffract_1d(wavefunc_0, pixel_size, wavelength, prop_dist): """ pixel_num = len(wavefunc_0) side_length = pixel_num * pixel_size - fx = np.arange( - -1 / (2 * pixel_size), 1 / (2 * pixel_size), 1 / side_length - ) + fx = np.arange(-1 / (2 * pixel_size), 1 / (2 * pixel_size), 1 / side_length) transferf = np.exp(-1j * pi * wavelength * prop_dist * (fx**2)) transferf = fftshift(transferf) From ba577dfc3ff78d794810a044be56d024ac8d17a4 Mon Sep 17 00:00:00 2001 From: J-K Date: Tue, 24 Sep 2024 18:56:21 +1000 Subject: [PATCH 05/10] Adjusted styling for ruff --- physics/fresnel_diffract.py | 48 ++++++++++++++++++++++++------------- 1 file changed, 32 insertions(+), 16 deletions(-) diff --git a/physics/fresnel_diffract.py b/physics/fresnel_diffract.py index 9e49e9c472ac..76f747920a4b 100644 --- a/physics/fresnel_diffract.py +++ b/physics/fresnel_diffract.py @@ -28,7 +28,12 @@ from scipy.fft import fft, fft2, fftshift, ifft, ifft2, ifftshift -def fresnel_diffract(wavefunc0, pixel_size, wavelength, prop_dist): +def fresnel_diffract( + wavefunc_0: np.ndarray, + pixel_size: float, + wavelength: float, + prop_dist: float + ) -> np.ndarray: """ Fresnel Diffraction of 1D or 2D Wave Fields. @@ -39,6 +44,7 @@ def fresnel_diffract(wavefunc0, pixel_size, wavelength, prop_dist): Args: wavefunc0 (np.ndarray): The initial wave field at the unpropagated plane. pixel_size (float): The physical size of a pixel (or data point) at the + pixel_size (float): The physical size of a pixel (or data point) at the unpropagated plane. wavelength (float): The wavelength of the wave field. prop_dist (float): The desired propagation distance. @@ -50,16 +56,22 @@ def fresnel_diffract(wavefunc0, pixel_size, wavelength, prop_dist): np.ndarray: The wave field at the propagated plane. """ - if len(wavefunc0.shape) == 1: - return _fresnel_diffract_1d(wavefunc0, pixel_size, wavelength, prop_dist) - elif len(wavefunc0.shape) == 2: - return _fresnel_diffract_2d(wavefunc0, pixel_size, wavelength, prop_dist) + if len(wavefunc_0.shape) == 1: + return _fresnel_diffract_1d( + wavefunc_0, pixel_size, wavelength, prop_dist) + elif len(wavefunc_0.shape) == 2: + return _fresnel_diffract_2d( + wavefunc_0, pixel_size, wavelength, prop_dist) else: - err_shape = wavefunc0.shape - raise ValueError(f"Expected a 1D or 2D wavefield, but got {err_shape}") - - -def _fresnel_diffract_2d(wavefunc0, pixel_size, wavelength, prop_dist): + error_message = f"Expected a 1D or 2D wavefield, but got {wavefunc_0.shape}" + raise ValueError(error_message) + +def _fresnel_diffract_2d( + wavefunc_0: np.ndarray, + pixel_size: float, + wavelength: float, + prop_dist: float + ) -> np.ndarray: """ Fresnel Diffraction of 2D Wave Fields. @@ -67,7 +79,7 @@ def _fresnel_diffract_2d(wavefunc0, pixel_size, wavelength, prop_dist): fresnel diffraction of 2D wave fields specifically. Args: - wavefunc0 (np.ndarray): The initial 2D wave field at the unpropagated plane. + wavefunc_0 (np.ndarray): The initial 2D wave field at the unpropagated plane. pixel_size (float): The physical size of a pixel (or data point) at the unpropagated plane. wavelength (float): The wavelength of the wave field. @@ -76,7 +88,7 @@ def _fresnel_diffract_2d(wavefunc0, pixel_size, wavelength, prop_dist): Returns: np.ndarray: The 2D wave field at the propagated plane. """ - pixel_num, _ = wavefunc0.shape + pixel_num, _ = wavefunc_0.shape side_length = pixel_num * pixel_size # Coordinates in Fourier space are proportionate to 1 / pixel_size @@ -89,14 +101,18 @@ def _fresnel_diffract_2d(wavefunc0, pixel_size, wavelength, prop_dist): transferf = fftshift(transferf) # Fourier space wave function at the unpropagated plane - f_wavefunc0 = fft2(fftshift(wavefunc0)) + f_wavefunc_0 = fft2(fftshift(wavefunc_0)) # Wave function at the propagated, or 'z' plane - wavefuncz = ifftshift(ifft2(transferf * f_wavefunc0)) + wavefuncz = ifftshift(ifft2(transferf * f_wavefunc_0)) return wavefuncz - -def _fresnel_diffract_1d(wavefunc_0, pixel_size, wavelength, prop_dist): +def _fresnel_diffract_1d( + wavefunc_0: np.ndarray, + pixel_size: float, + wavelength: float, + prop_dist: float + ) -> np.ndarray: """ Fresnel Diffraction of 1D Wave Fields. From 40e5f1e9b155971bf4e1b7486a83ffaf5b1e82c2 Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Tue, 24 Sep 2024 08:57:48 +0000 Subject: [PATCH 06/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- physics/fresnel_diffract.py | 29 ++++++++++------------------- 1 file changed, 10 insertions(+), 19 deletions(-) diff --git a/physics/fresnel_diffract.py b/physics/fresnel_diffract.py index 76f747920a4b..9c53b62db742 100644 --- a/physics/fresnel_diffract.py +++ b/physics/fresnel_diffract.py @@ -29,11 +29,8 @@ def fresnel_diffract( - wavefunc_0: np.ndarray, - pixel_size: float, - wavelength: float, - prop_dist: float - ) -> np.ndarray: + wavefunc_0: np.ndarray, pixel_size: float, wavelength: float, prop_dist: float +) -> np.ndarray: """ Fresnel Diffraction of 1D or 2D Wave Fields. @@ -57,21 +54,17 @@ def fresnel_diffract( """ if len(wavefunc_0.shape) == 1: - return _fresnel_diffract_1d( - wavefunc_0, pixel_size, wavelength, prop_dist) + return _fresnel_diffract_1d(wavefunc_0, pixel_size, wavelength, prop_dist) elif len(wavefunc_0.shape) == 2: - return _fresnel_diffract_2d( - wavefunc_0, pixel_size, wavelength, prop_dist) + return _fresnel_diffract_2d(wavefunc_0, pixel_size, wavelength, prop_dist) else: error_message = f"Expected a 1D or 2D wavefield, but got {wavefunc_0.shape}" raise ValueError(error_message) + def _fresnel_diffract_2d( - wavefunc_0: np.ndarray, - pixel_size: float, - wavelength: float, - prop_dist: float - ) -> np.ndarray: + wavefunc_0: np.ndarray, pixel_size: float, wavelength: float, prop_dist: float +) -> np.ndarray: """ Fresnel Diffraction of 2D Wave Fields. @@ -107,12 +100,10 @@ def _fresnel_diffract_2d( return wavefuncz + def _fresnel_diffract_1d( - wavefunc_0: np.ndarray, - pixel_size: float, - wavelength: float, - prop_dist: float - ) -> np.ndarray: + wavefunc_0: np.ndarray, pixel_size: float, wavelength: float, prop_dist: float +) -> np.ndarray: """ Fresnel Diffraction of 1D Wave Fields. From aa9aeaa82e6879d80423d7b30737266646a5d032 Mon Sep 17 00:00:00 2001 From: J-K Date: Thu, 26 Sep 2024 14:39:40 +1000 Subject: [PATCH 07/10] Included Tests Tests covering dimensionality, error checking, conservation of energy, and zero propagation distance, have all been included. --- physics/fresnel_diffract.py | 80 +++++++++++++++++++++++++++++++++++++ 1 file changed, 80 insertions(+) diff --git a/physics/fresnel_diffract.py b/physics/fresnel_diffract.py index 9c53b62db742..7390f33a972d 100644 --- a/physics/fresnel_diffract.py +++ b/physics/fresnel_diffract.py @@ -51,6 +51,44 @@ def fresnel_diffract( Returns: np.ndarray: The wave field at the propagated plane. + + Examples: + >>> import numpy as np + >>> res = fresnel_diffract(np.ones(64), 1, 1, 1) + >>> res.shape + (64,) + + >>> import numpy as np + >>> res = fresnel_diffract(np.ones((64, 64)), 1, 1, 1) + >>> res.shape + (64, 64) + + >>> import numpy as np + >>> res = fresnel_diffract(np.ones((4, 4, 4)), 1, 1, 1) + Traceback (most recent call last): + ... + ValueError: Expected a 1D or 2D wavefield, but got (4, 4, 4) + + # Test that conservation of energy is obeyed + >>> import numpy as np + >>> wf0 = np.ones(64) + >>> wfz = fresnel_diffract(wf0, 1, 1, 1) + >>> np.isclose(np.sum(abs(wf0)**2), np.sum(abs(wfz)**2)) + True + + >>> import numpy as np + >>> wf0 = np.ones((64, 64)) + >>> wfz = fresnel_diffract(wf0, 1, 1, 1) + >>> np.isclose(np.sum(abs(wf0)**2), np.sum(abs(wfz)**2)) + True + + # Test that propagation distance of 0 returns the contact image + >>> import numpy as np + >>> x = np.linspace(-32, 32, 1) + >>> wf0 = np.where(abs(x)<=8, 1, 0) + >>> wfz = fresnel_diffract(wf0, 1, 1, 0) + >>> np.allclose(wf0, wfz) + True """ if len(wavefunc_0.shape) == 1: @@ -80,6 +118,27 @@ def _fresnel_diffract_2d( Returns: np.ndarray: The 2D wave field at the propagated plane. + + Examples: + >>> import numpy as np + >>> res = _fresnel_diffract_2d(np.ones((64, 64)), 1, 1, 1) + >>> res.shape + (64, 64) + + >>> import numpy as np + >>> wf0 = np.ones((64, 64)) + >>> wfz = _fresnel_diffract_2d(wf0, 1, 1, 1) + >>> np.isclose(np.sum(abs(wf0)**2), np.sum(abs(wfz)**2)) + True + + # Test that propagation distance of 0 returns the contact image + >>> import numpy as np + >>> x = np.linspace(-32, 32, 1) + >>> X1, X2 = np.meshgrid(x, x) + >>> wf0 = np.where(abs(X1)<=8, 1, 0) * np.where(abs(X2)<=8, 1, 0) + >>> wfz = _fresnel_diffract_2d(wf0, 1, 1, 0) + >>> np.allclose(wf0, wfz) + True """ pixel_num, _ = wavefunc_0.shape side_length = pixel_num * pixel_size @@ -119,6 +178,27 @@ def _fresnel_diffract_1d( Returns: np.ndarray: The 1D wave field at the propagated plane. + + Examples: + >>> import numpy as np + >>> res = _fresnel_diffract_1d(np.ones(64), 1, 1, 1) + >>> res.shape + (64,) + + # Conservation of energy + >>> import numpy as np + >>> wf0 = np.ones(64) + >>> wfz = _fresnel_diffract_1d(wf0, 1, 1, 1) + >>> np.isclose(np.sum(abs(wf0)**2), np.sum(abs(wfz)**2)) + True + + # Test that propagation distance of 0 returns the contact image + >>> import numpy as np + >>> x = np.linspace(-32, 32, 1) + >>> wf0 = np.where(abs(x)<=8, 1, 0) + >>> wfz = _fresnel_diffract_1d(wf0, 1, 1, 0) + >>> np.allclose(wf0, wfz) + True """ pixel_num = len(wavefunc_0) side_length = pixel_num * pixel_size From c3a2a3f729ef6664486f41fa963f8600d9ec1f1c Mon Sep 17 00:00:00 2001 From: "pre-commit-ci[bot]" <66853113+pre-commit-ci[bot]@users.noreply.github.com> Date: Thu, 26 Sep 2024 04:40:12 +0000 Subject: [PATCH 08/10] [pre-commit.ci] auto fixes from pre-commit.com hooks for more information, see https://pre-commit.ci --- physics/fresnel_diffract.py | 24 ++++++++++++------------ 1 file changed, 12 insertions(+), 12 deletions(-) diff --git a/physics/fresnel_diffract.py b/physics/fresnel_diffract.py index 7390f33a972d..999044bf8e15 100644 --- a/physics/fresnel_diffract.py +++ b/physics/fresnel_diffract.py @@ -51,37 +51,37 @@ def fresnel_diffract( Returns: np.ndarray: The wave field at the propagated plane. - + Examples: >>> import numpy as np >>> res = fresnel_diffract(np.ones(64), 1, 1, 1) >>> res.shape (64,) - + >>> import numpy as np >>> res = fresnel_diffract(np.ones((64, 64)), 1, 1, 1) >>> res.shape (64, 64) - + >>> import numpy as np >>> res = fresnel_diffract(np.ones((4, 4, 4)), 1, 1, 1) Traceback (most recent call last): ... ValueError: Expected a 1D or 2D wavefield, but got (4, 4, 4) - + # Test that conservation of energy is obeyed >>> import numpy as np >>> wf0 = np.ones(64) >>> wfz = fresnel_diffract(wf0, 1, 1, 1) >>> np.isclose(np.sum(abs(wf0)**2), np.sum(abs(wfz)**2)) True - + >>> import numpy as np >>> wf0 = np.ones((64, 64)) >>> wfz = fresnel_diffract(wf0, 1, 1, 1) >>> np.isclose(np.sum(abs(wf0)**2), np.sum(abs(wfz)**2)) True - + # Test that propagation distance of 0 returns the contact image >>> import numpy as np >>> x = np.linspace(-32, 32, 1) @@ -118,19 +118,19 @@ def _fresnel_diffract_2d( Returns: np.ndarray: The 2D wave field at the propagated plane. - + Examples: >>> import numpy as np >>> res = _fresnel_diffract_2d(np.ones((64, 64)), 1, 1, 1) >>> res.shape (64, 64) - + >>> import numpy as np >>> wf0 = np.ones((64, 64)) >>> wfz = _fresnel_diffract_2d(wf0, 1, 1, 1) >>> np.isclose(np.sum(abs(wf0)**2), np.sum(abs(wfz)**2)) True - + # Test that propagation distance of 0 returns the contact image >>> import numpy as np >>> x = np.linspace(-32, 32, 1) @@ -178,20 +178,20 @@ def _fresnel_diffract_1d( Returns: np.ndarray: The 1D wave field at the propagated plane. - + Examples: >>> import numpy as np >>> res = _fresnel_diffract_1d(np.ones(64), 1, 1, 1) >>> res.shape (64,) - + # Conservation of energy >>> import numpy as np >>> wf0 = np.ones(64) >>> wfz = _fresnel_diffract_1d(wf0, 1, 1, 1) >>> np.isclose(np.sum(abs(wf0)**2), np.sum(abs(wfz)**2)) True - + # Test that propagation distance of 0 returns the contact image >>> import numpy as np >>> x = np.linspace(-32, 32, 1) From e2751c48c9eac321307869dc81192c061eea37d1 Mon Sep 17 00:00:00 2001 From: J-K Date: Thu, 26 Sep 2024 14:43:54 +1000 Subject: [PATCH 09/10] Updated styling for ruff --- physics/fresnel_diffract.py | 21 ++++----------------- 1 file changed, 4 insertions(+), 17 deletions(-) diff --git a/physics/fresnel_diffract.py b/physics/fresnel_diffract.py index 7390f33a972d..4f0e8b2da39c 100644 --- a/physics/fresnel_diffract.py +++ b/physics/fresnel_diffract.py @@ -51,37 +51,32 @@ def fresnel_diffract( Returns: np.ndarray: The wave field at the propagated plane. - - Examples: + + Examples: >>> import numpy as np >>> res = fresnel_diffract(np.ones(64), 1, 1, 1) >>> res.shape (64,) - >>> import numpy as np >>> res = fresnel_diffract(np.ones((64, 64)), 1, 1, 1) >>> res.shape (64, 64) - >>> import numpy as np >>> res = fresnel_diffract(np.ones((4, 4, 4)), 1, 1, 1) Traceback (most recent call last): ... ValueError: Expected a 1D or 2D wavefield, but got (4, 4, 4) - # Test that conservation of energy is obeyed >>> import numpy as np >>> wf0 = np.ones(64) >>> wfz = fresnel_diffract(wf0, 1, 1, 1) >>> np.isclose(np.sum(abs(wf0)**2), np.sum(abs(wfz)**2)) True - >>> import numpy as np >>> wf0 = np.ones((64, 64)) >>> wfz = fresnel_diffract(wf0, 1, 1, 1) >>> np.isclose(np.sum(abs(wf0)**2), np.sum(abs(wfz)**2)) True - # Test that propagation distance of 0 returns the contact image >>> import numpy as np >>> x = np.linspace(-32, 32, 1) @@ -105,10 +100,8 @@ def _fresnel_diffract_2d( ) -> np.ndarray: """ Fresnel Diffraction of 2D Wave Fields. - This private function is called by 'fresnel_diffract' to handle the fresnel diffraction of 2D wave fields specifically. - Args: wavefunc_0 (np.ndarray): The initial 2D wave field at the unpropagated plane. pixel_size (float): The physical size of a pixel (or data point) at the @@ -118,19 +111,17 @@ def _fresnel_diffract_2d( Returns: np.ndarray: The 2D wave field at the propagated plane. - + Examples: >>> import numpy as np >>> res = _fresnel_diffract_2d(np.ones((64, 64)), 1, 1, 1) >>> res.shape (64, 64) - >>> import numpy as np >>> wf0 = np.ones((64, 64)) >>> wfz = _fresnel_diffract_2d(wf0, 1, 1, 1) >>> np.isclose(np.sum(abs(wf0)**2), np.sum(abs(wfz)**2)) True - # Test that propagation distance of 0 returns the contact image >>> import numpy as np >>> x = np.linspace(-32, 32, 1) @@ -165,10 +156,8 @@ def _fresnel_diffract_1d( ) -> np.ndarray: """ Fresnel Diffraction of 1D Wave Fields. - This private function is called by 'fresnel_diffract' to handle the fresnel diffraction of 1D wave fields specifically. - Args: wavefunc0 (np.ndarray): The initial 1D wave field at the unpropagated plane. pixel_size (float): The physical size of a pixel (or data point) at the @@ -178,20 +167,18 @@ def _fresnel_diffract_1d( Returns: np.ndarray: The 1D wave field at the propagated plane. - + Examples: >>> import numpy as np >>> res = _fresnel_diffract_1d(np.ones(64), 1, 1, 1) >>> res.shape (64,) - # Conservation of energy >>> import numpy as np >>> wf0 = np.ones(64) >>> wfz = _fresnel_diffract_1d(wf0, 1, 1, 1) >>> np.isclose(np.sum(abs(wf0)**2), np.sum(abs(wfz)**2)) True - # Test that propagation distance of 0 returns the contact image >>> import numpy as np >>> x = np.linspace(-32, 32, 1) From 28d717fc7ba5e55dc20f4ccb77adafcdea0ae77e Mon Sep 17 00:00:00 2001 From: J-K Date: Thu, 26 Sep 2024 14:56:21 +1000 Subject: [PATCH 10/10] Updated Tests --- physics/fresnel_diffract.py | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/physics/fresnel_diffract.py b/physics/fresnel_diffract.py index 0ffb30a72916..8bcf7231a91e 100644 --- a/physics/fresnel_diffract.py +++ b/physics/fresnel_diffract.py @@ -66,6 +66,7 @@ def fresnel_diffract( Traceback (most recent call last): ... ValueError: Expected a 1D or 2D wavefield, but got (4, 4, 4) + # Test that conservation of energy is obeyed >>> import numpy as np >>> wf0 = np.ones(64) @@ -77,6 +78,7 @@ def fresnel_diffract( >>> wfz = fresnel_diffract(wf0, 1, 1, 1) >>> np.isclose(np.sum(abs(wf0)**2), np.sum(abs(wfz)**2)) True + # Test that propagation distance of 0 returns the contact image >>> import numpy as np >>> x = np.linspace(-32, 32, 1) @@ -123,6 +125,7 @@ def _fresnel_diffract_2d( >>> wfz = _fresnel_diffract_2d(wf0, 1, 1, 1) >>> np.isclose(np.sum(abs(wf0)**2), np.sum(abs(wfz)**2)) True + # Test that propagation distance of 0 returns the contact image >>> import numpy as np >>> x = np.linspace(-32, 32, 1) @@ -175,12 +178,14 @@ def _fresnel_diffract_1d( >>> res = _fresnel_diffract_1d(np.ones(64), 1, 1, 1) >>> res.shape (64,) + # Conservation of energy >>> import numpy as np >>> wf0 = np.ones(64) >>> wfz = _fresnel_diffract_1d(wf0, 1, 1, 1) >>> np.isclose(np.sum(abs(wf0)**2), np.sum(abs(wfz)**2)) True + # Test that propagation distance of 0 returns the contact image >>> import numpy as np >>> x = np.linspace(-32, 32, 1)