<jupyter_start><jupyter_text>Through-focus image     Un-debugged snippet from <NAME> to create Gaussian phase bump    phase_bump_pos = [0.2, 0.2]    phase_bump_rms = pupil_diameter / 10    phase_bump_amp = 0.75.  about pi/4    phase_bump = phase_bump_amp * np.exp(-((pupil_grid.x - phase_bump_pos[0])**2 + \                                           (pupil_grid.y -phase_bump_pos[1])**2) / \                                              (2 * phase_bump_rms**2))    aberration = np.exp(1j * phase_bump)    wf = Wavefront(...)     Manually apply aberration:    wf.electric_field *= aberration<jupyter_code>from hcipy import *

import numpy as np
import matplotlib.pyplot as plt
import os

%matplotlib inline<jupyter_output><empty_output><jupyter_text>To make life simpler later on, we define a function to nicely show two fields side-to-side, with a nice spacing, titles and axes labels.<jupyter_code>def double_plot(a, b, title='', xlabel='', ylabel='', figsize=(10,6),  **kwargs):
    '''A function to nicely show two fields side-to-side.
    '''
    fig, axes = plt.subplots(1, 2, 
                            gridspec_kw={'left': 0.14, 'right': 0.98, 'top': 0.95, 'bottom': 0.07, 'wspace': 0.02},
                            figsize=figsize)
    fig.suptitle(title)

    imshow_field(a, **kwargs, ax=axes[0])
    imshow_field(b, **kwargs, ax=axes[1])

    axes[1].yaxis.set_ticks([])
    axes[0].set_xlabel(xlabel)
    axes[1].set_xlabel(xlabel)
    axes[0].set_ylabel(ylabel)

    return fig
def easing(start, end, n):
    x = np.linspace(0, 1, n)
    y = np.where(x < 0.5, 4 * x**3, 1 - 4 * (1 - x)**3)

    return y * (end - start) + start<jupyter_output><empty_output><jupyter_text>Far-field propagation through focusWe simulate moving through the focal plane by using steps of defocus - a quadratic phase aberration in the pupil - which keeps the image pixel scale the same through focus.(Moving the detector changes the scale, a slight complication we ignore here.  But if you move your lens or detector, remember to change your image plane pixel scale!)First we recreate a pupil and pupil grid to suit, and a perfect wavefront for the two geometries<jupyter_code>pupil_diameter = 1.0 # meter
wavelength = 5e-6 # meter
focal_length = 5.0 # m

# size the pupil exactly to pupil diameter
pupil_grid = make_pupil_grid(256, 1.0 * pupil_diameter)
aperture_circ = evaluate_supersampled(circular_aperture(pupil_diameter), pupil_grid, 8)

aperture_luvoir = evaluate_supersampled(make_luvoir_a_aperture(True), pupil_grid.scaled(1 / pupil_diameter), 8)
aperture_luvoir.grid = pupil_grid


wf_circ = Wavefront(aperture_circ, wavelength)
wf_luvoir = Wavefront(aperture_luvoir, wavelength)

spatial_resolution = focal_length / pupil_diameter * wavelength
focal_grid = make_focal_grid(8, 12, spatial_resolution=spatial_resolution)

fraunhofer = FraunhoferPropagator(pupil_grid, focal_grid, focal_length=focal_length)
double_plot(aperture_circ, aperture_luvoir,
            xlabel='x [mm]', ylabel='y [mm]',
            grid_units=1e-3, cmap='gray')
plt.show()
# Quadratic bowl with max value 1 at pupil edges (more or less with the non-circlar geometry): Peak-to-Valley
# Actual max at square array corners will be 2, but the corners are not illuminated...
pupil_radius = pupil_diameter / 2.0
quadratic_PVunity = (pupil_grid.x/pupil_radius)**2 + (pupil_grid.y/pupil_radius)**2

print(pupil_grid.x.max(), pupil_grid.x.min(), quadratic_PVunity.max())

def create_supergaussian_phase_bump(pos=(0.2, 0.1), rms=0.1, amp=1.0):
    # Create a super-Gaussian bump array - purely numerical 
    phase_bump_pos = pos # center of bump in pupil coords (qn: +/- 0.5 range?)
    phase_bump_rms = pupil_diameter * rms # width of Gaussian
    phase_bump_amp = amp #radians

    phase_bump = phase_bump_amp * np.exp(-((pupil_grid.x - phase_bump_pos[0])**6 + \
                                           (pupil_grid.y - phase_bump_pos[1])**6) / \
                                              (2 * phase_bump_rms**6))

    #print("phase bump max & min: ", phase_bump.max(), phase_bump.min())
    return phase_bump
# Create a phase bump
phase = create_supergaussian_phase_bump(amp=2.0)
 
    
wf_circ = Wavefront(aperture_circ, wavelength)
wf_luvoir = Wavefront(aperture_luvoir, wavelength)

wf_circ_aberrated = wf_circ.copy()
wf_circ_aberrated.electric_field *= np.exp(1j * phase)
    
wf_luvoir_aberrated = wf_luvoir.copy()
wf_luvoir_aberrated.electric_field *= np.exp(1j * phase)

imshow_pupil_phase(wf_circ_aberrated.electric_field,
                           )

plt.show()
n = 16
defocusPV_waves = np.concatenate([easing(-3, -1, n),
                                  easing(-1,  1, n),
                                  easing( 1,  3, n),])

print(defocusPV_waves.max(), defocusPV_waves.min())

#img_circ = fraunhofer(wf_circ)
#img_luvoir = fraunhofer(wf_luvoir)


# Starting the animation object to write to an mp4 file.
anim = FFMpegWriter('throughfocus.mp4', framerate=5)

for defocus in defocusPV_waves[::-1]:
    print(".", end='')
    #print('defocus/waves: ', defocus, ' ', end='')
    phase = 2 * np.pi * defocus * quadratic_PVunity \
          + create_supergaussian_phase_bump(amp=2)
    #print('phase: ', phase.max())
 
    
    wf_circ = Wavefront(aperture_circ, wavelength)
    wf_luvoir = Wavefront(aperture_luvoir, wavelength)

    wf_circ_aberrated = wf_circ.copy()
    wf_circ_aberrated.electric_field *= np.exp(1j * phase)
    
    wf_luvoir_aberrated = wf_luvoir.copy()
    wf_luvoir_aberrated.electric_field *= np.exp(1j * phase)
    
    img_circ = fraunhofer(wf_circ_aberrated)
    img_luvoir = fraunhofer(wf_luvoir_aberrated)

    fig = double_plot(np.power(img_circ.power / img_circ.power.max(), 0.4), 
                np.power(img_luvoir.power / img_luvoir.power.max(), 0.4),
                title='Wavelength: %d um' % (wavelength * 1e6),
                xlabel='x [um]', ylabel='y [um]',
                cmap='inferno', grid_units=1e-6)
    fig.set_figheight(10)
    anim.add_frame()
    plt.close()

anim.close()

anim

# Cleanup created files
os.remove('throughfocus.mp4')<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.11798396334478808, 'fraction_numerical': 0.020454917362133857, 'mean_word_length': 3.31333803810868, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 14, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 10, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '155805', 'license': 'BSD-3-Clause', 'n_tokens_mistral': 2343, 'n_tokens_neox': 2150, 'n_words': 482, 'path': 'hci_thrufocusPhaseBump.ipynb', 'repo_name': 'anand0xff/FourierOpticsJHU2021', 'size': '6114'}