From ec6f9ada9691759e84bee2a65c628bb5bc5509ff Mon Sep 17 00:00:00 2001 From: gvarnavi Date: Mon, 29 Jul 2024 08:58:36 -0700 Subject: [PATCH] adding ctf, psf widget --- 05_algorithms.md | 29 --- 07_CTF.md | 10 +- environment.yml | 1 + figures/ctf_psf.png | Bin 0 -> 28988 bytes notebooks/07_ctf_psf_widget.ipynb | 404 ++++++++++++++++++++++++++++++ 5 files changed, 413 insertions(+), 31 deletions(-) create mode 100644 figures/ctf_psf.png create mode 100644 notebooks/07_ctf_psf_widget.ipynb diff --git a/05_algorithms.md b/05_algorithms.md index a1253e5..878c280 100644 --- a/05_algorithms.md +++ b/05_algorithms.md @@ -267,32 +267,3 @@ I(\bm{R},n) ``` where $\theta$ is the annular coordinate and $k'$ is the radial coordinate for $\bm{k}$-space. - - -(bloch-wave-method)= -### The Bloch Wave Method - -text - - -(prism-method)= -### PRISM - -text - - -(other-method)= -### Other Methods - -text - - - - \ No newline at end of file diff --git a/07_CTF.md b/07_CTF.md index 967d279..93fe7bf 100644 --- a/07_CTF.md +++ b/07_CTF.md @@ -16,7 +16,7 @@ This deviation is typically expressed as a phase error or the aberration functio Another, possibly more intuitive way of framing the phase error is the point spread function ```{math} - \mathrm{PSF}(\bm{r}) = F \mathrm{e} ^ {-i \chi(\bm{k})} , + \mathrm{PSF}(\bm{r}) = \mathscr{F}^{-1}_{\bm{k} \rightarrow \bm{r}}\left\{ \mathrm{e} ^ {-i \chi(\bm{k})} \right\} , ``` the point spread function describes how an imaging system responds to a point source. In STEM, the PSF would be the image of the probe, given an infinite objective aperture, in HRTEM the PSF would be how a perfect point source is imaged by an objective lens with an infinite collection angle. @@ -30,4 +30,10 @@ For an uncorrected microscope the dominant aberration is ther third order spheri ```{math} \chi(k) \approx \frac{2\pi}{\lambda}\left( \frac{\lambda^2 k^2}{2} \Delta f + \frac{\lambda^4 k^4}{4} C_s \right) \quad . ``` -Here we used the common aliases of the aberration coefficients, so $C10 = -\Delta f$ is the negative defocus and $C_{30} = C_s$ is the third order spherical aberration. \ No newline at end of file +Here we used the common aliases of the aberration coefficients, so $C10 = -\Delta f$ is the negative defocus and $C_{30} = C_s$ is the third order spherical aberration. + +```{figure} #app:ctf_psf +:name: fig_ctf_psf +:placeholder: ./figures/ctf_psf.png +**Interactive widget showing the influence of common aberrations on the point spread function (PSF) and contact transfer function (CTF) **: +``` diff --git a/environment.yml b/environment.yml index 6a5d498..f8e9257 100644 --- a/environment.yml +++ b/environment.yml @@ -7,6 +7,7 @@ dependencies: - scipy - h5py - matplotlib + - colorspacious - abtem - ipywidgets - jupyterlab diff --git a/figures/ctf_psf.png b/figures/ctf_psf.png new file mode 100644 index 0000000000000000000000000000000000000000..7036643d657c21477626d3827b1dc785ee69ecd4 GIT binary patch literal 28988 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 e+fZ@2e7}*tVTQN@8T>oM4Ju0NXR=S51pXf`>?
vmax, vmax, amp)\n", + " amp = ((amp - vmin) / vmax).clip(1e-16, 1)\n", + "\n", + " J = amp * 61.5 # Note we restrict luminance to the monotonic chroma cutoff\n", + " C = np.minimum(chroma_boost * 98 * J / 123, 110)\n", + " h = np.rad2deg(phase) + 180\n", + "\n", + " JCh = np.stack((J, C, h), axis=-1)\n", + " rgb = cspace_convert(JCh, \"JCh\", \"sRGB1\").clip(0, 1)\n", + "\n", + " return rgb\n", + "\n", + "\n", + "def add_colorbar_arg(ax, chroma_boost=1, c=49, j=61.5):\n", + " \"\"\"\n", + " cax : axis to add cbar to\n", + " chroma_boost (float): boosts chroma for higher-contrast (~1-2.25)\n", + " c (float) : constant chroma value\n", + " j (float) : constant luminance value\n", + " \"\"\"\n", + "\n", + " divider = make_axes_locatable(ax)\n", + " cax = divider.append_axes(\"right\", size=\"5%\", pad=\"2.5%\")\n", + " \n", + " h = np.linspace(0, 360, 256, endpoint=False)\n", + " J = np.full_like(h, j)\n", + " C = np.full_like(h, np.minimum(c * chroma_boost, 110))\n", + " JCh = np.stack((J, C, h), axis=-1)\n", + " rgb_vals = cspace_convert(JCh, \"JCh\", \"sRGB1\").clip(0, 1)\n", + " newcmp = mcolors.ListedColormap(rgb_vals)\n", + " norm = mcolors.Normalize(vmin=-np.pi, vmax=np.pi)\n", + "\n", + " cb = plt.colorbar(cm.ScalarMappable(norm=norm, cmap=newcmp), cax=cax)\n", + "\n", + " cb.set_label(\"arg\", rotation=0, ha=\"center\", va=\"bottom\")\n", + " cb.ax.yaxis.set_label_coords(0.5, 1.01)\n", + " cb.set_ticks(np.array([-np.pi, -np.pi / 2, 0, np.pi / 2, np.pi]))\n", + " cb.set_ticklabels(\n", + " [r\"$-\\pi$\", r\"$-\\dfrac{\\pi}{2}$\", \"$0$\", r\"$\\dfrac{\\pi}{2}$\", r\"$\\pi$\"]\n", + " )\n", + " return None" + ] + }, + { + "cell_type": "code", + "execution_count": 59, + "id": "33a64997-5076-4526-b701-71e85e04bbb1", + "metadata": {}, + "outputs": [], + "source": [ + "probe_init = abtem.Probe(\n", + " energy=300*1e3,\n", + " semiangle_cutoff=25,\n", + " gpts=(256,256),\n", + " sampling=0.4,\n", + ").build()\n", + "\n", + "ctf = abtem.CTF(\n", + " energy=300*1e3,\n", + " semiangle_cutoff=25,\n", + " defocus=100,\n", + ")\n", + "\n", + "probe = probe_init.apply_ctf(ctf)" + ] + }, + { + "cell_type": "code", + "execution_count": 67, + "id": "f83e7c71-e8e1-4a64-a746-522eedeee990", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "/tmp/ipykernel_33501/13827917.py:9: RuntimeWarning: More than 20 figures have been opened. Figures created through the pyplot interface (`matplotlib.pyplot.figure`) are retained until explicitly closed and may consume too much memory. (To control this warning, see the rcParam `figure.max_open_warning`). Consider using `matplotlib.pyplot.close()`.\n", + " fig, (ax_ctf,ax_psf) = plt.subplots(1,2,figsize=(675/dpi, 300/dpi), dpi=dpi)\n" + ] + } + ], + "source": [ + "array = probe.array.compute()\n", + "array_fourier = np.fft.fftshift(np.fft.fft2(np.fft.ifftshift(array)))\n", + "rgb_psf = Complex2RGB(array,vmin=0,vmax=1)\n", + "rgb_ctf = Complex2RGB(array_fourier,vmin=0,vmax=1)\n", + "\n", + "# widget figure generation\n", + "with plt.ioff():\n", + " dpi = 72\n", + " fig, (ax_ctf,ax_psf) = plt.subplots(1,2,figsize=(675/dpi, 300/dpi), dpi=dpi)\n", + "\n", + "im_ctf = ax_ctf.imshow(rgb_ctf)\n", + "im_psf = ax_psf.imshow(rgb_psf)\n", + "\n", + "for ax, title in zip((ax_ctf,ax_psf),['contrast transfer function (CTF)','point spread function (PSF)']):\n", + " ax.set_xticks([])\n", + " ax.set_yticks([])\n", + " add_colorbar_arg(ax)\n", + " ax.set_title(title)\n", + "\n", + "fig.tight_layout()\n", + "\n", + "fig.canvas.resizable = False\n", + "fig.canvas.header_visible = False\n", + "fig.canvas.footer_visible = False\n", + "fig.canvas.toolbar_visible = True\n", + "fig.canvas.layout.width = '675px'\n", + "fig.canvas.layout.height = '330px'\n", + "fig.canvas.toolbar_position = 'bottom'" + ] + }, + { + "cell_type": "code", + "execution_count": 68, + "id": "4db48b85-be46-4743-8e10-5b9b0ea83ee0", + "metadata": {}, + "outputs": [], + "source": [ + "def update_aberrations(energy, defocus, C30, semiangle):\n", + "\n", + " ctf = abtem.CTF(\n", + " energy=energy*1e3, \n", + " semiangle_cutoff = semiangle,\n", + " defocus = defocus,\n", + " C30 = C30*1e7,\n", + " )\n", + "\n", + " probe_init = abtem.Probe(\n", + " energy=energy*1e3,\n", + " semiangle_cutoff=semiangle,\n", + " gpts=(256,256),\n", + " sampling=0.4,\n", + " ).build()\n", + " \n", + " probe = probe_init.apply_ctf(ctf)\n", + " array = probe.array.compute()\n", + " array_fourier = np.fft.fftshift(np.fft.fft2(np.fft.ifftshift(array)))\n", + " rgb_psf = Complex2RGB(array,vmin=0,vmax=1)\n", + " rgb_ctf = Complex2RGB(array_fourier,vmin=0,vmax=1)\n", + " \n", + " im_ctf.set_data(rgb_ctf)\n", + " im_psf.set_data(rgb_psf)\n", + " fig.canvas.draw_idle()\n", + " return None" + ] + }, + { + "cell_type": "code", + "execution_count": 69, + "id": "7ad86424-7685-456e-b02e-6a4543213849", + "metadata": {}, + "outputs": [], + "source": [ + "# List of options\n", + "option_list = (\n", + " 'select an option',\n", + " 'uncorrected STEM',\n", + " 'uncorrected STEM at Scherzer',\n", + " 'aberration corrected STEM',\n", + " 'SEM',\n", + " 'boundary artifacts', \n", + ")\n", + "\n", + "# update the plots with a pre-selected function\n", + "def select_preset_eventhandler(change):\n", + " if change.new == option_list[1]: #uncorrected STEM\n", + " energy.value = 300\n", + " defocus.value = 0\n", + " C30.value = 1.3\n", + " semiangle.value = 10\n", + " \n", + " if change.new == option_list[2]: #uncorrected STEM @ Scherzer\n", + " #calculate scherzer \n", + " lambda_300kv = abtem.core.energy.energy2wavelength(300e3)\n", + " C1_Scherzer = 0.87 * (1.3e7*lambda_300kv) ** 0.5 \n", + " \n", + " energy.value = 300\n", + " defocus.value = C1_Scherzer\n", + " C30.value = 1.3\n", + " semiangle.value = 10\n", + " \n", + " if change.new == option_list[3]: #corrected STEM\n", + " energy.value = 300\n", + " defocus.value = 0\n", + " C30.value = 0.001\n", + " semiangle.value = 10\n", + " \n", + " if change.new == option_list[4]: #SEM\n", + " energy.value = 20\n", + " defocus.vaue = 0\n", + " C30.value = 5\n", + " semiangle.value = 2.5\n", + " \n", + " if change.new == option_list[5]: #artifacts\n", + " energy.value = 10\n", + " defocus.value = 2000\n", + " C30.value = 0\n", + " semiangle.value = 20 \n", + " \n", + "# Widgets\n", + "dropdown = ipywidgets.Dropdown(\n", + " options = option_list,\n", + " layout = ipywidgets.Layout(width='200px',height='30px'),\n", + ")\n", + "dropdown.observe(select_preset_eventhandler, names='value')\n", + "\n", + "style = {\n", + " 'description_width': 'initial',\n", + "}\n", + "\n", + "energy = ipywidgets.IntSlider(\n", + " value=60, min=10, max=300, \n", + " step = 2,\n", + " description = \"energy (kV)\",\n", + " style = style,\n", + ")\n", + "\n", + "defocus = ipywidgets.IntSlider(\n", + " value = 0, min = -2000, max = 2000, \n", + " step = 20,\n", + " description = \"defocus / -1*C1 (A)\",\n", + " style = style\n", + ")\n", + "\n", + "C30 = ipywidgets.FloatSlider(\n", + " value = 0, min = 0, max =5, \n", + " step = 0.1,\n", + " description = \"C3 (mm)\",\n", + " style = style\n", + ")\n", + "\n", + "semiangle = ipywidgets.FloatLogSlider(\n", + " value=20,\n", + " base=10,\n", + " min=0, # min exponent of base\n", + " max=1.6021, # max exponent of base\n", + " step=0.05, # exponent step\n", + " description = \"semiangle (mrad)\",\n", + " style = style,\n", + ")\n", + "\n", + "ipywidgets.interactive_output(\n", + " update_aberrations, \n", + " {\n", + " 'energy':energy,\n", + " 'defocus':defocus,\n", + " 'semiangle':semiangle,\n", + " 'C30':C30,\n", + " },\n", + ")\n", + "None" + ] + }, + { + "cell_type": "code", + "execution_count": 71, + "id": "37ec6eba-1870-48c0-82c3-882c310c553b", + "metadata": {}, + "outputs": [ + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "0a02f03f4d75477e9ccf81621b12aab7", + "version_major": 2, + "version_minor": 0 + }, + "text/plain": [ + "VBox(children=(Canvas(footer_visible=False, header_visible=False, layout=Layout(height='330px', width='675px')…" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "#| label: app:ctf_psf\n", + "\n", + "widget = ipywidgets.VBox(\n", + " [\n", + " fig.canvas,\n", + " ipywidgets.HBox([\n", + " ipywidgets.VBox([\n", + " energy,\n", + " defocus,\n", + " semiangle,\n", + " C30, \n", + " ]),\n", + " ipywidgets.VBox([\n", + " ipywidgets.Label('Preset probes',layout=ipywidgets.Layout(width='100px',height='30px')), \n", + " dropdown,\n", + " ])\n", + " ]),\n", + " ],\n", + ")\n", + "\n", + "display(widget);" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "44634d55-85d4-40f8-a32b-da5817fb1d2d", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3 (ipykernel)", + "language": "python", + "name": "python3" + }, + "language_info": { + "codemirror_mode": { + "name": "ipython", + "version": 3 + }, + "file_extension": ".py", + "mimetype": "text/x-python", + "name": "python", + "nbconvert_exporter": "python", + "pygments_lexer": "ipython3", + "version": "3.11.9" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +}