Reanalysis for thesis (incl. plate scale change)

This commit is contained in:
yosata committed 2022-07-14 15:09:31 +02:00
1 parent 1b3a1e0821
commit 8e0575e0e9
103 files changed
+15829 -46

No files matched your search

File diff suppressed because it is too large. Load diff
@@ -0,0 +1,163 @@
import numpy as np
import sys
# sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
# sys.path.insert(0, '/home/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Documents/Published/FourierOptics GitHub release/')
from fourierOptics import *
'''
Author: Joost van den Born, PhD student at University of Groningen
Contact: born@astro.rug.nl
Description: Script to generate the geometric distortions due to WFEs
off the ADC prisms. The distortions are produced by measuring
the offset of the PSF centroid with and without WFE as a
function of field position.
Script made for the SPIE manuscript.
'''
def plot_distortions():
# Coordinates without WFEs
xe = load_variable('./data/GD_obscured_PSF_xcentroid_expected_zern_psd.pkl')
ye = load_variable('./data/GD_obscured_PSF_ycentroid_expected_zern_psd.pkl')
# Coordinates with WFEs
xf = load_variable('./data/GD_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd.pkl')
yf = load_variable('./data/GD_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd.pkl')
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3)
n = xe.shape[0]
X = xe.flatten()
Y = ye.flatten()
dX = xf - xe
dY = yf - ye
dx = dX.flatten()
dy = dY.flatten()
# Magnitude of the distortions
R = np.sqrt(dx**2 + dy**2) * mcd.platescale * 1e6
# Dummy figure, used for the colorbar colors in the quiver plot
im = plt.imshow(np.reshape(R, (n,n)))
plt.close()
fig = plt.figure()
ax = fig.add_subplot()
for i in range(len(xe)):
ax.plot(xe[:,i], ye[:,i], 'k-', alpha=0.2, linewidth=.5)
ax.plot(xe[i,:], ye[i,:], 'k-', alpha=0.2, linewidth=.5)
ax.quiver(X,Y,dx,dy, angles='xy', edgecolor='k', facecolor='None', linewidth=.5, units='dots')
ax.quiver(X,Y,dx,dy,R, alpha=.5, units='dots')
ax.set_aspect('equal', adjustable='box')
ax.set_xlabel('x (mm)')
ax.set_ylabel('y (mm)')
fig.colorbar(im, ax=ax, label='PSF centroid shift ($\\mu$as)')
plt.savefig('./figures/UPDATED_GD_full_field_zern_psd.pdf', bbox_inches='tight', transparent=True)
plt.savefig('./figures/UPDATED_GD_full_field_zern_psd.png', bbox_inches='tight', transparent=True)
plt.tight_layout()
plt.show()
if __name__ == '__main__':
# plt.rc('text', usetex=True)
# plt.rc('font', family='serif')
# Setup of simulation
l = 1.49e-3
Elist, Eplist = [], []
xlist, ylist = [], []
xplist, yplist = [], []
x_expected_list, y_expected_list = [], []
x_centroid_list, y_centroid_list = [], []
# Set field points
hxList, hyList = np.mgrid[-1:1:11j,-1:1:11j]-(1/300)
hxList = hxList.flatten()
hyList = hyList.flatten()
# Loading in the WFEs
wfe_p1 = load_variable('./data/compressed items/ADC_tWFE_p1_zern_20nm_psd_15nm.pkl')
wfe_p2 = load_variable('./data/compressed items/ADC_tWFE_p2_zern_20nm_psd_15nm.pkl')
wfe_p3 = load_variable('./data/compressed items/ADC_tWFE_p3_zern_20nm_psd_15nm.pkl')
wfe_p4 = load_variable('./data/compressed items/ADC_tWFE_p4_zern_20nm_psd_15nm.pkl')
# Propagate through the field positions without any WFEs
for i in range(len(hxList)):
hx = hxList[i]
hy = hyList[i]
print('hx: {} - hy: {}'.format(hx,hy) )
# Initializing MICADO paraxial model
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50, entrance_pupil='obscured')
# Propagate through the MICADO system
E, x, y = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
print_progress=False, hx=hx, hy=hy)
# Find approximation for the centroid and amplitude as a first
# guess for the Obscured Airy pattern fit.
amplitude_guess = np.max(np.abs(E))**2
xbc, ybc, _, _ = mcd.centroid_shift(method='Barycenter')
print('Barycenter guess: ', xbc, ybc)
# Do the Obscured Airy Pattern Fit for the unperturbed PSF
xe, ye, _, _ = mcd.centroid_shift(method='Obscured Airy', initialGuess=(amplitude_guess, xbc, ybc, 0.0, 0.03))
print('Airy result: ', xe, ye)
x_expected_list.append(xe)
y_expected_list.append(ye)
# Load in the WFEs and set them to the corresponding ADC surfaces
print('\nSetting the wavefront errors...')
# null_wfe = np.zeros((3001,3001))
mcd.ELT_ADC.p1.add_wavefront_error(wfe_p1)
mcd.ELT_ADC.p2.add_wavefront_error(wfe_p2)
mcd.ELT_ADC.p3.add_wavefront_error(wfe_p3)
mcd.ELT_ADC.p4.add_wavefront_error(wfe_p4)
# Propagate through the MICADO system
print('Propagating with Wavefront Errors applied...')
Ep, xp, yp = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
print_progress=False, hx=hx, hy=hy)
# Do the Obscured Airy Pattern Fit for the perturbed PSF
xf, yf, _, _ = mcd.c entroid_shift(method='Obscured Airy', initialGuess=(amplitude_guess, xe, ye, 0.0, 0.03))
# Resulting centroid shift due to the WFE
x_centroid_list.append(xf)
y_centroid_list.append(yf)
R = np.sqrt( (xf-xe)**2 + (yf-ye)**2 ) * mcd.platescale * 1e6
print('xf: {}, yf: {}, shift (uas): {}'.format(xf,yf, R))
# Clear the memory by emptying the large arrays
mcd = None
wfe = None
E, x, y = None, None, None
Ep, xp, yp = None, None, None
# Reshaping the arrays
shape = (int(np.sqrt(len(x_expected_list))), int(np.sqrt(len(x_expected_list))))
x_expected = np.asarray(x_expected_list).reshape(shape)
y_expected = np.asarray(y_expected_list).reshape(shape)#.T
# Saving the arrays
save_variable('./data/GD_obscured_PSF_xcentroid_expected_zern_psd.pkl', x_expected)
save_variable('./data/GD_obscured_PSF_ycentroid_expected_zern_psd.pkl', y_expected)
# Reshaping the arrays
shape = (int(np.sqrt(len(x_centroid_list))), int(np.sqrt(len(x_centroid_list))))
x_centroid = np.asarray(x_centroid_list).reshape(shape)
y_centroid = np.asarray(y_centroid_list).reshape(shape)
# Saving the arrays
save_variable('./data/GD_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd.pkl', x_centroid)
save_variable('./data/GD_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd.pkl', y_centroid)
plot_distortions()
@@ -0,0 +1,212 @@
import numpy as np
import sys
# sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
# sys.path.insert(0, '/home/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Documents/Published/FourierOptics GitHub release/')
from fourierOptics import *
from pdb import set_trace
'''
Author: Joost van den Born, PhD student at University of Groningen
Contact: born@astro.rug.nl
Description: Script to generate the geometric distortions due to WFEs
off the ADC prisms. The distortions are produced by measuring
the offset of the PSF centroid with and without WFE as a
function of field position.
Script made for the SPIE manuscript.
'''
def plot_distortions():
# Coordinates without WFEs
xe = load_variable('../data/GD_IFP_obscured_PSF_xcentroid_expected_zern.pkl')
ye = load_variable('../data/GD_IFP_obscured_PSF_ycentroid_expected_zern.pkl')
# Coordinates with WFEs
xf = load_variable('../data/GD_IFP_obscured_PSF_xcentroid_found_with_wfe_airy_zern.pkl')
yf = load_variable('../data/GD_IFP_obscured_PSF_ycentroid_found_with_wfe_airy_zern.pkl')
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3)
n = xe.shape[0]
X = xe.flatten()
Y = ye.flatten()
dX = xf - xe
dY = yf - ye
dx = dX.flatten()
dy = dY.flatten()
# Magnitude of the distortions
R = np.sqrt(dx**2 + dy**2) * mcd.platescale * 1e6
# Dummy figure, used for the colorbar colors in the quiver plot
im = plt.imshow(np.reshape(R, (n,n)))
plt.close()
fig = plt.figure()
ax = fig.add_subplot()
for i in range(len(xe)):
ax.plot(xe[:,i], ye[:,i], 'k-', alpha=0.2, linewidth=.5)
ax.plot(xe[i,:], ye[i,:], 'k-', alpha=0.2, linewidth=.5)
ax.quiver(X,Y,dx,dy, angles='xy', edgecolor='k', facecolor='None', linewidth=.5, units='dots')
ax.quiver(X,Y,dx,dy,R, alpha=.5, units='dots')
ax.set_aspect('equal', adjustable='box')
ax.set_xlabel('x (mm)')
ax.set_ylabel('y (mm)')
fig.colorbar(im, ax=ax, label='PSF centroid shift ($\\mu$as)')
plt.savefig('../figures/UPDATED_GD_focal_plane_zern.pdf', bbox_inches='tight', transparent=True)
plt.savefig('../figures/UPDATED_GD_focal_plane_zern.png', bbox_inches='tight', transparent=True)
plt.tight_layout()
plt.show()
if __name__ == '__main__':
# plt.rc('text', usetex=True)
# plt.rc('font', family='serif')
# Setup of simulation
l = 1.49e-3
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50)
# mcd.plot_ray_trace()
wfe = WavefrontError(mcd.n, mcd.m)
# Get x3 and y3 (the coordinates to apply the ADC WFE to):
# The focal plane area is about 200x200 mm, so we apply the wavefront error to an area
# of 200x200 mm.
xfp, yfp = np.meshgrid(np.linspace(-150, 150, mcd.n), np.linspace(-150, 150, mcd.m))
# _, xfp, yfp = mcd.propagate(l=l,surface=1, zoom=False, show=False,
# print_progress=False)
# Generate a wavefront error for the intermediate focal plane.
print('\nSetting the wavefront errors...')
wfe_fp = WavefrontError(mcd.n,mcd.m)
wfe_rms = 50e-6
#PSD Wavefront error
# surface_map_fp = wfe_fp.generate_height_map(wfe_rms, 2, 1)
# plot_real_valued_results(surface_map_fp*1e6, xfp, yfp, logscale=False, fig_size=(8,6.4), grid=False, show=True,
# colormap='jet', labeltext='Surface height (nm)')
# save_variable('../data/MCD_IFP_wfe_object_PSD_50nm.pkl', wfe_fp)
# wfe_fp = load_variable('../data/MCD_IFP_wfe_object_PSD_50nm.pkl')
# surface_map_fp = wfe_fp.data
# Zernike wavefront error
# We re0se the ADC_surface classes because it can be applicable to any surface, if used properly
ifp_wfe = ADC_surfaces(xfp, yfp, clearAperture=300)
ifp_wfe.generate_ADC_wfe(zernRMS=wfe_rms, psdRMS=0.)
mask = np.sqrt(ifp_wfe.xz**2 + ifp_wfe.yz**2) > 1
# Plot the wfe
# surf_ifp = ifp_wfe.latest_surface.copy()
# surf_ifp[mask]=np.nan
# surface_map_fp = surf_ifp
# wfe_fp.data = surf_ifp
wfe_fp = load_variable('../data/MCD_IFP_wfe_object_zern_50nm.pkl')
surface_map_fp = wfe_fp.data
# save_variable('../data/MCD_IFP_wfe_object_zern_50nm.pkl', wfe_fp)
# figp1, axp1 = plot_real_valued_results(surface_map_fp*1e6, xfp, yfp,
# colormap='jet', labeltext='Surface height (nm)', fig_size=None, show=True)
plt.show()
Elist, Eplist = [], []
xlist, ylist = [], []
xplist, yplist = [], []
x_expected_list, y_expected_list = [], []
x_centroid_list, y_centroid_list = [], []
# Set field points
hxList, hyList = np.mgrid[-1:1:11j,-1:1:11j]-(1/300)
# hxList, hyList = np.mgrid[-.1/11:.1/11:11j,-.1/11:.1/11:11j]-(1/300) # Zoomed in to central area
hxList = hxList.flatten()
hyList = hyList.flatten()
# List of performed simulations
# Defined by PSD
## GD_IFP : -1:1
## GD_IFP_zoom : -1/11 :1/11
## GD_IFP_zoom2 : -.5/11:.5/11
## GD_IFP_zoom3 : -.1/11:.1/11
# Defined by zernikes
## GD_IFP_obscured_PSF_xcentroid_expected_zern : 50 nm rms 19 zernike modes : -1 : 1
## To do; check PSF shape at center field with zern wfe
## To do; check interpolated WFE at any zoomed in field point.
# Propagate through the field positions without any WFEs
for i in range(len(hxList)):
hx = hxList[i]
hy = hyList[i]
print('hx: {} - hy: {}'.format(hx,hy) )
# Initializing MICADO paraxial model
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50, entrance_pupil='obscured')
# Propagate through the MICADO system
E, x, y = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
print_progress=False, hx=hx, hy=hy)
# Find approximation for the centroid and amplitude as a first
# guess for the Obscured Airy pattern fit.
amplitude_guess = np.max(np.abs(E))**2
xbc, ybc, _, _ = mcd.centroid_shift(method='Barycenter')
print('Barycenter guess: ', xbc, ybc)
# Do the Obscured Airy Pattern Fit for the unperturbed PSF
xe, ye, _, _ = mcd.centroid_shift(method='Obscured Airy', initialGuess=(amplitude_guess, xbc, ybc, 0.0, 0.03))
print('Airy result: ', xe, ye)
x_expected_list.append(xe)
y_expected_list.append(ye)
# Load in the WFEs and set them to the corresponding ADC surfaces
print('\nSetting the wavefront errors...')
# null_wfe = np.zeros((3001,3001))
mcd.ELT_FP.add_wavefront_error(surface_map_fp, xfp, yfp, wfe=wfe_fp)
# Propagate through the MICADO system
print('Propagating with Wavefront Errors applied...')
Ep, xp, yp = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
print_progress=False, hx=hx, hy=hy)
# Do the Obscured Airy Pattern Fit for the perturbed PSF
xf, yf, _, _ = mcd.centroid_shift(method='Obscured Airy', initialGuess=(amplitude_guess, xe, ye, 0.0, 0.03))
# Resulting centroid shift due to the WFE
x_centroid_list.append(xf)
y_centroid_list.append(yf)
R = np.sqrt( (xf-xe)**2 + (yf-ye)**2 ) * mcd.platescale * 1e6
print('xf: {}, yf: {}, shift (uas): {}'.format(xf,yf, R))
# Clear the memory by emptying the large arrays
mcd = None
wfe = None
E, x, y = None, None, None
Ep, xp, yp = None, None, None
# Reshaping the arrays
shape = (int(np.sqrt(len(x_expected_list))), int(np.sqrt(len(x_expected_list))))
x_expected = np.asarray(x_expected_list).reshape(shape)
y_expected = np.asarray(y_expected_list).reshape(shape)#.T
# Saving the arrays
save_variable('../data/GD_IFP_obscured_PSF_xcentroid_expected_zern.pkl', x_expected)
save_variable('../data/GD_IFP_obscured_PSF_ycentroid_expected_zern.pkl', y_expected)
# Reshaping the arrays
shape = (int(np.sqrt(len(x_centroid_list))), int(np.sqrt(len(x_centroid_list))))
x_centroid = np.asarray(x_centroid_list).reshape(shape)
y_centroid = np.asarray(y_centroid_list).reshape(shape)
# Saving the arrays
save_variable('../data/GD_IFP_obscured_PSF_xcentroid_found_with_wfe_airy_zern.pkl', x_centroid)
save_variable('../data/GD_IFP_obscured_PSF_ycentroid_found_with_wfe_airy_zern.pkl', y_centroid)
plot_distortions()
@@ -0,0 +1,174 @@
import numpy as np
import sys
# sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Documents/Published/FourierOptics GitHub release/')
from fourierOptics import *
'''
Author: Joost van den Born, PhD student at University of Groningen
Contact: born@astro.rug.nl
Description: Script to generate the geometric distortions due to WFEs
off the ADC prisms. The distortions are produced by measuring
the offset of the PSF centroid with and without WFE as a
function of field position.
Script made for the SPIE manuscript.
'''
# Rotation of ADC angles - [0.125, 0.25, 0.5, 0.75, 1, 2, 5, 10, 30, 45, 60, 90, 180]
def plot_distortions():
# Coordinates without WFEs
xe = load_variable('./data/ADC rotation/GD_obscured_PSF_xcentroid_expected_zern_psd.pkl')
ye = load_variable('./data/ADC rotation/GD_obscured_PSF_ycentroid_expected_zern_psd.pkl')
# Coordinates with WFEs
xf = load_variable('./data/ADC rotation/GD_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd.pkl')
yf = load_variable('./data/ADC rotation/GD_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd.pkl')
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3)
n = xe.shape[0]
X = xe.flatten()
Y = ye.flatten()
dX = xf - xe
dY = yf - ye
dx = dX.flatten()
dy = dY.flatten()
# Magnitude of the distortions
R = np.sqrt(dx**2 + dy**2) * mcd.platescale * 1e6
# Dummy figure, used for the colorbar colors in the quiver plot
im = plt.imshow(np.reshape(R, (n,n)))
plt.close()
fig = plt.figure()
ax = fig.add_subplot()
for i in range(len(xe)):
ax.plot(xe[:,i], ye[:,i], 'k-', alpha=0.2, linewidth=.5)
ax.plot(xe[i,:], ye[i,:], 'k-', alpha=0.2, linewidth=.5)
ax.quiver(X,Y,dx,dy, angles='xy', edgecolor='k', facecolor='None', linewidth=.5, units='dots')
ax.quiver(X,Y,dx,dy,R, alpha=.5, units='dots')
ax.set_aspect('equal', adjustable='box')
ax.set_xlabel('x (mm)')
ax.set_ylabel('y (mm)')
fig.colorbar(im, ax=ax, label='PSF centroid shift ($\\mu$as)')
plt.savefig('./figures/UPDATED2_GD_full_field_zern_psd.pdf', bbox_inches='tight', transparent=True)
plt.savefig('./figures/UPDATED2_GD_full_field_zern_psd.png', bbox_inches='tight', transparent=True)
plt.tight_layout()
plt.show()
if __name__ == '__main__':
# plt.rc('text', usetex=True)
# plt.rc('font', family='serif')
# Loading in the WFEs
wfe_p1 = load_variable('./data/compressed items/ADC_tWFE_p1_zern_20nm_psd_15nm.pkl')
wfe_p2 = load_variable('./data/compressed items/ADC_tWFE_p2_zern_20nm_psd_15nm.pkl')
wfe_p3 = load_variable('./data/compressed items/ADC_tWFE_p3_zern_20nm_psd_15nm.pkl')
wfe_p4 = load_variable('./data/compressed items/ADC_tWFE_p4_zern_20nm_psd_15nm.pkl')
# Rotation of ADC angles - [0.125, 0.25, 0.5, 0.75, 1, 2, 5, 10], 30, 45, 60, 90, 180]
thetaList = [0.001, 0.125, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.5, 3, 3.5, 4, 4.5, 5, 6, 7, 8, 9, 10]
# Propagate through the field positions without any WFEs
for theta in thetaList:
# Setup of simulation
l = 1.49e-3
Elist, Eplist = [], []
xlist, ylist = [], []
xplist, yplist = [], []
x_expected_list, y_expected_list = [], []
x_centroid_list, y_centroid_list = [], []
# Set field points
hxList, hyList = np.mgrid[-1:1:11j,-1:1:11j]-(1/300)
hxList = hxList.flatten()
hyList = hyList.flatten()
for i in range(len(hxList)):
hx = hxList[i]
hy = hyList[i]
print('Rotation: {:.3f} - hx: {} - hy: {}'.format(theta,hx,hy) )
# Initializing MICADO paraxial model
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50, entrance_pupil='obscured')
# Propagate through the MICADO system
mcd.ELT_ADC.set_orientation(theta)
E, x, y = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
print_progress=False, hx=hx, hy=hy)
# Find approximation for the centroid and amplitude as a first
# guess for the Obscured Airy pattern fit.
amplitude_guess = np.max(np.abs(E))**2
xbc, ybc, _, _ = mcd.centroid_shift(method='Barycenter')
print('Barycenter guess: ', xbc, ybc)
# Do the Obscured Airy Pattern Fit for the unperturbed PSF
xe, ye, _, _ = mcd.centroid_shift(method='Obscured Airy', initialGuess=(amplitude_guess, xbc, ybc, 0.0, 0.03))
print('Airy result: ', xe, ye)
x_expected_list.append(xe)
y_expected_list.append(ye)
# Load in the WFEs and set them to the corresponding ADC surfaces
print('\nSetting the wavefront errors...')
# null_wfe = np.zeros((3001,3001))
mcd.ELT_ADC.set_orientation(0)
mcd.ELT_ADC.p1.add_wavefront_error(wfe_p1)
mcd.ELT_ADC.p2.add_wavefront_error(wfe_p2)
mcd.ELT_ADC.p3.add_wavefront_error(wfe_p3)
mcd.ELT_ADC.p4.add_wavefront_error(wfe_p4)
# Propagate through the MICADO system
print('Propagating with Wavefront Errors applied...')
mcd.ELT_ADC.set_orientation(theta)
Ep, xp, yp = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
print_progress=False, hx=hx, hy=hy)
# Do the Obscured Airy Pattern Fit for the perturbed PSF
xf, yf, _, _ = mcd.centroid_shift(method='Obscured Airy', initialGuess=(amplitude_guess, xe, ye, 0.0, 0.03))
# Resulting centroid shift due to the WFE
x_centroid_list.append(xf)
y_centroid_list.append(yf)
R = np.sqrt( (xf-xe)**2 + (yf-ye)**2 ) * mcd.platescale * 1e6
print('xf: {}, yf: {}, shift (uas): {}'.format(xf,yf, R))
# Clear the memory by emptying the large arrays
mcd = None
wfe = None
E, x, y = None, None, None
Ep, xp, yp = None, None, None
# Reshaping the arrays
shape = (int(np.sqrt(len(x_expected_list))), int(np.sqrt(len(x_expected_list))))
x_expected = np.asarray(x_expected_list).reshape(shape)
y_expected = np.asarray(y_expected_list).reshape(shape)#.T
# Saving the arrays
save_variable('./data/ADC rotation/GD_obscured_PSF_xcentroid_expected_zern_psd_rot{}.pkl'.format(theta), x_expected)
save_variable('./data/ADC rotation/GD_obscured_PSF_ycentroid_expected_zern_psd_rot{}.pkl'.format(theta), y_expected)
# Reshaping the arrays
shape = (int(np.sqrt(len(x_centroid_list))), int(np.sqrt(len(x_centroid_list))))
x_centroid = np.asarray(x_centroid_list).reshape(shape)
y_centroid = np.asarray(y_centroid_list).reshape(shape)
# Saving the arrays
save_variable('./data/ADC rotation/GD_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd_rot{}.pkl'.format(theta), x_centroid)
save_variable('./data/ADC rotation/GD_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd_rot{}.pkl'.format(theta), y_centroid)
# plot_distortions()
+471
View File
@@ -0,0 +1,471 @@
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.ticker as plticker
from matplotlib.gridspec import GridSpec
import pandas as pd
import sys
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Documents/Published/FourierOptics GitHub release/')
from fourierOptics import *
from pdb import set_trace
'''
Date: 2022-06-20
Author: Joost van den Born
Description: Plotting the geometric distortions, that were calculated
in an earlier simulation.
Here we also include the detector layout in the plot.
'''
def add_detector_layout(figureObj, lw=0.8, alpha=0.5, show_label=True):
'''
Adds the detector layout to an existing figure+axes object.
The detector outlines are based on the MICADO Hawaii 4RG mosaic
and the dimensions are in mm.
Parameters
----------
figureObj : tuple
Tuple containing the figure and axes objects (fig,ax)
lw : float, optional
Linewidth of the drawn detectors. Default: 0.8
alpha : float, optional
Alpha value to draw the rectangles at
show_label : bool, optional
If True, shows the detector ID number in the rectangle
Returns
-------
TYPE
Updated fig, axes objects
'''
fig, ax = figureObj
# Detector layout
det_hdr = ['id','x_cen', 'y_cen', 'x_size', 'y_size', 'pixel_size', 'angle', 'gain']
det_props = np.array([[1, -63.94, 63.94, 4096, 4096, 0.015, 0.0, 1.0],
[2, 0.00, 63.94, 4096, 4096, 0.015, 270.0, 1.0],
[3, 63.94, 63.94, 4096, 4096, 0.015, 180.0, 1.0],
[6, -63.94, 0.00, 4096, 4096, 0.015, 0.0, 1.0],
[5, 0.00, 0.00, 4096, 4096, 0.015, 180.0, 1.0],
[4, 67.94, 0.00, 4096, 4096, 0.015, 180.0, 1.0],
[7, -63.94, -63.94, 4096, 4096, 0.015, 0.0, 1.0],
[8, 0.00, -63.94, 4096, 4096, 0.015, 90.0, 1.0],
[9, 63.94, -63.94, 4096, 4096, 0.015, 180.0, 1.0]])
detectors = pd.DataFrame(det_props, columns=det_hdr)
detectors["id"] = detectors["id"].astype(int)
detectors["x_size"] = detectors["x_size"].astype(int)
detectors["y_size"] = detectors["y_size"].astype(int)
for ind, det in detectors.iterrows():
x_mm = det['x_cen'] - det['x_size']/2*det['pixel_size']
y_mm = det['y_cen'] - det['y_size']/2*det['pixel_size']
width = det['x_size']*det['pixel_size']
height = det['y_size']*det['pixel_size']
x_cen, y_cen = det['x_cen'], det['y_cen']
rect = patches.Rectangle((x_mm, y_mm), width, height,
linewidth=lw, edgecolor='k', facecolor='none', alpha=alpha, zorder=1)
ax.add_patch(rect)
if show_label:
ax.text(x_cen, y_cen, det['id'])
return fig, ax
def convert_detector_size(x, y, old=True):
old_ps = 100.13151872258219
new_ps = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3).platescale * 1e3
conv_fact = old_ps / new_ps
if old:
x *= conv_fact
y *= conv_fact
elif not old:
x /= conv_fact
y /= conv_fact
return x, y
def plot_distortions(xe, ye, xp, yp, lims=False, add_detectors=True,
save=False, figtitle='geom_distortions',
show=True):
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3)
n = xe.shape[0]
X = xe.flatten()
Y = ye.flatten()
dX = xp - xe
dY = yp - ye
dx = dX.flatten()
dy = dY.flatten()
# Magnitude of the distortions
R = np.sqrt(dx**2 + dy**2) * mcd.platescale * 1e6
print('RMS of the PSF shifts: {:.4f} μas.'.format(np.sqrt(np.mean((R)**2))))
# Dummy figure, used for the colorbar colors in the quiver plot
im = plt.imshow(np.reshape(R, (n,n)))
plt.close()
# Initiate the figure
fig = plt.figure(figsize=(6.4,4.8))
ax = fig.add_subplot(aspect='equal')
# Add the detector layout if so desired.
if add_detectors:
add_detector_layout((fig,ax), lw=.8, alpha=0.5, show_label=False)
# Plot the vector plot
for i in range(len(xe)):
ax.plot(xe[:,i], ye[:,i], 'k-', alpha=0.2, linewidth=.5)
ax.plot(xe[i,:], ye[i,:], 'k-', alpha=0.2, linewidth=.5)
ax.quiver(X,Y,dx,dy, angles='xy', edgecolor='k',
facecolor='None', linewidth=.8, units='dots', zorder=300)
ax.quiver(X,Y,dx,dy,R, alpha=1, units='dots', zorder=300)
ax.set_xlabel('x (mm)', fontsize=16)
ax.set_ylabel('y (mm)', fontsize=16)
ax.tick_params(axis='both', direction='in', labelsize=14, zorder=-1,
top=True, right=True)
cb = fig.colorbar(im, ax=ax)
cb.set_label(label='PSF centroid shift (μas)', size=14)
cb.ax.tick_params(labelsize=14)
if not lims:
ax.set_xlim([-125, 115])
ax.set_ylim([-115, 115])
elif lims:
ax.set_xlim(lims[0])
ax.set_ylim(lims[1])
plt.tight_layout()
if save:
plt.savefig('{}.pdf'.format(figtitle),
bbox_inches='tight',
transparent=False,
facecolor=(1, 1, 0, 0.0))
plt.savefig('{}.png'.format(figtitle),
bbox_inches='tight',
transparent=False,
facecolor=(1, 1, 0, 0.0))
if show:
plt.show()
return fig, ax, R
def get_differential_distortion_vectors(xe, ye, xp, yp, xe_ref, ye_ref, xp_ref, yp_ref):
# Reference distortions:
# Shape of the arrays
n = xe_ref.shape[0]
# Reshaping of the arrays so that they can be used for the quiver plot.
X_ref = xe_ref.flatten()
Y_ref = ye_ref.flatten()
dX_ref = xp_ref - xe_ref
dY_ref = yp_ref - ye_ref
dx_ref = dX_ref.flatten()
dy_ref = dY_ref.flatten()
# Distortions to compare
# Reshaping of the arrays so that they can be used for the quiver plot.
X = xe.flatten()
Y = ye.flatten()
dX = xp - xe
dY = yp - ye
dx = dX.flatten()
dy = dY.flatten()
ddx = dX - dX_ref
ddy = dY - dY_ref
return ddx, ddy
def plot_differential_distortions(xe, ye, xp, yp, xe_ref, ye_ref, xp_ref, yp_ref,
lims=False, add_detectors=True, save=False,
figtitle='diff_geom_distortions', show=True):
# Reference distortions:
# Shape of the arrays
n = xe_ref.shape[0]
# Reshaping of the arrays so that they can be used for the quiver plot.
X_ref = xe_ref.flatten()
Y_ref = ye_ref.flatten()
dX_ref = xp_ref - xe_ref
dY_ref = yp_ref - ye_ref
dx_ref = dX_ref.flatten()
dy_ref = dY_ref.flatten()
# Distortions to compare
# Reshaping of the arrays so that they can be used for the quiver plot.
X = xe.flatten()
Y = ye.flatten()
dX = xp - xe
dY = yp - ye
dx = dX.flatten()
dy = dY.flatten()
ddx = dX - dX_ref
ddy = dY - dY_ref
# Two values are comparatively (extremely large), they are set to 0
# to be able to see the other values.
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3)
R = (np.sqrt(ddx**2 + ddy**2) * mcd.platescale * 1e6) # Magnitude of the shift in micro arcseconds
print('RMS of the PSF shifts compared to the reference position: {:.4f} μas.'.format(np.sqrt(np.mean((R)**2))))
# Dummy figure
im = plt.imshow(np.reshape(R, (n,n)))
plt.close()
# Actual plotting of the figure
fig = plt.figure(figsize=(6.4, 4.8))
ax = fig.add_subplot()
# Add the detector layout if so desired.
if add_detectors:
add_detector_layout((fig,ax), lw=.8, alpha=0.5, show_label=False)
# Plot the vector plot
for i in range(len(xe_ref)):
ax.plot(xe_ref[:,i], ye_ref[:,i], 'k-', alpha=0.2, linewidth=.5)
ax.plot(xe_ref[i,:], ye_ref[i,:], 'k-', alpha=0.2, linewidth=.5)
ax.quiver(X,Y,ddx,ddy, angles='xy', edgecolor='k',
facecolor='None', linewidth=.8, units='dots', zorder=300)
ax.quiver(X,Y,ddx,ddy,R, alpha=1, units='dots', zorder=300)
ax.set_xlabel('x (mm)', fontsize=16)
ax.set_ylabel('y (mm)', fontsize=16)
ax.tick_params(axis='both', direction='in', labelsize=14, zorder=-1,
top=True, right=True)
cb = fig.colorbar(im, ax=ax)
cb.set_label(label='PSF centroid shift (μas)', size=14)
cb.ax.tick_params(labelsize=14)
if not lims:
ax.set_xlim([-125, 115])
ax.set_ylim([-115, 115])
elif lims:
ax.set_xlim(lims[0])
ax.set_ylim(lims[1])
plt.tight_layout()
if save:
plt.savefig('{}.pdf'.format(figtitle),
bbox_inches='tight',
transparent=False,
facecolor=(1, 1, 0, 0.0))
plt.savefig('{}.png'.format(figtitle),
bbox_inches='tight',
transparent=False,
facecolor=(1, 1, 0, 0.0))
if show:
plt.show()
return fig, ax, R
def get_data():
# Coordinates without WFEs
xe = load_variable('../data/GD_obscured_PSF_xcentroid_expected_zern_psd.pkl')
ye = load_variable('../data/GD_obscured_PSF_ycentroid_expected_zern_psd.pkl')
# Coordinates with WFEs
xf = load_variable('../data/GD_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd.pkl')
yf = load_variable('../data/GD_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd.pkl')
return xe, ye, xf, yf
def normalize_relative_angle(theta, degrees=True):
if type(theta) in [list, np.ndarray]:
values = np.array([normalize_relative_angle(i) for i in theta])
return values
circle = 360 if degrees else 2*np.pi
theta_mod = theta % circle
# theta_mod_half_circle = theta % (circle/2)
if theta_mod > (circle / 2):
rel_angle = theta_mod - (circle)
else:
rel_angle = theta_mod
return rel_angle
if __name__ == '__main__':
ps = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3).platescale
print(ps)
plt.rc('font', family='serif')
plt.rc('axes', labelsize='large')
# convert_detector_size()
# Plotting the original distortions
xe_og = load_variable('../data/GD full field (Airy small offset)/GD_PSF_xcentroid_expected.pkl')
ye_og = load_variable('../data/GD full field (Airy small offset)/GD_PSF_ycentroid_expected.pkl')
xp_og = load_variable('../data/GD full field (Airy small offset)/GD_PSF_xcentroid_found_with_wfe_airy.pkl')
yp_og = load_variable('../data/GD full field (Airy small offset)/GD_PSF_ycentroid_found_with_wfe_airy.pkl')
xe_og, ye_og = convert_detector_size(xe_og, ye_og)
xp_og, yp_og = convert_detector_size(xp_og, yp_og)
figtitle = '../figures adapted for thesis/GD_full_field_psd'
plot_distortions(xe_og, ye_og, xp_og, yp_og, show=False, save=False, figtitle=figtitle,
lims=[[-120,130],[-120,120]])
# Plotting the original distortions
xe_og = load_variable('../data/GD_obscured_PSF_xcentroid_expected_zern_psd.pkl')
ye_og = load_variable('../data/GD_obscured_PSF_ycentroid_expected_zern_psd.pkl')
xp_og = load_variable('../data/GD_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd.pkl')
yp_og = load_variable('../data/GD_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd.pkl')
figtitle = '../figures adapted for thesis/GD_full_field_zern_psd'
plot_distortions(xe_og, ye_og, xp_og, yp_og, show=False, save=False, figtitle=figtitle)
# Plotting the distortions when the ADC can rotate.
# First for a very small rotation, this will serve as the reference distortions
# that are calibrated for
xe = load_variable('../data/ADC rotation/GD_obscured_PSF_xcentroid_expected_zern_psd_rot0.001.pkl')
ye = load_variable('../data/ADC rotation/GD_obscured_PSF_ycentroid_expected_zern_psd_rot0.001.pkl')
xp = load_variable('../data/ADC rotation/GD_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd_rot0.001.pkl')
yp = load_variable('../data/ADC rotation/GD_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd_rot0.001.pkl')
figtitle = '../figures adapted for thesis/ADC rotation/GD_full_field_zern_psd_0'
plot_distortions(xe, ye, xp, yp, show=False, save=False, figtitle=figtitle, lims=None)
# And comparing it to the original (i.e. no rotation)
figtitle = '../figures adapted for thesis/ADC rotation/DGD_full_field_zern_psd_0'
plot_differential_distortions(xe, ye, xp, yp, xe_og, ye_og, xp_og, yp_og,
show=False, save=False, figtitle=figtitle, lims=None)
# Next we plot all the simulated rotation values
# rotangles = [0.001, 0.125, 0.25, 0.5, 0.75, 1, 2, 5, 10, 30, 45, 90, 180]
rotangles = [0.001, 0.125, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.5, 3, 3.5, 4, 4.5, 5, 6, 7, 8, 9, 10]
rms_of_distortions, max_of_distortions = [], []
vector_magnitude = np.zeros((121,len(rotangles)))
for i,rx in enumerate(rotangles):
# Full field
xe2 = load_variable('../data/ADC rotation/GD_obscured_PSF_xcentroid_expected_zern_psd_rot{}.pkl'.format(rx))
ye2 = load_variable('../data/ADC rotation/GD_obscured_PSF_ycentroid_expected_zern_psd_rot{}.pkl'.format(rx))
xp2 = load_variable('../data/ADC rotation/GD_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd_rot{}.pkl'.format(rx))
yp2 = load_variable('../data/ADC rotation/GD_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd_rot{}.pkl'.format(rx))
figtitle = '../figures adapted for thesis/ADC rotation/DGD_full_field_zern_psd_{}'.format(rx)
_,_, R = plot_differential_distortions(xe2, ye2, xp2, yp2, xe, ye, xp, yp, show=False, save=False,
figtitle=figtitle, lims=[[-120,120],[-120,120]])
rms_of_distortions.append(np.sqrt(np.mean((R)**2)))
max_of_distortions.append(np.max(R))
Rflat = R.flatten()
for j in range(len(Rflat)):
vector_magnitude[j,i] = Rflat[j]
gs = GridSpec(1, 2, width_ratios=[3,2])
fig = plt.figure(figsize=(6.4*2,4.8))
ax = fig.add_subplot(gs[0,0])
ax2 = fig.add_subplot(gs[0,1], projection='polar')
relangle = normalize_relative_angle(2*np.asarray(rotangles))
for i in range(len(Rflat)):
ax.plot(relangle, vector_magnitude[i], 'b-', linewidth=0.5, alpha=0.1)
ax.plot(relangle, rms_of_distortions, 'b-', label='RMS', zorder=30)
ax.plot(relangle, rms_of_distortions, 'bx', zorder=30)
ax.plot(relangle, max_of_distortions, 'r-', label='Maximum', zorder=30)
ax.plot(relangle, max_of_distortions, 'rx', zorder=30)
ax.axhline(50, color='k', linestyle='-', linewidth=1, label='50 μas', zorder=4)
ax.axhline(10, color='k', linestyle='-.', linewidth=1, label='10 μas', zorder=4)
ax.grid(True, alpha=0.3)
ax.tick_params(axis='both', direction='in', labelsize=14, zorder=-1,
top=True, right=True)
ax.set_xlabel('Relative prism rotation (deg)', fontsize=16)
ax.set_ylabel('Differential distortion (μas)', fontsize=16)
ax.set_xlim([0,20])
ax.set_ylim([-3,100])
# plt.tight_layout()
# save = False
# if save:
# figtitle = '../figures adapted for thesis/rotation_relation_relangles'
# plt.savefig('{}.pdf'.format(figtitle),
# bbox_inches='tight',
# transparent=False,
# facecolor=(1, 1, 0, 0.0))
# plt.savefig('{}.png'.format(figtitle),
# bbox_inches='tight',
# transparent=False,
# facecolor=(1, 1, 0, 0.0))
# Trying to plot the change in the distortion vector as a function of ADC rotation
ax2.grid(True, alpha=0.3)
vxs, vys = [], []
for i,rx in enumerate(rotangles):
xe2 = load_variable('../data/ADC rotation/GD_obscured_PSF_xcentroid_expected_zern_psd_rot{}.pkl'.format(rx))
ye2 = load_variable('../data/ADC rotation/GD_obscured_PSF_ycentroid_expected_zern_psd_rot{}.pkl'.format(rx))
xp2 = load_variable('../data/ADC rotation/GD_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd_rot{}.pkl'.format(rx))
yp2 = load_variable('../data/ADC rotation/GD_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd_rot{}.pkl'.format(rx))
# Find the distortion vector
ddx, ddy = get_differential_distortion_vectors(xe2, ye2, xp2, yp2, xe, ye, xp, yp)
cx = xe2.flatten()
cy = ye2.flatten()
# print(cx[ci], cy[ci])
vx = ddx.flatten() * ps * 1e6
vy = ddy.flatten() * ps * 1e6
vxs.append([vx])
vys.append([vy])
phi, mag = [],[]
for i in range(121):
# set_trace()
# Array slicing: rotation, 0, grid index
vx_evo = np.asarray(vxs)[:,0,i]
vy_evo = np.asarray(vys)[:,0,i]
phi_evo = np.arctan2(vy_evo, vx_evo)
mag_evo = np.sqrt(vx_evo**2 + vy_evo**2)
phi.append(phi_evo[-1])
mag.append(mag_evo[-1])
# Plot the vectors on the central detectors separately
if i in [48, 49, 50, 59, 60, 61, 70, 71, 72]:
if i == 48:
ax.plot(relangle, vector_magnitude[i], 'g-', linewidth=1, alpha=1, zorder=20, label='Central detector')
ax2.plot(phi_evo, mag_evo, 'g-', linewidth=2, zorder=300)
else:
ax.plot(relangle, vector_magnitude[i], 'g-', linewidth=1, alpha=1, zorder=20)
ax2.plot(phi_evo, mag_evo, 'g-', linewidth=2, zorder=300)
else:
ax2.plot(phi_evo, mag_evo, 'b-', linewidth=1, zorder=1)
# Making a legend on the first sub figure in the right order
handles, labels = ax.get_legend_handles_labels()
order = [0,1,4,2,3]
ax.legend([handles[idx] for idx in order],[labels[idx] for idx in order], fontsize=14)
# Slicing the polar plot to the relevant part.
phi = np.asarray(phi)
ax2.set_thetamin(np.degrees(np.min(phi%(2*np.pi)))-10)
ax2.set_thetamax(np.degrees(np.max(phi%(2*np.pi)))+10)
label_position=ax2.get_rlabel_position()
ax2.text(np.radians(label_position-10),ax2.get_rmax()/2.,'Differential\ndistortion (μas)',
rotation=np.degrees(np.min(phi%(2*np.pi)))-10,ha='center',va='center', fontsize=14)
loc = plticker.MultipleLocator(base=np.radians(10)) # this locator puts ticks at regular intervals
ax2.xaxis.set_major_locator(loc)
ticks = [40, '', 60,'', 80, '', 100, '', 120, '', 140, '', 160, '', 180, '', 200, '', 220]
ax2.xaxis.set_ticklabels(ticks)
ax2.tick_params(axis='both', direction='in', labelsize=12, zorder=-1,
top=True, right=False, left=True)
plt.tight_layout()
save = True
if save:
figtitle = '../figures adapted for thesis/rotation_relation_with_polar_plot'
plt.savefig('{}.pdf'.format(figtitle),
bbox_inches='tight',
transparent=False,
facecolor=(1, 1, 0, 0.0))
plt.savefig('{}.png'.format(figtitle),
bbox_inches='tight',
transparent=False,
facecolor=(1, 1, 0, 0.0))
plt.show()
@@ -0,0 +1,280 @@
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.ticker as plticker
from matplotlib.gridspec import GridSpec
import pandas as pd
import sys
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Documents/Published/FourierOptics GitHub release/')
from fourierOptics import *
from pdb import set_trace
from matplotlib.colors import Normalize, LogNorm
'''
Date: 2022-06-20
Author: Joost van den Born
Description: Plotting the geometric distortions, that were calculated
in an earlier simulation.
Here we also include the detector layout in the plot.
'''
def add_detector_layout(figureObj, lw=0.8, alpha=0.5, show_label=True):
'''
Adds the detector layout to an existing figure+axes object.
The detector outlines are based on the MICADO Hawaii 4RG mosaic
and the dimensions are in mm.
Parameters
----------
figureObj : tuple
Tuple containing the figure and axes objects (fig,ax)
lw : float, optional
Linewidth of the drawn detectors. Default: 0.8
alpha : float, optional
Alpha value to draw the rectangles at
show_label : bool, optional
If True, shows the detector ID number in the rectangle
Returns
-------
TYPE
Updated fig, axes objects
'''
fig, ax = figureObj
# Detector layout
det_hdr = ['id','x_cen', 'y_cen', 'x_size', 'y_size', 'pixel_size', 'angle', 'gain']
det_props = np.array([[1, -63.94, 63.94, 4096, 4096, 0.015, 0.0, 1.0],
[2, 0.00, 63.94, 4096, 4096, 0.015, 270.0, 1.0],
[3, 63.94, 63.94, 4096, 4096, 0.015, 180.0, 1.0],
[6, -63.94, 0.00, 4096, 4096, 0.015, 0.0, 1.0],
[5, 0.00, 0.00, 4096, 4096, 0.015, 180.0, 1.0],
[4, 67.94, 0.00, 4096, 4096, 0.015, 180.0, 1.0],
[7, -63.94, -63.94, 4096, 4096, 0.015, 0.0, 1.0],
[8, 0.00, -63.94, 4096, 4096, 0.015, 90.0, 1.0],
[9, 63.94, -63.94, 4096, 4096, 0.015, 180.0, 1.0]])
detectors = pd.DataFrame(det_props, columns=det_hdr)
detectors["id"] = detectors["id"].astype(int)
detectors["x_size"] = detectors["x_size"].astype(int)
detectors["y_size"] = detectors["y_size"].astype(int)
for ind, det in detectors.iterrows():
x_mm = det['x_cen'] - det['x_size']/2*det['pixel_size']
y_mm = det['y_cen'] - det['y_size']/2*det['pixel_size']
width = det['x_size']*det['pixel_size']
height = det['y_size']*det['pixel_size']
x_cen, y_cen = det['x_cen'], det['y_cen']
rect = patches.Rectangle((x_mm, y_mm), width, height,
linewidth=lw, edgecolor='k', facecolor='none', alpha=alpha, zorder=1)
ax.add_patch(rect)
if show_label:
ax.text(x_cen, y_cen, det['id'])
return fig, ax
def convert_detector_size(x, y, old=True):
old_ps = 100.13151872258219
new_ps = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3).platescale * 1e3
conv_fact = old_ps / new_ps
if old:
x *= conv_fact
y *= conv_fact
elif not old:
x /= conv_fact
y /= conv_fact
return x, y
def plot_distortions(xe, ye, xp, yp, lims=False, add_detectors=True,
save=False, figtitle='geom_distortions',
show=True, cmap='magma'):
vmin, vmax = 0.1, 100
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3)
n = xe.shape[0]
X = xe.flatten()
Y = ye.flatten()
dX = xp - xe
dY = yp - ye
dx = dX.flatten()
dy = dY.flatten()
# Magnitude of the distortions
R = np.sqrt(dx**2 + dy**2) * mcd.platescale * 1e6
print('RMS of the PSF shifts: {:.4f} μas.'.format(np.sqrt(np.mean((R)**2))))
# Dummy figure, used for the colorbar colors in the quiver plot
# im = plt.imshow(np.reshape(R, (n,n)))
im = plt.imshow(np.reshape(R[:121], (11,11)))
im = plt.scatter(X, Y, s=R, c=np.log10(R), cmap=cmap, vmin=np.log10(vmin), vmax=np.log10(vmax))
# im = plt.scatter(X, Y, s=R, c=R, cmap='jet')
plt.close()
# Initiate the figure
# fig = plt.figure(figsize=(9.6,4.8))
# ax = fig.add_subplot(121, aspect='equal')
# ax2 = fig.add_subplot(122, aspect='equal')
fig, axes = plt.subplots(ncols=2,
nrows=1,
gridspec_kw={'width_ratios': [1,1]},
figsize=(9.6,4.8))
ax, ax2 = axes
ax.set_aspect('equal')
ax2.set_aspect('equal')
# Add the detector layout if so desired.
if add_detectors:
add_detector_layout((fig,ax), lw=.8, alpha=1, show_label=False)
# Plot the vector plot
xe = np.asarray(xe[:121]).reshape((11,11))
ye = np.asarray(ye[:121]).reshape((11,11))
# for i in range(len(xe)):
# ax.plot(xe[:,i], ye[:,i], 'k-', alpha=0.2, linewidth=.5)
# ax.plot(xe[i,:], ye[i,:], 'k-', alpha=0.2, linewidth=.5)
# ax.quiver(X,Y,dx,dy,R, alpha=1, units='dots', zorder=300)
for k in range(4):
print()
ind_end = (k+1) * 121
ind_start = k * 121
dpix = np.diff(Y)[ind_start:ind_end][1]
print(k, ind_start, ind_end, dpix)
xplot = np.asarray(X[ind_start:ind_end]).reshape((11,11))
yplot = np.asarray(Y[ind_start:ind_end]).reshape((11,11))
yplot, xplot = np.mgrid[yplot.min()+dpix/2:yplot.max()-dpix/2:12j,
xplot.min()+dpix/2:xplot.max()-dpix/2:12j]
Rtemp = np.asarray(R[ind_start:ind_end]).reshape((11,11))
ax.pcolor(-1*yplot.T, -1*xplot.T, Rtemp.T, cmap=cmap, norm=LogNorm(vmin=vmin, vmax=vmax))
# ax2.pcolor(-1*xplot.T, -1*yplot.T, Rtemp.T, cmap=cmap, norm=LogNorm(vmin=1, vmax=100))
shiftx = X[ind_start:ind_end][61]#np.abs(dpix)/2
shifty = Y[ind_start:ind_end][60]
print(Y[ind_start:ind_end])
print('shiftx:', shiftx)
print('shifty:', shifty)
# ax2.pcolor(k*shifty-1*yplot.T, k*shiftx-1*xplot.T, Rtemp.T*10, cmap=cmap, norm=LogNorm(vmin=1, vmax=100))
if k == 1: ax2.pcolor(shifty-1*yplot.T, shiftx-1*xplot.T, Rtemp.T, cmap=cmap, norm=LogNorm(vmin=vmin, vmax=vmax))
elif k == 2: ax2.pcolor(2*shifty-1*yplot.T, 2*shiftx-1*xplot.T, Rtemp.T, cmap=cmap, norm=LogNorm(vmin=vmin, vmax=vmax))
elif k == 3: ax2.pcolor(2*shifty-1*yplot.T, 2*shiftx-1*xplot.T, Rtemp.T, cmap=cmap, norm=LogNorm(vmin=vmin, vmax=vmax))
if k == 0:
ax.quiver(X[ind_start:ind_end],Y[ind_start:ind_end],
dx[ind_start:ind_end],dy[ind_start:ind_end],
angles='xy', edgecolor='k', facecolor='k',
linewidth=.8, zorder=300, alpha=1, scale=1.4e-5,
units='dots')
elif k in [2,3]:
ax2.quiver(X[ind_start:ind_end],Y[ind_start:ind_end],
dx[ind_start:ind_end],dy[ind_start:ind_end],
angles='xy', edgecolor='k', facecolor='k',
linewidth=.8, zorder=300, alpha=1, scale=0.2e-5,
units='dots')
# ax.pcolor(xplot * (1 - dpix/105), yplot * (1 - dpix/105), Rtemp, cmap='jet', norm=LogNorm(vmin=1, vmax=100))
ax.set_xlabel('x (mm)', fontsize=16)
ax.set_ylabel('y (mm)', fontsize=16)
ax.tick_params(axis='both', direction='in', labelsize=14, zorder=-1,
top=True, right=True)
ax2.set_xlabel('x (mm)', fontsize=16)
ax2.set_ylabel('y (mm)', fontsize=16)
ax2.tick_params(axis='both', direction='in', labelsize=14, zorder=-1,
top=True, right=True)
cb = fig.colorbar(im, ax=axes, fraction=0.025, pad=0.04)
cb.set_label(label='PSF centroid shift (μas)', size=14)
cb.ax.tick_params(labelsize=14)
lbls = 10**np.asarray(cb.ax.get_yticks())
print(lbls)
newlbls = ['{:.0f}'.format(x) for x in 10**np.asarray(cb.ax.get_yticks())]
newlbls[1] = '{:.1f}'.format(lbls[1])
newlbls[0] = '{:.1f}'.format(lbls[0])
cb.ax.set_yticklabels(newlbls)
print(cb.ax.get_yticks())
if not lims:
ax.set_xlim([-125, 115])
ax.set_ylim([-115, 115])
elif lims:
ax.set_xlim(lims[0])
ax.set_ylim(lims[1])
ax2.set_xlim([-2.01,2.75])
ax2.set_ylim([-2.01,2.75])
ax.indicate_inset_zoom(ax2, edgecolor="black")
fig.subplots_adjust(top=1.0,
bottom=0.0,
left=0.1,
right=0.8,
hspace=0.135,
wspace=0.3)
# plt.tight_layout()
if save:
plt.savefig('{}.pdf'.format(figtitle),
bbox_inches='tight',
transparent=False,
facecolor=(1, 1, 0, 0.0))
plt.savefig('{}.png'.format(figtitle),
bbox_inches='tight',
transparent=False,
facecolor=(1, 1, 0, 0.0))
if show:
plt.show()
return fig, ax, R
if __name__ == '__main__':
ps = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3).platescale
print(ps)
plt.rc('font', family='serif')
plt.rc('axes', labelsize='large')
# convert_detector_size()
# Plotting the original distortions
data_dir = '../data/GD Focal Plane WFEs/'
xe_og = load_variable(data_dir + 'GD_IFP_obscured_PSF_xcentroid_expected_zern_psd.pkl')
ye_og = load_variable(data_dir + 'GD_IFP_obscured_PSF_ycentroid_expected_zern_psd.pkl')
xp_og = load_variable(data_dir + 'GD_IFP_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd.pkl')
yp_og = load_variable(data_dir + 'GD_IFP_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd.pkl')
# Zoom 1:
xe_og1 = load_variable(data_dir + 'GD_IFP_zoom_obscured_PSF_xcentroid_expected_zern_psd.pkl')
ye_og1 = load_variable(data_dir + 'GD_IFP_zoom_obscured_PSF_ycentroid_expected_zern_psd.pkl')
xp_og1 = load_variable(data_dir + 'GD_IFP_zoom_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd.pkl')
yp_og1 = load_variable(data_dir + 'GD_IFP_zoom_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd.pkl')
# Zoom 2
xe_og2 = load_variable(data_dir + 'GD_IFP_zoom2_obscured_PSF_xcentroid_expected_zern_psd.pkl')
ye_og2 = load_variable(data_dir + 'GD_IFP_zoom2_obscured_PSF_ycentroid_expected_zern_psd.pkl')
xp_og2 = load_variable(data_dir + 'GD_IFP_zoom2_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd.pkl')
yp_og2 = load_variable(data_dir + 'GD_IFP_zoom2_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd.pkl')
# Zoom 3
xe_og3 = load_variable(data_dir + 'GD_IFP_zoom3_obscured_PSF_xcentroid_expected_zern_psd.pkl')
ye_og3 = load_variable(data_dir + 'GD_IFP_zoom3_obscured_PSF_ycentroid_expected_zern_psd.pkl')
xp_og3 = load_variable(data_dir + 'GD_IFP_zoom3_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd.pkl')
yp_og3 = load_variable(data_dir + 'GD_IFP_zoom3_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd.pkl')
xe = np.append(xe_og, [xe_og1, xe_og2, xe_og3])
ye = np.append(ye_og, [ye_og1, ye_og2, ye_og3])
xp = np.append(xp_og, [xp_og1, xp_og2, xp_og3])
yp = np.append(yp_og, [yp_og1, yp_og2, yp_og3])
# xe = np.append(xe_og2, xe_og3)
# ye = np.append(ye_og2, ye_og3)
# xp = np.append(xp_og2, xp_og3)
# yp = np.append(yp_og2, yp_og3)
figtitle = '../figures adapted for thesis/Focal Plane/GD_IFP_zern'
plot_distortions(xe, ye, xp, yp, show=True, save=True, figtitle=figtitle,
lims=[[-120,120],[-120,120]])
@@ -0,0 +1,332 @@
import numpy as np
import matplotlib.pyplot as plt
import matplotlib.patches as patches
import matplotlib.ticker as plticker
from matplotlib.gridspec import GridSpec
import pandas as pd
import sys
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Documents/Published/FourierOptics GitHub release/')
from fourierOptics import *
from pdb import set_trace
from matplotlib.colors import Normalize, LogNorm
'''
Date: 2022-06-20
Author: Joost van den Born
Description: Plotting the geometric distortions, that were calculated
in an earlier simulation.
Here we also include the detector layout in the plot.
'''
def add_detector_layout(figureObj, lw=0.8, alpha=0.5, show_label=True):
'''
Adds the detector layout to an existing figure+axes object.
The detector outlines are based on the MICADO Hawaii 4RG mosaic
and the dimensions are in mm.
Parameters
----------
figureObj : tuple
Tuple containing the figure and axes objects (fig,ax)
lw : float, optional
Linewidth of the drawn detectors. Default: 0.8
alpha : float, optional
Alpha value to draw the rectangles at
show_label : bool, optional
If True, shows the detector ID number in the rectangle
Returns
-------
TYPE
Updated fig, axes objects
'''
fig, ax = figureObj
# Detector layout
det_hdr = ['id','x_cen', 'y_cen', 'x_size', 'y_size', 'pixel_size', 'angle', 'gain']
det_props = np.array([[1, -63.94, 63.94, 4096, 4096, 0.015, 0.0, 1.0],
[2, 0.00, 63.94, 4096, 4096, 0.015, 270.0, 1.0],
[3, 63.94, 63.94, 4096, 4096, 0.015, 180.0, 1.0],
[6, -63.94, 0.00, 4096, 4096, 0.015, 0.0, 1.0],
[5, 0.00, 0.00, 4096, 4096, 0.015, 180.0, 1.0],
[4, 67.94, 0.00, 4096, 4096, 0.015, 180.0, 1.0],
[7, -63.94, -63.94, 4096, 4096, 0.015, 0.0, 1.0],
[8, 0.00, -63.94, 4096, 4096, 0.015, 90.0, 1.0],
[9, 63.94, -63.94, 4096, 4096, 0.015, 180.0, 1.0]])
detectors = pd.DataFrame(det_props, columns=det_hdr)
detectors["id"] = detectors["id"].astype(int)
detectors["x_size"] = detectors["x_size"].astype(int)
detectors["y_size"] = detectors["y_size"].astype(int)
for ind, det in detectors.iterrows():
x_mm = det['x_cen'] - det['x_size']/2*det['pixel_size']
y_mm = det['y_cen'] - det['y_size']/2*det['pixel_size']
width = det['x_size']*det['pixel_size']
height = det['y_size']*det['pixel_size']
x_cen, y_cen = det['x_cen'], det['y_cen']
rect = patches.Rectangle((x_mm, y_mm), width, height,
linewidth=lw, edgecolor='k', facecolor='none', alpha=alpha, zorder=1)
ax.add_patch(rect)
if show_label:
ax.text(x_cen, y_cen, det['id'])
return fig, ax
def convert_detector_size(x, y, old=True):
old_ps = 100.13151872258219
new_ps = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3).platescale * 1e3
conv_fact = old_ps / new_ps
if old:
x *= conv_fact
y *= conv_fact
elif not old:
x /= conv_fact
y /= conv_fact
return x, y
def plot_distortions(xe, ye, xp, yp, lims=False, add_detectors=True,
save=False, figtitle='geom_distortions',
show=True):
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3)
n = xe.shape[0]
X = xe.flatten()
Y = ye.flatten()
dX = xp - xe
dY = yp - ye
dx = dX.flatten()
dy = dY.flatten()
# Magnitude of the distortions
R = np.sqrt(dx**2 + dy**2) * mcd.platescale * 1e6
print('RMS of the PSF shifts: {:.4f} μas.'.format(np.sqrt(np.mean((R)**2))))
# Dummy figure, used for the colorbar colors in the quiver plot
im = plt.imshow(np.reshape(R, (n,n)))
plt.close()
# Initiate the figure
fig = plt.figure(figsize=(6.4,4.8))
ax = fig.add_subplot(aspect='equal')
# Add the detector layout if so desired.
if add_detectors:
add_detector_layout((fig,ax), lw=.8, alpha=0.5, show_label=False)
# Plot the vector plot
for i in range(len(xe)):
ax.plot(xe[:,i], ye[:,i], 'k-', alpha=0.2, linewidth=.5)
ax.plot(xe[i,:], ye[i,:], 'k-', alpha=0.2, linewidth=.5)
ax.quiver(X,Y,dx,dy, angles='xy', edgecolor='k',
facecolor='None', linewidth=.8, units='dots', zorder=300)
ax.quiver(X,Y,dx,dy,R, alpha=1, units='dots', zorder=300)
ax.set_xlabel('x (mm)', fontsize=16)
ax.set_ylabel('y (mm)', fontsize=16)
ax.tick_params(axis='both', direction='in', labelsize=14, zorder=-1,
top=True, right=True)
cb = fig.colorbar(im, ax=ax)
cb.set_label(label='PSF centroid shift (μas)', size=14)
cb.ax.tick_params(labelsize=14)
if not lims:
ax.set_xlim([-125, 115])
ax.set_ylim([-115, 115])
elif lims:
ax.set_xlim(lims[0])
ax.set_ylim(lims[1])
plt.tight_layout()
if save:
plt.savefig('{}.pdf'.format(figtitle),
bbox_inches='tight',
transparent=False,
facecolor=(1, 1, 0, 0.0))
plt.savefig('{}.png'.format(figtitle),
bbox_inches='tight',
transparent=False,
facecolor=(1, 1, 0, 0.0))
if show:
plt.show()
return fig, ax, R
def plot_distortions2(xe, ye, xp, yp, lims=False, add_detectors=True,
save=False, figtitle='geom_distortions',
show=True, cmap='magma'):
vmin, vmax = 0.1, 100
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3)
n = xe.shape[0]
X = xe.flatten()
Y = ye.flatten()
dX = xp - xe
dY = yp - ye
dx = dX.flatten()
dy = dY.flatten()
# Magnitude of the distortions
R = np.sqrt(dx**2 + dy**2) * mcd.platescale * 1e6
print('RMS of the PSF shifts: {:.4f} μas.'.format(np.sqrt(np.mean((R)**2))))
# Dummy figure, used for the colorbar colors in the quiver plot
# im = plt.imshow(np.reshape(R, (n,n)))
im = plt.imshow(np.reshape(R[:121], (11,11)))
im = plt.scatter(X, Y, s=R, c=np.log10(R), cmap=cmap, vmin=np.log10(vmin), vmax=np.log10(vmax))
# im = plt.scatter(X, Y, s=R, c=R, cmap='jet')
plt.close()
# Initiate the figure
# fig = plt.figure(figsize=(9.6,4.8))
# ax = fig.add_subplot(121, aspect='equal')
# ax2 = fig.add_subplot(122, aspect='equal')
fig, axes = plt.subplots(ncols=2,
nrows=1,
gridspec_kw={'width_ratios': [1,1]},
figsize=(9.6,4.8))
ax, ax2 = axes
ax.set_aspect('equal')
ax2.set_aspect('equal')
# Add the detector layout if so desired.
if add_detectors:
add_detector_layout((fig,ax), lw=.8, alpha=1, show_label=False)
# Plot the vector plot
xe = np.asarray(xe[:121]).reshape((11,11))
ye = np.asarray(ye[:121]).reshape((11,11))
# for i in range(len(xe)):
# ax.plot(xe[:,i], ye[:,i], 'k-', alpha=0.2, linewidth=.5)
# ax.plot(xe[i,:], ye[i,:], 'k-', alpha=0.2, linewidth=.5)
# ax.quiver(X,Y,dx,dy,R, alpha=1, units='dots', zorder=300)
for k in range(1):
print()
ind_end = (k+1) * 121
ind_start = k * 121
dpix = np.diff(Y)[ind_start:ind_end][1]
print(k, ind_start, ind_end, dpix)
xplot = np.asarray(X[ind_start:ind_end]).reshape((11,11))
yplot = np.asarray(Y[ind_start:ind_end]).reshape((11,11))
yplot, xplot = np.mgrid[yplot.min()+dpix/2:yplot.max()-dpix/2:12j,
xplot.min()+dpix/2:xplot.max()-dpix/2:12j]
Rtemp = np.asarray(R[ind_start:ind_end]).reshape((11,11))
ax.pcolor(-1*yplot.T, -1*xplot.T, Rtemp.T, cmap=cmap, norm=LogNorm(vmin=vmin, vmax=vmax))
# ax2.pcolor(-1*xplot.T, -1*yplot.T, Rtemp.T, cmap=cmap, norm=LogNorm(vmin=1, vmax=100))
shiftx = X[ind_start:ind_end][61]#np.abs(dpix)/2
shifty = Y[ind_start:ind_end][60]
print(Y[ind_start:ind_end])
print('shiftx:', shiftx)
print('shifty:', shifty)
# ax2.pcolor(k*shifty-1*yplot.T, k*shiftx-1*xplot.T, Rtemp.T*10, cmap=cmap, norm=LogNorm(vmin=1, vmax=100))
if k == 1: ax2.pcolor(shifty-1*yplot.T, shiftx-1*xplot.T, Rtemp.T, cmap=cmap, norm=LogNorm(vmin=vmin, vmax=vmax))
elif k == 2: ax2.pcolor(2*shifty-1*yplot.T, 2*shiftx-1*xplot.T, Rtemp.T, cmap=cmap, norm=LogNorm(vmin=vmin, vmax=vmax))
elif k == 3: ax2.pcolor(2*shifty-1*yplot.T, 2*shiftx-1*xplot.T, Rtemp.T, cmap=cmap, norm=LogNorm(vmin=vmin, vmax=vmax))
if k == 0:
ax.quiver(X[ind_start:ind_end],Y[ind_start:ind_end],
dx[ind_start:ind_end],dy[ind_start:ind_end],
angles='xy', edgecolor='k', facecolor='k',
linewidth=.8, zorder=300, alpha=1, scale=1.4e-5,
units='dots')
elif k in [2,3]:
ax2.quiver(X[ind_start:ind_end],Y[ind_start:ind_end],
dx[ind_start:ind_end],dy[ind_start:ind_end],
angles='xy', edgecolor='k', facecolor='k',
linewidth=.8, zorder=300, alpha=1, scale=0.2e-5,
units='dots')
# ax.pcolor(xplot * (1 - dpix/105), yplot * (1 - dpix/105), Rtemp, cmap='jet', norm=LogNorm(vmin=1, vmax=100))
ax.set_xlabel('x (mm)', fontsize=16)
ax.set_ylabel('y (mm)', fontsize=16)
ax.tick_params(axis='both', direction='in', labelsize=14, zorder=-1,
top=True, right=True)
ax2.set_xlabel('x (mm)', fontsize=16)
ax2.set_ylabel('y (mm)', fontsize=16)
ax2.tick_params(axis='both', direction='in', labelsize=14, zorder=-1,
top=True, right=True)
cb = fig.colorbar(im, ax=axes, fraction=0.025, pad=0.04)
cb.set_label(label='PSF centroid shift (μas)', size=14)
cb.ax.tick_params(labelsize=14)
lbls = 10**np.asarray(cb.ax.get_yticks())
print(lbls)
newlbls = ['{:.0f}'.format(x) for x in 10**np.asarray(cb.ax.get_yticks())]
newlbls[1] = '{:.1f}'.format(lbls[1])
newlbls[0] = '{:.1f}'.format(lbls[0])
cb.ax.set_yticklabels(newlbls)
print(cb.ax.get_yticks())
if not lims:
ax.set_xlim([-125, 115])
ax.set_ylim([-115, 115])
elif lims:
ax.set_xlim(lims[0])
ax.set_ylim(lims[1])
ax2.set_xlim([-2.01,2.75])
ax2.set_ylim([-2.01,2.75])
ax.indicate_inset_zoom(ax2, edgecolor="black")
fig.subplots_adjust(top=1.0,
bottom=0.0,
left=0.1,
right=0.8,
hspace=0.135,
wspace=0.3)
# plt.tight_layout()
if save:
plt.savefig('{}.pdf'.format(figtitle),
bbox_inches='tight',
transparent=False,
facecolor=(1, 1, 0, 0.0))
plt.savefig('{}.png'.format(figtitle),
bbox_inches='tight',
transparent=False,
facecolor=(1, 1, 0, 0.0))
if show:
plt.show()
return fig, ax, R
if __name__ == '__main__':
ps = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3).platescale
print(ps)
plt.rc('font', family='serif')
plt.rc('axes', labelsize='large')
# convert_detector_size()
# Plotting the original distortions
data_dir = '../data/GD Focal Plane WFEs/'
xe_og = load_variable(data_dir + 'GD_IFP_obscured_PSF_xcentroid_expected_zern.pkl')
ye_og = load_variable(data_dir + 'GD_IFP_obscured_PSF_ycentroid_expected_zern.pkl')
xp_og = load_variable(data_dir + 'GD_IFP_obscured_PSF_xcentroid_found_with_wfe_airy_zern.pkl')
yp_og = load_variable(data_dir + 'GD_IFP_obscured_PSF_ycentroid_found_with_wfe_airy_zern.pkl')
# # Zoom 1:
# xe_og1 = load_variable(data_dir + 'GD_IFP_zoom_obscured_PSF_xcentroid_expected_zern.pkl')
# ye_og1 = load_variable(data_dir + 'GD_IFP_zoom_obscured_PSF_ycentroid_expected_zern.pkl')
# xp_og1 = load_variable(data_dir + 'GD_IFP_zoom_obscured_PSF_xcentroid_found_with_wfe_airy_zern.pkl')
# yp_og1 = load_variable(data_dir + 'GD_IFP_zoom_obscured_PSF_ycentroid_found_with_wfe_airy_zern.pkl')
xe = xe_og#np.append(xe_og, xe_og1)
ye = ye_og#np.append(ye_og, ye_og1)
xp = xp_og#np.append(xp_og, xp_og1)
yp = yp_og#np.append(yp_og, yp_og1)
# xe = np.append(xe_og2, xe_og3)
# ye = np.append(ye_og2, ye_og3)
# xp = np.append(xp_og2, xp_og3)
# yp = np.append(yp_og2, yp_og3)
figtitle = '../figures adapted for thesis/Focal Plane/GD_IFP_zern'
plot_distortions(xe, ye, xp, yp, show=True, save=False, figtitle=figtitle,
lims=[[-120,120],[-120,120]])
Binary file not shown.

