From 88cf2c18451193e8462f8a1d1308922081d93b80 Mon Sep 17 00:00:00 2001 From: rskoupy Date: Tue, 1 Oct 2024 18:02:57 +0200 Subject: [PATCH] ver0.3 --- .../ptychoScopy-checkpoint.ipynb | 1682 +++++++---------- ptychoScopy.ipynb | 63 +- ptychoscopy/__pycache__/pty.cpython-311.pyc | Bin 29354 -> 29356 bytes ptychoscopy/calibrations.xlsx | Bin 71481 -> 71483 bytes ptychoscopy/pty.py | 2 + 5 files changed, 686 insertions(+), 1061 deletions(-) diff --git a/.ipynb_checkpoints/ptychoScopy-checkpoint.ipynb b/.ipynb_checkpoints/ptychoScopy-checkpoint.ipynb index 1c53730..dde1a93 100644 --- a/.ipynb_checkpoints/ptychoScopy-checkpoint.ipynb +++ b/.ipynb_checkpoints/ptychoScopy-checkpoint.ipynb @@ -2,93 +2,52 @@ "cells": [ { "cell_type": "markdown", - "id": "1e474cb7-5fd4-4113-a3fa-ddf5ca152ce5", + "id": "cfe429ad-a3da-4b34-a78d-2828fcfe5f49", "metadata": {}, "source": [ - "# ptychoScopy\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", + "![title](ptychoscopy/logo.png)" + ] + }, + { + "cell_type": "markdown", + "id": "7ad928f6-e3a8-4a1b-a9a2-1d5993374d9a", + "metadata": {}, + "source": [ + " Code @ Radim Skoupý, PSI Villigen 2024" + ] + }, + { + "cell_type": "markdown", + "id": "62ff068b-4918-46fd-8045-7a1f8f8cd851", + "metadata": {}, + "source": [ + "Jupyter Notebook/Lab based interactive data acquisition tool designed for appropriate ptychographic data collection. It consists of **SSB** (Single Side Band ptychography) or **full-field ITR** (iterative reconstruction methods) tabs where method related charts may be found. With this tool, you can check the probe CTF, scanning step size, probe overlap, illumination uniformity, detector camera length a proper angular range collection, reconstructed probe size and many more. For in-detail intructions and up-to-date version visit [GitLab](https://gitlab.psi.ch/em-and-diffraction/low-dose-electron-ptychography/ptychoscopy/-/wikis/ptychoScopy) repository.\n", + " \n", + "#### Start the interactive gui by running the field called RUN ME and then\n", "```python\n", - "display(HBox([controls, VBox([small_controls, gui])]))\n", - "```" + "display(ptychoscopy)\n", + "```\n", + "\n", + "#### Check installed package versions\n", + "```python\n", + "from ptychoscopy import pty\n", + "pty.get_versions() # run before \"display(ptychoscopy)\" field\n", + "```\n", + "\n", + "#### If you use ptychoScopy in your research, we kindly ask that you cite our paper:\n", + "Skoupy R., Mueller E., Pennycook T., Guizar-Sicairos M., Fabbri E., Poghosyan E. ptychoScopy: Users Guide for Optimal Acquisition Design with Electron Ptychography, xxxx, xx, [DOI](https://doi.org)" ] }, { "cell_type": "code", - "execution_count": null, - "id": "9414daad-2958-4c26-8f29-8f6fe92fe992", - "metadata": {}, - "outputs": [], - "source": [ - "# # Used packages\n", - "# import sys\n", - "# print (sys.version)\n", - "# import openpyxl\n", - "# print(\"Openpyxl version \", openpyxl.__version__)\n", - "# import numpy as np\n", - "# print(\"Numpy version \", np.__version__)\n", - "# import scipy\n", - "# print(\"Scipy version \", scipy.__version__)\n", - "# import plotly\n", - "# print(\"Plotly version \", plotly.__version__)\n", - "# import pandas\n", - "# print(\"Pandas version \", pandas.__version__)\n", - "# import IPython\n", - "# print(\"IPython version \", IPython.__version__)\n", - "# import ipywidgets\n", - "# print(\"Ipywidgets version \", ipywidgets.__version__)" - ] - }, - { - "cell_type": "code", - "execution_count": 2, - "id": "de350192-85ae-4d38-8ed3-14ad43843e01", - "metadata": {}, - "outputs": [], - "source": [ - "### Initial packages import ###################################################\n", - "import ipywidgets as widgets\n", - "import io\n", - "import sys\n", - "import numpy as np\n", - "from abtem import Probe\n", - "import scipy.constants as cons\n", - "from scipy.stats import norm\n", - "import plotly.express as px\n", - "import plotly.graph_objects as go\n", - "from scipy.interpolate import splrep, BSpline \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, FloatSlider, Checkbox, Button, ButtonStyle, GridBox,IntSlider,Combobox, ColorPicker" - ] - }, - { - "cell_type": "code", - "execution_count": 15, - "id": "7937f054-fcd0-4e67-a20f-7696f5903a94", + "execution_count": 4, + "id": "5c5feaae-861c-4277-9dd5-aee373b3c174", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "c9cf20bfd02a4b7483a582dca71bdb4e", + "model_id": "37bb53443b8a4d50bb614d7156907632", "version_major": 2, "version_minor": 0 }, @@ -101,995 +60,652 @@ } ], "source": [ - "\n", - "display(VBox([top_set, HBox([controls, VBox([small_controls, gui])])]))\n" + "display(ptychoscopy)" ] }, { - "cell_type": "code", - "execution_count": 14, - "id": "41ac78f4-8a75-4258-bfd4-539b28746088", + "cell_type": "markdown", + "id": "b2865f08-6c85-4ce9-9173-a63e738a1224", "metadata": {}, - "outputs": [], "source": [ - "### CONTROLS ##########################################\n", - "ali = dict(style = {'description_width': '110px','button_width': '55px', 'font_weight': 'bold'}, button_style='', disabled = False)\n", - "ali2 = dict(style = {'description_width': '60px' ,'button_width': '90px', 'font_weight': 'bold'}, button_style='', disabled = False)\n", - "ali3 = dict(style = {'description_width': '110px','button_width': '45px', 'font_weight': 'bold'}, button_style='', disabled = False)\n", - "# header = Button(description='Control panel',layout=Layout(width='auto', grid_area='header'), style=ButtonStyle(button_color='navy', font_weight= 'bold',font_size= '20px',font_variant='small-caps',text_color='white'),disabled = False)\n", - "\n", - "beam_set = Button(description='Electron beam settings',layout=Layout(width='95%', grid_area='beam_set'), style=ButtonStyle(button_color='#222261', font_weight= 'bold',font_size= '16px',text_color='white'),disabled = False) \n", - "beam = Dropdown(options=opt.energies(), value=200,description='Beam energy (keV)', layout=Layout(width='95%', grid_area='beam_set1'), **ali )\n", - "aperture_name = Label(value = 'Aperture',layout=Layout(width='95%', grid_area='aperture_name'),)\n", - "if len(opt.apertures())>5:\n", - " aperture = Dropdown(options=opt.apertures(), description='', layout=Layout(width='95%', grid_area='beam_set2'), **ali)\n", - "else:\n", - " aperture = ToggleButtons(options=opt.apertures(), description='', layout=Layout(width='95%', grid_area='beam_set2'), **ali3)\n", - "\n", - "probe = Dropdown(options=opt.probes(), value='8C', description='Probe', layout=Layout(width='95%', grid_area='beam_set3'), **ali)\n", - "defocus = IntSlider(description='Defocus (nm)', value=0, min=0, max=1000, step=1, continuous_update=False, layout=Layout(width='95%', grid_area='beam_set4'), **ali)\n", - "\n", - "scanning_set = Button(description='Scanning parameters',layout=Layout(width='95%', grid_area='scanning_set'),style=ButtonStyle(button_color='#222261', font_weight= 'bold',font_size= '16px',text_color='white'),disabled = False)\n", - "mag = Dropdown(options=opt.magnifications(),value=20,description='Magnification Mx', layout=Layout(width='95%', grid_area='scanning_set1'), **ali)\n", - "matrix = Dropdown(options=opt.mappings(), value=256, description='Matrix', layout=Layout(width='95%', grid_area='scanning_set2'), **ali)\n", - "dwell_time = Dropdown(options=opt.dwelltimes(), value=10, description='Dwell time (μs)', layout=Layout(width='95%', grid_area='scanning_set3'), **ali)\n", - "\n", - "camera_set = Button(description='Detection',layout=Layout(width='95%', grid_area='camera_set'),style=ButtonStyle(button_color='#222261', font_weight= 'bold',font_size= '16px',text_color='white'),disabled = False)\n", - "cl = Dropdown(options=opt.cameralengths(), value=8, description='Nominal CL (cm)', layout=Layout(width='95%', grid_area='cl_set1'), **ali3)\n", - "camera_name = Label(value = 'Detector',layout=Layout(width='95%', grid_area='camera_name'),)\n", - "camera = ToggleButtons(options=opt.detectors(), description='', layout=Layout(width='95%', grid_area='camera_set1'), style = {'description_width': '60px','button_width': str(100/len(opt.detectors())-len(opt.detectors()))+'%', 'font_weight': 'bold'}, button_style='')\n", - "restriction_name = Label(value = 'PAAR',layout=Layout(width='95%', grid_area='restriction_name'),)\n", - "restriction = ToggleButtons(options=[('.',False), ('..',True)], value = False, description='',icons = ['ban','check'], layout=Layout(width='95%', grid_area='camera_set2'),style = {'description_width': '80px','button_width': '48%', 'font_weight': 'bold'}, button_style='')\n", - "binning_name = Label(value = 'Binning',layout=Layout(width='95%', grid_area='binning_name'),)\n", - "binning = ToggleButtons(options=[('.',1), ('2',2), ('4',4), ('8',8), ('16',16), ('24',24), ('32',32), ('48',48)], value=1, description='', icons = ['ban','',''], layout=Layout(width='95%', grid_area='camera_set3'), **ali3)\n", - "\n", - "beam_res = Label(value = f'λ (pm) '+ str(\"{:.1f}\".format(pty.get_wavelength(beam.value)*1e12)),layout=Layout(width='auto', grid_area='sidebar1'),)\n", - "beam.observe(inte.show_wavelength, names='value') \n", - "aperture_res = Label(value = f'Semi-angle (mrad) '+ str(\"{:.1f}\".format(pty.get_angle(aperture.value))), layout=Layout(width='auto', grid_area='sidebar2'),)\n", - "aperture.observe(inte.show_probe_angle, names='value') \n", - "aperture_res2 = Label(value = f'corr. '+ str(\"{:.2f}\".format(pty.get_angle_corr(aperture.value))),layout=Layout(width='auto', grid_area='sidebar5'),)\n", - "aperture.observe(inte.show_corrprobe_angle, names='value') \n", - "fov_res = Label(value = f'FoV (nm) '+ str(\"{:.1f}\".format(pty.get_fov(mag.value))),layout=Layout(width='auto', grid_area='sidebar3'),) \n", - "mag.observe(inte.show_fov, names='value') \n", - "dwell_time_res = Label(value = f'Rate (kHz) '+ str(\"{:.1f}\".format(pty.get_aq_frec(dwell_time.value))),layout=Layout(width='auto', grid_area='sidebar4'),) \n", - "dwell_time.observe(inte.show_frame_rate, names='value') \n", - "\n", - "\n", - "visual_set = Button(description='Visualisation',layout=Layout(width='95%', grid_area='visual_set'),style=ButtonStyle(button_color='white', font_weight= 'bold',font_size= '16px',text_color='black'),disabled = False)\n", - "\n", - "file = open(\"./logo_psi.png\", \"rb\")\n", - "image = file.read()\n", - "logo1 = widgets.Image(value=image, format='png', layout=Layout(grid_area='logo1'))\n", - "\n", - "file = open(\"./logo4.png\", \"rb\")\n", - "image = file.read()\n", - "logo2 = widgets.Image(value=image,format='png', layout=Layout(grid_area='logo2'))\n", - "\n", - "method = ToggleButtons(options=[('SSB ','direct'), ('ITR ','iterative')], description='', icons = ['opera','refresh'], tooltips=['Single side band ptychography', 'Iterative reconstruction methods (PIE, ML, DM)'],\n", - " layout=Layout(width='95%', grid_area='methods2'), style = {'button_width': '48%','font_weight': 'bold'}, button_style='', disabled = False)\n", - "\n", - "name1 = Button(description='Graphs (%)',layout=Layout(width='95%', grid_area='name1'),style=ButtonStyle(button_color='white', font_weight= 'bold',text_color='black'), disabled = False)\n", - "graph_size = IntSlider(value=100,min=75,max=125,step=5, description='', layout=Layout(width='95%', grid_area='gr_size2'), button_style='primary',disabled=False,)\n", - "\n", - "chart = ToggleButtons(options=[('L ','micr'), ('R ','dedic'),('L+R ','both')],value = 'both',icons = ['columns','columns','columns'], description='',\n", - " layout=Layout(width='95%', grid_area='charts'), style = {'button_width': '30%', 'font_weight': 'bold'}, button_style='',disabled=False,)\n", - "\n", - "controls = GridBox(children=[logo2,method, beam_set, beam,aperture_name, aperture, probe, defocus, scanning_set, mag,matrix,dwell_time, cl,camera_set, \n", - " camera,camera_name, restriction_name, restriction, binning_name, binning, beam_res, aperture_res,aperture_res2,fov_res, dwell_time_res, graph_size,name1, chart, visual_set],\n", - " layout=Layout(width='325px', grid_template_rows='90px 40px 35px 35px 35px 35px 35px 30px 30px 35px 35px 35px 35px 35px 35px 35px 80px 10px 75px 10px 35px 35px 35px', grid_template_columns='20% 10% 30% 15% 25%', grid_template_areas='''\n", - " \"logo2 logo2 logo2 logo2 logo2\" \n", - " \"methods2 methods2 methods2 methods2 methods2\"\n", - " \"beam_set beam_set beam_set beam_set beam_set\" \n", - " \"beam_set1 beam_set1 beam_set1 beam_set1 beam_set1\"\n", - " \"beam_set3 beam_set3 beam_set3 beam_set3 beam_set3\"\n", - " \"beam_set4 beam_set4 beam_set4 beam_set4 beam_set4\"\n", - " \"aperture_name beam_set2 beam_set2 beam_set2 beam_set2\"\n", - " \". sidebar2 sidebar2 sidebar2 sidebar5\"\n", - " \"scanning_set scanning_set scanning_set scanning_set scanning_set\" \n", - " \"scanning_set1 scanning_set1 scanning_set1 scanning_set1 scanning_set1\"\n", - " \"scanning_set2 scanning_set2 scanning_set2 scanning_set2 scanning_set2\"\n", - " \"scanning_set3 scanning_set3 scanning_set3 scanning_set3 scanning_set3\"\n", - " \"camera_set camera_set camera_set camera_set camera_set\"\n", - " \"cl_set1 cl_set1 cl_set1 cl_set1 cl_set1\"\n", - " \"camera_name camera_set1 camera_set1 camera_set1 camera_set1\"\n", - " \"restriction_name camera_set2 camera_set2 camera_set2 camera_set2\"\n", - " \"binning_name camera_set3 camera_set3 camera_set3 camera_set3\"\n", - " \". . . . .\"\n", - " \". . . . .\"\n", - " \". . . . .\"\n", - " \"visual_set visual_set visual_set visual_set visual_set\"\n", - " \"name1 name1 gr_size2 gr_size2 gr_size2\"\n", - " \"charts charts charts charts charts\"\n", - " '''))\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "### SMALL CONTROLS ##########################################\n", - "style = {'description_width': 'initial'}\n", - "element = Dropdown(options=opt.elements(), description='Element (ITR)', layout=Layout(width='95%', grid_area='ctf_element'))\n", - "ctf_xaxis_name = Label(value = 'x-axis',layout=Layout(width='95%', grid_area='ctf_xaxis_name'),)\n", - "ctf_xaxis = ToggleButtons(options=['α','mrad', 'Å'], layout=Layout(grid_area='ctxaxis'), style = {'button_width': '30%'}, disabled=False)\n", - "overlap_fig = ToggleButtons(options=['Geometrical','Intensity'], layout=Layout(grid_area='overlap_fig'), style = {'button_width': '45%'}, disabled=False)\n", - "beam_pos = IntSlider(value=4, min=4, max=16, step=2, description='Add beams:', disabled=False, continuous_update=False, orientation='horizontal', readout=True, readout_format='d', layout=Layout(grid_area='beam_pos', width = '100%'))\n", - "\n", - "fov_show = FloatSlider(value=0.3, min=0.1, max=10, step=0.1, description='FoV (nm):', disabled=False, continuous_update=False, orientation='horizontal', readout=True, readout_format='.1f', layout=Layout(grid_area='fov_show', width = '100%'))\n", - "top_set = Button(description='',layout=Layout(width='%', grid_area='scanning_set'), style=ButtonStyle(button_color='white', font_weight= 'bold',font_size= '16px',text_color='#0d48a1'),disabled = True)\n", - "red_box = Dropdown(options=[('tiny', 0.1), ('small', 0.2), ('middle', 0.3), ('large', 0.4), ('whole', 0.5)], value=0.1, description='Uniformity box', layout=Layout(grid_area='red_box', width = '95%'),style=style)\n", - "\n", - "\n", - "box_col = ColorPicker(concise=False,description='',value='cyan',disabled=False, layout=Layout(grid_area='box_col', width = '85%'),)\n", - "\n", - "\n", - "\n", - "\n", - "check0name = widgets.IntRangeSlider(value=[1, 6],min=0, max=10,step=1,description='Detector cover (α):',disabled=False,continuous_update=False,orientation='horizontal',readout=True, readout_format='d',layout=Layout(grid_area='check0name', width = '100%'),style=style)\n", - "check1name = widgets.IntSlider(value=10,min=0,max=20,step=5,description='Low angle approx. (°):', disabled=False,continuous_update=False,orientation='horizontal',readout=True,readout_format='d',layout=Layout(grid_area='check1name', width = '100%'),style=style)\n", - "check2name = widgets.Checkbox(value=False,description='Superresolution (ITR)',disabled=False, indent=False,layout=Layout(grid_area='check2name'))\n", - "check3name = widgets.Checkbox(value=True, description='Recon. box coverage (ITR)',disabled=False, indent=False,layout=Layout(grid_area='check3name'))\n", - "check4name = widgets.IntSlider(value=70,min=0,max=100,step=5,description='Beam overlap (%):', disabled=False,continuous_update=False,orientation='horizontal',readout=True,readout_format='d',layout=Layout(grid_area='check4name', width = '100%'),style=style)\n", - "check6name = widgets.Checkbox(value=False,description='Overall sampling (ITR)',disabled=False, indent=False,layout=Layout(grid_area='check6name'),style=style)\n", - "\n", - "sample_set= Button(description='Sample',layout=Layout(width='100%', grid_area='sample_set'), style=ButtonStyle(button_color='#F5F5F5', font_weight= 'bold',font_size= '16px',text_color='black'),disabled = True)\n", - "ctf_set = Button(description='PCTF',layout=Layout(width='100%', grid_area='ctf_set'), style=ButtonStyle(button_color='#F5F5F5', font_weight= 'bold',font_size= '16px',text_color='black'),disabled = True)\n", - "cl_set = Button(description='Camera length based limitations and checks', layout=Layout(width='100%', grid_area='cl_set'), style=ButtonStyle(button_color='#F5F5F5', font_weight= 'bold',font_size= '16px',text_color='black'), disabled = True)\n", - "\n", - "small_controls = GridBox(children=[sample_set, ctf_set, ctf_xaxis, element, beam_pos, fov_show, cl_set, overlap_fig, red_box, box_col, check0name, check1name, check2name, check3name,check4name, check6name, ctf_xaxis_name],\n", - " layout=Layout(width='109%', grid_template_rows='35px 35px 35px 35px 5px', grid_template_columns='4% 3.5% 14% 1.5% 8% 8% 8% 1% 27% 13%', grid_template_areas='''\n", - " \". ctf_set ctf_set . sample_set overlap_fig overlap_fig . cl_set cl_set \" \n", - " \". ctf_xaxis_name ctxaxis . fov_show fov_show fov_show . check0name check2name \"\n", - " \". ctf_element ctf_element . beam_pos beam_pos beam_pos . check4name check6name \"\n", - " \". . . . red_box red_box box_col . check1name check3name \"\n", - " \". . . . . . . . . . \"'''))\n", - "\n", - "\n", - "\n", - "def ptycho_interact(beam, aperture, aperture_res, aperture_res2, probe, cl, matrix, defocus, mag, camera, binning, dwell_time, restriction, method, ctf_xaxis, element, graph_size, chart, beam_pos, fov_show, overlap_fig, red_box, box_col, check0name, check1name,\n", - " check2name, check3name, check4name, check6name):\n", - " \n", - " ### SINGLE SETTING PARAMETERS ###\n", - " # beam ... energy in keV\n", - " pctf_itr = pty.get_ctf(element)\n", - " omega_itr = np.array(pty.get_omegas())\n", - " wavelength = pty.get_wavelength(beam)*1e12 # in pm\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) # in nm\n", - " step_size_corr = np.array(pty.get_step_correction())*pty.get_step_size(matrix) # in nm\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)/(size_pixel/1e6)/1000 # now in nm\n", - " oversampling = (wavelength/1000)/(2*pixel_angle/1000*step_size_corr)\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*size_pixel/1e6)/1e4\n", - " \n", - " probe_window_all = (wavelength*np.array(opt.cameralengths_eff())/100)/(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)/np.tan(semi_angle_corr/1000)\n", - " max_defocus_all[max_defocus_all < 0] = 'nan'\n", - " omega = np.linspace(1e-6,2,100) \n", - " pctf = pty.get_ssb_ctf()\n", - " apertury = opt.apertures()\n", - " oversampling_all = (wavelength/1000)/(2*pixel_covers/1000*step_size_corr)\n", - " \n", - "\n", - " \n", - "\n", - " ### SAMPLE PLANE ##########################################\n", - " if overlap_fig == 'Geometrical': \n", - " wid = np.linspace(-beam_pos/2,beam_pos/2,beam_pos+1) * step_size_corr\n", - " yyy = np.append(np.linspace(0,overlap,100), 200)\n", - " \n", - " fig5 = make_subplots(specs=[[{\"secondary_y\": True}]])\n", - " fig5.update_xaxes(title_text=\"Sample plane (nm)\", range=[-fov_show/2, fov_show/2], showgrid=False, zeroline=False)\n", - " fig5.update_yaxes(range=[-fov_show/2, fov_show/2],showgrid=False, showticklabels=False)\n", - " \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='black'),secondary_y=False)\n", - " \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_annotation(x=-1*step_size_corr, y=-2*step_size_corr, ax=-2*step_size_corr, ay=-2*step_size_corr, xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=2,arrowsize=2,arrowwidth=1,arrowcolor='red')\n", - " fig5.add_annotation(x=-2*step_size_corr, y=-1*step_size_corr, ax=-2*step_size_corr, ay=-2*step_size_corr, xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=2,arrowsize=2,arrowwidth=1,arrowcolor='red')\n", - " fig5.add_annotation(x=2*step_size_corr-0.75*beam_diameter/2, y=-2*step_size_corr-0.75*beam_diameter/2, ax=2*step_size_corr, ay=-2*step_size_corr,xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=2,arrowsize=2,arrowwidth=1,arrowcolor='magenta')\n", - " fig5.add_annotation(x=2*step_size_corr+0.75*beam_diameter/2, y=-2*step_size_corr+0.75*beam_diameter/2, ax=2*step_size_corr, ay=-2*step_size_corr,xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=2,arrowsize=2,arrowwidth=1,arrowcolor='magenta')\n", - " fig5.add_trace(go.Scatter(showlegend=True, x=[-1], y=[-1],marker_size=12, marker_color='red', name='Step size '+str(np.round(10*step_size_corr,2))+' Å')) \n", - " fig5.add_trace(go.Scatter(showlegend=True, x=[-1], y=[-1],marker_size=12, marker_color='magenta', name='Beam ⌀ '+str(np.round(10*beam_diameter,2))+' Å')) \n", - " \n", - " if method == 'direct':\n", - " xx = wavelength/(np.sin(semi_angle_corr*omega/1000))/100\n", - " fig5.add_trace(go.Scatter(showlegend=True, x=[-1], y=[-1],marker_size=12, marker_color='green', name='Rec step '+str(np.round(xx[-1]/3,2))+' Å')) \n", - " fig5.update_layout(legend=dict(orientation=\"v\",yanchor=\"bottom\",y=1.0,xanchor=\"right\",x=0.9))\n", - "\n", - " fig5.add_trace(go.Scatter(showlegend=False, x = -fov_show/2*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", - " fig5.update_yaxes(range=[0, 100], showgrid=False, showticklabels=False, secondary_y=True)\n", - " fig5.update_yaxes(title_text=\"Overlap (%)\", showgrid=False, showticklabels=True, tickvals = [-fov_show/2, -fov_show/4, 0, fov_show/4, fov_show/2],ticktext = ['0', '25', '50', '75', '100'], secondary_y=False)\n", - " fig5.update_layout(legend=dict(orientation=\"v\",yanchor=\"bottom\",y=1.01,xanchor=\"right\",x=0.9))\n", - " fig5.update_layout(plot_bgcolor='white')\n", - " fig5.update_xaxes(mirror=True,ticks='outside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", - " fig5.update_yaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", - "\n", - " if method == 'direct':\n", - " fig5.update_layout(width=3.6*graph_size, height=4*graph_size, margin =dict(l=0.6*graph_size, r=0.3*graph_size, t=0.1*graph_size, b=0.7*graph_size))\n", - " fig5.update_layout(title={'text': \"Sample\",'y': 0.87, 'x': 0.17,'xanchor': 'left','yanchor': 'top'})\n", - " if method == 'iterative':\n", - " fig5.update_layout(legend=dict(orientation=\"h\",yanchor=\"bottom\",y=1.01,xanchor=\"right\",x=1))\n", - " fig5.update_layout(title={'text': \"Sample\",'y': 0.98, 'x': 0.14,'xanchor': 'left','yanchor': 'top'})\n", - " fig5.update_layout(width=4.1*graph_size, height=3.1*graph_size, margin =dict(l=1.3*graph_size, r=0.0*graph_size, t=0.1*graph_size, b=0))\n", - "\n", - "\n", - " elif overlap_fig == 'Intensity':\n", - "\n", - " ### INTENSIY DISTRIBUTION ##################################\n", - " # create a text trap and redirect stdout\n", - " text_trap = io.StringIO()\n", - " sys.stdout = text_trap\n", - " \n", - " sampling= 0.02 # sampling of the simulated potential in A\n", - "\n", - " probe = Probe(sampling = sampling, extent = 2*beam_diameter*10, energy = beam*1e3, semiangle_cutoff = semi_angle_corr, defocus = defocus*10)\n", - " # probe = Probe(sampling=sampling, extent= A , energy=beam*1e3 eV, semiangle_cutoff = mrad, defocus= A)\n", - " intensity = probe.build().intensity().compute()\n", - " intensity = intensity.array\n", - " # # now restore stdout function\n", - " sys.stdout = sys.__stdout__\n", - "\n", - " x_pix = int(step_size_corr*10/sampling) # step size from nm to A\n", - " field = np.zeros([intensity.shape[0]+(beam_pos)*x_pix, intensity.shape[1]+(beam_pos)*x_pix])\n", - " cen = int(intensity.shape[0]/2)\n", - " o = int(intensity.shape[0]/2)\n", - " for i in range(0,beam_pos+1):\n", - " for j in range(0,beam_pos+1):\n", - " xx = x_pix*i\n", - " xy = x_pix*j\n", - " field[cen-o+xy : cen+o+xy, cen-o+xx : cen+o+xx] = field[cen-o+xy : cen+o+xy, cen-o+xx : cen+o+xx] + intensity\n", - "\n", - " field_cen = int(field.shape[0]/2)\n", - " middle = field[int(field_cen-(x_pix*(beam_pos)*red_box)): int(field_cen+(x_pix*(beam_pos)*red_box)), int(field_cen-(x_pix*(beam_pos)*red_box)): int(field_cen+(x_pix*(beam_pos)*red_box))]\n", - " uniformity = (1-((np.max(middle)-np.min(middle))/np.max(middle)))*100\n", - " \n", - " fig5 = go.Figure() \n", - " fig5.add_trace(px.imshow(field).data[0],)\n", - "\n", - " field_size = int(field.shape[0]) \n", - " field_cen = int(field.shape[0]/2) \n", - " \n", - " fig5.add_shape(type=\"rect\",x0= field_cen-red_box*field_size, y0=field_cen-red_box*field_size, x1= field_cen+red_box*field_size, y1=field_cen+red_box*field_size,line=dict(color=box_col),)\n", - " fig5.update_layout(title={'text': \"Uniformity: \"+str(np.round(uniformity,1))+\"%\",'y':0.96, 'x':0.35,'xanchor': 'left','yanchor': 'top'})\n", - " fig5.update_traces(dict(showscale=False, coloraxis=None, colorscale='plasma'), selector={'type':'heatmap'})\n", - "\n", - " fig5.update_yaxes(showticklabels=False)\n", - " fig5.update_xaxes(mirror=True,ticks='outside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", - " fig5.update_xaxes(title_text=\"Sample plane (nm)\", showgrid=False, showticklabels=True, tickvals = [0, field.shape[0]/2, field.shape[0]-1], \n", - " ticktext = [0, np.round((field.shape[0]/2)*sampling,1), np.round((field.shape[0]-1)*sampling)])\n", - "\n", - " \n", - " if method == 'direct':\n", - " fig5.update_layout(width=3.2*graph_size, height=3.2*graph_size, margin =dict(l=0.4*graph_size, r=0.05*graph_size, t=0.3*graph_size, b=0))\n", - "\n", - " if method == 'iterative':\n", - " fig5.update_layout(width=3.9*graph_size, height=3.1*graph_size, margin =dict(l=1.3*graph_size, r=0.2*graph_size, t=0.3*graph_size, b=0))\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - " ### DETECTOR PLANE ##########################################\n", - " fig6 = make_subplots(specs=[[{\"secondary_y\": True}]])\n", - " # fig6.update_xaxes(title_text=\"\", range=[0.5, num_pixels+0.5], tickvals = [1, num_pixels/2+0.5, num_pixels], ticktext = [1, \"Detector pixel array\", num_pixels], showticklabels=True,showgrid=True) \n", - "\n", - " fig6.update_xaxes(title_text=\"Detector pixel array\", range=[0.5, num_pixels+0.5], tickvals = [1, num_pixels/2+0.5, num_pixels], ticktext = [1, num_pixels/2, num_pixels], showticklabels=True,showgrid=True) \n", - " fig6.update_yaxes(range=[0.5, num_pixels+0.5], showticklabels=False, showgrid=False, secondary_y=False)\n", - " fig6.add_shape(type=\"circle\",xref=\"x\", yref=\"y\",opacity=0.5, fillcolor=\"#FF7F7F\", x0=(num_pixels+1)/2-beam_diameter_pix/2, y0=(num_pixels+1)/2-beam_diameter_pix/2, x1=(num_pixels+1)/2+beam_diameter_pix/2, y1=(num_pixels+1)/2+beam_diameter_pix/2,line_color=\"red\",secondary_y=False)\n", - " fig6.add_shape(type=\"rect\",xref=\"x\", yref=\"y\",opacity=0.5, fillcolor=\"#f0f921\", x0=0.5, y0=0.5, x1=1.5, y1=1.5,line_color=\"#000004\",secondary_y=False)\n", - " fig6.add_trace(go.Scatter(showlegend=True, x=[0], y=[0],marker_size=12, marker_color='#FF7F7F', name='Cover angle '+str(np.round(detector_cover,1))+' mrad', opacity = 0)) \n", - " fig6.add_annotation(x=(num_pixels+1)/2-beam_diameter_pix/2, y=(num_pixels+1)/2, ax=(num_pixels+1)/2+beam_diameter_pix/2, ay=(num_pixels+1)/2, xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=2,arrowsize=2,arrowwidth=1,arrowcolor='black')\n", - " fig6.add_annotation(x=(num_pixels+1)/2+beam_diameter_pix/2,y=(num_pixels+1)/2, ax=(num_pixels+1)/2-beam_diameter_pix/2, ay=(num_pixels+1)/2, xref='x',yref='y',axref='x',ayref='y', text='', showarrow=True,arrowhead=2,arrowsize=2,arrowwidth=1,arrowcolor='black')\n", - " fig6.add_annotation(x=(num_pixels+1)/2, y=(num_pixels+1)/2, text=str(np.round(beam_diameter_pix,1))+\" pix\", showarrow=False, yshift=10)\n", - " fig6.add_annotation(x=1, y=1, text=str(np.round(size_pixel,2))+\" μm ≈ \" +str(np.round(pixel_angle,4))+\" mrad\", showarrow=False, xshift=70+(50/np.sqrt(num_pixels)), yshift=10+(50/np.sqrt(num_pixels)))\n", - " fig6.add_trace(go.Scatter(showlegend=False,x=[-1], y=[-1]),secondary_y=True)\n", - " fig6.update_yaxes(title_text=\"\", range=[-1, 1], showticklabels=False, showgrid=False, tickvals = [-1, 0, 0.85], ticktext = [\"\", \"Max cover angle (mrad)\", str(np.round(detector_cover,1))], secondary_y=True) \n", - " fig6.update_yaxes(tickangle=-90)\n", - " fig6.update_layout(legend=dict(orientation=\"v\",yanchor=\"bottom\",y=1.01,xanchor=\"right\",x=0.9))\n", - " fig6.update_layout(plot_bgcolor='white')\n", - " fig6.update_xaxes(mirror=True,ticks='outside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", - " fig6.update_yaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", - " fig6.update_layout(title={'text': \"Detector\",'y':0.975, 'x': 0.09,'xanchor': 'left','yanchor': 'top'})\n", - " fig6.update_layout(width=2.9*graph_size, height=3.1*graph_size, margin =dict(l=0.1*graph_size, r=0.1*graph_size, t=0.1*graph_size, b=0)) \n", - " \n", - " focusdepth = wavelength/(semi_angle_corr/1000)**2/1000\n", - " ssb_cl, kolik = pty.cl4ssb(detector_cover_a_all)\n", - "\n", - "\n", - " \n", - " ### MICROSCOPE SCHEME ##########################################\n", - " width = 500 # in-graph setting\n", - " det_width = 400 # in-graph setting\n", - " y_down = np.log(np.max(opt.cameralengths()))\n", - " reduc = 0.4 # in-graph setting\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", - " fig8.add_shape(type=\"rect\",xref=\"x\", yref=\"y\",opacity=0.05, fillcolor=\"gray\", x0=-width, y0=-y_down, x1=width, y1=reduc*y_down,line_color=\"gray\")\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=\"Aperture \", showarrow=False, yshift=2)\n", - " fig8.add_annotation(x=-0.7*width, y=reduc*0.8*y_down, text=str(aperture), showarrow=False, yshift=-15)\n", - " fig8.add_annotation(x=0.0*width, y=-y_down,text='Acquisition time (s) '+ str(np.round(matrix*matrix*dwell_time/1e6,1)), showarrow=False, yshift=-10)\n", - " fig8.add_annotation(x=0, y=reduc*0.96*y_down,text='λ (pm) '+ str(np.round((pty.get_wavelength(beam)*1e12),2)), showarrow=False, 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=70, 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.7*width, y=0,text=\"Sample\", 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.4*width, y=0.05*y_down,text=\"FoV \"+str(np.round(fov,2))+\" nm\", showarrow=False, yshift=0)\n", - " fig8.add_annotation(x=0.5*width, y=0.05*y_down,text=\"Dose \"+str(np.round(dose,1))+\" e/Å2\", showarrow=False, yshift=-40)\n", - " fig8.add_annotation(x=-0.5*width, y=0.05*y_down,text=\"DoF \"+str(np.round(focusdepth,1))+\" nm\", showarrow=False, yshift=-40)\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.7*width, y=-np.log(cl),text=\"Detector\", showarrow=False,align= 'left', yshift=15)\n", - " fig8.add_annotation(x=-0.7*width, y=-np.log(cl),text=str(np.round(cl_det,2))+' cm', showarrow=False,align= 'left', yshift=-15) \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", - " if method == 'direct':\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*width, y=-np.log(ssb_cl),text=\"\", 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=\"PAAR\", 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.85*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(width=3.5*graph_size, height=7.2*graph_size, margin = dict(l=0.3*graph_size, r=0, t=0.0*graph_size, b=0))\n", - " fig8.update_layout(plot_bgcolor='white')\n", - "\n", - "\n", - " \n", - " ### METHODS ########################################## \n", - " if method == 'direct':\n", - " \n", - " xx = wavelength/(np.sin(semi_angle_corr*omega/1000))/100 # pitch size\n", - " \n", - " ### PROBE ##########################################\n", - " fig = go.Figure() \n", - " fig.update_yaxes(title_text=\"Transfer (-)\")\n", - "\n", - " if ctf_xaxis == 'α': \n", - " fig.add_trace(go.Scatter(showlegend=True, x=omega, y=pctf, marker_color='red', name='Common for all',))\n", - " fig.update_xaxes(title_text=\"Scattering angle (α)\", range=[0, 2], zeroline=False)\n", - " \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='black', name='SSB-CTF',))\n", - "\n", - " fig.add_trace(go.Scatter(showlegend=False, x=semi_angle_corr*omega, y=pctf, marker_color='red'))\n", - " fig.update_layout(legend=dict(orientation=\"h\",yanchor=\"bottom\",y=0.85,xanchor=\"right\",x=1))\n", - " fig.update_xaxes(title_text=\"Spacial frequency (mrad)\", range=[0, 60], zeroline=False)\n", - " \n", - " elif ctf_xaxis == 'Å':\n", - " for x in apertury:\n", - " d = wavelength/(np.sin(pty.get_angle_corr(x)*omega/1000))/100 # Full pitch size\n", - " fig.add_trace(go.Scatter(showlegend=False, x=d, y=pctf, marker_color='black', name='SSB-CTF',))\n", - "\n", - " fig.add_trace(go.Scatter(showlegend=False, x=xx, y=pctf, marker_color='red'))\n", - " fig.update_xaxes(title_text=\"Real space distance (Å)\", range=[-1, 2], type=\"log\", zeroline=False)\n", - "\n", - " fig.update_layout(legend=dict(orientation=\"v\",yanchor=\"bottom\",y=1.01,xanchor=\"right\",x=0.9))\n", - " fig.update_layout(title={'text': \"PCTF\",'y':0.7, 'x':0.28,'xanchor': 'left','yanchor': 'top'})\n", - " fig.update_layout(plot_bgcolor='white')\n", - " fig.update_xaxes(mirror=True,ticks='outside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", - " fig.update_yaxes(mirror=True,ticks='outside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", - " fig.update_layout(width=4.95*graph_size, height=3.3*graph_size, margin = dict(l=1.3*graph_size, r=0.25*graph_size, t=1.2*graph_size, b=0.3*graph_size))\n", - " \n", - "\n", - "\n", - "\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='black'), secondary_y=False,)\n", - " fig4.add_trace(go.Scatter(showlegend=False, x=opt.cameralengths(), y=detector_cover_a_all,marker_color='black'), 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 = \"Recommended CL\"), secondary_y=True,) \n", - " fig4.update_layout(legend=dict(orientation=\"v\",yanchor=\"bottom\",y=0.75,xanchor=\"right\",x=0.9))\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=5.25*graph_size, height=3*graph_size, margin =dict(l=1.3*graph_size, r=0.25*graph_size, t=0.3*graph_size, b=0.3*graph_size))\n", - " fig4.update_layout(legend=dict(orientation=\"v\",yanchor=\"bottom\",y=1.01,xanchor=\"right\",x=0.9), plot_bgcolor='white')\n", - " fig4.update_xaxes(mirror=True,ticks='outside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", - " fig4.update_yaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", - " fig4.update_layout(title={'text': \"CL\",'y':0.87, 'x':0.26,'xanchor': 'left','yanchor': 'top'})\n", - " \n", - " \n", - " elif method == 'iterative': \n", - " ### PROBE ##########################################\n", - " pctf_norm = pctf_itr/np.max(pctf_itr)\n", - "\n", - " fig = go.Figure() \n", - " fig.update_yaxes(title_text=\"Transfer (-)\")\n", - " match ctf_xaxis: \n", - " case 'α':\n", - " fig.add_trace(go.Scatter(showlegend=False, x=omega_itr, y= pctf_norm, marker_color='red',))\n", - " fig.update_xaxes(title_text=\"Scattering angle (α)\", range=[0, 5], zeroline=False)\n", - " fig.update_yaxes(range=[0, 1.1])\n", - " \n", - " case 'mrad': \n", - " for x in apertury:\n", - " fig.add_trace(go.Scatter(showlegend=False, x=pty.get_angle_corr(x)*omega_itr, y=pctf_norm, marker_color='black', name='',))\n", - " \n", - " fig.add_trace(go.Scatter(showlegend=False, x=semi_angle_corr*omega_itr, y=pctf_norm, marker_color='red'))\n", - " fig.update_xaxes(title_text=\"Spacial frequency (mrad)\", range=[0, 100], zeroline=False)\n", - "\n", - " case 'Å':\n", - " for x in apertury:\n", - " d = wavelength/(np.sin(pty.get_angle_corr(x)*omega_itr/1000))/100\n", - " fig.add_trace(go.Scatter(showlegend=False, x=d, y=pctf_norm, marker_color='black', name='CTF'))\n", - " \n", - " xx = wavelength/(np.sin(semi_angle_corr*omega_itr/1000))/100\n", - " fig.add_trace(go.Scatter(showlegend=False, x=xx, y=pctf_norm, marker_color='red'))\n", - " fig.update_xaxes(title_text=\"Real space distance (Å)\",range=[-1, 2], type=\"log\", zeroline=False) # \n", - "\n", - " fig.update_layout(legend=dict(orientation=\"h\",yanchor=\"bottom\",y=0.8,xanchor=\"right\",x=0.95))\n", - " fig.update_layout(width=4.25*graph_size, height=2.2*graph_size, margin = dict(l=1.3*graph_size, r=0.3*graph_size, t=0.22*graph_size, b=0.7*graph_size))\n", - " fig.update_layout(title={'text': \"PCTF\",'y':0.99, 'x':0.33,'xanchor': 'left','yanchor': 'top'})\n", - " fig.update_layout(legend=dict(orientation=\"v\",yanchor=\"bottom\",y=1.01,xanchor=\"right\",x=0.9),plot_bgcolor='white')\n", - " fig.update_xaxes(mirror=True,ticks='outside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", - " fig.update_yaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " ### FINAL CHECKS ########################################## \n", - " align_check = dict(layout=Layout(width='235px') , style = {'description_width': '140px','button_width': \"95px\"}, disabled=True,) \n", - " check1 = Valid(value= bool(overlap > check4name), description='Beam overlap', **align_check)\n", - " check2 = Valid(value= bool(step_size_corr*10 > (wavelength * cl_det)/(num_pixels*size_pixel/1e6)/1e4), description='Superresolution', **align_check)\n", - " check3 = Valid(value= bool(beam_diameter/2 < probe_window/2), description='Recon. box coverage', **align_check) \n", - " check4 = Valid(value= bool(oversampling > 1), description='Overall sampling', **align_check) \n", - "\n", - " \n", - " checks = VBox([check1, check2, check3, check4]) # Label('Final checks')\n", - " checks.layout = Layout(margin='30px 0px 00px 240px', padding='5px 5px 5px 5px') # border='dashed 1px gray',\n", - "\n", - " \n", - "\n", - " \n", - " ### PROBE WINDOW ##########################################\n", - " if overlap_fig == 'Geometrical': \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=\"#6F6F6F\", x0=probe_window/4, y0=probe_window/4, x1=3*probe_window/4, y1=3*probe_window/4,line_color=\"#6F6F6F\")\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, opacity = 0))\n", - " fig7.add_shape(type=\"circle\",xref=\"x\", yref=\"y\", opacity=0.2, fillcolor=color, x0=probe_window/2-beam_diameter/8, y0=probe_window/2-beam_diameter/8, x1=probe_window/2+beam_diameter/8, y1=probe_window/2+beam_diameter/8, line_color=color,)\n", - " fig7.add_shape(type=\"circle\",xref=\"x\", yref=\"y\", opacity=0.2, fillcolor=color, x0=probe_window/2-beam_diameter/6, y0=probe_window/2-beam_diameter/6, x1=probe_window/2+beam_diameter/6, y1=probe_window/2+beam_diameter/6, line_color=color,)\n", - " fig7.add_shape(type=\"circle\",xref=\"x\", yref=\"y\", opacity=0.2, fillcolor=color, x0=probe_window/2-beam_diameter/5, y0=probe_window/2-beam_diameter/5, x1=probe_window/2+beam_diameter/5, y1=probe_window/2+beam_diameter/5, line_color=color,)\n", - " fig7.add_shape(type=\"circle\",xref=\"x\", yref=\"y\", opacity=0.2, fillcolor=color, x0=probe_window/2-beam_diameter/4.25, y0=probe_window/2-beam_diameter/4.25, x1=probe_window/2+beam_diameter/4.25, y1=probe_window/2+beam_diameter/4.25, line_color=color,)\n", - " fig7.add_shape(type=\"circle\",xref=\"x\", yref=\"y\", opacity=0.2, fillcolor=color, x0=probe_window/2-beam_diameter/3.5, y0=probe_window/2-beam_diameter/3.5, x1=probe_window/2+beam_diameter/3.5, y1=probe_window/2+beam_diameter/3.5, line_color=color,)\n", - " fig7.add_shape(type=\"circle\",xref=\"x\", yref=\"y\", opacity=0.2, fillcolor=color, x0=probe_window/2-beam_diameter/3, y0=probe_window/2-beam_diameter/3, x1=probe_window/2+beam_diameter/3, y1=probe_window/2+beam_diameter/3, line_color=color,)\n", - " fig7.add_shape(type=\"circle\",xref=\"x\", yref=\"y\", opacity=0.2, fillcolor=color, x0=probe_window/2-beam_diameter/2.5, y0=probe_window/2-beam_diameter/2.5, x1=probe_window/2+beam_diameter/2.5, y1=probe_window/2+beam_diameter/2.5, line_color=color,)\n", - " fig7.add_shape(type=\"circle\",xref=\"x\", yref=\"y\", opacity=0.4, 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=\"Reconstruction box (nm)\", range=[0, probe_window], tickvals = [0, probe_window/4, probe_window/2, 3*probe_window/4, probe_window], ticktext = [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)])\n", - " fig7.update_yaxes(range=[0, probe_window], tickvals = [0, probe_window/4, probe_window/2, 3*probe_window/4, probe_window], showticklabels=False,)\n", - " fig7.update_yaxes(range=[0, probe_window], showticklabels=False,)\n", - " fig7.update_yaxes(range=[0, probe_window], showticklabels=False,)\n", - " fig7.update_layout(legend=dict(orientation=\"v\",yanchor=\"bottom\",y=1.01,xanchor=\"right\",x=1),title={'text': \"Probe\",'y':0.975, 'x':0.05,'xanchor': 'left','yanchor': 'top'})\n", - " fig7.update_layout(width=2.7*graph_size, height=3.1*graph_size, margin =dict(l=0, r=0, t=0.1*graph_size, b=0)) \n", - " fig7.update_layout(plot_bgcolor='white')\n", - " fig7.update_xaxes(mirror=True,ticks='outside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", - " fig7.update_yaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", - "\n", - "\n", - " ####################\n", - " ####################\n", - " ####################\n", - " ####################\n", - " ####################\n", - " elif method == 'iterative': \n", - " sampling= 0.1 # sampling of the simulated potential in A\n", - " probe = Probe(sampling = sampling, extent = 2*probe_window*10, energy = beam*1e3, semiangle_cutoff = semi_angle_corr, defocus = defocus*10)\n", - " # probe = Probe(sampling=sampling, extent= A , energy=beam*1e3 eV, semiangle_cutoff = mrad, defocus= A)\n", - " intensity2 = probe.build().intensity().compute()\n", - " intensity2 = intensity2.array\n", - " inten = intensity2/np.max(intensity2)\n", - " \n", - " cen2 = inten.shape\n", - " sirkaA = cen2[0]*sampling\n", - " sirkaB = probe_window*10/sampling\n", - "\n", - " just_probe_window = inten[int(cen2[0]/2)-int(sirkaB/2) : int(cen2[0]/2)+int(sirkaB/2), int(cen2[0]/2)-int(sirkaB/2) : int(cen2[0]/2)+int(sirkaB/2)]\n", - " int_tot = np.sum(just_probe_window)/np.sum(inten)*100\n", - "\n", - " fig7 = go.Figure() \n", - " fig7.add_trace(px.imshow(inten).data[0],)\n", - " fig7.add_shape(type=\"rect\",x0= cen2[0]/2-sirkaB/2, y0=cen2[0]/2-sirkaB/2, x1= cen2[1]/2+sirkaB/2, y1=cen2[1]/2+sirkaB/2, line=dict(color=\"white\"),)\n", - " fig7.update_layout(title={'text': \"Probe cover \",'y':0.96, 'x':0.05,'xanchor': 'left','yanchor': 'top'})\n", - " fig7.update_layout(width=2.7*graph_size, height=2.65*graph_size, margin =dict(l=0.1*graph_size, r=0.1*graph_size, t=0.3*graph_size, b=0))\n", - " fig7.update_traces(dict(showscale=False, \n", - " coloraxis=None, \n", - " colorscale='plasma'), selector={'type':'heatmap'})\n", - " fig7.update_xaxes(showticklabels=False).update_yaxes(showticklabels=False)\n", - " fig7.add_annotation(x=cen2[0]/2, y=cen2[0]/2+sirkaB/2, text='Recon. box '+str(np.round(probe_window,2))+' nm', showarrow=False, yshift=15)\n", - " fig7.add_annotation(x=cen2[0]/2, y=cen2[0]/2-sirkaB/2, text='Probe covered '+str(np.round(int_tot,1))+' %', showarrow=False, yshift=-15)\n", - " fig7.update_annotations(font=dict(color=\"white\"))\n", - " # fig7.update_annotations(font=dict(family=\"sans serif\", size=18, color=\"red\"))\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - "\n", - " \n", - " \n", - "\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), opt.cameralengths(), np.round(oversampling_all,1)])\n", - "\n", - " align6 = dict(layout=Layout(width=str(int(graph_size/100*57))+'px') , style = {'description_width': '0px','button_width': str(int(graph_size/100*56))+'px'}, disabled=True,)\n", - " align7 = dict(layout=Layout(width='128px') , style = {'description_width': '0px','button_width': \"128px\"}, disabled=True,)\n", - " \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, 5.oversampling\n", - " data_tuple = tuple(tab[0:5,int(i)]) + (\"\",tab[5,int(i)])\n", - " icons=['','','','','']\n", - "\n", - "# check1name = 'Low anlge approximation'\n", - "# check2name = 'Ptycho pixel < step size'\n", - "# check3name = 'Beam fits in probe window'\n", - "# check4name = 'Detector cover < 1α'\n", - "# check5name = 'Detector cover > 6α'\n", - "# check6name = 'Oversampling > 1'\n", - "\n", - " if data[1] > 1000*np.radians(check1name):\n", - " button_style = 'danger' \n", - " \n", - " if check2name == True: \n", - " if data[0] > step_size_corr*10:\n", - " button_style = 'danger'\n", - " \n", - " if check3name == True: \n", - " if data[3] < defocus:\n", - " button_style = 'danger'\n", - " \n", - " if data[2] < check0name[0]:\n", - " button_style = 'danger' \n", - "\n", - " if data[2] > check0name[1]:\n", - " button_style = 'warning' \n", - "\n", - " if check6name == True: \n", - " if data[5] < 1:\n", - " button_style = 'danger' \n", - " \n", - " if cl == data[4]:\n", - " icons=['','','','','','check'] \n", - " \n", - " dictionary[i] = ToggleButtons(options=data_tuple, text_color= 'red', button_style=button_style, icons = icons, **align6)\n", - "\n", - " legend = ToggleButtons(options=['Ptycho pixel (Å)','Det. cover (mrad)','Det. cover (α)', 'Max. def. (nm)','Nominal CL (cm)','Selected by CL ','Oversampling'], \n", - " tooltips=['Dependent on: detector, beam energy, camera length', 'Dependent on: detector, camera length', 'Dependent on: detector, camera length, probe semi-angle', \n", - " 'Dependent on: detector, binning, beam energy, camera length, zero defocus beam diameter, probe semi-angle', 'Just nominal camera length'],button_style='', **align7) \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('Recommended parameters for proper ptychographic reconstruction.'), cltab])\n", - " cltab.layout = Layout(border='solid 0px gray',margin='10px 0px 10px 125px', padding='5px 5px 5px 5px')\n", - "\n", - "\n", - "\n", - " ### SHOWING ###\n", - " if method == 'direct': \n", - " match chart:\n", - " case 'micr':\n", - " total = HBox([go.FigureWidget(fig8)]) \n", - " case 'dedic':\n", - " total = VBox([ HBox([go.FigureWidget(fig) ,go.FigureWidget(fig5)]), HBox([go.FigureWidget(fig4),go.FigureWidget(fig6)])])\n", - " case _: \n", - " right_column = VBox([HBox([go.FigureWidget(fig) ,go.FigureWidget(fig5)]), HBox([go.FigureWidget(fig4),go.FigureWidget(fig6)])]) \n", - " left_column = go.FigureWidget(fig8)\n", - " total = HBox([left_column, right_column])\n", - " \n", - " total.layout = Layout(border='solid 0px gray',margin='0px 0px 0px 20px', padding='0px 0px 0px 0px') \n", - " display(total)\n", - "\n", - " elif method == 'iterative': \n", - " match chart:\n", - " case 'micr':\n", - " total = HBox([go.FigureWidget(fig8)])\n", - " case 'dedic':\n", - " sample_overlap = HBox([go.FigureWidget(fig5), go.FigureWidget(fig7), go.FigureWidget(fig6)]) \n", - " total = VBox([HBox([go.FigureWidget(fig),go.FigureWidget(fig9)]), sample_overlap, HBox([cltab, checks])]) \n", - " case _:\n", - " sample_overlap = HBox([go.FigureWidget(fig5), go.FigureWidget(fig7), go.FigureWidget(fig6)]) \n", - " right_column = VBox([HBox([go.FigureWidget(fig), checks]) , sample_overlap, cltab]) \n", - " left_column = VBox([go.FigureWidget(fig8)]) \n", - " total = HBox([left_column, right_column]) \n", - " \n", - " total.layout = Layout(border='solid 0px gray',margin='0px 0px 0px 10px', padding='0px 0px 0px 10px') \n", - " display(total)\n", - "\n", - " return \n", - " \n", - "gui = interactive_output(ptycho_interact, {\"beam\": beam, \"aperture\": aperture,\"aperture_res\": aperture_res,\"aperture_res2\": aperture_res2, \"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, \"element\": element, \"graph_size\": graph_size,\"chart\": chart, \"beam_pos\": beam_pos, \n", - " \"fov_show\": fov_show, \"overlap_fig\":overlap_fig, \"red_box\": red_box, \"box_col\":box_col, \"check0name\":check0name, \"check1name\": check1name, \"check2name\": check2name, \"check3name\": check3name, \"check4name\": check4name, \"check6name\": check6name}) \n" + "## RUN ME" ] }, { "cell_type": "code", "execution_count": 3, - "id": "68780f2b-efa0-4240-870b-2b0876977e90", + "id": "fecbecdb-0fac-4ac8-a2b3-1ccb3f869a77", "metadata": {}, "outputs": [], "source": [ - "### Function definitions ###################################################\n", - "calib = r'calibrations.xlsx' # Path to the calibration file\n", - "class interaction: \n", - " \"\"\"Loads calibration settings and ranges from .xlsx file.\n", - " These are than used for widgets creation.\"\"\"\n", - " \n", - " def __init__(self):\n", - " self.calib = calib\n", + "### Initial packages import\n", + "import io\n", + "import sys\n", + "import numpy as np\n", + "import ipywidgets as widg\n", + "import scipy.constants as cons\n", + "import plotly.express as px\n", + "import plotly.graph_objects as go\n", + "from ptychoscopy import pty\n", + "from IPython.display import display\n", + "from plotly.subplots import make_subplots\n", "\n", - " def elements(self):\n", - " excel_data = read_excel(calib,sheet_name='CTF')\n", - " elements = [str(e) for e in list(excel_data.CTF)]\n", - " elements = [x for x in elements if x != 'nan']\n", - " return elements\n", + "try:\n", + " from abtem import Probe\n", + " abtem = True\n", + "except:\n", + " abtem = False\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", + "def show_wavelength(caller):\n", + " beam_res.value = f'λ (pm) {str(\"{:.1f}\".format(pty.get_wavelength(caller.new)*1e12))}'\n", + " return beam_res.value\n", + "def show_probe_angle(caller):\n", + " aperture_res.value = f'Semi-angle (mrad) {\"{:.1f}\".format(pty.get_angle(caller.new))}' \n", + " return aperture_res.value\n", + "def show_corrprobe_angle(caller):\n", + " aperture_res2.value = f'corr. {\"{:.2f}\".format(pty.get_angle_corr(caller.new))}'\n", + " return aperture_res2.value\n", + "def show_fov(caller):\n", + " fov_res.value = f'FoV (nm) {\"{:.1f}\".format(pty.get_fov(caller.new))}'\n", + " return fov_res.value\n", + "def show_frame_rate(caller):\n", + " dwell_time_res.value = f'Rate (kHz) {\"{:.1f}\".format(pty.get_aq_frec(caller.new))}' \n", + " return dwell_time_res.value\n", + "def show_cd_det(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", + "### MICROSCOPE CONTROL PANEL\n", + "image = open(\"ptychoscopy/logo.png\", \"rb\").read()\n", + "logo = widg.Image(value=image, format='png', layout=widg.Layout(grid_area='logo'))\n", + "ali = dict(style = {'description_width': '110px','button_width': '55px', 'font_weight': 'bold'}, button_style='', disabled = False)\n", + "ali2 = dict(style = {'description_width': '60px' ,'button_width': '90px', 'font_weight': 'bold'}, button_style='', disabled = False)\n", + "ali3 = dict(style = {'description_width': '110px','button_width': '45px', 'font_weight': 'bold'}, button_style='', disabled = False)\n", + "method = widg.ToggleButtons(options=[('SSB ','ssb'),('ITR ','iterative')],description='',icons=['opera','refresh'], tooltips=['Single side band ptychography', 'Iterative reconstruction methods (PIE, ML, DM)'],\n", + " layout=widg.Layout(width='95%', grid_area='methods'), style = {'button_width': '48%','font_weight': 'bold'}, button_style='', disabled = False)\n", + "### Electron beam settings\n", + "beam_set = widg.Button(description='Electron beam settings',layout=widg.Layout(width='95%',grid_area='beam_set'),style=widg.ButtonStyle(button_color='#222261',font_weight='bold',font_size='16px',text_color='white'),disabled=False) \n", + "beam_energy = widg.Dropdown(options=pty.load_energies(), value=200, description='Beam energy (keV)', layout=widg.Layout(width='95%', grid_area='beam_set1'), **ali)\n", + "probe_size = widg.Dropdown(options=pty.load_probes(), value='8C', description='Probe', layout=widg.Layout(width='95%', grid_area='beam_set3'), **ali)\n", + "defocus = widg.FloatSlider(description='Defocus (nm)', value=0, min=0, max=1000, step=5, readout_format='d',continuous_update=False, layout=widg.Layout(width='95%', grid_area='beam_set4'), **ali)\n", + "aperture_name = widg.Label(value = 'Aperture', layout=widg.Layout(width='95%', grid_area='aperture_name'),)\n", + "aperture = widg.ToggleButtons(options=pty.load_apertures(), description='', layout=widg.Layout(width='95%', grid_area='beam_set2'), **ali3)\n", + "\n", + "### Scanning parameters\n", + "scanning_set = widg.Button(description='Scanning parameters', layout=widg.Layout(width='95%', grid_area='scanning_set'),style=widg.ButtonStyle(button_color='#222261', font_weight= 'bold',font_size= '16px',text_color='white'),disabled = False)\n", + "mag = widg.Dropdown(options=pty.load_magnifications(), value=20, description='Magnification Mx', layout=widg.Layout(width='95%', grid_area='scanning_set1'), **ali)\n", + "matrix = widg.Dropdown(options=pty.load_mappings(), value=256, description='Matrix', layout=widg.Layout(width='95%', grid_area='scanning_set2'), **ali)\n", + "dwell_time = widg.Dropdown(options=pty.load_dwelltimes(), value=10, description='Dwell time (μs)', layout=widg.Layout(width='95%', grid_area='scanning_set3'), **ali)\n", + "\n", + "### Detection\n", + "camera_set = widg.Button(description='Detection',layout=widg.Layout(width='95%', grid_area='camera_set'),style=widg.ButtonStyle(button_color='#222261', font_weight= 'bold',font_size= '16px',text_color='white'),disabled = False)\n", + "cl = widg.Dropdown(options=pty.load_cameralengths(aperture, \"nominal\"), value=8, description='Nominal CL (cm)', layout=widg.Layout(width='95%', grid_area='cl_set1'), **ali3)\n", + "camera_name = widg.Label(value = 'Detector',layout=widg.Layout(width='95%', grid_area='camera_name'),)\n", + "camera = widg.ToggleButtons(options=pty.load_detectors(), description='', layout=widg.Layout(width='95%', grid_area='camera_set1'), style = {'description_width': '60px','button_width': str(100/len(pty.load_detectors())-len(pty.load_detectors()))+'%', 'font_weight': 'bold'}, button_style='')\n", + "restr_name = widg.Label(value = 'PAAR',layout=widg.Layout(width='95%', grid_area='restr_name'))\n", + "restr = widg.ToggleButtons(options=[('.',False), ('..',True)], value = False, description='',icons = ['ban','check'], layout=widg.Layout(width='95%', grid_area='camera_set2'),style = {'description_width': '80px','button_width': '48%', 'font_weight': 'bold'}, button_style='')\n", + "binning_name = widg.Label(value = 'Binning',layout=widg.Layout(width='95%', grid_area='binning_name'))\n", + "binning = widg.ToggleButtons(options=[('.',1), ('2',2), ('4',4), ('8',8), ('16',16), ('32',32), ('48',48)], value=1, description='', icons = ['ban','',''], layout=widg.Layout(width='95%', grid_area='camera_set3'), **ali3)\n", + "beam_res = widg.Label(value = f'λ (pm) ' + str(\"{:.1f}\".format(pty.get_wavelength(beam_energy.value)*1e12)),layout=widg.Layout(width='auto', grid_area='sidebar1'))\n", + "aperture_res = widg.Label(value = f'Semi-angle (mrad) '+ str(\"{:.1f}\".format(pty.get_angle(aperture.value))), layout=widg.Layout(width='auto', grid_area='sidebar2'))\n", + "aperture_res2 = widg.Label(value = f'corr. ' + str(\"{:.2f}\".format(pty.get_angle_corr(aperture.value))), layout=widg.Layout(width='auto', grid_area='sidebar5'))\n", + "fov_res = widg.Label(value = f'FoV (nm) ' + str(\"{:.1f}\".format(pty.get_fov(mag.value))), layout=widg.Layout(width='auto', grid_area='sidebar3')) \n", + "dwell_time_res= widg.Label(value = f'Rate (kHz) ' + str(\"{:.1f}\".format(pty.get_aq_frec(dwell_time.value))), layout=widg.Layout(width='auto', grid_area='sidebar4')) \n", + "mag.observe(show_fov, names='value') \n", + "beam_energy.observe(show_wavelength, names='value') \n", + "aperture.observe(show_probe_angle, names='value') \n", + "dwell_time.observe(show_frame_rate, names='value') \n", + "aperture.observe(show_corrprobe_angle, names='value') \n", + "\n", + "### Visualisation\n", + "visual_set = widg.Button(description='Visualisation',layout=widg.Layout(width='95%', grid_area='visual_set'),style=widg.ButtonStyle(button_color='white', font_weight= 'bold',font_size= '16px',text_color='black'),disabled = False)\n", + "name1 = widg.Button(description='Graphs (%)',layout=widg.Layout(width='95%', grid_area='name1'),style=widg.ButtonStyle(button_color='white', font_weight= 'bold',text_color='black'), disabled = False)\n", + "graph_size = widg.IntSlider(value=100,min=75,max=125,step=5, description='', layout=widg.Layout(width='95%', grid_area='gr_size2'), button_style='primary',disabled=False,)\n", + "\n", + "### Layout\n", + "controls = widg.GridBox(children=[logo, method, beam_energy, beam_set, aperture_name, aperture, probe_size, defocus, scanning_set, mag, matrix, dwell_time, cl,camera_set, camera, camera_name, restr_name, restr, binning_name,\n", + " binning, beam_res, aperture_res, aperture_res2, fov_res, dwell_time_res, graph_size, name1, visual_set],\n", + " layout=widg.Layout(width='325px', grid_template_rows='90px 40px 35px 35px 35px 35px 35px 30px 30px 35px 35px 35px 35px 35px 35px 35px 80px 95px 35px 35px 35px', grid_template_columns='20% 10% 30% 15% 25%', grid_template_areas='''\n", + " \"logo logo logo logo logo \" \n", + " \"methods methods methods methods methods \"\n", + " \"beam_set beam_set beam_set beam_set beam_set \" \n", + " \"beam_set1 beam_set1 beam_set1 beam_set1 beam_set1 \"\n", + " \"beam_set3 beam_set3 beam_set3 beam_set3 beam_set3 \"\n", + " \"beam_set4 beam_set4 beam_set4 beam_set4 beam_set4 \"\n", + " \"aperture_name beam_set2 beam_set2 beam_set2 beam_set2 \"\n", + " \". sidebar2 sidebar2 sidebar2 sidebar5 \"\n", + " \"scanning_set scanning_set scanning_set scanning_set scanning_set \" \n", + " \"scanning_set1 scanning_set1 scanning_set1 scanning_set1 scanning_set1\"\n", + " \"scanning_set2 scanning_set2 scanning_set2 scanning_set2 scanning_set2\"\n", + " \"scanning_set3 scanning_set3 scanning_set3 scanning_set3 scanning_set3\"\n", + " \"camera_set camera_set camera_set camera_set camera_set \"\n", + " \"cl_set1 cl_set1 cl_set1 cl_set1 cl_set1 \"\n", + " \"camera_name camera_set1 camera_set1 camera_set1 camera_set1 \"\n", + " \"restr_name camera_set2 camera_set2 camera_set2 camera_set2 \"\n", + " \"binning_name camera_set3 camera_set3 camera_set3 camera_set3 \"\n", + " \". . . . . \"\n", + " \"visual_set visual_set visual_set visual_set visual_set \"\n", + " \"name1 name1 gr_size2 gr_size2 gr_size2 \"'''))\n", + "\n", + "### GRAPH CONTROL\n", + "style = {'description_width': 'initial'}\n", + "top_set = widg.Button(description='',layout=widg.Layout(width='%', grid_area='scanning_set'), style=widg.ButtonStyle(button_color='white', font_weight= 'bold',font_size= '16px',text_color='#0d48a1'),disabled = True)\n", + "style_graph = widg.ButtonStyle(button_color='#F5F5F5', font_weight= 'bold',font_size= '16px',text_color='black')\n", + "\n", + "### PCTF\n", + "ctf_set = widg.Button(description='Phase CTF',layout=widg.Layout(width='100%', grid_area='ctf_set'), style=style_graph,disabled = True)\n", + "ctf_xaxis_name = widg.Label(value = 'x-axis',layout=widg.Layout(width='95%', grid_area='ctf_xaxis_name'),)\n", + "ctf_xaxis = widg.ToggleButtons(options=['α','mrad', 'Å'], layout=widg.Layout(grid_area='ctxaxis'), style = {'button_width': '30%'}, disabled=False)\n", + "element = widg.Dropdown(options=pty.load_elements(), description='Element (ITR)', layout=widg.Layout(width='95%', grid_area='ctf_element'))\n", + "\n", + "### Sample\n", + "sample_set = widg.Button(description='Sample',layout=widg.Layout(width='100%', grid_area='sample_set'), style=style_graph, disabled = True)\n", + "overlap_fig = widg.ToggleButtons(options=['Geometrical','Ilumination'], layout=widg.Layout(grid_area='overlap_fig'), style = {'button_width': '45%'}, disabled=False)\n", + "fov_show = widg.FloatSlider(value=0.3, min=0.1, max=10, step=0.1, description='FoV (nm):', disabled=False, continuous_update=False, orientation='horizontal', readout=True, readout_format='.1f', layout=widg.Layout(grid_area='fov_show', width = '100%'))\n", + "beam_pos = widg.IntSlider(value=4, min=4, max=100, step=2, description='Add beams:', disabled=False, continuous_update=False, orientation='horizontal', readout=True, readout_format='d', layout=widg.Layout(grid_area='beam_pos', width = '100%'))\n", + "red_box = widg.Dropdown(options=[('tiny', 0.1), ('small', 0.2), ('middle', 0.3), ('large', 0.4), ('whole', 0.5)], value=0.1, description='Uniformity box', layout=widg.Layout(grid_area='red_box', width = '95%'),style=style)\n", + "box_col = widg.ColorPicker(concise=False, description='', value='cyan', disabled=False, layout=widg.Layout(grid_area='box_col', width = '85%'),)\n", + "\n", + "### Camera length based limitations and checks\n", + "cl_set = widg.Button(description='Camera length based limitations and checks', layout=widg.Layout(width='100%', grid_area='cl_set'), style=style_graph, disabled = True)\n", + "check0name = widg.IntRangeSlider(value=[1,6],min=0, max=10,step=1, description='Detector cover (α):', disabled=False, continuous_update=False, orientation='horizontal',readout=True, readout_format='d',layout=widg.Layout(grid_area='check0name', width = '100%'),style=style)\n", + "check1name = widg.IntSlider(value=10,min=0,max=20,step=5,description='Low angle approx. (°):', disabled=False,continuous_update=False,orientation='horizontal',readout=True,readout_format='d',layout=widg.Layout(grid_area='check1name', width = '100%'),style=style)\n", + "check2name = widg.Checkbox(value=False,description='Resolution gain (ITR)',disabled=False, indent=False,layout=widg.Layout(grid_area='check2name'))\n", + "check3name = widg.Checkbox(value=True, description='Recon. box coverage (ITR)',disabled=False, indent=False,layout=widg.Layout(grid_area='check3name'))\n", + "check4name = widg.IntSlider(value=70, min=0 ,max=100, step=5, description='Beam overlap (%):', disabled=False, continuous_update=False, orientation='horizontal', readout=True,readout_format='d', layout=widg.Layout(grid_area='check4name', width = '100%'),style=style)\n", + "check6name = widg.BoundedIntText(value=1,min=1,max=20,step=1, description='Overall sampling (ITR)', disabled=False,continuous_update=False,orientation='horizontal',readout=True, readout_format='d', layout=widg.Layout(grid_area='check6name', width = '100%'), style=style)\n", + "\n", + "\n", + "\n", + "### Layout\n", + "graph_controls = widg.GridBox(children=[sample_set, ctf_set, ctf_xaxis, element, beam_pos, fov_show, cl_set, overlap_fig, red_box, box_col, check0name, check1name, check2name, check3name,check4name, check6name, ctf_xaxis_name],\n", + " layout=widg.Layout(width='109%', grid_template_rows='35px 35px 35px 35px 5px', grid_template_columns='4% 3.5% 14% 1.5% 8% 8% 8% 1% 26% 14%', grid_template_areas='''\n", + " \". ctf_set ctf_set . sample_set overlap_fig overlap_fig . cl_set cl_set \" \n", + " \". ctf_xaxis_name ctxaxis . fov_show fov_show fov_show . check0name check2name \"\n", + " \". ctf_element ctf_element . beam_pos beam_pos beam_pos . check4name check3name \"\n", + " \". . . . red_box red_box box_col . check1name check6name \"\n", + " \". . . . . . . . . . \"'''))\n", + "\n", + "def ptycho_interact(beam_energy, aperture, aperture_res, aperture_res2, probe_size, cl, matrix, defocus, mag, camera, binning, dwell_time, restr, method,\n", + " ctf_xaxis, element, graph_size, beam_pos, fov_show, overlap_fig, red_box, box_col, check0name, check1name, check2name, check3name, check4name, check6name):\n", + "\n", + " fov = pty.get_fov(mag) \n", + " pctf_itr = pty.get_ctf(element)\n", + " cl_det = pty.get_cl_detector(cl, camera)\n", + " step_size = pty.get_step_size(fov, matrix) # in nm\n", + " semi_angle = pty.get_angle(aperture)\n", + " omega_itr = np.array(pty.get_omegas())\n", + " frame_rate = pty.get_aq_frec(dwell_time)\n", + " current = pty.get_current(probe_size,aperture) \n", + " wavelength = pty.get_wavelength(beam_energy)*1e12 # in pm\n", + " semi_angle_corr = pty.get_angle_corr(aperture) \n", + " pixel_angle = pty.get_pixel_angle(cl, camera, binning)\n", + " beam_diameter = pty.get_beam_diameter(aperture, defocus, semi_angle_corr)\n", + " num_pixels, size_pixel = pty.get_detector(camera, binning)\n", + " step_size_corr = np.array(pty.get_step_correction())*pty.get_step_size(fov, matrix) # in nm\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", + " e_per_scan = (dwell_time/1e6)*(current/1e12/cons.e)\n", + " dose = ((matrix**2)*e_per_scan)/((((matrix-1)*step_size_corr)**2)*100)\n", + " probe_window = (wavelength*cl_det/100)/(size_pixel/1e6)/1000 # now in nm\n", + " oversampling = (wavelength/1000)/(2*pixel_angle/1000*step_size_corr)\n", + " max_defocus = (probe_window/4)/np.tan(semi_angle_corr/1000)\n", + " z_res = wavelength/(2*np.sin(detector_cover/1000/2)*np.sin(detector_cover/1000/2))/100 # now in A\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", + " ### ALL CAMERA LENGTHS PARAMETERS\n", + " cl_all = pty.load_cameralengths(camera, \"nominal\")\n", + " cl_eff_all = pty.load_cameralengths(camera, \"effective\")\n", + " apertures = pty.load_apertures()\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", + "\n", + " if restr == True:\n", + " for x in range(0,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,1) \n", + " ptycho_pixel_size_all = (wavelength*np.array(cl_eff_all))/(detector_pixels_all*size_pixel/1e6)/1e4 \n", + " else:\n", + " ptycho_pixel_size_all = (wavelength*np.array(cl_eff_all))/(num_pixels/2*size_pixel/1e6)/1e4\n", + "\n", + " probe_window_all = (wavelength*np.array(cl_eff_all)/100)/(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)/np.tan(semi_angle_corr/1000)\n", + " max_defocus_all[max_defocus_all < 0] = 'nan'\n", + " oversampling_all = (wavelength/1000)/(2*pixel_covers/1000*step_size_corr)\n", + " z_res_all = wavelength/(2*np.sin(detector_cover_all/1000/2)*np.sin(detector_cover_all/1000/2))/100 # now in A\n", + "\n", + " ### MICROSCOPE SCHEME\n", + " width = 550 # in-graph setting\n", + " det_width = 400 # in-graph setting\n", + " reduc = 0.4 # in-graph setting\n", + " defo = np.power(defocus,0.4)/100\n", + " y_down = np.log(np.max(cl_all))\n", + " ssb_cl, kolik = pty.get_cl4ssb(detector_cover_a_all, camera, \"nominal\")\n", + " focusdepth = wavelength/(semi_angle_corr/1000)**2/1000\n", + " y = -np.log(cl)*np.ones(int(num_pixels)+1)\n", + " x = np.linspace(-det_width, det_width, int(num_pixels)+1)\n", " \n", - " def probes(self):\n", - " probes = list(read_excel(self.calib,sheet_name='Probes').Probe)\n", - " probes = probes[3::]\n", - " return probes\n", + " fig = go.Figure() \n", + " fig.update_xaxes(range=[-width, width], showticklabels=False,zeroline=False)\n", + " fig.update_yaxes(range=[-y_down, reduc*y_down], showticklabels=False)\n", + " fig.add_shape(type=\"rect\",xref=\"x\", yref=\"y\",opacity=0.05, fillcolor=\"gray\", x0=-width, y0=-y_down, x1=width, y1=reduc*y_down,line_color=\"gray\")\n", + " fig.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", + " fig.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", + " fig.add_annotation(x=-0.7*width, y=reduc*0.8*y_down, text=\"Aperture \", showarrow=False, yshift=2)\n", + " fig.add_annotation(x=-0.2*width, y=reduc*0.8*y_down, text=str(aperture), showarrow=False, yshift=-15)\n", + " fig.add_annotation(x=0, y=-y_down,text='Net acquisition time (s) '+ str(np.round(matrix*matrix*dwell_time/1e6,1)),showarrow=False,yshift=-10)\n", + " fig.add_annotation(x=0, y=reduc*0.96*y_down,text='λ (pm) '+ str(np.round(wavelength,2)),showarrow=False,yshift=0)\n", + "\n", + " # Beam\n", + " fig.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", + " fig.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", + " fig.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", + " fig.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", + " fig.add_annotation(x=-0.3*width, y=0.05*y_down,text=\"Δf \"+str(np.round(defocus,1))+\" nm\", showarrow=False)\n", + " fig.add_annotation(x=0, y=reduc*0.5*y_down,text=\"Current \"+str(np.round(current,1))+\" pA\", showarrow=True,ax=90, ay=0, yshift=0)\n", + " fig.add_annotation(x=0, y=reduc*0.5*y_down,text=\"e per spot \"+str(np.round(e_per_scan,1)), showarrow=True,ax=90, ay=0, yshift=-20)\n", + " fig.add_annotation(x=-1.7*det_width, y=reduc*0.5*y_down, ax=-0.5*det_width, ay=reduc*0.5*y_down, xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=3,arrowsize=2,arrowwidth=2,arrowcolor='black')\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", + " # Sample\n", + " fig.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", + " fig.add_annotation(x=-0.7*width, y=0,text=\"Sample\", showarrow=False, yshift=15, xshift =-8)\n", + " fig.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", + " fig.add_annotation(x=0.4*width, y=0.05*y_down,text=\"FoV \"+str(np.round(fov,2))+\" nm\", showarrow=False, yshift=0)\n", + " fig.add_annotation(x=0.5*width, y=0.05*y_down,text=\"Dose \"+str(np.round(dose,1))+\" e/Å2\", showarrow=False, yshift=-40)\n", + " fig.add_annotation(x=-0.5*width, y=0.05*y_down,text=\"DoF \"+str(np.round(focusdepth,1))+\" nm\", showarrow=False, yshift=-40)\n", + " fig.add_annotation(x=1.7*det_width, y=0, ax=np.log(fov)/20*width, ay=0, xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=3,arrowsize=2,arrowwidth=2,arrowcolor='black')\n", + " \n", + " # Detector\n", + " fig.add_trace(go.Scatter(showlegend=False, x=x, y=y, mode='markers', marker_symbol=\"line-ns\",marker_line_width=0.5))\n", + " fig.add_annotation(x=-0.5*width, y=-np.log(cl),text=\"Detector\", showarrow=False,align= 'left', yshift=15)\n", + " fig.add_annotation(x=-1.7*det_width, y=-np.log(cl), ax=-det_width, ay=-np.log(cl), xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=3,arrowsize=2,arrowwidth=2,arrowcolor='black',yshift=0)\n", + "\n", + " # Scattering\n", + " fig.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", + " fig.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", + " \n", + " # BF disk\n", + " fig.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", + " fig.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", + " if method == 'ssb':\n", + " fig.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", + " fig.add_annotation(x=0*width, y=-np.log(ssb_cl),text=\"\", showarrow=False, align= 'left', yshift=15)\n", + " if restr == True:\n", + " fig.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", + " fig.add_annotation(x=-0.35*width, y=-reduc*0.2*y_down,text=\"PAAR\", showarrow=False,align= 'left', yshift=-15)\n", + " \n", + " # Cover\n", + " fig.add_annotation(x=0, y=-np.log(cl), ax=det_width, ay=-np.log(cl), xref='x',yref='y',axref='x',ayref='y', text='', showarrow=True,arrowhead=3,arrowsize=1,arrowwidth=1,arrowcolor='black')\n", + " fig.add_annotation(x=det_width,y=-np.log(cl), ax=0, ay=-np.log(cl), xref='x',yref='y',axref='x',ayref='y', text='', showarrow=True,arrowhead=3,arrowsize=1,arrowwidth=1,arrowcolor='black')\n", + " fig.add_annotation(x=det_width/2, y=-np.log(cl), text=str(np.round(detector_cover,1)) + \" mrad or \" + str(np.round(covered_alfas,1))+\"α\", showarrow=False, yshift=15, xshift=0)\n", + " \n", + " # CLs\n", + " xx = 0\n", + " for x in cl_all:\n", + " if xx == 0:\n", + " fig.add_annotation(x=-0.7*width, y=-np.log(x),text=\"Nominal CL\", showarrow=False, yshift=50)\n", + " fig.add_annotation(x=-0.7*width, y=-np.log(x),text=\"(cm)\", showarrow=False, yshift=35)\n", + " fig.add_annotation(x= 0.7*width, y=-np.log(x),text=\"Effective CL\", showarrow=False, yshift=50)\n", + " fig.add_annotation(x= 0.7*width, y=-np.log(x),text=\"(cm)\", showarrow=False, yshift=35)\n", + " fig.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", + " fig.add_annotation(x=-0.9*width, y=-np.log(x), text=str(x), showarrow=False, yshift=8)\n", + " fig.add_annotation(x=0.85*width, y=-np.log(x), text=str(np.round(cl_eff_all[xx],1)), showarrow=False, yshift=8)\n", + " xx +=1\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", + " fig.add_annotation(x=width, y=-np.log(cl_all[0]), ax=width, ay=-np.log(cl_all[-1]), xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=0,arrowsize=2,arrowwidth=2,arrowcolor='gray',yshift=0)\n", + " fig.add_annotation(x=1.7*det_width, y=-(np.log(cl_all[0])+np.log(cl_all[-1]))/2,ax=width, ay=-(np.log(cl_all[0])+np.log(cl_all[-1]))/2, xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=3,arrowsize=2,arrowwidth=2,arrowcolor='black')\n", + " fig.update_xaxes(title_text=\"\")\n", + " fig.update_layout(plot_bgcolor='white',width=4.1*graph_size, height=7.2*graph_size, margin = dict(l=0.45*graph_size, r=0.45*graph_size, t=0.0*graph_size, b=0))\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", + " ### SAMPLE PLANE\n", + " match overlap_fig: \n", + " case 'Geometrical':\n", + " wid = np.linspace(-beam_pos/2,beam_pos/2,beam_pos+1)*step_size_corr\n", + " yyy = np.append(np.linspace(0,overlap,100),200)\n", + " \n", + " fig1 = make_subplots(specs=[[{\"secondary_y\": True}]])\n", + " fig1.update_xaxes(title_text=\"Sample plane (nm)\", range=[-fov_show/2, fov_show/2], showgrid=False, zeroline=False)\n", + " fig1.update_yaxes(range=[-fov_show/2, fov_show/2],showgrid=False, showticklabels=False)\n", + " \n", + " for x in range(len(wid)): \n", + " fig1.add_trace(go.Scatter(showlegend=False, x=wid, y=np.ones(len(wid))*wid[x], marker_color='black'),secondary_y=False)\n", + " for y in range(len(wid)): \n", + " fig1.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", + " fig1.add_annotation(x=-1*step_size_corr, y=-2*step_size_corr, ax=-2*step_size_corr, ay=-2*step_size_corr, xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=2,arrowsize=2,arrowwidth=1,arrowcolor='red')\n", + " fig1.add_annotation(x=-2*step_size_corr, y=-1*step_size_corr, ax=-2*step_size_corr, ay=-2*step_size_corr, xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=2,arrowsize=2,arrowwidth=1,arrowcolor='red')\n", + " fig1.add_annotation(x=2*step_size_corr-0.75*beam_diameter/2, y=-2*step_size_corr-0.75*beam_diameter/2, ax=2*step_size_corr, ay=-2*step_size_corr,xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=2,arrowsize=2,arrowwidth=1,arrowcolor='blue')\n", + " fig1.add_annotation(x=2*step_size_corr+0.75*beam_diameter/2, y=-2*step_size_corr+0.75*beam_diameter/2, ax=2*step_size_corr, ay=-2*step_size_corr,xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=2,arrowsize=2,arrowwidth=1,arrowcolor='blue')\n", + " fig1.add_trace(go.Scatter(showlegend=True, x=[-100], y=[-100],marker_size=12, marker_color='red', name='Step '+str(np.round(10*step_size_corr,2))+' Å')) \n", + " fig1.add_trace(go.Scatter(showlegend=True, x=[-100], y=[-100],marker_size=12, marker_color='blue', name='Beam ⌀ '+str(np.round(10*beam_diameter,2))+' Å')) \n", + " \n", + " if method == 'ssb':\n", + " omega, pctf = pty.get_ssb_ctf()\n", + " xx = wavelength/(np.sin(semi_angle_corr*omega/1000))/100\n", + " fig1.add_trace(go.Scatter(showlegend=True, x=[-100], y=[-100],marker_size=12, marker_color='green', name='Rec step '+str(np.round(xx[-1]/3,2))+' Å')) \n", + " fig1.update_layout(legend=dict(orientation=\"v\",yanchor=\"bottom\",y=1.0,xanchor=\"right\",x=0.9))\n", + "\n", + " fig1.add_trace(go.Scatter(showlegend=False, x = -fov_show/2*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", + " fig1.update_yaxes(range=[0, 100], showgrid=False, showticklabels=False, secondary_y=True)\n", + " fig1.update_yaxes(title_text=\"Overlap (%)\", showgrid=False, showticklabels=True, tickvals = [-fov_show/2, -fov_show/4, 0, fov_show/4, fov_show/2],ticktext = ['0', '25', '50', '75', '100'], secondary_y=False)\n", + " fig1.update_layout(plot_bgcolor='white', legend=dict(orientation=\"v\",yanchor=\"bottom\",y=1.01,xanchor=\"right\",x=0.9))\n", + " fig1.update_xaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", + " fig1.update_yaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", + "\n", + " match method: \n", + " case 'ssb':\n", + " fig1.update_layout(width=3.6*graph_size, height=4*graph_size, margin =dict(l=0.6*graph_size, r=0.3*graph_size, t=0.1*graph_size, b=0.7*graph_size))\n", + " fig1.update_layout(title={'text': \"Sample\",'y': 0.87, 'x': 0.17,'xanchor': 'left','yanchor': 'top'})\n", + " case 'iterative':\n", + " fig1.update_layout(legend=dict(orientation=\"h\",yanchor=\"bottom\",y=1.01,xanchor=\"right\",x=1.0))\n", + " fig1.update_layout(title={'text': \"Sample\",'y': 0.92, 'x': 0.5,'xanchor': 'left','yanchor': 'top'})\n", + " fig1.update_layout(width=3.5*graph_size, height=3.7*graph_size, margin =dict(l=0.8*graph_size, r=0.0*graph_size, t=0.8*graph_size, b=0))\n", + "\n", + " case 'Ilumination':\n", + " if abtem == True:\n", + " sampling= 0.05 # sampling of the simulated potential in A\n", + " sys.stdout = io.StringIO() # create a text trap and redirect stdout\n", + " probe = Probe(sampling = sampling, extent = 2*beam_diameter*10, energy = beam_energy*1e3, semiangle_cutoff = semi_angle_corr, defocus = defocus*10) # sampling=sampling, extent=A , energy=beam*1e3eV, semiangle_cutoff=mrad, defocus=A)\n", + " intensity = probe.build().intensity().compute()\n", + " intensity = np.abs(intensity.array)\n", + " sys.stdout = sys.__stdout__ # now restore stdout function\n", + " x_pix = int(step_size_corr*10/sampling) # step size from nm to A\n", + " field = np.zeros([intensity.shape[0]+(beam_pos)*x_pix, intensity.shape[1]+(beam_pos)*x_pix])\n", + " cen = int(intensity.shape[0]/2)\n", + " \n", + " for i in range(0,beam_pos+1):\n", + " for j in range(0,beam_pos+1):\n", + " xx = x_pix*i\n", + " xy = x_pix*j\n", + " field[xy:intensity.shape[0]+xy,xx:intensity.shape[0]+xx]=field[xy:intensity.shape[0]+xy,xx:intensity.shape[0]+xx]+intensity\n", + " \n", + " field_size =int(field.shape[0]) \n", + " field_cen = int(field.shape[0]/2)\n", + " middle = field[int(field_cen-(x_pix*(beam_pos)*red_box)):int(field_cen+(x_pix*(beam_pos)*red_box)),int(field_cen-(x_pix*(beam_pos)*red_box)):int(field_cen+(x_pix*(beam_pos)*red_box))]\n", + " uniformity = (1-(np.max(middle)-np.min(middle))/(np.max(field)-np.min(field)))*100\n", " \n", - "opt = interaction()\n", + " fig1 = go.Figure() \n", + " fig1.add_trace(px.imshow(field).data[0])\n", + " fig1.add_shape(type=\"rect\",x0= field_cen-red_box*field_size, y0=field_cen-red_box*field_size, x1= field_cen+red_box*field_size, y1=field_cen+red_box*field_size,line=dict(color=box_col))\n", + " fig1.update_layout(title={'text': \"Uniformity: \"+str(np.round(uniformity,1))+\"%\",'y':0.85, 'x':0.3,'xanchor': 'left','yanchor': 'top'})\n", + " fig1.update_traces(dict(showscale=False, coloraxis=None, colorscale='plasma'), selector={'type':'heatmap'})\n", + " fig1.update_xaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\", title_text=\"Sample plane (nm)\", showgrid=False, showticklabels=True,\n", + " tickvals = [0, field.shape[0]/2, field.shape[0]-1], ticktext = [0, np.round((field.shape[0]/2)*sampling,1), np.round((field.shape[0]-1)*sampling,1)]).update_yaxes(showticklabels=False)\n", + " fig1.update_layout(width=3.1*graph_size, height=3.9*graph_size, margin =dict(l=0.5*graph_size, r=0.2*graph_size, t=0.9*graph_size, b=0.55*graph_size))\n", + " else:\n", + " fig1 = go.Figure() \n", + " fig1.update_layout(title={'text': \"abTEM not available\",'y': 0.98, 'x': 0.14,'xanchor': 'left','yanchor': 'top'})\n", + " fig1.update_layout(width=3.1*graph_size, height=3.9*graph_size, margin =dict(l=0.5*graph_size, r=0.2*graph_size, t=0.9*graph_size, b=0.55*graph_size))\n", "\n", - "\n", - "class ptychoScopy:\n", - " \"\"\"Computes various characteristics describing used setting.\"\"\"\n", + " ### DETECTOR PLANE\n", + " fig2 = make_subplots(specs=[[{\"secondary_y\": True}]])\n", + " fig2.update_xaxes(title_text=\"Detector pixel array\", range=[0.5, num_pixels+0.5], tickvals = [1, num_pixels/2+0.5, num_pixels], ticktext = [1, num_pixels/2, num_pixels], showticklabels=True,showgrid=True) \n", + " fig2.update_yaxes(range=[0.5, num_pixels+0.5], showticklabels=False, showgrid=False, secondary_y=False)\n", + " fig2.add_shape(type=\"circle\",xref=\"x\", yref=\"y\",opacity=0.5, fillcolor=\"#FF7F7F\", x0=(num_pixels+1)/2-beam_diameter_pix/2, y0=(num_pixels+1)/2-beam_diameter_pix/2, x1=(num_pixels+1)/2+beam_diameter_pix/2, y1=(num_pixels+1)/2+beam_diameter_pix/2,line_color=\"red\",secondary_y=False)\n", + " fig2.add_shape(type=\"rect\",xref=\"x\", yref=\"y\",opacity=0.5, fillcolor=\"#f0f921\", x0=0.5, y0=0.5, x1=1.5, y1=1.5,line_color=\"#000004\",secondary_y=False) \n", + " fig2.add_annotation(x=(num_pixels+1)/2-beam_diameter_pix/2, y=(num_pixels+1)/2, ax=(num_pixels+1)/2+beam_diameter_pix/2, ay=(num_pixels+1)/2, xref='x',yref='y',axref='x',ayref='y',text='', showarrow=True,arrowhead=2,arrowsize=2,arrowwidth=1,arrowcolor='black')\n", + " fig2.add_annotation(x=(num_pixels+1)/2+beam_diameter_pix/2,y=(num_pixels+1)/2, ax=(num_pixels+1)/2-beam_diameter_pix/2, ay=(num_pixels+1)/2, xref='x',yref='y',axref='x',ayref='y', text='', showarrow=True,arrowhead=2,arrowsize=2,arrowwidth=1,arrowcolor='black')\n", + " fig2.add_annotation(x=(num_pixels+1)/2, y=(num_pixels+1)/2, text=str(np.round(beam_diameter_pix,1))+\" pix\", showarrow=False, yshift=10)\n", + " fig2.add_annotation(x=1, y=1, text=str(np.round(size_pixel,2))+\" μm ≈ \" +str(np.round(pixel_angle,4))+\" mrad\", showarrow=False, xshift=70+(50/np.sqrt(num_pixels)), yshift=10+(50/np.sqrt(num_pixels)))\n", + " fig2.update_yaxes(title_text=\"Cover angle (mrad)\", showticklabels=True, showgrid=True, range=[0.5, num_pixels+0.5], tickvals = [1, num_pixels/2+0.5, num_pixels], ticktext = [str(np.round(-detector_cover,1)), \"0\", str(np.round(detector_cover,1))])\n", + " fig2.update_layout(plot_bgcolor='white', legend=dict(orientation=\"v\",yanchor=\"bottom\",y=1.01,xanchor=\"left\",x=0.1))\n", + " fig2.update_xaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", + " fig2.update_yaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", + " fig2.update_layout(title={'text': \"Detector\",'y':0.65, 'x': 0.44,'xanchor': 'left','yanchor': 'top'})\n", + " fig2.update_layout(width=3.45*graph_size, height=4.7*graph_size, margin =dict(l=0.65*graph_size, r=0.1*graph_size, t=1.9*graph_size, b=0)) \n", + " fig2.add_annotation(x=(num_pixels+1)/2, y=(num_pixels+1)/2, text=\"BF disk\", showarrow=False, yshift=-15, font=dict(family=\"calibri\", size=18, color=\"#FF7F7F\"))\n", " \n", - " def __init__(self):\n", - " self.calib = calib\n", + " match method: \n", + " case 'ssb':\n", + " ### CAMERA LENGTH GRAPH\n", + " fig4 = make_subplots(specs=[[{\"secondary_y\": True}]])\n", + " fig4.add_trace(go.Scatter(showlegend=False,x=cl_all, y=detector_cover_all, marker_color='black'), secondary_y=False)\n", + " fig4.add_trace(go.Scatter(showlegend=False,x=cl_all, y=detector_cover_a_all,marker_color='black'), 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 = \"Maximal CL\"), secondary_y=True) \n", + " fig4.add_trace(go.Scatter(showlegend=False,x=[np.min(cl_all)/1.5,np.array(cl)], y=[detector_cover, detector_cover], mode='lines',marker_color='gray'), secondary_y=False)\n", + " fig4.add_trace(go.Scatter(showlegend=False,x=[np.array(cl),np.array(cl)], y=[0, np.array(covered_alfas)], mode='lines',marker_color='gray'), secondary_y=True)\n", + " fig4.add_trace(go.Scatter(showlegend=False,x=[np.array(cl),np.max(cl_all)*1.5], y=[np.array(covered_alfas), np.array(covered_alfas)], mode='lines',marker_color='gray'), secondary_y=True)\n", + " fig4.add_trace(go.Scatter(showlegend=False,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_annotation(x=np.log10(np.max(cl_all)), y=detector_cover, text=str(np.round(covered_alfas,1)), showarrow=False, xshift=20, yshift=+10, secondary_y=False)\n", + " fig4.add_annotation(x=np.log10(np.min(cl_all)), y=detector_cover, text=str(np.round(detector_cover,1)), showarrow=False, xshift=-20, yshift=+10, secondary_y=False)\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_xaxes(title_text=\"Nominal camera length (cm)\", type=\"log\", tickvals = cl_all, mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", + " fig4.update_xaxes(range=[np.log10(np.min(cl_all)/1.5), np.log10(np.max(cl_all)*1.5)]) \n", + " fig4.update_yaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\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(title={'text': \"Camera length\",'y':0.95, 'x':0.17,'xanchor': 'left','yanchor': 'top'}, legend=dict(orientation=\"v\",yanchor=\"bottom\",y=1.01,xanchor=\"right\",x=0.95), plot_bgcolor='white')\n", + " fig4.update_layout(width=3.61*graph_size, height=3.4*graph_size, margin =dict(l=0.3*graph_size, r=0.25*graph_size, t=0.3*graph_size, b=0.3*graph_size))\n", + " \n", + " ### SSB-PCTF\n", + " omega, pctf = pty.get_ssb_ctf()\n", + " xx = wavelength/(np.sin(semi_angle_corr*omega/1000))/100 # pitch size\n", + " \n", + " fig5 = go.Figure() \n", + " fig5.update_yaxes(title_text=\"Transfer (-)\")\n", + " match ctf_xaxis:\n", + " case 'α':\n", + " fig5.add_trace(go.Scatter(showlegend=True, x=omega, y=pctf, marker_color='red', name='For all apertures')) \n", + " fig5.update_xaxes(title_text=\"Scattering angle (α)\", range=[0, 2], zeroline=False)\n", + " \n", + " case 'mrad':\n", + " for x in apertures:\n", + " if x == apertures[0]:\n", + " fig5.add_trace(go.Scatter(showlegend=True, x=pty.get_angle_corr(x)*omega, y=pctf, marker_color='gray', name='Others'))\n", + " else:\n", + " fig5.add_trace(go.Scatter(showlegend=False, x=pty.get_angle_corr(x)*omega, y=pctf, marker_color='gray'))\n", + " fig5.add_trace(go.Scatter(showlegend=True, x=semi_angle_corr*omega, y=pctf, marker_color='red', name='Selected aperture'))\n", + " fig5.update_xaxes(title_text=\"Scattering angle (mrad)\", range=[0, 2*semi_angle_corr], zeroline=False)\n", "\n", - " def get_omegas(self):\n", - " excel_data = read_excel(calib,sheet_name='CTF')\n", - " excel_lin = list((excel_data[excel_data.CTF.isin([\"CTF\"])]))\n", - " self.omegas = excel_lin[1::]\n", - " return self.omegas\n", + " case 'Å':\n", + " for x in apertures:\n", + " d = wavelength/(np.sin(pty.get_angle_corr(x)*omega/1000))/100 # Full pitch size\n", + " if x == apertures[0]:\n", + " fig5.add_trace(go.Scatter(showlegend=True, x=d, y=pctf, marker_color='gray', name='Others'))\n", + " else:\n", + " fig5.add_trace(go.Scatter(showlegend=False, x=d, y=pctf, marker_color='gray'))\n", + " fig5.add_trace(go.Scatter(showlegend=True, x=xx, y=pctf, marker_color='red', name='Selected aperture'))\n", + " fig5.update_xaxes(title_text=\"Spacing (Å)\", range=[-0.5, 2], type=\"log\", zeroline=False)\n", + " \n", + " fig5.update_layout(plot_bgcolor='white', title={'text': \"Phase CTF\",'y':0.99, 'x':0.42,'xanchor': 'left','yanchor': 'top'},legend=dict(orientation=\"h\",yanchor=\"bottom\",y=1.01,xanchor=\"right\",x=0.95)) \n", + " fig5.update_xaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", + " fig5.update_yaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", + " fig5.update_layout(width=3.5*graph_size, height=2.2*graph_size, margin = dict(l=0.3*graph_size, r=0.3*graph_size, t=0.5*graph_size, b=0.4*graph_size))\n", + " \n", + " case 'iterative':\n", + " ### ITR-PCTF\n", + " pctf_norm = pctf_itr/np.max(pctf_itr)\n", + " fig5 = go.Figure() \n", + " fig5.update_yaxes(title_text=\"Transfer (-)\")\n", + " match ctf_xaxis: \n", + " case 'α':\n", + " fig5.add_trace(go.Scatter(showlegend=True, x=omega_itr, y= pctf_norm, marker_color='red', name='For all apertures'))\n", + " fig5.update_xaxes(title_text=\"Scattering angle (α)\", range=[0, 6], zeroline=False)\n", + " fig5.update_yaxes(range=[0, 1.1])\n", + " case 'mrad': \n", + " for x in apertures:\n", + " if x == apertures[0]:\n", + " fig5.add_trace(go.Scatter(showlegend=True, x=pty.get_angle_corr(x)*omega_itr, y=pctf_norm, marker_color='gray', name='Others'))\n", + " else:\n", + " fig5.add_trace(go.Scatter(showlegend=False, x=pty.get_angle_corr(x)*omega_itr, y=pctf_norm, marker_color='gray'))\n", + " fig5.add_trace(go.Scatter(showlegend=True, x=semi_angle_corr*omega_itr, y=pctf_norm, marker_color='red', name='Selected aperture'))\n", + " fig5.update_xaxes(title_text=\"Scattering angle (mrad)\", range=[0, 6*semi_angle_corr], zeroline=False)\n", + " case 'Å':\n", + " for x in apertures:\n", + " d = wavelength/(np.sin(pty.get_angle_corr(x)*omega_itr/1000))/100\n", + " if x == apertures[0]:\n", + " fig5.add_trace(go.Scatter(showlegend=True, x=d, y=pctf_norm, marker_color='gray', name='Others'))\n", + " else:\n", + " fig5.add_trace(go.Scatter(showlegend=False, x=d, y=pctf_norm, marker_color='gray'))\n", + " xx = wavelength/(np.sin(semi_angle_corr*omega_itr/1000))/100\n", + " fig5.add_trace(go.Scatter(showlegend=True, x=xx, y=pctf_norm, marker_color='red', name='Selected aperture'))\n", + " fig5.update_xaxes(title_text=\"Spacing (Å)\",range=[-1, 2], type=\"log\", zeroline=False)\n", + " \n", + " fig5.update_layout(title={'text': \"Phase CTF\",'y':0.99, 'x':0.42,'xanchor': 'left','yanchor': 'top'},legend=dict(orientation=\"h\",yanchor=\"bottom\",y=1.01,xanchor=\"left\",x=0),plot_bgcolor='white') \n", + " fig5.update_xaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", + " fig5.update_yaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", + " fig5.update_layout(width=3.5*graph_size, height=2.2*graph_size, margin = dict(l=0.3*graph_size, r=0.3*graph_size, t=0.5*graph_size, b=0.4*graph_size))\n", "\n", - " def get_ctf(self, element):\n", - " excel_data = read_excel(calib, sheet_name='CTF', header = 0)\n", - " excel_line = np.array(excel_data[excel_data.CTF.isin([element])])\n", - " ctf = excel_line[0]\n", - " self.ctf = ctf[1::]\n", - " return self.ctf\n", + " ### PROBE WINDOW\n", + " match overlap_fig:\n", + " case 'Geometrical': \n", + " if beam_diameter < probe_window/2:\n", + " color = \"green\"\n", + " elif beam_diameter < probe_window:\n", + " color = \"orange\"\n", + " else:\n", + " color = \"red\"\n", + "\n", + " opacity =[0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.2, 0.4]\n", + " xcoef = [8, 6, 5, 4.25, 3.5, 3, 2.5, 2]\n", + "\n", + " fig3 = go.Figure() \n", + " fig3.add_shape(type=\"rect\",xref=\"x\", yref=\"y\",opacity=0.3, fillcolor=\"#6F6F6F\", x0=probe_window/4, y0=probe_window/4, x1=3*probe_window/4, y1=3*probe_window/4,line_color=\"#6F6F6F\")\n", + " fig3.add_trace(go.Scatter(x=np.array(probe_window/2), y=np.array(probe_window/2), name='Maximal recomm. Δf '+str(np.round(max_defocus,1))+' nm', showlegend=True, marker_color=color, opacity = 0))\n", + "\n", + " for i in range(0, len(opacity)):\n", + " fig3.add_shape(type=\"circle\",xref=\"x\", yref=\"y\", opacity=opacity[i], fillcolor=color, x0=probe_window/2-beam_diameter/xcoef[i], y0=probe_window/2-beam_diameter/xcoef[i], \n", + " x1=probe_window/2+beam_diameter/xcoef[i], y1=probe_window/2+beam_diameter/xcoef[i], line_color=color)\n", + " \n", + " fig3.update_xaxes(title_text=\"Reconstruction box (nm)\", range=[0, probe_window], tickvals = [0, probe_window/4, probe_window/2, 3*probe_window/4, probe_window], ticktext = [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)])\n", + " fig3.update_yaxes(range=[0, probe_window], tickvals = [0, probe_window/4, probe_window/2, 3*probe_window/4, probe_window], showticklabels=False)\n", + " fig3.update_layout(plot_bgcolor='white',legend=dict(orientation=\"v\",yanchor=\"bottom\",y=1.01,xanchor=\"right\",x=0.8),title={'text':\"Probe\",'y':0.92,'x':0.4,'xanchor':'left','yanchor':'top'})\n", + " fig3.update_xaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", + " fig3.update_yaxes(mirror=True,ticks='inside',showline=True,linecolor='black',gridcolor='lightgrey',title_font_color=\"#000000\")\n", + " fig3.update_layout(width=2.7*graph_size, height=4.0*graph_size, margin =dict(l=0, r=0, t=0.8*graph_size, b=0.75*graph_size)) \n", + "\n", + " case 'Ilumination': \n", + " if abtem == True:\n", + " sampling= 0.1 # sampling of the simulated potential in A\n", + " probe = Probe(sampling = sampling, extent = 2*probe_window*10, energy = beam_energy*1e3, semiangle_cutoff = semi_angle_corr, defocus = defocus*10)\n", + " # probe = Probe(sampling=sampling, extent= A , energy=beam*1e3 eV, semiangle_cutoff = mrad, defocus= A)\n", + " intensity2 = probe.build().intensity().compute().array\n", + " intensity3 = intensity2/np.max(intensity2)\n", + " cen2 = intensity3.shape\n", + " sirkaA = cen2[0]*sampling\n", + " sirkaB = np.round(probe_window,2)*10/sampling\n", + " just_probe_window = intensity3[int(cen2[0]/2)-int(sirkaB/2):int(cen2[0]/2)+int(sirkaB/2), int(cen2[0]/2)-int(sirkaB/2):int(cen2[0]/2)+int(sirkaB/2)]\n", + " int_tot = np.sum(just_probe_window)/np.sum(intensity3)*100\n", + " cross_section = intensity2[int(cen2[0]/2),:]\n", + " cross_section = (cross_section-np.min(cross_section))/np.max(cross_section)\n", + "\n", + " fig3 = go.Figure() \n", + " fig3.add_trace(px.imshow(intensity3).data[0])\n", + " fig3.add_trace(go.Scatter(x=np.linspace(0,int(cen2[0])-1,len(cross_section)), y=int(cen2[0]/4)+cross_section*int(cen2[0]/2), showlegend=False, marker_color=\"white\", opacity = 0.7))\n", + " fig3.add_shape(type=\"rect\",x0= cen2[0]/2-sirkaB/2, y0=cen2[0]/2-sirkaB/2, x1= cen2[1]/2+sirkaB/2, y1=cen2[1]/2+sirkaB/2, line=dict(color=\"red\"))\n", + " fig3.update_layout(title={'text': \"Probe cover \",'y':0.85, 'x':0.3,'xanchor': 'left','yanchor': 'top'})\n", + " fig3.update_traces(dict(showscale=False, coloraxis=None, colorscale='plasma'), selector={'type':'heatmap'})\n", + " fig3.update_xaxes(showticklabels=False).update_yaxes(showticklabels=False)\n", + " fig3.add_annotation(x=cen2[0]/2, y=cen2[0]/2+sirkaB/2, text='Recon. box '+str(np.round(probe_window,2))+' nm', showarrow=False, yshift=15)\n", + " fig3.add_annotation(x=cen2[0]/2, y=cen2[0]/2-sirkaB/2, text='Probe covered '+str(np.round(int_tot,1))+' %', showarrow=False, yshift=-15)\n", + " fig3.update_annotations(font=dict(color=\"white\"))\n", + " fig3.update_layout(width=2.7*graph_size, height=3.9*graph_size, margin =dict(l=0.1*graph_size, r=0.1*graph_size, t=0.9*graph_size, b=0.55*graph_size))\n", + " else:\n", + " fig3 = go.Figure() \n", + " fig3.update_layout(title={'text': \"abTEM not available\",'y': 0.98, 'x': 0.14,'xanchor': 'left','yanchor': 'top'})\n", + " fig3.update_layout(width=2.7*graph_size, height=3.9*graph_size, margin =dict(l=0.1*graph_size, r=0.1*graph_size, t=0.9*graph_size, b=0.55*graph_size))\n", + " \n", + " ### FINAL CHECKS \n", + " check1 = widg.Valid(value= bool(overlap > check4name), description='Beam overlap',layout=widg.Layout(width='250px'), style = {'description_width': '100px'}, disabled=True)\n", + " check2 = widg.Valid(value= bool(step_size_corr*10 > (wavelength*cl_det)/(num_pixels*size_pixel/1e6)/1e4), description='Resolution gain', layout=widg.Layout(width='250px'), style = {'description_width': '100px'}, disabled=True)\n", + " check3 = widg.Valid(value= bool(beam_diameter/2 < probe_window/2), description='Box coverage', layout=widg.Layout(width='250px'), style = {'description_width': '100px'}, disabled=True) \n", + " check4 = widg.Valid(value= bool(oversampling > 1), description='Overall sampling', layout=widg.Layout(width='250px'), style = {'description_width': '100px'}, disabled=True) \n", + " checks = widg.VBox([widg.HBox([check1, check2]), widg.HBox([check3, check4])]) # Label('Final checks')\n", + " checks.layout = widg.Layout(margin='0px 0px 0px 100px', padding='0px 0px 0px 0px', border='solid 3px gray') # border='dashed 1px gray'\n", + "\n", + " ### CAMERA LENGTH TABLE\n", + " dictionary = {}\n", + " tab = np.array([cl_all, np.round(ptycho_pixel_size_all,2), np.round(z_res_all,2), np.round(detector_cover_all,1), np.round(detector_cover_a_all,1), np.round(probe_window_all,1), np.round(oversampling_all,1)])\n", + " \n", + " for i in range(0,len(cl_eff_all)):\n", + " button_style = 'success'\n", + " icons=['','','','','','','']\n", + " data = tab[:,int(i)] # 0.cl, 1. ptycho pix xy, 2. ptycho pix z, 3.det cov, 4.det cov a, 5.max def, 6.probe window, 7.oversampling\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", - " FoVat1x = [str(e) for e in list(read_excel(calib,sheet_name='Ranges').FoVat1x)]\n", - " FoVat1x = np.array([x for x in FoVat1x if x != 'nan']).astype(float)\n", - " FoVat1x = FoVat1x.item()\n", - " self.fov = FoVat1x/(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", + " if cl == data[0]:\n", + " icons=['hand-point-left','','','','','',''] \n", + " if check2name == True and data[1] > step_size_corr*10: # check2name = 'Ptycho pixel < step size'\n", + " icons=['','bell','','','','',''] \n", + " button_style = 'warning'\n", + " if data[3] > 1000*np.radians(check1name): # check1name = 'Low anlge approximation'\n", + " icons=['','','','bell','','',''] \n", + " button_style = 'warning' \n", + " \n", + " if data[4] < check0name[0] or data[4] > check0name[1]: # 'Detector cover'\n", + " icons=['','','','','bell','',''] \n", + " button_style = 'warning'\n", + " if check3name == True and beam_diameter > data[5]/2 and beam_diameter < data[5]:\n", + " icons=['','','','','','bell',''] \n", + " button_style = 'warning'\n", + " if check3name == True and beam_diameter > data[5]:\n", + " icons=['','','','','','ban',''] \n", + " button_style = 'danger'\n", + " if data[6] < 1: # check6name = 'Sampling > 1' \n", + " icons=['','','','','','','ban'] \n", + " button_style = 'danger' \n", + " if data[6] > 1 and data[6] < int(check6name): # check6name = 'Sampling > check6name' \n", + " icons=['','','','','','','bell'] \n", + " button_style = 'warning' \n", + " dictionary[i] = widg.ToggleButtons(options=tuple(data), text_color= 'red', button_style=button_style, icons = icons, layout=widg.Layout(width=str(int(graph_size/100*65))+'px'),\n", + " style = {'description_width': '0px','button_width': str(int(graph_size/100*63))+'px'}, disabled=True)\n", + " legend = widg.ToggleButtons(options=['Nominal CL (cm)','Resolution XY (Å)','Resolution Z (Å)', 'Detector cover (mrad)','Detector cover (α)', 'Reconstr. box (nm)', 'Overall sampling'],\n", + " button_style='', layout=widg.Layout(width='150px'), style = {'description_width': '0px','button_width': \"150px\"}, disabled=True) \n", + " \n", + " # FIX here\n", + " match len(cl_eff_all):\n", + " case 1: \n", + " cltab = widg.HBox([legend, dictionary[0]])\n", + " case 2: \n", + " cltab = widg.HBox([legend, dictionary[0], dictionary[1]])\n", + " case 3: \n", + " cltab = widg.HBox([legend, dictionary[0], dictionary[1], dictionary[2]])\n", + " case 4: \n", + " cltab = widg.HBox([legend, dictionary[0], dictionary[1], dictionary[2], dictionary[3]])\n", + " case 5: \n", + " cltab = widg.HBox([legend, dictionary[0], dictionary[1], dictionary[2], dictionary[3], dictionary[4]])\n", + " case 6: \n", + " cltab = widg.HBox([legend, dictionary[0], dictionary[1], dictionary[2], dictionary[3], dictionary[4], dictionary[5]])\n", + " case 7: \n", + " cltab = widg.HBox([legend, dictionary[0], dictionary[1], dictionary[2], dictionary[3], dictionary[4], dictionary[5], dictionary[6]])\n", + " case 8: \n", + " cltab = widg.HBox([legend, dictionary[0], dictionary[1], dictionary[2], dictionary[3], dictionary[4], dictionary[5], dictionary[6], dictionary[7]])\n", + " case 9: \n", + " cltab = widg.HBox([legend, dictionary[0], dictionary[1], dictionary[2], dictionary[3], dictionary[4], dictionary[5], dictionary[6], dictionary[7], dictionary[8]])\n", + " case 10: \n", + " cltab = widg.HBox([legend, dictionary[0], dictionary[1], dictionary[2], dictionary[3], dictionary[4], dictionary[5], dictionary[6], dictionary[7], dictionary[8], dictionary[9]])\n", + " case 11: \n", + " cltab = widg.HBox([legend, dictionary[0], dictionary[1], dictionary[2], dictionary[3], dictionary[4], dictionary[5], dictionary[6], dictionary[7], dictionary[8], dictionary[9], dictionary[10]])\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", + " cltab = widg.VBox([widg.Label('CAMERA LENGTH GUIDE'), cltab])\n", + " cltab.layout = widg.Layout(border='solid 0px gray',margin='0px 0px 0px 0px', padding='5px 5px 5px 5px')\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 = 2*defocus*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", + " ### SHOWING\n", + " match method: \n", + " case 'ssb':\n", + " right = widg.VBox([go.FigureWidget(fig1),go.FigureWidget(fig4)])\n", + " case 'iterative':\n", + " right = widg.VBox([widg.HBox([go.FigureWidget(fig1),go.FigureWidget(fig3)]), cltab, checks])\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", + " left = widg.VBox([go.FigureWidget(fig5),go.FigureWidget(fig2)])\n", + " total = widg.HBox([left, go.FigureWidget(fig), right])\n", + " total.layout = widg.Layout(border='solid 0px gray',margin='10px 10px 10px 10px', padding='0px 0px 0px 0px') \n", + " display(total)\n", + " return \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", - " 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", - "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", - " def show_wavelength(self,caller):\n", - " beam_res.value = f'λ (pm) {str(\"{:.1f}\".format(pty.get_wavelength(caller.new)*1e12))}'\n", - " return beam_res.value\n", - " \n", - " def show_probe_angle(self,caller):\n", - " aperture_res.value = f'Semi-angle (mrad) {\"{:.1f}\".format(pty.get_angle(caller.new))}' \n", - " return aperture_res.value\n", - " \n", - " def show_corrprobe_angle(self,caller):\n", - " aperture_res2.value = f'corr. {\"{:.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'FoV (nm) {\"{:.1f}\".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'Rate (kHz) {\"{:.1f}\".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", + "gui = widg.interactive_output(ptycho_interact, {\"beam_energy\" : beam_energy, \"aperture\": aperture, \"aperture_res\": aperture_res, \"aperture_res2\": aperture_res2, \"probe_size\": probe_size, \"cl\": cl, \"matrix\": matrix,\n", + " \"defocus\": defocus, \"mag\": mag, \"camera\": camera, \"binning\": binning, \"dwell_time\" : dwell_time, \"restr\": restr, \"method\": method, \"ctf_xaxis\": ctf_xaxis, \"element\": element,\n", + " \"graph_size\": graph_size, \"beam_pos\": beam_pos, \"fov_show\": fov_show, \"overlap_fig\" :overlap_fig, \"red_box\": red_box, \"box_col\":box_col, \"check0name\":check0name, \n", + " \"check1name\": check1name, \"check2name\": check2name, \"check3name\": check3name, \"check4name\": check4name, \"check6name\": check6name}) \n", "\n", - "inte = interaction() " + "ptychoscopy = widg.VBox([top_set, widg.HBox([controls, widg.VBox([graph_controls, gui])])])\n" ] } ], diff --git a/ptychoScopy.ipynb b/ptychoScopy.ipynb index e8a7a96..dde1a93 100644 --- a/ptychoScopy.ipynb +++ b/ptychoScopy.ipynb @@ -40,14 +40,14 @@ }, { "cell_type": "code", - "execution_count": 68, + "execution_count": 4, "id": "5c5feaae-861c-4277-9dd5-aee373b3c174", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "3910cf673b40428cbbaaa2a78bfa0200", + "model_id": "37bb53443b8a4d50bb614d7156907632", "version_major": 2, "version_minor": 0 }, @@ -73,7 +73,7 @@ }, { "cell_type": "code", - "execution_count": 67, + "execution_count": 3, "id": "fecbecdb-0fac-4ac8-a2b3-1ccb3f869a77", "metadata": {}, "outputs": [], @@ -213,15 +213,17 @@ "check2name = widg.Checkbox(value=False,description='Resolution gain (ITR)',disabled=False, indent=False,layout=widg.Layout(grid_area='check2name'))\n", "check3name = widg.Checkbox(value=True, description='Recon. box coverage (ITR)',disabled=False, indent=False,layout=widg.Layout(grid_area='check3name'))\n", "check4name = widg.IntSlider(value=70, min=0 ,max=100, step=5, description='Beam overlap (%):', disabled=False, continuous_update=False, orientation='horizontal', readout=True,readout_format='d', layout=widg.Layout(grid_area='check4name', width = '100%'),style=style)\n", - "check6name = widg.Checkbox(value=False, description='Overall sampling (ITR)', disabled=False, indent=False,layout=widg.Layout(grid_area='check6name'), style=style)\n", + "check6name = widg.BoundedIntText(value=1,min=1,max=20,step=1, description='Overall sampling (ITR)', disabled=False,continuous_update=False,orientation='horizontal',readout=True, readout_format='d', layout=widg.Layout(grid_area='check6name', width = '100%'), style=style)\n", + "\n", + "\n", "\n", "### Layout\n", "graph_controls = widg.GridBox(children=[sample_set, ctf_set, ctf_xaxis, element, beam_pos, fov_show, cl_set, overlap_fig, red_box, box_col, check0name, check1name, check2name, check3name,check4name, check6name, ctf_xaxis_name],\n", - " layout=widg.Layout(width='109%', grid_template_rows='35px 35px 35px 35px 5px', grid_template_columns='4% 3.5% 14% 1.5% 8% 8% 8% 1% 27% 13%', grid_template_areas='''\n", + " layout=widg.Layout(width='109%', grid_template_rows='35px 35px 35px 35px 5px', grid_template_columns='4% 3.5% 14% 1.5% 8% 8% 8% 1% 26% 14%', grid_template_areas='''\n", " \". ctf_set ctf_set . sample_set overlap_fig overlap_fig . cl_set cl_set \" \n", " \". ctf_xaxis_name ctxaxis . fov_show fov_show fov_show . check0name check2name \"\n", - " \". ctf_element ctf_element . beam_pos beam_pos beam_pos . check4name check6name \"\n", - " \". . . . red_box red_box box_col . check1name check3name \"\n", + " \". ctf_element ctf_element . beam_pos beam_pos beam_pos . check4name check3name \"\n", + " \". . . . red_box red_box box_col . check1name check6name \"\n", " \". . . . . . . . . . \"'''))\n", "\n", "def ptycho_interact(beam_energy, aperture, aperture_res, aperture_res2, probe_size, cl, matrix, defocus, mag, camera, binning, dwell_time, restr, method,\n", @@ -252,7 +254,8 @@ " probe_window = (wavelength*cl_det/100)/(size_pixel/1e6)/1000 # now in nm\n", " oversampling = (wavelength/1000)/(2*pixel_angle/1000*step_size_corr)\n", " max_defocus = (probe_window/4)/np.tan(semi_angle_corr/1000)\n", - "\n", + " z_res = wavelength/(2*np.sin(detector_cover/1000/2)*np.sin(detector_cover/1000/2))/100 # now in A\n", + " \n", " ### ALL CAMERA LENGTHS PARAMETERS\n", " cl_all = pty.load_cameralengths(camera, \"nominal\")\n", " cl_eff_all = pty.load_cameralengths(camera, \"effective\")\n", @@ -276,7 +279,7 @@ " max_defocus_all = (usable_probe_semi_window_all)/np.tan(semi_angle_corr/1000)\n", " max_defocus_all[max_defocus_all < 0] = 'nan'\n", " oversampling_all = (wavelength/1000)/(2*pixel_covers/1000*step_size_corr)\n", - "\n", + " z_res_all = wavelength/(2*np.sin(detector_cover_all/1000/2)*np.sin(detector_cover_all/1000/2))/100 # now in A\n", "\n", " ### MICROSCOPE SCHEME\n", " width = 550 # in-graph setting\n", @@ -387,7 +390,7 @@ " if method == 'ssb':\n", " omega, pctf = pty.get_ssb_ctf()\n", " xx = wavelength/(np.sin(semi_angle_corr*omega/1000))/100\n", - " fig1.add_trace(go.Scatter(showlegend=True, x=[-1], y=[-1],marker_size=12, marker_color='green', name='Rec step '+str(np.round(xx[-1]/3,2))+' Å')) \n", + " fig1.add_trace(go.Scatter(showlegend=True, x=[-100], y=[-100],marker_size=12, marker_color='green', name='Rec step '+str(np.round(xx[-1]/3,2))+' Å')) \n", " fig1.update_layout(legend=dict(orientation=\"v\",yanchor=\"bottom\",y=1.0,xanchor=\"right\",x=0.9))\n", "\n", " fig1.add_trace(go.Scatter(showlegend=False, x = -fov_show/2*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", @@ -620,36 +623,40 @@ "\n", " ### CAMERA LENGTH TABLE\n", " dictionary = {}\n", - " tab = np.array([cl_all, np.round(ptycho_pixel_size_all,2), np.round(detector_cover_all,1), np.round(detector_cover_a_all,1), np.round(probe_window_all,1), np.round(oversampling_all,1)])\n", + " tab = np.array([cl_all, np.round(ptycho_pixel_size_all,2), np.round(z_res_all,2), np.round(detector_cover_all,1), np.round(detector_cover_a_all,1), np.round(probe_window_all,1), np.round(oversampling_all,1)])\n", " \n", " for i in range(0,len(cl_eff_all)):\n", " button_style = 'success'\n", - " icons=['','','','','','']\n", - " data = tab[:,int(i)] # 0.cl, 1. ptycho pix, 2.det cov 3.det cov a, 4.max def, 5.probe window, 6.oversampling\n", + " icons=['','','','','','','']\n", + " data = tab[:,int(i)] # 0.cl, 1. ptycho pix xy, 2. ptycho pix z, 3.det cov, 4.det cov a, 5.max def, 6.probe window, 7.oversampling\n", " \n", " if cl == data[0]:\n", - " icons=['hand-point-left','','','','',''] \n", + " icons=['hand-point-left','','','','','',''] \n", " if check2name == True and data[1] > step_size_corr*10: # check2name = 'Ptycho pixel < step size'\n", - " icons=['','bell','','','',''] \n", + " icons=['','bell','','','','',''] \n", " button_style = 'warning'\n", - " if data[2] > 1000*np.radians(check1name): # check1name = 'Low anlge approximation'\n", - " icons=['','','bell','','',''] \n", + " if data[3] > 1000*np.radians(check1name): # check1name = 'Low anlge approximation'\n", + " icons=['','','','bell','','',''] \n", " button_style = 'warning' \n", - " if data[3] < check0name[0] or data[3] > check0name[1]: # 'Detector cover'\n", - " icons=['','','','bell','',''] \n", + " \n", + " if data[4] < check0name[0] or data[4] > check0name[1]: # 'Detector cover'\n", + " icons=['','','','','bell','',''] \n", " button_style = 'warning'\n", - " if check3name == True and beam_diameter > data[4]/2 and beam_diameter < data[4]:\n", - " icons=['','','','','','bell'] \n", + " if check3name == True and beam_diameter > data[5]/2 and beam_diameter < data[5]:\n", + " icons=['','','','','','bell',''] \n", " button_style = 'warning'\n", - " if check3name == True and beam_diameter > data[4]:\n", - " icons=['','','','','','ban'] \n", + " if check3name == True and beam_diameter > data[5]:\n", + " icons=['','','','','','ban',''] \n", " button_style = 'danger'\n", - " if check6name == True and data[5] < 1: # check6name = 'Sampling > 1' \n", - " icons=['','','','','ban',''] \n", - " button_style = 'danger' \n", + " if data[6] < 1: # check6name = 'Sampling > 1' \n", + " icons=['','','','','','','ban'] \n", + " button_style = 'danger' \n", + " if data[6] > 1 and data[6] < int(check6name): # check6name = 'Sampling > check6name' \n", + " icons=['','','','','','','bell'] \n", + " button_style = 'warning' \n", " dictionary[i] = widg.ToggleButtons(options=tuple(data), text_color= 'red', button_style=button_style, icons = icons, layout=widg.Layout(width=str(int(graph_size/100*65))+'px'),\n", " style = {'description_width': '0px','button_width': str(int(graph_size/100*63))+'px'}, disabled=True)\n", - " legend = widg.ToggleButtons(options=['Nominal CL (cm)','Recon. pixel size (Å)','Detector cover (mrad)','Detector cover (α)', 'Probe box (nm)', 'Overall sampling'],\n", + " legend = widg.ToggleButtons(options=['Nominal CL (cm)','Resolution XY (Å)','Resolution Z (Å)', 'Detector cover (mrad)','Detector cover (α)', 'Reconstr. box (nm)', 'Overall sampling'],\n", " button_style='', layout=widg.Layout(width='150px'), style = {'description_width': '0px','button_width': \"150px\"}, disabled=True) \n", " \n", " # FIX here\n", @@ -678,7 +685,7 @@ " cltab = widg.HBox([legend, dictionary[0], dictionary[1], dictionary[2], dictionary[3], dictionary[4], dictionary[5], dictionary[6], dictionary[7], dictionary[8], dictionary[9], dictionary[10]])\n", "\n", " cltab = widg.VBox([widg.Label('CAMERA LENGTH GUIDE'), cltab])\n", - " cltab.layout = widg.Layout(border='solid 0px gray',margin='10px 0px 10px 25px', padding='5px 5px 5px 5px')\n", + " cltab.layout = widg.Layout(border='solid 0px gray',margin='0px 0px 0px 0px', padding='5px 5px 5px 5px')\n", "\n", " ### SHOWING\n", " match method: \n", diff --git a/ptychoscopy/__pycache__/pty.cpython-311.pyc b/ptychoscopy/__pycache__/pty.cpython-311.pyc index 93aec97aac34c5f6095ab9c91fdbfc6e6890eb53..3f091ab525e387ad08c6b3219a3629d19c120b63 100644 GIT binary patch delta 401 zcmWO2Ur1A79Eb7qecv;2u@mYRREvrDCz<6Ji{GfXHBV_7)gl8 z1o37+5+}hRaJtB7{BD$iU>H;oVGNvLe=b^Df_V|$+MdhL<@2J9mt|hb-UhIrQPDwL*K_EkxOWX6y4W?1HeT(Tl$7q#$m4sCTlCdez-?OWc?2)pZ`7&i=a!o* zDh&SQuaQX7_kk>CC>e-hg8v3m0<)aFJ1?-nu0fx`5|4!L3FLWmXj9-FO$}%9p4@s7 zALv9+V1pCkKLR@xjbu@xTH`f#>5UPyX5&x=RT&PwCSn%6Ki=E78a=4XTQ6$}n!iMW;qW8}~hPOZ0N&MU#Y|P3bm?N$$^x zNPOnHtk)7Dp35}}>~T0h3LNpQIWF*rW(&i(rdG=|qI_p5S8>ld#UUx;3jZ#NsW9+% zg-%5&eXCwZ8THp}pq%n*11R9t+K&>isK~m8W;(Zq$zs(gSnop>KW#`=VdLE9B^53{ zv>7A(O~7~)6!l)wa!x6KI5u&LcDu)wa4PJyqy)3qb;okrgTu}@}41V1S5 z@MDYp&c6c3VB7{m5V{6JXNcOQ!{4A4F+J=#4gx8iO zOP0z|Sz?eZi5V5L#D}iy``+t2=Z|yW&w1|Woa;H~JlFZBjJ>vuz1*9NW9>G^WSHp7 zC5iV7m^do(r-8nipv35VeFKqbZIRJlDKx*ovqE1;NIOYJ)QS{p3lOGWF+*`27|Os~ zbC34r#h!mw_PI0ggOhnbjB#dXdr$Y?EmA2?JZq9-cIMCFw2DfyGjtEnTa0ndw;bnh zU;+bQ>#oy4(yDZBG;$36;G9VBTT-#NO2e1vqqCsssnlsqW5&T>Pxblsy=vtwc;{;i6@4D$lz3OrURy0XDw|H#!*qQ)*Znp3;F(9Fv^sWSoqWd^ z6av|LUpOiy7JIy_ah^Zu4u66>-)2X2+wlmVoHB##zFb;zPpee!$Lqz(a*y-e#6UHn9-=1SZIv*0&kM(p6+t=`F zbnPK^+4_*P#;xOckaDwR4cK5lNug1-L1kSvzll5;q+a|DZgC8L47Puz-WGA*!#D!X zoiS9n_Pmo^IsXJ^TAJG7uG+~%lEP;os@c@jP8=_Z#}s!aUvm4fqQFpL1v;q@l0Vz8 zn)byr+SA?L74QyPjWjFeN^B=NH+z`260f(o zjJM8^gRP@Qbu+ruXo2{rC^EKO*3aej=aYTXXa;{zN3w2Td1TMB-6_BIGCXDJP~-D5TM#6#Oz!!8%89Qb zNoxE85c(&MGuEO)xuw?>eyrebkt5qxw+CzoEY-vUFjW$`^-jGJ#L;Gp2{hYx*VxFw z>@U9N$+s;f3iJqeloGoyPXP`NDYwvrMbEV(#zr&wKgU~y)EbB-;0M}|rX;v#x=~mH z+TCfU83Zxs2Mgm4r#iH#ghIa%{~m623)-;M`?{-n`2k!PXR19B%Tmv7+<0+wt9{Ao zlPELL%O*#8>OwcRE-pOEbSl!dNrn?~sLh2rpK!*CLbsjz&(u;kLHQU;d6+&nU-io2I7 z(bPLkFxvWhVzQ9z?^+ap;bAix<5Y?dS=##t>j;Ec zv?@Zo%9pIb0~8l@UxYy*vRT?P_~C2Any`2#*LNxQ5k+e7`y-NX25y3lAq>DcUG=gi--SvyeIayJBF09( z#U|G2f!SiU*2l${&2{kARKB1<9Ez1!=uKa{ot4vkHegQETzk%|!4}^nnwk<5lDBm_ zH=<4QySLhy_@Nu_ma7pSc)Pddv-+M#*wi*P&V*1^W*Ogc1lHYl8GZPZdVI*sQaSX| zi)NDj^7Zdhp3IV{AG8m>Kgbilb;Ta)ZWsdh^B$bP=5#93BzY6iqke1EIAG_oqv0-FpRF{M^lvzbUcwm6P6XJmw3-5 zNw4L4Bl9mGZs?)4{tB~Cnu#c1Tfxeb;c1wdQNi@F&C40}U*BZ?ptb9WNb>e46CPS~ zK_Hn@L_k}dxQXJz+oca_BI23Z%Z8W+u4#!_Zq*8r(12m`d?7(cMl_5xG-Y#oD_qgj z^UOpn+Iqr@w2~*jzVv~oQ=YA6=lVQm61DIihJLGCfIVRzwK|kvat98e=T=Tjdca#+d84yoi{~& zbg8+2v_&&iokNW<;CuOx_yuEZ`ckcV*n&yl#6HqgSnV9tGbADLr8E5=r;@yj?Y$$E z7ZH?lrq`Vy<22FdV$8{`i@&3YRyLjlotM%wd3XI9uDDqA~zSWDHGO=9cU3& zI!y{*Zs`S(;7XReqMVtrqyhds>e$lGpJ4!G= zK{{b^zbeB+gwW=Qk=uSMFM>yBK2;?hSv{NRXTXiE<8G;q!&$x)Z$IOsl}y)6*DCt? zWVC74dnV-Rk|BgP;#il(5zT4RU`s2UQ~>afsAf%(+YGx6xDBH!Od?Tt*s`A`m((jx z2(Sx}x&6{_=m3j3&)Kcq*1k+yUm_J;q}7++LTOfBaZZ~^ybloxFnxqRc2j+NT%EVn z%euVAG2w2wHR1U-B`tX2~(dyy(2W~^HtW~d#23*7}IX?T!^;Q6xH+DzDqfD!{>+#^X zldNu2d7a~kA^DHpHMbcnR4DfP@2~ad{U@qQuyMDzBQ$T8V$q}Y^@O0biWYxAjNELGkobj@LCI_?rny|O?!=k43-3j7zSg z2t*9>?>3{g>$L>~4npG$cCi`%Ha=#ti&OZw)&G0G|F8at+V$$)Rsd)a5CF`eqt|y$ zZUWmTFOVPr7(o>i!59P}L3B&x{kvawIItHu2};8OJs<;gfdj_SFCcLfl>a+T-vL(I#Gp5-E-8FE|VK_db!a>RQy4iFUH=CZXr9Gn*3 z&d5~rHdY3WMF17x8R#zpoB$+2vIt-VSc7vSfU3mq%?BV5Unm43`0pG;Qb8>wU;x0u zKqTM{(7{$DZ~{8DxEotZbUXI5)mmMuwPh9P?txle?OLRpd# z70tz1-|AAHSEW2(_{pCiES&}Dl86KL6+C@-f#Q=YN6Q15e4&v6A#F}oA9kTvqIM#h=n z@?8km6Fl?Ji0V-jp_R_vaVxliN3zItgvCBw1Qo%qDJ*&1g`co_-+RwF(LOUO{)l;D zA82BG=w?lUZ4)8q@Ruc6e@im!KKJ&!h`Qpxd7SL-pYUvOsQYUac5)gurL=wfAvQ>q zMjyH&qUtT?4e z=%Dy3YNQvQpbH{!g))hy12GDNscf#0M(t~~-ntW{N}$e-DgC-uo#ML6XW5!{S`sS!ty@bNRypbN-IS{c^({ zE2r5e!-rESlzf_%TEl{;@{;xYgt+l_#&V3#{1t@_zVK0U3@P^3>58J|);UP%%m;Ba ze`)P{nnAQ)%_#hxz!)_^e&Fz4U9YzCxKNKJ)*tKg{zeqIku$m0=BbHpVx>zs|A87F-LLsV8FHy+iZd zoU$Ha3R-5e{}im`9k}r>w~0$A6mFkawlB9 zZlP2_qj0ZjMNtl7QHhS(plKe-Li9)owdM$%Y%NGlzcRO9h}8Moy(%36K3yIYTVdyl zgdugC`UTe3_@Q@_Jx;~s#Y+Wf863~s^ZH8sQoPLV^EEC*USCR-rh`ZiqEi~2pk?9w zQV~Vyj(w>m#-9j1p6I|*n0fsk5s{#v7vcQj=_B0B$v$7S^m2#FRcYV*NQ8J3=i4bZ zBa&`+CF5mu)o{kE(Yg7zF1Q_dQ`z-g6YJ5RIUann?S*5$R#})v*Enfh;x71tA1@o zA`KHK!tfDHkP`^9D>Qc&fE}&Lqp# z-nzKTasiZ^x^@%H%_#TG9CM>1^h7?vMMw8(%!Spcg64?GX<60w5ZG` zoi^^R*Z75O?sJE+C4IP7-;9awPUOR&UR5798CX8ED1MS)h?bX9r4F~W!!_}xb)GZ9 z;o68ZSL6D~hgg^CHo3&rmw$Ymzgb_CvI-R&`!<(7VkhL=y>{a;{s!Z-mP>+LaKftk z<{>9_Ws`3AEjyQ=5)E?rE$Zf!i9hsjxO7QW|O_WpCZTk`^=Q$qwT@MYqc zvJD>u@=$VT5w&&~vDtS}RXAprcMZlftNtQ1a=bRqTeB+2fZg-%;K>9 zYzT8dP?1F58aBYfCgF!m-T}pF`3fGI0t%5PcWtx=>04{BU~+c|9rsd|*vAYhwOz4| zla>p4&vos%L+H^>sEQ?Kw%UX-G_(4)=fk=TT8n+#QR)ExatZIbrGq8*=$IpHXRRQa z_x~IfI%R89+Yu}snBFPc@=;SziEoQ!=QrEWcrwaIP#$8&Ih ztG2+jK2bqz%xykl-a=VxbLD2*U-jY_6%CBkB?6gvT1$RXqS935R<){i3l8m873o*F za)G8m>`zDiU6%^4|EW~Gem1xgbT`~S*qQvVgf`~LFA zkEX?f$jUW(wOD!E&PhU})b?O?keXvz(OcK`mC>r1(6#>5eTq!Gt?DCG-d80@#V=+% z@4w+aZ(8w>1xgEP0Ci~Y?%hw!3lOnL3owcA)Ad`tztG^Izc&DW9m7nST%A+KNDb5l zgxOknP#C5j2uLS8#DgC${&dd00U6ab&<{Kkv#<)Kw2hb>%EE$o;Ve<_bbQZtK zc!IqI7WSu^B^7n8n0)c|J|hqO+3TnBqtY>Z9?|~Fp#2plTiSR$oUY}L*AU^w{5)2k z2?nM;>~$R(#&p;#9x3tSKj2mO;2JeNU7cuOGUCuHP=T)tNtT7WC?0q6M%DF|;rDuR zP2RF_?sc@9rX^pGLb>a{2GFr1P|@=W1)Ns;ttc|ig5196(ZKXmKL419TtK%tnisLP zesLUsEd(bj zpTZ){vofS(i3F@QId_V*ypgi1{B7PS%V@(gYq7x;F_h|dBGtoKkNc+xB`kSE@b{?* zMsNe_49iJ>+1;BE*dPel@K6LHkhCyCad1@_5C)Bf0C8X&qzC~-E{t5-1AP=&Ed-#@ z|DL4~$bQIw$CTQR7XSrRfKX5k$`PuPcBXDZIl_PU@Ba(iEO)%v93hvj-Hv?##<7R4 z?${KL4Y-0SFyI&<2X?{$E5HcEzyTc~1$2f3hQKJ81LsT*gR^kpBrpT&33F1LWr1BV zKmyDW1~j=WvUg#Y1ArAMi{Pkqz(0RK_`yO1V8nH#c-Mn(AIDvzoZ1UPUlHIarfZC%W$VmeEA3nnFH~;_u diff --git a/ptychoscopy/pty.py b/ptychoscopy/pty.py index ecd5ea9..792d558 100644 --- a/ptychoscopy/pty.py +++ b/ptychoscopy/pty.py @@ -1,3 +1,5 @@ +#!/usr/bin/env python3 + ### Packages import import numpy as np from copy import deepcopy