808 lines
50 KiB
Plaintext
808 lines
50 KiB
Plaintext
{
|
||
"cells": [
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 41,
|
||
"id": "7425242d-3c91-4c1e-a424-08625a38ee7a",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"### Initial packages import ###################################################\n",
|
||
"import numpy as np\n",
|
||
"import scipy.constants as cons\n",
|
||
"import plotly.graph_objects as go\n",
|
||
"from copy import deepcopy\n",
|
||
"from pandas import read_excel\n",
|
||
"from IPython.display import display\n",
|
||
"from plotly.subplots import make_subplots\n",
|
||
"from ipywidgets import interactive_output, HBox, VBox, Layout, Label, Valid, ToggleButtons, RadioButtons, Dropdown, IntSlider, Checkbox\n",
|
||
"\n",
|
||
"# print(\"Numpy version \", np.__version__)\n",
|
||
"# print(\"Pandas version \", pd.__version__)\n",
|
||
"# print(\"Ipywidgets version \", widgets.__version__)\n",
|
||
"# print(\"Plotly version \", plotly.__version__)\n",
|
||
"\n",
|
||
"### Function definitions ###################################################\n",
|
||
"\n",
|
||
"calib = r'calibrations.xlsx' # Path to the calibration file\n",
|
||
"\n",
|
||
"class interaction: \n",
|
||
" \"\"\"Loads calibration settings and ranges from .xlsx file.\n",
|
||
" These are than used for widgets creation.\"\"\"\n",
|
||
" \n",
|
||
"\n",
|
||
" def __init__(self):\n",
|
||
" self.calib = calib\n",
|
||
"\n",
|
||
" def apertures(self):\n",
|
||
" excel_data = read_excel(self.calib,sheet_name='Probes')\n",
|
||
" excel_lin = list((excel_data[excel_data.Probe.isin([\"Probe\"])]))\n",
|
||
" apertures = excel_lin[1::]\n",
|
||
" return apertures\n",
|
||
" \n",
|
||
" def detectors(self):\n",
|
||
" excel_data = read_excel(self.calib,sheet_name='Detector')\n",
|
||
" excel_lin = list((excel_data[excel_data.Type.isin([\"Type\"])]))\n",
|
||
" detectors = excel_lin[1::]\n",
|
||
" return detectors\n",
|
||
" \n",
|
||
" def probes(self):\n",
|
||
" probes = list(read_excel(self.calib,sheet_name='Probes').Probe)\n",
|
||
" probes = probes[3::]\n",
|
||
" return probes\n",
|
||
" \n",
|
||
" def magnifications(self):\n",
|
||
" excel_data = read_excel(self.calib,sheet_name='Ranges')\n",
|
||
" magnifications = list(excel_data.Magnification)\n",
|
||
" return magnifications\n",
|
||
" \n",
|
||
" def energies(self): \n",
|
||
" excel_data = read_excel(self.calib,sheet_name='Ranges')\n",
|
||
" energies = [str(e) for e in list(excel_data.BeamEnergy)]\n",
|
||
" energies = [x for x in energies if x != 'nan']\n",
|
||
" energies = [int(float(e)) for e in energies]\n",
|
||
" return energies\n",
|
||
" \n",
|
||
" def mappings(self): \n",
|
||
" excel_data = read_excel(self.calib,sheet_name='Ranges')\n",
|
||
" mappings = [str(e) for e in list(excel_data.Mapping)]\n",
|
||
" mappings = [x for x in mappings if x != 'nan']\n",
|
||
" mappings = [int(float(e)) for e in mappings]\n",
|
||
" return mappings\n",
|
||
" \n",
|
||
" def cameralengths(self): \n",
|
||
" cameralengths = list(read_excel(self.calib,sheet_name='Pixel').NominalCL)\n",
|
||
" return cameralengths\n",
|
||
" \n",
|
||
" def cameralengths_eff(self): \n",
|
||
" cameralengths_eff = list(read_excel(self.calib,sheet_name='Pixel').DetectorCL)\n",
|
||
" return cameralengths_eff\n",
|
||
"\n",
|
||
" def dwelltimes(self): \n",
|
||
" excel_data = read_excel(self.calib,sheet_name='Ranges')\n",
|
||
" dwelltimes = [str(e) for e in list(excel_data.DwellTime)]\n",
|
||
" dwelltimes = [x for x in dwelltimes if x != 'nan']\n",
|
||
" dwelltimes = [int(float(e)) for e in dwelltimes] \n",
|
||
" return dwelltimes \n",
|
||
" \n",
|
||
"opt = interaction()\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"class ptychoScopy:\n",
|
||
" \"\"\"Computes various characteristics describing used setting.\"\"\"\n",
|
||
" \n",
|
||
" def __init__(self):\n",
|
||
" self.calib = calib\n",
|
||
" \n",
|
||
" \n",
|
||
" \n",
|
||
" def get_wavelength(self, beam):\n",
|
||
" self.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))))\n",
|
||
" return self.wavelength\n",
|
||
" \n",
|
||
" def get_fov(self, mag):\n",
|
||
" self.fov = 214620000/(mag*1e6)\n",
|
||
" return self.fov\n",
|
||
" \n",
|
||
" def get_angle(self, aperture):\n",
|
||
" excel_data = read_excel(calib, sheet_name='Probes',header=0)\n",
|
||
" excel_line = excel_data[excel_data.Probe.isin(['SemiAngle'])]\n",
|
||
" angle = excel_line[aperture]\n",
|
||
" self.angle = np.array(angle).item()\n",
|
||
" return self.angle\n",
|
||
" \n",
|
||
" def get_angle_corr(self, aperture):\n",
|
||
" excel_data = read_excel(calib, sheet_name='Probes',header=0)\n",
|
||
" excel_line = excel_data[excel_data.Probe.isin(['SemiAngleCorr'])]\n",
|
||
" angle_corr = excel_line[aperture]\n",
|
||
" self.angle_corr = np.array(angle_corr).item()\n",
|
||
" return self.angle_corr\n",
|
||
" \n",
|
||
" def get_current(self, probe,aperture):\n",
|
||
" excel_data = read_excel(calib, sheet_name='Probes',header=0)\n",
|
||
" excel_line = excel_data[excel_data.Probe.isin([probe])]\n",
|
||
" current = excel_line[aperture]\n",
|
||
" self.current = np.array(current).item()\n",
|
||
" return self.current\n",
|
||
" \n",
|
||
" def get_currents_over_probes(self, probe):\n",
|
||
" excel_data = read_excel(calib, sheet_name='Probes',header=0)\n",
|
||
" currents_probes = np.array(excel_data[excel_data.Probe.isin([probe])])\n",
|
||
" currents_probes = currents_probes[0]\n",
|
||
" currents_probes = currents_probes[1::]\n",
|
||
" return currents_probes\n",
|
||
"\n",
|
||
" def get_currents_over_apertures(self, aperture):\n",
|
||
" excel_data = read_excel(calib, sheet_name='Probes',header=0)\n",
|
||
" currents_apertures = np.array(list(excel_data[aperture]))\n",
|
||
" return currents_apertures\n",
|
||
"\n",
|
||
" def get_pixel_angle(self, cl, camera, binning):\n",
|
||
" excel_data = read_excel(calib,sheet_name='Pixel',header=0)\n",
|
||
" excel_line = excel_data[excel_data.NominalCL.isin([cl])]\n",
|
||
" pixel_angle = excel_line[camera]\n",
|
||
" pixel_angle = np.array(pixel_angle).item()\n",
|
||
" self.pixel_angle = pixel_angle*binning\n",
|
||
" return self.pixel_angle\n",
|
||
" \n",
|
||
" def get_cl_detector(self,cl):\n",
|
||
" excel_data = read_excel(calib,sheet_name='Pixel')\n",
|
||
" excel_line = excel_data[excel_data.NominalCL.isin([cl])]\n",
|
||
" self.cl_detector = excel_line['DetectorCL']\n",
|
||
" self.cl_detector = self.cl_detector.item()\n",
|
||
" return self.cl_detector\n",
|
||
" \n",
|
||
" def get_aq_frec(self, dwell_time):\n",
|
||
" self.aq_frec = 1000/dwell_time\n",
|
||
" return self.aq_frec \n",
|
||
" \n",
|
||
" def get_step_size(self, matrix):\n",
|
||
" self.step_size = self.fov/(matrix-1)\n",
|
||
" return self.step_size \n",
|
||
" \n",
|
||
" def get_step_correction(self): \n",
|
||
" step_correction = [str(e) for e in list(read_excel(calib,sheet_name='Ranges').StepSizeCorr)]\n",
|
||
" step_correction = np.array([x for x in step_correction if x != 'nan']).astype(float)\n",
|
||
" self.step_correction = step_correction.item()\n",
|
||
" return self.step_correction\n",
|
||
" \n",
|
||
" def get_beam_diameter(self, aperture, defocus):\n",
|
||
" excel_data = read_excel(calib, sheet_name='Probes')\n",
|
||
" excel_line = excel_data[excel_data.Probe.isin(['Def0Diameter'])]\n",
|
||
" beam_0_diameter = np.array([excel_line[aperture]]).astype(float)\n",
|
||
" beam_0_diameter = beam_0_diameter.item()\n",
|
||
" self.beam_diameter = defocus*2*np.tan(self.angle_corr/1000)+beam_0_diameter\n",
|
||
" return self.beam_diameter\n",
|
||
" \n",
|
||
" def get_0beam_diameter(self, aperture):\n",
|
||
" excel_data = read_excel(calib, sheet_name='Probes')\n",
|
||
" excel_line = excel_data[excel_data.Probe.isin(['Def0Diameter'])]\n",
|
||
" beam_0_diameter = np.array([excel_line[aperture]]).astype(float)\n",
|
||
" self.beam_0_diameter = beam_0_diameter.item()\n",
|
||
" return self.beam_0_diameter\n",
|
||
" \n",
|
||
" def get_detector(self, camera, binning):\n",
|
||
" excel_data = read_excel(calib, sheet_name='Detector')\n",
|
||
" excel_line = excel_data[excel_data.Type.isin(['Array'])]\n",
|
||
" num_pixels = np.array([excel_line[camera]]).astype(float)\n",
|
||
" num_pixels = num_pixels.item()\n",
|
||
" self.num_pixels = num_pixels/binning\n",
|
||
" excel_line = excel_data[excel_data.Type.isin(['RealSize'])]\n",
|
||
" size_pixel = excel_line[camera]\n",
|
||
" size_pixel = size_pixel.item()\n",
|
||
" self.size_pixel = size_pixel*binning\n",
|
||
" return self.num_pixels, self.size_pixel \n",
|
||
" \n",
|
||
" def get_det_resolution(self, camera):\n",
|
||
" excel_data = read_excel(calib, sheet_name='Detector')\n",
|
||
" excel_line = excel_data[excel_data.Type.isin(['Array'])]\n",
|
||
" num_pixels = np.array([excel_line[camera]]).astype(float)\n",
|
||
" self.num_pixels = num_pixels.item()\n",
|
||
" return self.num_pixels\n",
|
||
" \n",
|
||
" def get_det_orig_pixel_size(self, camera):\n",
|
||
" excel_data = read_excel(calib, sheet_name='Detector')\n",
|
||
" excel_line = excel_data[excel_data.Type.isin(['RealSize'])]\n",
|
||
" orig_size_pixel = excel_line[camera]\n",
|
||
" self.orig_size_pixel = orig_size_pixel.item()\n",
|
||
" return self.orig_size_pixel\n",
|
||
" \n",
|
||
" def get_pixel_covers(self,camera, binning): \n",
|
||
" excel_data = read_excel(calib, sheet_name='Pixel')\n",
|
||
" pixel_covers = list(excel_data[camera])\n",
|
||
" pixel_covers = [str(e) for e in pixel_covers]\n",
|
||
" pixel_covers = [x for x in pixel_covers if x != 'nan']\n",
|
||
" pixel_covers = [float(e) for e in pixel_covers] \n",
|
||
" pixel_covers = np.array(pixel_covers)\n",
|
||
" self.pixel_covers = pixel_covers * binning\n",
|
||
" return self.pixel_covers\n",
|
||
"\n",
|
||
" def get_pumping_apertures(self): \n",
|
||
" excel_data = read_excel(calib,sheet_name='Pixel')\n",
|
||
" pump_apert = [str(e) for e in list(excel_data.PAAR)]\n",
|
||
" pump_apert = [x for x in pump_apert if x != 'nan']\n",
|
||
" self.pump_apert = [float(e) for e in pump_apert]\n",
|
||
" return self.pump_apert \n",
|
||
" \n",
|
||
" def get_ssb_ctf(self):\n",
|
||
" ### Contrast transfer function ###\n",
|
||
" omega = np.linspace(1e-6,2,100)\n",
|
||
" p3 = np.arccos(np.minimum(1,omega))\n",
|
||
" p3[np.isnan(p3)] = 0\n",
|
||
" p5 = 1-(omega**2)\n",
|
||
" p5[p5 <0] = 0\n",
|
||
" p4 = omega*np.sqrt(p5)\n",
|
||
" p4[np.isnan(p4)] = 0\n",
|
||
" pctf = (2/cons.pi)*(np.arccos(omega/2)-p3+p4-(omega/2*np.sqrt(1-(omega/2)**2)))\n",
|
||
" return pctf\n",
|
||
" \n",
|
||
" \n",
|
||
" def cl4ssb(self, detector_cover_a_all):\n",
|
||
" ssb_cl = deepcopy(detector_cover_a_all)\n",
|
||
" ssb_cl[ssb_cl<1] = \"nan\"\n",
|
||
" ssb_cl = np.nanmin(ssb_cl)\n",
|
||
" kde = np.array(np.where(ssb_cl == detector_cover_a_all)).item()\n",
|
||
" kolik = np.array(detector_cover_a_all[kde]) \n",
|
||
" cl_all = opt.cameralengths()\n",
|
||
" ssb_cl = np.array(cl_all[kde]) # Recommended cl\n",
|
||
" return ssb_cl, kolik\n",
|
||
" \n",
|
||
"\n",
|
||
"pty = ptychoScopy() \n",
|
||
" \n",
|
||
"class interaction:\n",
|
||
" \"\"\"Live interaction with computing of various parameters.\"\"\"\n",
|
||
" \n",
|
||
" def __init__(self):\n",
|
||
" self.calib = calib\n",
|
||
" \n",
|
||
" \n",
|
||
" def show_wavelength(self,caller):\n",
|
||
" beam_res.value = f'Wavelength (pm) {str(\"{:.2f}\".format(pty.get_wavelength(caller.new)*1e12))}'\n",
|
||
" return beam_res.value\n",
|
||
" \n",
|
||
" def show_detector(self,caller):\n",
|
||
" camera_res.value = f'Detector full pixel array {\"{:.0f}\".format(pty.get_det_resolution(caller.new))}'\n",
|
||
" return camera_res.value\n",
|
||
" \n",
|
||
" def show_pixel_size(self,caller):\n",
|
||
" pixel_size_res.value = f'Native pixel size (μm) {\"{:.0f}\".format(pty.get_det_orig_pixel_size(caller.new))}' \n",
|
||
" return pixel_size_res.value\n",
|
||
" \n",
|
||
" def show_probe_angle(self,caller):\n",
|
||
" aperture_res.value = f'Probe semi angle (mrad) {\"{:.2f}\".format(pty.get_angle(caller.new))}' \n",
|
||
" return aperture_res.value\n",
|
||
" \n",
|
||
" def show_corrprobe_angle(self,caller):\n",
|
||
" aperture_res2.value = f'Corrected semi angle (mrad) {\"{:.2f}\".format(pty.get_angle_corr(caller.new))}'\n",
|
||
" return aperture_res2.value\n",
|
||
" \n",
|
||
" def show_fov(self,caller):\n",
|
||
" fov_res.value = f'Field of view (nm) {\"{:.2f}\".format(pty.get_fov(caller.new))}'\n",
|
||
" return fov_res.value\n",
|
||
" \n",
|
||
" def show_frame_rate(self,caller):\n",
|
||
" dwell_time_res.value = f'Frame rate (kHz) {\"{:.2f}\".format(pty.get_aq_frec(caller.new))}' \n",
|
||
" return dwell_time_res.value\n",
|
||
" \n",
|
||
" def show_cd_det(self,caller):\n",
|
||
" cl_det_res.value = f'Detector CL (cm) {\"{:.1f}\".format(pty.get_cl_detector(caller.new))}' \n",
|
||
" return cl_det_res.value\n",
|
||
" \n",
|
||
" \n",
|
||
"inte = interaction() \n"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 68,
|
||
"id": "8055b802-cf83-4250-aea9-54e3e6b73db0",
|
||
"metadata": {},
|
||
"outputs": [],
|
||
"source": [
|
||
"### CONTROLS ##########################################\n",
|
||
"align = dict(layout=Layout(width='385px') , style = {'description_width': '80px','button_width': \"35px\"}, button_style='primary',disabled=False,)\n",
|
||
"align3 = dict(layout=Layout(width='230px') , style = {'description_width': '80px','button_width': \"35px\"}, button_style='primary', disabled=False,)\n",
|
||
"to_right = dict(layout=Layout(display=\"flex\", justify_content=\"flex-end\", width=\"95%\", ))\n",
|
||
"to_right2 = dict(layout=Layout(display=\"flex\", justify_content=\"flex-end\", width=\"35%\", ))\n",
|
||
"\n",
|
||
"### Main controls ###\n",
|
||
"beam = Dropdown(options=opt.energies(),value=200,description='Energy (keV)', **align3)\n",
|
||
"aperture = ToggleButtons(options=opt.apertures(), value='30um', description='Aperture', **align, tooltips=['', ''])\n",
|
||
"probe = ToggleButtons(options=opt.probes(), value='8C', description='Probe', **align, tooltips=['', ''])\n",
|
||
"defocus = IntSlider(description='Defocus (nm)', value=0, min=0, max=1000, step=1, continuous_update=False, **align )\n",
|
||
"defocus.style.handle_color = 'blue'\n",
|
||
"mag = ToggleButtons(options=opt.magnifications(),value=3,description='Mag. (Mx)', **align) \n",
|
||
"matrix = ToggleButtons(options=opt.mappings(), value=2048, description='Matrix', **align, tooltips=['', ''])\n",
|
||
"cl = ToggleButtons(options=opt.cameralengths(), value=12, description='Nominal (cm)', **align, tooltips=['', ''])\n",
|
||
"camera = Dropdown(options=opt.detectors(), description='Detector', **align3, tooltips=['', ''])\n",
|
||
"restriction = ToggleButtons(options=[('NO',False), ('YES',True)], description='Use PAAR',**align3, tooltips=['', ''])\n",
|
||
"binning = ToggleButtons(options=[('NO',1), ('2×2',2), ('4×4',4),('6×6',6),('8×8',8)], description='Binning', **align, tooltips=['Full detector resolution', 'Binning 2x2 - detector resolution /2, pixel size *2', 'Binning 4x4'])\n",
|
||
"dwell_time = ToggleButtons(options=opt.dwelltimes(), value=10, description='Dwell time (μs)', **align, tooltips=['', ''])\n",
|
||
"\n",
|
||
"### Small controls ###\n",
|
||
"align2 = dict(layout=Layout(width='200px') , style = {'description_width': '100px','button_width': '100px'}, disabled=False,)\n",
|
||
"method = ToggleButtons(options=[('Direct methods','direct'), ('Iterative methods','iterative')], description='', **align2, button_style='', tooltips=['SSB', 'PIE, MLc, DM'])\n",
|
||
"ctf_xaxis = RadioButtons(options=['mrad', 'A'], description='CTF-SSB x-axis:', **align2) \n",
|
||
"scans = RadioButtons(options=[4,6,8,10],description='Beam positions:',continuous_update=False, **align2)\n",
|
||
"\n",
|
||
"\n",
|
||
"cl_check_laa = Checkbox(value=True, description='Low angle approximation', disabled=False, indent=False,) # Low angle approximation check - scattering angle < 10 deg\n",
|
||
"cl_check_pix = Checkbox(value=True, description='Ptycho pixel < step size', disabled=False, indent=False,) # Reconstructed pixel size < scanning step size \n",
|
||
"cl_check_def = Checkbox(value=True, description='Beam fits in probe window', disabled=False, indent=False,) # Is probe window big enough to accomodate defocused probe?\n",
|
||
"cl_check_nbf = Checkbox(value=True, description='Detector cover < 1α', disabled=False, indent=False,) # Detector cover is lower than 1 α; orange\n",
|
||
"\n",
|
||
"\n",
|
||
" \n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"\n",
|
||
"### Live update ### \n",
|
||
"beam_res = Label(value = f'Wavelength (pm) '+ str(\"{:.2f}\".format(pty.get_wavelength(beam.value)*1e12)), **to_right2)\n",
|
||
"beam.observe(inte.show_wavelength, names='value')\n",
|
||
"camera_res = Label(value = f'Full pixel array '+ str(\"{:.0f}\".format(pty.get_det_resolution(camera.value))), **to_right2)\n",
|
||
"camera.observe(inte.show_detector, names='value')\n",
|
||
"pixel_size_res = Label(value = f'Native pixel size (μm) '+ str(\"{:.0f}\".format(pty.get_det_orig_pixel_size(camera.value))),**to_right)\n",
|
||
"camera.observe(inte.show_pixel_size, names='value')\n",
|
||
"# aperture_res = Label(value = f'Probe semi angle (mrad) '+ str(\"{:.2f}\".format(pty.get_angle(aperture.value))), **to_right)\n",
|
||
"# aperture.observe(inte.show_probe_angle, names='value') \n",
|
||
"# aperture_res2 = Label(value = f'Corrected semi angle (mrad) '+ str(\"{:.2f}\".format(pty.get_angle_corr(aperture.value))), **to_right)\n",
|
||
"# aperture.observe(inte.show_corrprobe_angle, names='value') \n",
|
||
"fov_res = Label(value = f'Field of view (nm) '+ str(\"{:.2f}\".format(pty.get_fov(mag.value))), **to_right)\n",
|
||
"mag.observe(inte.show_fov, names='value') \n",
|
||
"dwell_time_res = Label(value = f'Frame rate (kHz) '+ str(\"{:.2f}\".format(pty.get_aq_frec(dwell_time.value))),**to_right)\n",
|
||
"dwell_time.observe(inte.show_frame_rate, names='value') \n",
|
||
"cl_det_res = Label(value = f'Detector CL (cm) '+ str(\"{:.1f}\".format(pty.get_cl_detector(cl.value))),**to_right2)\n",
|
||
"cl.observe(inte.show_cd_det, names='value') \n",
|
||
"\n",
|
||
"### Controls layout ###\n",
|
||
"box_layout = Layout(border='solid 2px #1976D2',margin='0px 0px 0px 0px', padding='5px 5px 5px 5px')\n",
|
||
"col1 = VBox([Label('Beam'), HBox([beam ,beam_res]), aperture, probe, defocus], layout=box_layout) # aperture_res, aperture_res2,\n",
|
||
"col2 = VBox([Label('Scanning'), mag, fov_res, matrix], layout=box_layout)\n",
|
||
"col3 = VBox([Label('Camera length'), cl, HBox([restriction, cl_det_res])], layout=box_layout)\n",
|
||
"col4 = VBox([Label('Detection'), HBox([camera, camera_res]), pixel_size_res, binning, dwell_time, dwell_time_res], layout=box_layout)\n",
|
||
"\n",
|
||
"small_control = VBox([Label('Graph controls'),method, ctf_xaxis, scans, VBox([Label('Camera length check list'), cl_check_laa, cl_check_pix, cl_check_def, cl_check_nbf])], layout = Layout(border='dashed 0px gray',margin='32px 30px 00px 10px', padding='5px 5px 5px 5px'))\n",
|
||
"controls = HBox([VBox([Label(''), col1, col2, col3, col4]), small_control])\n",
|
||
"\n",
|
||
"def ptycho_interact(beam, aperture, probe, cl, matrix, defocus, mag, camera, binning, dwell_time, restriction, method, ctf_xaxis, scans, cl_check_laa, cl_check_pix, cl_check_def, cl_check_nbf):\n",
|
||
" \n",
|
||
" ### SINGLE SETTING PARAMETERS ###\n",
|
||
" wavelength = pty.get_wavelength(beam)*1e12\n",
|
||
" fov = pty.get_fov(mag)\n",
|
||
" semi_angle = pty.get_angle(aperture)\n",
|
||
" semi_angle_corr = pty.get_angle_corr(aperture) \n",
|
||
" current = pty.get_current(probe,aperture) \n",
|
||
" pixel_angle = pty.get_pixel_angle(cl, camera, binning)\n",
|
||
" cl_det = pty.get_cl_detector(cl)\n",
|
||
" frame_rate = pty.get_aq_frec(dwell_time)\n",
|
||
" step_size = pty.get_step_size(matrix)\n",
|
||
" step_size_corr = np.array(pty.get_step_correction())*pty.get_step_size(matrix)\n",
|
||
" beam_diameter = pty.get_beam_diameter(aperture, defocus)\n",
|
||
" num_pixels, size_pixel = pty.get_detector(camera, binning)\n",
|
||
" beam_diameter_pix = 2*semi_angle_corr/pixel_angle\n",
|
||
" detector_cover = num_pixels/2*pixel_angle\n",
|
||
" covered_alfas = detector_cover/semi_angle_corr\n",
|
||
" overlap = (beam_diameter-step_size_corr)/beam_diameter*100\n",
|
||
" if overlap < 0:\n",
|
||
" overlap = 0\n",
|
||
" dose = ((matrix**2)*(dwell_time/1e6)*(current/1e12/cons.e))/((((matrix-1)*step_size_corr)**2)*100)\n",
|
||
" probe_window = (wavelength*cl_det/100)/(2*size_pixel/1e6)/1000 # now in nm\n",
|
||
" \n",
|
||
" ### ALL CAMERA LENGTHS PARAMETERS ###\n",
|
||
" pixel_covers = pty.get_pixel_covers(camera, binning) \n",
|
||
" pump_apertures = pty.get_pumping_apertures()\n",
|
||
" detector_cover_all = pixel_covers*num_pixels/2\n",
|
||
" if restriction == True:\n",
|
||
" for x in range(len(detector_cover_all)):\n",
|
||
" if detector_cover_all[x] > pump_apertures[x]:\n",
|
||
" detector_cover_all[x] = pump_apertures[x] \n",
|
||
" detector_pixels_all = np.round(detector_cover_all/pixel_covers) \n",
|
||
" ptycho_pixel_size_all = (wavelength * np.array(opt.cameralengths_eff() )) /(detector_pixels_all*size_pixel/1e6)/1e4 \n",
|
||
" else:\n",
|
||
" ptycho_pixel_size_all = (wavelength * np.array(opt.cameralengths_eff() )) /(num_pixels/2*size_pixel/1e6)/1e4\n",
|
||
" \n",
|
||
" probe_window_all = (wavelength*np.array(opt.cameralengths_eff())/100)/(2*size_pixel/1e6)/1000 # now in nm\n",
|
||
" usable_probe_semi_window_all = probe_window_all/4\n",
|
||
" detector_cover_a_all = detector_cover_all/semi_angle_corr\n",
|
||
" max_defocus_all = (usable_probe_semi_window_all - pty.get_0beam_diameter(aperture)/2)/np.tan(semi_angle_corr/1000)\n",
|
||
" max_defocus_all[max_defocus_all < 0] = 'nan'\n",
|
||
" \n",
|
||
" omega = np.linspace(1e-6,2,100) \n",
|
||
" pctf = pty.get_ssb_ctf()\n",
|
||
" apertury = opt.apertures()\n",
|
||
" \n",
|
||
" ### PROBE ##########################################\n",
|
||
" fig = go.Figure() \n",
|
||
" fig.update_yaxes(title_text=\" CTF-SSB\")\n",
|
||
" xx = 2*wavelength/(np.sin(semi_angle_corr*omega/1000))/100\n",
|
||
" if ctf_xaxis == 'mrad': \n",
|
||
" for x in apertury:\n",
|
||
" fig.add_trace(go.Scatter(showlegend=False, x=pty.get_angle_corr(x) *omega, y=pctf, marker_color='gray', name='SSB-CTF',))\n",
|
||
" \n",
|
||
" fig.add_trace(go.Scatter(x=semi_angle_corr*omega, y=pctf, marker_color='red', name=str(np.round(semi_angle_corr,2))+ ' mrad',))\n",
|
||
" fig.update_xaxes(title_text=\"Spacial frequency (mrad)\", range=[0, 60], zeroline=False)\n",
|
||
"\n",
|
||
" elif ctf_xaxis == 'A':\n",
|
||
" for x in apertury:\n",
|
||
" d = 2*wavelength/(np.sin(pty.get_angle_corr(x)*omega/1000))/100\n",
|
||
" fig.add_trace(go.Scatter(showlegend=False, x=d, y=pctf, marker_color='gray', name='SSB-CTF',))\n",
|
||
" \n",
|
||
" fig.add_trace(go.Scatter(x=xx, y=pctf, marker_color='red', name=str(np.round(semi_angle_corr,2))+ ' mrad',))\n",
|
||
" fig.update_xaxes(title_text=\"Real space distance (Å)\", range=[0.0001, 2.5], type=\"log\", zeroline=False)\n",
|
||
" \n",
|
||
" fig.update_layout(legend=dict(orientation=\"h\",yanchor=\"bottom\",y=0.75,xanchor=\"right\",x=1))\n",
|
||
" # fig3.update_layout(title={'text': \"CTF\",'y':0.93, 'x':0.12,'xanchor': 'left','yanchor': 'top'})\n",
|
||
" fig.update_layout(width=800, height=225, margin = dict(l=110, r=30, t=30, b=30))\n",
|
||
"\n",
|
||
" \n",
|
||
" ### SAMPLE PLANE ##########################################\n",
|
||
" yyy = np.append(np.linspace(0,overlap,100), 200)\n",
|
||
" wid = np.linspace(0,scans-1,scans) * step_size_corr\n",
|
||
" \n",
|
||
" fig5 = make_subplots(specs=[[{\"secondary_y\": True}]])\n",
|
||
" fig5.update_xaxes(title_text=\"Sample plane (nm)\", range=[0, scans*step_size_corr], showgrid=False, zeroline=False)\n",
|
||
" fig5.update_yaxes(range=[0, scans*step_size_corr],showgrid=False, showticklabels=False)\n",
|
||
" for x in range(len(wid)):\n",
|
||
" fig5.add_trace(go.Scatter(showlegend=False, x=wid, y=np.ones(len(wid))*wid[x], marker_color='blue'),secondary_y=False)\n",
|
||
" for x in range(len(wid)): \n",
|
||
" for y in range(len(wid)): \n",
|
||
" fig5.add_shape(type=\"circle\",xref=\"x\", yref=\"y\", opacity=0.1, fillcolor=\"#FF7F7F\",name=False, x0=wid[x]-beam_diameter/2, y0=wid[y]-beam_diameter/2, x1=wid[x]+beam_diameter/2, y1=wid[y]+beam_diameter/2, line_color=\"red\",secondary_y=False)\n",
|
||
"\n",
|
||
" fig5.add_trace(go.Scatter(showlegend=True, x=[-1], y=[-1],marker_size=12, marker_color='blue', name='Step '+str(np.round(10*step_size,3))+' Å ('+str(np.round(10*step_size_corr,3))+')'))\n",
|
||
" fig5.add_trace(go.Scatter(showlegend=True, x=[-1], y=[-1],marker_size=12, marker_color='#FF7F7F', name='Beam ⌀ '+ str(np.round(10*beam_diameter,2))+\" Å\"))\n",
|
||
" fig5.update_layout(legend=dict(orientation=\"v\",yanchor=\"bottom\",y=0.85,xanchor=\"right\",x=0.9))\n",
|
||
" fig5.add_trace(go.Scatter(showlegend=False, x = scans*step_size_corr*np.ones(len(yyy)), y=yyy, opacity=1,mode='markers',marker_symbol = \"triangle-down\",marker=dict(size=20, color=yyy, colorscale='rainbow_r', showscale=False)),secondary_y=True) \n",
|
||
" \n",
|
||
" \n",
|
||
" fig5.update_yaxes(title_text=\"Overlap %\", range=[0, 100],showgrid=False, showticklabels=True, tickvals = [0, 20, 40,50, 60,70, 80, 90, 100], secondary_y=True)\n",
|
||
" fig5.update_layout(title={'text': \"Sample\",'y':0.95, 'x':0.10,'xanchor': 'left','yanchor': 'top'})\n",
|
||
" fig5.update_layout(width=430, height=380, margin =dict(l=30, r=30, t=10, b=0))\n",
|
||
"\n",
|
||
" \n",
|
||
" ### DETECTOR PLANE ##########################################\n",
|
||
" fig6 = go.Figure() \n",
|
||
" fig6.update_xaxes(title_text=\"Pixels\", range=[1, num_pixels], zeroline=False)\n",
|
||
" fig6.update_yaxes(range=[1, num_pixels], showticklabels=False,)\n",
|
||
" for x in np.linspace(1,int(np.round(covered_alfas)),int(np.round(covered_alfas))):\n",
|
||
" fig6.add_shape(type=\"circle\",xref=\"x\", yref=\"y\", x0=num_pixels/2-x*beam_diameter_pix, y0=num_pixels/2-x*beam_diameter_pix, x1=num_pixels/2+x*beam_diameter_pix, y1=num_pixels/2+x*beam_diameter_pix,line_color=\"gray\")\n",
|
||
" fig6.add_trace(go.Scatter(showlegend=False,x=[num_pixels/2],y=[num_pixels/2-x*beam_diameter_pix],mode=\"lines+text\", text=str(int(2*x))+\"α\",textposition=\"top center\"))\n",
|
||
" \n",
|
||
" fig6.add_shape(type=\"circle\",xref=\"x\", yref=\"y\", fillcolor=\"#FF7F7F\", x0=num_pixels/2-beam_diameter_pix/2, y0=num_pixels/2-beam_diameter_pix/2, x1=num_pixels/2+beam_diameter_pix/2, y1=num_pixels/2+beam_diameter_pix/2,line_color=\"#FF7F7F\")\n",
|
||
" fig6.add_annotation(x=num_pixels/2-beam_diameter_pix/2, y=num_pixels/2, ax=num_pixels/2+beam_diameter_pix/2, ay=num_pixels/2, xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=3,arrowsize=1,arrowwidth=1,arrowcolor='black')\n",
|
||
" fig6.add_annotation(x=num_pixels/2+beam_diameter_pix/2,y=num_pixels/2, ax=num_pixels/2-beam_diameter_pix/2, ay=num_pixels/2, xref='x',yref='y',axref='x',ayref='y', text='', showarrow=True,arrowhead=3,arrowsize=1,arrowwidth=1,arrowcolor='black')\n",
|
||
" fig6.add_annotation(x=num_pixels/2, y=num_pixels/2, text=str(np.round(beam_diameter_pix,1))+\" pix\", showarrow=False, yshift=10)\n",
|
||
" fig6.add_trace(go.Scatter(x=[1,1.5,1,1.5], y=[1,1,1.5,1.5], name='Pix ∠ ' +str(np.round(pixel_angle,2))+' mrad'))\n",
|
||
" fig6.update_layout(legend=dict(orientation=\"v\",yanchor=\"bottom\",y=0.85,xanchor=\"right\",x=1))\n",
|
||
" # fig6.update_layout(title={'text': \"Detector\",'y':0.925, 'x':0.10,'xanchor': 'left','yanchor': 'top'})\n",
|
||
" fig6.update_layout(xaxis = dict(tickmode = 'array', tickvals = [1, num_pixels/4, num_pixels/2, 3*num_pixels/4, num_pixels])) \n",
|
||
" fig6.update_layout(width=350, height=280, margin = dict(l=40, r=60, t=0, b=0))\n",
|
||
"\n",
|
||
" \n",
|
||
" ssb_cl, kolik = pty.cl4ssb(detector_cover_a_all)\n",
|
||
" ### MICROSCOPE SCHEME ##########################################\n",
|
||
" width = 500 \n",
|
||
" det_width = 400\n",
|
||
" y_down = np.log(np.max(opt.cameralengths()))\n",
|
||
" reduc = 0.4\n",
|
||
" \n",
|
||
" fig8 = go.Figure() \n",
|
||
" fig8.update_xaxes(range=[-width, width], showticklabels=False,zeroline=False)\n",
|
||
" fig8.update_yaxes(range=[-y_down, reduc*y_down], showticklabels=False,)\n",
|
||
"\n",
|
||
" fig8.add_shape(type=\"rect\",xref=\"x\", yref=\"y\",opacity=0.7, fillcolor=\"red\", x0=-100, y0=reduc*0.8*y_down, x1=100, y1=reduc*0.9*y_down,line_color=\"red\")\n",
|
||
" fig8.add_trace(go.Scatter(showlegend=False, x=[-150, -2*semi_angle, None, 2*semi_angle, 150], y=[reduc*0.8*y_down,reduc*0.8*y_down,None,reduc*0.8*y_down, reduc*0.8*y_down],mode='lines', line=dict(color='black',width=7)))\n",
|
||
" fig8.add_annotation(x=-0.7*width, y=reduc*0.8*y_down, text=\"<b>Aperture </b>\"+str(aperture), showarrow=False, yshift=2)\n",
|
||
" fig8.add_annotation(x=semi_angle, y=reduc*0.7*y_down, text=\"α \"+str(np.round(semi_angle,2))+\" mrad (\"+str(np.round(semi_angle_corr,2))+\")\", showarrow=True, ax=100, ay=0, yshift=0)\n",
|
||
"\n",
|
||
" if defocus > 0:\n",
|
||
" defo = np.log(defocus)/100\n",
|
||
" else:\n",
|
||
" defo = 0 \n",
|
||
"\n",
|
||
" # Beam\n",
|
||
" fig8.add_trace(go.Scatter(showlegend=False, x=[0, 2*semi_angle, 0, 0], y=[defo*y_down, reduc*0.8*y_down, reduc*0.8*y_down, defo*y_down], mode='lines',fill=\"toself\", fillcolor=\"#FF7F7F\", opacity=0.7,line=dict(color='#FF7F7F',width=1)))\n",
|
||
" fig8.add_trace(go.Scatter(showlegend=False, x=[0, 0, -2*semi_angle, 0], y=[defo*y_down, reduc*0.8*y_down, reduc*0.8*y_down, defo*y_down],mode='lines', fill=\"toself\", fillcolor=\"red\", opacity=0.7,line=dict(color='red',width=1)))\n",
|
||
" fig8.add_annotation(x=0, y=reduc*0.5*y_down,text=\"Current \"+str(np.round(current,1))+\" pA\", showarrow=True,ax=100, ay=0, yshift=0)\n",
|
||
" \n",
|
||
" if defocus > 0:\n",
|
||
" fig8.add_annotation(x=-0.05*width, y=0, ax=-0.05*width, ay=defo*y_down, xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=1,arrowsize=1,arrowwidth=1,arrowcolor='black')\n",
|
||
" fig8.add_annotation(x=-0.05*width, y=defo*y_down, ax=-0.05*width, ay=0, xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=1,arrowsize=1,arrowwidth=1,arrowcolor='black')\n",
|
||
" fig8.add_annotation(x=-0.3*width, y=0.05*y_down,text=\"Δf \"+str(np.round(defocus,1))+\" nm\", showarrow=False)\n",
|
||
"\n",
|
||
" # Sample\n",
|
||
" fig8.add_trace(go.Scatter(showlegend=False, x=[-0.8*width, 0.8*width], y=[0, 0], line=dict(color='magenta',width=7), opacity=0.5))\n",
|
||
" fig8.add_annotation(x=-0.8*width, y=0,text=\"<b>Sample</b>\", showarrow=False, yshift=15)\n",
|
||
" fig8.add_trace(go.Scatter(showlegend=False, x=[-np.log(fov)/20*width, np.log(fov)/20*width, np.log(fov)/20*width, -np.log(fov)/20*width, -np.log(fov)/20*width], y=[-0.01*y_down, -0.01*y_down, 0.01*y_down, 0.01*y_down, -0.01*y_down],mode='lines', fill=\"toself\", fillcolor=\"black\", line=dict(color='black',width=1), opacity=0.5))\n",
|
||
" fig8.add_annotation(x=0.35*width, y=0.05*y_down,text=\"FoV \"+str(np.round(fov,2))+\" nm\", showarrow=False, ax=50, ay=-30, yshift=0)\n",
|
||
" \n",
|
||
" # Detector\n",
|
||
" y = -np.log(cl)*np.ones(int(num_pixels)+1)\n",
|
||
" x = np.linspace(-det_width,det_width, int(num_pixels)+1)\n",
|
||
" fig8.add_trace(go.Scatter(showlegend=False, x=x, y=y, mode='markers', marker_symbol=\"line-ns\",marker_line_width=0.5))\n",
|
||
" fig8.add_annotation(x=-0.8*width, y=-np.log(cl),text=\"<b>Detector</b>\", showarrow=False,align= 'left', yshift=15)\n",
|
||
" \n",
|
||
" # Scattering\n",
|
||
" fig8.add_trace(go.Scatter(showlegend=False, x=[0, det_width, -det_width, 0], y=[defo*y_down, -np.log(cl), -np.log(cl), -np.log(cl), defo*y_down],mode='lines', fill=\"toself\", fillcolor=\"gray\", opacity=0.1,line=dict(color='black',width=1)))\n",
|
||
" fig8.add_trace(go.Scatter(showlegend=False, x=[0, -det_width, det_width, 0], y=[defo*y_down, -np.log(cl), -np.log(cl), -np.log(cl), defo*y_down],mode='lines', fill=\"toself\", fillcolor=\"gray\", opacity=0.1,line=dict(color='black',width=1)))\n",
|
||
" # BF disk\n",
|
||
" fig8.add_trace(go.Scatter(showlegend=False, x=[0, det_width/covered_alfas, -det_width/covered_alfas, 0], y=[defo*y_down, -np.log(cl), -np.log(cl), -np.log(cl), defo*y_down],mode='lines', fill=\"toself\", fillcolor=\"#FF7F7F\", opacity=0.7,line=dict(color='#FF7F7F',width=1)))\n",
|
||
" fig8.add_trace(go.Scatter(showlegend=False, x=[0, -det_width/covered_alfas, det_width/covered_alfas, 0], y=[defo*y_down, -np.log(cl), -np.log(cl), -np.log(cl), defo*y_down],mode='lines', fill=\"toself\", fillcolor=\"red\", opacity=0.7,line=dict(color='#FF7F7F',width=1)))\n",
|
||
" \n",
|
||
" fig8.add_trace(go.Scatter(showlegend=False, x=[-width, width], y=[-np.log(ssb_cl), -np.log(ssb_cl)], opacity=0.8, line=dict(color='green',width=3)))\n",
|
||
" fig8.add_annotation(x=-0.7*width, y=-np.log(ssb_cl),text=\"<b>REC for SSB</b>\", showarrow=False,align= 'left', yshift=-15)\n",
|
||
" \n",
|
||
" if restriction == True:\n",
|
||
" fig8.add_trace(go.Scatter(showlegend=False, x=[-250, -4*semi_angle, None, 4*semi_angle, 250], y=[-reduc*0.2*y_down,-reduc*0.2*y_down,None,-reduc*0.2*y_down, -reduc*0.2*y_down],mode='lines', line=dict(color='black',width=7)))\n",
|
||
" fig8.add_annotation(x=-0.35*width, y=-reduc*0.2*y_down,text=\"<b>PAAR</b>\", showarrow=False,align= 'left', yshift=15)\n",
|
||
" \n",
|
||
" # Cover\n",
|
||
" fig8.add_annotation(x=0, y=-1.05*np.log(cl), ax=det_width, ay=-1.05*np.log(cl), xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=3,arrowsize=1,arrowwidth=1,arrowcolor='black')\n",
|
||
" fig8.add_annotation(x=det_width,y=-1.05*np.log(cl), ax=0, ay=-1.05*np.log(cl), xref='x',yref='y',axref='x',ayref='y', text='', showarrow=True,arrowhead=3,arrowsize=1,arrowwidth=1,arrowcolor='black')\n",
|
||
" fig8.add_annotation(x=det_width/2, y=-1.05*np.log(cl), text=\"Cover \"+str(np.round(detector_cover,1)) + \" mrad;\" + str(np.round(covered_alfas,1))+\"α\", showarrow=False, yshift=-10, xshift=-10)\n",
|
||
"\n",
|
||
" # CLs\n",
|
||
" fig8.add_annotation(x=0.9*width, y=-np.log(1.5),text=\"CL cm\", showarrow=False, yshift=0)\n",
|
||
" for x in opt.cameralengths():\n",
|
||
" fig8.add_trace(go.Scatter(showlegend=False, x=[-width, width], y=[-np.log(x), -np.log(x)], opacity=0.3, line=dict(color='gray',width=1)))\n",
|
||
" fig8.add_annotation(x=0.9*width, y=-np.log(x),text=str(x), showarrow=False, yshift=8)\n",
|
||
"\n",
|
||
" fig8.update_xaxes(title_text=\"\")\n",
|
||
" # fig8.update_layout(title={'text': \"Microscope\" ,'y':1, 'x':0.10,'xanchor': 'left','yanchor': 'top'})\n",
|
||
" fig8.update_layout(width=350, height=570, margin = dict(l=10, r=30, t=20, b=0))\n",
|
||
" fig8.update_layout(plot_bgcolor='white')\n",
|
||
" \n",
|
||
" \n",
|
||
" ### FINAL CHECKS ########################################## \n",
|
||
" align3 = dict(layout=Layout(width='200px') , style = {'description_width': '150px','button_width': \"100px\"}, disabled=True,) \n",
|
||
" \n",
|
||
" check1 = Valid(value= bool(overlap > 60), description='Overlap > 60 %', **align3)\n",
|
||
" check2 = Valid(value= bool(step_size_corr*10 > (wavelength * cl_det)/(num_pixels*size_pixel/1e6)/1e4), description='Ptycho pix < step size', **align3)\n",
|
||
" check3 = Valid(value= bool(beam_diameter/2 < probe_window/2), description='Beam ⌀ < window/2', **align3) \n",
|
||
" \n",
|
||
" electron_dose = Label(value = f'Electron dose (e/Å2) '+ str(np.round(dose,1)), **align3) \n",
|
||
" acquisition_time = Label(value = f'Acquisition time (s) '+ str(np.round(matrix*matrix*dwell_time/1e6,1)), **align3) \n",
|
||
" focusdepth = Label(value = f'Depth of focus (nm) '+ str(np.round(wavelength/(semi_angle_corr/1000)**2/1000,1)), **align3) \n",
|
||
"\n",
|
||
"\n",
|
||
" ### METHODS ########################################## \n",
|
||
" if method == 'direct':\n",
|
||
" \n",
|
||
" \n",
|
||
" ssb_sampling = Label(value = f'Recommended sampling (Å) '+ str(np.round(xx[-1]/3,2)), **align3) \n",
|
||
" \n",
|
||
" ### CAMERA LENGTH GRAPH ##########################################\n",
|
||
" fig4 = make_subplots(specs=[[{\"secondary_y\": True}]])\n",
|
||
" fig4.add_trace(go.Scatter(showlegend=False, x=opt.cameralengths(), y=detector_cover_all, marker_color='gray'), secondary_y=False,)\n",
|
||
" fig4.add_trace(go.Scatter(showlegend=False, x=opt.cameralengths(), y=detector_cover_a_all,marker_color='gray'), secondary_y=True,)\n",
|
||
" fig4.add_trace(go.Scatter(x=np.array(cl), y=np.array(covered_alfas), marker_size=12, marker_color='red', name = str(np.round(detector_cover,1))+ \" mrad; \"+str(np.round(covered_alfas,2))+ \" α\"), secondary_y=True,) \n",
|
||
" fig4.add_trace(go.Scatter(x=np.array(ssb_cl), y=np.array(kolik),marker_size=12, marker_color='green', name = \"Rec SSB CL\"), secondary_y=True,) \n",
|
||
" fig4.update_layout(legend=dict(orientation=\"v\",yanchor=\"bottom\",y=0.65,xanchor=\"right\",x=0.9))\n",
|
||
" # fig4.update_layout(title={'text': \"CL to α\",'y':0.93, 'x':0.12,'xanchor': 'left','yanchor': 'top'})\n",
|
||
" fig4.update_xaxes(title_text=\"Nominal camera length (cm)\", type=\"log\", tickvals = opt.cameralengths())\n",
|
||
" fig4.update_layout(xaxis = dict(tickmode = 'array', tickvals = [1, num_pixels/4, num_pixels/2, 3*num_pixels/4, num_pixels]))\n",
|
||
" fig4.update_yaxes(title_text=\" Cover angle (mrad)\", range=[0, 1.1*np.max(detector_cover_all)], secondary_y=False)\n",
|
||
" fig4.update_yaxes(title_text=\" Cover angle (α)\", range=[0, 1.1*np.max(detector_cover_a_all)], showgrid=False, secondary_y=True)\n",
|
||
" fig4.update_layout(xaxis = dict(tickmode = 'array', tickvals = opt.cameralengths()))\n",
|
||
" fig4.update_layout(width=800, height=225, margin =dict(l=110, r=30, t=30, b=30))\n",
|
||
" \n",
|
||
" \n",
|
||
" checks = VBox([Label('Final checks'), electron_dose, ssb_sampling, focusdepth, acquisition_time]) \n",
|
||
" checks.layout = Layout(border='dashed 1px gray',margin='30px 5px 5px 5px', padding='10px 10px 10px 10px')\n",
|
||
" \n",
|
||
" \n",
|
||
" ### SHOWING ###\n",
|
||
" right_column = VBox([go.FigureWidget(fig),go.FigureWidget(fig5),go.FigureWidget(fig4)])\n",
|
||
" left_column = VBox([go.FigureWidget(fig8), go.FigureWidget(fig6)])\n",
|
||
" display(HBox([left_column, right_column, checks]))\n",
|
||
" \n",
|
||
" \n",
|
||
" \n",
|
||
" \n",
|
||
" \n",
|
||
" if method == 'iterative':\n",
|
||
" \n",
|
||
" checks = VBox([Label('Final checks'),check1, check2, check3,electron_dose,focusdepth, acquisition_time]) \n",
|
||
" checks.layout = Layout(border='dashed 1px gray',margin='30px 5px 5px 5px', padding='10px 10px 10px 10px')\n",
|
||
" \n",
|
||
" \n",
|
||
" ### PROBE WINDOW ##########################################\n",
|
||
" if beam_diameter < probe_window/2:\n",
|
||
" color = \"green\"\n",
|
||
" name = 'Beam ⌀ is fine'\n",
|
||
" elif beam_diameter < probe_window:\n",
|
||
" color = \"orange\"\n",
|
||
" name = 'Beam ⌀ is quite big'\n",
|
||
" else:\n",
|
||
" color = \"red\"\n",
|
||
" name = 'Beam ⌀ is too big'\n",
|
||
"\n",
|
||
" fig7 = go.Figure() \n",
|
||
" fig7.add_shape(type=\"rect\",xref=\"x\", yref=\"y\",opacity=0.3, fillcolor=\"LightSkyBlue\", x0=probe_window/4, y0=probe_window/4, x1=3*probe_window/4, y1=3*probe_window/4,line_color=\"LightSkyBlue\")\n",
|
||
" fig7.add_trace(go.Scatter(x=np.array(probe_window/2), y=np.array(probe_window/2), showlegend=False, marker_color=\"LightSkyBlue\"))\n",
|
||
" fig7.add_trace(go.Scatter(x=np.array(probe_window/2), y=np.array(probe_window/2), name=name, showlegend=True, marker_color=color))\n",
|
||
" fig7.add_annotation(x=probe_window/2, y=3*probe_window/4, text=\"<b>Usable area </b>\", showarrow=False, yshift=-15)\n",
|
||
" fig7.add_shape(type=\"circle\",xref=\"x\", yref=\"y\", opacity=0.9, fillcolor=color, x0=probe_window/2-beam_diameter/2, y0=probe_window/2-beam_diameter/2, x1=probe_window/2+beam_diameter/2, y1=probe_window/2+beam_diameter/2, line_color=color,)\n",
|
||
" fig7.update_xaxes(title_text=\"Probe window (nm)\", range=[0, probe_window], tickvals = [0, np.round(probe_window/4,2), np.round(probe_window/2,2), np.round(3*probe_window/4,2), np.round(probe_window,2)-0.01])\n",
|
||
" fig7.update_yaxes(range=[0, probe_window], showticklabels=False,)\n",
|
||
" fig7.update_layout(legend=dict(orientation=\"v\",yanchor=\"bottom\",y=0.9,xanchor=\"right\",x=1))\n",
|
||
" fig7.update_layout(title={'text': \"Probe window \",'y':0.925, 'x':0.10,'xanchor': 'left','yanchor': 'top'})\n",
|
||
" fig7.update_layout(width=400, height=380, margin =dict(l=30, r=30, t=10, b=0)) \n",
|
||
" \n",
|
||
" ### CAMERA LENGTH TABLE ########################################## \n",
|
||
" dictionary = {}\n",
|
||
" tab = np.array([np.round(ptycho_pixel_size_all,2),np.round(detector_cover_all,1), np.round(detector_cover_a_all,1), np.round(max_defocus_all,1), np.array(opt.cameralengths())])\n",
|
||
" \n",
|
||
" align6 = dict(layout=Layout(width='50px') , style = {'description_width': '0px','button_width': \"33px\"}, disabled=True,)\n",
|
||
" align7 = dict(layout=Layout(width='130px') , style = {'description_width': '0px','button_width': \"110px\"}, disabled=True,)\n",
|
||
" for i in range(0,12):\n",
|
||
" button_style = 'success'\n",
|
||
" data = tab[:,int(i)] # 0. ptycho pix, 1.det cov 2.det cov a, 3.max def, 4.cl\n",
|
||
"\n",
|
||
" if cl_check_laa == True:\n",
|
||
" if data[1] > 1000*np.radians(10):\n",
|
||
" button_style = 'danger' \n",
|
||
" \n",
|
||
" if cl_check_pix == True: \n",
|
||
" if data[0] > step_size_corr*10:\n",
|
||
" button_style = 'danger'\n",
|
||
" \n",
|
||
" if cl_check_def == True: \n",
|
||
" if data[3] < defocus:\n",
|
||
" button_style = 'danger'\n",
|
||
" \n",
|
||
" if cl_check_nbf == True: \n",
|
||
" if data[2] < 1:\n",
|
||
" button_style = 'danger' \n",
|
||
" \n",
|
||
" dictionary[i] = ToggleButtons(options=data, description='',button_style=button_style, **align6)\n",
|
||
" \n",
|
||
" legend = ToggleButtons(options=['Ptycho pix. (Å)','Det. cover (mrad)','Det. cover (α)', 'Max. defocus (nm)','Nominal CL (cm)'], \n",
|
||
" tooltips=['Dependent on: detector, beam energy, camera length',\n",
|
||
" 'Dependent on: detector, camera length',\n",
|
||
" 'Dependent on: detector, camera length, probe semi-angle',\n",
|
||
" 'Dependent on: detector, binning, beam energy, camera length, zero defocus beam diameter, probe semi-angle',\n",
|
||
" 'Just nominal camera length',\n",
|
||
" ],button_style='', **align7) \n",
|
||
" \n",
|
||
" \n",
|
||
" \n",
|
||
" \n",
|
||
" cltab = HBox([legend,dictionary[0],dictionary[1],dictionary[2],dictionary[3],dictionary[4],dictionary[5],dictionary[6],dictionary[7],dictionary[8],dictionary[9], dictionary[10],dictionary[11]])\n",
|
||
" cltab = VBox([Label('Chose your reconstructed ptychographic pixe size, check needed defocus and set CL'), cltab])\n",
|
||
" cltab.layout = Layout(border='solid 0px gray',margin='10px 10px 10px 10px', padding='10px 10px 10px 10px')\n",
|
||
" \n",
|
||
" \n",
|
||
" \n",
|
||
" ### SHOWING ###\n",
|
||
" sample_overlap = HBox([go.FigureWidget(fig5), go.FigureWidget(fig7)]) \n",
|
||
" right_column = VBox([go.FigureWidget(fig), sample_overlap, cltab ]) \n",
|
||
" left_column = VBox([go.FigureWidget(fig8), go.FigureWidget(fig6)]) \n",
|
||
" \n",
|
||
" display(HBox([left_column, right_column, checks]))\n",
|
||
" \n",
|
||
" return \n",
|
||
" \n",
|
||
"gui = interactive_output(ptycho_interact, {\"beam\": beam, \"aperture\": aperture, \"probe\": probe, \"cl\": cl, \"matrix\": matrix, \"defocus\": defocus, \"mag\": mag, \"camera\": camera,\n",
|
||
" \"binning\": binning, \"dwell_time\": dwell_time, \"restriction\": restriction, \"method\": method, \"ctf_xaxis\": ctf_xaxis, \"scans\": scans,\n",
|
||
" \"cl_check_laa\":cl_check_laa, \"cl_check_pix\": cl_check_pix, \"cl_check_def\": cl_check_def, \"cl_check_nbf\": cl_check_nbf}) "
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "markdown",
|
||
"id": "1e474cb7-5fd4-4113-a3fa-ddf5ca152ce5",
|
||
"metadata": {},
|
||
"source": [
|
||
"\n",
|
||
"\n",
|
||
"Jupyter based interactive data acquisition tool designed for appropriate ptychographic data collection. It computes nessesary characteristics which play crutial role in final data reconstruction. \n",
|
||
"You can chose of **Direct methods** (mainly Single Side Band ptychography) or **Iterative reconstruction** which takes probe defocus into account. With this tool, you can check for probe CTF, scanning step size, probe overlap, detector camera length a proper angular range collection, reconstructed probe size and many more.\n",
|
||
"\n",
|
||
"For more info go to https://gitlab.psi.ch/em-and-diffraction/low-dose-electron-ptychography/ptychoscopy/-/wikis/ptychoScopy\n",
|
||
"\n",
|
||
"### Controls\n",
|
||
"List of controls consists of all parameters needed for proper dataset acquisition design:\n",
|
||
"\n",
|
||
"| Beam | | Scanning | | Camera length | | Detection | |\n",
|
||
"|------ | ------| ------| ------| ------| ------| ------| ------|\n",
|
||
"| **Aperture**| probe forming aperture gives probe semi-angle (α) | **Magnification**| controls image field of view | **Nominal CL** | sample to detector distance gives maximal detected angle as well as angular sampling | **Detector** | detector used for data collection | \n",
|
||
"| **Energy** | energy of primary electron beam in keV ... gives final pixel size | **Matrix** | gives beam position to position distance + beam defocus = beam overlap | **Use PAAR** | Pumping Aperture Anglar Restriction, build-in aperture may limit maximal scattering angles for shortest camera lengths |**Binning** | reduction in pixel array size usually increas maximum frame rate |\n",
|
||
"| **Probe** | probe setting together with chosen probe forming aperture give probe current| | | | | **Dwell time**|single position beam time ... check your detector characteristics |\n",
|
||
"| **Defocus** | moves focus out of the sample plane - enlarges beam diameter | | | | | | |\n",
|
||
"\n",
|
||
"### Start the interactive gui by running the field\n",
|
||
"```python\n",
|
||
"display(HBox([controls, gui]))\n",
|
||
"```"
|
||
]
|
||
},
|
||
{
|
||
"cell_type": "code",
|
||
"execution_count": 69,
|
||
"id": "7937f054-fcd0-4e67-a20f-7696f5903a94",
|
||
"metadata": {},
|
||
"outputs": [
|
||
{
|
||
"data": {
|
||
"application/vnd.jupyter.widget-view+json": {
|
||
"model_id": "0d132191d4f0427aaa01278a955425f0",
|
||
"version_major": 2,
|
||
"version_minor": 0
|
||
},
|
||
"text/plain": [
|
||
"HBox(children=(HBox(children=(VBox(children=(Label(value=''), VBox(children=(Label(value='Beam'), HBox(childre…"
|
||
]
|
||
},
|
||
"metadata": {},
|
||
"output_type": "display_data"
|
||
}
|
||
],
|
||
"source": [
|
||
"display(HBox([controls, gui]))"
|
||
]
|
||
}
|
||
],
|
||
"metadata": {
|
||
"kernelspec": {
|
||
"display_name": "Python 3 (ipykernel)",
|
||
"language": "python",
|
||
"name": "python3"
|
||
},
|
||
"language_info": {
|
||
"codemirror_mode": {
|
||
"name": "ipython",
|
||
"version": 3
|
||
},
|
||
"file_extension": ".py",
|
||
"mimetype": "text/x-python",
|
||
"name": "python",
|
||
"nbconvert_exporter": "python",
|
||
"pygments_lexer": "ipython3",
|
||
"version": "3.9.13"
|
||
},
|
||
"varInspector": {
|
||
"cols": {
|
||
"lenName": 16,
|
||
"lenType": 16,
|
||
"lenVar": 40
|
||
},
|
||
"kernels_config": {
|
||
"python": {
|
||
"delete_cmd_postfix": "",
|
||
"delete_cmd_prefix": "del ",
|
||
"library": "var_list.py",
|
||
"varRefreshCmd": "print(var_dic_list())"
|
||
},
|
||
"r": {
|
||
"delete_cmd_postfix": ") ",
|
||
"delete_cmd_prefix": "rm(",
|
||
"library": "var_list.r",
|
||
"varRefreshCmd": "cat(var_dic_list()) "
|
||
}
|
||
},
|
||
"position": {
|
||
"height": "144.294px",
|
||
"left": "1149.02px",
|
||
"right": "19.9884px",
|
||
"top": "119.988px",
|
||
"width": "349.977px"
|
||
},
|
||
"types_to_exclude": [
|
||
"module",
|
||
"function",
|
||
"builtin_function_or_method",
|
||
"instance",
|
||
"_Feature"
|
||
],
|
||
"window_display": false
|
||
}
|
||
},
|
||
"nbformat": 4,
|
||
"nbformat_minor": 5
|
||
}
|