After

Width:  |  Height:  |  Size: 24 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 55 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 56 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 57 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 60 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 66 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 58 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 54 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 126 KiB

Binary file not shown.

After

Width:  |  Height:  |  Size: 224 KiB

+2 -1
View File
@@ -1,6 +1,7 @@
import numpy as np
import sys
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
# sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Documents/Published/FourierOptics GitHub release/')
from fourierOptics import *
from pdb import set_trace
+8 -7
View File
@@ -1,7 +1,8 @@
import numpy as np
import sys
# sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
sys.path.insert(0, '/home/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
# sys.path.insert(0, '/home/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Documents/Published/FourierOptics GitHub release/')
from fourierOptics import *
'''
@@ -51,8 +52,8 @@ def plot_distortions():
ax.set_xlabel('x (mm)')
ax.set_ylabel('y (mm)')
fig.colorbar(im, ax=ax, label='PSF centroid shift ($\\mu$as)')
plt.savefig('./figures/GD_full_field_zern_psd.pdf', bbox_inches='tight', transparent=True)
plt.savefig('./figures/GD_full_field_zern_psd.png', bbox_inches='tight', transparent=True)
plt.savefig('./figures/UPDATED_GD_full_field_zern_psd.pdf', bbox_inches='tight', transparent=True)
plt.savefig('./figures/UPDATED_GD_full_field_zern_psd.png', bbox_inches='tight', transparent=True)
plt.tight_layout()
plt.show()
@@ -75,10 +76,10 @@ if __name__ == '__main__':
hyList = hyList.flatten()
# Loading in the WFEs
wfe_p1 = load_variable('./data/ADC_tWFE_p1_zern_20nm_psd_15nm.pkl')
wfe_p2 = load_variable('./data/ADC_tWFE_p2_zern_20nm_psd_15nm.pkl')
wfe_p3 = load_variable('./data/ADC_tWFE_p3_zern_20nm_psd_15nm.pkl')
wfe_p4 = load_variable('./data/ADC_tWFE_p4_zern_20nm_psd_15nm.pkl')
wfe_p1 = load_variable('./data/compressed items/ADC_tWFE_p1_zern_20nm_psd_15nm.pkl')
wfe_p2 = load_variable('./data/compressed items/ADC_tWFE_p2_zern_20nm_psd_15nm.pkl')
wfe_p3 = load_variable('./data/compressed items/ADC_tWFE_p3_zern_20nm_psd_15nm.pkl')
wfe_p4 = load_variable('./data/compressed items/ADC_tWFE_p4_zern_20nm_psd_15nm.pkl')
# Propagate through the field positions without any WFEs
for i in range(len(hxList)):
@@ -0,0 +1,174 @@
import numpy as np
import sys
# sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Analyses/Python/Analytical/Fourier Optics')
sys.path.insert(0, '/Users/joost/Dropbox/Werk/PhD/Documents/Published/FourierOptics GitHub release/')
from fourierOptics import *
'''
Author: Joost van den Born, PhD student at University of Groningen
Contact: born@astro.rug.nl
Description: Script to generate the geometric distortions due to WFEs
off the ADC prisms. The distortions are produced by measuring
the offset of the PSF centroid with and without WFE as a
function of field position.
Script made for the SPIE manuscript.
'''
# Rotation of ADC angles - [0.125, 0.25, 0.5, 0.75, 1, 2, 5, 10, 30, 45, 60, 90, 180]
def plot_distortions():
# Coordinates without WFEs
xe = load_variable('./data/ADC rotation/GD_obscured_PSF_xcentroid_expected_zern_psd.pkl')
ye = load_variable('./data/ADC rotation/GD_obscured_PSF_ycentroid_expected_zern_psd.pkl')
# Coordinates with WFEs
xf = load_variable('./data/ADC rotation/GD_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd.pkl')
yf = load_variable('./data/ADC rotation/GD_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd.pkl')
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50, l=1.49e-3)
n = xe.shape[0]
X = xe.flatten()
Y = ye.flatten()
dX = xf - xe
dY = yf - ye
dx = dX.flatten()
dy = dY.flatten()
# Magnitude of the distortions
R = np.sqrt(dx**2 + dy**2) * mcd.platescale * 1e6
# Dummy figure, used for the colorbar colors in the quiver plot
im = plt.imshow(np.reshape(R, (n,n)))
plt.close()
fig = plt.figure()
ax = fig.add_subplot()
for i in range(len(xe)):
ax.plot(xe[:,i], ye[:,i], 'k-', alpha=0.2, linewidth=.5)
ax.plot(xe[i,:], ye[i,:], 'k-', alpha=0.2, linewidth=.5)
ax.quiver(X,Y,dx,dy, angles='xy', edgecolor='k', facecolor='None', linewidth=.5, units='dots')
ax.quiver(X,Y,dx,dy,R, alpha=.5, units='dots')
ax.set_aspect('equal', adjustable='box')
ax.set_xlabel('x (mm)')
ax.set_ylabel('y (mm)')
fig.colorbar(im, ax=ax, label='PSF centroid shift ($\\mu$as)')
plt.savefig('./figures/UPDATED2_GD_full_field_zern_psd.pdf', bbox_inches='tight', transparent=True)
plt.savefig('./figures/UPDATED2_GD_full_field_zern_psd.png', bbox_inches='tight', transparent=True)
plt.tight_layout()
plt.show()
if __name__ == '__main__':
# plt.rc('text', usetex=True)
# plt.rc('font', family='serif')
# Loading in the WFEs
wfe_p1 = load_variable('./data/compressed items/ADC_tWFE_p1_zern_20nm_psd_15nm.pkl')
wfe_p2 = load_variable('./data/compressed items/ADC_tWFE_p2_zern_20nm_psd_15nm.pkl')
wfe_p3 = load_variable('./data/compressed items/ADC_tWFE_p3_zern_20nm_psd_15nm.pkl')
wfe_p4 = load_variable('./data/compressed items/ADC_tWFE_p4_zern_20nm_psd_15nm.pkl')
# Rotation of ADC angles - [0.125, 0.25, 0.5, 0.75, 1, 2, 5, 10], 30, 45, 60, 90, 180]
thetaList = [0.001, 0.125, 0.25, 0.5, 0.75, 1, 1.25, 1.5, 1.75, 2, 2.5, 3, 3.5, 4, 4.5, 5, 6, 7, 8, 9, 10]
# Propagate through the field positions without any WFEs
for theta in thetaList:
# Setup of simulation
l = 1.49e-3
Elist, Eplist = [], []
xlist, ylist = [], []
xplist, yplist = [], []
x_expected_list, y_expected_list = [], []
x_centroid_list, y_centroid_list = [], []
# Set field points
hxList, hyList = np.mgrid[-1:1:11j,-1:1:11j]-(1/300)
hxList = hxList.flatten()
hyList = hyList.flatten()
for i in range(len(hxList)):
hx = hxList[i]
hy = hyList[i]
print('Rotation: {:.3f} - hx: {} - hy: {}'.format(theta,hx,hy) )
# Initializing MICADO paraxial model
mcd = ParaxialMICADO(n=3001, m=3001, dpix=50, entrance_pupil='obscured')
# Propagate through the MICADO system
mcd.ELT_ADC.set_orientation(theta)
E, x, y = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
print_progress=False, hx=hx, hy=hy)
# Find approximation for the centroid and amplitude as a first
# guess for the Obscured Airy pattern fit.
amplitude_guess = np.max(np.abs(E))**2
xbc, ybc, _, _ = mcd.centroid_shift(method='Barycenter')
print('Barycenter guess: ', xbc, ybc)
# Do the Obscured Airy Pattern Fit for the unperturbed PSF
xe, ye, _, _ = mcd.centroid_shift(method='Obscured Airy', initialGuess=(amplitude_guess, xbc, ybc, 0.0, 0.03))
print('Airy result: ', xe, ye)
x_expected_list.append(xe)
y_expected_list.append(ye)
# Load in the WFEs and set them to the corresponding ADC surfaces
print('\nSetting the wavefront errors...')
# null_wfe = np.zeros((3001,3001))
mcd.ELT_ADC.set_orientation(0)
mcd.ELT_ADC.p1.add_wavefront_error(wfe_p1)
mcd.ELT_ADC.p2.add_wavefront_error(wfe_p2)
mcd.ELT_ADC.p3.add_wavefront_error(wfe_p3)
mcd.ELT_ADC.p4.add_wavefront_error(wfe_p4)
# Propagate through the MICADO system
print('Propagating with Wavefront Errors applied...')
mcd.ELT_ADC.set_orientation(theta)
Ep, xp, yp = mcd.propagate(l=l,surface=-1, zoom=False, show=False,
print_progress=False, hx=hx, hy=hy)
# Do the Obscured Airy Pattern Fit for the perturbed PSF
xf, yf, _, _ = mcd.centroid_shift(method='Obscured Airy', initialGuess=(amplitude_guess, xe, ye, 0.0, 0.03))
# Resulting centroid shift due to the WFE
x_centroid_list.append(xf)
y_centroid_list.append(yf)
R = np.sqrt( (xf-xe)**2 + (yf-ye)**2 ) * mcd.platescale * 1e6
print('xf: {}, yf: {}, shift (uas): {}'.format(xf,yf, R))
# Clear the memory by emptying the large arrays
mcd = None
wfe = None
E, x, y = None, None, None
Ep, xp, yp = None, None, None
# Reshaping the arrays
shape = (int(np.sqrt(len(x_expected_list))), int(np.sqrt(len(x_expected_list))))
x_expected = np.asarray(x_expected_list).reshape(shape)
y_expected = np.asarray(y_expected_list).reshape(shape)#.T
# Saving the arrays
save_variable('./data/ADC rotation/GD_obscured_PSF_xcentroid_expected_zern_psd_rot{}.pkl'.format(theta), x_expected)
save_variable('./data/ADC rotation/GD_obscured_PSF_ycentroid_expected_zern_psd_rot{}.pkl'.format(theta), y_expected)
# Reshaping the arrays
shape = (int(np.sqrt(len(x_centroid_list))), int(np.sqrt(len(x_centroid_list))))
x_centroid = np.asarray(x_centroid_list).reshape(shape)
y_centroid = np.asarray(y_centroid_list).reshape(shape)
# Saving the arrays
save_variable('./data/ADC rotation/GD_obscured_PSF_xcentroid_found_with_wfe_airy_zern_psd_rot{}.pkl'.format(theta), x_centroid)
save_variable('./data/ADC rotation/GD_obscured_PSF_ycentroid_found_with_wfe_airy_zern_psd_rot{}.pkl'.format(theta), y_centroid)
# plot_distortions()