503 lines
19 KiB
Python
503 lines
19 KiB
Python
#!/usr/bin/env python3
|
|
|
|
### Packages import
|
|
import numpy as np
|
|
from copy import deepcopy
|
|
from pandas import read_excel
|
|
import scipy.constants as cons
|
|
from ptychoscopy import pty
|
|
|
|
|
|
|
|
def get_versions():
|
|
"""
|
|
--------------------------------------------------------------
|
|
Show versions of the used packages.
|
|
--------------------------------------------------------------
|
|
Inputs:
|
|
none
|
|
"""
|
|
import sys
|
|
print (sys.version)
|
|
import openpyxl
|
|
print("Openpyxl version ", openpyxl.__version__)
|
|
import numpy as np
|
|
print("Numpy version ", np.__version__)
|
|
import scipy
|
|
print("Scipy version ", scipy.__version__)
|
|
import plotly
|
|
print("Plotly version ", plotly.__version__)
|
|
import pandas
|
|
print("Pandas version ", pandas.__version__)
|
|
import IPython
|
|
print("IPython version ", IPython.__version__)
|
|
import ipywidgets
|
|
print("Ipywidgets version ", ipywidgets.__version__)
|
|
|
|
try:
|
|
import abtem
|
|
print("abTEM version ", abtem.__version__)
|
|
except:
|
|
print("abTEM not available ")
|
|
return
|
|
|
|
def get_omegas():
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads x-axis in multiplications of probe semi-angle for iterative
|
|
CTF curves from sheet called "CTF" ("CTF" row).
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx',sheet_name='CTF')
|
|
excel_lin = list((excel_data[excel_data.CTF.isin(["CTF"])]))
|
|
omegas = excel_lin[1::]
|
|
return omegas
|
|
|
|
def get_ctf(element):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads iterative CTF curve for chosen element from sheet called "CTF"
|
|
("chosen element" row).
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
element ... name of the chosen CTF profile
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx', sheet_name='CTF', header = 0)
|
|
excel_line = np.array(excel_data[excel_data.CTF.isin([element])])
|
|
ctf = excel_line[0]
|
|
ctf = ctf[1::]
|
|
return ctf
|
|
|
|
def get_wavelength(beam):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Computes relativistic electron wavelength.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
beam ... beam energy
|
|
Outputs:
|
|
wavelength ... electron wavelength in m
|
|
"""
|
|
wavelength = cons.h/np.sqrt(2*cons.electron_mass*cons.elementary_charge*beam*1e3*(1+((cons.elementary_charge*beam*1e3)/(2*cons.electron_mass*cons.speed_of_light**2))))
|
|
return wavelength
|
|
|
|
def get_fov(mag):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads field of view at 1x magnification and computes field of view
|
|
at given magnification.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
mag ... image magnification in millions
|
|
Outputs:
|
|
fov ... field of view in nm
|
|
"""
|
|
|
|
FoVat1x = [str(e) for e in list(read_excel(r'ptychoscopy/calibrations.xlsx',sheet_name='Ranges').FoVat1x)]
|
|
FoVat1x = np.array([x for x in FoVat1x if x != 'nan']).astype(float)
|
|
FoVat1x = FoVat1x.item()
|
|
fov = FoVat1x/(mag*1e6)
|
|
return fov
|
|
|
|
def get_angle(aperture):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads probe semi-angle of the chosen aperture.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
aperture ... probe defining aperture name
|
|
Outputs:
|
|
angle ... probe semi-angle in mrad
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx', sheet_name='Probes',header=0)
|
|
excel_line = excel_data[excel_data.Probe.isin(['SemiAngle'])]
|
|
angle = excel_line[aperture]
|
|
angle = np.array(angle).item()
|
|
return angle
|
|
|
|
def get_angle_corr(aperture):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads corrected probe semi-angle of the chosen aperture.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
aperture ... probe defining aperture name
|
|
Outputs:
|
|
angle_corr ... corrected probe semi-angle in mrad
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx', sheet_name='Probes',header=0)
|
|
excel_line = excel_data[excel_data.Probe.isin(['SemiAngleCorr'])]
|
|
angle_corr = excel_line[aperture]
|
|
angle_corr = np.array(angle_corr).item()
|
|
return angle_corr
|
|
|
|
def get_current(probe, aperture):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads probe current for chosen probe size and aperture.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
probe ... chosen probe name
|
|
aperture ... probe defining aperture name
|
|
Outputs:
|
|
current ... probe current in pA
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx', sheet_name='Probes',header=0)
|
|
excel_line = excel_data[excel_data.Probe.isin([probe])]
|
|
current = excel_line[aperture]
|
|
current = np.array(current).item()
|
|
return current
|
|
|
|
def get_pixel_angle(cl, camera, binning):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads and computes probe current for chosen probe size and aperture.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
cl ... chosen nominal camera length
|
|
camera ... chosen camera type
|
|
binning... chosen camera binning
|
|
Outputs:
|
|
pixel_angle ... single pixel cover angle in mrad
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx',sheet_name='Pixel',header=0)
|
|
excel_line = excel_data[excel_data.NominalCL.isin([cl])]
|
|
pixel_angle = excel_line[camera]
|
|
pixel_angle = np.array(pixel_angle).item()
|
|
pixel_angle = pixel_angle*binning
|
|
return pixel_angle
|
|
|
|
def get_cl_detector(cl, detector):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads effective camera length.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
cl ... chosen nominal camera length
|
|
detector ... chosen detector type
|
|
Outputs:
|
|
cl_detector ... efective camera length of detector in cm
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx',sheet_name='Camera_length')
|
|
excel_line = excel_data[excel_data.NominalCL.isin([cl])]
|
|
cl_detector = excel_line[detector]
|
|
cl_detector = cl_detector.item()
|
|
return cl_detector
|
|
|
|
def get_aq_frec(dwell_time):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Compute acquisition frame rate from dwell time.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
dwell_time ... beam position dwell time in us
|
|
Outputs:
|
|
aq_frec ... detection frame rate in kHz
|
|
"""
|
|
aq_frec = 1000/dwell_time
|
|
return aq_frec
|
|
|
|
def get_step_size(fov, matrix):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Compute scanning step size.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
matrix ... number of beam positions in scanning matrix
|
|
Outputs:
|
|
step_size ... detection frame rate in nm
|
|
"""
|
|
step_size = fov/(matrix-1)
|
|
return step_size
|
|
|
|
def get_step_correction():
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Load scanning correction coefficient.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
Outputs:
|
|
step_correction ... scaling factor
|
|
"""
|
|
step_correction = [str(e) for e in list(read_excel(r'ptychoscopy/calibrations.xlsx',sheet_name='Ranges').StepSizeCorr)]
|
|
step_correction = np.array([x for x in step_correction if x != 'nan']).astype(float)
|
|
step_correction = step_correction.item()
|
|
return step_correction
|
|
|
|
def get_beam_diameter(aperture, defocus, angle_corr):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Computes geometrical beam diameter.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
aperture ... probe defining aperture name
|
|
defocus ... introduced beam defocus in nm
|
|
Outputs:
|
|
beam_diameter ... beam diameter in nm
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx', sheet_name='Probes')
|
|
excel_line = excel_data[excel_data.Probe.isin(['Def0Diameter'])]
|
|
beam_0_diameter = np.array([excel_line[aperture]]).astype(float)
|
|
beam_0_diameter = beam_0_diameter.item()
|
|
beam_diameter = 2*defocus*np.tan(angle_corr/1000)+beam_0_diameter
|
|
return beam_diameter
|
|
|
|
def get_0beam_diameter(aperture):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Computes geometrical beam diameter at 0 nm defocus.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
aperture ... probe defining aperture name
|
|
Outputs:
|
|
beam_0_diameter ... beam diameter in nm
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx', sheet_name='Probes')
|
|
excel_line = excel_data[excel_data.Probe.isin(['Def0Diameter'])]
|
|
beam_0_diameter = np.array([excel_line[aperture]]).astype(float)
|
|
beam_0_diameter = beam_0_diameter.item()
|
|
return beam_0_diameter
|
|
|
|
def get_detector(camera, binning):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads detection array size toghether with pixel size and computes
|
|
effective pixel size (inluding binning).
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
camera ... detector name
|
|
binning ... applied diffraction pattern binning
|
|
Outputs:
|
|
num_pixels ... number of pixel in detection array
|
|
size_pixel ... detection pixel size in um
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx', sheet_name='Detector')
|
|
excel_line = excel_data[excel_data.Type.isin(['Array'])]
|
|
num_pixels = np.array([excel_line[camera]]).astype(float)
|
|
num_pixels = num_pixels.item()
|
|
num_pixels = num_pixels/binning
|
|
excel_line = excel_data[excel_data.Type.isin(['RealSize'])]
|
|
size_pixel = excel_line[camera]
|
|
size_pixel = size_pixel.item()
|
|
size_pixel = size_pixel*binning
|
|
return num_pixels, size_pixel
|
|
|
|
def get_pixel_covers(camera, binning):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Computes effective single detection pixel cover angle.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
camera ... detector name
|
|
binning ... applied diffraction pattern binning
|
|
Outputs:
|
|
pixel_covers ... effective pixel cover angle in mrad
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx', sheet_name='Pixel')
|
|
pixel_covers = list(excel_data[camera])
|
|
pixel_covers = [str(e) for e in pixel_covers]
|
|
pixel_covers = [x for x in pixel_covers if x != 'nan']
|
|
pixel_covers = [float(e) for e in pixel_covers]
|
|
pixel_covers = np.array(pixel_covers)
|
|
pixel_covers = pixel_covers*binning
|
|
return pixel_covers
|
|
|
|
def get_pumping_apertures():
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Load differencial pumping aperture caused maximal detection angle
|
|
limitation for all camera lengths.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
Outputs:
|
|
pump_apert ... maximal detected angles in mrad for all camera lengths
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx',sheet_name='Camera_length')
|
|
pump_apert = [str(e) for e in list(excel_data.PAAR)]
|
|
pump_apert = [x for x in pump_apert if x != 'nan']
|
|
pump_apert = [float(e) for e in pump_apert]
|
|
return pump_apert
|
|
|
|
def get_ssb_ctf():
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Computes SSB CTF.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
none
|
|
Outputs:
|
|
omega ... scattering angle from 0 to 2 alpha
|
|
pctf ... ssb ctf
|
|
"""
|
|
omega = np.linspace(1e-6,2,100)
|
|
p = np.arccos(np.minimum(1,omega))
|
|
p[np.isnan(p)] = 0
|
|
p2 = 1-(omega**2)
|
|
p2[p2 <0] = 0
|
|
p3 = omega*np.sqrt(p2)
|
|
p3[np.isnan(p3)] = 0
|
|
pctf = (2/cons.pi)*(np.arccos(omega/2)-p+p3-(omega/2*np.sqrt(1-(omega/2)**2)))
|
|
return omega, pctf
|
|
|
|
def get_cl4ssb(detector_cover_a_all, camera, which):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Computes maximal camera length for SSB.
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
detector_cover_a_all ... detector cover in alfa for all camera lengths
|
|
Outputs:
|
|
ssb_cl ... maximal recommended camera length
|
|
kolik ... covered alfa of minimal detector cover
|
|
"""
|
|
ssb_cl = deepcopy(detector_cover_a_all)
|
|
ssb_cl[ssb_cl<1] = "nan"
|
|
ssb_cl = np.nanmin(ssb_cl)
|
|
kde = np.array(np.where(ssb_cl == detector_cover_a_all)).item()
|
|
kolik = np.array(detector_cover_a_all[kde])
|
|
cl_all = load_cameralengths(camera, which)
|
|
ssb_cl = np.array(cl_all[kde])
|
|
return ssb_cl, kolik
|
|
|
|
def load_elements():
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads names of various phase contrast transfer functions from sheet
|
|
called "CTF" ("CTF" column).
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx', sheet_name='CTF')
|
|
elements = [str(e) for e in list(excel_data.CTF)]
|
|
elements = [x for x in elements if x != 'nan']
|
|
return elements
|
|
|
|
def load_apertures():
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads aperture names from sheet called "Probes" ("Probe" row).
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx', sheet_name='Probes')
|
|
excel_lin = list((excel_data[excel_data.Probe.isin(["Probe"])]))
|
|
apertures = excel_lin[1::]
|
|
return apertures
|
|
|
|
def load_detectors():
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads detector names from sheet called "Detector" ("Type" row).
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx', sheet_name='Detector')
|
|
excel_lin = list((excel_data[excel_data.Type.isin(["Type"])]))
|
|
detectors = excel_lin[1::]
|
|
return detectors
|
|
|
|
def load_probes():
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads probe size names from sheet called "Probes" ("Probe" column).
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
"""
|
|
probes = list(read_excel(r'ptychoscopy/calibrations.xlsx', sheet_name='Probes').Probe)
|
|
probes = probes[3::] # from fifth row
|
|
return probes
|
|
|
|
def load_magnifications():
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads list of possible magnifications in millions from sheet called
|
|
"Ranges" ("Magnification" column).
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx',sheet_name='Ranges')
|
|
magnifications = list(excel_data.Magnification)
|
|
return magnifications
|
|
|
|
def load_energies():
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads list of possible beam energies in keV from sheet called
|
|
"Ranges" ("BeamEnergy" column).
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx',sheet_name='Ranges')
|
|
energies = [str(e) for e in list(excel_data.BeamEnergy)]
|
|
energies = [x for x in energies if x != 'nan']
|
|
energies = [int(float(e)) for e in energies]
|
|
return energies
|
|
|
|
def load_mappings():
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads list of possible scanning matricies from sheet called "Ranges"
|
|
("Mapping" column).
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx',sheet_name='Ranges')
|
|
mappings = [str(e) for e in list(excel_data.Mapping)]
|
|
mappings = [x for x in mappings if x != 'nan']
|
|
mappings = [int(float(e)) for e in mappings]
|
|
return mappings
|
|
|
|
def load_dwelltimes():
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads list of possible dwell times in us from sheet called "Ranges"
|
|
("DwellTime" column).
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
"""
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx',sheet_name='Ranges')
|
|
dwelltimes = [str(e) for e in list(excel_data.DwellTime)]
|
|
dwelltimes = [x for x in dwelltimes if x != 'nan']
|
|
dwelltimes = [int(float(e)) for e in dwelltimes]
|
|
return dwelltimes
|
|
|
|
def load_cameralengths(camera, which):
|
|
"""
|
|
--------------------------------------------------------------------
|
|
Loads list of possible nominal camera lengths in cm from sheet
|
|
called "Pixel" ("NominalCL" column).
|
|
--------------------------------------------------------------------
|
|
Inputs:
|
|
calib ... path to the calibration file
|
|
"""
|
|
match which:
|
|
case "nominal":
|
|
cameralengths = list(read_excel(r'ptychoscopy/calibrations.xlsx',sheet_name='Camera_length').NominalCL)
|
|
case "effective":
|
|
excel_data = read_excel(r'ptychoscopy/calibrations.xlsx',sheet_name='Camera_length')
|
|
cameralengths = list(np.array(excel_data[camera]))
|
|
return cameralengths |