diff --git a/.github/workflows/ci.yml b/.github/workflows/ci.yml index c3c5809..6636cbb 100644 --- a/.github/workflows/ci.yml +++ b/.github/workflows/ci.yml @@ -16,12 +16,10 @@ concurrency: jobs: tests: strategy: + fail-fast: false matrix: - python_version: ["3.9", "3.10", "3.11", "3.12"] + python_version: ["3.10", "3.11", "3.12"] os: [ubuntu-latest, windows-latest, macos-14] - exclude: - - os: macos-14 - python_version: "3.9" runs-on: ${{ matrix.os }} steps: - uses: actions/checkout@v5 @@ -39,6 +37,7 @@ jobs: CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }} pinned-requirements: + if: false # skip job runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 @@ -52,6 +51,7 @@ jobs: run: pytest --cov=microscope_calibration --cov-report=xml --cov-report=term tests/ numba_coverage: + if: false # skip job runs-on: ubuntu-latest steps: - uses: actions/checkout@v5 diff --git a/.pre-commit-config.yaml b/.pre-commit-config.yaml index cc613f8..ed13d47 100644 --- a/.pre-commit-config.yaml +++ b/.pre-commit-config.yaml @@ -8,6 +8,7 @@ repos: - id: end-of-file-fixer - id: check-yaml - id: check-added-large-files + exclude: prototypes/clcalib.ipynb - repo: https://github.com/pycqa/flake8 rev: 7.3.0 hooks: diff --git a/examples/generate.ipynb b/examples/generate.ipynb index 08e4f52..69e3d18 100644 --- a/examples/generate.ipynb +++ b/examples/generate.ipynb @@ -22,6 +22,7 @@ "import numpy as np\n", "import matplotlib.pyplot as plt\n", "\n", + "from microscope_calibration.common.model import Parameters4DSTEM, PixelYX\n", "from microscope_calibration.util.stem_overfocus_sim import smiley, project" ] }, @@ -37,23 +38,29 @@ }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 4, "id": "a26e070d", "metadata": {}, "outputs": [], "source": [ "size = 64\n", + "overfocus = 0.001 # m\n", + "camera_length = 0.15 # m,\n", + "propagation_distance = overfocus + camera_length\n", + "detector_pixel_pitch=0.000050 # m\n", + "angle = np.arctan2(size/2*detector_pixel_pitch/2, propagation_distance)\n", "\n", - "sim_params = {\n", - " 'overfocus': 0.001, # m\n", - " 'scan_pixel_size': 0.000001, # m\n", - " 'camera_length': 0.15, # m\n", - " 'detector_pixel_size': 0.000050, # m\n", - " 'scan_rotation': 37,\n", - " 'flip_y': False,\n", - " 'cy': size//2,\n", - " 'cx': size//2,\n", - "}" + "sim_params = Parameters4DSTEM(\n", + " overfocus=overfocus, # m\n", + " scan_pixel_pitch=0.000001, # m\n", + " scan_center=PixelYX(x=size/2, y=size/2),\n", + " camera_length=camera_length, # m,\n", + " detector_pixel_pitch=detector_pixel_pitch, # m\n", + " detector_center=PixelYX(x=size/2, y=size/2),\n", + " scan_rotation=37/180*np.pi, # rad\n", + " flip_y=False,\n", + " semiconv=angle,\n", + ")" ] }, { @@ -68,7 +75,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 5, "id": "d623219f", "metadata": {}, "outputs": [], @@ -86,23 +93,23 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 6, "id": "81dfea81", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 4, + "execution_count": 6, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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RY0XoZesA/x1xVrUALxNjReDAQFg5YuP0vpF9//YVuvO5a/ZoMPnnpvQi5vBgG0OoaHeXJ0BWZaFJUuWYN26dXjppZcwevTouO9PnToVGRkZ2LBhQ09tz5492LdvH8rLy93clYiIpDhXZ0CLFy/Gk08+iaeffhp5eXk913UKCgqQlZWFgoICXH311Vi+fDmKioqQn5+P66+/HuXl5UrAiYhIHFcL0IoVKwAA55xzTlx9zZo1+M53vgMAuO++++D3+zF//nyEw2HMmTMHDz30kCc7KyIiqcPVAmRZTn9W9oXMzExUV1ejurr6K++UiIikPvWCExERI5J2IF3UiiHa64SLtagBeJsaty1qOsfxpI3/sD0h5ZTWKUvnfS3SfDxldaCLn1HuaLcfjxcDpQBv0jrdH/OofPfsqbQeGmzfR6e0jj/g0NLFKaYY4j9DBUhS0alFTbZDCs5E6tLNcMB3D/P7dNOiBuBtarwaDGiF+fEHWllKkSenMgykLt20qAF4mxrWogbwJnUJABHykWBl8f3rPoUnblHPU5osdTklh7fmGp5uf/ZbSI3RGZCIiBihBUhERIzQAiQiIkZoARIRESO0AImIiBFJm4Jrs8LwW/HrI+uRBvA+aW57pLlJ69y3bCXddpCfR886YhFar+saQus7m0i65zDvJ2cirZM+incsbynmj7mbtE6a36HnW4Q/P+ltvM6GAzr1SItafF8SmbpkgwEBd8MBP244mW7rpkcawPukJXIwIAAE7CErZDfyF7OJ1KWbHmkA75PGeqQBQLafPw9uUpcAkDXF/l6ONPPbdvoLzqiL1OXYwEG6Let1GfMloBeciIiIV7QAiYiIEVqARETECC1AIiJihBYgERExImlTcA3dFtq647MbrEcawPukOfVI65xo74UGAL6jPPHF0jpuJxoejPL73NXJ02QfHymy70cT/1nBRFqn6wT7/gFAaDDfx648eyLGF3To+UarfDIt4DydNvuw/fadeqS5mUwLeJO6ZJNpAXfTab2YTAs49ElL4GRagE+nDe4nbzYAPgOpy668vk+mBXifNNYjDfAmdQnw5GVaFk8vOk6mbebPG0tduul1mda3VnA6AxIRETO0AImIiBFagERExAgtQCIiYoQWIBERMSJpU3AfdA1Gdld88on2SANonzSnHmkxh55iTmmdOxY9aqt5NdFwRwtP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", + "image/png": "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VmDv3r04++yz0dramjLHCAAffvghVqxYgTFjxuCFF17AokWL8MMf/hCPPfYYADOfQUk3jkFSx+LFi7Fr166436enklNPPRU7duxAc3Mz/vCHP2DhwoXYtGmT6d3yTH19PW644Qa8+OKLyMzMNL07CTN37tye/540aRJmzJiBUaNG4fe//z2ysrIM7pm3YrEYpk2bhjvvvBMAcPrpp2PXrl1YuXIlFi5caGSfkvIMaMiQIUhLS7MlTRobG1FSUmJorxLrL8eVKse8ZMkSPPfcc3j55ZfjJiKWlJQgEomgqakpbvuBeJyBQAAnn3wypk6diqqqKkyePBkPPPBAyhxjbW0tDh06hDPOOAPp6elIT0/Hpk2b8OCDDyI9PR3FxcUpcZy9FRYW4pRTTsH777+fMs8lAJSWlmL8+PFxtXHjxvX8utHEZ1BSLkCBQABTp07Fhg0bemqxWAwbNmxAeXm5wT1LnNGjR6OkpCTumFtaWvDaa68NqGO2LAtLlizBunXr8NJLL2H06NFx3586dSoyMjLijnPPnj3Yt2/fgDpOJhaLIRwOp8wxnnfeedi5cyd27NjR8zVt2jQsWLCg579T4Th7a2trwwcffIDS0tKUeS4BYObMmbY/iXjvvfcwatQoAIY+gxISbfBATU2NFQwGrUcffdTavXu3de2111qFhYVWQ0OD6V37ylpbW60333zTevPNNy0A1r333mu9+eab1scff2xZlmXdddddVmFhofX0009bb731ljVv3jxr9OjRVmdnp+E977tFixZZBQUF1saNG62DBw/2fHV0dPRsc91111kjR460XnrpJWv79u1WeXm5VV5ebnCv3bvpppusTZs2WXv37rXeeust66abbrJ8Pp/1pz/9ybKs1DhG5sspOMtKjeO88cYbrY0bN1p79+61Xn31VauiosIaMmSIdejQIcuyUuMYLcuyXn/9dSs9Pd36+c9/btXV1VlPPPGElZ2dbT3++OM92/T3Z1DSLkCWZVm/+MUvrJEjR1qBQMA688wzra1bt5repWPy8ssvWwBsXwsXLrQs6/MY5C233GIVFxdbwWDQOu+886w9e/aY3WmX2PEBsNasWdOzTWdnp/WDH/zAGjRokJWdnW1961vfsg4ePGhup7+C733ve9aoUaOsQCBgDR061DrvvPN6Fh/LSo1jZHovQKlwnJdffrlVWlpqBQIB64QTTrAuv/xy6/333+/5fioc4188++yz1sSJE61gMGiNHTvWevjhh+O+39+fQZoHJCIiRiTlNSAREUl9WoBERMQILUAiImKEFiARETFCC5CIiBihBUhERIzQAiQiIkZoARIRESO0AImIiBFagERExAgtQCIiYsT/B6n4czXQGxMcAAAAAElFTkSuQmCC", "text/plain": [ "
" ] @@ -128,10 +135,18 @@ }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 7, "id": "eaf9e402", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:2025-09-15 19:10:50,881:jax._src.xla_bridge:864: An NVIDIA GPU may be present on this machine, but a CUDA-enabled jaxlib is not installed. Falling back to cpu.\n" + ] + } + ], "source": [ "fourdstem_overfocused = project(obj, detector_shape=(size, size), scan_shape=(size, size), sim_params=sim_params)" ] @@ -148,23 +163,23 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 8, "id": "02563bd2", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 6, + "execution_count": 8, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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sWAwiK1btyIvL8/ikXln/PjxSE1N7XPOTU1N2LVr15A6Z8dxsHz5cmzatAmvvvoqxo8f3+f+GTNmICoqqs95lpWVoaKiYkidpyQYDCIQCAybc7z88suxb98+7N27t/d20UUX4cYbb+z97+Fwnp/W0tKC999/H2lpacPmewkAc+fODfmTiPfeew9ZWVkALL0HeRJtMKC4uNjx+/3OU0895Rw8eNC59dZbncTERKempsb2oQ1Yc3Oz8/bbbztvv/22A8D5+c9/7rz99tvOBx984DiO4zz00ENOYmKi8/zzzzvvvvuuc8011zjjx4932tvbLR95/y1dutRJSEhwtm3b5lRXV/fe2traeh9z2223OZmZmc6rr77q7Nmzx8nLy3Py8vIsHrW+e+65xykpKXGOHTvmvPvuu84999zjhIWFOX/7298cxxke5yj59xSc4wyP87zrrrucbdu2OceOHXPeeOMNJz8/30lOTnbq6uocxxke5+g4jvPmm286kZGRzgMPPOCUl5c7f/zjH53Y2FjnD3/4Q+9jzvR70KBtQI7jOL/85S+dzMxMx+fzObNmzXJ27txp+5Bcee211xwAIbclS5Y4jvNxDPLee+91UlJSHL/f71x++eVOWVmZ3YPWJJ0fAGfDhg29j2lvb3duv/12Z9SoUU5sbKzzH//xH051dbW9gx6Ab37zm05WVpbj8/mcMWPGOJdffnlv83Gc4XGOkk83oOFwntdff72Tlpbm+Hw+56yzznKuv/5658iRI733D4dz/MSLL77oTJkyxfH7/U5OTo7zxBNP9Ln/TL8HcT8gIiKyYlBeAyIiouGPDYiIiKxgAyIiIivYgIiIyAo2ICIisoINiIiIrGADIiIiK9iAiIjICjYgIiKygg2IiIisYAMiIiIr/n/3DnFpkmWMZAAAAABJRU5ErkJggg==", + "image/png": "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", "text/plain": [ "
" ] @@ -190,23 +205,23 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 9, "id": "256436c1", "metadata": {}, "outputs": [ { "data": { "text/plain": [ - "" + "" ] }, - "execution_count": 7, + "execution_count": 9, "metadata": {}, "output_type": "execute_result" }, { "data": { - "image/png": "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RY0XoZesA/x1xVrUALxNjReDAQFg5YuP0vpF9//YVuvO5a/ZoMPnnpvQi5vBgG0OoaHeXJ0BWZaFJUuWYN26dXjppZcwevTouO9PnToVGRkZ2LBhQ09tz5492LdvH8rLy93clYiIpDhXZ0CLFy/Gk08+iaeffhp5eXk913UKCgqQlZWFgoICXH311Vi+fDmKioqQn5+P66+/HuXl5UrAiYhIHFcL0IoVKwAA55xzTlx9zZo1+M53vgMAuO++++D3+zF//nyEw2HMmTMHDz30kCc7KyIiqcPVAmRZTn9W9oXMzExUV1ejurr6K++UiIikPvWCExERI5J2IF3UiiHa64SLtagBeJsaty1qOsfxpI3/sD0h5ZTWKUvnfS3SfDxldaCLn1HuaLcfjxcDpQBv0jrdH/OofPfsqbQeGmzfR6e0jj/g0NLFKaYY4j9DBUhS0alFTbZDCs5E6tLNcMB3D/P7dNOiBuBtarwaDGiF+fEHWllKkSenMgykLt20qAF4mxrWogbwJnUJABHykWBl8f3rPoUnblHPU5osdTklh7fmGp5uf/ZbSI3RGZCIiBihBUhERIzQAiQiIkZoARIRESO0AImIiBFJm4Jrs8LwW/HrI+uRBvA+aW57pLlJ69y3bCXddpCfR886YhFar+saQus7m0i65zDvJ2cirZM+incsbynmj7mbtE6a36HnW4Q/P+ltvM6GAzr1SItafF8SmbpkgwEBd8MBP244mW7rpkcawPukJXIwIAAE7CErZDfyF7OJ1KWbHmkA75PGeqQBQLafPw9uUpcAkDXF/l6ONPPbdvoLzqiL1OXYwEG6Let1GfMloBeciIiIV7QAiYiIEVqARETECC1AIiJihBYgERExImlTcA3dFtq647MbrEcawPukOfVI65xo74UGAL6jPPHF0jpuJxoejPL73NXJ02QfHymy70cT/1nBRFqn6wT7/gFAaDDfx648eyLGF3To+UarfDIt4DydNvuw/fadeqS5mUwLeJO6ZJNpAXfTab2YTAs49ElL4GRagE+nDe4nbzYAPgOpy668vk+mBXifNNYjDfAmdQnw5GVaFk8vOk6mbebPG0tduul1mda3VnA6AxIRETO0AImIiBFagERExAgtQCIiYoQWIBERMSJpU3AfdA1Gdld88on2SANonzSnHmkxh55iTmmdOxY9aqt5NdFwRwtP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", + "image/png": "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VmDv3r04++yz0dramjLHCAAffvghVqxYgTFjxuCFF17AokWL8MMf/hCPPfYYADOfQUk3jkFSx+LFi7Fr166436enklNPPRU7duxAc3Mz/vCHP2DhwoXYtGmT6d3yTH19PW644Qa8+OKLyMzMNL07CTN37tye/540aRJmzJiBUaNG4fe//z2ysrIM7pm3YrEYpk2bhjvvvBMAcPrpp2PXrl1YuXIlFi5caGSfkvIMaMiQIUhLS7MlTRobG1FSUmJorxLrL8eVKse8ZMkSPPfcc3j55ZfjJiKWlJQgEomgqakpbvuBeJyBQAAnn3wypk6diqqqKkyePBkPPPBAyhxjbW0tDh06hDPOOAPp6elIT0/Hpk2b8OCDDyI9PR3FxcUpcZy9FRYW4pRTTsH777+fMs8lAJSWlmL8+PFxtXHjxvX8utHEZ1BSLkCBQABTp07Fhg0bemqxWAwbNmxAeXm5wT1LnNGjR6OkpCTumFtaWvDaa68NqGO2LAtLlizBunXr8NJLL2H06NFx3586dSoyMjLijnPPnj3Yt2/fgDpOJhaLIRwOp8wxnnfeedi5cyd27NjR8zVt2jQsWLCg579T4Th7a2trwwcffIDS0tKUeS4BYObMmbY/iXjvvfcwatQoAIY+gxISbfBATU2NFQwGrUcffdTavXu3de2111qFhYVWQ0OD6V37ylpbW60333zTevPNNy0A1r333mu9+eab1scff2xZlmXdddddVmFhofX0009bb731ljVv3jxr9OjRVmdnp+E977tFixZZBQUF1saNG62DBw/2fHV0dPRsc91111kjR460XnrpJWv79u1WeXm5VV5ebnCv3bvpppusTZs2WXv37rXeeust66abbrJ8Pp/1pz/9ybKs1DhG5sspOMtKjeO88cYbrY0bN1p79+61Xn31VauiosIaMmSIdejQIcuyUuMYLcuyXn/9dSs9Pd36+c9/btXV1VlPPPGElZ2dbT3++OM92/T3Z1DSLkCWZVm/+MUvrJEjR1qBQMA688wzra1bt5repWPy8ssvWwBsXwsXLrQs6/MY5C233GIVFxdbwWDQOu+886w9e/aY3WmX2PEBsNasWdOzTWdnp/WDH/zAGjRokJWdnW1961vfsg4ePGhup7+C733ve9aoUaOsQCBgDR061DrvvPN6Fh/LSo1jZHovQKlwnJdffrlVWlpqBQIB64QTTrAuv/xy6/333+/5fioc4188++yz1sSJE61gMGiNHTvWevjhh+O+39+fQZoHJCIiRiTlNSAREUl9WoBERMQILUAiImKEFiARETFCC5CIiBihBUhERIzQAiQiIkZoARIRESO0AImIiBFagERExAgtQCIiYsT/B6n4czXQGxMcAAAAAElFTkSuQmCC", "text/plain": [ "
" ] @@ -232,7 +247,7 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 10, "id": "5105a58d", "metadata": {}, "outputs": [], @@ -255,9 +270,9 @@ "lastKernelId": null }, "kernelspec": { - "display_name": "Python (calib311)", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "calib311" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -269,7 +284,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.5" + "version": "3.13.5" } }, "nbformat": 4, diff --git a/examples/stem_overfocus.ipynb b/examples/stem_overfocus.ipynb index 772ea88..ad68e06 100644 --- a/examples/stem_overfocus.ipynb +++ b/examples/stem_overfocus.ipynb @@ -19,24 +19,25 @@ "metadata": {}, "outputs": [], "source": [ + "import time\n", + "\n", "import numpy as np\n", "import ipywidgets\n", "from jupyter_ui_poll import ui_events\n", "from skimage.measure import blur_effect\n", - "from temgymbasic.plotting import plot_model, PlotParams\n", "\n", "from libertem.api import Context\n", "from libertem.udf.sum import SumUDF\n", "from libertem.viz.bqp import BQLive2DPlot\n", "\n", - "from microscope_calibration.udf.stem_overfocus import OverfocusUDF, OverfocusParams\n", - "from microscope_calibration.common.stem_overfocus import make_model\n", + "from microscope_calibration.udf.stem_overfocus import OverfocusUDF\n", + "from microscope_calibration.common.model import Parameters4DSTEM, PixelYX, Model4DSTEM\n", "from microscope_calibration.util.optimize import make_overfocus_loss_function, optimize" ] }, { "cell_type": "code", - "execution_count": 2, + "execution_count": 11, "id": "89ac4b00", "metadata": {}, "outputs": [], @@ -47,7 +48,9 @@ "# ctx = Context()\n", "\n", "# Compatible with running inside an Apptainer image\n", - "ctx = Context.make_with('threads')" + "ctx = Context.make_with('threads', cpus=4)\n", + "# Debugging\n", + "# ctx = Context.make_with('inline')" ] }, { @@ -64,7 +67,7 @@ }, { "cell_type": "code", - "execution_count": 3, + "execution_count": 12, "id": "17ef93bb", "metadata": {}, "outputs": [], @@ -89,28 +92,33 @@ }, { "cell_type": "code", - "execution_count": 4, + "execution_count": 13, "id": "dd960283", "metadata": {}, "outputs": [], "source": [ - "overfocus_params = OverfocusParams(\n", + "overfocus_params = Parameters4DSTEM(\n", " overfocus=0.0015, # m\n", - " scan_pixel_size=0.000001, # m\n", - " camera_length=0.15, # m\n", - " detector_pixel_size=0.000050, # m\n", - " semiconv=0.020, # rad\n", - " scan_rotation=330.,\n", + " scan_pixel_pitch=0.000001, # m\n", + " scan_center=PixelYX(\n", + " y=ds.shape.nav[0] / 2,\n", + " x=ds.shape.nav[1] / 2,\n", + " ),\n", + " camera_length=0.15, # m,\n", + " detector_pixel_pitch=0.000050, # m\n", + " detector_center=PixelYX(\n", + " y=ds.shape.sig[0] / 2 - 2,\n", + " x=ds.shape.sig[1] / 2 - 2,\n", + " ),\n", + " scan_rotation=330/180*np.pi, # rad\n", " flip_y=False,\n", - " # Offset to avoid subchip gap in butted detectors\n", - " cy=ds.shape.sig[0] / 2 - 2,\n", - " cx=ds.shape.sig[1] / 2 - 2,\n", + " semiconv=0.020,\n", ")" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": 14, "id": "e3a94908", "metadata": {}, "outputs": [], @@ -127,24 +135,24 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": 15, "id": "ed72f5e9", "metadata": {}, "outputs": [], "source": [ - "test_params = overfocus_params.copy()" + "test_params = overfocus_params.derive()" ] }, { "cell_type": "code", - "execution_count": 7, + "execution_count": 16, "id": "53d13744-74f5-4fda-8704-18f3037b8c8b", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { - "model_id": "e2a34af316554f5fb5d7595b006db96d", + "model_id": "9ccd26e91e31489a95feca653e3d6676", "version_major": 2, "version_minor": 0 }, @@ -152,21 +160,21 @@ "VBox(children=(HBox(children=(Output(), Output(), Output())), HBox(children=(Output(), Output())), HBox(childr…" ] }, - "execution_count": 7, + "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "overfocus_udf = OverfocusUDF(\n", - " overfocus_params=test_params.copy(),\n", + " overfocus_params={'params': test_params},\n", ")\n", "sum_udf = SumUDF()\n", "\n", "point_plot = BQLive2DPlot(dataset=ds, udf=overfocus_udf, channel='point')\n", "shifted_sum_plot = BQLive2DPlot(dataset=ds, udf=overfocus_udf, channel='shifted_sum')\n", "sum_plot_plain = BQLive2DPlot(dataset=ds, udf=sum_udf, channel='intensity')\n", - "sum_plot = BQLive2DPlot(dataset=ds, udf=overfocus_udf, channel='sum')\n", + "sum_plot = BQLive2DPlot(dataset=ds, udf=overfocus_udf, channel='corrected_sum')\n", "selected_plot = BQLive2DPlot(dataset=ds, udf=overfocus_udf, channel='selected')\n", "\n", "plots = (point_plot, shifted_sum_plot, sum_plot_plain, selected_plot, sum_plot, )\n", @@ -188,35 +196,36 @@ "rp = test_params\n", "\n", "# Create input and output widgets\n", - "scan_rotation = ipywidgets.FloatSlider(min=0, max=360, description='Scan rotation / deg', value=rp['scan_rotation'])\n", - "flip_y = ipywidgets.Checkbox(description='Flip detector Y axis', value=rp['flip_y'])\n", - "overfocus = ipywidgets.FloatText(description='Overfocus / m', value=rp['overfocus'])\n", - "camera_length = ipywidgets.FloatText(description='Camera length / m', value=rp['camera_length'])\n", - "detector_pixel_size = ipywidgets.FloatText(description='Detector pixel size / m', value=rp['detector_pixel_size'])\n", - "scan_pixel_size = ipywidgets.FloatText(description='Scan pixel size / m', value=rp['scan_pixel_size'])\n", + "scan_rotation = ipywidgets.FloatSlider(min=0, max=360, description='Scan rotation / deg', value=rp.scan_rotation * 180 / np.pi)\n", + "flip_y = ipywidgets.Checkbox(description='Flip detector Y axis', value=rp.flip_y)\n", + "overfocus = ipywidgets.FloatText(description='Overfocus / m', value=rp.overfocus)\n", + "camera_length = ipywidgets.FloatText(description='Camera length / m', value=rp.camera_length)\n", + "detector_pixel_pitch = ipywidgets.FloatText(description='Detector pixel pitch / m', value=rp.detector_pixel_pitch)\n", + "scan_pixel_pitch = ipywidgets.FloatText(description='Scan pixel pitch / m', value=rp.scan_pixel_pitch)\n", "blur = ipywidgets.FloatText(description='Blur metric', value=0, disabled=True)\n", "\n", "# Functions to update params and widgets\n", "def update_blur(udf_result):\n", " blur.value = blur_effect(udf_result['shifted_sum'].data)\n", "\n", - "def params_to_input(params):\n", + "def params_to_input(params: Parameters4DSTEM):\n", " tp = params\n", - " scan_rotation.value = tp['scan_rotation']\n", - " flip_y.value = tp['flip_y']\n", - " overfocus.value = tp['overfocus']\n", - " camera_length.value = tp['camera_length']\n", - " detector_pixel_size.value = tp['detector_pixel_size']\n", - " scan_pixel_size.value = tp['scan_pixel_size']\n", + " scan_rotation.value = tp.scan_rotation * 180 / np.pi\n", + " flip_y.value = tp.flip_y\n", + " overfocus.value = tp.overfocus\n", + " camera_length.value = tp.camera_length\n", + " detector_pixel_pitch.value = tp.detector_pixel_pitch\n", + " scan_pixel_pitch.value = tp.scan_pixel_pitch\n", "\n", - "def input_to_params(params):\n", - " tp = params\n", - " tp['scan_rotation'] = scan_rotation.value\n", - " tp['flip_y'] = flip_y.value\n", - " tp['overfocus'] = overfocus.value\n", - " tp['camera_length'] = camera_length.value\n", - " tp['detector_pixel_size'] = detector_pixel_size.value\n", - " tp['scan_pixel_size'] = scan_pixel_size.value\n", + "def input_to_params(params: Parameters4DSTEM):\n", + " return params.derive(\n", + " scan_rotation=scan_rotation.value / 180 * np.pi,\n", + " flip_y=flip_y.value,\n", + " overfocus=overfocus.value,\n", + " camera_length=camera_length.value,\n", + " detector_pixel_pitch=detector_pixel_pitch.value,\n", + " scan_pixel_pitch=scan_pixel_pitch.value,\n", + " )\n", "\n", "# Arrange and display widgets\n", "ipywidgets.VBox([\n", @@ -225,7 +234,7 @@ " ipywidgets.HBox([scan_rotation, blur]),\n", " flip_y,\n", " ipywidgets.HBox([overfocus, camera_length]),\n", - " ipywidgets.HBox([detector_pixel_size, scan_pixel_size]),\n", + " ipywidgets.HBox([detector_pixel_pitch, scan_pixel_pitch]),\n", " stop_btn\n", "])" ] @@ -244,25 +253,50 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": 18, "id": "597b299c", "metadata": {}, - "outputs": [], + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "step 1\n", + "step 2\n", + "step 3\n", + "step 1\n", + "step 2\n", + "step 3\n", + "step 1\n", + "step 2\n", + "step 3\n", + "step 1\n", + "step 2\n", + "step 3\n" + ] + } + ], "source": [ "with ui_events() as poll:\n", " keep_running = True\n", " stop_btn.description = 'Stop series'\n", " params_to_input(test_params)\n", + " new_params = test_params\n", + " new = True\n", " while keep_running:\n", - " result_iter = ctx.run_udf_iter(dataset=ds, udf=(overfocus_udf, sum_udf), plots=plots)\n", - " for adjustment_res in result_iter:\n", - " input_to_params(test_params)\n", - " result_iter.update_parameters_experimental([\n", - " {'overfocus_params': test_params},\n", - " {}\n", - " ])\n", - " poll(100)\n", - " update_blur(adjustment_res.buffers[0])\n", + " if new or new_params != test_params:\n", + " print('step 1')\n", + " overfocus_udf.params.overfocus_params['params'] = new_params\n", + " print('step 2')\n", + " result = ctx.run_udf(dataset=ds, udf=(overfocus_udf, sum_udf), plots=plots)\n", + " print('step 3')\n", + " update_blur(result[0])\n", + " test_params = new_params\n", + " new = False\n", + " else:\n", + " time.sleep(0.1)\n", + " poll(100)\n", + " new_params = input_to_params(test_params)\n", " stop_btn.description = 'Stopped'" ] }, @@ -280,7 +314,7 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": 19, "id": "ff6540f0-36e2-425c-8587-722cb3c88b05", "metadata": {}, "outputs": [ @@ -288,49 +322,59 @@ "name": "stdout", "output_type": "stream", "text": [ - "[0. 0.] loss 0.33090615 scan_rotation 36.8 overfocus 0.001\n", - "[-10. 10.] loss 0.4506146 scan_rotation 26.799999999999997 overfocus 0.00125\n", - "[-10. -10.] loss 0.40948784 scan_rotation 26.799999999999997 overfocus 0.00075\n", - "[10. 10.] loss 0.43503198 scan_rotation 46.8 overfocus 0.00125\n", - "[ 10. -10.] loss 0.39679593 scan_rotation 46.8 overfocus 0.00075\n", - "[0. 0.] loss 0.33090615 scan_rotation 36.8 overfocus 0.001\n", - "[1. 0.] loss 0.33091488 scan_rotation 37.8 overfocus 0.001\n", - "[0. 1.] loss 0.3307775 scan_rotation 36.8 overfocus 0.001025\n", - "[-0.06771542 1.99770468] loss 0.33506528 scan_rotation 36.73228457950865 overfocus 0.0010499426169164805\n", - "[-0.03385771 1.49885234] loss 0.33168203 scan_rotation 36.76614228975432 overfocus 0.0010374713084582404\n", - "[-0.24942617 0.98307114] loss 0.33073044 scan_rotation 36.55057383083519 overfocus 0.001024576778621929\n", - "[-0.26737678 0.48339347] loss 0.3308296 scan_rotation 36.532623216855775 overfocus 0.0010120848368328757\n", - "[-0.42486214 1.16117847] loss 0.33111203 scan_rotation 36.375137858577546 overfocus 0.0010290294617763607\n", - "[-0.25174789 0.85809271] loss 0.3307775 scan_rotation 36.548252112055124 overfocus 0.0010214523177062363\n", - "[-0.18745911 0.99121569] loss 0.33073044 scan_rotation 36.61254089004958 overfocus 0.0010247803921841008\n", - "[-0.25757071 1.0450382 ] loss 0.33074787 scan_rotation 36.54242928834832 overfocus 0.0010261259551022888\n", - "[-0.2453539 0.95208762] loss 0.33073044 scan_rotation 36.55464610207863 overfocus 0.0010238021903817493\n", - "[-0.24168029 0.98408921] loss 0.33073044 scan_rotation 36.55831971323699 overfocus 0.0010246022303172005\n", - "[-0.24891714 0.9791982 ] loss 0.33073044 scan_rotation 36.55108286474062 overfocus 0.0010244799550919066\n", - "[-0.24845793 0.9831984 ] loss 0.33073044 scan_rotation 36.55154206613542 overfocus 0.001024579960083838\n", - "[-0.24936254 0.98258703] loss 0.33073044 scan_rotation 36.55063746007337 overfocus 0.0010245646756806763\n", - "[-0.24930514 0.98308705] loss 0.33073044 scan_rotation 36.55069486024772 overfocus 0.0010245771763046677\n", - "[-0.24941965 0.98302157] loss 0.33073044 scan_rotation 36.55058034646918 overfocus 0.0010245755392807449\n", + "[0. 0.] loss 0.35099728928651697 scan_rotation 0.9948376736367678 overfocus 0.0011\n", + "[-10. 10.] loss 0.36959742497599535 scan_rotation 0.8203047484373349 overfocus 0.0013750000000000001\n", + "[-10. -10.] loss 0.3370680950899284 scan_rotation 0.8203047484373349 overfocus 0.000825\n", + "[10. 10.] loss 0.4081434098906211 scan_rotation 1.1693705988362009 overfocus 0.0013750000000000001\n", + "[ 10. -10.] loss 0.34847540110928316 scan_rotation 1.1693705988362009 overfocus 0.000825\n", + "[-10. -10.] loss 0.33706809544857086 scan_rotation 0.8203047484373349 overfocus 0.000825\n", + "[ -9. -10.] loss 0.3362874258172616 scan_rotation 0.8377580409572781 overfocus 0.000825\n", + "[-9. -9.] loss 0.33810004241484426 scan_rotation 0.8377580409572781 overfocus 0.0008525000000000001\n", + "[ -8.60444014 -10.9184402 ] loss 0.33798581760248175 scan_rotation 0.8446618629283223 overfocus 0.0007997428945743582\n", + "[ -8.80222007 -10.4592201 ] loss 0.3379815931003953 scan_rotation 0.8412099519428003 overfocus 0.0008123714472871792\n", + "[ -9.2475207 -10.0351213] loss 0.3359289983296108 scan_rotation 0.8334379898608855 overfocus 0.0008240341643355578\n", + "[-9.38275014 -9.82485243] loss 0.3371302289525947 scan_rotation 0.8310777908223704 overfocus 0.0008298165582514493\n", + "[ -9.27139704 -10.28397852] loss 0.335928999529431 scan_rotation 0.833021268943022 overfocus 0.0008171905905660535\n", + "[ -9.37194927 -10.02318272] loss 0.3359290002342965 scan_rotation 0.8312663015411064 overfocus 0.0008243624752808513\n", + "[ -9.18638697 -10.02212447] loss 0.3359289982162762 scan_rotation 0.8345049746731841 overfocus 0.0008243915770422272\n", + "[ -9.17093721 -10.08268481] loss 0.3359290002342965 scan_rotation 0.8347746238375815 overfocus 0.0008227261676550398\n", + "[-9.19594601 -9.9603598 ] loss 0.33628742514806387 scan_rotation 0.8343381379365421 overfocus 0.0008260901055289589\n", + "[-9.19116649 -9.99124214] loss 0.33628742514806387 scan_rotation 0.8344215563048631 overfocus 0.000825240841285593\n", + "[ -9.18313776 -10.0374079 ] loss 0.33592900021394734 scan_rotation 0.834561684065471 overfocus 0.0008239712826863057\n", + "[ -9.17874525 -10.02049987] loss 0.33592900239729717 scan_rotation 0.8346383477702454 overfocus 0.0008244362536637333\n", + "[ -9.20200708 -10.02173351] loss 0.3359290005602736 scan_rotation 0.8342323523597642 overfocus 0.0008244023285334918\n", + "[ -9.18102721 -10.01644045] loss 0.3359289993049074 scan_rotation 0.8345985201014626 overfocus 0.0008245478877484315\n", + "[ -9.19017107 -10.02115525] loss 0.3359289993049074 scan_rotation 0.8344389297220759 overfocus 0.0008244182307607192\n", + "[ -9.18459678 -10.02559636] loss 0.3359289986775951 scan_rotation 0.8345362194124664 overfocus 0.000824296100136165\n", + "[ -9.18491643 -10.02083909] loss 0.33592900055410835 scan_rotation 0.8345306404446015 overfocus 0.0008244269250618826\n", + "[ -9.18646769 -10.02309769] loss 0.3359289986775951 scan_rotation 0.8345035657518944 overfocus 0.0008243648134839895\n", + "[ -9.18732175 -10.02184187] loss 0.33592900021394734 scan_rotation 0.8344886597103593 overfocus 0.0008243993485757258\n", + "[ -9.18590277 -10.02206146] loss 0.33592899765194256 scan_rotation 0.8345134255320902 overfocus 0.0008243933098356772\n", + "[ -9.18544074 -10.02190352] loss 0.33592899765194256 scan_rotation 0.8345214894824513 overfocus 0.0008243976533177562\n", + "[ -9.18593428 -10.02181936] loss 0.3359290001736779 scan_rotation 0.8345128756602547 overfocus 0.0008243999675657202\n", + "[ -9.18578631 -10.02253565] loss 0.33592899860351516 scan_rotation 0.8345154581902738 overfocus 0.0008243802696438979\n", + "[ -9.1858132 -10.02183435] loss 0.3359289983296108 scan_rotation 0.8345149888955801 overfocus 0.0008243995554919303\n", + "[ -9.18600276 -10.02206029] loss 0.3359290027979101 scan_rotation 0.8345116803232335 overfocus 0.0008243933421359566\n", + "[ -9.18590336 -10.02211146] loss 0.3359289984603294 scan_rotation 0.8345134152821588 overfocus 0.0008243919349305265\n", + "[ -9.18580702 -10.02203261] loss 0.33592899749422195 scan_rotation 0.8345150966440197 overfocus 0.0008243941032406931\n", " message: Optimization terminated successfully.\n", " success: True\n", - " fun: 0.3307304382324219\n", - " funl: [ 3.307e-01]\n", - " x: [-2.494e-01 9.831e-01]\n", - " xl: [[-2.494e-01 9.831e-01]]\n", + " fun: 0.33592899749422195\n", + " funl: [ 3.359e-01]\n", + " x: [-9.186e+00 -1.002e+01]\n", + " xl: [[-9.186e+00 -1.002e+01]]\n", " nit: 1\n", - " nfev: 23\n", - " nlfev: 18\n", + " nfev: 35\n", + " nlfev: 30\n", " nljev: 0\n", " nlhev: 0\n", - "CPU times: user 8.23 s, sys: 427 ms, total: 8.66 s\n", - "Wall time: 8.16 s\n" + "Parameters4DSTEM(overfocus=np.float64(0.0008243941032406931), scan_pixel_pitch=1e-06, scan_center=PixelYX(y=32.0, x=32.0), scan_rotation=np.float64(0.8345150966440197), camera_length=0.15, detector_pixel_pitch=5e-05, detector_center=PixelYX(y=30.0, x=30.0), semiconv=0.02, flip_y=False, descan_error=DescanError(pxo_pxi=0.0, pxo_pyi=0.0, pyo_pxi=0.0, pyo_pyi=0.0, sxo_pxi=0.0, sxo_pyi=0.0, syo_pxi=0.0, syo_pyi=0.0, offpxi=0.0, offpyi=0.0, offsxi=0.0, offsyi=0.0), detector_rotation=0.0)\n" ] } ], "source": [ - "%%time\n", - "def my_callback(args, params: OverfocusParams, res, blur):\n", - " print(args, 'loss', blur, 'scan_rotation', params['scan_rotation'], 'overfocus', params['overfocus'])\n", + "def my_callback(args, params: Parameters4DSTEM, res, blur):\n", + " print(args, 'loss', blur, 'scan_rotation', params.scan_rotation, 'overfocus', params.overfocus)\n", " update_blur(res[0])\n", " params_to_input(params)\n", "\n", @@ -345,8 +389,8 @@ ")\n", "opt_res = optimize(loss)\n", "print(opt_res)\n", - "new_params = make_new_params(opt_res.x)\n", - "test_params.update(new_params)" + "test_params = make_new_params(opt_res.x)\n", + "print(test_params)" ] }, { @@ -369,33 +413,35 @@ "name": "stdout", "output_type": "stream", "text": [ - "{'overfocus': 0.001024576778621929, 'scan_pixel_size': 1e-06, 'camera_length': 0.15, 'detector_pixel_size': 5e-05, 'semiconv': 0.02, 'scan_rotation': 36.55057383083519, 'flip_y': False, 'cy': 30.0, 'cx': 30.0}\n" + "Parameters4DSTEM(overfocus=9.999999999999999e-05, scan_pixel_pitch=9.999999999999999e-05, scan_center=PixelYX(y=32.0, x=32.0), scan_rotation=np.float64(0.6847241935014454), camera_length=0.15, detector_pixel_pitch=5e-05, detector_center=PixelYX(y=30.0, x=30.0), semiconv=0.02, flip_y=False, descan_error=DescanError(pxo_pxi=0.0, pxo_pyi=0.0, pyo_pxi=0.0, pyo_pyi=0.0, sxo_pxi=0.0, sxo_pyi=0.0, syo_pxi=0.0, syo_pyi=0.0, offpxi=0.0, offpyi=0.0, offsxi=0.0, offsyi=0.0), detector_rotation=0.0)\n" ] }, { - "data": { - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAuMAAAIMCAYAAABfb6LzAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAEAAElEQVR4nOzdd5xcVfn48c85t07dzSabhIQACb0ISAkIJCC9CIiK0sQA0hT5oqJI+QoWmqLiT6Qj5UsXBAvNIAECIqCA0o1AIAFSNsnu1FvP+f1xd4fsJgSCkN2Q83698nplZu7ceeZmzuTZs+d5jtBaawzDMAzDMAzDWOHkYAdgGIZhGIZhGKsqk4wbhmEYhmEYxiAxybhhGIZhGIZhDBKTjBuGYRiGYRjGIDHJuGEYhmEYhmEMEpOMG4ZhGIZhGMYgMcm4YRiGYRiGYQwSk4wbhmEYhmEYxiAxybhhGIZhGIZhDBKTjBuGYRiGYQwRa621FlOmTGndfvDBBxFC8OCDDy73ua655hqEEMycOfNDi8/48Jlk3DAMwzCMVVZfwtr3x/d91ltvPU444QTmzp072OF96Hbaaad+79d1XcaPH88xxxzDrFmzBju8VZI92AEYhmEYhmEMth/+8IeMHz+eIAh45JFHuOSSS7j77rt57rnnyOfzgx3eh2r11Vfn3HPPBSCKIl544QUuvfRS7rvvPl588cWP3fsd6kwybhiGYRjGKm+vvfZiq622AuCrX/0qw4cP5+c//zm///3vOfjggz/QOZVSRFGE7/sfZqj/tba2Ng477LB+940fP54TTjiBRx99lN12222QIls1mWUqhmEYhmEYA+y8884AvPbaa1xwwQVst912DB8+nFwux5Zbbsltt922xHOEEJxwwgnccMMNbLzxxniex7333gvwvs/xfj3++OPsueeetLW1kc/n2XHHHXn00Uc/8PlGjx4NgG33n6d98803OfLIIxk1ahSe57Hxxhvzm9/8pt8xURTx/e9/ny233JK2tjYKhQKTJk1i2rRp/Y6bOXMmQgguuOACfv3rXzNhwgTy+Ty77747s2bNQmvNj370I1ZffXVyuRz7778/Cxcu/MDvaWVhZsYNwzAMwzAGeOWVVwAYPnw4P/7xj9lvv/049NBDiaKIm2++mQMPPJA//elP7LPPPv2e98ADD3DrrbdywgknMGLECNZaay0AfvnLX77vc7yXBx54gL322ostt9ySM888EyklV199NTvvvDPTp09n4sSJy3x+mqZ0dXUBEMcxL774ImeeeSbrrLMO22+/feu4uXPnsu2227Z+yOjs7OSee+7hqKOOolKpcNJJJwFQqVS48sorOfjggzn66KOpVqtcddVV7LHHHjzxxBNsvvnm/V7/hhtuIIoivvGNb7Bw4UJ+8pOf8MUvfpGdd96ZBx98kFNOOYX//Oc//OpXv+Lkk09eIvn/2NGGYRiGYRirqKuvvloD+v7779fz58/Xs2bN0jfffLMePny4zuVyevbs2brRaPR7ThRFepNNNtE777xzv/sBLaXUzz///BKv837Pseaaa+qvfOUrrdvTpk3TgJ42bZrWWmullF533XX1HnvsoZVS/c4/fvx4vdtuuy3x3l577bXWfTvuuKMGlviz4YYb6ldffbVfLEcddZRebbXVdFdXV7/7DzroIN3W1tZ6T0mS6DAM+x2zaNEiPWrUKH3kkUe27nvttdc0oDs7O3V3d3fr/lNPPVUDerPNNtNxHLfuP/jgg7XrujoIgiWu58fJB16m8uSTT7L33nvT3t5OoVBg22235dZbb12uc4RhyA9/+EPWXXddfN9nzJgxHHPMMcybN+9dn3PDDTcwceJECoUCw4YN4zOf+QxPPfXUhxbn22+/zVFHHcVqq62G7/usv/76nH322cRxvFzvzTAMwzCMlceuu+5KZ2cn48aN46CDDqJYLHLHHXcwduxYcrlc67hFixbR09PDpEmTlpp/7Ljjjmy00UZL3L8851iWZ555hhkzZnDIIYewYMECurq66Orqol6vs8suu/Dwww+jlFrmOdZaay2mTp3K1KlTueeee7jwwgvp6elhr732Yv78+QBorbn99tvZd9990Vq3Xqerq4s99tiDnp6eVuyWZeG6LpCtk1+4cCFJkrDVVlst9f0deOCBtLW1tW5vs802ABx22GH9lslss802RFHEm2++uVzXaGXzgZapTJs2jT322APf9znooIMolUrcfvvtfOlLX2LWrFl8+9vffs9zKKXYf//9ue+++9h22235/Oc/z4wZM7jyyiv5y1/+wt/+9jc6Ozv7Pefss8/mjDPOYM011+S4446jWq1y8803s9122/GXv/yl369WPkicc+bMYZtttmH27NkccMABrLvuujz00EOcccYZPPHEE9x5550IIT7IJTMMwzAMYwj79a9/zXrrrYdt24waNYr1118fKbM5yz/96U/8+Mc/5plnniEMw9ZzlpYTjB8/fqnnX55zLMuMGTMA+MpXvvKux/T09DBs2LB3fbxQKLDrrru2bu+5557ssMMObLXVVpx33nn87Gc/Y/78+XR3d3P55Zdz+eWXL/U8i0+eXnvttfzsZz/jpZde6jeBubTrscYaa/S73ZeYjxs3bqn3L1q06F3fy8fBcifjSZJw9NFHI6Xk4Ycfbq0D+v73v8/EiRM57bTT+MIXvsCaa665zPNce+213HfffRx88MHccMMNrQ/jpZdeyvHHH88ZZ5zBZZdd1jp+xowZnHXWWay33no88cQTrX+gr33ta2y77bYcffTRPPfcc62B80HiPOWUU5g1axaXXHIJxx13HJD9ZHjIIYdw8803c/PNN3/gimrDMAzDMIauiRMntrqpLG769Onst99+TJ48mYsvvpjVVlsNx3G4+uqrufHGG5c4fvEZ8A96jmXpm/X+6U9/usRa7D7FYnG5zgm0ii8ffvjhfq9z2GGHvWviv+mmmwJw/fXXM2XKFD772c/yne98h5EjR2JZFueee25r7f3iLMta6vne7X6t9XK/n5XJcifjDzzwAK+88gpHHHFEvw9BW1sbp512GlOmTOHaa6/l+9///jLPc8UVVwBw7rnn9vup8Nhjj+WnP/0pN9xwAxdeeGHrQ3311VeTJAmnn356v19tbL755hx88MFcc801PPLII0yePPkDxVmtVrnllluYMGECxx57bOt4IQTnnXceN998M1dccYVJxg3DMAxjFXL77bfj+z733Xcfnue17r/66qtX6Dn6rL322gCUy+V+s9sfhjRNqdVqAHR2dlIqlUjT9D1f57bbbmPChAn87ne/65fTnXnmmR9qfB9Xy71mvG871t13332Jx/bYYw8AHnrooWWeIwgCHn/8cdZff/0lZtCFEOy2227U63X+/ve/f+DXXd7jH3vsMcIwZLfddlviV0Zrrrkm66+/Po8++ihpmi7zvRmGYRiG8fFhWRZCiH7//8+cOZM777xzhZ6jz5Zbbsnaa6/NBRdc0EqcF9e35nt5TZs2jVqtxmabbdaK+fOf/zy33347zz333DJfp29Ge/EZ7Mcff5zHHnvsA8WyqlnumfG+tUrrrrvuEo+NHj2aYrHY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v/wy22+/fb+doYyPp771jcbH34SmM9ghGCuQGduGYQxFy52M77LLLkyYMIEbb7yRZ555pnV/T08P55xzDq7rcvjhh7fuf/vtt3nppZeWWP5xzDHHAHDqqaf2S34vu+wyXn31VQ499NB+jfOPOOIIbNvm7LPP7neuZ555hptuuokNN9yQHXbY4QPHWS6XOeigg3j11Vf7bTaktebUU08F4Oijj17ey2UYhmEYhmEY72q5p3lt2+bKK69kjz32YPLkyf22mX/99de54IILWGuttVrHn3rqqVx77bVcffXVTJkypXX/V77yFW655RZuuukmXnvtNXbccUf+85//8Lvf/Y7x48fz4x//uN/rrrfeepx11lmcccYZbLbZZnz+85+nWq1y8803A1nRZ9/umx8kTninhc/XvvY17r//ftZZZx0eeugh/va3v7Hvvvty0EEHLe/lMlZCY8eOHewQjBXkb23BYIdgrEBmbBuGMRQt98w4wKc//WkeeeQRtt9+e2655RYuueQSRo0axc0338y3v/3t9/fCUvL73/+es846i/nz5/OLX/yCRx99lKOOOorHHnuMzs7OJZ5z+umnc/3119PZ2ckll1zCrbfeyqRJk1rdWf7bOFdbbTUef/xxjjjiCB555BF+8YtfsGDBAn70ox9x2223LbEZkPHx1Ne2zfj426juDnYIxgpkxrZhGEPRB14APXHiRO655573PO6aa67hmmuuWepjnudx5plnLtd2qYceeiiHHnro+z7+/cbZZ7XVVuOqq65638cbHz8D21MaH1/l5APNRxgrKTO2DcMYisz/RIYxgOua2dJVRdVW732Q8bFhxrZhGEORScYNY4ClLZEyPp6eK5iZ0lWJGduGYQxFJhk3jAH6tmc2Pv4+1ZN774OMjw0ztg3DGIpMMm4YhmEYhmEYg8Qk44YxQHt7+2CHYKwgr+XiwQ7BWIHM2DYMYygyybhhDLB4v3rj4y0RZnv0VYkZ24ZhDEXmm8kwBli4cOFgh2CsIOs2THeNVYkZ24ZhDEUmGTcMwzAMwzCMQWKSccMYYMyYMYMdgrGCPFEOBjsEYwUyY9swjKHIJOOGMYD5VfaqY92mM9ghGCuQGduGYQxFJhk3jAGCwMyWriqGxdZgh2CsQGZsG4YxFJlk3DAGcBwzW7qqaFhqsEMwViAztg3DGIpMMm4YA4wePXqwQzBWkKdK4WCHYKxAZmwbhjEUmWTcMAaYNWvWYIdgrCA7dOcGOwRjBTJj2zCMocgk44ZhGIZhGIYxSEwybhgDtLW1DXYIxgryuh8PdgjGCmTGtmEYQ5FJxg1jANu2BzsEYwVpSj3YIRgrkBnbhmEMRSYZN4wBFixYMNghGCvIBg13sEMwViAztg3DGIpMMm4YhmEYhmEYg8Qk44YxgGl/tur4R8lsArMqMWPbMIyhyCTjhjFAT0/PYIdgrCBrBWYTmFWJGduGYQxFJhk3jAGazeZgh2CsIMNja7BDMFYgM7YNwxiKTDJuGAOYjgurjkCqwQ7BWIHM2DYMYygyybhhDDBmzJjBDsFYQZ4oh4MdgrECmbFtGMZQZJJxwxjgjTfeGOwQjBVkcndusEMwViAztg3DGIpMMm4YhmEYhmEYg8Qk44YxQKlUGuwQjBVktp8MdgjGCmTGtmEYQ5FJxg1jAM/zBjsEYwWpWKaAc1VixrZhGEORScYNY4Curq7BDsFYQTaqu4MdgrECmbFtGMZQZJJxwzAMwzAMwxgkJhk3jAFGjRo12CEYK8jTJdPacFVixrZhGEORScYNY4BqtTrYIRgryNjQ7MC5KjFj2zCMocgk44YxQKPRGOwQjBVkZGR2ZFyVmLFtGMZQZJJxwxhASjMsVhWx1IMdgrECmbFtGMZQZL6ZDGOAcePGDXYIxgry17ZgsEMwViAztg3DGIpMMm4YA5gts1cdk7r9wQ7BWIHM2DYMYygyybhhDKC1WbqwqpBaDHYIxgpkxrZhGEORScYNY4BisTjYIRgryNteMtghGCuQGduGYQxFJhk3jAFyudxgh2CsIF1OOtghGCuQGduGYQxFJhk3jAHmz58/2CEYK8gnat5gh2CsQGZsG4YxFJlk3DAMwzAMwzAGiUnGDWOAkSNHDnYIxgryr2I42CEYK5AZ24ZhDEUmGTeMAcwufauOztga7BCMFciMbcMwhiKTjBvGALVabbBDMFaQ1UJ7sEMwViAztg3DGIpMMm4YAwhhek+vKlJh+k6vSszYNgxjKDLJuGEMsMYaawx2CMYK8kh7MNghGCuQGduGseqaMmUKa621Vr/7hBCcddZZgxLP4kwybhgDzJo1a7BDMFaQ7Xv8wQ7BWIHM2DYGOuussxBC0NXVtdTHN9lkE3baaacVG9SHSCnFddddxzbbbENHRwelUon11luPww8/nL/97W+DHd4yzZ07l5NPPpkNNtiAfD5PoVBgyy235Mc//jHd3d2DHd6HyiyYNIwBlFKDHYKxgtjKLFtYlZixbaxqTjzxRH7961+z//77c+ihh2LbNi+//DL33HMPEyZMYNtttx3sEJfqySefZO+996ZWq3HYYYex5ZZbAvD3v/+d8847j4cffpg///nPy3XOK664Ysh+B5hk3DAGKBQKgx2CsYLMdZPBDsFYgczYNj5ulFJEUYTvL/lbvrlz53LxxRdz9NFHc/nll/d77MILLxyym2B1d3dzwAEHYFkWTz/9NBtssEG/x88++2yuuOKK5T6v4zgfVogfOrNMxTAGKBaLgx2CsYLMcdPBDsFYgczYNv5bDz74IEIIbrnlFk477TRGjx5NoVBgv/32W2IZ1E477cQmm2zCP/7xD7bbbjtyuRzjx4/n0ksvXeK8YRhy5plnss466+B5HuPGjeO73/0uYdh/LwQhBCeccAI33HADG2+8MZ7nce+99y411tdeew2tNdtvv/0Sjwkhlui7393dzTe/+U3WWmstPM9j9dVX5/DDD28t4YmiiO9///tsueWWtLW1USgUmDRpEtOmTet3npkzZyKE4IILLuDyyy9n7bXXxvM8tt56a5588sn3vMaXXXYZb775Jj//+c+XSMQBRo0axRlnnNHvvosvvrh1PcaMGcPXv/71JZayLG3N+FBhZsYNY4C5c+ey5pprDnYYxgqwWc3jwQ4zO76qMGPb+LCcffbZCCE45ZRTmDdvHhdeeCG77rorzzzzDLlcrnXcokWL2HvvvfniF7/IwQcfzK233srxxx+P67oceeSRQDa7vd9++/HII49wzDHHsOGGG/Lss8/yi1/8gn//+9/ceeed/V77gQce4NZbb+WEE05gxIgR75pg9n3Wf/vb33LggQeSz+ff9f3UajUmTZrEiy++yJFHHskWW2xBV1cXf/jDH5g9ezYjRoygUqlw5ZVXcvDBB3P00UdTrVa56qqr2GOPPXjiiSfYfPPN+53zxhtvpFqtcuyxxyKE4Cc/+Qmf+9znePXVV5c5S/2HP/yBXC7HF77whWX8C7zjrLPO4gc/+AG77rorxx9/PC+//DKXXHIJTz75JI8++uiQnhHvY5JxwzAMwzCM5bBw4UJefPFFSqUSAFtssQVf/OIXueKKKzjxxBNbx7311lv87Gc/41vf+hYAxx57LNtssw2nnnoqX/7yl3EchxtvvJH777+fhx56iB122KH13E022YTjjjuOv/71r2y33Xat+19++WWeffZZNtpoo2XGuNpqq3H44Ydz3XXXsfrqq7PTTjux/fbbs88++ywx4/zTn/6U5557jt/97ncccMABrfvPOOMMtM5awA4bNoyZM2fium7r8aOPPpoNNtiAX/3qV1x11VX9zvnGG28wY8YMhg0bBsD666/P/vvvz3333cdnPvOZd437xRdfZL311uv3Ou9m/vz5nHvuuey+++7cc889SJkt+Nhggw044YQTuP766zniiCPe8zyDzSxTMYwBOjs7BzsEYwV5vhC+90HGx4YZ28aH5fDDD28l4gBf+MIXWG211bj77rv7HWfbNscee2zrtuu6HHvsscybN49//OMfQDZzveGGG7LBBhvQ1dXV+rPzzjsDLLEMZMcdd3zPRLzP1VdfzUUXXcT48eO54447OPnkk9lwww3ZZZddePPNN1vH3X777Wy22Wb9EvE+ff35LctqJchKKRYuXEiSJGy11VY89dRTSzzvS1/6UisRB5g0aRIAr7766jJjrlQq/a7tstx///1EUcRJJ53USsQh+yGhXC5z1113va/zDDaTjBvGAEFgek+vKtoTa7BDMFYgM7aND2Jpm0Wtu+66SxyzzjrrMHPmzH73jxkzZonC4fXWWw+gdeyMGTN4/vnn6ezs7Pen77h58+b1e/748ePfd+xSSr7+9a/zj3/8g66uLn7/+9+z11578cADD3DQQQe1jnvllVfYZJNN3vN81157LZtuuim+7zN8+HA6Ozu566676OnpWeLYgX39+xLzRYsWLfM1yuUy1Wr1/bw9Xn/9dSCbdV+c67pMmDCh9fhQZ5apGMYA1WqVjo6OwQ7DWAHGhjYzzOz4KsOMbWOgvi4kzWZzqY83Go2ldir5MCml+MQnPsHPf/7zpT4+bty4frcXX5O+PIYPH85+++3Hfvvtx0477cRDDz3E66+//r7rKK6//nqmTJnCZz/7Wb7zne8wcuRILMvi3HPP5ZVXXlnieMta+mRH37KXd7PBBhvwzDPPEEXR+1qq8nFgknHDMAzDMFZJfYnoyy+/vETS22g0mDVrFrvvvvsSz5sxY0a/21pr/vOf/7Dpppv2u/+tt96iXq/3mx3/97//DdAqvFx77bX55z//yS677LLUWfiPwlZbbcVDDz3E22+/zZprrsnaa6/Nc889t8zn3HbbbUyYMIHf/e53/eI888wzP9TY9t13Xx577DFuv/12Dj744GUeu/i/34QJE1r3R1HEa6+9xq677vqhxvZRMctUDGMA021h1fHQsKXPhhkfT2ZsGwPtsssuuK7LJZdcssSGMJdffjlJkrDXXnst8bzrrruu31KK2267jbfffnuJY5Mk4bLLLmvdjqKIyy67jM7OztZGNl/84hd58803l9o7u9lsUq/XP9B7mzNnDi+88MIS90dRxF/+8heklKyzzjoAfP7zn+ef//wnd9xxxxLH981k9810Lz6z/fjjj/PYY499oPjezXHHHcdqq63Gt7/97dYPLoubN28eP/7xjwHYddddcV2X//f//l+/uK666ip6enrYZ599PtTYPipmZtwwBpg9ezarr776YIdhrADb9vg81t4Y7DCMFcSMbWOgkSNH8v3vf58zzjiDyZMns99++5HP5/nrX//KTTfdxO67786+++67xPM6OjrYYYcdOOKII5g7dy4XXngh66yzDkcffXS/48aMGcP555/PzJkzWW+99bjlllt45plnuPzyy1st97785S9z6623ctxxxzFt2jS233570jTlpZde4tZbb+W+++5jq622Wu73Nnv2bCZOnMjOO+/MLrvswujRo5k3bx433XQT//znPznppJMYMWIEAN/5zne47bbbOPDAAznyyCPZcsstWbhwIX/4wx+49NJL2WyzzfjMZz7T6rayzz778Nprr3HppZey0UYbUavVPsDVX7phw4Zxxx13sPfee7P55pv324Hzqaee4qabbuJTn/oUkBVln3rqqfzgBz9gzz33ZL/99uPll1/m4osvZuutt+awww770OL6KJlk3DAGSFOzEcyqwlMr5lfCxtBgxraxNKeffjprrbUWF110ET/84Q9JkoTx48fzgx/8gFNOOaVfl44+p512Gv/6178499xzqVar7LLLLlx88cVL9PIeNmwY1157Ld/4xje44oorGDVqFBdddFG/pF1KyZ133skvfvELrrvuOu644w7y+TwTJkzgf/7nf1qFnMtr/fXX58ILL+Tuu+/m4osvZu7cufi+zyabbMIVV1zBUUcd1Tq2WCwyffp0zjzzTO644w6uvfZaRo4cyS677NL6AXbKlCnMmTOH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1nq8u7sby7L4f//v/7Xu6+rqQkrJ8OHD+61LPv7445eoXXj88cfZc889aWtrI5/Ps+OOOy6xnPass85CCMELL7zAIYccwrBhw5aZl7zyyiusvvrqS93oamkNK+655x523HFHSqUS5XKZrbfemhtvvLH1+PTp0znwwANZY4018DyPcePG8c1vfpNms9nvPFOmTKFYLPLmm2/y2c9+lmKxSGdnJyeffDJpmr5rvJBNvJ577rlssMEGXHDBBUutV/nyl7/MxIkTW7dfffVVDjzwQDo6Osjn82y77bbcdddd/Z4zc+ZMhBBcc801y3z9wbJcP1rYts2VV17JHnvsweTJkznooIMolUrcfvvtvP7661xwwQX9ZpxPPfVUrr322n4L5iH7gJ588smt23Ec09XV1e+YCy64oLW+77jjjmPq1KmMHj2aUqm01K3sp0yZ0nrtl156id12243tttuOddddl87OTmbNmsW9997LggUL2Hnnnfnud7/b7/nrrbceZ511FmeccQabbbYZn//856lWq9x8880AXHHFFWb3TcMYJJ/ZeCJjvzOC31x8ObVf/QH9lV1x1xmNtB2SRohUDjg2thCoNIFEYVkOaR7SWg1R9JAR4FsQ6d7CToXIe4ikRlBJ8cs5lGURLujBG17EK7qEjQBQuKUcUSMkmNuDPbyEHUCwsIbfXqA4poNgfjcydbE7yiRdFWrVBr6rkO0FVDWk0VMnXyzgloYRVRcR9TRx8znctjxRtQqhjVf00IEiSWOkkii/gIqaYEksIRF2VgwaNQK8gocs2IsVdkZYRY+oEaGSBLe3sFOlCpSVzQaVfdJaA3IOJArhW6SxQvVU8YaXULWQJFVQbeKUPCQWcdiAROOMbKftpH2pXvsAN//6SmYf+BkO2Wmvwf5YGMYK8fzzzzNp0iTK5TLf/e53cRyHyy67jJ122omHHnqIbbbZhvb2djbZZBMefvhhTjzxRAAeeeQRhBAsXLiQF154gY033hjIktpJkya1zv/AAw+w1157seWWW3LmmWcipeTqq69m5513Zvr06f0ST4ADDzyQddddl3POOWeZxYdrrrkm999/Pw888AA777zzMt/jNddcw5FHHsnGG2/MqaeeSnt7O08//TT33ntva/Lyt7/9LY1Gg+OPP57hw4fzxBNP8Ktf/YrZs2fz29/+tt/50jRljz32YJtttuGCCy7g/vvv52c/+xlrr712q8Pc0jzyyCMsXLiQk0466X3NYs+dO5ftttuORqPBiSeeyPDhw7n22mvZb7/9uO222zjggAPe8xxDwfLN8wOf/vSneeSRRzjzzDO55ZZbiOOYT3ziE5x//vl86Utfel/nqNVqS+zUWa/X+9131llntZLxvi4rc+bMWaJ1YJ+ddtqplYyvvfbaTJkyhSeffJI777yTnp4eisUim266KYcccghf/epXl/qPfPrpp7PWWmtx4YUXcskll+C6LpMmTeJHP/oRW2yxxft6b8bKb9GiRa12lsbQ8cnVJvC9U77Lzy+7mNpld5P/wvb4W6+PytuoIMgKO30LmQiSMEaIrLBTF/OoegPheb2FnQpECqlmnYbLm8PyJGGQFXbmc8TlIuH8HrxhbXjFInElREVN3EIe5bokXVXcjhJ2u6RRq+GrHPbwdpKFNdSCCu6IMna9SRSEyEqCUy6g0NQqddwoQrTlEJWEKIxxNbhtbUSLasT1AMfPYduKpBkhdITI5dFBk1iFICSOJcCVhM0GtnSxih5xvQ6Oi9Dg5FxSlRAvqmG159CNGJ0qYh1hRxZW2SeuBmArbMfGsWxiKYnnV7A7SshmSpxGUM1+o+DkfdJ6CvUGMp+jdNSe1P/wGI/c+kfenvM2Jx54eFYcupIwY9v4IM444wziOOaRRx5hwoQJABx++OGsv/76fPe7321tCDhp0iRuu+221vOmT5/ODjvswEsvvcT06dPZeOONW4n5McccA2Tro4877jg+/elPc88997Rmgo899lg23nhjzjjjjCWWz2622Wb9ZqzfzYknnsj//d//scsuu7D55puz44478ulPf5rddtuNfD7fOq6np4cTTzyRiRMn8uCDD+L7fuuxxZP9888/v9/O6ccccwzrrLMOp512Gm+88QZrrLFG67EgCPjSl77E//7v/wLZpOoWW2zBVVddtcxk/MUXXwTgE5/4xHu+P4DzzjuPuXPntq41wNFHH82mm27Kt771Lfbff/+VYiL1A0U4ceJE7rnnHnp6emg0Gjz++ONLTcSvueYatNb9ZrwB1lprLbTWy/yz+Az7gw8++J7H77TTTq3jx40bxxVXXMEzzzxDV1cXcRyzaNEiHnroIY499thl/rR16KGH8uSTT9JoNOju7uauu+4yibhhDBFjix388H++w8itN6Zx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o5c97z2XX3kFtRK0zjmOTIa64PhQtlBqjS0MMldIIM01pl2iBtIwK55nYB1ea7QOM91SaoQXyFSABOcsklDqUCQKV4RFkKYweCeQiYKiQqdhdlspgdQ63Ne63sfmEMBP2MSrV+YpMhQED7ndE7McEj2QQGWQUuF8KHU4vrATSS9n3fcCeIfWaW9WPQTTAoUUAukkUgqcEzhpw+x4M4XaY+mlwmgZzkll0c0USfgAYhx4pWhdcBL18jV85sYvhW8IpshLKecwen5xvKPJbrvttk3O5H77298GYN99991uxyKE4J//+Z+55JJLeMc73rFF9+10OvzoRz/a5G3f+c53gGeey/iM9vrP+957733W+79YTz75JF/96lcnfh4ZGeHKK6/kkEMO2WSKCsDhhx/Onnvuyac+9Sna7fZGt69YsWKbHOtUecEz4z/5yU+45JJLuPvuu6nrmoMOOoj/+l//K+ecc85m3f/yyy/n3e9+97Peftttt020ln0x+33qqae4+OKL+fa3v82aNWvYddddeec738l/+2//bZMrpcuy5BOf+ARf+MIXWLJkCTNmzOCMM87gf/yP/7Hdao5G29cPfvADHv7Nbxl836mIwSYLlyr+MNxFKI3T4K0F5/CEWfG6LnGVIRkIFVSSoSb1inXogd6suBMI6ZBSofOUeqQNeRZyrdsemQpUqkLQKiVSerz0YZbbAQjwIc3EGRByfJVlCJLleIv7TcQV43nlUmtMWSCFDGkn4VpcZZGtFLoGV/fy04XEtAt0K8dZCVjoFMhUY7xF13VYVJpoTDuUcfTe47RDVhKZClxlUHmGaReooSag8dJgnUX1vgVAKuhUyKEcvWAW+amHsvQ79/Kdgw7m9Xsduk3H+NmsXbt2g4VJ0UtbHO9osg9+8IN0Oh3OOuss9ttvP6qq4u677+a6665jt912e8445bkYY561xf1ZZ53FwMDAJm8788wzOfPMM7d4f51Oh2OOOYajjz6a0047jQULFrB27Vq+9rWvceedd/KmN72JQw8N77NnnHEGN9xwA2eddRZveMMbeOSRR/i3f/s39t9//00Gvi/WPvvsw3vf+15+8pOfMGfOHC699FKWL1/OZZdd9qz3kVLyuc99jtNPP50DDjiAd7/73cyfP58nnniC2267jaGhIb75zW9u9WOdKi8oGL/ttts49dRTyfOc8847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N9X6ICBpDAiLUGGZwBlaUVxkN7FIdI9cxR/bQH33bVGbzeT3Z1/IQ6PLnsHNqLAu4iknvRUqPAMUGuHzzjuPY445hmnTpjEwMMBb3/pWFi5c2LfuHnvswTbbbMNf/vIXdtppJ+r1OhtttBHf//73x+230+lw3HHHsckmm1Cr1Zg9ezaf/OQn6XQ6fesJIfjwhz/Mj3/8Y7beemtqtRq/+c1vnvV5BEHA//7v/7LVVlvxne98h5UrV/YtP+ecc9h+++2p1+tMnjyZQw45ZNz53XPPPRxwwAFMmzaNOI6ZNWsWhxxyyGr3tcMOO9BoNJg0aRK77bYbl112Wbn84osv5k1vehMzZsygVqsxb948vvjFLzrZ4Wqu5/z589lzzz1pNBrMnDmTr371q097vo888ginnHIK//zP/zyuEC+uxyc+8QlmzZpVfnbLLbew3377MTQ0RLPZZO+99+aGG27o2251mvHngqoYr/CCIssyTjv9R8gNJtB8y44lW90bB+8i732svdb9TZt5jjQQhkGp/Y6acVncZqMpUgY+uZFSK47x4S0dTZ7mpb1doRU3xiBU0JNk2WW2i2Y/k3QImw0W1wqm1DGohbzE6K7tn/HfnEIvHoTKMey9loOF7rrns9U6pPT0DUpFWaz2OsBQaLefCsYH/fQy4lJg8/EFSBEmZMZW6z1Jod1i2znKdJtn/a6Vu4c6SejXjUuKCz0uFdW706ihAbLlre76vphXcdRt5PTyGJ2kXYlL7HoAXFppCJiy4FeN2M3rdEau85JZL4OAIkluLOQ5zjvdsLQp+u6JjIIeuUo3eEogGDx0T2yq+f5Pzyav5CovSVQJnBVeKHzpS1/i17/+NZ/61Kc46qijuPzyy/mnf/qncY49y5cv541vfCPbb789X/3qV5k1axYf/OAH+dGPflSuY4zhrW99K1/72td4y1vewre//W32339/TjrpJA4++OBxx77iiiv4r//6Lw4++GC+9a1vPetmwQJBEPCv//qvtFotrrvuur5zO/zww9l00035xje+wUc/+lF+//vfs9tuu7FixQoA0jRl33335YYbbuA///M/+e53v8v73/9+7r///nIdgC984QscdthhhGHI8ccfzxe+8AVmz57NFVdcUa5zxhln0Gw2+djHPsa3vvUttt9+ez73uc/x6U9/etyYly9fzhve8Aa22247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vZUf/OAHhKGTXR522GGcf/75HHnkkVx55ZXsvPPO5HnOggULOP/88/ntb3/La17zmud8jitXruScc84BHNt/77338vOf/5z77ruPQw45hC9+8YvluvPmzeOEE07g6KOP5sEHH2T//fdncHCQBx54gIsuuoj3v//9fOITn+CKK67gwx/+MO94xzvYbLPN0Fpz9tlnEwQBBxxwAOCkL5/5zGf44he/yK677srb3/52arUaf/7zn5kxYwYnnngiO+20E5MmTeLf//3fOeqooxBCcPbZZz+t7OS54Otf/zr33XcfRx11FD//+c9585vfzKRJk3j44Ye54IILWLBgAYcccggAJ5xwApdffjm77LILH/rQh1BKccopp9DpdJ6Rr/mzRVWMV3jOuO6667hz/nwG37svdqiOGCtPKTzFQ+VtABPU2KTNVCNCZ1uUjrRAeU24I1/RKzuImug6o6QpRkqkKdjenDxztnjSR7U7CYOTW4jAF9dp10aPVJfe4tlwCznoXFRMqqGhuG5KihLO79oiQAukkaXNoSvoNeiMYKCJ0T6YwPjmzbjfrlEWrHSPu0vfO6lC/94DpRTPugSXY/4GV2S2NIF3hiqL8OJUIi+07t0kitAjIxSn219gA9KgtXYuKRGOPTapL5SjLosvJca4AHmhtZ/cFMx6V6ri/OPb1AYHvHe5OwcVSXRqykTOIqFTNmNMAgqXfqrTFBXHnjGXfey4SXWXHffSHWP882gkf5iiMQhkGGCzzMnni6LbO96UNpcq9jIVXU4I1IZTqe/7ahb+5gYu22Y79t24/xV1hXULc+bMWdtDqLAO4jOf+Qxz587lO9/5DscffzxaazbaaCO+8IUv8KlPfWq1byaPOeYYbr/9dk488URWrVrF3nvvzcknnzzOy37SpEmceeaZ/Od//iennnoqU6dO5Tvf+U5f0S6l5Be/+AUnnXQSZ511FhdddBGNRoONN96Yj3zkI89ILvJUeOSRR0ppRrPZZPr06bz+9a/ne9/7Hv/8z/88bv1Pf/rTbLbZZpx00kl84QtfAByzvM8++/DWt74VgO222459992XX/3qVzz66KM0Gg222247Lr30Ul73uteV+zr++OPZaKON+Pa3v81nPvMZGo0Gr3jFK8rxrLfeelxyySV8/OMf59hjj2XSpEm8853vZO+992bfffd9Xuc9Fo1Gg0sv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Ou0jyntxySWXsP322zNt2jSOPPJITjnllDXuf9q0aZx99tkcdNBBfbOWL3/5y+y4445897vf5fDDD2eHHXYYt+0ee+zB5z//+accf4VnhxoBm8sJbD771TD71azaJ+PubAW33n8X9955FyN3Pkz7wutoW5DrDaE2nYHadCbRJtOQgw1ko4ZJnFQiNwbT0gRxBKFEopCx8iFBBmENmTAwnBJGNcLYsd5hIyYfTZw0AokRQJoS1AKCKILcoGo1x5y3jCvOc8+cDzYItGfORYDQAmukY/OtXy+QhBOa5NZiWh2EgDxxBZxs1glQEFsCKbDaok2O7GhM7s4pUJJwogvuya2BICBvjTiWOVLO0QXhitDckEuL1IbcGuzICFJIVFxH5DkilAQGTCcl0xkiB2sNUb2BUC5kyaaarNVCJwnS5ghpCBtNbCQRQYhNczrDI2RZG90OUGGAjWrU4hhjcgSCzvCIC+nJNbW4gQkVg+utT9JKUDWFTloYA63FI6h6hAwiF+qUGyfb6Gh0J0GPamSokGGMHPBJmkZjkgSTGowQRI0YIwQqCkmTBJ0nmFzjojqlm5BgybMUk0NmXYKmChUiigkMEEDWyTCLlgAglAIE1AJqURPdSchWtRGB81a32mJDkPWIIPdvNDKDMRrjTW+wAhFZhIycqYyU7p60MrJAuElIkRBaDwkCge6k5KlE4Bl0FSACf5+l8JaekjzVmFqE3Gwm0ZYbIiVYCQy3MI8uJXt4CQ8+toT7Lr8HEvcfW22oybTZM5k3Zy6bzN6QOXPmMGnSpEqHXqHC88Df/vY3dt11V4aGhvjkJz9JGIaccsop7LHHHlx99dXsuOOOTJw4kW222YZrrrmGo446CnAp1UIIli1bxvz589l6660BRxjuuuuu5f6vuOIK9ttvP7bffnuOO+44pJScfvrp7LXXXlx77bXjapV3vOMdbLrppnz5y19+XrHxBx54IO95z3u47LLL+NKXvgTAk08+yete50izD3/4w0yZMoVLL72U97znPQwPD/PRj34UgFNPPZWjjjqKAw88kI985CMkScLtt9/OjTfeyKGHHgrAY489xg477MCKFSt4//vfzxZbbMGjjz7KhRdeSKvVIooi7r//fn7xi1/wjne8g4022ognn3ySU045hd1335358+czY8aMvjF/5StfQUrJJz7xCVauXMlXv/pV/u3f/o0bb7zxKc/1V7/6FRtvvDE77bTTM7o2733veznzzDM58MAD+fjHP86NN97IiSeeyJ133slFF130LK/00+NZFeNXXHEF9913H0cccUQfUzxhwgSOOeYY3vWud3HmmWfyuc997in3c/LJJ/Pwww9z2mmnjSvEgdXagL3pTW96xuN85StfuVome+rUqXzgAx/gmGOO4ZprrlltMV7hxccgIduHU9h+8ynYzXdmyf4pd44u4pa75rNwwb0kCxaS3rCAlhAEM9dDbTaTcNMZhBtOJRxskCUdZ3WoDZlOIekQxjWoO3u/UCqyJCHPDFIbjIBs5UrCsLc4j8hWtVzypcWlL2YZQSS5bkILYaQrzvOMvJW6HsXcYIUp0zZNrrFWEeA053k7BZFjZY4VknBCA1CONbUWk+QYnSEbdUKlQBoCEWF1jjGWvKOdLMFqhJSEzaaTjuQGKaQr4rI2UkWQC6wwrgjWKQgw5AgL2WiCkhLCkEAEiEASBBE66ZCnOXmWusIxilDNOkIECGHIkhZklo5JXBFbixgYXI+so4kiRbJqGCskWSelVo8RQcDAhCGSVpswrpGsGqHTSclGR6E5AJ49D2oxMhDkWY7ppOhOijGaKHJvDWTccJaPQmA6HdJWgpGSKFREExreJVKi0wQ9krlo+nqEilxIkkSgOx1sbty1UgIRBqgowmpL3nFsu2kZCLy2PAwwxnBNvYVuZ5jhNgQglCuqpapRr8XododsdBWBiJBKYnONDSJULUb6RFOjAZv6At3pyIWSrsAWYOuS3GpXoEtfoOsUpWJUo0aARWcpeSYRxqAzgwqdzCZoRmB8c62U2I7GBBK58XTizWe7YKpQwGiKfWwJ+qHFPPLoEh6+5mquGE0AiAbqbDBrBhvN2ZBNZ89lzpw5rL/++quN+H65Y/bs2Wt7CBVegjj22GPJsozrrruOjTfeGIDDDz+czTffnE9+8pNcffXVgJODXHjhheV21157LbvssgsLFizg2muvZeutty4L8/e///2AaxA/8sgj2XPPPbn00kvLifMHPvABtt56a4499thxuuTttttuHAP9XBCGIZttthn33Xdf+dlnPvMZ8jznjjvuYL311gMo5b2f//zn+cAHPkC9XufXv/41W2+9NRdccMEa93/00UfzxBNPcOONN/Y1xx5//PHlJGLbbbfl7rvv7vt9dNhhh7HFFltw2mmn8dnPfrZvn0mScOutt5ZE66RJk/jIRz7CX//6V7bZZpvVjmN4eJhHH320JIGfDrfddhtnnnkm733vezn11FMB+NCHPsQGG2zA1772Na688sqnlDU/FzyrYrywbtlnn33GLdt3330ByofyqXDeeechhOCAAw7grrvu4rLLLqPdbrPFFlvwhje84QXT4KwORSf9mnx/77nnHr75zW/SbreZNWsWe+21VxWf/CJCIJhCjSkDs9nt1bPJX71PV2++4E6eXHAf6Q0L6FxxG3i9ebj5TMJNZhLMmEQ9bJC1EufEkRl0qpEqI6iFBF5vXlOSbNSvYzQaAyudq0IQOrFyVK+Rrhwlb2t2SJr8sTHiinMlIZQuuTOqoW1GnvhiVneL88A45lzIEJkH6NyQjaZI0XHrBYJwsA5qkKzVwmbWSR/SxDHnvsFU1iOsCTAmJ8s1MjWu8DcQxjEEEoNG5a4pNE9ayJrCYAlyC0oREiEDQUZOICRZxxfngSQcbGDSBFVvYNot6OR0EEShxEiBGqghUoGqx+gkRbfaZO0MESuEDAmbdaxqE8Z1kiShMzxM1ukgTY4wFtGsU6v3sufD/ey5kgxMnkzSSYjCiLTdwpCSrmyh4ggpQuLJE9EdjRoI0a2O0+anKbIWgxREE4Z8c6gibSeg3RuGaKCBsygRkGlMO3UTFSmRIiAcqCGFJNc5eSfFaNhR17k+BDngJiXoHMIAvWoV2hinzw8UBkM40KQex6SjLZLh5SgZgpDkHY1oRG5iUTDnxkDuCnREADg/fBEqx3Br5Qr00RQjZbdAj2LUQE+BnngGPTWowN3DII4B58ajIuUmNzZHzp5CtPF0IsAKgehozGNLyRcu5olHlvDon27k2suvACCoRUyZNZ25G27IprPmsuGcOUydOrXbY/EyxRNPPDGOaatQ4amQ5zmXXXYZ+++/f1mIA0yfPp1DDz2UU089leHhYYaGhth111357ne/y1133cXmm2/Otddey7777suUKVO49tprOfLII7nuuuuw1pbM+K233so999zDsccey9Kl/Rare++9N2effbZLPu4pVo888sgX7PyazSarVjmzBWstP/vZzzjooIOw1rJkyZJyvX333Zef/vSn3Hzzzey8885MnDiRRx55hD//+c+89rWvHbdfYwy/+MUveMtb3rJal5pi0lGr1crP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T6e6upp0Os2AAQO47LLLaGho6HRdy5cvZ9SoUVRWVlJVVcXJJ5/MY4891m75V199lfPOO48ePXpQVlbG0UcfzYIFC2hrS8bVV1+NZVnt/nvzzTc73d5PKs8++yynn346Xbt2JZvNcvzxx7N06dJO1ZHP57nmmmuora0lk8nQp08fLrroInbs2NHuNffccw/Dhg0jm81y2GGHccYZZ/DCCy98pO081DkYxnrAgAHtfm5POumkTrXVYDAYIpwD3QCDYX/Q2NjIqFGjePHFFxkzZgwTJkxg3bp1zJ8/n9WrV/PEE0+QyWQ6VNfdd9/NxIkT6dmzZxyO8/7772f06NEsXbqU8ePHl5Rfv349X/rSl2hubua8886jT58+PPzww3zve99j/fr13HzzzW3eZ9KkSW0mtmorK+2hSHshVM8//3y2bt1aEkK1PaSUnH322Sxfvpzjjz+ec889l82bN7Nw4UIee+wxnnnmGXr27FlyzU9+8hN+9KMfUV1dzXe+8x12797Nfffdx5e+9CUee+wxhg8fvt/beahzsIw1QJcuXZg2bVqr4x1NUmcwGAytOMDRXAyG/cJVV12lAHX55ZeXHL/88ssVoObOnduhet5//33VtWtX1aNHD7V169b4+NatW1WPHj1Ujx49WoXFPPHEExWg/vCHP8TH8vm8GjlypALUU089VVJ+1qxZClArV67s5FMeOhQKBTVo0CCVTqfVunXr4uO7du1SRxxxhHJdV7355pt7refOO+9UgJowYYKSUsbHFyxYoAB10UUXlZR/9dVXleM46ogjjlC7du2Kj69bt06l02l11FFHqSAI9ns7D2UOlrFWSqnq6mpVXV29bw9qMBgM7WDEuOGgR0qp+vTpoyoqKlRDQ0PJuYaGBlVRUaEGDhzYobpuv/12BajZs2e3Onf11VcrQC1evDg+tmnTJgWok08+uVX5VatWKUBNmTKl5LgR43tn+fLlbfadUkotWrSo3TFqyQknnKCAVmJOSqkGDhyostmsampqio/PnDmz1RhHTJ48WQFq9erV+72dhzIHy1grZcS4wWD4aDA+44aDns2bN/P2228zfPhwstlsyblsNsvw4cN5/fXX2bp1617rWrVqFQBjxoxpdW7s2LEArF69ukPlR4wYQTabLSmf5IknnmDevHn89Kc/5Xe/+90++bZ/UunsOLRFLpdj7dq1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", - "text/plain": [ - "
" - ] - }, - "metadata": {}, - "output_type": "display_data" + "ename": "NameError", + "evalue": "name 'PlotParams' is not defined", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mNameError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[10]\u001b[39m\u001b[32m, line 7\u001b[39m\n\u001b[32m 5\u001b[39m \u001b[38;5;28mprint\u001b[39m(exaggerated_params)\n\u001b[32m 6\u001b[39m model = Model4DSTEM.build(params=exaggerated_params, scan_pos=PixelYX(y=\u001b[32m0\u001b[39m, x=\u001b[32m0\u001b[39m))\n\u001b[32m----> \u001b[39m\u001b[32m7\u001b[39m plot_params = \u001b[43mPlotParams\u001b[49m(extent_scale=\u001b[32m1.1\u001b[39m)\n\u001b[32m 8\u001b[39m fig, ax = plot_model(model.components, plot_params=plot_params)\n", + "\u001b[31mNameError\u001b[39m: name 'PlotParams' is not defined" + ] } ], "source": [ - "exaggerated_params = test_params.copy()\n", + "exaggerated_params = test_params.derive(\n", + " scan_pixel_pitch=1e2*test_params.scan_pixel_pitch,\n", + " overfocus=1e2*test_params.scan_pixel_pitch,\n", + ")\n", "print(exaggerated_params)\n", - "exaggerated_params['scan_pixel_size'] *= 1e2\n", - "exaggerated_params['overfocus'] *= 1e2\n", - "model = make_model(exaggerated_params, ds.shape)\n", + "model = Model4DSTEM.build(params=exaggerated_params, scan_pos=PixelYX(y=0, x=0))\n", "plot_params = PlotParams(extent_scale=1.1)\n", - "fig, ax = plot_model(model, plot_params=plot_params)" + "fig, ax = plot_model(model.components, plot_params=plot_params)" ] }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "086eb89e", "metadata": {}, "outputs": [], @@ -418,9 +464,9 @@ "lastKernelId": null }, "kernelspec": { - "display_name": "Python (calib311)", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "calib311" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -432,7 +478,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.5" + "version": "3.13.5" } }, "nbformat": 4, diff --git a/prototypes/.gitignore b/prototypes/.gitignore new file mode 100644 index 0000000..56fa964 --- /dev/null +++ b/prototypes/.gitignore @@ -0,0 +1 @@ +*.npy diff --git a/prototypes/BiFeO3EntryWithCollCode29921.cif b/prototypes/BiFeO3EntryWithCollCode29921.cif new file mode 100644 index 0000000..20b2111 --- /dev/null +++ b/prototypes/BiFeO3EntryWithCollCode29921.cif @@ -0,0 +1,85 @@ + +#(C) 2025 by FIZ Karlsruhe - Leibniz Institute for Information Infrastructure. All rights reserved. +data_29921-ICSD +_database_code_ICSD 29921 +_audit_creation_date 2021-08-01 +_chemical_name_common 'Bismuth ferrite' +_chemical_formula_structural 'Bi Fe O3' +_chemical_formula_sum 'Bi1 Fe1 O3' +_chemical_name_structure_type LiNbO3 +_exptl_crystal_density_diffrn 8.34 +_citation_title + +; +Rietveld study of the changes of phase composition, crystal structure, and +morphology of BiFeO$_3$ by partial substitution of bismuth with rare-earth +ions +; +loop_ +_citation_id +_citation_journal_full +_citation_year +_citation_journal_volume +_citation_page_first +_citation_page_last +_citation_journal_id_ASTM +primary 'Minerals (Basel, Switzerland)' 2021 11 1 11 MBSIBI +loop_ +_citation_author_citation_id +_citation_author_name +primary 'Kireva, Maria' +primary 'Tumbalev, Ventsislav' +primary 'Kostov-Kytin, Vladislav' +primary 'Tzvetkov, Peter' +primary 'Kovacheva, Daniela' +_cell_length_a 5.5785(2) +_cell_length_b 5.5785(2) +_cell_length_c 13.8696(5) +_cell_angle_alpha 90. +_cell_angle_beta 90. +_cell_angle_gamma 120. +_cell_volume 373.79 +_cell_formula_units_Z 6 +_space_group_name_H-M_alt 'R 3 c H' +_space_group_IT_number 161 +loop_ +_space_group_symop_id +_space_group_symop_operation_xyz +1 '-x+y, y, z+1/2' +2 'x, x-y, z+1/2' +3 '-y, -x, z+1/2' +4 '-x+y, -x, z' +5 '-y, x-y, z' +6 'x, y, z' +7 '-x+y+2/3, y+1/3, z+5/6' +8 'x+2/3, x-y+1/3, z+5/6' +9 '-y+2/3, -x+1/3, z+5/6' +10 '-x+y+2/3, -x+1/3, z+1/3' +11 '-y+2/3, x-y+1/3, z+1/3' +12 'x+2/3, y+1/3, z+1/3' +13 '-x+y+1/3, y+2/3, z+1/6' +14 'x+1/3, x-y+2/3, z+1/6' +15 '-y+1/3, -x+2/3, z+1/6' +16 '-x+y+1/3, -x+2/3, z+2/3' +17 '-y+1/3, x-y+2/3, z+2/3' +18 'x+1/3, y+2/3, z+2/3' +loop_ +_atom_type_symbol +_atom_type_oxidation_number +Bi3+ 3 +Fe3+ 3 +O2- -2 +loop_ +_atom_site_label +_atom_site_type_symbol +_atom_site_symmetry_multiplicity +_atom_site_Wyckoff_symbol +_atom_site_fract_x +_atom_site_fract_y +_atom_site_fract_z +_atom_site_B_iso_or_equiv +_atom_site_occupancy +Bi1 Bi3+ 6 a 0 0 0 1.30(1) 1. +Fe1 Fe3+ 6 a 0 0 0.2206(1) 1.41(1) 1. +O1 O2- 18 b 0.446(4) 0.021(1) 0.9504(3) 1.3(1) 1. +#End of TTdata_29921-ICSD diff --git a/prototypes/EntryWithCollCode163723.cif b/prototypes/EntryWithCollCode163723.cif new file mode 100644 index 0000000..9028e61 --- /dev/null +++ b/prototypes/EntryWithCollCode163723.cif @@ -0,0 +1,250 @@ + +#(C) 2025 by FIZ Karlsruhe - Leibniz Institute for Information Infrastructure. All rights reserved. +data_163723-ICSD +_database_code_ICSD 163723 +_audit_creation_date 2009-08-01 +_chemical_name_common Gold +_chemical_formula_structural Au +_chemical_formula_sum Au1 +_chemical_name_structure_type Cu +_exptl_crystal_density_diffrn 19.39 +_citation_title 'Isothermal section of the Ce - Au - Sb system at 870 K' +loop_ +_citation_id +_citation_journal_full +_citation_year +_citation_journal_volume +_citation_page_first +_citation_page_last +_citation_journal_id_ASTM +primary 'Journal of Alloys and Compounds' 2009 479 184 188 JALCEU +loop_ +_citation_author_citation_id +_citation_author_name +primary 'Salamakha, L.P.' +primary 'Bauer, E.' +primary 'Mudryi, S.I.' +primary 'Goncalves, A.P.' +primary 'Almeida, M.' +primary 'Noel, H.' +_cell_length_a 4.0709(2) +_cell_length_b 4.0709(2) +_cell_length_c 4.0709(2) +_cell_angle_alpha 90. +_cell_angle_beta 90. +_cell_angle_gamma 90. +_cell_volume 67.46 +_cell_formula_units_Z 4 +_space_group_name_H-M_alt 'F m -3 m' +_space_group_IT_number 225 +loop_ +_space_group_symop_id +_space_group_symop_operation_xyz +1 'z, y, -x' +2 'y, x, -z' +3 'x, z, -y' +4 'z, x, -y' +5 'y, z, -x' +6 'x, y, -z' +7 'z, -y, x' +8 'y, -x, z' +9 'x, -z, y' +10 'z, -x, y' +11 'y, -z, x' +12 'x, -y, z' +13 '-z, y, x' +14 '-y, x, z' +15 '-x, z, y' +16 '-z, x, y' +17 '-y, z, x' +18 '-x, y, z' +19 '-z, -y, -x' +20 '-y, -x, -z' +21 '-x, -z, -y' +22 '-z, -x, -y' +23 '-y, -z, -x' +24 '-x, -y, -z' +25 '-z, -y, x' +26 '-y, -x, z' +27 '-x, -z, y' +28 '-z, -x, y' +29 '-y, -z, x' +30 '-x, -y, z' +31 '-z, y, -x' +32 '-y, x, -z' +33 '-x, z, -y' +34 '-z, x, -y' +35 '-y, z, -x' +36 '-x, y, -z' +37 'z, -y, -x' +38 'y, -x, -z' +39 'x, -z, -y' +40 'z, -x, -y' +41 'y, -z, -x' +42 'x, -y, -z' +43 'z, y, x' +44 'y, x, z' +45 'x, z, y' +46 'z, x, y' +47 'y, z, x' +48 'x, y, z' +49 'z, y+1/2, -x+1/2' +50 'y, x+1/2, -z+1/2' +51 'x, z+1/2, -y+1/2' +52 'z, x+1/2, -y+1/2' +53 'y, z+1/2, -x+1/2' +54 'x, y+1/2, -z+1/2' +55 'z, -y+1/2, x+1/2' +56 'y, -x+1/2, z+1/2' +57 'x, -z+1/2, y+1/2' +58 'z, -x+1/2, y+1/2' +59 'y, -z+1/2, x+1/2' +60 'x, -y+1/2, z+1/2' +61 '-z, y+1/2, x+1/2' +62 '-y, x+1/2, z+1/2' +63 '-x, z+1/2, y+1/2' +64 '-z, x+1/2, y+1/2' +65 '-y, z+1/2, x+1/2' +66 '-x, y+1/2, z+1/2' +67 '-z, -y+1/2, -x+1/2' +68 '-y, -x+1/2, -z+1/2' +69 '-x, -z+1/2, -y+1/2' +70 '-z, -x+1/2, -y+1/2' +71 '-y, -z+1/2, -x+1/2' +72 '-x, -y+1/2, -z+1/2' +73 '-z, -y+1/2, x+1/2' +74 '-y, -x+1/2, z+1/2' +75 '-x, -z+1/2, y+1/2' +76 '-z, -x+1/2, y+1/2' +77 '-y, -z+1/2, x+1/2' +78 '-x, -y+1/2, z+1/2' +79 '-z, y+1/2, -x+1/2' +80 '-y, x+1/2, -z+1/2' +81 '-x, z+1/2, -y+1/2' +82 '-z, x+1/2, -y+1/2' +83 '-y, z+1/2, -x+1/2' +84 '-x, y+1/2, -z+1/2' +85 'z, -y+1/2, -x+1/2' +86 'y, -x+1/2, -z+1/2' +87 'x, -z+1/2, -y+1/2' +88 'z, -x+1/2, -y+1/2' +89 'y, -z+1/2, -x+1/2' +90 'x, -y+1/2, -z+1/2' +91 'z, y+1/2, x+1/2' +92 'y, x+1/2, z+1/2' +93 'x, z+1/2, y+1/2' +94 'z, x+1/2, y+1/2' +95 'y, z+1/2, x+1/2' +96 'x, y+1/2, z+1/2' +97 'z+1/2, y, -x+1/2' +98 'y+1/2, x, -z+1/2' +99 'x+1/2, z, -y+1/2' +100 'z+1/2, x, -y+1/2' +101 'y+1/2, z, -x+1/2' +102 'x+1/2, y, -z+1/2' +103 'z+1/2, -y, x+1/2' +104 'y+1/2, -x, z+1/2' +105 'x+1/2, -z, y+1/2' +106 'z+1/2, -x, y+1/2' +107 'y+1/2, -z, x+1/2' +108 'x+1/2, -y, z+1/2' +109 '-z+1/2, y, x+1/2' +110 '-y+1/2, x, z+1/2' +111 '-x+1/2, z, y+1/2' +112 '-z+1/2, x, y+1/2' +113 '-y+1/2, z, x+1/2' +114 '-x+1/2, y, z+1/2' +115 '-z+1/2, -y, -x+1/2' +116 '-y+1/2, -x, -z+1/2' +117 '-x+1/2, -z, -y+1/2' +118 '-z+1/2, -x, -y+1/2' +119 '-y+1/2, -z, -x+1/2' +120 '-x+1/2, -y, -z+1/2' +121 '-z+1/2, -y, x+1/2' +122 '-y+1/2, -x, z+1/2' +123 '-x+1/2, -z, y+1/2' +124 '-z+1/2, -x, y+1/2' +125 '-y+1/2, -z, x+1/2' +126 '-x+1/2, -y, z+1/2' +127 '-z+1/2, y, -x+1/2' +128 '-y+1/2, x, -z+1/2' +129 '-x+1/2, z, -y+1/2' +130 '-z+1/2, x, -y+1/2' +131 '-y+1/2, z, -x+1/2' +132 '-x+1/2, y, -z+1/2' +133 'z+1/2, -y, -x+1/2' +134 'y+1/2, -x, -z+1/2' +135 'x+1/2, -z, -y+1/2' +136 'z+1/2, -x, -y+1/2' +137 'y+1/2, -z, -x+1/2' +138 'x+1/2, -y, -z+1/2' +139 'z+1/2, y, x+1/2' +140 'y+1/2, x, z+1/2' +141 'x+1/2, z, y+1/2' +142 'z+1/2, x, y+1/2' +143 'y+1/2, z, x+1/2' +144 'x+1/2, y, z+1/2' +145 'z+1/2, y+1/2, -x' +146 'y+1/2, x+1/2, -z' +147 'x+1/2, z+1/2, -y' +148 'z+1/2, x+1/2, -y' +149 'y+1/2, z+1/2, -x' +150 'x+1/2, y+1/2, -z' +151 'z+1/2, -y+1/2, x' +152 'y+1/2, -x+1/2, z' +153 'x+1/2, -z+1/2, y' +154 'z+1/2, -x+1/2, y' +155 'y+1/2, -z+1/2, x' +156 'x+1/2, -y+1/2, z' +157 '-z+1/2, y+1/2, x' +158 '-y+1/2, x+1/2, z' +159 '-x+1/2, z+1/2, y' +160 '-z+1/2, x+1/2, y' +161 '-y+1/2, z+1/2, x' +162 '-x+1/2, y+1/2, z' +163 '-z+1/2, -y+1/2, -x' +164 '-y+1/2, -x+1/2, -z' +165 '-x+1/2, -z+1/2, -y' +166 '-z+1/2, -x+1/2, -y' +167 '-y+1/2, -z+1/2, -x' +168 '-x+1/2, -y+1/2, -z' +169 '-z+1/2, -y+1/2, x' +170 '-y+1/2, -x+1/2, z' +171 '-x+1/2, -z+1/2, y' +172 '-z+1/2, -x+1/2, y' +173 '-y+1/2, -z+1/2, x' +174 '-x+1/2, -y+1/2, z' +175 '-z+1/2, y+1/2, -x' +176 '-y+1/2, x+1/2, -z' +177 '-x+1/2, z+1/2, -y' +178 '-z+1/2, x+1/2, -y' +179 '-y+1/2, z+1/2, -x' +180 '-x+1/2, y+1/2, -z' +181 'z+1/2, -y+1/2, -x' +182 'y+1/2, -x+1/2, -z' +183 'x+1/2, -z+1/2, -y' +184 'z+1/2, -x+1/2, -y' +185 'y+1/2, -z+1/2, -x' +186 'x+1/2, -y+1/2, -z' +187 'z+1/2, y+1/2, x' +188 'y+1/2, x+1/2, z' +189 'x+1/2, z+1/2, y' +190 'z+1/2, x+1/2, y' +191 'y+1/2, z+1/2, x' +192 'x+1/2, y+1/2, z' +loop_ +_atom_type_symbol +_atom_type_oxidation_number +Au0+ 0 +loop_ +_atom_site_label +_atom_site_type_symbol +_atom_site_symmetry_multiplicity +_atom_site_Wyckoff_symbol +_atom_site_fract_x +_atom_site_fract_y +_atom_site_fract_z +_atom_site_B_iso_or_equiv +_atom_site_occupancy +Au1 Au0+ 4 a 0 0 0 . 1. +#End of TTdata_163723-ICSD diff --git a/prototypes/EntryWithCollCode52700.cif b/prototypes/EntryWithCollCode52700.cif new file mode 100644 index 0000000..9225ce6 --- /dev/null +++ b/prototypes/EntryWithCollCode52700.cif @@ -0,0 +1,253 @@ + +#(C) 2025 by FIZ Karlsruhe - Leibniz Institute for Information Infrastructure. All rights reserved. +data_52700-ICSD +_database_code_ICSD 52700 +_audit_creation_date 2008-07-07 +_audit_update_record 2009-02-01 +_chemical_name_common Gold +_chemical_formula_structural Au +_chemical_formula_sum Au1 +_chemical_name_structure_type Cu +_chemical_name_mineral Gold +_exptl_crystal_density_diffrn 19.28 +_diffrn_ambient_temperature 298. +_citation_title + +; +Neubestimmung der Gitterparameter, Dichten und thermischen +Ausdehnungskoeffizienten von Silber und Gold, und Vollkommenheit der Struktur +; +loop_ +_citation_id +_citation_journal_full +_citation_year +_citation_journal_volume +_citation_page_first +_citation_page_last +_citation_journal_id_ASTM +primary 'Monatshefte fuer Chemie' 1971 102 1377 1386 MOCMB7 +loop_ +_citation_author_citation_id +_citation_author_name +primary 'Straumanis, M.E.' +_cell_length_a 4.07894(5) +_cell_length_b 4.07894 +_cell_length_c 4.07894 +_cell_angle_alpha 90. +_cell_angle_beta 90. +_cell_angle_gamma 90. +_cell_volume 67.86 +_cell_formula_units_Z 4 +_space_group_name_H-M_alt 'F m -3 m' +_space_group_IT_number 225 +loop_ +_space_group_symop_id +_space_group_symop_operation_xyz +1 'z, y, -x' +2 'y, x, -z' +3 'x, z, -y' +4 'z, x, -y' +5 'y, z, -x' +6 'x, y, -z' +7 'z, -y, x' +8 'y, -x, z' +9 'x, -z, y' +10 'z, -x, y' +11 'y, -z, x' +12 'x, -y, z' +13 '-z, y, x' +14 '-y, x, z' +15 '-x, z, y' +16 '-z, x, y' +17 '-y, z, x' +18 '-x, y, z' +19 '-z, -y, -x' +20 '-y, -x, -z' +21 '-x, -z, -y' +22 '-z, -x, -y' +23 '-y, -z, -x' +24 '-x, -y, -z' +25 '-z, -y, x' +26 '-y, -x, z' +27 '-x, -z, y' +28 '-z, -x, y' +29 '-y, -z, x' +30 '-x, -y, z' +31 '-z, y, -x' +32 '-y, x, -z' +33 '-x, z, -y' +34 '-z, x, -y' +35 '-y, z, -x' +36 '-x, y, -z' +37 'z, -y, -x' +38 'y, -x, -z' +39 'x, -z, -y' +40 'z, -x, -y' +41 'y, -z, -x' +42 'x, -y, -z' +43 'z, y, x' +44 'y, x, z' +45 'x, z, y' +46 'z, x, y' +47 'y, z, x' +48 'x, y, z' +49 'z, y+1/2, -x+1/2' +50 'y, x+1/2, -z+1/2' +51 'x, z+1/2, -y+1/2' +52 'z, x+1/2, -y+1/2' +53 'y, z+1/2, -x+1/2' +54 'x, y+1/2, -z+1/2' +55 'z, -y+1/2, x+1/2' +56 'y, -x+1/2, z+1/2' +57 'x, -z+1/2, y+1/2' +58 'z, -x+1/2, y+1/2' +59 'y, -z+1/2, x+1/2' +60 'x, -y+1/2, z+1/2' +61 '-z, y+1/2, x+1/2' +62 '-y, x+1/2, z+1/2' +63 '-x, z+1/2, y+1/2' +64 '-z, x+1/2, y+1/2' +65 '-y, z+1/2, x+1/2' +66 '-x, y+1/2, z+1/2' +67 '-z, -y+1/2, -x+1/2' +68 '-y, -x+1/2, -z+1/2' +69 '-x, -z+1/2, -y+1/2' +70 '-z, -x+1/2, -y+1/2' +71 '-y, -z+1/2, -x+1/2' +72 '-x, -y+1/2, -z+1/2' +73 '-z, -y+1/2, x+1/2' +74 '-y, -x+1/2, z+1/2' +75 '-x, -z+1/2, y+1/2' +76 '-z, -x+1/2, y+1/2' +77 '-y, -z+1/2, x+1/2' +78 '-x, -y+1/2, z+1/2' +79 '-z, y+1/2, -x+1/2' +80 '-y, x+1/2, -z+1/2' +81 '-x, z+1/2, -y+1/2' +82 '-z, x+1/2, -y+1/2' +83 '-y, z+1/2, -x+1/2' +84 '-x, y+1/2, -z+1/2' +85 'z, -y+1/2, -x+1/2' +86 'y, -x+1/2, -z+1/2' +87 'x, -z+1/2, -y+1/2' +88 'z, -x+1/2, -y+1/2' +89 'y, -z+1/2, -x+1/2' +90 'x, -y+1/2, -z+1/2' +91 'z, y+1/2, x+1/2' +92 'y, x+1/2, z+1/2' +93 'x, z+1/2, y+1/2' +94 'z, x+1/2, y+1/2' +95 'y, z+1/2, x+1/2' +96 'x, y+1/2, z+1/2' +97 'z+1/2, y, -x+1/2' +98 'y+1/2, x, -z+1/2' +99 'x+1/2, z, -y+1/2' +100 'z+1/2, x, -y+1/2' +101 'y+1/2, z, -x+1/2' +102 'x+1/2, y, -z+1/2' +103 'z+1/2, -y, x+1/2' +104 'y+1/2, -x, z+1/2' +105 'x+1/2, -z, y+1/2' +106 'z+1/2, -x, y+1/2' +107 'y+1/2, -z, x+1/2' +108 'x+1/2, -y, z+1/2' +109 '-z+1/2, y, x+1/2' +110 '-y+1/2, x, z+1/2' +111 '-x+1/2, z, y+1/2' +112 '-z+1/2, x, y+1/2' +113 '-y+1/2, z, x+1/2' +114 '-x+1/2, y, z+1/2' +115 '-z+1/2, -y, -x+1/2' +116 '-y+1/2, -x, -z+1/2' +117 '-x+1/2, -z, -y+1/2' +118 '-z+1/2, -x, -y+1/2' +119 '-y+1/2, -z, -x+1/2' +120 '-x+1/2, -y, -z+1/2' +121 '-z+1/2, -y, x+1/2' +122 '-y+1/2, -x, z+1/2' +123 '-x+1/2, -z, y+1/2' +124 '-z+1/2, -x, y+1/2' +125 '-y+1/2, -z, x+1/2' +126 '-x+1/2, -y, z+1/2' +127 '-z+1/2, y, -x+1/2' +128 '-y+1/2, x, -z+1/2' +129 '-x+1/2, z, -y+1/2' +130 '-z+1/2, x, -y+1/2' +131 '-y+1/2, z, -x+1/2' +132 '-x+1/2, y, -z+1/2' +133 'z+1/2, -y, -x+1/2' +134 'y+1/2, -x, -z+1/2' +135 'x+1/2, -z, -y+1/2' +136 'z+1/2, -x, -y+1/2' +137 'y+1/2, -z, -x+1/2' +138 'x+1/2, -y, -z+1/2' +139 'z+1/2, y, x+1/2' +140 'y+1/2, x, z+1/2' +141 'x+1/2, z, y+1/2' +142 'z+1/2, x, y+1/2' +143 'y+1/2, z, x+1/2' +144 'x+1/2, y, z+1/2' +145 'z+1/2, y+1/2, -x' +146 'y+1/2, x+1/2, -z' +147 'x+1/2, z+1/2, -y' +148 'z+1/2, x+1/2, -y' +149 'y+1/2, z+1/2, -x' +150 'x+1/2, y+1/2, -z' +151 'z+1/2, -y+1/2, x' +152 'y+1/2, -x+1/2, z' +153 'x+1/2, -z+1/2, y' +154 'z+1/2, -x+1/2, y' +155 'y+1/2, -z+1/2, x' +156 'x+1/2, -y+1/2, z' +157 '-z+1/2, y+1/2, x' +158 '-y+1/2, x+1/2, z' +159 '-x+1/2, z+1/2, y' +160 '-z+1/2, x+1/2, y' +161 '-y+1/2, z+1/2, x' +162 '-x+1/2, y+1/2, z' +163 '-z+1/2, -y+1/2, -x' +164 '-y+1/2, -x+1/2, -z' +165 '-x+1/2, -z+1/2, -y' +166 '-z+1/2, -x+1/2, -y' +167 '-y+1/2, -z+1/2, -x' +168 '-x+1/2, -y+1/2, -z' +169 '-z+1/2, -y+1/2, x' +170 '-y+1/2, -x+1/2, z' +171 '-x+1/2, -z+1/2, y' +172 '-z+1/2, -x+1/2, y' +173 '-y+1/2, -z+1/2, x' +174 '-x+1/2, -y+1/2, z' +175 '-z+1/2, y+1/2, -x' +176 '-y+1/2, x+1/2, -z' +177 '-x+1/2, z+1/2, -y' +178 '-z+1/2, x+1/2, -y' +179 '-y+1/2, z+1/2, -x' +180 '-x+1/2, y+1/2, -z' +181 'z+1/2, -y+1/2, -x' +182 'y+1/2, -x+1/2, -z' +183 'x+1/2, -z+1/2, -y' +184 'z+1/2, -x+1/2, -y' +185 'y+1/2, -z+1/2, -x' +186 'x+1/2, -y+1/2, -z' +187 'z+1/2, y+1/2, x' +188 'y+1/2, x+1/2, z' +189 'x+1/2, z+1/2, y' +190 'z+1/2, x+1/2, y' +191 'y+1/2, z+1/2, x' +192 'x+1/2, y+1/2, z' +loop_ +_atom_type_symbol +_atom_type_oxidation_number +Au0+ 0 +loop_ +_atom_site_label +_atom_site_type_symbol +_atom_site_symmetry_multiplicity +_atom_site_Wyckoff_symbol +_atom_site_fract_x +_atom_site_fract_y +_atom_site_fract_z +_atom_site_B_iso_or_equiv +_atom_site_occupancy +Au1 Au0+ 4 a 0 0 0 . 1. +#End of TTdata_52700-ICSD diff --git a/prototypes/clcalib.ipynb b/prototypes/clcalib.ipynb new file mode 100644 index 0000000..e0af86a --- /dev/null +++ b/prototypes/clcalib.ipynb @@ -0,0 +1,2488 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "2492fe11-2ec1-45c1-ac93-5ab43a9f80bc", + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "ad8d8a41-f6a9-4699-b8a5-05e9b34adc60", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "2f861e17-f0fa-4d19-be3d-f727b73507bb", + "metadata": {}, + "outputs": [], + "source": [ + "import numpy as np\n", + "import panel as pn\n", + "from IPython.display import display" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "01555198-0adb-42e3-9e67-87e58e073347", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "(function(root) {\n", + " function now() {\n", + " return new Date();\n", + " }\n", + "\n", + " const force = true;\n", + " const py_version = '3.8.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", + " const reloading = false;\n", + " const Bokeh = root.Bokeh;\n", + "\n", + " // Set a timeout for this load but only if we are not already initializing\n", + " if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_failed_load = false;\n", + " }\n", + "\n", + " function run_callbacks() {\n", + " try {\n", + " root._bokeh_onload_callbacks.forEach(function(callback) {\n", + " if (callback != null)\n", + " callback();\n", + " });\n", + " } finally {\n", + " delete root._bokeh_onload_callbacks;\n", + " }\n", + " console.debug(\"Bokeh: all callbacks have finished\");\n", + " }\n", + "\n", + " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", + " if (css_urls == null) css_urls = [];\n", + " if (js_urls == null) js_urls = [];\n", + " if (js_modules == null) js_modules = [];\n", + " if (js_exports == null) js_exports = {};\n", + "\n", + " root._bokeh_onload_callbacks.push(callback);\n", + "\n", + " if (root._bokeh_is_loading > 0) {\n", + " // Don't load bokeh if it is still initializing\n", + " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", + " return null;\n", + " } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", + " // There is nothing to load\n", + " run_callbacks();\n", + " return null;\n", + " }\n", + "\n", + " function on_load() {\n", + " root._bokeh_is_loading--;\n", + " if (root._bokeh_is_loading === 0) {\n", + " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", + " run_callbacks()\n", + " }\n", + " }\n", + " window._bokeh_on_load = on_load\n", + "\n", + " function on_error(e) {\n", + " const src_el = e.srcElement\n", + " console.error(\"failed to load \" + (src_el.href || src_el.src));\n", + " }\n", + "\n", + " const skip = [];\n", + " if (window.requirejs) {\n", + " window.requirejs.config({'packages': {}, 'paths': {'tabulator': 'https://cdn.jsdelivr.net/npm/tabulator-tables@6.3.1/dist/js/tabulator.min', 'moment': 'https://cdn.jsdelivr.net/npm/luxon/build/global/luxon.min'}, 'shim': {}});\n", + " require([\"tabulator\"], function(Tabulator) {\n", + " window.Tabulator = Tabulator\n", + " on_load()\n", + " })\n", + " require([\"moment\"], function(moment) {\n", + " window.moment = moment\n", + " on_load()\n", + " })\n", + " root._bokeh_is_loading = css_urls.length + 2;\n", + " } else {\n", + " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", + " }\n", + "\n", + " const existing_stylesheets = []\n", + " const links = document.getElementsByTagName('link')\n", + " for (let i = 0; i < links.length; i++) {\n", + " const link = links[i]\n", + " if (link.href != null) {\n", + " existing_stylesheets.push(link.href)\n", + " }\n", + " }\n", + " for (let i = 0; i < css_urls.length; i++) {\n", + " const url = css_urls[i];\n", + " const escaped = encodeURI(url)\n", + " if (existing_stylesheets.indexOf(escaped) !== -1) {\n", + " on_load()\n", + " continue;\n", + " }\n", + " const element = document.createElement(\"link\");\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.rel = \"stylesheet\";\n", + " element.type = \"text/css\";\n", + " element.href = url;\n", + " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", + " document.body.appendChild(element);\n", + " } if (((window.Tabulator !== undefined) && (!(window.Tabulator instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } if (((window.moment !== undefined) && (!(window.moment instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/luxon/build/global/luxon.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } var existing_scripts = []\n", + " const scripts = document.getElementsByTagName('script')\n", + " for (let i = 0; i < scripts.length; i++) {\n", + " var script = scripts[i]\n", + " if (script.src != null) {\n", + " existing_scripts.push(script.src)\n", + " }\n", + " }\n", + " for (let i = 0; i < js_urls.length; i++) {\n", + " const url = js_urls[i];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " const element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (let i = 0; i < js_modules.length; i++) {\n", + " const url = js_modules[i];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (const name in js_exports) {\n", + " const url = js_exports[name];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " element.textContent = `\n", + " import ${name} from \"${url}\"\n", + " window.${name} = ${name}\n", + " window._bokeh_on_load()\n", + " `\n", + " document.head.appendChild(element);\n", + " }\n", + " if (!js_urls.length && !js_modules.length) {\n", + " on_load()\n", + " }\n", + " };\n", + "\n", + " function inject_raw_css(css) {\n", + " const element = document.createElement(\"style\");\n", + " element.appendChild(document.createTextNode(css));\n", + " document.body.appendChild(element);\n", + " }\n", + "\n", + " const js_urls = [\"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/luxon/build/global/luxon.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.8.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.8.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.8.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.8.0.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/panel.min.js\"];\n", + " const js_modules = [];\n", + " const js_exports = {};\n", + " const css_urls = [\"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/css/tabulator_simple.min.css\"];\n", + " const inline_js = [ function(Bokeh) {\n", + " Bokeh.set_log_level(\"info\");\n", + " },\n", + "function(Bokeh) {} // ensure no trailing comma for IE\n", + " ];\n", + "\n", + " function run_inline_js() {\n", + " if ((root.Bokeh !== undefined) || (force === true)) {\n", + " for (let i = 0; i < inline_js.length; i++) {\n", + " try {\n", + " inline_js[i].call(root, root.Bokeh);\n", + " } catch(e) {\n", + " if (!reloading) {\n", + " throw e;\n", + " }\n", + " }\n", + " }\n", + " // Cache old bokeh versions\n", + " if (Bokeh != undefined && !reloading) {\n", + " var NewBokeh = root.Bokeh;\n", + " if (Bokeh.versions === undefined) {\n", + " Bokeh.versions = new Map();\n", + " }\n", + " if (NewBokeh.version !== Bokeh.version) {\n", + " Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", + " }\n", + " root.Bokeh = Bokeh;\n", + " }\n", + " } else if (Date.now() < root._bokeh_timeout) {\n", + " setTimeout(run_inline_js, 100);\n", + " } else if (!root._bokeh_failed_load) {\n", + " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", + " root._bokeh_failed_load = true;\n", + " }\n", + " root._bokeh_is_initializing = false\n", + " }\n", + "\n", + " function load_or_wait() {\n", + " // Implement a backoff loop that tries to ensure we do not load multiple\n", + " // versions of Bokeh and its dependencies at the same time.\n", + " // In recent versions we use the root._bokeh_is_initializing flag\n", + " // to determine whether there is an ongoing attempt to initialize\n", + " // bokeh, however for backward compatibility we also try to ensure\n", + " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", + " // before older versions are fully initialized.\n", + " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", + " // If the timeout and bokeh was not successfully loaded we reset\n", + " // everything and try loading again\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_is_initializing = false;\n", + " root._bokeh_onload_callbacks = undefined;\n", + " root._bokeh_is_loading = 0\n", + " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", + " load_or_wait();\n", + " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", + " setTimeout(load_or_wait, 100);\n", + " } else {\n", + " root._bokeh_is_initializing = true\n", + " root._bokeh_onload_callbacks = []\n", + " const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n", + " if (!reloading && !bokeh_loaded) {\n", + " if (root.Bokeh) {\n", + " root.Bokeh = undefined;\n", + " }\n", + " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", + " }\n", + " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", + " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", + " run_inline_js();\n", + " });\n", + " }\n", + " }\n", + " // Give older versions of the autoload script a head-start to ensure\n", + " // they initialize before we start loading newer version.\n", + " setTimeout(load_or_wait, 100)\n", + "}(window));" + ], + "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n const force = true;\n const py_version = '3.8.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n const reloading = false;\n const Bokeh = root.Bokeh;\n\n // Set a timeout for this load but only if we are not already initializing\n if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n // Don't load bokeh if it is still initializing\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n // There is nothing to load\n run_callbacks();\n return null;\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error(e) {\n const src_el = e.srcElement\n console.error(\"failed to load \" + (src_el.href || src_el.src));\n }\n\n const skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'tabulator': 'https://cdn.jsdelivr.net/npm/tabulator-tables@6.3.1/dist/js/tabulator.min', 'moment': 'https://cdn.jsdelivr.net/npm/luxon/build/global/luxon.min'}, 'shim': {}});\n require([\"tabulator\"], function(Tabulator) {\n window.Tabulator = Tabulator\n on_load()\n })\n require([\"moment\"], function(moment) {\n window.moment = moment\n on_load()\n })\n root._bokeh_is_loading = css_urls.length + 2;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n const existing_stylesheets = []\n const links = document.getElementsByTagName('link')\n for (let i = 0; i < links.length; i++) {\n const link = links[i]\n if (link.href != null) {\n existing_stylesheets.push(link.href)\n }\n }\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const escaped = encodeURI(url)\n if (existing_stylesheets.indexOf(escaped) !== -1) {\n on_load()\n continue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window.Tabulator !== undefined) && (!(window.Tabulator instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } if (((window.moment !== undefined) && (!(window.moment instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/luxon/build/global/luxon.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } var existing_scripts = []\n const scripts = document.getElementsByTagName('script')\n for (let i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n existing_scripts.push(script.src)\n }\n }\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (let i = 0; i < js_modules.length; i++) {\n const url = js_modules[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n const url = js_exports[name];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/luxon/build/global/luxon.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.8.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.8.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.8.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.8.0.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/panel.min.js\"];\n const js_modules = [];\n const js_exports = {};\n const css_urls = [\"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/css/tabulator_simple.min.css\"];\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (let i = 0; i < inline_js.length; i++) {\n try {\n inline_js[i].call(root, root.Bokeh);\n } catch(e) {\n if (!reloading) {\n throw e;\n }\n }\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n var NewBokeh = root.Bokeh;\n if (Bokeh.versions === undefined) {\n Bokeh.versions = new Map();\n }\n if (NewBokeh.version !== Bokeh.version) {\n Bokeh.versions.set(NewBokeh.version, NewBokeh)\n }\n root.Bokeh = Bokeh;\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n // If the timeout and bokeh was not successfully loaded we reset\n // everything and try loading again\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n root._bokeh_is_loading = 0\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n if (root.Bokeh) {\n root.Bokeh = undefined;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "\n", + "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", + " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", + "}\n", + "\n", + "\n", + " function JupyterCommManager() {\n", + " }\n", + "\n", + " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", + " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " comm_manager.register_target(comm_id, function(comm) {\n", + " comm.on_msg(msg_handler);\n", + " });\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", + " comm.onMsg = msg_handler;\n", + " });\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data, comm_id};\n", + " var buffers = []\n", + " for (var buffer of message.buffers || []) {\n", + " buffers.push(new DataView(buffer))\n", + " }\n", + " var metadata = message.metadata || {};\n", + " var msg = {content, buffers, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " })\n", + " }\n", + " }\n", + "\n", + " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", + " if (comm_id in window.PyViz.comms) {\n", + " return window.PyViz.comms[comm_id];\n", + " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", + " if (msg_handler) {\n", + " comm.on_msg(msg_handler);\n", + " }\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", + " let retries = 0;\n", + " const open = () => {\n", + " if (comm.active) {\n", + " comm.open();\n", + " } else if (retries > 3) {\n", + " console.warn('Comm target never activated')\n", + " } else {\n", + " retries += 1\n", + " setTimeout(open, 500)\n", + " }\n", + " }\n", + " if (comm.active) {\n", + " comm.open();\n", + " } else {\n", + " setTimeout(open, 500)\n", + " }\n", + " if (msg_handler) {\n", + " comm.onMsg = msg_handler;\n", + " }\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", + " comm_promise.then((comm) => {\n", + " window.PyViz.comms[comm_id] = comm;\n", + " if (msg_handler) {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data};\n", + " var metadata = message.metadata || {comm_id};\n", + " var msg = {content, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " })\n", + " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", + " return comm_promise.then((comm) => {\n", + " comm.send(data, metadata, buffers, disposeOnDone);\n", + " });\n", + " };\n", + " var comm = {\n", + " send: sendClosure\n", + " };\n", + " }\n", + " window.PyViz.comms[comm_id] = comm;\n", + " return comm;\n", + " }\n", + " window.PyViz.comm_manager = new JupyterCommManager();\n", + " \n", + "\n", + "\n", + "var JS_MIME_TYPE = 'application/javascript';\n", + "var HTML_MIME_TYPE = 'text/html';\n", + "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", + "var CLASS_NAME = 'output';\n", + "\n", + "/**\n", + " * Render data to the DOM node\n", + " */\n", + "function render(props, node) {\n", + " var div = document.createElement(\"div\");\n", + " var script = document.createElement(\"script\");\n", + " node.appendChild(div);\n", + " node.appendChild(script);\n", + "}\n", + "\n", + "/**\n", + " * Handle when a new output is added\n", + " */\n", + "function handle_add_output(event, handle) {\n", + " var output_area = handle.output_area;\n", + " var output = handle.output;\n", + " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", + " return\n", + " }\n", + " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", + " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", + " if (id !== undefined) {\n", + " var nchildren = toinsert.length;\n", + " var html_node = toinsert[nchildren-1].children[0];\n", + " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var scripts = [];\n", + " var nodelist = html_node.querySelectorAll(\"script\");\n", + " for (var i in nodelist) {\n", + " if (nodelist.hasOwnProperty(i)) {\n", + " scripts.push(nodelist[i])\n", + " }\n", + " }\n", + "\n", + " scripts.forEach( function (oldScript) {\n", + " var newScript = document.createElement(\"script\");\n", + " var attrs = [];\n", + " var nodemap = oldScript.attributes;\n", + " for (var j in nodemap) {\n", + " if (nodemap.hasOwnProperty(j)) {\n", + " attrs.push(nodemap[j])\n", + " }\n", + " }\n", + " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", + " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", + " oldScript.parentNode.replaceChild(newScript, oldScript);\n", + " });\n", + " if (JS_MIME_TYPE in output.data) {\n", + " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", + " }\n", + " output_area._hv_plot_id = id;\n", + " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", + " window.PyViz.plot_index[id] = Bokeh.index[id];\n", + " } else {\n", + " window.PyViz.plot_index[id] = null;\n", + " }\n", + " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", + " var bk_div = document.createElement(\"div\");\n", + " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var script_attrs = bk_div.children[0].attributes;\n", + " for (var i = 0; i < script_attrs.length; i++) {\n", + " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", + " }\n", + " // store reference to server id on output_area\n", + " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle when an output is cleared or removed\n", + " */\n", + "function handle_clear_output(event, handle) {\n", + " var id = handle.cell.output_area._hv_plot_id;\n", + " var server_id = handle.cell.output_area._bokeh_server_id;\n", + " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", + " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", + " if (server_id !== null) {\n", + " comm.send({event_type: 'server_delete', 'id': server_id});\n", + " return;\n", + " } else if (comm !== null) {\n", + " comm.send({event_type: 'delete', 'id': id});\n", + " }\n", + " delete PyViz.plot_index[id];\n", + " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", + " var doc = window.Bokeh.index[id].model.document\n", + " doc.clear();\n", + " const i = window.Bokeh.documents.indexOf(doc);\n", + " if (i > -1) {\n", + " window.Bokeh.documents.splice(i, 1);\n", + " }\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle kernel restart event\n", + " */\n", + "function handle_kernel_cleanup(event, handle) {\n", + " delete PyViz.comms[\"hv-extension-comm\"];\n", + " window.PyViz.plot_index = {}\n", + "}\n", + "\n", + "/**\n", + " * Handle update_display_data messages\n", + " */\n", + "function handle_update_output(event, handle) {\n", + " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", + " handle_add_output(event, handle)\n", + "}\n", + "\n", + "function register_renderer(events, OutputArea) {\n", + " function append_mime(data, metadata, element) {\n", + " // create a DOM node to render to\n", + " var toinsert = this.create_output_subarea(\n", + " metadata,\n", + " CLASS_NAME,\n", + " EXEC_MIME_TYPE\n", + " );\n", + " this.keyboard_manager.register_events(toinsert);\n", + " // Render to node\n", + " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", + " render(props, toinsert[0]);\n", + " element.append(toinsert);\n", + " return toinsert\n", + " }\n", + "\n", + " events.on('output_added.OutputArea', handle_add_output);\n", + " events.on('output_updated.OutputArea', handle_update_output);\n", + " events.on('clear_output.CodeCell', handle_clear_output);\n", + " events.on('delete.Cell', handle_clear_output);\n", + " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", + "\n", + " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", + " safe: true,\n", + " index: 0\n", + " });\n", + "}\n", + "\n", + "if (window.Jupyter !== undefined) {\n", + " try {\n", + " var events = require('base/js/events');\n", + " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", + " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", + " register_renderer(events, OutputArea);\n", + " }\n", + " } catch(err) {\n", + " }\n", + "}\n" + ], + "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n let retries = 0;\n const open = () => {\n if (comm.active) {\n comm.open();\n } else if (retries > 3) {\n console.warn('Comm target never activated')\n } else {\n retries += 1\n setTimeout(open, 500)\n }\n }\n if (comm.active) {\n comm.open();\n } else {\n setTimeout(open, 500)\n }\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n })\n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "eaf3d91b-9c82-4e1a-8510-b92daf944ea6" + } + }, + "output_type": "display_data" + } + ], + "source": [ + "pn.extension('tabulator')" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "02c8aba9-c9ee-45a1-899a-db841def67d9", + "metadata": {}, + "outputs": [ + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "(function(root) {\n", + " function now() {\n", + " return new Date();\n", + " }\n", + "\n", + " const force = true;\n", + " const py_version = '3.8.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", + " const reloading = false;\n", + " const Bokeh = root.Bokeh;\n", + "\n", + " // Set a timeout for this load but only if we are not already initializing\n", + " if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_failed_load = false;\n", + " }\n", + "\n", + " function run_callbacks() {\n", + " try {\n", + " root._bokeh_onload_callbacks.forEach(function(callback) {\n", + " if (callback != null)\n", + " callback();\n", + " });\n", + " } finally {\n", + " delete root._bokeh_onload_callbacks;\n", + " }\n", + " console.debug(\"Bokeh: all callbacks have finished\");\n", + " }\n", + "\n", + " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", + " if (css_urls == null) css_urls = [];\n", + " if (js_urls == null) js_urls = [];\n", + " if (js_modules == null) js_modules = [];\n", + " if (js_exports == null) js_exports = {};\n", + "\n", + " root._bokeh_onload_callbacks.push(callback);\n", + "\n", + " if (root._bokeh_is_loading > 0) {\n", + " // Don't load bokeh if it is still initializing\n", + " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", + " return null;\n", + " } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", + " // There is nothing to load\n", + " run_callbacks();\n", + " return null;\n", + " }\n", + "\n", + " function on_load() {\n", + " root._bokeh_is_loading--;\n", + " if (root._bokeh_is_loading === 0) {\n", + " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", + " run_callbacks()\n", + " }\n", + " }\n", + " window._bokeh_on_load = on_load\n", + "\n", + " function on_error(e) {\n", + " const src_el = e.srcElement\n", + " console.error(\"failed to load \" + (src_el.href || src_el.src));\n", + " }\n", + "\n", + " const skip = [];\n", + " if (window.requirejs) {\n", + " window.requirejs.config({'packages': {}, 'paths': {'tabulator': 'https://cdn.jsdelivr.net/npm/tabulator-tables@6.3.1/dist/js/tabulator.min', 'moment': 'https://cdn.jsdelivr.net/npm/luxon/build/global/luxon.min'}, 'shim': {}});\n", + " require([\"tabulator\"], function(Tabulator) {\n", + " window.Tabulator = Tabulator\n", + " on_load()\n", + " })\n", + " require([\"moment\"], function(moment) {\n", + " window.moment = moment\n", + " on_load()\n", + " })\n", + " root._bokeh_is_loading = css_urls.length + 2;\n", + " } else {\n", + " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", + " }\n", + "\n", + " const existing_stylesheets = []\n", + " const links = document.getElementsByTagName('link')\n", + " for (let i = 0; i < links.length; i++) {\n", + " const link = links[i]\n", + " if (link.href != null) {\n", + " existing_stylesheets.push(link.href)\n", + " }\n", + " }\n", + " for (let i = 0; i < css_urls.length; i++) {\n", + " const url = css_urls[i];\n", + " const escaped = encodeURI(url)\n", + " if (existing_stylesheets.indexOf(escaped) !== -1) {\n", + " on_load()\n", + " continue;\n", + " }\n", + " const element = document.createElement(\"link\");\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.rel = \"stylesheet\";\n", + " element.type = \"text/css\";\n", + " element.href = url;\n", + " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", + " document.body.appendChild(element);\n", + " } if (((window.Tabulator !== undefined) && (!(window.Tabulator instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } if (((window.moment !== undefined) && (!(window.moment instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/luxon/build/global/luxon.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } var existing_scripts = []\n", + " const scripts = document.getElementsByTagName('script')\n", + " for (let i = 0; i < scripts.length; i++) {\n", + " var script = scripts[i]\n", + " if (script.src != null) {\n", + " existing_scripts.push(script.src)\n", + " }\n", + " }\n", + " for (let i = 0; i < js_urls.length; i++) {\n", + " const url = js_urls[i];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " const element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (let i = 0; i < js_modules.length; i++) {\n", + " const url = js_modules[i];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (const name in js_exports) {\n", + " const url = js_exports[name];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " element.textContent = `\n", + " import ${name} from \"${url}\"\n", + " window.${name} = ${name}\n", + " window._bokeh_on_load()\n", + " `\n", + " document.head.appendChild(element);\n", + " }\n", + " if (!js_urls.length && !js_modules.length) {\n", + " on_load()\n", + " }\n", + " };\n", + "\n", + " function inject_raw_css(css) {\n", + " const element = document.createElement(\"style\");\n", + " element.appendChild(document.createTextNode(css));\n", + " document.body.appendChild(element);\n", + " }\n", + "\n", + " const js_urls = [\"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/luxon/build/global/luxon.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.8.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.8.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.8.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.8.0.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/panel.min.js\"];\n", + " const js_modules = [];\n", + " const js_exports = {};\n", + " const css_urls = [\"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/css/tabulator_simple.min.css\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/font-awesome/css/all.min.css\"];\n", + " const inline_js = [ function(Bokeh) {\n", + " Bokeh.set_log_level(\"info\");\n", + " },\n", + "function(Bokeh) {} // ensure no trailing comma for IE\n", + " ];\n", + "\n", + " function run_inline_js() {\n", + " if ((root.Bokeh !== undefined) || (force === true)) {\n", + " for (let i = 0; i < inline_js.length; i++) {\n", + " try {\n", + " inline_js[i].call(root, root.Bokeh);\n", + " } catch(e) {\n", + " if (!reloading) {\n", + " throw e;\n", + " }\n", + " }\n", + " }\n", + " // Cache old bokeh versions\n", + " if (Bokeh != undefined && !reloading) {\n", + " var NewBokeh = root.Bokeh;\n", + " if (Bokeh.versions === undefined) {\n", + " Bokeh.versions = new Map();\n", + " }\n", + " if (NewBokeh.version !== Bokeh.version) {\n", + " Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", + " }\n", + " root.Bokeh = Bokeh;\n", + " }\n", + " } else if (Date.now() < root._bokeh_timeout) {\n", + " setTimeout(run_inline_js, 100);\n", + " } else if (!root._bokeh_failed_load) {\n", + " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", + " root._bokeh_failed_load = true;\n", + " }\n", + " root._bokeh_is_initializing = false\n", + " }\n", + "\n", + " function load_or_wait() {\n", + " // Implement a backoff loop that tries to ensure we do not load multiple\n", + " // versions of Bokeh and its dependencies at the same time.\n", + " // In recent versions we use the root._bokeh_is_initializing flag\n", + " // to determine whether there is an ongoing attempt to initialize\n", + " // bokeh, however for backward compatibility we also try to ensure\n", + " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", + " // before older versions are fully initialized.\n", + " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", + " // If the timeout and bokeh was not successfully loaded we reset\n", + " // everything and try loading again\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_is_initializing = false;\n", + " root._bokeh_onload_callbacks = undefined;\n", + " root._bokeh_is_loading = 0\n", + " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", + " load_or_wait();\n", + " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", + " setTimeout(load_or_wait, 100);\n", + " } else {\n", + " root._bokeh_is_initializing = true\n", + " root._bokeh_onload_callbacks = []\n", + " const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n", + " if (!reloading && !bokeh_loaded) {\n", + " if (root.Bokeh) {\n", + " root.Bokeh = undefined;\n", + " }\n", + " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", + " }\n", + " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", + " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", + " run_inline_js();\n", + " });\n", + " }\n", + " }\n", + " // Give older versions of the autoload script a head-start to ensure\n", + " // they initialize before we start loading newer version.\n", + " setTimeout(load_or_wait, 100)\n", + "}(window));" + ], + "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n const force = true;\n const py_version = '3.8.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n const reloading = false;\n const Bokeh = root.Bokeh;\n\n // Set a timeout for this load but only if we are not already initializing\n if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n // Don't load bokeh if it is still initializing\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n // There is nothing to load\n run_callbacks();\n return null;\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error(e) {\n const src_el = e.srcElement\n console.error(\"failed to load \" + (src_el.href || src_el.src));\n }\n\n const skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'tabulator': 'https://cdn.jsdelivr.net/npm/tabulator-tables@6.3.1/dist/js/tabulator.min', 'moment': 'https://cdn.jsdelivr.net/npm/luxon/build/global/luxon.min'}, 'shim': {}});\n require([\"tabulator\"], function(Tabulator) {\n window.Tabulator = Tabulator\n on_load()\n })\n require([\"moment\"], function(moment) {\n window.moment = moment\n on_load()\n })\n root._bokeh_is_loading = css_urls.length + 2;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n const existing_stylesheets = []\n const links = document.getElementsByTagName('link')\n for (let i = 0; i < links.length; i++) {\n const link = links[i]\n if (link.href != null) {\n existing_stylesheets.push(link.href)\n }\n }\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const escaped = encodeURI(url)\n if (existing_stylesheets.indexOf(escaped) !== -1) {\n on_load()\n continue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window.Tabulator !== undefined) && (!(window.Tabulator instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } if (((window.moment !== undefined) && (!(window.moment instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/luxon/build/global/luxon.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } var existing_scripts = []\n const scripts = document.getElementsByTagName('script')\n for (let i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n existing_scripts.push(script.src)\n }\n }\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (let i = 0; i < js_modules.length; i++) {\n const url = js_modules[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n const url = js_exports[name];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/luxon/build/global/luxon.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-3.8.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-gl-3.8.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-widgets-3.8.0.min.js\", \"https://cdn.bokeh.org/bokeh/release/bokeh-tables-3.8.0.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/panel.min.js\"];\n const js_modules = [];\n const js_exports = {};\n const css_urls = [\"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/css/tabulator_simple.min.css\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/font-awesome/css/all.min.css\"];\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (let i = 0; i < inline_js.length; i++) {\n try {\n inline_js[i].call(root, root.Bokeh);\n } catch(e) {\n if (!reloading) {\n throw e;\n }\n }\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n var NewBokeh = root.Bokeh;\n if (Bokeh.versions === undefined) {\n Bokeh.versions = new Map();\n }\n if (NewBokeh.version !== Bokeh.version) {\n Bokeh.versions.set(NewBokeh.version, NewBokeh)\n }\n root.Bokeh = Bokeh;\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n // If the timeout and bokeh was not successfully loaded we reset\n // everything and try loading again\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n root._bokeh_is_loading = 0\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n if (root.Bokeh) {\n root.Bokeh = undefined;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "\n", + "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", + " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", + "}\n", + "\n", + "\n", + " function JupyterCommManager() {\n", + " }\n", + "\n", + " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", + " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " comm_manager.register_target(comm_id, function(comm) {\n", + " comm.on_msg(msg_handler);\n", + " });\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", + " comm.onMsg = msg_handler;\n", + " });\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data, comm_id};\n", + " var buffers = []\n", + " for (var buffer of message.buffers || []) {\n", + " buffers.push(new DataView(buffer))\n", + " }\n", + " var metadata = message.metadata || {};\n", + " var msg = {content, buffers, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " })\n", + " }\n", + " }\n", + "\n", + " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", + " if (comm_id in window.PyViz.comms) {\n", + " return window.PyViz.comms[comm_id];\n", + " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", + " if (msg_handler) {\n", + " comm.on_msg(msg_handler);\n", + " }\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", + " let retries = 0;\n", + " const open = () => {\n", + " if (comm.active) {\n", + " comm.open();\n", + " } else if (retries > 3) {\n", + " console.warn('Comm target never activated')\n", + " } else {\n", + " retries += 1\n", + " setTimeout(open, 500)\n", + " }\n", + " }\n", + " if (comm.active) {\n", + " comm.open();\n", + " } else {\n", + " setTimeout(open, 500)\n", + " }\n", + " if (msg_handler) {\n", + " comm.onMsg = msg_handler;\n", + " }\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", + " comm_promise.then((comm) => {\n", + " window.PyViz.comms[comm_id] = comm;\n", + " if (msg_handler) {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data};\n", + " var metadata = message.metadata || {comm_id};\n", + " var msg = {content, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " })\n", + " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", + " return comm_promise.then((comm) => {\n", + " comm.send(data, metadata, buffers, disposeOnDone);\n", + " });\n", + " };\n", + " var comm = {\n", + " send: sendClosure\n", + " };\n", + " }\n", + " window.PyViz.comms[comm_id] = comm;\n", + " return comm;\n", + " }\n", + " window.PyViz.comm_manager = new JupyterCommManager();\n", + " \n", + "\n", + "\n", + "var JS_MIME_TYPE = 'application/javascript';\n", + "var HTML_MIME_TYPE = 'text/html';\n", + "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", + "var CLASS_NAME = 'output';\n", + "\n", + "/**\n", + " * Render data to the DOM node\n", + " */\n", + "function render(props, node) {\n", + " var div = document.createElement(\"div\");\n", + " var script = document.createElement(\"script\");\n", + " node.appendChild(div);\n", + " node.appendChild(script);\n", + "}\n", + "\n", + "/**\n", + " * Handle when a new output is added\n", + " */\n", + "function handle_add_output(event, handle) {\n", + " var output_area = handle.output_area;\n", + " var output = handle.output;\n", + " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", + " return\n", + " }\n", + " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", + " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", + " if (id !== undefined) {\n", + " var nchildren = toinsert.length;\n", + " var html_node = toinsert[nchildren-1].children[0];\n", + " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var scripts = [];\n", + " var nodelist = html_node.querySelectorAll(\"script\");\n", + " for (var i in nodelist) {\n", + " if (nodelist.hasOwnProperty(i)) {\n", + " scripts.push(nodelist[i])\n", + " }\n", + " }\n", + "\n", + " scripts.forEach( function (oldScript) {\n", + " var newScript = document.createElement(\"script\");\n", + " var attrs = [];\n", + " var nodemap = oldScript.attributes;\n", + " for (var j in nodemap) {\n", + " if (nodemap.hasOwnProperty(j)) {\n", + " attrs.push(nodemap[j])\n", + " }\n", + " }\n", + " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", + " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", + " oldScript.parentNode.replaceChild(newScript, oldScript);\n", + " });\n", + " if (JS_MIME_TYPE in output.data) {\n", + " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", + " }\n", + " output_area._hv_plot_id = id;\n", + " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", + " window.PyViz.plot_index[id] = Bokeh.index[id];\n", + " } else {\n", + " window.PyViz.plot_index[id] = null;\n", + " }\n", + " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", + " var bk_div = document.createElement(\"div\");\n", + " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var script_attrs = bk_div.children[0].attributes;\n", + " for (var i = 0; i < script_attrs.length; i++) {\n", + " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", + " }\n", + " // store reference to server id on output_area\n", + " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle when an output is cleared or removed\n", + " */\n", + "function handle_clear_output(event, handle) {\n", + " var id = handle.cell.output_area._hv_plot_id;\n", + " var server_id = handle.cell.output_area._bokeh_server_id;\n", + " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", + " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", + " if (server_id !== null) {\n", + " comm.send({event_type: 'server_delete', 'id': server_id});\n", + " return;\n", + " } else if (comm !== null) {\n", + " comm.send({event_type: 'delete', 'id': id});\n", + " }\n", + " delete PyViz.plot_index[id];\n", + " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", + " var doc = window.Bokeh.index[id].model.document\n", + " doc.clear();\n", + " const i = window.Bokeh.documents.indexOf(doc);\n", + " if (i > -1) {\n", + " window.Bokeh.documents.splice(i, 1);\n", + " }\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle kernel restart event\n", + " */\n", + "function handle_kernel_cleanup(event, handle) {\n", + " delete PyViz.comms[\"hv-extension-comm\"];\n", + " window.PyViz.plot_index = {}\n", + "}\n", + "\n", + "/**\n", + " * Handle update_display_data messages\n", + " */\n", + "function handle_update_output(event, handle) {\n", + " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", + " handle_add_output(event, handle)\n", + "}\n", + "\n", + "function register_renderer(events, OutputArea) {\n", + " function append_mime(data, metadata, element) {\n", + " // create a DOM node to render to\n", + " var toinsert = this.create_output_subarea(\n", + " metadata,\n", + " CLASS_NAME,\n", + " EXEC_MIME_TYPE\n", + " );\n", + " this.keyboard_manager.register_events(toinsert);\n", + " // Render to node\n", + " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", + " render(props, toinsert[0]);\n", + " element.append(toinsert);\n", + " return toinsert\n", + " }\n", + "\n", + " events.on('output_added.OutputArea', handle_add_output);\n", + " events.on('output_updated.OutputArea', handle_update_output);\n", + " events.on('clear_output.CodeCell', handle_clear_output);\n", + " events.on('delete.Cell', handle_clear_output);\n", + " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", + "\n", + " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", + " safe: true,\n", + " index: 0\n", + " });\n", + "}\n", + "\n", + "if (window.Jupyter !== undefined) {\n", + " try {\n", + " var events = require('base/js/events');\n", + " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", + " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", + " register_renderer(events, OutputArea);\n", + " }\n", + " } catch(err) {\n", + " }\n", + "}\n" + ], + "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n let retries = 0;\n const open = () => {\n if (comm.active) {\n comm.open();\n } else if (retries > 3) {\n console.warn('Comm target never activated')\n } else {\n retries += 1\n setTimeout(open, 500)\n }\n }\n if (comm.active) {\n comm.open();\n } else {\n setTimeout(open, 500)\n }\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n })\n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ] + }, + "metadata": { + "application/vnd.holoviews_exec.v0+json": { + "id": "da9a2e5a-e7db-4092-a604-1dcd57c7b05e" + } + }, + "output_type": "display_data" + }, + { + "data": { + "text/html": [ + "" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "(function(root) {\n", + " function now() {\n", + " return new Date();\n", + " }\n", + "\n", + " const force = false;\n", + " const py_version = '3.8.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n", + " const reloading = true;\n", + " const Bokeh = root.Bokeh;\n", + "\n", + " // Set a timeout for this load but only if we are not already initializing\n", + " if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_failed_load = false;\n", + " }\n", + "\n", + " function run_callbacks() {\n", + " try {\n", + " root._bokeh_onload_callbacks.forEach(function(callback) {\n", + " if (callback != null)\n", + " callback();\n", + " });\n", + " } finally {\n", + " delete root._bokeh_onload_callbacks;\n", + " }\n", + " console.debug(\"Bokeh: all callbacks have finished\");\n", + " }\n", + "\n", + " function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n", + " if (css_urls == null) css_urls = [];\n", + " if (js_urls == null) js_urls = [];\n", + " if (js_modules == null) js_modules = [];\n", + " if (js_exports == null) js_exports = {};\n", + "\n", + " root._bokeh_onload_callbacks.push(callback);\n", + "\n", + " if (root._bokeh_is_loading > 0) {\n", + " // Don't load bokeh if it is still initializing\n", + " console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n", + " return null;\n", + " } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n", + " // There is nothing to load\n", + " run_callbacks();\n", + " return null;\n", + " }\n", + "\n", + " function on_load() {\n", + " root._bokeh_is_loading--;\n", + " if (root._bokeh_is_loading === 0) {\n", + " console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n", + " run_callbacks()\n", + " }\n", + " }\n", + " window._bokeh_on_load = on_load\n", + "\n", + " function on_error(e) {\n", + " const src_el = e.srcElement\n", + " console.error(\"failed to load \" + (src_el.href || src_el.src));\n", + " }\n", + "\n", + " const skip = [];\n", + " if (window.requirejs) {\n", + " window.requirejs.config({'packages': {}, 'paths': {'tabulator': 'https://cdn.jsdelivr.net/npm/tabulator-tables@6.3.1/dist/js/tabulator.min', 'moment': 'https://cdn.jsdelivr.net/npm/luxon/build/global/luxon.min', 'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock'}, 'shim': {'jspanel': {'exports': 'jsPanel'}}});\n", + " require([\"tabulator\"], function(Tabulator) {\n", + " window.Tabulator = Tabulator\n", + " on_load()\n", + " })\n", + " require([\"moment\"], function(moment) {\n", + " window.moment = moment\n", + " on_load()\n", + " })\n", + " require([\"jspanel\"], function(jsPanel) {\n", + " window.jsPanel = jsPanel\n", + " on_load()\n", + " })\n", + " require([\"jspanel-modal\"], function() {\n", + " on_load()\n", + " })\n", + " require([\"jspanel-tooltip\"], function() {\n", + " on_load()\n", + " })\n", + " require([\"jspanel-hint\"], function() {\n", + " on_load()\n", + " })\n", + " require([\"jspanel-layout\"], function() {\n", + " on_load()\n", + " })\n", + " require([\"jspanel-contextmenu\"], function() {\n", + " on_load()\n", + " })\n", + " require([\"jspanel-dock\"], function() {\n", + " on_load()\n", + " })\n", + " root._bokeh_is_loading = css_urls.length + 9;\n", + " } else {\n", + " root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n", + " }\n", + "\n", + " const existing_stylesheets = []\n", + " const links = document.getElementsByTagName('link')\n", + " for (let i = 0; i < links.length; i++) {\n", + " const link = links[i]\n", + " if (link.href != null) {\n", + " existing_stylesheets.push(link.href)\n", + " }\n", + " }\n", + " for (let i = 0; i < css_urls.length; i++) {\n", + " const url = css_urls[i];\n", + " const escaped = encodeURI(url)\n", + " if (existing_stylesheets.indexOf(escaped) !== -1) {\n", + " on_load()\n", + " continue;\n", + " }\n", + " const element = document.createElement(\"link\");\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.rel = \"stylesheet\";\n", + " element.type = \"text/css\";\n", + " element.href = url;\n", + " console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n", + " document.body.appendChild(element);\n", + " } if (((window.Tabulator !== undefined) && (!(window.Tabulator instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } if (((window.moment !== undefined) && (!(window.moment instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/luxon/build/global/luxon.min.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } if (((window.jsPanel !== undefined) && (!(window.jsPanel instanceof HTMLElement))) || window.requirejs) {\n", + " var urls = ['https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n", + " for (var i = 0; i < urls.length; i++) {\n", + " skip.push(encodeURI(urls[i]))\n", + " }\n", + " } var existing_scripts = []\n", + " const scripts = document.getElementsByTagName('script')\n", + " for (let i = 0; i < scripts.length; i++) {\n", + " var script = scripts[i]\n", + " if (script.src != null) {\n", + " existing_scripts.push(script.src)\n", + " }\n", + " }\n", + " for (let i = 0; i < js_urls.length; i++) {\n", + " const url = js_urls[i];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " const element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (let i = 0; i < js_modules.length; i++) {\n", + " const url = js_modules[i];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onload = on_load;\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.src = url;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " document.head.appendChild(element);\n", + " }\n", + " for (const name in js_exports) {\n", + " const url = js_exports[name];\n", + " const escaped = encodeURI(url)\n", + " if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n", + " if (!window.requirejs) {\n", + " on_load();\n", + " }\n", + " continue;\n", + " }\n", + " var element = document.createElement('script');\n", + " element.onerror = on_error;\n", + " element.async = false;\n", + " element.type = \"module\";\n", + " console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n", + " element.textContent = `\n", + " import ${name} from \"${url}\"\n", + " window.${name} = ${name}\n", + " window._bokeh_on_load()\n", + " `\n", + " document.head.appendChild(element);\n", + " }\n", + " if (!js_urls.length && !js_modules.length) {\n", + " on_load()\n", + " }\n", + " };\n", + "\n", + " function inject_raw_css(css) {\n", + " const element = document.createElement(\"style\");\n", + " element.appendChild(document.createTextNode(css));\n", + " document.body.appendChild(element);\n", + " }\n", + "\n", + " const js_urls = [\"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/luxon/build/global/luxon.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js\"];\n", + " const js_modules = [];\n", + " const js_exports = {};\n", + " const css_urls = [\"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/css/tabulator_simple.min.css\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.css\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/font-awesome/css/all.min.css\"];\n", + " const inline_js = [ function(Bokeh) {\n", + " Bokeh.set_log_level(\"info\");\n", + " },\n", + "function(Bokeh) {} // ensure no trailing comma for IE\n", + " ];\n", + "\n", + " function run_inline_js() {\n", + " if ((root.Bokeh !== undefined) || (force === true)) {\n", + " for (let i = 0; i < inline_js.length; i++) {\n", + " try {\n", + " inline_js[i].call(root, root.Bokeh);\n", + " } catch(e) {\n", + " if (!reloading) {\n", + " throw e;\n", + " }\n", + " }\n", + " }\n", + " // Cache old bokeh versions\n", + " if (Bokeh != undefined && !reloading) {\n", + " var NewBokeh = root.Bokeh;\n", + " if (Bokeh.versions === undefined) {\n", + " Bokeh.versions = new Map();\n", + " }\n", + " if (NewBokeh.version !== Bokeh.version) {\n", + " Bokeh.versions.set(NewBokeh.version, NewBokeh)\n", + " }\n", + " root.Bokeh = Bokeh;\n", + " }\n", + " } else if (Date.now() < root._bokeh_timeout) {\n", + " setTimeout(run_inline_js, 100);\n", + " } else if (!root._bokeh_failed_load) {\n", + " console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n", + " root._bokeh_failed_load = true;\n", + " }\n", + " root._bokeh_is_initializing = false\n", + " }\n", + "\n", + " function load_or_wait() {\n", + " // Implement a backoff loop that tries to ensure we do not load multiple\n", + " // versions of Bokeh and its dependencies at the same time.\n", + " // In recent versions we use the root._bokeh_is_initializing flag\n", + " // to determine whether there is an ongoing attempt to initialize\n", + " // bokeh, however for backward compatibility we also try to ensure\n", + " // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n", + " // before older versions are fully initialized.\n", + " if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n", + " // If the timeout and bokeh was not successfully loaded we reset\n", + " // everything and try loading again\n", + " root._bokeh_timeout = Date.now() + 5000;\n", + " root._bokeh_is_initializing = false;\n", + " root._bokeh_onload_callbacks = undefined;\n", + " root._bokeh_is_loading = 0\n", + " console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n", + " load_or_wait();\n", + " } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n", + " setTimeout(load_or_wait, 100);\n", + " } else {\n", + " root._bokeh_is_initializing = true\n", + " root._bokeh_onload_callbacks = []\n", + " const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n", + " if (!reloading && !bokeh_loaded) {\n", + " if (root.Bokeh) {\n", + " root.Bokeh = undefined;\n", + " }\n", + " console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n", + " }\n", + " load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n", + " console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n", + " run_inline_js();\n", + " });\n", + " }\n", + " }\n", + " // Give older versions of the autoload script a head-start to ensure\n", + " // they initialize before we start loading newer version.\n", + " setTimeout(load_or_wait, 100)\n", + "}(window));" + ], + "application/vnd.holoviews_load.v0+json": "(function(root) {\n function now() {\n return new Date();\n }\n\n const force = false;\n const py_version = '3.8.0'.replace('rc', '-rc.').replace('.dev', '-dev.');\n const reloading = true;\n const Bokeh = root.Bokeh;\n\n // Set a timeout for this load but only if we are not already initializing\n if (typeof (root._bokeh_timeout) === \"undefined\" || (force || !root._bokeh_is_initializing)) {\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_failed_load = false;\n }\n\n function run_callbacks() {\n try {\n root._bokeh_onload_callbacks.forEach(function(callback) {\n if (callback != null)\n callback();\n });\n } finally {\n delete root._bokeh_onload_callbacks;\n }\n console.debug(\"Bokeh: all callbacks have finished\");\n }\n\n function load_libs(css_urls, js_urls, js_modules, js_exports, callback) {\n if (css_urls == null) css_urls = [];\n if (js_urls == null) js_urls = [];\n if (js_modules == null) js_modules = [];\n if (js_exports == null) js_exports = {};\n\n root._bokeh_onload_callbacks.push(callback);\n\n if (root._bokeh_is_loading > 0) {\n // Don't load bokeh if it is still initializing\n console.debug(\"Bokeh: BokehJS is being loaded, scheduling callback at\", now());\n return null;\n } else if (js_urls.length === 0 && js_modules.length === 0 && Object.keys(js_exports).length === 0) {\n // There is nothing to load\n run_callbacks();\n return null;\n }\n\n function on_load() {\n root._bokeh_is_loading--;\n if (root._bokeh_is_loading === 0) {\n console.debug(\"Bokeh: all BokehJS libraries/stylesheets loaded\");\n run_callbacks()\n }\n }\n window._bokeh_on_load = on_load\n\n function on_error(e) {\n const src_el = e.srcElement\n console.error(\"failed to load \" + (src_el.href || src_el.src));\n }\n\n const skip = [];\n if (window.requirejs) {\n window.requirejs.config({'packages': {}, 'paths': {'tabulator': 'https://cdn.jsdelivr.net/npm/tabulator-tables@6.3.1/dist/js/tabulator.min', 'moment': 'https://cdn.jsdelivr.net/npm/luxon/build/global/luxon.min', 'jspanel': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/jspanel', 'jspanel-modal': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal', 'jspanel-tooltip': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip', 'jspanel-hint': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint', 'jspanel-layout': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout', 'jspanel-contextmenu': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu', 'jspanel-dock': 'https://cdn.jsdelivr.net/npm/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock'}, 'shim': {'jspanel': {'exports': 'jsPanel'}}});\n require([\"tabulator\"], function(Tabulator) {\n window.Tabulator = Tabulator\n on_load()\n })\n require([\"moment\"], function(moment) {\n window.moment = moment\n on_load()\n })\n require([\"jspanel\"], function(jsPanel) {\n window.jsPanel = jsPanel\n on_load()\n })\n require([\"jspanel-modal\"], function() {\n on_load()\n })\n require([\"jspanel-tooltip\"], function() {\n on_load()\n })\n require([\"jspanel-hint\"], function() {\n on_load()\n })\n require([\"jspanel-layout\"], function() {\n on_load()\n })\n require([\"jspanel-contextmenu\"], function() {\n on_load()\n })\n require([\"jspanel-dock\"], function() {\n on_load()\n })\n root._bokeh_is_loading = css_urls.length + 9;\n } else {\n root._bokeh_is_loading = css_urls.length + js_urls.length + js_modules.length + Object.keys(js_exports).length;\n }\n\n const existing_stylesheets = []\n const links = document.getElementsByTagName('link')\n for (let i = 0; i < links.length; i++) {\n const link = links[i]\n if (link.href != null) {\n existing_stylesheets.push(link.href)\n }\n }\n for (let i = 0; i < css_urls.length; i++) {\n const url = css_urls[i];\n const escaped = encodeURI(url)\n if (existing_stylesheets.indexOf(escaped) !== -1) {\n on_load()\n continue;\n }\n const element = document.createElement(\"link\");\n element.onload = on_load;\n element.onerror = on_error;\n element.rel = \"stylesheet\";\n element.type = \"text/css\";\n element.href = url;\n console.debug(\"Bokeh: injecting link tag for BokehJS stylesheet: \", url);\n document.body.appendChild(element);\n } if (((window.Tabulator !== undefined) && (!(window.Tabulator instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } if (((window.moment !== undefined) && (!(window.moment instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/luxon/build/global/luxon.min.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } if (((window.jsPanel !== undefined) && (!(window.jsPanel instanceof HTMLElement))) || window.requirejs) {\n var urls = ['https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js', 'https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js', 'https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js', 'https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js', 'https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js', 'https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js', 'https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js'];\n for (var i = 0; i < urls.length; i++) {\n skip.push(encodeURI(urls[i]))\n }\n } var existing_scripts = []\n const scripts = document.getElementsByTagName('script')\n for (let i = 0; i < scripts.length; i++) {\n var script = scripts[i]\n if (script.src != null) {\n existing_scripts.push(script.src)\n }\n }\n for (let i = 0; i < js_urls.length; i++) {\n const url = js_urls[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n const element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (let i = 0; i < js_modules.length; i++) {\n const url = js_modules[i];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) !== -1 || existing_scripts.indexOf(escaped) !== -1) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onload = on_load;\n element.onerror = on_error;\n element.async = false;\n element.src = url;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n document.head.appendChild(element);\n }\n for (const name in js_exports) {\n const url = js_exports[name];\n const escaped = encodeURI(url)\n if (skip.indexOf(escaped) >= 0 || root[name] != null) {\n if (!window.requirejs) {\n on_load();\n }\n continue;\n }\n var element = document.createElement('script');\n element.onerror = on_error;\n element.async = false;\n element.type = \"module\";\n console.debug(\"Bokeh: injecting script tag for BokehJS library: \", url);\n element.textContent = `\n import ${name} from \"${url}\"\n window.${name} = ${name}\n window._bokeh_on_load()\n `\n document.head.appendChild(element);\n }\n if (!js_urls.length && !js_modules.length) {\n on_load()\n }\n };\n\n function inject_raw_css(css) {\n const element = document.createElement(\"style\");\n element.appendChild(document.createTextNode(css));\n document.body.appendChild(element);\n }\n\n const js_urls = [\"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/reactiveesm/es-module-shims@^1.10.0/dist/es-module-shims.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/js/tabulator.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/luxon/build/global/luxon.min.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/modal/jspanel.modal.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/tooltip/jspanel.tooltip.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/hint/jspanel.hint.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/layout/jspanel.layout.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/contextmenu/jspanel.contextmenu.js\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/extensions/dock/jspanel.dock.js\"];\n const js_modules = [];\n const js_exports = {};\n const css_urls = [\"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/datatabulator/tabulator-tables@6.3.1/dist/css/tabulator_simple.min.css\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/floatpanel/jspanel4@4.12.0/dist/jspanel.css\", \"https://cdn.holoviz.org/panel/1.8.2/dist/bundled/font-awesome/css/all.min.css\"];\n const inline_js = [ function(Bokeh) {\n Bokeh.set_log_level(\"info\");\n },\nfunction(Bokeh) {} // ensure no trailing comma for IE\n ];\n\n function run_inline_js() {\n if ((root.Bokeh !== undefined) || (force === true)) {\n for (let i = 0; i < inline_js.length; i++) {\n try {\n inline_js[i].call(root, root.Bokeh);\n } catch(e) {\n if (!reloading) {\n throw e;\n }\n }\n }\n // Cache old bokeh versions\n if (Bokeh != undefined && !reloading) {\n var NewBokeh = root.Bokeh;\n if (Bokeh.versions === undefined) {\n Bokeh.versions = new Map();\n }\n if (NewBokeh.version !== Bokeh.version) {\n Bokeh.versions.set(NewBokeh.version, NewBokeh)\n }\n root.Bokeh = Bokeh;\n }\n } else if (Date.now() < root._bokeh_timeout) {\n setTimeout(run_inline_js, 100);\n } else if (!root._bokeh_failed_load) {\n console.log(\"Bokeh: BokehJS failed to load within specified timeout.\");\n root._bokeh_failed_load = true;\n }\n root._bokeh_is_initializing = false\n }\n\n function load_or_wait() {\n // Implement a backoff loop that tries to ensure we do not load multiple\n // versions of Bokeh and its dependencies at the same time.\n // In recent versions we use the root._bokeh_is_initializing flag\n // to determine whether there is an ongoing attempt to initialize\n // bokeh, however for backward compatibility we also try to ensure\n // that we do not start loading a newer (Panel>=1.0 and Bokeh>3) version\n // before older versions are fully initialized.\n if (root._bokeh_is_initializing && Date.now() > root._bokeh_timeout) {\n // If the timeout and bokeh was not successfully loaded we reset\n // everything and try loading again\n root._bokeh_timeout = Date.now() + 5000;\n root._bokeh_is_initializing = false;\n root._bokeh_onload_callbacks = undefined;\n root._bokeh_is_loading = 0\n console.log(\"Bokeh: BokehJS was loaded multiple times but one version failed to initialize.\");\n load_or_wait();\n } else if (root._bokeh_is_initializing || (typeof root._bokeh_is_initializing === \"undefined\" && root._bokeh_onload_callbacks !== undefined)) {\n setTimeout(load_or_wait, 100);\n } else {\n root._bokeh_is_initializing = true\n root._bokeh_onload_callbacks = []\n const bokeh_loaded = root.Bokeh != null && (root.Bokeh.version === py_version || (root.Bokeh.versions !== undefined && root.Bokeh.versions.has(py_version)));\n if (!reloading && !bokeh_loaded) {\n if (root.Bokeh) {\n root.Bokeh = undefined;\n }\n console.debug(\"Bokeh: BokehJS not loaded, scheduling load and callback at\", now());\n }\n load_libs(css_urls, js_urls, js_modules, js_exports, function() {\n console.debug(\"Bokeh: BokehJS plotting callback run at\", now());\n run_inline_js();\n });\n }\n }\n // Give older versions of the autoload script a head-start to ensure\n // they initialize before we start loading newer version.\n setTimeout(load_or_wait, 100)\n}(window));" + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/javascript": [ + "\n", + "if ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n", + " window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n", + "}\n", + "\n", + "\n", + " function JupyterCommManager() {\n", + " }\n", + "\n", + " JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n", + " if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " comm_manager.register_target(comm_id, function(comm) {\n", + " comm.on_msg(msg_handler);\n", + " });\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n", + " comm.onMsg = msg_handler;\n", + " });\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data, comm_id};\n", + " var buffers = []\n", + " for (var buffer of message.buffers || []) {\n", + " buffers.push(new DataView(buffer))\n", + " }\n", + " var metadata = message.metadata || {};\n", + " var msg = {content, buffers, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " })\n", + " }\n", + " }\n", + "\n", + " JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n", + " if (comm_id in window.PyViz.comms) {\n", + " return window.PyViz.comms[comm_id];\n", + " } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n", + " var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n", + " var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n", + " if (msg_handler) {\n", + " comm.on_msg(msg_handler);\n", + " }\n", + " } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n", + " var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n", + " let retries = 0;\n", + " const open = () => {\n", + " if (comm.active) {\n", + " comm.open();\n", + " } else if (retries > 3) {\n", + " console.warn('Comm target never activated')\n", + " } else {\n", + " retries += 1\n", + " setTimeout(open, 500)\n", + " }\n", + " }\n", + " if (comm.active) {\n", + " comm.open();\n", + " } else {\n", + " setTimeout(open, 500)\n", + " }\n", + " if (msg_handler) {\n", + " comm.onMsg = msg_handler;\n", + " }\n", + " } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n", + " var comm_promise = google.colab.kernel.comms.open(comm_id)\n", + " comm_promise.then((comm) => {\n", + " window.PyViz.comms[comm_id] = comm;\n", + " if (msg_handler) {\n", + " var messages = comm.messages[Symbol.asyncIterator]();\n", + " function processIteratorResult(result) {\n", + " var message = result.value;\n", + " var content = {data: message.data};\n", + " var metadata = message.metadata || {comm_id};\n", + " var msg = {content, metadata}\n", + " msg_handler(msg);\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " return messages.next().then(processIteratorResult);\n", + " }\n", + " })\n", + " var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n", + " return comm_promise.then((comm) => {\n", + " comm.send(data, metadata, buffers, disposeOnDone);\n", + " });\n", + " };\n", + " var comm = {\n", + " send: sendClosure\n", + " };\n", + " }\n", + " window.PyViz.comms[comm_id] = comm;\n", + " return comm;\n", + " }\n", + " window.PyViz.comm_manager = new JupyterCommManager();\n", + " \n", + "\n", + "\n", + "var JS_MIME_TYPE = 'application/javascript';\n", + "var HTML_MIME_TYPE = 'text/html';\n", + "var EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\n", + "var CLASS_NAME = 'output';\n", + "\n", + "/**\n", + " * Render data to the DOM node\n", + " */\n", + "function render(props, node) {\n", + " var div = document.createElement(\"div\");\n", + " var script = document.createElement(\"script\");\n", + " node.appendChild(div);\n", + " node.appendChild(script);\n", + "}\n", + "\n", + "/**\n", + " * Handle when a new output is added\n", + " */\n", + "function handle_add_output(event, handle) {\n", + " var output_area = handle.output_area;\n", + " var output = handle.output;\n", + " if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n", + " return\n", + " }\n", + " var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n", + " var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n", + " if (id !== undefined) {\n", + " var nchildren = toinsert.length;\n", + " var html_node = toinsert[nchildren-1].children[0];\n", + " html_node.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var scripts = [];\n", + " var nodelist = html_node.querySelectorAll(\"script\");\n", + " for (var i in nodelist) {\n", + " if (nodelist.hasOwnProperty(i)) {\n", + " scripts.push(nodelist[i])\n", + " }\n", + " }\n", + "\n", + " scripts.forEach( function (oldScript) {\n", + " var newScript = document.createElement(\"script\");\n", + " var attrs = [];\n", + " var nodemap = oldScript.attributes;\n", + " for (var j in nodemap) {\n", + " if (nodemap.hasOwnProperty(j)) {\n", + " attrs.push(nodemap[j])\n", + " }\n", + " }\n", + " attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n", + " newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n", + " oldScript.parentNode.replaceChild(newScript, oldScript);\n", + " });\n", + " if (JS_MIME_TYPE in output.data) {\n", + " toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n", + " }\n", + " output_area._hv_plot_id = id;\n", + " if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n", + " window.PyViz.plot_index[id] = Bokeh.index[id];\n", + " } else {\n", + " window.PyViz.plot_index[id] = null;\n", + " }\n", + " } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n", + " var bk_div = document.createElement(\"div\");\n", + " bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n", + " var script_attrs = bk_div.children[0].attributes;\n", + " for (var i = 0; i < script_attrs.length; i++) {\n", + " toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n", + " }\n", + " // store reference to server id on output_area\n", + " output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle when an output is cleared or removed\n", + " */\n", + "function handle_clear_output(event, handle) {\n", + " var id = handle.cell.output_area._hv_plot_id;\n", + " var server_id = handle.cell.output_area._bokeh_server_id;\n", + " if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n", + " var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n", + " if (server_id !== null) {\n", + " comm.send({event_type: 'server_delete', 'id': server_id});\n", + " return;\n", + " } else if (comm !== null) {\n", + " comm.send({event_type: 'delete', 'id': id});\n", + " }\n", + " delete PyViz.plot_index[id];\n", + " if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n", + " var doc = window.Bokeh.index[id].model.document\n", + " doc.clear();\n", + " const i = window.Bokeh.documents.indexOf(doc);\n", + " if (i > -1) {\n", + " window.Bokeh.documents.splice(i, 1);\n", + " }\n", + " }\n", + "}\n", + "\n", + "/**\n", + " * Handle kernel restart event\n", + " */\n", + "function handle_kernel_cleanup(event, handle) {\n", + " delete PyViz.comms[\"hv-extension-comm\"];\n", + " window.PyViz.plot_index = {}\n", + "}\n", + "\n", + "/**\n", + " * Handle update_display_data messages\n", + " */\n", + "function handle_update_output(event, handle) {\n", + " handle_clear_output(event, {cell: {output_area: handle.output_area}})\n", + " handle_add_output(event, handle)\n", + "}\n", + "\n", + "function register_renderer(events, OutputArea) {\n", + " function append_mime(data, metadata, element) {\n", + " // create a DOM node to render to\n", + " var toinsert = this.create_output_subarea(\n", + " metadata,\n", + " CLASS_NAME,\n", + " EXEC_MIME_TYPE\n", + " );\n", + " this.keyboard_manager.register_events(toinsert);\n", + " // Render to node\n", + " var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n", + " render(props, toinsert[0]);\n", + " element.append(toinsert);\n", + " return toinsert\n", + " }\n", + "\n", + " events.on('output_added.OutputArea', handle_add_output);\n", + " events.on('output_updated.OutputArea', handle_update_output);\n", + " events.on('clear_output.CodeCell', handle_clear_output);\n", + " events.on('delete.Cell', handle_clear_output);\n", + " events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n", + "\n", + " OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n", + " safe: true,\n", + " index: 0\n", + " });\n", + "}\n", + "\n", + "if (window.Jupyter !== undefined) {\n", + " try {\n", + " var events = require('base/js/events');\n", + " var OutputArea = require('notebook/js/outputarea').OutputArea;\n", + " if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n", + " register_renderer(events, OutputArea);\n", + " }\n", + " } catch(err) {\n", + " }\n", + "}\n" + ], + "application/vnd.holoviews_load.v0+json": "\nif ((window.PyViz === undefined) || (window.PyViz instanceof HTMLElement)) {\n window.PyViz = {comms: {}, comm_status:{}, kernels:{}, receivers: {}, plot_index: []}\n}\n\n\n function JupyterCommManager() {\n }\n\n JupyterCommManager.prototype.register_target = function(plot_id, comm_id, msg_handler) {\n if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n comm_manager.register_target(comm_id, function(comm) {\n comm.on_msg(msg_handler);\n });\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n window.PyViz.kernels[plot_id].registerCommTarget(comm_id, function(comm) {\n comm.onMsg = msg_handler;\n });\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n google.colab.kernel.comms.registerTarget(comm_id, (comm) => {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data, comm_id};\n var buffers = []\n for (var buffer of message.buffers || []) {\n buffers.push(new DataView(buffer))\n }\n var metadata = message.metadata || {};\n var msg = {content, buffers, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n })\n }\n }\n\n JupyterCommManager.prototype.get_client_comm = function(plot_id, comm_id, msg_handler) {\n if (comm_id in window.PyViz.comms) {\n return window.PyViz.comms[comm_id];\n } else if (window.comm_manager || ((window.Jupyter !== undefined) && (Jupyter.notebook.kernel != null))) {\n var comm_manager = window.comm_manager || Jupyter.notebook.kernel.comm_manager;\n var comm = comm_manager.new_comm(comm_id, {}, {}, {}, comm_id);\n if (msg_handler) {\n comm.on_msg(msg_handler);\n }\n } else if ((plot_id in window.PyViz.kernels) && (window.PyViz.kernels[plot_id])) {\n var comm = window.PyViz.kernels[plot_id].connectToComm(comm_id);\n let retries = 0;\n const open = () => {\n if (comm.active) {\n comm.open();\n } else if (retries > 3) {\n console.warn('Comm target never activated')\n } else {\n retries += 1\n setTimeout(open, 500)\n }\n }\n if (comm.active) {\n comm.open();\n } else {\n setTimeout(open, 500)\n }\n if (msg_handler) {\n comm.onMsg = msg_handler;\n }\n } else if (typeof google != 'undefined' && google.colab.kernel != null) {\n var comm_promise = google.colab.kernel.comms.open(comm_id)\n comm_promise.then((comm) => {\n window.PyViz.comms[comm_id] = comm;\n if (msg_handler) {\n var messages = comm.messages[Symbol.asyncIterator]();\n function processIteratorResult(result) {\n var message = result.value;\n var content = {data: message.data};\n var metadata = message.metadata || {comm_id};\n var msg = {content, metadata}\n msg_handler(msg);\n return messages.next().then(processIteratorResult);\n }\n return messages.next().then(processIteratorResult);\n }\n })\n var sendClosure = (data, metadata, buffers, disposeOnDone) => {\n return comm_promise.then((comm) => {\n comm.send(data, metadata, buffers, disposeOnDone);\n });\n };\n var comm = {\n send: sendClosure\n };\n }\n window.PyViz.comms[comm_id] = comm;\n return comm;\n }\n window.PyViz.comm_manager = new JupyterCommManager();\n \n\n\nvar JS_MIME_TYPE = 'application/javascript';\nvar HTML_MIME_TYPE = 'text/html';\nvar EXEC_MIME_TYPE = 'application/vnd.holoviews_exec.v0+json';\nvar CLASS_NAME = 'output';\n\n/**\n * Render data to the DOM node\n */\nfunction render(props, node) {\n var div = document.createElement(\"div\");\n var script = document.createElement(\"script\");\n node.appendChild(div);\n node.appendChild(script);\n}\n\n/**\n * Handle when a new output is added\n */\nfunction handle_add_output(event, handle) {\n var output_area = handle.output_area;\n var output = handle.output;\n if ((output.data == undefined) || (!output.data.hasOwnProperty(EXEC_MIME_TYPE))) {\n return\n }\n var id = output.metadata[EXEC_MIME_TYPE][\"id\"];\n var toinsert = output_area.element.find(\".\" + CLASS_NAME.split(' ')[0]);\n if (id !== undefined) {\n var nchildren = toinsert.length;\n var html_node = toinsert[nchildren-1].children[0];\n html_node.innerHTML = output.data[HTML_MIME_TYPE];\n var scripts = [];\n var nodelist = html_node.querySelectorAll(\"script\");\n for (var i in nodelist) {\n if (nodelist.hasOwnProperty(i)) {\n scripts.push(nodelist[i])\n }\n }\n\n scripts.forEach( function (oldScript) {\n var newScript = document.createElement(\"script\");\n var attrs = [];\n var nodemap = oldScript.attributes;\n for (var j in nodemap) {\n if (nodemap.hasOwnProperty(j)) {\n attrs.push(nodemap[j])\n }\n }\n attrs.forEach(function(attr) { newScript.setAttribute(attr.name, attr.value) });\n newScript.appendChild(document.createTextNode(oldScript.innerHTML));\n oldScript.parentNode.replaceChild(newScript, oldScript);\n });\n if (JS_MIME_TYPE in output.data) {\n toinsert[nchildren-1].children[1].textContent = output.data[JS_MIME_TYPE];\n }\n output_area._hv_plot_id = id;\n if ((window.Bokeh !== undefined) && (id in Bokeh.index)) {\n window.PyViz.plot_index[id] = Bokeh.index[id];\n } else {\n window.PyViz.plot_index[id] = null;\n }\n } else if (output.metadata[EXEC_MIME_TYPE][\"server_id\"] !== undefined) {\n var bk_div = document.createElement(\"div\");\n bk_div.innerHTML = output.data[HTML_MIME_TYPE];\n var script_attrs = bk_div.children[0].attributes;\n for (var i = 0; i < script_attrs.length; i++) {\n toinsert[toinsert.length - 1].childNodes[1].setAttribute(script_attrs[i].name, script_attrs[i].value);\n }\n // store reference to server id on output_area\n output_area._bokeh_server_id = output.metadata[EXEC_MIME_TYPE][\"server_id\"];\n }\n}\n\n/**\n * Handle when an output is cleared or removed\n */\nfunction handle_clear_output(event, handle) {\n var id = handle.cell.output_area._hv_plot_id;\n var server_id = handle.cell.output_area._bokeh_server_id;\n if (((id === undefined) || !(id in PyViz.plot_index)) && (server_id !== undefined)) { return; }\n var comm = window.PyViz.comm_manager.get_client_comm(\"hv-extension-comm\", \"hv-extension-comm\", function () {});\n if (server_id !== null) {\n comm.send({event_type: 'server_delete', 'id': server_id});\n return;\n } else if (comm !== null) {\n comm.send({event_type: 'delete', 'id': id});\n }\n delete PyViz.plot_index[id];\n if ((window.Bokeh !== undefined) & (id in window.Bokeh.index)) {\n var doc = window.Bokeh.index[id].model.document\n doc.clear();\n const i = window.Bokeh.documents.indexOf(doc);\n if (i > -1) {\n window.Bokeh.documents.splice(i, 1);\n }\n }\n}\n\n/**\n * Handle kernel restart event\n */\nfunction handle_kernel_cleanup(event, handle) {\n delete PyViz.comms[\"hv-extension-comm\"];\n window.PyViz.plot_index = {}\n}\n\n/**\n * Handle update_display_data messages\n */\nfunction handle_update_output(event, handle) {\n handle_clear_output(event, {cell: {output_area: handle.output_area}})\n handle_add_output(event, handle)\n}\n\nfunction register_renderer(events, OutputArea) {\n function append_mime(data, metadata, element) {\n // create a DOM node to render to\n var toinsert = this.create_output_subarea(\n metadata,\n CLASS_NAME,\n EXEC_MIME_TYPE\n );\n this.keyboard_manager.register_events(toinsert);\n // Render to node\n var props = {data: data, metadata: metadata[EXEC_MIME_TYPE]};\n render(props, toinsert[0]);\n element.append(toinsert);\n return toinsert\n }\n\n events.on('output_added.OutputArea', handle_add_output);\n events.on('output_updated.OutputArea', handle_update_output);\n events.on('clear_output.CodeCell', handle_clear_output);\n events.on('delete.Cell', handle_clear_output);\n events.on('kernel_ready.Kernel', handle_kernel_cleanup);\n\n OutputArea.prototype.register_mime_type(EXEC_MIME_TYPE, append_mime, {\n safe: true,\n index: 0\n });\n}\n\nif (window.Jupyter !== undefined) {\n try {\n var events = require('base/js/events');\n var OutputArea = require('notebook/js/outputarea').OutputArea;\n if (OutputArea.prototype.mime_types().indexOf(EXEC_MIME_TYPE) == -1) {\n register_renderer(events, OutputArea);\n }\n } catch(err) {\n }\n}\n" + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "from libertem.api import Context\n", + "\n", + "from microscope_calibration.common.model import Parameters4DSTEM, DescanError, PixelYX\n", + "from microscope_calibration.ui import CoordinateCorrectionLayout\n", + "from microscope_calibration.util.diffraction import get_twothetas" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "876593d9-1767-4d97-bdbf-a07615028a16", + "metadata": {}, + "outputs": [], + "source": [ + "acceleration_voltage_V = 300000" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "52b88bb5-8ec8-468f-a0e5-6cfacc8e8d3c", + "metadata": {}, + "outputs": [], + "source": [ + "structure_filename = 'BiFeO3EntryWithCollCode29921.cif'" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "5cc3c66a-fcda-40f9-826f-a082fc60abb0", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0. , 0.00242, 0.00419, 0.00484, 0.00541, 0.00684, 0.00802,\n", + " 0.00838, 0.00967, 0.01054, 0.01081, 0.01185, 0.01256, 0.01368,\n", + " 0.0143 , 0.01451, 0.01529, 0.01586, 0.01604, 0.01675, 0.01727,\n", + " 0.01744, 0.01809, 0.01857, 0.01934, 0.01979, 0.01994, 0.02052,\n", + " 0.02094, 0.02108, 0.02163, 0.02203, 0.02216, 0.02268, 0.02307,\n", + " 0.02369, 0.02406, 0.02418, 0.02466, 0.02501, 0.02513, 0.02593,\n", + " 0.02604, 0.02649, 0.02682, 0.02736, 0.02768, 0.02778, 0.0282 ,\n", + " 0.02851, 0.02861, 0.02902, 0.02932, 0.02942])" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "twothetas = get_twothetas(structure_filename, acceleration_voltage_V, reciprocal_radius=3)\n", + "twothetas" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "0978e580-1129-4f0e-9867-d7124798d52a", + "metadata": {}, + "outputs": [], + "source": [ + "#calib_filename = '/storage/er-c-data/adhoc/libertem/libertem-test-data/default.blo'\n", + "calib_filename = 'with_descan.npy'" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "167f0ebe-1ae7-4de0-8a3c-b5f42b5684ed", + "metadata": {}, + "outputs": [], + "source": [ + "#ctx = Context.make_with(cpus=8)\n", + "ctx = Context.make_with('inline')" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "32e95fed-a926-4620-a808-a91149a0d84c", + "metadata": {}, + "outputs": [], + "source": [ + "ds = ctx.load('auto', calib_filename)" + ] + }, + { + "cell_type": "code", + "execution_count": 12, + "id": "4cbc33f2-fda8-4cf6-8259-51fd6d9803da", + "metadata": {}, + "outputs": [], + "source": [ + "start_params = None" + ] + }, + { + "cell_type": "code", + "execution_count": 25, + "id": "bb85b4d9-9c26-4ea9-8fab-0f1a3bfe1d74", + "metadata": {}, + "outputs": [ + { + "data": {}, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.holoviews_exec.v0+json": "", + "text/html": [ + "
\n", + "
\n", + "
\n", + "" + ], + "text/plain": [ + "Column\n", + " [0] Markdown(str, max_width=500)\n", + " [1] Row\n", + " [0] FloatInput(name='Scan rotation / degrees')\n", + " [1] FloatInput(name='Detector pixel p..., value=50.0)\n", + " [2] FloatInput(name='Camera length / m', step=0.01, value=1.0)\n", + " [3] FloatInput(name='Convergence s..., step=0.01, value=1.0)\n", + " [2] Row\n", + " [0] Column(margin=(3, 3), max_width=350, sizing_mode='stretch_width')\n", + " [0] Row(height=40, margin=(0, 0))\n", + " [0] FloatPanel(config={'headerControls': {'maxim...}, contained=False, name='Image Controls', objects=[Row\n", + " [0] Select(name='...], position='center', status='closed')\n", + " [1] Row(height=40, margin=(0, 0))\n", + " [2] Toggle(height=2, margin=(5, 5, 5, 5), name='Image Controls', sizing_mode='fixed', tags=['927c7c44-7344-4cb5-b29a-...], visible=False, width=2)\n", + " [1] Bokeh(figure)\n", + " [1] Column(margin=(3, 3), max_width=350, sizing_mode='stretch_width')\n", + " [0] Row(height=40, margin=(0, 0))\n", + " [0] FloatPanel(config={'headerControls': {'maxim...}, contained=False, name='Image Controls', objects=[Row\n", + " [0] Select(name='...], position='center', status='closed')\n", + " [1] Row(height=40, margin=(0, 0))\n", + " [2] Toggle(height=2, margin=(5, 5, 5, 5), name='Image Controls', sizing_mode='fixed', tags=['fdd10290-e993-42d2-9b84-...], visible=False, width=2)\n", + " [1] Bokeh(figure)\n", + " [3] Column\n", + " [0] Markdown(str)\n", + " [1] Tabulator(buttons={'select': ' as an abstract array. The problematic value is of type and was passed to the function at path dynamic_nodonate['rest'][33].\nThis typically means that a jit-wrapped function was called with a non-array argument, and this argument was not marked as static using the static_argnums or static_argnames parameters of jax.jit.", + "output_type": "error", + "traceback": [ + "\u001b[31m---------------------------------------------------------------------------\u001b[39m", + "\u001b[31mTypeError\u001b[39m Traceback (most recent call last)", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[24]\u001b[39m\u001b[32m, line 1\u001b[39m\n\u001b[32m----> \u001b[39m\u001b[32m1\u001b[39m new_param, residuals = \u001b[43msolve_coords_points\u001b[49m\u001b[43m(\u001b[49m\u001b[43mparams\u001b[49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mpoints\u001b[49m\u001b[43m)\u001b[49m\n", + "\u001b[36mCell\u001b[39m\u001b[36m \u001b[39m\u001b[32mIn[23]\u001b[39m\u001b[32m, line 8\u001b[39m, in \u001b[36msolve_coords_points\u001b[39m\u001b[34m(ref_params, points)\u001b[39m\n\u001b[32m 2\u001b[39m args = _CoordPointArgs(\n\u001b[32m 3\u001b[39m params=ref_params,\n\u001b[32m 4\u001b[39m points=points,\n\u001b[32m 5\u001b[39m )\n\u001b[32m 7\u001b[39m start = jnp.array([ref_params.detector_rotation, ref_params.overfocus, ref_params.flip_factor] + [\u001b[32m0.\u001b[39m, \u001b[32m0.\u001b[39m] * \u001b[38;5;28mlen\u001b[39m(points))\n\u001b[32m----> \u001b[39m\u001b[32m8\u001b[39m opt_res = \u001b[43moptimistix\u001b[49m\u001b[43m.\u001b[49m\u001b[43mleast_squares\u001b[49m\u001b[43m(\u001b[49m\n\u001b[32m 9\u001b[39m \u001b[43m \u001b[49m\u001b[43mfn\u001b[49m\u001b[43m=\u001b[49m\u001b[43m_coords_point_loss\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 10\u001b[39m \u001b[43m \u001b[49m\u001b[43margs\u001b[49m\u001b[43m=\u001b[49m\u001b[43margs\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 11\u001b[39m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# FIXME Doesn't reach 1e-12 like the others, for unknown reasons\u001b[39;49;00m\n\u001b[32m 12\u001b[39m \u001b[43m \u001b[49m\u001b[43msolver\u001b[49m\u001b[43m=\u001b[49m\u001b[43moptimistix\u001b[49m\u001b[43m.\u001b[49m\u001b[43mBFGS\u001b[49m\u001b[43m(\u001b[49m\u001b[43matol\u001b[49m\u001b[43m=\u001b[49m\u001b[32;43m1e-11\u001b[39;49m\u001b[43m,\u001b[49m\u001b[43m \u001b[49m\u001b[43mrtol\u001b[49m\u001b[43m=\u001b[49m\u001b[32;43m1e-11\u001b[39;49m\u001b[43m)\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 13\u001b[39m \u001b[43m \u001b[49m\u001b[43my0\u001b[49m\u001b[43m=\u001b[49m\u001b[43mstart\u001b[49m\u001b[43m,\u001b[49m\n\u001b[32m 14\u001b[39m \u001b[43m \u001b[49m\u001b[38;5;66;43;03m# FIXME needs more steps than others, for unknown reasons\u001b[39;49;00m\n\u001b[32m 15\u001b[39m \u001b[43m \u001b[49m\u001b[43mmax_steps\u001b[49m\u001b[43m=\u001b[49m\u001b[32;43m10000\u001b[39;49m\u001b[43m,\u001b[49m\n\u001b[32m 16\u001b[39m \u001b[43m\u001b[49m\u001b[43m)\u001b[49m\n\u001b[32m 17\u001b[39m residual = _coords_point_loss(opt_res.value, args)\n\u001b[32m 18\u001b[39m \u001b[38;5;66;03m# Write the new tilts and offsets into the previous descan error\u001b[39;00m\n", + " \u001b[31m[... skipping hidden 7 frame]\u001b[39m\n", + "\u001b[36mFile \u001b[39m\u001b[32m~/miniforge3/envs/calib313/lib/python3.13/site-packages/jax/_src/pjit.py:680\u001b[39m, in \u001b[36m_infer_input_type\u001b[39m\u001b[34m(fun, dbg, explicit_args)\u001b[39m\n\u001b[32m 678\u001b[39m \u001b[38;5;28;01mexcept\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m:\n\u001b[32m 679\u001b[39m arg_description = \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mpath \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mdbg.arg_names[i]\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mif\u001b[39;00m\u001b[38;5;250m \u001b[39mdbg.arg_names\u001b[38;5;250m \u001b[39m\u001b[38;5;129;01mis\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;129;01mnot\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01melse\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[33m'\u001b[39m\u001b[33munknown\u001b[39m\u001b[33m'\u001b[39m\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m\"\u001b[39m \u001b[38;5;66;03m# pytype: disable=name-error\u001b[39;00m\n\u001b[32m--> \u001b[39m\u001b[32m680\u001b[39m \u001b[38;5;28;01mraise\u001b[39;00m \u001b[38;5;167;01mTypeError\u001b[39;00m(\n\u001b[32m 681\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33mError interpreting argument to \u001b[39m\u001b[38;5;132;01m{\u001b[39;00mfun\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m as an abstract array.\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 682\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33m The problematic value is of type \u001b[39m\u001b[38;5;132;01m{\u001b[39;00m\u001b[38;5;28mtype\u001b[39m(x)\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m and was passed to\u001b[39m\u001b[33m\"\u001b[39m \u001b[38;5;66;03m# pytype: disable=name-error\u001b[39;00m\n\u001b[32m 683\u001b[39m \u001b[33mf\u001b[39m\u001b[33m\"\u001b[39m\u001b[33m the function at \u001b[39m\u001b[38;5;132;01m{\u001b[39;00marg_description\u001b[38;5;132;01m}\u001b[39;00m\u001b[33m.\u001b[39m\u001b[38;5;130;01m\\n\u001b[39;00m\u001b[33m\"\u001b[39m\n\u001b[32m 684\u001b[39m \u001b[33m\"\u001b[39m\u001b[33mThis typically means that a jit-wrapped function was called with a non-array\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 685\u001b[39m \u001b[33m\"\u001b[39m\u001b[33m argument, and this argument was not marked as static using the\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 686\u001b[39m \u001b[33m\"\u001b[39m\u001b[33m static_argnums or static_argnames parameters of jax.jit.\u001b[39m\u001b[33m\"\u001b[39m\n\u001b[32m 687\u001b[39m ) \u001b[38;5;28;01mfrom\u001b[39;00m\u001b[38;5;250m \u001b[39m\u001b[38;5;28;01mNone\u001b[39;00m\n\u001b[32m 688\u001b[39m \u001b[38;5;28;01mif\u001b[39;00m config.mutable_array_checks.value:\n\u001b[32m 689\u001b[39m _check_no_aliased_ref_args(dbg, avals, explicit_args)\n", + "\u001b[31mTypeError\u001b[39m: Error interpreting argument to as an abstract array. The problematic value is of type and was passed to the function at path dynamic_nodonate['rest'][33].\nThis typically means that a jit-wrapped function was called with a non-array argument, and this argument was not marked as static using the static_argnums or static_argnames parameters of jax.jit." + ] + } + ], + "source": [ + "new_param, residuals = solve_coords_points(params, points)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6ce0b81c-325b-4bc1-9494-88e27561ab1d", + "metadata": {}, + "outputs": [], + "source": [ + "gui.update_with_force(gui.model_params, gui.params_update(new_param))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a61be83c-f727-45f5-9952-558c13cc856e", + "metadata": {}, + "outputs": [], + "source": [] + } + ], + "metadata": { + "kernelspec": { + "display_name": "Python 3.13 (microscope_calibration)", + "language": "python", + "name": "calib313" + }, + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/prototypes/descan_compensation.ipynb b/prototypes/descan_compensation.ipynb new file mode 100644 index 0000000..9eb0e0b --- /dev/null +++ b/prototypes/descan_compensation.ipynb @@ -0,0 +1,822 @@ +{ + "cells": [ + { + "cell_type": "code", + "execution_count": 1, + "id": "025e8136-1141-4b08-92af-2b4371c2ddb9", + "metadata": {}, + "outputs": [], + "source": [ + "%matplotlib widget" + ] + }, + { + "cell_type": "code", + "execution_count": 2, + "id": "0e7c4e1b-6e5f-4215-a8eb-e515035c8d86", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload" + ] + }, + { + "cell_type": "code", + "execution_count": 3, + "id": "12b52cff-df6f-4199-b6ef-c7833c4c3057", + "metadata": {}, + "outputs": [], + "source": [ + "import numba\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import jax.numpy as jnp\n", + "import jax\n", + "jax.config.update(\"jax_enable_x64\", True)\n", + "import optax\n", + "from libertem.api import Context\n", + "from libertem.udf.com import CoMUDF, RegressionOptions" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "98a420bd-e7e8-4362-bdec-955d479345c1", + "metadata": {}, + "outputs": [], + "source": [ + "%autoreload\n", + "from microscope_calibration.common.model import (\n", + " Parameters4DSTEM, Model4DSTEM, Result4DSTEM, PixelYX, CoordXY, identity, rotate, scale, flip_y,\n", + " DescanError\n", + ")\n", + "from microscope_calibration.util.stem_overfocus_sim import smiley, project\n", + "from microscope_calibration.common.stem_overfocus import (\n", + " get_backward_transformation_matrix, get_detector_correction_matrix, correct_frame, project_frame_backwards\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "db69828d-9a9a-4ac1-8017-8efae1f7f53e", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:2025-09-19 12:43:25,867:jax._src.xla_bridge:872: An NVIDIA GPU may be present on this machine, but a CUDA-enabled jaxlib is not installed. Falling back to cpu.\n" + ] + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "6e39a24879d84ea399a61d2690fb11e8", + "version_major": 2, + "version_minor": 0 + }, + "image/png": "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QACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEAChGAAIAFCMAAQCKEYAAAMUIQACAYgQgAEAxAhAAoBgBCABQjAAEACjm/wMXyQ76mzWIggAAAABJRU5ErkJggg==", + "text/html": [ + "\n", + "
\n", + "
\n", + " Figure\n", + "
\n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "08481bca59414ee3866d7c55fad99513", + "version_major": 2, + "version_minor": 0 + }, + "image/png": "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tqFtvPnNb65e/epXV8uWLavuvPPO6rjjjqvOP//84fqRqqoyA/titM5AVZmDfTFa58AM7L3ROgPNSAAegOuvv76aNWtW1dbWVp1xxhnVXXfdNdxLGpH+8R//sUrygssFF1xQVdWzb/3/yEc+Uk2fPr1qb2+v3vCGN1QPP/zwbttYv359df7551cTJ06sOjs7q3e/+93V5s2bh+Gn2Z0Z2DujeQaqyhzsrdE8B2Zg74zmGWg2taqqqoN3vBEAgOHmHEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDCCEAAgMIIQACAwghAAIDC/P8mHPNqxrS0XQAAAABJRU5ErkJggg==", + "text/html": [ + "\n", + "
\n", + "
\n", + " Figure\n", + "
\n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" + ] + }, + "metadata": {}, + "output_type": "display_data" + }, + { + "data": { + "application/vnd.jupyter.widget-view+json": { + "model_id": "4f74689d07374aa9bf4bac54d0dda8ff", + "version_major": 2, + "version_minor": 0 + }, + "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOnRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjEwLjUsIGh0dHBzOi8vbWF0cGxvdGxpYi5vcmcvWftoOwAAAAlwSFlzAAAPYQAAD2EBqD+naQAAKBpJREFUeJzt3Xt4VPWdx/HPTCaZhMAkhEtCIEBE5OIqWpA0u2qtxkVdqVh7kdKWCpYuK1aN1BZboWq3WLpaa6Wlta5sn6et1rZotWqrYKVYRESUispN7pBAEpNJQu5z9o+UkZQgSZjJmTPf9+t5eB4zt/wyfD28M3POGZ/jOI4AAABght/tBQAAAKB3EYAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGEIAAAADGmA/ApUuXauTIkUpPT1dRUZFeffVVt5cEFzAHYAYgMQeww3QAPvbYYyotLdWiRYv0+uuva8KECZoyZYoOHTrk9tLQi5gDMAOQmAPY4nMcx3F7EW4pKirSeeedpwcffFCSFIlEVFBQoBtvvFHf+MY3XF4degtzAGYAEnMAWwJuL8Atzc3N2rBhgxYsWBC9zO/3q6SkRGvXru3SY0QiER04cED9+vWTz+eL11IRI47jqLa2Vvn5+fL721/8PtU5YAa8JR4zIDEHXsO2AJ3NgDVmA7CiokJtbW3Kzc3tcHlubq7efffdTu/T1NSkpqam6Nf79+/X+PHj47pOxN7evXs1bNgwSd2fA2YgOZzKDEjMQbJgW4BjZ8AaswHYE4sXL9add9553OXn6woFlOrCitAdrWrRGj2jfv369fgxmAFvi8UMSMyB17EtQKy2BV5mNgAHDhyolJQUlZeXd7i8vLxceXl5nd5nwYIFKi0tjX4dDodVUFCggFIV8PE/fML7x96ux7490905sDIDU79UoT592zq9rrI8VS88ntPLK4qRGMyAZGcOkhbbAnQyA9aYDcC0tDRNnDhRK1eu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nkur8qajz9eHPZd5eXnH7Uzd2tqqqqoq155vZiB2vDoDEnMQS16dA2Ygdrw6A15FAPZAWlqaJk6cqJUrV0Yvi0QiWrlypYqLi11cmfcUFhYqLy+vw3MZDoe1bt266HNZXFys6upqbdiwIXqbVatWKRKJqKioqNfXLDEDseTVGZCYg1jy6hwwA7Hj1RnwLLePQvGqRx991AkGg87y5cudt99+25kzZ46TnZ3tlJWVub20hFNbW+ts3LjR2bhxoyPJue+++5yNGzc6u3fvdhzHce655x4nOzvbefLJJ51NmzY5V111lVNYWOg0NDREH+Oyyy5zzj33XGfdunXOmjVrnNGjRzvTp09360dyHIcZ6I5knQHHYQ66I1nngBnoumSdAS8iAE/Bj370I2f48OFOWlqaM3nyZOeVV15xe0kJ6cUXX3QkHfdn5syZjuO0H/p/xx13OLm5uU4wGHQuueQSZ8uWLR0eo7Ky0pk+fbrTt29fJxQKOdddd51TW1vrwk/TETPQNck8A47DHHRVMs8BM9A1yTwDXuNzHMfpvdcbAQAA4Db2AQQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADCGAAQAADDm/wHRVUOa1xGJgwAAAABJRU5ErkJggg==", + "text/html": [ + "\n", + "
\n", + "
\n", + " Figure\n", + "
\n", + " \n", + "
\n", + " " + ], + "text/plain": [ + "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" + ] + }, + "metadata": {}, + "output_type": "display_data" + } + ], + "source": [ + "scan_pixel_pitch = 0.1\n", + "detector_pixel_pitch = scan_pixel_pitch\n", + "overfocus = 0.\n", + "camera_length = 1.\n", + "propagation_distance = overfocus + camera_length\n", + "obj_half_size = 4\n", + "angle = np.arctan2(obj_half_size*detector_pixel_pitch/2*4, propagation_distance)\n", + "\n", + "params = Parameters4DSTEM(\n", + " overfocus=overfocus,\n", + " scan_pixel_pitch=scan_pixel_pitch,\n", + " camera_length=camera_length,\n", + " detector_pixel_pitch=detector_pixel_pitch,\n", + " semiconv=angle,\n", + " scan_center=PixelYX(x=obj_half_size, y=obj_half_size),\n", + " scan_rotation=np.pi/2,\n", + " flip_y=True,\n", + " detector_center=PixelYX(x=obj_half_size*16, y=obj_half_size*16),\n", + " detector_rotation=-np.pi*4/3,\n", + " descan_error=DescanError(\n", + " offpxi=detector_pixel_pitch,\n", + " offpyi=2 * detector_pixel_pitch,\n", + " offsxi=-1 * detector_pixel_pitch/camera_length,\n", + " offsyi=-2 * detector_pixel_pitch/camera_length,\n", + " pxo_pxi=1 * detector_pixel_pitch/scan_pixel_pitch,\n", + " pyo_pyi=2 * detector_pixel_pitch/scan_pixel_pitch,\n", + " sxo_pxi=-3 * detector_pixel_pitch/scan_pixel_pitch/camera_length,\n", + " syo_pyi=-2 * detector_pixel_pitch/scan_pixel_pitch/camera_length,\n", + " ),\n", + ")\n", + "\n", + "obj = np.ones((2*obj_half_size, 2*obj_half_size))\n", + "\n", + "sims = {}\n", + "\n", + "for cl in (1, 2, 3):\n", + " sims[cl] = project(\n", + " image=obj,\n", + " detector_shape=(32*obj_half_size, 32*obj_half_size),\n", + " scan_shape=(2*obj_half_size, 2*obj_half_size),\n", + " sim_params=params.derive(camera_length=cl),\n", + " )\n", + " fig, axes = plt.subplots(1, 4)\n", + " axes[0].imshow(sims[cl][0, 0])\n", + " axes[1].imshow(sims[cl][0, -1])\n", + " axes[2].imshow(sims[cl][-1, 0])\n", + " axes[3].imshow(sims[cl][-1, -1])" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "0fd1bd46-9293-49df-a465-72bb379117d1", + "metadata": {}, + "outputs": [], + "source": [ + "ctx = Context.make_with('inline')\n", + "udf = CoMUDF.with_params(\n", + " regression=RegressionOptions.SUBTRACT_LINEAR,\n", + ")\n", + "regs = {}\n", + "for (cl, sim) in sims.items():\n", + " ds = ctx.load('memory', data=sim)\n", + " res = ctx.run_udf(dataset=ds, udf=udf)\n", + " regs[cl] = res['regression'].raw_data" + ] + }, + { + "cell_type": "code", + "execution_count": 7, + "id": "b99dddce-3329-43f2-9680-02e6bec8fda4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{1: array([[-6.90956137e+00, 3.98811224e+00],\n", + " [ 1.72807100e+00, -9.98795107e-01],\n", + " [ 9.76800977e-04, 4.98367845e-06]]),\n", + " 2: array([[-15.18492459, 15.69053952],\n", + " [ 4.33269717, -2.49978101],\n", + " [ -1.00209797, -1.73023201]]),\n", + " 3: array([[-23.44737689, 27.38049086],\n", + " [ 6.93250047, -4.00068786],\n", + " [ -1.99941691, -3.45880991]])}" + ] + }, + "execution_count": 7, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "regs" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "7bdf96cb-0c00-48b9-aa1a-a0ab27568733", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "{1: array([[-6.92820323, 4. ],\n", + " [ 1.73205081, -1. ],\n", + " [ 0. , 0. ]]),\n", + " 2: array([[-15.18653348, 15.69615242],\n", + " [ 4.33012702, -2.5 ],\n", + " [ -1. , -1.73205081]]),\n", + " 3: array([[-23.44486373, 27.39230485],\n", + " [ 6.92820323, -4. ],\n", + " [ -2. , -3.46410162]])}" + ] + }, + "execution_count": 8, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "exact_regs = {}\n", + "for cl in sims.keys():\n", + " exact_params = params.derive(\n", + " camera_length=cl\n", + " )\n", + " model_0 = Model4DSTEM.build(params=exact_params, scan_pos=PixelYX(0, 0))\n", + " ray = model_0.make_source_ray(source_dy=0, source_dx=0).ray\n", + " res_0 = model_0.trace(ray)\n", + " model_y = Model4DSTEM.build(params=exact_params, scan_pos=PixelYX(y=1., x=0.))\n", + " res_y = model_y.trace(ray)\n", + " model_x = Model4DSTEM.build(params=exact_params, scan_pos=PixelYX(y=0., x=1.))\n", + " res_x = model_x.trace(ray)\n", + " dy = res_0['detector'].sampling['detector_px'].y - exact_params.detector_center.y\n", + " dx = res_0['detector'].sampling['detector_px'].x - exact_params.detector_center.x\n", + " \n", + " dydy = res_y['detector'].sampling['detector_px'].y - res_0['detector'].sampling['detector_px'].y\n", + " dxdy = res_y['detector'].sampling['detector_px'].x - res_0['detector'].sampling['detector_px'].x\n", + " dydx = res_x['detector'].sampling['detector_px'].y - res_0['detector'].sampling['detector_px'].y\n", + " dxdx = res_x['detector'].sampling['detector_px'].x - res_0['detector'].sampling['detector_px'].x\n", + " \n", + " reg = np.array((\n", + " (dy, dx),\n", + " (dydy, dxdy),\n", + " (dydx, dxdx)\n", + " ))\n", + " exact_regs[cl] = reg\n", + "exact_regs" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "d95efcc3-52bf-45bd-8bb6-ccffb6917d97", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "True\n", + "True\n", + "True\n" + ] + } + ], + "source": [ + "for cl in sims.keys():\n", + " print(np.allclose(regs[cl], exact_regs[cl], rtol=1e-2, atol=1e-2))" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "da328177-f80b-4ca7-8a9c-8ded3d0f0043", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": 18, + "id": "8e845e26-c995-4366-b78e-1c86eebb6aeb", + "metadata": {}, + "outputs": [], + "source": [ + "%autoreload\n", + "from microscope_calibration.util.optimize import solve_full_descan_error\n", + "res, residual = solve_full_descan_error(\n", + " ref_params=params,\n", + " regressions=exact_regs,\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": 17, + "id": "f70f723d-593c-4528-b4e8-1a47f7db777c", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(array([ 1.73205081, 0.5 , 1. , -0.8660254 , -1.73205081,\n", + " -1.5 , -1. , 2.59807621, 0.12320508, 0.18660254,\n", + " -0.12320508, -0.18660254]),\n", + " array([ 1. , 0. , 0. , 2. , -3. , 0. , 0. , -2. , 0.1, 0.2, -0.1,\n", + " -0.2]))" + ] + }, + "execution_count": 17, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.array(res.descan_error), np.array(params.descan_error)" + ] + }, + { + "cell_type": "code", + "execution_count": 35, + "id": "0b688c9f-b634-49fc-b5db-b260733bd713", + "metadata": {}, + "outputs": [], + "source": [ + "# Align coordinate system directions with native CoM coordinate\n", + "# system without corrections\n", + "ref_params = params.derive(\n", + " flip_y=False,\n", + " scan_rotation=0.,\n", + " detector_rotation=0.,\n", + ")\n", + "@jax.jit\n", + "def loss(optargs, args=None):\n", + " de = DescanError(*optargs)\n", + " distances = []\n", + " for cl, reg in exact_regs.items():\n", + " opt_params = ref_params.derive(\n", + " camera_length=cl,\n", + " descan_error=de,\n", + " )\n", + " for scan_y in (0., 1.):\n", + " for scan_x in (0., 1.):\n", + " dy = reg[0, 0]\n", + " dx = reg[0, 1]\n", + " dydy = reg[1, 0]\n", + " dxdy = reg[1, 1]\n", + " dydx = reg[2, 0]\n", + " dxdx = reg[2, 1]\n", + " det_y = opt_params.detector_center.y + (dy + dydy*scan_y + dydx*scan_x)\n", + " det_x = opt_params.detector_center.x + (dx + dxdy*scan_y + dxdx*scan_x)\n", + " model = Model4DSTEM.build(\n", + " params=opt_params,\n", + " scan_pos=PixelYX(y=scan_y, x=scan_x)\n", + " )\n", + " ray = model.make_source_ray(source_dy=0., source_dx=0.).ray\n", + " res = model.trace(ray)\n", + " distances.append((\n", + " det_y - res['detector'].sampling['detector_px'].y,\n", + " det_x - res['detector'].sampling['detector_px'].x,\n", + " ))\n", + " return jnp.linalg.norm(jnp.array(distances))\n", + " " + ] + }, + { + "cell_type": "code", + "execution_count": 36, + "id": "eafb2922-1b8e-4545-997f-81a1fe0d3b6f", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "Array(76.01315599, dtype=float64)" + ] + }, + "execution_count": 36, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "loss(jnp.full(shape=(len(DescanError()), ), fill_value=1e-6))" + ] + }, + { + "cell_type": "code", + "execution_count": 37, + "id": "fb64b3d5-c188-4291-86b3-8b3a0e898208", + "metadata": {}, + "outputs": [], + "source": [ + "import optimistix" + ] + }, + { + "cell_type": "code", + "execution_count": 38, + "id": "c863d650-f6ae-45a1-b6f2-877d77be5b6b", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "[ 1.73205081 0.5 1. -0.8660254 -1.73205081 -1.5\n", + " -1. 2.59807621 0.12320508 0.18660254 -0.12320508 -0.18660254]\n", + "CPU times: user 1.46 s, sys: 443 ms, total: 1.9 s\n", + "Wall time: 1.32 s\n" + ] + } + ], + "source": [ + "%%time\n", + "res = optimistix.minimise(fn=loss, solver=optimistix.BFGS(rtol=1e-12, atol=1e-12), y0=jnp.full(shape=(len(DescanError()), ), fill_value=1e-6), max_steps=2**31)\n", + "print(res.value)" + ] + }, + { + "cell_type": "code", + "execution_count": 46, + "id": "9dfb9480-4688-41ec-8614-71e195b73d8e", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "(Array([ 1.73205081, 0.5 , 1. , -0.8660254 , -1.73205081,\n", + " -1.5 , -1. , 2.59807621, 0.12320508, 0.18660254,\n", + " -0.12320508, -0.18660254], dtype=float64),\n", + " array([ 1.00000000e+00, -1.87481768e-12, -3.89530072e-12, 2.00000000e+00,\n", + " -3.00000000e+00, 7.68813502e-13, 1.60125229e-12, -2.00000000e+00,\n", + " 1.00000000e-01, 2.00000000e-01, -1.00000000e-01, -2.00000000e-01]),\n", + " array([ 1. , 0. , 0. , 2. , -3. , 0. , 0. , -2. , 0.1, 0.2, -0.1,\n", + " -0.2]),\n", + " array([ 1. , 0. , 0. , 2. , -3. , 0. , 0. , -2. , 0.1, 0.2, -0.1,\n", + " -0.2]))" + ] + }, + "execution_count": 46, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "res_params = ref_params.derive(\n", + " descan_error=DescanError(*res.value)\n", + ").adjust_scan_rotation(\n", + " params.scan_rotation\n", + ").adjust_detector_rotation(\n", + " params.detector_rotation\n", + ").adjust_flip_y(\n", + " params.flip_y\n", + ")\n", + "res.value, np.array(res_params.descan_error), np.array(ref_params.descan_error), np.array(params.descan_error)" + ] + }, + { + "cell_type": "code", + "execution_count": 49, + "id": "a6a0f48d-9aa5-4cee-8c6e-14f112a09df4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "array([0.1 , 0.06181818, 0.02363636, 0.09545455, 0.05727273,\n", + " 0.01909091, 0.09090909, 0.05272727, 0.01454545, 0.08636364,\n", + " 0.04818182, 0.01 ])" + ] + }, + "execution_count": 49, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.linspace(-1, 1, 12) % 0.11" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "03681c33-8783-4b17-a1ea-2e6ffe465ed7", + "metadata": {}, + "outputs": [], + "source": [ + "@jax.jit\n", + "def loss_lstsq(optargs, _=None):\n", + " de = DescanError(*optargs)\n", + " distances = []\n", + " for cl, reg in exact_regs.items():\n", + " opt_params = ref_params.derive(\n", + " camera_length=cl,\n", + " descan_error=de,\n", + " )\n", + " for scan_y in (0., 1.):\n", + " for scan_x in (0., 1.):\n", + " dy = reg[0, 0]\n", + " dx = reg[0, 1]\n", + " dydy = reg[1, 0]\n", + " dxdy = reg[1, 1]\n", + " dydx = reg[2, 0]\n", + " dxdx = reg[2, 1]\n", + " det_y = opt_params.detector_center.y + (dy + dydy*scan_y + dydx*scan_x)\n", + " det_x = opt_params.detector_center.x + (dx + dxdy*scan_y + dxdx*scan_x)\n", + " model = Model4DSTEM.build(\n", + " params=opt_params,\n", + " scan_pos=PixelYX(y=scan_y, x=scan_x)\n", + " )\n", + " ray = model.make_source_ray(source_dy=0., source_dx=0.).ray\n", + " res = model.trace(ray)\n", + " distances.extend((\n", + " det_y - res['detector'].sampling['detector_px'].y,\n", + " det_x - res['detector'].sampling['detector_px'].x,\n", + " ))\n", + " return jnp.array(distances)**2 + 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e09840c9-53a3-4634-b485-ef15ae2ec901", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "%%time\n", + "res_lstsq = optimistix.least_squares(loss_lstsq, solver=optimistix.BFGS(rtol=1e-12, atol=1e-12), y0=jnp.full(shape=(len(DescanError()), ), fill_value=1e-6), max_steps=2**16)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b2c12e0d-806c-4a1a-a524-095718ec65b6", + "metadata": {}, + "outputs": [], + "source": [ + "res_lstsq.value, opt_res" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "98a4fa3e-30e4-4c72-bed8-1fc78d21e1a3", + "metadata": {}, + "outputs": [], + "source": [ + "type(res_lstsq)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "250081f3-bd71-46f3-a8a9-63197118b0a1", + "metadata": {}, + "outputs": [], + "source": [ + "def test_loss(optargs, args=None):\n", + " return optargs**2 - 1" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e06bc999-a722-4402-a696-7d8e1c40db10", + "metadata": {}, + "outputs": [], + "source": [ + "(-1)**False" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "5edd9c6e-60df-43de-b28f-e24901b1bcad", + "metadata": {}, + "outputs": [], + "source": [ + "optimistix.least_squares(test_loss, solver=optimistix.GaussNewton(rtol=1e-12, atol=1e-12), y0=jnp.zeros(3))" + ] + }, + { + "cell_type": "code", + "execution_count": 50, + "id": "816b955f-4acb-49d1-a816-2e31e821d05f", + "metadata": {}, + "outputs": [], + "source": [ + "angle = np.arctan2(obj_half_size*detector_pixel_pitch/2*2 + 0.0001, propagation_distance)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cae27736-b674-40ca-a47b-07daed7adf76", + "metadata": {}, + "outputs": [], + "source": [ + "y = jnp.full(shape=(len(DescanError()), ), fill_value=1e-6)\n", + "gradient_fn = jax.grad(loss)\n", + "hessian = lx.JacobianLinearOperator(gradient_fn, y, tags=lx.positive_semidefinite_tag)\n", + "solver = lx.CG(rtol=1e-6, atol=1e-6)\n", + "out = lx.linear_solve(hessian, gradient_fn(y, args=None), solver)\n", + "minimum = y - out.value" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "997f820d-65d7-4061-8544-a8e80dc731a3", + "metadata": {}, + "outputs": [], + "source": [ + "res_params = ref_params.derive(\n", + " descan_error=DescanError(*opt_res)\n", + ").adjust_scan_rotation(\n", + " params.scan_rotation\n", + ").adjust_detector_rotation(\n", + " params.detector_rotation\n", + ").adjust_flip_y(\n", + " params.flip_y\n", + ")\n", + "print(np.array(params.descan_error) - np.array(res_params.descan_error))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "36efedf2-3820-4ab8-a894-178740de77a6", + "metadata": {}, + "outputs": [], + "source": [ + "%autoreload\n", + "from microscope_calibration.util.optimize import solve_camera_length\n", + "# Determine camera length from a known diffraction angle in radians,\n", + "# corresponding detector pixel offset, and detector pixel pitch\n", + "scan_pixel_pitch = 0.1\n", + "detector_pixel_pitch = 0.2\n", + "overfocus = 0.01\n", + "camera_length = 1.234\n", + "propagation_distance = overfocus + camera_length\n", + "obj_half_size = 16\n", + "# This is known, e.g. from crystal structure, diffraction order and\n", + "# wavelength\n", + "angle = np.arctan2(obj_half_size*detector_pixel_pitch/2 + 0.00314157, propagation_distance)\n", + "params = Parameters4DSTEM(\n", + " overfocus=overfocus,\n", + " scan_pixel_pitch=scan_pixel_pitch,\n", + " camera_length=camera_length,\n", + " detector_pixel_pitch=detector_pixel_pitch,\n", + " semiconv=angle,\n", + " scan_center=PixelYX(x=obj_half_size, y=obj_half_size),\n", + " scan_rotation=0.,\n", + " flip_y=False,\n", + " detector_center=PixelYX(x=2*obj_half_size, y=2*obj_half_size),\n", + ")\n", + "# This is observed on the detector\n", + "px_radius = jnp.tan(angle) * propagation_distance / detector_pixel_pitch\n", + "\n", + "def doit():\n", + " res, residual = solve_camera_length(\n", + " # Start with a negative value on purpose\n", + " ref_params=params.derive(camera_length=-2*camera_length),\n", + " diffraction_angle=angle,\n", + " radius_px=px_radius,\n", + " )\n", + " return res, residual\n", + "\n", + "%time res, residual = doit()\n", + "\n", + "print(jnp.allclose(res.camera_length, propagation_distance))\n", + "print(jnp.allclose(residual, 0., atol=1e-12))" + ] + }, + { + "cell_type": "code", + "execution_count": 53, + "id": "ec3ba78a-0720-49b1-9294-89a11a32a3b5", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "np.float64(0.6748019148589584)" + ] + }, + "execution_count": 53, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.arctan2(obj_half_size*detector_pixel_pitch/2*4 + 0.0001, propagation_distance)" + ] + }, + { + "cell_type": "code", + "execution_count": 54, + "id": "310f9351-67f2-4d03-85e1-ce84b0307a9b", + "metadata": {}, + "outputs": [], + "source": [ + "mod_params = params.adjust_flip_y(\n", + " flip_y=False,\n", + ").adjust_scan_rotation(\n", + " scan_rotation=0.,\n", + ").adjust_detector_rotation(\n", + " detector_rotation=0.,\n", + ").adjust_detector_rotation(\n", + " detector_rotation=params.detector_rotation\n", + ").adjust_scan_rotation(\n", + " scan_rotation=params.scan_rotation,\n", + ").adjust_flip_y(\n", + " flip_y=params.flip_y,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 56, + "id": "08ca2801-5f80-41a6-99a3-8aca78fc21d4", + "metadata": {}, + "outputs": [ + { + "data": { + "text/plain": [ + "True" + ] + }, + "execution_count": 56, + "metadata": {}, + "output_type": "execute_result" + } + ], + "source": [ + "np.allclose(mod_params.descan_error, params.descan_error)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "77de994e-8a16-44ff-988a-7ba123629523", + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/prototypes/guistuff.ipynb b/prototypes/guistuff.ipynb new file mode 100644 index 0000000..d8caf5a --- /dev/null +++ b/prototypes/guistuff.ipynb @@ -0,0 +1,41 @@ +{ + "cells": [ + { + "cell_type": "markdown", + "id": "c78115ed-4d4c-4fc1-8a83-ab7c5c3f7d4c", + "metadata": {}, + "source": [ + "panel-ui RingSet" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "da662907-d4e8-454f-98b5-763f252b9852", + "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.13.5" + } + }, + "nbformat": 4, + "nbformat_minor": 5 +} diff --git a/prototypes/testbed.ipynb b/prototypes/testbed.ipynb index 9b9c477..636fc25 100644 --- a/prototypes/testbed.ipynb +++ b/prototypes/testbed.ipynb @@ -7,132 +7,871 @@ "metadata": {}, "outputs": [], "source": [ - "%load_ext autoreload\n", "%matplotlib widget" ] }, { "cell_type": "code", "execution_count": 2, + "id": "89b54069-e738-4a09-ba55-5066346e36cb", + "metadata": {}, + "outputs": [], + "source": [ + "%load_ext autoreload" + ] + }, + { + "cell_type": "code", + "execution_count": 3, "id": "0195cf88", "metadata": {}, "outputs": [], "source": [ - "import numpy as np\n", - "import matplotlib.pyplot as plt" + "import numba\n", + "import numpy as np\n", + "import matplotlib.pyplot as plt\n", + "import jax.numpy as jnp\n", + "import jax\n", + "jax.config.update(\"jax_enable_x64\", True)\n", + "import optax" + ] + }, + { + "cell_type": "code", + "execution_count": 4, + "id": "b1bb6a97-e4a5-4f49-98ca-1255e25f2e33", + "metadata": {}, + "outputs": [], + "source": [ + "%autoreload\n", + "from microscope_calibration.common.model import (\n", + " Parameters4DSTEM, Model4DSTEM, Result4DSTEM, PixelYX, CoordXY, identity, rotate, scale, flip_y,\n", + " DescanError\n", + ")\n", + "from microscope_calibration.util.stem_overfocus_sim import smiley, project\n", + "from microscope_calibration.common.stem_overfocus import (\n", + " get_backward_transformation_matrix, get_detector_correction_matrix, correct_frame, project_frame_backwards\n", + ")\n", + "from microscope_calibration.util.optimize import _solve" + ] + }, + { + "cell_type": "code", + "execution_count": 5, + "id": "1f82eb00-7e79-430c-91f4-45217d64e79e", + "metadata": {}, + "outputs": [], + "source": [ + "scan_pixel_pitch = 0.1\n", + "detector_pixel_pitch = 0.2\n", + "overfocus = 0.01\n", + "camera_length = 1.234\n", + "propagation_distance = overfocus + camera_length\n", + "obj_half_size = 16\n", + "angle = np.arctan2(obj_half_size*detector_pixel_pitch/2 + 0.00314157, propagation_distance)\n", + "params = Parameters4DSTEM(\n", + " overfocus=overfocus,\n", + " scan_pixel_pitch=scan_pixel_pitch,\n", + " camera_length=camera_length,\n", + " detector_pixel_pitch=detector_pixel_pitch,\n", + " semiconv=angle,\n", + " scan_center=PixelYX(x=1.1*obj_half_size, y=0.9*obj_half_size),\n", + " scan_rotation=np.pi/23,\n", + " flip_y=True,\n", + " detector_center=PixelYX(x=2.3*obj_half_size, y=1.9*obj_half_size),\n", + " # descan_error=DescanError(\n", + " # offpxi=detector_pixel_pitch,\n", + " # offpyi=detector_pixel_pitch * 2,\n", + " # offsxi=-1 * detector_pixel_pitch/camera_length,\n", + " # offsyi=-2 * detector_pixel_pitch/camera_length,\n", + " # pxo_pxi=2 * detector_pixel_pitch/scan_pixel_pitch,\n", + " # pyo_pyi=3 * detector_pixel_pitch/scan_pixel_pitch,\n", + " # sxo_pxi=-3 * detector_pixel_pitch/scan_pixel_pitch/camera_length,\n", + " # syo_pyi=-4 * detector_pixel_pitch/scan_pixel_pitch/camera_length,\n", + " # ),\n", + " descan_error=DescanError(*np.random.normal(scale=1,size=len(DescanError()))),\n", + " detector_rotation=np.pi/42,\n", + ")\n", + "\n", + "target_params = params.derive(\n", + " descan_error=DescanError(),\n", + " #scan_rotation=np.pi/7,\n", + " #scan_pixel_pitch=scan_pixel_pitch*1.321,\n", + " #detector_center=PixelYX(x=2.12*obj_half_size, y=1.87*obj_half_size),\n", + " #flip_y=True,\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 6, + "id": "7c202b10-1d52-4dc0-a85e-c2dd1cf9ec56", + "metadata": {}, + "outputs": [ + { + "name": "stderr", + "output_type": "stream", + "text": [ + "WARNING:2025-09-18 09:24:04,619:jax._src.xla_bridge:864: An NVIDIA GPU may be present on this machine, but a CUDA-enabled jaxlib is not installed. Falling back to cpu.\n" + ] + }, + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.0048591735576161e-14\n", + "8.702335715267317e-15\n", + "8.702335715267317e-15\n", + "8.702335715267317e-15\n" + ] + } + ], + "source": [ + "%autoreload\n", + "def check_descan_equivalence(params, target_params):\n", + " distances = []\n", + " for scan_y in (0, 1):\n", + " for scan_x in (0, 1):\n", + " for cl in (0, 1):\n", + " ref_params = params.derive(\n", + " camera_length=cl\n", + " )\n", + " ref_model = Model4DSTEM.build(params=ref_params, scan_pos=PixelYX(y=scan_y, x=scan_x))\n", + " ref_ray = ref_model.make_source_ray(source_dy=0., source_dx=0.).ray\n", + " ref = ref_model.trace(ref_ray)\n", + " opt_params = target_params.derive(\n", + " camera_length=cl,\n", + " )\n", + " opt_model = Model4DSTEM.build(params=opt_params, scan_pos=PixelYX(y=scan_y, x=scan_x))\n", + " opt_ray = opt_model.make_source_ray(source_dy=0., source_dx=0.).ray\n", + " opt = opt_model.trace(opt_ray)\n", + " distances.append((\n", + " opt['detector'].sampling['detector_px'].y - ref['detector'].sampling['detector_px'].y,\n", + " opt['detector'].sampling['detector_px'].x - ref['detector'].sampling['detector_px'].x,\n", + " ))\n", + " return jnp.linalg.norm(jnp.array(distances))\n", + "\n", + "\n", + "\n", + "for angle in (0., np.pi/2, np.pi, -np.pi/2):\n", + " print(check_descan_equivalence(\n", + " params,\n", + " Model4DSTEM.set_scan_rotation(params, angle)\n", + " ))\n", + "\n" + ] + }, + { + "cell_type": "code", + "execution_count": 13, + "id": "739d15cc-5519-415b-b889-cb58b6b57f4f", + "metadata": {}, + "outputs": [], + "source": [ + "random_params = Parameters4DSTEM(\n", + " overfocus=np.random.uniform(0.1, 2),\n", + " scan_pixel_pitch=np.random.uniform(0.01, 2),\n", + " scan_center=PixelYX(\n", + " y=np.random.uniform(-10, 10),\n", + " x=np.random.uniform(-10, 10),\n", + " ),\n", + " scan_rotation=np.random.uniform(-np.pi, np.pi),\n", + " camera_length=np.random.uniform(0.1, 2),\n", + " detector_pixel_pitch=np.random.uniform(0.01, 2),\n", + " detector_center=PixelYX(\n", + " y=np.random.uniform(-10, 10),\n", + " x=np.random.uniform(-10, 10),\n", + " ),\n", + " semiconv=np.random.uniform(0.0001, np.pi/2),\n", + " flip_y=np.random.choice([True, False]),\n", + " descan_error=DescanError(\n", + " *np.random.uniform(-1, 1, size=len(DescanError()))\n", + " ),\n", + " detector_rotation=np.random.uniform(-np.pi, np.pi),\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": 15, + "id": "d40a903f-924e-4d8d-b239-b4eec1f4f6a0", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "9.057678187205881e-15\n", + "5.329070518200751e-15\n", + "1.0658141036401503e-14\n", + "1.3053503572900977e-14\n" + ] + } + ], + "source": [ + "%autoreload\n", + "for angle in (0., np.pi/2, np.pi, -np.pi/2):\n", + " print(check_descan_equivalence(\n", + " random_params,\n", + " Model4DSTEM.set_scan_rotation(random_params, angle)\n", + " ))" + ] + }, + { + "cell_type": "code", + "execution_count": 8, + "id": "f5bb1127-dce2-4cdd-9dc0-f72b86902f9e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.507288760336424e-14\n" + ] + } + ], + "source": [ + "%autoreload\n", + "print(check_descan_equivalence(\n", + " params,\n", + " Model4DSTEM.set_flip_y(params, not params.flip_y)\n", + "))" + ] + }, + { + "cell_type": "code", + "execution_count": 9, + "id": "1ef59ca6-92b8-48bc-8902-5588c2190e7e", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "2.5864145986817697e-14\n" + ] + } + ], + "source": [ + "%autoreload\n", + "print(check_descan_equivalence(\n", + " params,\n", + " Model4DSTEM.set_detector_center(params, PixelYX(x=3, y=5))\n", + "))" + ] + }, + { + "cell_type": "code", + "execution_count": 19, + "id": "044b8d2f-c415-4a1b-9b93-d4801c5dfc92", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.2809491335957507e-14\n" + ] + } + ], + "source": [ + "%autoreload\n", + "print(check_descan_equivalence(\n", + " params,\n", + " Model4DSTEM.set_scan_center(params, PixelYX(x=3, y=5))\n", + "))" + ] + }, + { + "cell_type": "code", + "execution_count": 10, + "id": "fc7f65f2-089b-44fa-addb-119c722b03fd", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "0.0\n" + ] + } + ], + "source": [ + "%autoreload\n", + "print(check_descan_equivalence(\n", + " params,\n", + " Model4DSTEM.set_detector_pixel_pitch(params, params.detector_pixel_pitch * np.e)\n", + "))" + ] + }, + { + "cell_type": "code", + "execution_count": 11, + "id": "8efe2275-598d-44e9-8eb9-16b68a2b77f7", + "metadata": {}, + "outputs": [ + { + "name": "stdout", + "output_type": "stream", + "text": [ + "1.0658141036401503e-14\n" + ] + } + ], + "source": [ + "%autoreload\n", + "distances = []\n", + "cl_factor = 2.3\n", + "\n", + "for scan_y in (0, 1):\n", + " for scan_x in (0, 1):\n", + " ref_params = params.derive()\n", + " ref_model = Model4DSTEM.build(params=ref_params, scan_pos=PixelYX(y=scan_y, x=scan_x))\n", + " ref_ray = ref_model.make_source_ray(source_dy=0., source_dx=0.).ray\n", + " ref = ref_model.trace(ref_ray)\n", + " \n", + " opt_params = Model4DSTEM.set_camera_length(\n", + " params,\n", + " params.camera_length * cl_factor,\n", + " )\n", + " opt_model = Model4DSTEM.build(params=opt_params, scan_pos=PixelYX(y=scan_y, x=scan_x))\n", + " opt_ray = opt_model.make_source_ray(source_dy=0., source_dx=0.).ray\n", + " opt = opt_model.trace(opt_ray)\n", + " distances.append((\n", + " opt['detector'].sampling['detector_px'].y - ref['detector'].sampling['detector_px'].y,\n", + " opt['detector'].sampling['detector_px'].x - ref['detector'].sampling['detector_px'].x,\n", + " ))\n", + "print(jnp.linalg.norm(jnp.array(distances)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "16a6f8a4-72ab-47a1-933d-d3f05c246629", + "metadata": { + "scrolled": true + }, + "outputs": [], + "source": [ + "_solve(start=np.random.normal(scale=100,size=len(DescanError())), loss=loss, debug=True)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "b17f4bd7-d5ef-4378-8845-dec8fba31717", + "metadata": {}, + "outputs": [], + "source": [ + "%autoreload\n", + "opt_res = []\n", + "for i in range(10):\n", + " res, residual = _solve(start=np.random.normal(scale=100,size=len(DescanError())), loss=loss) \n", + " print(residual)\n", + " opt_res.append(res)\n", + "np.allclose(opt_res, opt_res[0])" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ffd927cf-ec54-4167-9131-b65c14947ff4", + "metadata": {}, + "outputs": [], + "source": [ + "%autoreload\n", + "for i in range(10):\n", + " opt_res = _solve(start=np.random.normal(scale=100,size=len(DescanError())), loss=loss, debug=False)\n", + " print(np.allclose(params.descan_error, DescanError(*opt_res)))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9f77d8e5-8432-44a4-af59-bc9009324ac8", + "metadata": {}, + "outputs": [], + "source": [ + "np.allclose(params.descan_error, DescanError(*opt_res))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "9534fbd8-26c3-41ce-bc9c-0fd9073e6b02", + "metadata": {}, + "outputs": [], + "source": [ + "start = jnp.array((1., ))\n", + "correct = jnp.array((scan_pixel_pitch, ))\n", + "loss(start), loss(correct)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "810ce193-a428-4a91-b550-26eae6a84186", + "metadata": {}, + "outputs": [], + "source": [ + "solver = optax.lbfgs()\n", + "optargs = start.copy()\n", + "opt_state = solver.init(optargs)\n", + "value_and_grad = optax.value_and_grad_from_state(loss)\n", + "\n", + "def optstep(optargs, opt_state):\n", + " value, grad = value_and_grad(optargs, state=opt_state)\n", + " updates, opt_state = solver.update(\n", + " grad, opt_state, optargs, value=value, grad=grad, value_fn=loss\n", + " )\n", + " print(jnp.linalg.norm(updates))\n", + " optargs = optax.apply_updates(optargs, updates)\n", + " return optargs, opt_state, jnp.linalg.norm(updates)\n", + "\n", + "while True:\n", + " print(f'Optargs: {optargs}, Objective function: {loss(optargs)}, distance {optargs - correct}')\n", + " optargs, opt_state, change = optstep(optargs, opt_state)\n", + " if change < 1e-12:\n", + " break" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "e8d0beff-292e-4264-810b-a92425736342", + "metadata": {}, + "outputs": [], + "source": [ + "%autoreload\n", + "scan_pixel_pitch = 0.1\n", + "detector_pixel_pitch = 0.2\n", + "overfocus = 1.\n", + "camera_length = 1.\n", + "propagation_distance = overfocus + camera_length\n", + "obj_half_size = 16\n", + "angle = np.arctan2(obj_half_size*detector_pixel_pitch/2 + 0.00314157, propagation_distance)\n", + "\n", + "params = Parameters4DSTEM(\n", + " overfocus=overfocus,\n", + " scan_pixel_pitch=scan_pixel_pitch,\n", + " camera_length=camera_length,\n", + " detector_pixel_pitch=detector_pixel_pitch,\n", + " semiconv=angle,\n", + " scan_center=PixelYX(x=obj_half_size, y=obj_half_size),\n", + " scan_rotation=0.,\n", + " flip_y=False,\n", + " detector_center=PixelYX(x=2*obj_half_size, y=2*obj_half_size),\n", + " detector_rotation=0.,\n", + " descan_error=DescanError(\n", + " sxo_pyi=1 * detector_pixel_pitch/scan_pixel_pitch,\n", + " syo_pxi=1 * detector_pixel_pitch/scan_pixel_pitch,\n", + " sxo_pxi=-2 * detector_pixel_pitch/scan_pixel_pitch/camera_length,\n", + " syo_pyi=-1 * detector_pixel_pitch/scan_pixel_pitch/camera_length,\n", + " )\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d71ac6d5-4d17-4581-aabf-f94a3deb1ce9", + "metadata": {}, + "outputs": [], + "source": [ + "obj = smiley(2* obj_half_size)\n", + "sim = project(\n", + " image=obj,\n", + " scan_shape=PixelYX(x=2*obj_half_size, y=2*obj_half_size),\n", + " detector_shape=PixelYX(x=4*obj_half_size, y=4*obj_half_size),\n", + " sim_params=params\n", + ")" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "a1846360-ad9b-4713-b657-bc2db128ab1c", + "metadata": {}, + "outputs": [], + "source": [ + "#np.save('with_descan.npy', sim)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6f528107-9dad-4308-8414-b16bc643de8c", + "metadata": {}, + "outputs": [], + "source": [ + "%autoreload\n", + "test_positions = jnp.array((\n", + " (0, 0),\n", + " (100, 0),\n", + " (0, 100)\n", + "))\n", + "\n", + "target_px = []\n", + "for scan_y, scan_x in test_positions:\n", + " target_model = Model4DSTEM.build(params=params, scan_pos=PixelYX(y=scan_y, x=scan_x))\n", + " target_ray = target_model.make_source_ray(source_dx=0, source_dy=0).ray\n", + " target_res = target_model.trace(target_ray)\n", + " target_px.append((\n", + " target_res['detector'].sampling['detector_px'].x, \n", + " target_res['detector'].sampling['detector_px'].y, \n", + " ))\n", + "\n", + "target_px = jnp.array(target_px)\n", + "\n", + "@jax.jit\n", + "def loss(args):\n", + " sxo_pyi, syo_pxi, sxo_pxi, syo_pyi = args\n", + " opt_params = params.derive(descan_error=DescanError(\n", + " sxo_pyi=sxo_pyi,\n", + " syo_pxi=syo_pxi,\n", + " sxo_pxi=sxo_pxi,\n", + " syo_pyi=syo_pyi,\n", + " ))\n", + " res = []\n", + " for scan_y, scan_x in test_positions:\n", + " opt_model = Model4DSTEM.build(params=opt_params, scan_pos=PixelYX(y=scan_y, x=scan_x))\n", + " opt_ray = opt_model.make_source_ray(source_dx=0, source_dy=0).ray\n", + " opt_res = opt_model.trace(opt_ray)\n", + " res.append((\n", + " opt_res['detector'].sampling['detector_px'].x, \n", + " opt_res['detector'].sampling['detector_px'].y, \n", + " ))\n", + " return jnp.linalg.norm(jnp.array(res) - target_px)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "f129a186-e532-4e1f-90e0-d5e1e94a83f9", + "metadata": {}, + "outputs": [], + "source": [ + "%autoreload\n", + "start = jnp.zeros(4)\n", + "correct = jnp.array((\n", + " 1 * detector_pixel_pitch/scan_pixel_pitch,\n", + " 1 * detector_pixel_pitch/scan_pixel_pitch,\n", + " -2 * detector_pixel_pitch/scan_pixel_pitch/camera_length,\n", + " -1 * detector_pixel_pitch/scan_pixel_pitch/camera_length,\n", + "))\n", + "loss(start), loss(correct)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "888b52f6-aef9-4667-b0c0-03aa9b05d26a", + "metadata": {}, + "outputs": [], + "source": [ + "%%time\n", + "%autoreload\n", + "solver = optax.lbfgs()\n", + "optargs = start.copy()\n", + "opt_state = solver.init(optargs)\n", + "value_and_grad = optax.value_and_grad_from_state(loss)\n", + "\n", + "@jax.jit\n", + "def optstep(optargs, opt_state):\n", + "\n", + " value, grad = value_and_grad(optargs, state=opt_state)\n", + " updates, opt_state = solver.update(\n", + " grad, opt_state, optargs, value=value, grad=grad, value_fn=loss\n", + " )\n", + " optargs = optax.apply_updates(optargs, updates)\n", + " return optargs, opt_state\n", + "\n", + "for i in range(10):\n", + " print(f'Objective function: {loss(optargs)}, distance {optargs - correct}')\n", + " optargs, opt_state = optstep(optargs, opt_state)\n", + "print(f'Objective function: {loss(optargs)}, distance {optargs - correct}')" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "3742cc29-d4a2-4223-b171-93fb1373e1bc", + "metadata": {}, + "outputs": [], + "source": [ + "%autoreload\n", + "obj = smiley(obj_half_size * 2) # np.ones((obj_half_size * 2, obj_half_size * 2))\n", + "\n", + "projected = project(\n", + " image=obj,\n", + " detector_shape=(obj_half_size * 4, obj_half_size * 4),\n", + " scan_shape=(obj_half_size * 2, obj_half_size * 2),\n", + " sim_params=params,\n", + ")\n" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ca0bb727-0fe2-4dd1-ad2f-b3c13e93f554", + "metadata": {}, + "outputs": [], + "source": [] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "4aa08218-3d57-41a7-a934-b42a0c4791ad", + "metadata": {}, + "outputs": [], + "source": [ + "%autoreload\n", + "\n", + "out = np.zeros_like(projected)\n", + "for scan_y in range(out.shape[0]):\n", + " for scan_x in range(out.shape[1]):\n", + " correct_frame(\n", + " frame=projected[scan_y, scan_x],\n", + " mat=mat,\n", + " scan_y=scan_y,\n", + " scan_x=scan_x,\n", + " detector_out=out[scan_y, scan_x],\n", + " )\n", + "\n", + "projected_ref = project(\n", + " image=obj,\n", + " detector_shape=(obj_half_size * 4, obj_half_size * 4),\n", + " scan_shape=(obj_half_size * 2, obj_half_size * 2),\n", + " sim_params=params_ref,\n", + " specimen_to_image=map_coord,\n", + ")\n", + "\n", + "\n", + "scan_y = 16\n", + "scan_x = 16\n", + "\n", + " \n", + "fig, axes = plt.subplots(2, 4, squeeze=False)\n", + "\n", + "axes[0, 0].imshow(projected[scan_y, scan_x])\n", + "axes[0, 1].imshow(projected[:, :, obj_half_size * 2, obj_half_size * 2])\n", + "axes[0, 2].imshow(out[scan_y, scan_x])\n", + "axes[0, 3].imshow(out[:, :, obj_half_size* 2, obj_half_size * 2])\n", + "\n", + "axes[1, 0].imshow(projected_ref[scan_y, scan_x])\n", + "axes[1, 1].imshow(projected_ref[:, :, obj_half_size * 2, obj_half_size * 2])\n", + "axes[1, 2].imshow(out[scan_y, scan_x])\n", + "axes[1, 3].imshow(out[:, :, obj_half_size * 2, obj_half_size * 2])\n" ] }, { "cell_type": "code", - "execution_count": 3, - "id": "1c712893", + "execution_count": null, + "id": "808c9fef-6db7-4104-a4ec-9948daf82183", + "metadata": {}, + "outputs": [], + "source": [ + "clip = 1\n", + "clip2 = 1\n", + "np.allclose(projected_ref, out)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "99175151-8aa0-4139-952a-e97199b4ecf8", "metadata": {}, "outputs": [], "source": [ - "%autoreload 2\n", - "from microscope_calibration.util.stem_overfocus_sim import get_transformation_matrix, detector_px_to_specimen_px, smiley, project\n", - "from microscope_calibration.common.stem_overfocus import OverfocusParams\n", - "from microscope_calibration.udf.stem_overfocus import OverfocusUDF\n", "\n", - "from libertem.api import Context" + "np.allclose(projected_ref[scan_y, scan_x, clip2:-clip2, clip2:-clip2], out[scan_y, scan_x, clip2:-clip2, clip2:-clip2])" ] }, { "cell_type": "code", - "execution_count": 4, - "id": "75b85d71-a5a0-43ec-bc2a-9949578de84a", + "execution_count": null, + "id": "c6ba3ad5-e8ab-4845-97b2-ae36866b4bca", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 4, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "e071166dc865494b882623e951220bf1", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAABNAElEQVR4nO3df3RU5b3v8U8mZCYJSQbCj8QYohwB0VppTQGDPV7FKMtWLr9adV1vpdYerxroBXpWF5xVtbraG5ftqWgb4a7qQtsjRWkFr7b+OiCxngJqBH+WCB6uBCEBquQXZBJm9v3DS+LwPNEdJ8nM5Hm/1spazTcze/ZO4qdfJt9nPxme53kCAACAMwLJPgEAAAAMLhpAAAAAx9AAAgAAOIYGEAAAwDE0gAAAAI6hAQQAAHAMDSAAAIBjaAABAAAcQwMIAADgGBpAAAAAx9AAAgAAOIYGEAAAwDE0gAAAAI6hAQQAAHAMDSAAAIBjaAABAAAcQwMIAADgGBpAAAAAx9AAAgAAOIYGEAAAwDE0gAAAAI6hAQQAAHAMDSAAAIBjaAABAAAcQwMIAADgGBpAAAAAx9AAAgAAOIYGEAAAwDE0gAAAAI6hAQQAAHAMDSAAAIBjaAABAAAcQwMIAADgGBpAAAAAx9AAAgAAOIYGEAAAwDE0gAAAAI6hAQQAAHAMDSAAAIBjaAABAAAcQwMIAADgGBpAAAAAx9AAAgAAOIYGEAAAwDE0gAAAAI6hAQQAAHAMDSAAAIBjaAABAAAcQwMIAADgGBpAAAAAx9AAAgAAOIYGEAAAwDE0gAAAAI6hAQQAAHAMDSAAAIBjaACToKamRmeeeaays7M1ffp0vfLKK8k+JQBpgOwA0F8yPM/zkn0SLnnsscd0/fXXa/Xq1Zo+fbpWrlyp9evXq76+XmPHjv3c58diMR04cED5+fnKyMgYhDMG/PM8T62trSopKVEgwL8v+1Mi2UFuIJWRG8lBAzjIpk+frqlTp+rXv/61pE+Cedy4cVq8eLGWL1/+uc/fv3+/xo0bN9CnCSSkoaFBpaWlyT6NISWR7CA3kA7IjcE1LNkn4JLOzk7V1dVpxYoV3bVAIKDKykpt3brV+pxIJKJIJNL9+cl+/YPXz1RBXs+/lH7x9wnGc9f9n0usx+z6h+NG7fGK3xi1wkzz3wbz3rjeeszOV0catenffMuorTzdvM4/to+yHrP66flG7UR+1Kg9MPMRo1Yeihg1Sfrve64yah9uKjNqp1+2z6j924Snrcesi4SM2q2bFxq1Ya2ZRm3FVU9Yj7lg+N+N2pIPK4za9j992agFp35sPeaGKb81ah9FzXeDrt76T0Yt6z9zrMe89r9uifs80n5Cv6jcrPz8fOvj8cX0NTvIjXjkRjxyAxIN4KA6cuSIotGoioqK4upFRUXatWuX9TnV1dW68847jXpBXkAF+T1Bnh3JMh6TmZ1tPWY01wzovHzzbfd8S5Bn5pqhJUmZIfO1gnlBo1ZgeZ2cDPuvYcBy/oEcM8iH55sBWRCy/xlh2HDz/G3nbnuc7dwlaXjQfP1AjuXcu8zH5eTZr/3T/yd9ku37aTv33n5G+Zbz77QEeSDXcsxefpey88zfO0n8mbGf9TU7yI1TauRGHHIDEotAUt6KFSvU3Nzc/dHQ0JDsUwKQ4sgNAJ+HdwAH0ejRo5WZmammpqa4elNTk4qLi63PCYVCCoXs/zID4Ia+Zge5AeDz0AAOomAwqPLycm3atElz586V9Mkg96ZNm7Ro0aI+HetwtF0d0Z43cNfv/arxmIB9nEUzJ75n1CZlmW/Vr2sbY9TadpkzO5J0ouyEUbtutGU2yTMf97sPL7QeM/SR+eeAs6Z+aNSmhTqM2isR+58e6utPN2rDCs0/WX3n9G3m+fTyJ6dHj5gzNrn7zMcGL/zIqF2ea84MSdJ7Xea1b949yTym5f/jvz1+h/WYYzOHG7UHPz7bPOYec26nc4I5/yVJ8wriX6stI6afWR+JRPRXdpAbPciNeOSGe2gAB9myZcu0cOFCfe1rX9O0adO0cuVKtbe364Ybbkj2qQFIYWQHgP5EAzjIrrnmGh0+fFi33367Ghsb9ZWvfEXPPvusMdwNAJ9GdgDoTzSASbBo0aI+/8kXAMgOAP2FVcAAAACO4R3ANPXi8VLlZPb8+GxD1rYBaymxIWvbgLWU2JC1bcBaSmzI2jZgLSU2ZG0bsJYSG7K2DVhLiQ1ZnzpgfdKhqPn99LsIwLYAQDIXAbRkxayPQ2ogNz51TuRGHHLDPbwDCAAA4BgaQAAAAMfQAAIAADiGBhAAAMAxNIAAAACOYRVwmlp3YKqGDe9ZMuZ3+yMpsVV2thV2UmKr7Gwr7KTEVtnZVthJia2ys62wkxJbZWdbYScltsrOtj2X5H+LLr/bc0nmKtCIx2q+VEZu9CA34pEb7uEdQAAAAMfQAAIAADiGBhAAAMAxNIAAAACOYRFImtq9u0SBnJ6hXb/bH0mJDVnbBqylxIasbQPWkn3I+jvjLjJqB5fNMJ98gTlMLUkdY81B5eeXX2zUthw1t7N6/1vm0LYkZUw6ZtRC7+YatUmXmkPWtgFrKbEha9v2XJL/Lbr8bs8lmYsA2iNR6+OQGsiNHuRGPHLDPbwDCAAA4BgaQAAAAMfQAAIAADiGBhAAAMAxLAJJUzn7hykz1PPj83v3eymxIWvbgLXUtzvgn8o2YC3Zh6yDMzqNWuZ/Ma89e1uh9Zgz5r5h1FbP+YtRsw1Z/2Tj1dZjnmgOGrXw++ad7WfPNJ+/Z6F9mFtnmsPoZxcfNmp+d2eQ/O/Q4Hd3BslcBNDZ1inpfetjkXzkRg9yIx654R7eAQQAAHAMDSAAAIBjaAABAAAcQwMIAADgGBaBpKlYUMr41LC1bcjaNmAt2Yesg3vMu9V3TjAHiucV2Ie5D0XNoeCH/v1So5ZRbA4fV5a/Yz1mIkPWtrvfS/7vgO/37veS/Q74T8zeYNRsQ9Y3PP996zEzOjON2uF1ZeY53eFvdwbJ/w4NfndnkMxFALFj9jv/IzWQGz3IjXjkhnt4BxAAAMAxNIAAAACOoQEEAABwDA0gAACAY2gAAQAAHMMq4DTV9Q/HFc3tWUFnW2VnW2EnSev3ftWoBSLm42ZOfM+o/XDqHOsxm+ZNMI95lvk42/ZHthV2UmKr7Gwr7CT/WyD53f5I8r8Fkm2VnW2FnSQFL2wxas/cdr9Ru+yflhi1D66yr7zL9rlFV1+25zp1FWi0w/7aSA3kRg9yIx654R7eAQQAAHAMDSAAAIBjaAABAAAcQwMIAADgGBaBpKmLz9qjYF7PYPSkLHMg2bb9kSS17Rpp1GxbIL298stGbWThEesxx1xrbgMUee4Mo2YbsrYNWEuJDVnbBqylxIasbdsfSf63QDp1+yNJCloGrCX/Q9ZX3P2SUXvozRnWY9q+y34XAdgWAEjmIgCv0/owpAhyowe5EY/ccA/vAAIAADiGBhAAAMAxNIAAAACOoQEEAABwDItA0tTVo17R8PzM7s/93v1est8BPyOaadRGvn7YqP3oz09Yj3nD8983an6HrL/11W9aj/l//8dEo5Z57jGjlldijinbBqylxIasbQPWkv874J9693tJ6pxw3HrMRIass98xX0eSPPNHbN2h4bqXXzdqtgUAkrkIIHbc/D1E6iA3epAb8cgN9/AOIAAAgGNoAAEAABxDA9iPXnrpJc2ePVslJSXKyMjQxo0b477ueZ5uv/12nXbaacrJyVFlZaV2796dnJMFkBLIDQDJQAPYj9rb2zVlyhTV1NRYv37PPffo/vvv1+rVq7V9+3YNHz5cs2bNUkeH/YamAIY+cgNAMrAIpB9deeWVuvLKK61f8zxPK1eu1I9//GPNmfPJAO1vf/tbFRUVaePGjbr22mv79FrloYgKQj39u9+730tSxjkRozbyr0Gj9tTmx43azfv/0XpMv3fAf+SGq4xa51TztSXpeIk5GByImcPY0dpCozZ2qjlgLSU2ZP388outx9xy1Byaf/9b5jEzJpmD6KF3c63H/OFSc8i6ad4Eo9Z2lvlc2+4MkrTmigeN2j3r5xu1O/94tVELNZvfd8ncoeFEe0T7rY9Eb8iNeORGPHIDA4V3AAfJ3r171djYqMrKyu5aOBzW9OnTtXXr1iSeGYBURW4AGCi8AzhIGhsbJUlFRUVx9aKiou6v2UQiEUUiPf/ybmlpGZgTBJByyA0AA4V3AFNcdXW1wuFw98e4ceOSfUoAUhy5AeDz0AAOkuLiYklSU1NTXL2pqan7azYrVqxQc3Nz90dDQ8OAnieA1EFuABgoNICDZPz48SouLtamTZu6ay0tLdq+fbsqKip6fV4oFFJBQUHcBwA3kBsABgozgP2ora1Ne/bs6f5879692rlzpwoLC1VWVqYlS5bopz/9qSZOnKjx48frtttuU0lJiebOndvn1wplDFMoo6d/f/SI+X8GthV2ktQxxuz7n7ntF0bN7/ZHkv8tkGr/aq5y+2jZDOsxAwXmirpYS5ZRK9zVZdQORdutx7RtgRQwFzdq5sT3jNqHr9pX3tlW2XmFnUYt1m6ee/j9mPWYKgwbpdYzzYfZtuc6dYXdSdNC5m1DbFt03bD5RqPmZdp/l07dout42wm9aH0kekNuxCM34pEbGCg0gP3otdde06WXXtr9+bJlyyRJCxcu1MMPP6wf/ehHam9v10033aSjR4/q61//up599lllZ5u3YgDgBnIDQDLQAPajSy65RJ5nbrx9UkZGhu666y7dddddg3hWAFIZuQEgGZgBBAAAcAwNIAAAgGP4E3Ca2tPVobyunv7dOmT9JXMYWpKGv24OVI/NNLdA8rv9kWTfAmlegTnMvWXGLUatvdQ+0JwRMP8slnPA/JXNfXW3UXvhWJn1mG27Rho12xZI1402d1m4p9Dc/kiyD1lnBqNGLeOAuXXVyNcPW4/58QWjjVrXGPM8bUPWpw5YnxTKMB9rWwSQOdwcjo+1ZlqPeXnuvrjPW6O9DKcjJZAbPciNeOSGe3gHEAAAwDE0gAAAAI6hAQQAAHAMDSAAAIBjWASSpp5qPV/ZXs8d4m1D1h1jzeFfSXrsB+bd+w9FzcFpv3e/l+x3wJ+UZd6oduGap43abVvnWo/p9w74f9jxJ6M2/7151mP6vQO+37vfS9INz3/fqA1rMH8edyx43Khdu9A+zH3z/n80ai0bpxi14IUfGbVTB6xP8rtDg+13KavFekhjEUB2JsPcqYzc6EFuxCM33MM7gAAAAI6hAQQAAHAMDSAAAIBjaAABAAAcwyKQNLXxgynKzA11f24bsrbd/V6yD1mvaxtj1Pze/V6y3wE/4pmP/d2HFxq13L+FjJoklc76wKg9ceUGo/ZKxLye+vrTrcccVmgOrdvugO/37veSlLvPfKzfIWvbgLXUy5C15dv07fHmrgm23Rkk/zs02HZnKFpr/106FG2P+5w7+qc2cqMHuRGP3HAP7wACAAA4hgYQAADAMTSAAAAAjqEBBAAAcAwNIAAAgGNYBZym2t8boUB2zyo22yq74pfs/b3fVXZ+tz+S7Fsg+V1lZ1thJyW2ys62wk6Sjk3oNGp+V9nZVthJia2ys62wk/yvsptXYL6ObXsuyf8WXbbtuT58Ndd6zBeOlcV9fvz4CUlN1sci+ciNHuRGPHLDPbwDCAAA4BgaQAAAAMfQAAIAADiGBhAAAMAxLAJJU8GPM5QZ6hk4tg1ZB1aaA8FSYkPWtgFrKbEha9v2R1JiQ9ZZX221HjPnjXyj5nfI2jZgLSU2ZG0bsJb8D1n73Z5L8r9Fl217rnsK51uPeeoigBPtEUl11sci+ciNHuRGPHLDPbwDCAAA4BgaQAAAAMfQAAIAADiGBhAAAMAxLAJJU50jPQWye4aDbUPWj350gfW5iQxZ2wasJf9D1n7vfi/5H7L2ouZrR5rNIWdJOmNHl1E7FG03an7vfi8lNmRtG7CW/A9Z+92dQfK/Q4Ntd4aPLxhtPWZjfSzu89hx87lIHeRGD3IjHrnhHt4BBAAAcAwNIAAAgGNoAAEAABxDAwgAAOAYFoGkqeGTjiozt2cy2jZk/Zup9ruwb95tDgD7HbK2DVhL/u+A7/fu95L/O+Dn7DIHp2fMfcN6zNXf+ItRW9dWZtT83v1eSmzI2jZgLfkfsva7O4Pkf4cG2+4MzWfZ/62Yuy++Ho0QKamM3OhBbsQjN9zDO4AAAACOoQEEAABwDA0gAACAY2gAAQAAHEMDCAAA4BiW3qSpuWe8oey8rO7PbavsPpqcZdQkKbjHrPtdZWdbYSfZV9l1TTpm1ELv5hq1Hy6dYz3mdS+/btT8rrKzrbCTEltlZ1thJyW2yi7jHPs+UYfXmSsMv7Xhm0bt9KfN77Ftey7J/xZdtu25jpfYVzJmH4p/rZj91wMpgtzoQW7EIzfcwzuAAAAAjqEBBAAAcAwNYD+qrq7W1KlTlZ+fr7Fjx2ru3Lmqr6+Pe0xHR4eqqqo0atQo5eXlacGCBWpqakrSGQNINnIDQDLQAPaj2tpaVVVVadu2bXrhhRfU1dWlK664Qu3t7d2PWbp0qZ566imtX79etbW1OnDggObPt995H8DQR24ASAYWgfSjZ599Nu7zhx9+WGPHjlVdXZ0uvvhiNTc366GHHtLatWs1c+ZMSdKaNWt0zjnnaNu2bbrwQnOouDez899UXn5P/24bsm4vjVmfm1FsDh/PPGu3UZuUZQ4kr2sbYz2mbcg6WhA1auH3LedUGLYe884/Xm3UQs3+hqxtA9aS/yFrv9sfSfYtkB49UmHUMsOdRs1rNM9Hkka9bQ5p/+urTxq1q16uMmq27bkk/1t0Vd57q1ELXGAO+0tSZ0FX3OexY/bvO3pHbsQjN+KRGxgovAM4gJqbmyVJhYWFkqS6ujp1dXWpsrKy+zGTJ09WWVmZtm7tZfVZJKKWlpa4DwBDF7kBYDDQAA6QWCymJUuW6KKLLtJ5550nSWpsbFQwGNSIESPiHltUVKTGxkbrcaqrqxUOh7s/xo0bN9CnDiBJyA0Ag4UGcIBUVVXp7bff1rp16xI6zooVK9Tc3Nz90dDQ0E9nCCDVkBsABgszgANg0aJFevrpp/XSSy+ptLS0u15cXKzOzk4dPXo07l/zTU1NKi4uth4rFAopFOplOAPAkEFuABhMNID9yPM8LV68WBs2bNCWLVs0fvz4uK+Xl5crKytLmzZt0oIFCyRJ9fX12rdvnyoqzOHfzzIhK1sFWT1v4NqGrAOWO7NL0ol2847+tjvg+737veT/DviBlTlG7eMLRluP2TXGfP0TJeYwuG3I2jZgLdmHrG13wPd793vJfgf8f6/7klELnDL4LEnD99vfhM/46xtG7Zr7/9k8zwLzubbdGST/OzTYFgFkv2P+3CRpxtz48+xs69S/WR+J3pAb8ciNeOQGBgoNYD+qqqrS2rVr9eSTTyo/P797PiccDisnJ0fhcFg33nijli1bpsLCQhUUFGjx4sWqqKjo00o+AEMHuQEgGWgA+9GqVaskSZdccklcfc2aNfrud78rSbr33nsVCAS0YMECRSIRzZo1Sw888MAgnymAVEFuAEgGGsB+5Hmfv6N1dna2ampqVFNTMwhnBCDVkRsAkoFVwAAAAI7hHcA0FfFOKOL19O+2IWvbgLUkZUTNH/s93zC3lfrRn58wara730v+74B/7ebDRu3LqxZZj5k53Lw7vO0O+I/ccJVR+82IoPWYDf/NHBC33QHfdvf774y7yHrMg8tmGDXbHfBjLeYQfeEuc8BbkrwZU4yadcj6sPlvuJkT37Me07ZDw7Q7zR0BvBnmzgPHcjKtxzx1EUB7KMowdwojN3qQG/HIDffwDiAAAIBjaAABAAAcQwMIAADgGBpAAAAAx9AAAgAAOIZVwGmqLhLS8GDPCivbKjvbCjtJ+sncx43ao/deYNRuXXOzUcuN2s/H7xZItu2PIpPtWxApZj7WtgWSbfujjywr7D5hrubrGGvWnl9+sVELWla5SfZVdhkB83ufc8D8zy331d3WYzbNm2DUvEJ/q+xs23NJ0uyZVxu11oXm43L/Zi5vLJ31gfWY00LxKy5bOs3vBVIHudGD3IhHbriHdwABAAAcQwMIAADgGBpAAAAAx9AAAgAAOIZFIGnq8b9PUzDSs21R7j7zR2kbsJbsQ9YXvNpg1L7x5yVGLVBg34LoOssWSGMzhxu1Bz8+26gF9+RYj9k5wRzyfuwHvzBq/3PbLUbNNmAtJTZkbRuwluxD1rFmc0up8PuWcyoMW4/ZeqZZywyak/RnlTUaNdv2XJL08QWjjVrXSPOYXqY5IG7bnkuSQhnDTvmcYe5URm70IDfikRvu4R1AAAAAx9AAAgAAOIYGEAAAwDE0gAAAAI5hEUiaeun9CQrkZnd/HjRvwq5vWwasJf9D1tmHzF+PDqPyCdsd8L//v183auv3ftWoBSL2Y86c+J5Rm5SVbdQWrnnaqP1ko3n3ekk6YRmyfuCG1UZt2s3mlc5/b571mJHnzjBqtjvgPzF7g1F7JWJejyTd8Pz3jdqwBnPo/fCWMqNW9NEe6zHPW3LQqLVsnGLU/O7OIJk7NLR1McydysiNHuRGPHLDPbwDCAAA4BgaQAAAAMfQAAIAADiGBhAAAMAxLAJJU1n/maPM7J5BYNvd7+cV2Ie5D0XNu9r7HbKuLH/HeszVc/5i1Kbd+c9GrXmGefd7r+yE9ZjXjd5q1CKe+djffXihUQt9lGHUJOmsqR+a5xkyB7dtQ9b19adbjzms0Px+2u6Af+rd7yXp0SMV1mNmhi27BBw3z+mZ2/7VqP39X+zXftXLVUbN7yIA2wIAyVwE0NHWJcncZQCpgdzoQW7EIzfcwzuAAAAAjqEBBAAAcAwNIAAAgGNoAAEAABxDAwgAAOAYVgGnqUCnFPjUoi2/2x9J0rq2MUatbddIo3bCssrOtsJOsq+yG3OtuQ1QS6P52hkHzG2WJOmeb8w3ah9fMNqoNV5sbiNkW2EnJbbKLnef/T8X2xZIj9xwlVH7zQjzOj+4yr7yLlDQZdRurHzRqPndnkuSgnvMLaH8rgK1rQCVzFWg0WMRSc9bH4vkIzd6kBvxyA338A4gAACAY2gAAQAAHEMDCAAA4BgaQAAAAMewCCRNHS89oUBOzwC13+2PJP9bIPnd/kjyvwXSsJZMo3bHgsetx7x24WGj9uVVi4xaZtg8J9v2R1JiQ9aBL5mDz5KUWVto1DL++lejdsWb5vN/98Rl1mN2Woa5/Q5Z27bnkuxbdPldBGBbACCZiwBiHfbfD6QGcqMHuRGP3HAP7wACAAA4hgYQAADAMTSAAAAAjqEBBAAAcAyLQNLUxIkHNGx4qPtz25C1bcBa6mXI2nIHfL93v5f83wHfdvf7y3PNO/9L0ntd5kB1ZLI5EB18L9eofWf+Jusx/+XaeqP2v46Yd8C3DVnbBqwl6bEf/MKojVpqfj9nvX6jUbMNWEuJDVnbdmeQ/O/QYFsEYFsAIJmLAKIR+w4FSA3kxqeOSW7EITfcwzuAAAAAjqEBBAAAcAwNYD9atWqVzj//fBUUFKigoEAVFRV65plnur/e0dGhqqoqjRo1Snl5eVqwYIGampqSeMYAko3cAJAMNID9qLS0VHfffbfq6ur02muvaebMmZozZ47eeecdSdLSpUv11FNPaf369aqtrdWBAwc0f/78JJ81gGQiNwAkA4tA+tHs2bPjPv/Zz36mVatWadu2bSotLdVDDz2ktWvXaubMmZKkNWvW6JxzztG2bdt04YX2YdneXFvyqnLyen58tiFr24C1lNiQtW3AWpI2755kHjNkPu7b48270o/NHG495oMfm0PWwT05Rq1zgjngbbv7veT/Dvh+734vJTZkbRuwlhIbsrbtziD536HB7+4MkrkIINZhfn/x2ciNU45JbsQhNzBQeAdwgESjUa1bt07t7e2qqKhQXV2durq6VFlZ2f2YyZMnq6ysTFu3mv/RAnAPuQFgsPAOYD976623VFFRoY6ODuXl5WnDhg0699xztXPnTgWDQY0YMSLu8UVFRWpsbOz1eJFIRJFIzz8rW1paBurUASQJuQFgsPEOYD87++yztXPnTm3fvl233HKLFi5cqHffffcLH6+6ulrhcLj7Y9y4cf14tgBSAbkBYLDRAPazYDCoCRMmqLy8XNXV1ZoyZYruu+8+FRcXq7OzU0ePHo17fFNTk4qLi3s93ooVK9Tc3Nz90dDQMMBXAGCwkRsABhsN4ACLxWKKRCIqLy9XVlaWNm3qudN8fX299u3bp4oK+9C1JIVCoe7bQ5z8ADC0kRsABhozgP1oxYoVuvLKK1VWVqbW1latXbtWW7Zs0XPPPadwOKwbb7xRy5YtU2FhoQoKCrR48WJVVFT0eSWfJF2as1/5uT39u22VnW2FnZTYKjvbCjspsVV2thV2UmKr7Gwr7KTEVtnZVthJia2ys62wkxJbZWfbnkvyv0WX3+25JHMVaPRYL3tUoVfkRjxyIx65gYFCA9iPDh06pOuvv14HDx5UOBzW+eefr+eee06XX365JOnee+9VIBDQggULFIlENGvWLD3wwANJPmsAyURuAEgGGsB+9NBDD33m17Ozs1VTU6OamppBOiMAqY7cAJAMzAACAAA4hncA04znfTKn0dYWi6u3Rc05kdgxcx5EkqId5mM72rqMWkso5utxnxzTfC3b67e1mscMZtpnT2xzIdGIeczOtk6j1mJ5HUk63m7O3cRs554VNWrtrWZNklo6zdc60e7v3G2Pk+zn3x4xXz923HLuHZnW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", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ - "size = 32\n", - "params = OverfocusParams(\n", + "projected_ref[scan_y, scan_x] - out[scan_y, scan_x]" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "d3be418e-109f-4088-b6f1-e124882a74a5", + "metadata": {}, + "outputs": [], + "source": [ + "detector_rotation = 0.\n", + "scan_rotation = 0.\n", + "\n", + "params = Parameters4DSTEM(\n", " overfocus=1,\n", - " scan_pixel_size=1,\n", + " scan_pixel_pitch=2,\n", " camera_length=1,\n", - " detector_pixel_size=1,\n", - " semiconv=0.004,\n", - " cy=size*2/2,\n", - " cx=size*2/2,\n", - " scan_rotation=0,\n", - " flip_y=False\n", + " detector_pixel_pitch=2,\n", + " semiconv=np.pi/2,\n", + " scan_center=PixelYX(x=16., y=16.),\n", + " scan_rotation=0.,\n", + " flip_y=False,\n", + " detector_center=PixelYX(x=32, y=32.),\n", + " detector_rotation=0.,\n", + " descan_error=DescanError()\n", ")\n", - "obj = smiley(size)\n", + "obj = smiley(64)\n", + "res = np.zeros((32, 32))\n", + "\n", + "# def map_coord(inp):\n", + "# cy = obj.shape[0] / 2\n", + "# cx = obj.shape[1] / 2\n", + "# inp_vec = jnp.array((inp.y, inp.x))\n", + "# y, x = scale(1) @ inp_vec\n", + "# return PixelYX(y=y+cy, x=x+cx)\n", + "\n", + "map_coord = None\n", + "\n", "projected = project(\n", " image=obj,\n", - " scan_shape=(size, size),\n", - " detector_shape=(size*2, size*2),\n", + " scan_shape=((32, 32)),\n", + " detector_shape=((64, 64)),\n", " sim_params=params,\n", + " specimen_to_image=map_coord,\n", ")\n", "\n", - "fig, axes = plt.subplots(2, 2)\n", + "print(projected.shape)\n", "\n", - "axes[0, 0].imshow(obj)\n", - "axes[0, 1].imshow(projected[size//2, size//2, ::2, ::2])\n", - "axes[1, 0].imshow(obj)\n", - "axes[1, 1].imshow(projected[:, :, size*2//2, size*2//2])\n", + "fig, axes = plt.subplots(1, 2, squeeze=False)\n", + "axes[0, 0].imshow(projected[:, :, 32, 32])\n", + "axes[0, 1].imshow(projected[16, 16])\n", + "\n", + "mat = get_backward_transformation_matrix(\n", + " rec_params=params,\n", + " specimen_to_image=map_coord\n", + ")\n", + "project_frame_backwards(\n", + " frame=projected[16, 16],\n", + " source_semiconv=np.pi/2,\n", + " mat=mat,\n", + " scan_y=16,\n", + " scan_x=16,\n", + " image_out=res,\n", + ")\n", + "\n", + "\n", + "\n", + "\n", + "fig, axes = plt.subplots(1, 2, squeeze=False)\n", "\n", - "#assert_allclose(obj, projected[size//2, size//2, ::2, ::2])\n", - "#assert_allclose(obj, projected[::2, ::2, size//2, size//2])" + "axes[0, 0].imshow(obj)\n", + "axes[0, 1].imshow(res)\n" ] }, { "cell_type": "code", - "execution_count": 5, + "execution_count": null, + "id": "e5f1a331-44aa-4892-94e6-853a5d3bae6b", + "metadata": {}, + "outputs": [], + "source": [ + "params = Parameters4DSTEM(\n", + " overfocus=1,\n", + " scan_pixel_pitch=1,\n", + " camera_length=1,\n", + " detector_pixel_pitch=2,\n", + " semiconv=np.pi/2,\n", + " scan_center=PixelYX(x=16, y=16.),\n", + " scan_rotation=0.,\n", + " flip_y=False,\n", + " detector_center=PixelYX(x=16, y=16.),\n", + " detector_rotation=np.pi/2,\n", + " descan_error=DescanError()\n", + ")\n", + "obj = smiley(32)\n", + "res = project(\n", + " image=obj,\n", + " detector_shape=(32, 32),\n", + " scan_shape=(32, 32),\n", + " sim_params=params,\n", + ")\n", + "fig, axes = plt.subplots(1, 2)\n", + "axes[0].imshow(obj)\n", + "axes[1].imshow(np.rot90(res[16, 15], k=-1)) \n", + "#assert_allclose(obj, np.rot90(res[15, 16], k=-1))" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "c96860df-5e7b-44c0-b216-d4fc01c9fff8", + "metadata": {}, + "outputs": [], + "source": [ + "trans = rotate(np.pi/1.23) @ scale(0.23) @ flip_y()\n", + "cis = jnp.linalg.inv(trans)" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "cd89101f-ad89-46a2-8507-ab8e227ca3dc", + "metadata": {}, + "outputs": [], + "source": [ + "trans, cis" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "6cdc3d38-60ac-47ce-84dd-114bb9a3a741", + "metadata": {}, + "outputs": [], + "source": [ + "cis2 = flip_y() @ scale(1/0.23) @ rotate(-np.pi/1.23)\n", + "cis2" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "14e67d70-a0d1-4850-bd19-3a293996177e", + "metadata": {}, + "outputs": [], + "source": [ + "I = np.eye(2, dtype=trans.dtype)\n", + "cis3 = jnp.linalg.solve(trans, I)\n", + "cis3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "0a255952-e3dc-44e9-a8c3-9eda1020524b", + "metadata": {}, + "outputs": [], + "source": [ + "cis3" + ] + }, + { + "cell_type": "code", + "execution_count": null, + "id": "ebb7d83d-280a-4aab-89f8-9b9f19acc9ea", + "metadata": {}, + "outputs": [], + "source": [ + "trans.dtype" + ] + }, + { + "cell_type": "code", + "execution_count": null, "id": "bc0dcc61", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "{'overfocus': 1,\n", - " 'scan_pixel_size': 1,\n", - " 'camera_length': 1,\n", - " 'detector_pixel_size': 1,\n", - " 'cy': 0,\n", - " 'cx': 0}" - ] - }, - "execution_count": 5, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "p = OverfocusParams(\n", " overfocus=1,\n", @@ -147,21 +886,10 @@ }, { "cell_type": "code", - "execution_count": 6, + "execution_count": null, "id": "da01928a", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "(0.0, 0.5)" - ] - }, - "execution_count": 6, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "detector_px_to_specimen_px(\n", " y_px=1.,\n", @@ -175,7 +903,7 @@ }, { "cell_type": "code", - "execution_count": 7, + "execution_count": null, "id": "50ced9b6", "metadata": {}, "outputs": [], @@ -204,71 +932,10 @@ }, { "cell_type": "code", - "execution_count": 8, + "execution_count": null, "id": "6e96ba6c", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 8, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "4896eb20d98b4312bc3677be6d62b2ee", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "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AQAyIwACAGRGAAQAyIwACACQGQEQACAzAiAAQGYEQACAzAiAAACZEQABADIjAAIAZEYABADIjAAIAJAZARAAIDMCIABAZgRAAIDMCIAAAJkRAAEAMiMAAgBkRgAEAMiMAAgAkBkBEAAgMwIgAEBmBEAAgMwIgAAAmREAAQAyIwACAGRGAAQAyIwACACQGQEQACAzAiAAQGYEQACAzAiAAACZEQABADIjAAIAZEYABADIjAAIAJAZARAAIDMCIABAZgRAAIDMCIAAAJkRAAEAMiMAAgBkRgAEAMiMAAgAkBkBEAAgMwIgAEBmBEAAgMwIgAAAmREAAQAyIwACAGRGAAQAyIwACACQGQEQACAzAiAAQGYEQACAzAiAAACZEQABADIjAAIAZEYABADIjAAIAJAZARAAIDMCIABAZgRAAIDMCIAAAJkRAAEAMiMAAgBkRgAEAMiMAAgAkBkBEAAgMwIgAEBmBEAAgMwIgAAAmREAAQAyIwACAGRGAAQAyIwACACQGQEQACAzAiAAQGYEQACAzAiAAACZEQABADIjAAIAZEYABADIjAAIAJAZARAAIDMCIABAZgRAAIDMCIAAAJkRAAEAMiMAAgBkRgAEAMiMAAgAkBkBEAAgMwIgAEBmBEAAgMwIgAAAmREAAQAyIwACAGRGAAQAyIwACACQGQEQACAzAiAAQGYEQACAzAiAAACZEQABADIjAAIAZEYABADIjAAIAJAZARAAIDMCIABAZgRAAIDMCIAAAJn5f1X6GIVdRNHEAAAAAElFTkSuQmCC", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "880558113c3748c195c70a45cf27ad27", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "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AQAyIwACAGRGAAQAyIwACACQGQEQACAzAiAAQGYEQACAzAiAAACZEQABADIjAAIAZEYABADIjAAIAJAZARAAIDMCIABAZgRAAIDMCIAAAJkRAAEAMiMAAgBkRgAEAMiMAAgAkBkBEAAgMwIgAEBmBEAAgMwIgAAAmREAAQAyIwACAGRGAAQAyIwACACQGQEQACAzAiAAQGYEQACAzAiAAACZEQABADIjAAIAZEYABADIjAAIAJAZARAAIDMCIABAZgRAAIDMCIAAAJkRAAEAMiMAAgBkRgAEAMiMAAgAkBkBEAAgMwIgAEBmBEAAgMwIgAAAmREAAQAyIwACAGRGAAQAyIwACACQGQEQACAzAiAAQGYEQACAzAiAAACZEQABADIjAAIAZEYABADIjAAIAJAZARAAIDMCIABAZgRAAIDMCIAAAJkRAAEAMiMAAgBkRgAEAMiMAAgAkBkBEAAgMwIgAEBmBEAAgMwIgAAAmREAAQAyIwACAGRGAAQAyIwACACQGQEQACAzAiAAQGYEQACAzAiAAACZEQABADIjAAIAZEYABADIjAAIAJAZARAAIDMCIABAZgRAAIDMCIAAAJkRAAEAMiMAAgBkRgAEAMiMAAgAkBkBEAAgMwIgAEBmBEAAgMwIgAAAmREAAQAyIwACAGRGAAQAyIwACACQGQEQACAzAiAAQGYEQACAzAiAAACZEQABADIjAAIAZEYABADIjAAIAJAZARAAIDMCIABAZgRAAIDMCIAAAJn5f1X6GIVdRNHEAAAAAElFTkSuQmCC", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "fig, axes = plt.subplots(1, 3)\n", "axes[0].imshow(obj)\n", @@ -283,121 +950,10 @@ }, { "cell_type": "code", - "execution_count": 9, + "execution_count": null, "id": "984405c9", "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "ed13357a252148ab8c1988facd52d00e", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "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", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "8bd9f6fa7eab4f7a8c460ed469f6c65c", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "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e+/p7bff1ueff653331XktSqVSv99re/1TPPPKOxY8e6f/euv/56Sb+EfXp6urp06aKpU6fKx8dHc+bM0U033aS//OUv6tatmyTp66+/dh+PadOm6cyZM5o6dar7d+RSZGRk6JtvvtH48ePVokULHT58WKtXr9b+/fvdv0uXquL1nD59ujZt2qS3335bwcHB+uyzzxQXF6fnnntOf/7znzVz5ky1b99ew4cPv6yfA9R7BkCNKiwsNJLMwIEDz7vdv/3bvxlJpri42BhjzLBhw0x4eLg5c+aMe5tDhw4ZHx8f89vf/ta9rG/fvqZDhw7m1KlT7mXl5eXm+uuvN61atXIvmzNnjpFkbrjhBo/nNMaYTz/91EgyCxcu9FjeuXNnEx4ebo4dO+Ze9tVXXxkfHx8zfPhw97Lhw4cbHx8f88UXX1Tar/LycmOMMVOnTjVV/S+mYq69e/caY4xZsmSJkVTlc1XYu3evkWRmzpxZ5fqZM2d6PKcxxvTu3du0a9eu2ues+Lmvvvqqe1l8fLyRVOk2depUY8z/vW4V96vzt7/9rcrX91ySjL+/v9mzZ4972VdffWUkmddff9297NzXzBhjRowYYRo3buzxfF988YWRZObMmeOxvLy83LRq1cqkpaW5j48xxpw8edIkJCSYm2++2b1s0KBBpmHDhua7775zL/v222+Nr69vlcezOj/99NN5j1mF6l7P+Ph4M2LECPf9itfg3H1ISUkxDofDPPTQQ+5lZ86cMTExMaZ3794XPS9gG94CBmrY8ePHJUmBgYHn3a5ifXFxsSRpyJAhOnz4sNatW+feZtGiRSovL9eQIUMkST/++KPWrl2ru+66S8ePH9fRo0d19OhRHTt2TGlpadq9e7d++OEHj58zZsyYStePVeXQoUPKzc3VyJEjFRIS4l7esWNH3Xzzzfrzn/8sSSovL9fSpUs1YMAAXXfddZWe51K/KqTiOsSPPvpIZWVll/TYK9GkSRNJ/3e8KiQnJ2v16tUet4qzSH369JEx5rxn/yS5z/CtXLlSJ0+ePO+2qampSkpKct/v2LGjgoKC9Pe///1Sd6laubm52r17t+6++24dO3bM/XtTUlKivn37av369SovL9fZs2e1cuVKDRo0SHFxce7HX3vttUpLS7ukn1lxfeK6dev0008/1di+jB492uN3LDk5WcYYjR492r3M19dX1113XY2+hkB9QwACNawi7M4Ni3OdG4oV12YtWLDAvc2CBQvUuXNnXXPNNZKkPXv2yBijKVOmKCwszOM2depUSXJ/wKNCQkLCRc393XffSZJat25dad21117rDoYjR46ouLjY/Zb0lerdu7cyMjI0ffp0hYaGauDAgZozZ45KS0sv+bkuJT5PnDghqXKoh4aGKjU11eN2qR/USUhI0KRJk/Tuu+8qNDRUaWlpmjVrVpXX//1jaFVo2rRpjUbT7t27JUkjRoyo9Hvz7rvvqrS0VEVFRTpy5Ih+/vlntWrVqtJzVPV7cT5Op1O///3v9fHHHysiIkK9evXSjBkzlJ+ff0X7cu7rVRHbsbGxlZbX5GsI1DdcAwjUMJfLpaioKG3btu28223btk3NmzdXUFCQpF/+wRw0aJCWLFmiN954QwUFBfrrX/+q5557zv2Y8vJySdLjjz9e7RmZli1betwPCAi4kt25bNXF2NmzZyttt2jRIm3atEnLly/XypUrdf/99+vFF1/Upk2b1KRJEzVs2FCS9PPPP1f5nBVn2Sq2uxgVH6o59/WqKS+++KJGjhypZcuWadWqVZowYYKysrK0adMmxcTEuLer7uysqcEPMFT83sycObPar4dp0qTJZUX3+UycOFEDBgzQ0qVLtXLlSk2ZMkVZWVlau3at/uVf/uW8jz3396RCda9XVctr8jUE6hsCEKgFt912m9555x1t2LBBN9xwQ6X1f/nLX7Rv3z49+OCDHsuHDBmiefPmac2aNdqxY4eMMe63fyW5z0T5+fkpNTW1Rmeu+CLoXbt2VVq3c+dOhYaGqnHjxgoICFBQUJDHp5Kr0rRpU0lSYWGhx9fNVJxpPFf37t3VvXt3/fu//7uys7N1zz33aP78+XrggQcUFhamRo0aVTlbxcyNGjVSaGjoxeyqzp49q+zsbDVq1KjK41NTOnTooA4dOujpp5/WZ599ph49emj27Nl69tlna+XnVRfdFW8xBwUFnff3JiwsTAEBAe4zhv+outf+QpKSkvTYY4/pscce0+7du9W5c2e9+OKLev/99yX98ntSWFjo8ZjTp0/r0KFDl/XzAFwc3gIGasETTzyhgIAAPfjggzp27JjHuh9//FEPPfSQGjVqpCeeeMJjXWpqqkJCQrRgwQItWLBA3bp183gLNzw8XH369NFbb71V5T+QR44cueyZo6Ki1LlzZ82bN8/jH+Tt27dr1apVuuWWWyRJPj4+GjRokJYvX64tW7ZUep6Ksy4V0bF+/Xr3upKSEs2bN89j+59++qnSmZqKs1QVZ6R8fX3Vr18/LV++XPv37/fYdv/+/Vq+fLn69et3Udc6nj17VhMmTNCOHTs0YcIE9xnYi3GxXwNTXFysM2fOeCzr0KGDfHx8avws2z9q3LixJFUKqi5duigpKUkvvPCC+63vf1Txe+Pr66u0tDQtXbrU43XesWOHVq5ceUmznDx5stJfT0lKSlJgYKDHa5CUlOTxOyJJb7/9drVnAAHUDM4AArWgVatWmjdvnu655x516NCh0l8COXr0qD744AOPi/+lX87sDR48WPPnz1dJSUmVf/ps1qxZuuGGG9ShQweNGTNGiYmJKigo0MaNG/X999/rq6++uuy5Z86cqfT0dKWkpGj06NHur4FxuVweH3x47rnntGrVKvXu3Vtjx47Vtddeq0OHDmnhwoXasGGDgoOD1a9fP8XFxWn06NF64okn5Ovrqz/+8Y8KCwvziIt58+bpjTfe0O23366kpCQdP35c77zzjoKCgtzRWfEzu3fvrn/913/V2LFj1aJFC+3bt09vv/22HA6Hx1vlFYqKitxnmk6ePOn+SyB5eXkaOnSofve7313S63OxXwOzdu1ajRs3TnfeeaeuueYanTlzRu+99558fX2VkZFxST/zUiQlJSk4OFizZ89WYGCgGjdurOTkZCUkJOjdd99Venq62rVrp1GjRql58+b64Ycf9OmnnyooKEjLly+XJE2fPl0rVqxQz5499cgjj+jMmTN6/fXX1a5duwte1vCP/vd//1d9+/bVXXfdpbZt26pBgwZasmSJCgoKNHToUPd2DzzwgB566CFlZGTo5ptv1ldffaWVK1de9NlcAJfJex9ABuq/bdu2mWHDhpmoqCjj5+dnIiMjzbBhw8zXX39d7WNWr15tJBmHw2EOHDhQ5TZ5eXlm+PDhJjIy0vj5+ZnmzZub2267zSxatMi9TcXXZlT19SrVfQ2MMcZ88sknpkePHiYgIMAEBQWZAQMGmG+//bbSdt99950ZPny4CQsLM06n0yQmJprMzExTWlrq3mbr1q0mOTnZ+Pv7m7i4OPPSSy9V+kqTL7/80gwbNszExcUZp9NpwsPDzW233Wa2bNlS6Wfu2LHDDBkyxISHh5sGDRqY8PBwM3ToULNjx45K2/bu3dvjq1yaNGliWrVqZe69916zatWqKl/X+Ph4c+utt1a57h9ftwt9Dczf//53c//995ukpCTTsGFDExISYm688UbzySefeGwnyWRmZlY5R1VfgXKhr4Exxphly5aZtm3bmgYNGlT6Spi//e1vZvDgwaZZs2bG6XSa+Ph4c9ddd5k1a9Z4PEdOTo7p0qWL8ff3N4mJiWb27NnVfq1PdY4ePWoyMzNNmzZtTOPGjY3L5TLJycnmww8/9Nju7Nmz5qmnnjKhoaGmUaNGJi0tzezZs6fa1+Dc3+eKuY4cOeKxvLrXB8AvHMZwlSwAAIBNuAYQAADAMlwDCAC4JEVFRdV+JU+FyMjIOpoGwOXgLWAAwCUZOXJkpU9zn4t/WoB/bgQgAOCSfPvttzp48OB5t6np76kEULMIQAAAAMvwIRAAAADL8CEQXJby8nIdPHhQgYGB1f75KQDAPy9jjI4fP67o6Gj5+HA+yDYEIC7LwYMHFRsb6+0xAABX6MCBA4qJifH2GKhjBKDlZs2apZkzZyo/P1+dOnXS66+/rm7dul3wcYGBgZKkG3SLGsivtscEANSwMyrTBv3Z/f9z2IUAtNiCBQs0adIkzZ49W8nJyXrllVeUlpamXbt2KTw8/LyPrXjbt4H81MBBAALAVef/fwSUy3jsxJv+FnvppZc0ZswYjRo1Sm3bttXs2bPVqFEj/fGPf/T2aAAAoBYRgJY6ffq0tm7d6vFdXT4+PkpNTdXGjRsrbV9aWqri4mKPGwAAuDoRgJY6evSozp49q4iICI/lERERys/Pr7R9VlaWXC6X+8YHQAAAuHoRgLgokydPVlFRkft24MABb48EAAAuEx8CsVRoaKh8fX1VUFDgsbygoKDKP+LudDrldDrrajwAAFCLOANoKX9/f3Xp0kVr1qxxLysvL9eaNWuUkpLixckAAEBt4wygxSZNmqQRI0bouuuuU7du3fTKK6+opKREo0aN8vZoAACgFhGAFhsyZIiOHDmiZ555Rvn5+ercubNWrFhR6YMhAACgfnEYY4y3h8DVp7i4WC6XS300kC+CBoCr0BlTpnVapqKiIgUFBXl7HNQxrgEEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwBaatq0aXI4HB63Nm3aeHssAABQBxp4ewB4T7t27fTJJ5+47zdowK8DAAA24F98izVo0ECRkZHeHgMAANQx3gK22O7duxUdHa3ExETdc8892r9/f7XblpaWqri42OMGAACuTgSgpZKTkzV37lytWLFCb775pvbu3auePXvq+PHjVW6flZUll8vlvsXGxtbxxAAAoKY4jDHG20PA+woLCxUfH6+XXnpJo0ePrrS+tLRUpaWl7vvFxcWKjY1VHw1UA4dfXY4KAKgBZ0yZ1mmZioqKFBQU5O1xUMe4BhCSpODgYF1zzTXas2dPleudTqecTmcdTwUAAGoDbwFDknTixAnl5eUpKirK26MAAIBaRgBa6vHHH1dOTo727dunzz77TLfffrt8fX01bNgwb48GAABqGW8BW+r777/XsGHDdOzYMYWFhemGG27Qpk2bFBYW5u3RAABALSMALTV//nxvjwAAALyEt4ABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCMB6aP369RowYICio6PlcDi0dOlSj/XGGD3zzDOKiopSQECAUlNTtXv3bu8MCwAA6hwBWA+VlJSoU6dOmjVrVpXrZ8yYoddee02zZ8/W5s2b1bhxY6WlpenUqVN1PCkAAPCGBt4eADUvPT1d6enpVa4zxuiVV17R008/rYEDB0qS/vM//1MRERFaunSphg4dWpejAgAAL+AMoGX27t2r/Px8paamupe5XC4lJydr48aNXpwMAADUFc4AWiY/P1+SFBER4bE8IiLCva4qpaWlKi0tdd8vLi6unQEBAECt4wwgLkpWVpZcLpf7Fhsb6+2RAADAZSIALRMZGSlJKigo8FheUFDgXleVyZMnq6ioyH07cOBArc4JAABqDwFomYSEBEVGRmrNmjXuZcXFxdq8ebNSUlKqfZzT6VRQUJDHDQAAXJ24BrAeOnHihPbs2eO+v3fvXuXm5iokJERxcXGaOHGinn32WbVq1UoJCQmaMmWKoqOjNWjQIO8NDQAA6gwBWA9t2bJFN954o/v+pEmTJEkjRozQ3Llz9eSTT6qkpERjx45VYWGhbrjhBq1YsUINGzb01sgAAKAOOYwxxttD4OpTXFwsl8ulPhqoBg4/b48DALhEZ0yZ1mmZioqKuKzHQlwDCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYArIfWr1+vAQMGKDo6Wg6HQ0uXLvVYP3LkSDkcDo9b//79vTMsAACocwRgPVRSUqJOnTpp1qxZ1W7Tv39/HTp0yH374IMP6nBCAADgTQ28PQBqXnp6utLT08+7jdPpVGRkZB1NBAAA/plwBtBS69atU3h4uFq3bq2HH35Yx44d8/ZIAACgjnAG0EL9+/fX4MGDlZCQoLy8PP3mN79Renq6Nm7cKF9f3yofU1paqtLSUvf94uLiuhoXAADUMALQQkOHDnX/d4cOHdSxY0clJSVp3bp16tu3b5WPycrK0vTp0+tqRAAAUIt4CxhKTExUaGio9uzZU+02kydPVlFRkft24MCBOpwQAADUJM4AQt9//72OHTumqKioardxOp1yOp11OBUAAKgtBGA9dOLECY+zeXv37lVubq5CQkIUEhKi6dOnKyMjQ5GRkcrLy9OTTz6pli1bKi0tzYtTAwCAukIA1kNbtmzRjTfe6L4/adIkSdKIESP05ptvatu2bZo3b54KCwsVHR2tfv366Xe/+x1n+AAAsAQBWA/16dNHxphq169cubIOpwEAAP9s+BAIAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQKwHsrKylLXrl0VGBio8PBwDRo0SLt27fLY5tSpU8rMzFSzZs3UpEkTZWRkqKCgwEsTAwCAukQA1kM5OTnKzMzUpk2btHr1apWVlalfv34qKSlxb/Poo49q+fLlWrhwoXJycnTw4EENHjzYi1MDAIC64jDGGG8Pgdp15MgRhYeHKycnR7169VJRUZHCwsKUnZ2tO+64Q5K0c+dOXXvttdq4caO6d+9+wecsLi6Wy+VSHw1UA4dfbe8CAKCGnTFlWqdlKioqUlBQkLfHQR3jDKAFioqKJEkhISGSpK1bt6qsrEypqanubdq0aaO4uDht3LixyucoLS1VcXGxxw0AAFydCMB6rry8XBMnTlSPHj3Uvn17SVJ+fr78/f0VHBzssW1ERITy8/OrfJ6srCy5XC73LTY2trZHBwAAtYQArOcyMzO1fft2zZ8//4qeZ/LkySoqKnLfDhw4UEMTAgCAutbA2wOg9owbN04fffSR1q9fr5iYGPfyyMhInT59WoWFhR5nAQsKChQZGVnlczmdTjmdztoeGQAA1AHOANZDxhiNGzdOS5Ys0dq1a5WQkOCxvkuXLvLz89OaNWvcy3bt2qX9+/crJSWlrscFAAB1jDOA9VBmZqays7O1bNkyBQYGuq/rc7lcCggIkMvl0ujRozVp0iSFhIQoKChI48ePV0pKykV9AhgAAFzdCMB66M0335Qk9enTx2P5nDlzNHLkSEnSyy+/LB8fH2VkZKi0tFRpaWl644036nhSAADgDXwPIC4L3wMIAFc3vgfQblwDCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYArIeysrLUtWtXBQYGKjw8XIMGDdKuXbs8tunTp48cDofH7aGHHvLSxAAAoC4RgPVQTk6OMjMztWnTJq1evVplZWXq16+fSkpKPLYbM2aMDh065L7NmDHDSxMDAIC61MDbA6DmrVixwuP+3LlzFR4erq1bt6pXr17u5Y0aNVJkZGRdjwcAALyMM4AWKCoqkiSFhIR4LP/Tn/6k0NBQtW/fXpMnT9bJkyerfY7S0lIVFxd73AAAwNWJM4D1XHl5uSZOnKgePXqoffv27uV333234uPjFR0drW3btumpp57Srl27tHjx4iqfJysrS9OnT6+rsQEAQC1yGGOMt4dA7Xn44Yf18ccfa8OGDYqJial2u7Vr16pv377as2ePkpKSKq0vLS1VaWmp+35xcbFiY2PVRwPVwOFXK7MDAGrPGVOmdVqmoqIiBQUFeXsc1DHOANZj48aN00cffaT169efN/4kKTk5WZKqDUCn0ymn01krcwIAgLpFANZDxhiNHz9eS5Ys0bp165SQkHDBx+Tm5kqSoqKiank6AADgbQRgPZSZmans7GwtW7ZMgYGBys/PlyS5XC4FBAQoLy9P2dnZuuWWW9SsWTNt27ZNjz76qHr16qWOHTt6eXoAAFDbuAawHnI4HFUunzNnjkaOHKkDBw7o3nvv1fbt21VSUqLY2Fjdfvvtevrppy/6OpDi4mK5XC6uAQSAqxTXANqNM4D10IWaPjY2Vjk5OXU0DQAA+GfD9wACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEID10JtvvqmOHTsqKChIQUFBSklJ0ccff+xef+rUKWVmZqpZs2Zq0qSJMjIyVFBQ4MWJAQBAXSIA66GYmBg9//zz2rp1q7Zs2aKbbrpJAwcO1DfffCNJevTRR7V8+XItXLhQOTk5OnjwoAYPHuzlqQEAQF1xGGOMt4dA7QsJCdHMmTN1xx13KCwsTNnZ2brjjjskSTt37tS1116rjRs3qnv37hf1fMXFxXK5XOqjgWrg8KvN0QEAteCMKdM6LVNRUZGCgoK8PQ7qGGcA67mzZ89q/vz5KikpUUpKirZu3aqysjKlpqa6t2nTpo3i4uK0ceNGL04KAADqSgNvD4Da8fXXXyslJUWnTp1SkyZNtGTJErVt21a5ubny9/dXcHCwx/YRERHKz8+v9vlKS0tVWlrqvl9cXFxbowMAgFrGGcB6qnXr1srNzdXmzZv18MMPa8SIEfr2228v+/mysrLkcrnct9jY2BqcFgAA1CUCsJ7y9/dXy5Yt1aVLF2VlZalTp0569dVXFRkZqdOnT6uwsNBj+4KCAkVGRlb7fJMnT1ZRUZH7duDAgVreAwAAUFsIQEuUl5ertLRUXbp0kZ+fn9asWeNet2vXLu3fv18pKSnVPt7pdLq/VqbiBgAArk5cA1gPTZ48Wenp6YqLi9Px48eVnZ2tdevWaeXKlXK5XBo9erQmTZqkkJAQBQUFafz48UpJSbnoTwADAICrGwFYDx0+fFjDhw/XoUOH5HK51LFjR61cuVI333yzJOnll1+Wj4+PMjIyVFpaqrS0NL3xxhtenhoAANQVvgcQl4XvAQSAqxvfA2g3rgEEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBn+FjAuS8VfEDyjMok/JggAV50zKpP0f/8/h10IQFyW48ePS5I26M9engQAcCWOHz8ul8vl7TFQxxyG9MdlKC8v18GDBxUYGCiHw+FeXlxcrNjYWB04cKBe/3FxG/bThn2U2M/6xob9rKl9NMbo+PHjio6Olo8PV4TZhjOAuCw+Pj6KiYmpdn1QUFC9/Z/vP7JhP23YR4n9rG9s2M+a2EfO/NmL5AcAALAMAQgAAGAZAhA1yul0aurUqXI6nd4epVbZsJ827KPEftY3NuynDfuI2seHQAAAACzDGUAAAADLEIAAAACWIQABAAAsQwACAABYhgBEjZk1a5ZatGihhg0bKjk5WZ9//rm3R6pR06ZNk8Ph8Li1adPG22NdsfXr12vAgAGKjo6Ww+HQ0qVLPdYbY/TMM88oKipKAQEBSk1N1e7du70z7BW40H6OHDmy0vHt37+/d4a9TFlZWeratasCAwMVHh6uQYMGadeuXR7bnDp1SpmZmWrWrJmaNGmijIwMFRQUeGniy3Mx+9mnT59Kx/Ohhx7y0sSX580331THjh3dX/ickpKijz/+2L2+PhxLeA8BiBqxYMECTZo0SVOnTtWXX36pTp06KS0tTYcPH/b2aDWqXbt2OnTokPu2YcMGb490xUpKStSpUyfNmjWryvUzZszQa6+9ptmzZ2vz5s1q3Lix0tLSdOrUqTqe9MpcaD8lqX///h7H94MPPqjDCa9cTk6OMjMztWnTJq1evVplZWXq16+fSkpK3Ns8+uijWr58uRYuXKicnBwdPHhQgwcP9uLUl+5i9lOSxowZ43E8Z8yY4aWJL09MTIyef/55bd26VVu2bNFNN92kgQMH6ptvvpFUP44lvMgANaBbt24mMzPTff/s2bMmOjraZGVleXGqmjV16lTTqVMnb49RqySZJUuWuO+Xl5ebyMhIM3PmTPeywsJC43Q6zQcffOCFCWvGuftpjDEjRowwAwcO9Mo8teXw4cNGksnJyTHG/HLs/Pz8zMKFC93b7Nixw0gyGzdu9NaYV+zc/TTGmN69e5tf/epX3huqljRt2tS8++679fZYou5wBhBX7PTp09q6datSU1Pdy3x8fJSamqqNGzd6cbKat3v3bkVHRysxMVH33HOP9u/f7+2RatXevXuVn5/vcWxdLpeSk5Pr3bGVpHXr1ik8PFytW7fWww8/rGPHjnl7pCtSVFQkSQoJCZEkbd26VWVlZR7Hs02bNoqLi7uqj+e5+1nhT3/6k0JDQ9W+fXtNnjxZJ0+e9MZ4NeLs2bOaP3++SkpKlJKSUm+PJepOA28PgKvf0aNHdfbsWUVERHgsj4iI0M6dO700Vc1LTk7W3Llz1bp1ax06dEjTp09Xz549tX37dgUGBnp7vFqRn58vSVUe24p19UX//v01ePBgJSQkKC8vT7/5zW+Unp6ujRs3ytfX19vjXbLy8nJNnDhRPXr0UPv27SX9cjz9/f0VHBzsse3VfDyr2k9JuvvuuxUfH6/o6Ght27ZNTz31lHbt2qXFixd7cdpL9/XXXyslJUWnTp1SkyZNtGTJErVt21a5ubn17liibhGAwEVKT093/3fHjh2VnJys+Ph4ffjhhxo9erQXJ0NNGDp0qPu/O3TooI4dOyopKUnr1q1T3759vTjZ5cnMzNT27dvrxXWq51Pdfo4dO9b93x06dFBUVJT69u2rvLw8JSUl1fWYl61169bKzc1VUVGRFi1apBEjRignJ8fbY6Ee4C1gXLHQ0FD5+vpW+vRZQUGBIiMjvTRV7QsODtY111yjPXv2eHuUWlNx/Gw7tpKUmJio0NDQq/L4jhs3Th999JE+/fRTxcTEuJdHRkbq9OnTKiws9Nj+aj2e1e1nVZKTkyXpqjue/v7+atmypbp06aKsrCx16tRJr776ar07lqh7BCCumL+/v7p06aI1a9a4l5WXl2vNmjVKSUnx4mS168SJE8rLy1NUVJS3R6k1CQkJioyM9Di2xcXF2rx5c70+tpL0/fff69ixY1fV8TXGaNy4cVqyZInWrl2rhIQEj/VdunSRn5+fx/HctWuX9u/ff1UdzwvtZ1Vyc3Ml6ao6nlUpLy9XaWlpvTmW8B7eAkaNmDRpkkaMGKHrrrtO3bp10yuvvKKSkhKNGjXK26PVmMcff1wDBgxQfHy8Dh48qKlTp8rX11fDhg3z9mhX5MSJEx5nRfbu3avc3FyFhIQoLi5OEydO1LPPPqtWrVopISFBU6ZMUXR0tAYNGuS9oS/D+fYzJCRE06dPV0ZGhiIjI5WXl6cnn3xSLVu2VFpamhenvjSZmZnKzs7WsmXLFBgY6L4WzOVyKSAgQC6XS6NHj9akSZMUEhKioKAgjR8/XikpKerevbuXp794F9rPvLw8ZWdn65ZbblGzZs20bds2Pfroo+rVq5c6duzo5ekv3uTJk5Wenq64uDgdP35c2dnZWrdunVauXFlvjiW8yNsfQ0b98frrr5u4uDjj7+9vunXrZjZt2uTtkWrUkCFDTFRUlPH39zfNmzc3Q4YMMXv27PH2WFfs008/NZIq3UaMGGGM+eWrYKZMmWIiIiKM0+k0ffv2Nbt27fLu0JfhfPt58uRJ069fPxMWFmb8/PxMfHy8GTNmjMnPz/f22Jekqv2TZObMmePe5ueffzaPPPKIadq0qWnUqJG5/fbbzaFDh7w39GW40H7u37/f9OrVy4SEhBin02latmxpnnjiCVNUVOTdwS/R/fffb+Lj442/v78JCwszffv2NatWrXKvrw/HEt7jMMaYugxOAAAAeBfXAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACW+X82WVV530RvOQAAAABJRU5ErkJggg==", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "33aa14789384459c813d2d205bf22714", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAvQ0lEQVR4nO3de1TVdb7/8dcGYYsKm1CuCoiXtLyuQ4rktSSQyjQtb5Vapl0wRz3V5JzMPFPR5ExajWZ1zqSnIk3Hy9hMmmliNtqMFpmNcpSjiSmYNmwUdYvy+f3Rjz3tQPMGW/k8H2vttdzf73d/9/vL16XP9d0XHMYYIwAAAFgjwN8DAAAAoHYRgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABnLe///3vuv7669WwYUM5HA7l5eX5eyScwejRo9W8eXN/j3FBHA6Hnn76aX+PAdRJBCBwmfr666919913q2nTpnI6nYqLi9Ndd92lr7/+2q9zlZeX684779T333+vmTNn6q233lJiYqJfZzqbPXv2yOFw6Le//W2163/729/K4XBoz5493mV9+vSRw+GQw+FQQECAwsLC1KZNG91zzz1avXp1tftp3ry59zE/vZ04caImDu2ykJOTo1mzZvl7DADnqZ6/BwBQ1ZIlSzR8+HBFRERozJgxSkpK0p49e/Tf//3fWrx4sRYsWKDbb7/dL7MVFBTom2++0RtvvKH777/fLzPUhmbNmik7O1uSVFZWpl27dmnJkiV6++23NWTIEL399tsKCgryeUznzp317//+71X2FRwcXCsz+0NOTo62bdumiRMn+nsUAOeBAAQuMwUFBbrnnnvUokULrV+/XpGRkd51v/jFL9SzZ0/dc8892rp1q1q0aFFrc5WVlalhw4Y6ePCgJCk8PLzWntsfXC6X7r77bp9lzz//vCZMmKA5c+aoefPm+s1vfuOzvmnTplUeAwCXI14CBi4zM2bM0LFjx/T666/7xJ8kNWnSRK+99prKysr0wgsvSJIWL14sh8Oh3NzcKvt67bXX5HA4tG3bNu+yHTt26I477lBERITq16+v6667Tn/60598Hjdv3jzvPh9++GFFRUWpWbNmGj16tHr37i1JuvPOO+VwONSnTx/v49auXauePXuqYcOGCg8P14ABA7R9+/Yqc3377bcaM2aM4uLi5HQ6lZSUpIceekgnT56UJD399NNyOBxVHlc5149frt28ebMyMjLUpEkThYSEKCkpSffdd9/P/JQvTGBgoF5++WVde+21+v3vfy+3233Ojz127Jh27NihQ4cO/ey2O3fu1ODBgxUTE6P69eurWbNmGjZsWJXne/vtt5WcnKyQkBBFRERo2LBhKiws/Nn9V1RUaNasWWrXrp3q16+v6OhoPfDAA/rnP/9ZZdsPPvhAvXv3VmhoqMLCwtSlSxfl5ORI+uGl8j//+c/65ptvvC93//j9hh6PR9OmTVOrVq3kdDoVHx+vxx9/XB6Px+c5PB6PJk2apMjISIWGhuq2227Tvn37fvY4AFw4rgACl5kVK1aoefPm6tmzZ7Xre/XqpebNm+vPf/6zJOmWW25Ro0aN9N5773njrNLChQvVrl07tW/fXtIP7yvs3r27mjZtqieeeEINGzbUe++9p4EDB+qPf/xjlZeVH374YUVGRuqpp55SWVmZevXqpaZNm+q5557ThAkT1KVLF0VHR0uSPvroI2VmZqpFixZ6+umndfz4cb3yyivq3r27Pv/8c28Y7N+/X127dlVJSYnGjRuntm3b6ttvv9XixYt17Nix83q59ODBg0pPT1dkZKSeeOIJhYeHa8+ePVqyZMk57+N8BQYGavjw4Zo6dao2bNigW265xbuuvLy8SuA1aNBADRo00N/+9jfdcMMNmjZt2lk/2HDy5EllZGTI4/HokUceUUxMjL799lu9//77KikpkcvlkiQ9++yzmjp1qoYMGaL7779f3333nV555RX16tVLX3zxxVmv0D7wwAOaN2+e7r33Xk2YMEG7d+/W73//e33xxRf69NNPvS9tz5s3T/fdd5/atWunKVOmKDw8XF988YVWrlypESNG6D/+4z/kdru1b98+zZw5U5LUqFEjST9E5m233aYNGzZo3Lhxuuaaa/TVV19p5syZ+t///V8tW7bMO8/9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6o033qiy7vjx4yorK5MkZWZmSpJefvlln2347SJAzeIKIHCZad26tebPn6+77rpLHTp0qPKbQA4dOqR33323ynumgoKCNGjQIC1YsEBlZWXV/uqz2bNnq0ePHurQoYPGjh2rFi1aqLi4WBs3btS+ffv05ZdfXvDcM2bMUGZmplJTUzVmzBjv18C4XC6fDz4899xz+vDDD9W7d2/v14McOHBAixYt0oYNGxQeHq709HQlJCRozJgxeuyxxxQYGKg//OEPioyM9Im4+fPna86cObr99tvVsmVLHTlyRG+88YbCwsK80Vn5nN26ddO//du/ady4cWrevLn27Nmj119/XQ6Hw+el8kput1tvv/22pB/irfI3gRQUFGjYsGHVBtTZnOvXwKxdu1bjx4/XnXfeqauvvlqnTp3SW2+9pcDAQA0ePFjSD4H8zDPPaMqUKdqzZ48GDhyo0NBQ7d69W0uXLtW4ceP06KOPVrv/3r1764EHHlB2drby8vKUnp6uoKAg7dy5U4sWLdJLL72kO+64Q2FhYZo5c6buv/9+denSRSNGjNBVV12lL7/8UseOHfPGeHJyshYuXKjJkyerS5cuatSokfr376977rlH7733nh588EF9/PHH6t69u06fPq0dO3bovffe06pVq3Tdddepc+fOGj58uObMmSO3263rr79ea9as0a5du87r5wvgPPnr48cAzm7r1q1m+PDhJjY21gQFBZmYmBgzfPhw89VXX53xMatXrzaSjMPhMIWFhdVuU1BQYEaOHGliYmJMUFCQadq0qbn11lvN4sWLvdtUft1KdV+vcqavgTHGmI8++sh0797dhISEmLCwMNO/f3/zj3/8o8p233zzjRk5cqSJjIw0TqfTtGjRwmRlZRmPx+PdZsuWLSYlJcUEBwebhIQE8+KLL1b5GpjPP//cDB8+3CQkJBin02mioqLMrbfeajZv3lzlObdv326GDh1qoqKiTL169UxUVJQZNmyY2b59e5Vte/fu7fNVLo0aNTKtW7c2d999t/nwww+r/bkmJiaaW265pdp1P/65/dzXmvzf//2fue+++0zLli1N/fr1TUREhLnhhhvMRx99VGXbP/7xj6ZHjx6mYcOGpmHDhqZt27YmKyvL5Ofne7f56dfAVHr99ddNcnKyCQkJMaGhoaZDhw7m8ccfN/v37/fZ7k9/+pO5/vrr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", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "c24a48c6f3164f78bf662fb860153bff", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAArmElEQVR4nO3de3TU9Z3/8dckJMMtmRhzmYQQCBdBuZ4FiSkIKCkhKhsEFagKaIQVg1ZYtcUjIlvXUGm9LoJtt8BWEYQVWGi9IEgou4EW3BShkkIKgkDCRZOBIEMgn98f/jLbMUG5JPMt83k+zvme43y/35l5f+fbQ5/nO5e4jDFGAAAAsEaE0wMAAAAgtAhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAc88c//lHf+9731KpVK7lcLpWUlDg9EgBYgQAEwtzOnTt1zz33qE2bNnK73UpNTdXdd9+tnTt3OjpXTU2N7rzzTn3xxRd68cUX9Zvf/Ebt2rVzdKZvs2/fPrlcLv3sZz9rcPvPfvYzuVwu7du3L7Bu8ODBcrlccrlcioiIUGxsrLp06aJ7771Xa9eubfBx2rdvH7jPN5fTp083xaEBsFAzpwcA0HTeeecdjR07VvHx8crPz1dGRob27dunf//3f9fy5cu1ZMkS3X777Y7MVlZWps8++0y//OUv9cADDzgyQyikpaWpsLBQklRdXa09e/bonXfe0RtvvKG77rpLb7zxhqKiooLu07t3b/3zP/9zvceKjo4OycwAwh8BCISpsrIy3XvvverQoYM2btyoxMTEwLYf/vCHuvHGG3Xvvfdq+/bt6tChQ8jmqq6uVqtWrXTkyBFJUlxcXMie2wkej0f33HNP0LrZs2frkUce0Wuvvab27dvrpz/9adD2Nm3a1LsPADQm3gIGwtScOXN06tQp/eIXvwiKP0lKSEjQ66+/rurqaj3//POSpOXLl8vlcqmoqKjeY73++utyuVzasWNHYN2uXbt0xx13KD4+Xs2bN1ffvn31X//1X0H3W7hwYeAxH3roISUlJSktLU0TJkzQoEGDJEl33nmnXC6XBg8eHLjf+vXrdeONN6pVq1aKi4tTXl6ePv3003pzHTx4UPn5+UpNTZXb7VZGRoYmT56sM2fOSJKeeeYZuVyueverm+tv367dunWrcnJylJCQoBYtWigjI0P333//d7zKlyYyMlKvvPKKrrvuOv3bv/2bqqqqLvi+p06d0q5du3Ts2LHv3Hf37t0aNWqUvF6vmjdvrrS0NI0ZMybwfHVvay9cuLDefV0ul5555pnA7brX8i9/+YvuueceeTweJSYmasaMGTLG6MCBA8rLy1NsbKy8Xq9+/vOfX/AxAQg9rgACYWr16tVq3769brzxxga3Dxw4UO3bt9dvf/tbSdKtt96q1q1b6+233w7EWZ2lS5eqW7du6t69u6SvP1fYv39/tWnTRj/+8Y/VqlUrvf322xoxYoT+8z//s97byg899JASExP19NNPq7q6WgMHDlSbNm303HPP6ZFHHtH111+v5ORkSdKHH36o3NxcdejQQc8884y++uorvfrqq+rfv78+/vhjtW/fXpJ06NAh9evXT5WVlZo0aZK6du2qgwcPavny5Tp16tRFvV165MgRDR06VImJifrxj3+suLg47du3T++8884FP8bFioyM1NixYzVjxgxt2rRJt956a2BbTU1NvcBr2bKlWrZsqT/84Q+66aabNHPmzKBA+6YzZ84oJydHfr9fDz/8sLxerw4ePKg1a9aosrJSHo/nkuYePXq0rr32Ws2ePVu//e1v9eyzzyo+Pl6vv/66br75Zv30pz/Vm2++qccee0zXX3+9Bg4ceEnPA6CJGQBhp7Ky0kgyeXl537rfP/7jPxpJxufzGWOMGTt2rElKSjJnz54N7HP48GETERFh/uVf/iWwbsiQIaZHjx7m9OnTgXW1tbXme9/7nuncuXNg3YIFC4wkM2DAgKDHNMaYjz76yEgyy5YtC1rfu3dvk5SUZI4fPx5Y96c//clERESYcePGBdaNGzfOREREmD/+8Y/1jqu2ttYYY8zMmTNNQ//M1c21d+9eY4wxK1asMJIafKw6e/fuNZLMnDlzGtw+Z86coMc0xphBgwaZbt26nfcx65735ZdfDqxr166dkVRvmTlzpjHm/163utvn87//+78Nvr4NHdOCBQvqbfvmc9S9lpMmTQqsO3v2rElLSzMul8vMnj07sP7LL780LVq0MOPHj//WGQE4h7eAgTB04sQJSVJMTMy37le33efzSfr66s6RI0e0YcOGwD7Lly9XbW2tRo8eLUn64osvtH79et111106ceKEjh07pmPHjun48ePKycnR7t27dfDgwaDnmThxoiIjI79z7sOHD6ukpEQTJkxQfHx8YH3Pnj31/e9/X7/73e8kSbW1tVq5cqWGDx+uvn371nucht72/TZ1n0Ncs2aNampqLuq+l6N169aS/u981cnMzNTatWuDlnHjxkn6+pvFxphvvfonKXCF7/3339epU6cabea//cJOZGSk+vbtK2OM8vPzA+vj4uLUpUsX/fWvf2205wXQuAhAIAzVhd03w+KbvhmKw4YNk8fj0dKlSwP7LF26VL1799Y111wjSdqzZ4+MMZoxY4YSExODlpkzZ0pS4AsedTIyMi5o7s8++0yS1KVLl3rbrr32Wh07dkzV1dU6evSofD5f4C3pyzVo0CCNGjVKs2bNUkJCgvLy8rRgwQL5/f6LfqyLic+TJ09Kqh/qCQkJys7ODlou9os6GRkZmjZtmn71q18pISFBOTk5mjt37kV93rAh6enpQbc9Ho+aN2+uhISEeuu//PLLy3ouAE2HAATCkMfjUUpKirZv3/6t+23fvl1t2rRRbGysJMntdmvEiBFasWKFzp49q4MHD+q///u/A1f/pK+vvknSY489Vu8qVd3SqVOnoOdp0aJFIx/hhTlfjJ07d67efsuXL1dxcbGmTJmigwcP6v7771efPn0Ckda8eXNJ0ldffdXgY9ZdZavb70LUfanmm69XY/n5z3+u7du368knn9RXX32lRx55RN26ddPnn38u6cJfn7/V0JXc813dNcZcwtQAQoEABMLUbbfdpr1792rTpk0Nbv/973+vffv26bbbbgtaP3r0aB07dkzr1q3TsmXLZIwJCsC6K1FRUVH1rlLVLd/11vP51P0QdGlpab1tu3btUkJCglq1aqXExETFxsYGfSu5IVdddZUkqbKyMmh93ZXGb7rhhhv0r//6r9q6davefPNN7dy5U0uWLJEkJSYmqmXLlg3OVjdzy5Yt610JO59z585p8eLFatmypQYMGHBB97kUPXr00FNPPaWNGzfq97//vQ4ePKj58+dLuvjXB0D4IACBMPX444+rRYsW+qd/+icdP348aNsXX3yhBx98UC1bttTjjz8etC07O1vx8fFaunSpli5dqn79+gW9hZuUlKTBgwfr9ddf1+HDh+s979GjRy955pSUFPXu3VuLFi0KipIdO3bogw8+0C233CJJioiI0IgRI7R69Wpt3bq13uPUXXnq2LGjJGnjxo2BbdXV1Vq0aFHQ/l9++WW9q1W9e/eWpMDbwJGRkRo6dKhWr16t/fv3B+27f/9+rV69WkOHDr2gzzqeO3dOjzzyiD799FM98sgjgSuwF+JCfwbG5/Pp7NmzQet69OihiIiIwDHFxsYqISEh6PWRpNdee+2C5wFwZeJnYIAw1blzZy1atEh33323evToUe8vgRw7dkxvvfVWIJLqREVFaeTIkVqyZImqq6sb/NNnc+fO1YABA9SjRw9NnDhRHTp0UEVFhYqLi/X555/rT3/60yXPPWfOHOXm5iorK0v5+fmBn4HxeDxBX3x47rnn9MEHH2jQoEGaNGmSrr32Wh0+fFjLli3Tpk2bFBcXp6FDhyo9PV35+fl6/PHHFRkZqV//+tdKTEwMirhFixbptdde0+23366OHTvqxIkT+uUvf6nY2NhAdNY95w033KB/+Id/0KRJk9S+fXvt27dPv/jFL+RyufTcc8/VO56qqiq98cYbkr6Ot7q/BFJWVqYxY8boJz/5yUW9Phf6MzDr16/XlClTdOedd+qaa67R2bNn9Zvf/EaRkZEaNWpUYL8HHnhAs2fP1gMPPKC+fftq48aN+stf/nJRMwG4Ajn4DWQAIbB9+3YzduxYk5KSYqKioozX6zVjx441n3zyyXnvs3btWiPJuFwuc+DAgQb3KSsrM+PGjTNer9dERUWZNm3amNtuu80sX748sE/dz6009PMq5/sZGGOM+fDDD03//v1NixYtTGxsrBk+fLj585//XG+/zz77zIwbN84kJiYat9ttOnToYAoKCozf7w/ss23bNpOZmWmio6NNenq6eeGFF+r9DMzHH39sxo4da9LT043b7TZJSUnmtttuM1u3bq33nJ9++qkZPXq0SUpKMs2aNTNJSUlmzJgx5tNPP62376BBg4J+yqV169amc+fO5p577jEffPBBg69ru3btzK233trgtr993b7rZ2D++te/mvvvv9907NjRNG/e3MTHx5ubbrrJfPjhh0H7nTp1yuTn5xuPx2NiYmLMXXfdZY4cOXLen4E5evRo0P3Hjx9vWrVq1eCxf9tP4ABwlssYPqULAABgEz4DCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGvwSCS1JbW6tDhw4pJibmvH9QHgDw98sYoxMnTig1NVUREVwPsg0BiEty6NAhtW3b1ukxAACX6cCBA0pLS3N6DIQYAWi5uXPnas6cOSovL1evXr306quvql+/ft95v5iYGEnSAN2iZopq6jEBAI3srGq0Sb8L/HsOuxCAFlu6dKmmTZum+fPnKzMzUy+99JJycnJUWlqqpKSkb71v3du+zRSlZi4CEACuOP//D8HyMR478aa/xV544QVNnDhR9913n6677jrNnz9fLVu21K9//WunRwMAAE2IALTUmTNntG3bNmVnZwfWRUREKDs7W8XFxfX29/v98vl8QQsAALgyEYCWOnbsmM6dO6fk5OSg9cnJySovL6+3f2FhoTweT2DhCyAAAFy5CEBckOnTp6uqqiqwHDhwwOmRAADAJeJLIJZKSEhQZGSkKioqgtZXVFTI6/XW29/tdsvtdodqPAAA0IS4Amip6Oho9enTR+vWrQusq62t1bp165SVleXgZAAAoKlxBdBi06ZN0/jx49W3b1/169dPL730kqqrq3Xfffc5PRoAAGhCBKDFRo8eraNHj+rpp59WeXm5evfurffee6/eF0MAAEB4cRljjNND4Mrj8/nk8Xg0WHn8EDQAXIHOmhpt0CpVVVUpNjbW6XEQYnwGEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBaKlnnnlGLpcraOnatavTYwEAgBBo5vQAcE63bt304YcfBm43a8b/HAAAsAH/j2+xZs2ayev1Oj0GAAAIMd4Cttju3buVmpqqDh066O6779b+/fvPu6/f75fP5wtaAADAlYkAtFRmZqYWLlyo9957T/PmzdPevXt144036sSJEw3uX1hYKI/HE1jatm0b4okBAEBjcRljjNNDwHmVlZVq166dXnjhBeXn59fb7vf75ff7A7d9Pp/atm2rwcpTM1dUKEcFADSCs6ZGG7RKVVVVio2NdXochBifAYQkKS4uTtdcc4327NnT4Ha32y232x3iqQAAQFPgLWBIkk6ePKmysjKlpKQ4PQoAAGhiBKClHnvsMRUVFWnfvn36n//5H91+++2KjIzU2LFjnR4NAAA0Md4CttTnn3+usWPH6vjx40pMTNSAAQO0efNmJSYmOj0aAABoYgSgpZYsWeL0CAAAwCG8BQwAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAIahjRs3avjw4UpNTZXL5dLKlSuDthtj9PTTTyslJUUtWrRQdna2du/e7cywAAAg5AjAMFRdXa1evXpp7ty5DW5//vnn9corr2j+/PnasmWLWrVqpZycHJ0+fTrEkwIAACc0c3oANL7c3Fzl5uY2uM0Yo5deeklPPfWU8vLyJEn/8R//oeTkZK1cuVJjxowJ5agAAMABXAG0zN69e1VeXq7s7OzAOo/Ho8zMTBUXFzs4GQAACBWuAFqmvLxckpScnBy0Pjk5ObCtIX6/X36/P3Db5/M1zYAAAKDJcQUQF6SwsFAejyewtG3b1umRAADAJSIALeP1eiVJFRUVQesrKioC2xoyffp0VVVVBZYDBw406ZwAAKDpEICWycjIkNfr1bp16wLrfD6ftmzZoqysrPPez+12KzY2NmgBAABXJj4DGIZOnjypPXv2BG7v3btXJSUlio+PV3p6uh599FE9++yz6ty5szIyMjRjxgylpqZqxIgRzg0NAABChgAMQ1u3btVNN90UuD1t2jRJ0vjx47Vw4UI98cQTqq6u1qRJk1RZWakBAwbovffeU/PmzZ0aGQAAhJDLGGOcHgJXHp/PJ4/Ho8HKUzNXlNPjAAAu0llTow1apaqqKj7WYyE+AwgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAxDGzdu1PDhw5WamiqXy6WVK1cGbZ8wYYJcLlfQMmzYMGeGBQAAIUcAhqHq6mr16tVLc+fOPe8+w4YN0+HDhwPLW2+9FcIJAQCAk5o5PQAaX25urnJzc791H7fbLa/XG6KJAADA3xOuAFpqw4YNSkpKUpcuXTR58mQdP37c6ZEAAECIcAXQQsOGDdPIkSOVkZGhsrIyPfnkk8rNzVVxcbEiIyMbvI/f75ff7w/c9vl8oRoXAAA0MgLQQmPGjAn8d48ePdSzZ0917NhRGzZs0JAhQxq8T2FhoWbNmhWqEQEAQBPiLWCoQ4cOSkhI0J49e867z/Tp01VVVRVYDhw4EMIJAQBAY+IKIPT555/r+PHjSklJOe8+brdbbrc7hFMBAICmQgCGoZMnTwZdzdu7d69KSkoUHx+v+Ph4zZo1S6NGjZLX61VZWZmeeOIJderUSTk5OQ5ODQAAQoUADENbt27VTTfdFLg9bdo0SdL48eM1b948bd++XYsWLVJlZaVSU1M1dOhQ/eQnP+EKHwAAliAAw9DgwYNljDnv9vfffz+E0wAAgL83fAkEAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEYhgoLC3X99dcrJiZGSUlJGjFihEpLS4P2OX36tAoKCnT11VerdevWGjVqlCoqKhyaGAAAhBIBGIaKiopUUFCgzZs3a+3ataqpqdHQoUNVXV0d2Gfq1KlavXq1li1bpqKiIh06dEgjR450cGoAABAqLmOMcXoINK2jR48qKSlJRUVFGjhwoKqqqpSYmKjFixfrjjvukCTt2rVL1157rYqLi3XDDTd852P6fD55PB4NVp6auaKa+hAAAI3srKnRBq1SVVWVYmNjnR4HIcYVQAtUVVVJkuLj4yVJ27ZtU01NjbKzswP7dO3aVenp6SouLm7wMfx+v3w+X9ACAACuTARgmKutrdWjjz6q/v37q3v37pKk8vJyRUdHKy4uLmjf5ORklZeXN/g4hYWF8ng8gaVt27ZNPToAAGgiBGCYKygo0I4dO7RkyZLLepzp06erqqoqsBw4cKCRJgQAAKHWzOkB0HSmTJmiNWvWaOPGjUpLSwus93q9OnPmjCorK4OuAlZUVMjr9Tb4WG63W263u6lHBgAAIcAVwDBkjNGUKVO0YsUKrV+/XhkZGUHb+/Tpo6ioKK1bty6wrrS0VPv371dWVlaoxwUAACHGFcAwVFBQoMWLF2vVqlWKiYkJfK7P4/GoRYsW8ng8ys/P17Rp0xQfH6/Y2Fg9/PDDysrKuqBvAAMAgCsbARiG5s2bJ0kaPHhw0PoFCxZowoQJkqQXX3xRERERGjVqlPx+v3JycvTaa6+FeFIAAOAEfgcQl4TfAQSAKxu/A2g3PgMIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAMQ4WFhbr++usVExOjpKQkjRgxQqWlpUH7DB48WC6XK2h58MEHHZoYAACEEgEYhoqKilRQUKDNmzdr7dq1qqmp0dChQ1VdXR2038SJE3X48OHA8vzzzzs0MQAACKVmTg+Axvfee+8F3V64cKGSkpK0bds2DRw4MLC+ZcuW8nq9oR4PAAA4jCuAFqiqqpIkxcfHB61/8803lZCQoO7du2v69Ok6derUeR/D7/fL5/MFLQAA4MrEFcAwV1tbq0cffVT9+/dX9+7dA+t/8IMfqF27dkpNTdX27dv1ox/9SKWlpXrnnXcafJzCwkLNmjUrVGMDAIAm5DLGGKeHQNOZPHmy3n33XW3atElpaWnn3W/9+vUaMmSI9uzZo44dO9bb7vf75ff7A7d9Pp/atm2rwcpTM1dUk8wOAGg6Z02NNmiVqqqqFBsb6/Q4CDGuAIaxKVOmaM2aNdq4ceO3xp8kZWZmStJ5A9DtdsvtdjfJnAAAILQIwDBkjNHDDz+sFStWaMOGDcrIyPjO+5SUlEiSUlJSmng6AADgNAIwDBUUFGjx4sVatWqVYmJiVF5eLknyeDxq0aKFysrKtHjxYt1yyy26+uqrtX37dk2dOlUDBw5Uz549HZ4eAAA0NT4DGIZcLleD6xcsWKAJEybowIEDuueee7Rjxw5VV1erbdu2uv322/XUU09d8OdAfD6fPB4PnwEEgCsUnwG0G1cAw9B3NX3btm1VVFQUomkAAMDfG34HEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYADEPz5s1Tz549FRsbq9jYWGVlZendd98NbD99+rQKCgp09dVXq3Xr1ho1apQqKiocnBgAAIQSARiG0tLSNHv2bG3btk1bt27VzTffrLy8PO3cuVOSNHXqVK1evVrLli1TUVGRDh06pJEjRzo8NQAACBWXMcY4PQSaXnx8vObMmaM77rhDiYmJWrx4se644w5J0q5du3TttdequLhYN9xwwwU9ns/nk8fj0WDlqZkrqilHBwA0gbOmRhu0SlVVVYqNjXV6HIQYVwDD3Llz57RkyRJVV1crKytL27ZtU01NjbKzswP7dO3aVenp6SouLnZwUgAAECrNnB4ATeOTTz5RVlaWTp8+rdatW2vFihW67rrrVFJSoujoaMXFxQXtn5ycrPLy8vM+nt/vl9/vD9z2+XxNNToAAGhiXAEMU126dFFJSYm2bNmiyZMna/z48frzn/98yY9XWFgoj8cTWNq2bduI0wIAgFAiAMNUdHS0OnXqpD59+qiwsFC9evXSyy+/LK/XqzNnzqiysjJo/4qKCnm93vM+3vTp01VVVRVYDhw40MRHAAAAmgoBaIna2lr5/X716dNHUVFRWrduXWBbaWmp9u/fr6ysrPPe3+12B35Wpm4BAABXJj4DGIamT5+u3Nxcpaen68SJE1q8eLE2bNig999/Xx6PR/n5+Zo2bZri4+MVGxurhx9+WFlZWRf8DWAAAHBlIwDD0JEjRzRu3DgdPnxYHo9HPXv21Pvvv6/vf//7kqQXX3xRERERGjVqlPx+v3JycvTaa685PDUAAAgVfgcQl4TfAQSAKxu/A2g3PgMIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDL8LWBckrq/IHhWNRJ/TBAArjhnVSPp//49h10IQFySEydOSJI26XcOTwIAuBwnTpyQx+NxegyEmMuQ/rgEtbW1OnTokGJiYuRyuQLrfT6f2rZtqwMHDoT1Hxe34ThtOEaJ4ww3NhxnYx2jMUYnTpxQamqqIiL4RJhtuAKISxIREaG0tLTzbo+NjQ3bf3z/lg3HacMxShxnuLHhOBvjGLnyZy+SHwAAwDIEIAAAgGUIQDQqt9utmTNnyu12Oz1Kk7LhOG04RonjDDc2HKcNx4imx5dAAAAALMMVQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAESjmTt3rtq3b6/mzZsrMzNTf/jDH5weqVE988wzcrlcQUvXrl2dHuuybdy4UcOHD1dqaqpcLpdWrlwZtN0Yo6efflopKSlq0aKFsrOztXv3bmeGvQzfdZwTJkyod36HDRvmzLCXqLCwUNdff71iYmKUlJSkESNGqLS0NGif06dPq6CgQFdffbVat26tUaNGqaKiwqGJL82FHOfgwYPrnc8HH3zQoYkvzbx589SzZ8/ADz5nZWXp3XffDWwPh3MJ5xCAaBRLly7VtGnTNHPmTH388cfq1auXcnJydOTIEadHa1TdunXT4cOHA8umTZucHumyVVdXq1evXpo7d26D259//nm98sormj9/vrZs2aJWrVopJydHp0+fDvGkl+e7jlOShg0bFnR+33rrrRBOePmKiopUUFCgzZs3a+3ataqpqdHQoUNVXV0d2Gfq1KlavXq1li1bpqKiIh06dEgjR450cOqLdyHHKUkTJ04MOp/PP/+8QxNfmrS0NM2ePVvbtm3T1q1bdfPNNysvL087d+6UFB7nEg4yQCPo16+fKSgoCNw+d+6cSU1NNYWFhQ5O1bhmzpxpevXq5fQYTUqSWbFiReB2bW2t8Xq9Zs6cOYF1lZWVxu12m7feesuBCRvHN4/TGGPGjx9v8vLyHJmnqRw5csRIMkVFRcaYr89dVFSUWbZsWWCfTz/91EgyxcXFTo152b55nMYYM2jQIPPDH/7QuaGayFVXXWV+9atfhe25ROhwBRCX7cyZM9q2bZuys7MD6yIiIpSdna3i4mIHJ2t8u3fvVmpqqjp06KC7775b+/fvd3qkJrV3716Vl5cHnVuPx6PMzMywO7eStGHDBiUlJalLly6aPHmyjh8/7vRIl6WqqkqSFB8fL0natm2bampqgs5n165dlZ6efkWfz28eZ50333xTCQkJ6t69u6ZPn65Tp045MV6jOHfunJYsWaLq6mplZWWF7blE6DRzegBc+Y4dO6Zz584pOTk5aH1ycrJ27drl0FSNLzMzUwsXLlSXLl10+PBhzZo1SzfeeKN27NihmJgYp8drEuXl5ZLU4Lmt2xYuhg0bppEjRyojI0NlZWV68sknlZubq+LiYkVGRjo93kWrra3Vo48+qv79+6t79+6Svj6f0dHRiouLC9r3Sj6fDR2nJP3gBz9Qu3btlJqaqu3bt+tHP/qRSktL9c477zg47cX75JNPlJWVpdOnT6t169ZasWKFrrvuOpWUlITduURoEYDABcrNzQ38d8+ePZWZmal27drp7bffVn5+voOToTGMGTMm8N89evRQz5491bFjR23YsEFDhgxxcLJLU1BQoB07doTF51S/zfmOc9KkSYH/7tGjh1JSUjRkyBCVlZWpY8eOoR7zknXp0kUlJSWqqqrS8uXLNX78eBUVFTk9FsIAbwHjsiUkJCgyMrLet88qKirk9XodmqrpxcXF6ZprrtGePXucHqXJ1J0/286tJHXo0EEJCQlX5PmdMmWK1qxZo48++khpaWmB9V6vV2fOnFFlZWXQ/lfq+TzfcTYkMzNTkq648xkdHa1OnTqpT58+KiwsVK9evfTyyy+H3blE6BGAuGzR0dHq06eP1q1bF1hXW1urdevWKSsry8HJmtbJkydVVlamlJQUp0dpMhkZGfJ6vUHn1ufzacuWLWF9biXp888/1/Hjx6+o82uM0ZQpU7RixQqtX79eGRkZQdv79OmjqKiooPNZWlqq/fv3X1Hn87uOsyElJSWSdEWdz4bU1tbK7/eHzbmEc3gLGI1i2rRpGj9+vPr27at+/frppZdeUnV1te677z6nR2s0jz32mIYPH6527drp0KFDmjlzpiIjIzV27FinR7ssJ0+eDLoqsnfvXpWUlCg+Pl7p6el69NFH9eyzz6pz587KyMjQjBkzlJqaqhEjRjg39CX4tuOMj4/XrFmzNGrUKHm9XpWVlemJJ55Qp06dlJOT4+DUF6egoECLFy/WqlWrFBMTE/gsmMfjUYsWLeTxeJSfn69p06YpPj5esbGxevjhh5WVlaUbbrjB4ekv3HcdZ1lZmRYvXqxbbrlFV199tbZv366pU6dq4MCB6tmzp8PTX7jp06crNzdX6enpOnHihBYvXqwNGzbo/fffD5tzCQc5/TVkhI9XX33VpKenm+joaNOvXz+zefNmp0dqVKNHjzYpKSkmOjratGnTxowePdrs2bPH6bEu20cffWQk1VvGjx9vjPn6p2BmzJhhkpOTjdvtNkOGDDGlpaXODn0Jvu04T506ZYYOHWoSExNNVFSUadeunZk4caIpLy93euyL0tDxSTILFiwI7PPVV1+Zhx56yFx11VWmZcuW5vbbbzeHDx92buhL8F3HuX//fjNw4EATHx9v3G636dSpk3n88cdNVVWVs4NfpPvvv9+0a9fOREdHm8TERDNkyBDzwQcfBLaHw7mEc1zGGBPK4AQAAICz+AwgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYJn/B5FcfsDI5Q4VAAAAAElFTkSuQmCC", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 9, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "%autoreload\n", "size = 32\n", @@ -428,46 +984,10 @@ }, { "cell_type": "code", - "execution_count": 10, + "execution_count": null, "id": "cc589032", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 10, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "b8eec9ed893e46d09beab7a1d67bad11", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAetUlEQVR4nO3df2xV933w8Y/5YZcU+1Lzw8bDMCe00JRAJRocKy2jxQMcKYJApCTtNJKhVM1MNLC6VFRNUrRKrhKpTVtR8se0ZJNK0mUqQYmWZBkpRtEMU5gsmm6xAmKCCOy0SNjgDEPwef6oep/HCzQJ2Pc89vf1ko7qe87x1eerU5G3zv3hsizLsgAAIBkT8h4AAIDSEoAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAImZlPcAjE1DQ0Nx8uTJqKysjLKysrzHAeBjyrIszp49G3V1dTFhgvtBqRGAXJWTJ09GfX193mMAcI1OnDgRc+bMyXsMSkwAJm7Hjh3x+OOPR09PTyxZsiR+8pOfxLJlyz709yorKyMi4otxW0yKyaM9JgAj7P24GK/HPxf/PSctAjBhP//5z6OtrS2efPLJaGxsjCeeeCJWr14d3d3dMWvWrD/4u79/2XdSTI5JZQIQYMzJfvc/3saTJi/6J+wHP/hB3H///XHffffFjTfeGE8++WRcd9118Xd/93d5jwYAjCIBmKgLFy7EoUOHorm5ubhvwoQJ0dzcHJ2dnR84f3BwMPr7+4dtAMDYJAAT9dvf/jYuXboUNTU1w/bX1NRET0/PB85vb2+PQqFQ3HwABADGLgHIR7Jt27bo6+srbidOnMh7JADgKvkQSKJmzJgREydOjN7e3mH7e3t7o7a29gPnV1RUREVFRanGAwBGkTuAiSovL4+lS5fG3r17i/uGhoZi79690dTUlONkAMBocwcwYW1tbbFx48b4whe+EMuWLYsnnngiBgYG4r777st7NABgFAnAhN11113xm9/8Jh555JHo6emJz3/+8/Hyyy9/4IMhAMD4UpZlWZb3EIw9/f39USgUYkWs9UXQAGPQ+9nF2Bd7oq+vL6qqqvIehxLzHkAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAjARH33u9+NsrKyYdvChQvzHgsAKIFJeQ9Afj73uc/Fv/7rvxYfT5rk/w4AkAL/xU/YpEmTora2Nu8xAIAS8xJwwt5+++2oq6uL66+/Pr72ta/F8ePHr3ju4OBg9Pf3D9sAgLFJACaqsbExnn766Xj55Zdj586dcezYsfjSl74UZ8+evez57e3tUSgUilt9fX2JJwYARkpZlmVZ3kOQvzNnzsS8efPiBz/4QWzatOkDxwcHB2NwcLD4uL+/P+rr62NFrI1JZZNLOSoAI+D97GLsiz3R19cXVVVVeY9DiXkPIBERMW3atPjMZz4TR44cuezxioqKqKioKPFUAMBo8BIwERFx7ty5OHr0aMyePTvvUQCAUSYAE/XNb34zOjo64r//+7/j3/7t3+KOO+6IiRMnxj333JP3aADAKPMScKLeeeeduOeee+L06dMxc+bM+OIXvxgHDhyImTNn5j0aADDKBGCinn322bxHAABy4iVgAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhAAIDECEAAgMQIQACAxAhA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ifLy8pg2bdqwc2tqaqKnp+eyz9Pe3h6FQqG41dfXj/boAMAoEYDjXGtra7z55pvx7LPPXtPzbNu2Lfr6+orbiRMnRmhCAKDUJuU9AKNn8+bN8eKLL8b+/ftjzpw5xf21tbVx4cKFOHPmzLC7gL29vVFbW3vZ56qoqIiKiorRHhkAKAF3AMehLMti8+bNsXv37njttdeioaFh2PGlS5fG5MmTY+/evcV93d3dcfz48Whqair1uABAibkDOA61trbGrl27Ys+ePVFZWVl8X1+hUIgpU6ZEoVCITZs2RVtbW1RXV0dVVVU8+OCD0dTU9JE+AQwAjG0CcBzauXNnRESsWLFi2P6nnnoq7r333oiI+OEPfxgTJkyIDRs2xODgYKxevTp++tOflnhSACAPvgeQq+J7AAHGNt8DmDbvAQQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAch9rb2+Pmm2+OysrKmDVrVqxbty66u7uHnbNixYooKysbtn3jG9/IaWIAoJQE4DjU0dERra2tceDAgXj11Vfj4sWLsWrVqhgYGBh23v333x+nTp0qbo899lhOEwMApTQp7wEYeS+//PKwx08//XTMmjUrDh06FMuXLy/uv+6666K2trbU4wEAOXMHMAF9fX0REVFdXT1s/89+9rOYMWNGLFq0KLZt2xbvvffeFZ9jcHAw+vv7h20AwNjkDuA4NzQ0FFu2bIlbb701Fi1aVNz/1a9+NebNmxd1dXVx+PDh+Na3vhXd3d3xi1/84rLP097eHtu3by/V2ADAKCrLsizLewhGzwMPPBAvvfRSvP766zFnzpwrnvfaa6/FypUr48iRI3HDDTd84Pjg4GAMDg4WH/f390d9fX2siLUxqWzyqMwOwOh5P7sY+2JP9PX1RVVVVd7jUGLuAI5jmzdv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OHjw4Li+thER77zzTpw+fXpMXd8sy2Lz5s2xe/fueO2116KhoWHY8aVLl8bkyZOHXc/u7u44fvz4mLqeH7bOy+nq6oqIGFPX83KGhoZicHBw3FxL8uMlYEZEW1tbbNy4Mb7whS/EsmXL4oknnoiBgYG477778h5txHzzm9+M22+/PebNmxcnT56MRx99NCZOnBj33HNP3qNdk3Pnzg27K3Ls2LHo6uqK6urqmDt3bmzZsiW+973vxac//eloaGiIhx9+OOrq6mLdunX5DX0V/tA6q6urY/v27bFhw4aora2No0ePxkMPPRTz58+P1atX5zj1x9Pa2hq7du2KPXv2RGVlZfG9YIVCIaZMmRKFQiE2bdoUbW1tUV1dHVVVVfHggw9GU1NT3HLLLTlP/9F92DqPHj0au3btittuuy2mT58ehw8fjq1bt8by5ctj8eLFOU//0W3bti1aWlpi7ty5cfbs2di1a1fs27cvXnnllXFzLclR3h9DZvz4yU9+ks2dOzcrLy/Pli1blh04cCDvkUbUXXfdlc2ePTsrLy/P/uiP/ii76667siNHjuQ91jX75S9/mUXEB7aNGzdmWfa7r4J5+OGHs5qamqyioiJbuXJl1t3dne/QV+EPrfO9997LVq1alc2cOTObPHlyNm/evOz+++/Penp68h77Y7nc+iIie+qpp4rn/M///E/2l3/5l9mnPvWp7LrrrsvuuOOO7NSpU/kNfRU+bJ3Hjx/Pli9fnlVXV2cVFRXZ/Pnzs7/+67/O+vr68h38Y/qLv/iLbN68eVl5eXk2c+bMbOXKldm//Mu/FI+Ph2tJfsqyLMtKGZwAAOTLewABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABLzfwBt9U01C+igRQAAAABJRU5ErkJggg==", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "fig, axes = plt.subplots()\n", "axes.imshow(sim[size//2, size//2])" @@ -475,46 +995,10 @@ }, { "cell_type": "code", - "execution_count": 11, + "execution_count": null, "id": "845d2423", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 11, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "a1de5a267c744b67adbc7ecd725ca4bc", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAex0lEQVR4nO3df2xV933w8Y/5YZcU+1Lzw8bDMBJaaEqgEg3ESstoYYAjRRCIlKSdRjKUqpmJBqhL5apJilbJVSK1aStK/piWbFJJukwlKNGSLCO1UTTDFCaLplusYDFBBHZaJGxwhnHwef6oep/HCzQJ2Pc89vf1ko7KPef46vPVqchb5x5fyrIsywIAgGRMyHsAAABKSwACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRGAAIAJEYAAgAkRgACACRmUt4DMDYNDQ3FqVOnorKyMsrKyvIeB4CPKcuyOHfuXNTV1cWECe4HpUYAclVOnToV9fX1eY8BwDU6efJkzJkzJ+8xKDEBmLjdu3fH448/Ht3d3bF06dL4yU9+EsuXL//Qn6usrIyIiC/GbTEpJo/2mACMsPdjMF6Pfy7+fU5aBGDCfv7zn8fOnTvjySefjBUrVsQTTzwR69ati87Ozpg1a9Yf/Nnff+w7KSbHpDIBCDDmZL/7H4/xpMmH/gn7wQ9+EPfff3/cd999ceONN8aTTz4Z1113Xfzd3/1d3qMBAKNIACbq4sWLceTIkVizZk1x34QJE2LNmjXR3t7+gfMHBgair69v2AYAjE0CMFG//e1v49KlS1FTUzNsf01NTXR3d3/g/JaWligUCsXNL4AAwNglAPlImpubo7e3t7idPHky75EAgKvkl0ASNWPGjJg4cWL09PQM29/T0xO1tbUfOL+ioiIqKipKNR4AMIrcAUxUeXl5LFu2LA4cOFDcNzQ0FAcOHIiGhoYcJwMARps7gAnbuXNnbNmyJb7whS/E8uXL44knnoj+/v6477778h4NABhFAjBhd911V/zmN7+JRx55JLq7u+Pzn/98vPzyyx/4xRAAYHwpy7Isy3sIxp6+vr4oFAqxKjb4ImiAMej9bDBaY3/09vZGVVVV3uNQYp4BBABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAEzUd7/73SgrKxu2LVq0KO+xAIASmJT3AOTnc5/7XPzrv/5r8fWkSf7vAAAp8F/8hE2aNClqa2vzHgMAKDEfASfs7bffjrq6urj++uvja1/7Wpw4ceKK5w4MDERfX9+wDQAYmwRgolasWBFPP/10vPzyy7Fnz544fvx4fOlLX4pz585d9vyWlpYoFArFrb6+vsQTAwAjpSzLsizvIcjf2bNnY968efGDH/wgtm7d+oHjAwMDMTAwUHzd19cX9fX1sSo2xKSyyaUcFYAR8H42GK2xP3p7e6OqqirvcSgxzwASERHTpk2Lz3zmM3Hs2LHLHq+oqIiKiooSTwUAjAYfARMREefPn4+urq6YPXt23qMAAKNMACbqm9/8ZrS1tcV///d/x7/927/FHXfcERMnTox77rkn79EAgFHmI+BEvfPOO3HPPffEmTNnYubMmfHFL34xDh06FDNnzsx7NABglAnARD377LN5jwAA5MRHwAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGAAACJEYAAAIkRgAAAiRGA49DBgwfj9ttvj7q6uigrK4vnn39+2PEsy+KRRx6J2bNnx5QpU2LNmjXx9ttv5zMsAFByAnAc6u/vj6VLl8bu3bsve/yxxx6LH//4x/Hkk0/G4cOH45Of/GSsW7cuLly4UOJJAYA8TMp7AEZeY2NjNDY2XvZYlmXxxBNPxHe+853YsGFDRET8wz/8Q9TU1MTzzz8fd999dylHBQBy4A5gYo4fPx7d3d2xZs2a4r5CoRArVqyI9vb2HCcDAErFHcDEdHd3R0RETU3NsP01NTXFY5czMDAQAwMDxdd9fX2jMyAAMOrcAeQjaWlpiUKhUNzq6+vzHgkAuEoCMDG1tbUREdHT0zNsf09PT/HY5TQ3N0dvb29xO3ny5KjOCQCMHgGYmPnz50dtbW0cOHCguK+vry8OHz4cDQ0NV/y5ioqKqKqqGrYBAGOTZwDHofPnz8exY8eKr48fPx4dHR1RXV0dc+fOje3bt8f3vve9+PSnPx3z58+Phx9+OOrq6mLjxo35DQ0AlIwAHIfeeOON+PKXv1x8vXPnzoiI2LJlSzz99NPx0EMPRX9/f3z961+Ps2fPxhe/+MV4+eWX4xOf+EReIwMAJVSWZVmW9xCMPX19fVEoFGJVbIhJZZPzHgeAj+n9bDBaY3/09vZ6rCdBngEEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIzKS8BwAolVdOdXys89fVfX5U5gDImzuAAACJEYDj0MGDB+P222+Purq6KCsri+eff37Y8XvvvTfKysqGbevXr89nWACg5ATgONTf3x9Lly6N3bt3X/Gc9evXx+nTp4vbM888U8IJAYA8eQZwHGpsbIzGxsY/eE5FRUXU1taWaCIA4P8n7gAmqrW1NWbNmhULFy6MBx54IM6cOZP3SABAibgDmKD169fHpk2bYv78+dHV1RXf/va3o7GxMdrb22PixImX/ZmBgYEYGBgovu7r6yvVuADACBOACbr77ruLf77ppptiyZIlccMNN0Rra2usXr36sj/T0tISu3btKtWIAMAo8hEwcf3118eMGTPi2LFjVzynubk5ent7i9vJkydLOCEAMJLcASTeeeedOHPmTMyePfuK51RUVERFRUUJpwIARosAHIfOnz8/7G7e8ePHo6OjI6qrq6O6ujp27doVmzdvjtra2ujq6oqHHnooFixYEOvWrctxagCgVATgOPTGG2/El7/85eLrnTt3RkTEli1bYs+ePXH06NH4+7//+zh79mzU1dXF2rVr42/+5m/c4QOARJRlWZblPQRjT19fXxQKhVgVG2JS2eS8xwHgY3o/G4zW2B+9vb1RVVWV9ziUmF8CAQBIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAByHWlpa4uabb47KysqYNWtWbNy4MTo7O4edc+HChWhqaorp06fH1KlTY/PmzdHT05PTxABAKQnAcaitrS2ampri0KFD8eqrr8bg4GCsXbs2+vv7i+fs2LEjXnjhhXjuueeira0tTp06FZs2bcpxagCgVMqyLMvyHoLR9Zvf/CZmzZoVbW1tsXLlyujt7Y2ZM2fG3r17484774yIiLfeeis++9nPRnt7e9xyyy0f+p59fX1RKBRiVWyISWWTR3sJAIyw97PBaI390dvbG1VVVXmPQ4m5A5iA3t7eiIiorq6OiIgjR47E4OBgrFmzpnjOokWLYu7cudHe3n7Z9xgYGIi+vr5hGwAwNgnAcW5oaCi2b98et956ayxevDgiIrq7u6O8vDymTZs27Nyampro7u6+7Pu0tLREoVAobvX19aM9OgAwSgTgONfU1BRvvvlmPPvss9f0Ps3NzdHb21vcTp48OUITAgClNinvARg927ZtixdffDEOHjwYc+bMKe6vra2NixcvxtmzZ4fdBezp6Yna2trLvldFRUVUVFSM9sgAQAm4AzgOZVkW27Zti3379sVrr70W8+fPH3Z82bJlMXny5Dhw4EBxX2dnZ5w4cSIaGhpKPS4AUGLuAI5DTU1NsXfv3ti/f39UVlYWn+srFAoxZcqUKBQKsXXr1ti5c2dUV1dHVVVVPPjgg9HQ0PCRfgMYABjbBOA4tGfPnoiIWLVq1bD9Tz31VNx7770REfHDH/4wJkyYEJs3b46BgYFYt25d/PSnPy3xpABAHnwPIFfF9wACjG2+BzBtngEEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwAHIdaWlri5ptvjsrKypg1a1Zs3LgxOjs7h52zatWqKCsrG7Z94xvfyGliAKCUBOA41NbWFk1NTXHo0KF49dVXY3BwMNauXRv9/f3Dzrv//vvj9OnTxe2xxx7LaWIAoJQm5T0AI+/ll18e9vrpp5+OWbNmxZEjR2LlypXF/dddd13U1taWejwAIGfuACagt7c3IiKqq6uH7f/Zz34WM2bMiMWLF0dzc3O89957V3yPgYGB6OvrG7YBAGOTO4Dj3NDQUGzfvj1uvfXWWLx4cXH/V7/61Zg3b17U1dXF0aNH41vf+lZ0dnbGL37xi8u+T0tLS+zatatUYwMAo6gsy7Is7yEYPQ888EC89NJL8frrr8ecOXOueN5rr70Wq1evjmPHjsUNN9zwgeMDAwMxMDBQfN3X1xf19fWxKjbEpLLJozI7AKPn/WwwWmN/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jhw5Em+88UZ85StfiQ0bNsSvf/3riBgf15IcZTACli9fnjU1NRVfX7p0Kaurq8taWlpynGpkPfroo9nSpUvzHmNURUS2b9++4uuhoaGstrY2e/zxx4v7zp49m1VUVGTPPPNMDhOOjP+9zizLsi1btmQbNmzIZZ7R8u6772YRkbW1tWVZ9rtrN3ny5Oy5554rnvNf//VfWURk7e3teY15zf73OrMsy/7kT/4k+6u/+qv8hholn/rUp7K//du/HbfXktJxB5BrdvHixThy5EisWbOmuG/ChAmxZs2aaG9vz3Gykff2229HXV1dXH/99fG1r30tTpw4kfdIo+r48ePR3d097NoWCoVYsWLFuLu2ERGtra0xa9asWLhwYTzwwANx5syZvEe6Jr29vRERUV1dHRERR44cicHBwWHXc9GiRTF37twxfT3/9zp/72c/+1nMmDEjFi9eHM3NzfHee+/lMd6IuHTpUjz77LPR398fDQ0N4/ZaUjqT8h6Ase+3v/1tXLp0KWpqaobtr6mpibfeeiunqUbeihUr4umnn46FCxfG6dOnY9euXfGlL30p3nzzzaisrMx7vFHR3d0dEXHZa/v7Y+PF+vXrY9OmTTF//vzo6uqKb3/729HY2Bjt7e0xceLEvMf72IaGhmL79u1x6623xuLFiyPid9ezvLw8pk2bNuzcsXw9L7fOiIivfvWrMW/evKirq4ujR4/Gt771rejs7Ixf/OIXOU778f3qV7+KhoaGuHDhQkydOjX27dsXN954Y3R0dIy7a0lpCUD4iBobG4t/XrJkSaxYsSLmzZsX//iP/xhbt27NcTJGwt13313880033RRLliyJG264IVpbW2P16tU5TnZ1mpqa4s033xwXz6n+IVda59e//vXin2+66aaYPXt2rF69Orq6uuKGG24o9ZhXbeHChdHR0RG9vb3xT//0T7Fly5Zoa2vLeyzGAR8Bc81mzJgREydO/MBvn/X09ERtbW1OU42+adOmxWc+85k4duxY3qOMmt9fv9SubUTE9ddfHzNmzBiT13fbtm3x4osvxi9/+cuYM2dOcX9tbW1cvHgxzp49O+z8sXo9r7TOy1mxYkVExJi7nuXl5bFgwYJYtmxZtLS0xNKlS+NHP/rRuLuWlJ4A5JqVl5fHsmXL4sCBA8V9Q0NDceDAgWhoaMhxstF1/vz56OrqitmzZ+c9yqiZP39+1NbWDru2fX19cfjw4XF9bSMi3nnnnThz5syYur5ZlsW2bdti37598dprr8X8+fOHHV+2bFlMnjx52PXs7OyMEydOjKnr+WHrvJyOjo6IiDF1PS9naGgoBgYGxs21JD8+AmZE7Ny5M7Zs2RJf+MIXYvny5fHEE09Ef39/3HfffXmPNmK++c1vxu233x7z5s2LU6dOxaOPPhoTJ06Me+65J+/Rrsn58+eH3RU5fvx4dHR0RHV1dcydOze2b98e3/ve9+LTn/50zJ8/Px5++OGoq6uLjRs35jf0VfhD66yuro5du3bF5s2bo7a2Nrq6uuKhhx6KBQsWxLp163Kc+uNpamqKvXv3xv79+6OysrL4LFihUIgpU6ZEoVCIrVu3xs6dO6O6ujqqqqriwQcfjIaGhrjllltynv6j+7B1dnV1xd69e+O2226L6dOnx9GjR2PHjh2xcuXKWLJkSc7Tf3TNzc3R2NgYc+fOjXPnzsXevXujtbU1XnnllXFzLclR3r+GzPjxk5/8JJs7d25WXl6eLV++PDt06FDeI42ou+66K5s9e3ZWXl6e/dEf/VF21113ZceOHct7rGv2y1/+MouID2xbtmzJsux3XwXz8MMPZzU1NVlFRUW2evXqrLOzM9+hr8IfWud7772XrV27Nps5c2Y2efLkbN68edn999+fdXd35z32x3K59UVE9tRTTxXP+Z//+Z/sL//yL7NPfepT2XXXXZfdcccd2enTp/Mb+ip82DpPnDiRrVy5Mquurs4qKiqyBQsWZH/913+d9fb25jv4x/QXf/EX2bx587Ly8vJs5syZ2erVq7N/+Zd/KR4fD9eS/JRlWZaVMjgBAMiXZwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABIjAAEAEiMAAQASIwABABLzfwBLhlW1NsH4gQAAAABJRU5ErkJggg==", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "fig, axes = plt.subplots()\n", "axes.imshow(sim[:, :, size//2 + 1, size//2 + 1])" @@ -522,7 +1006,7 @@ }, { "cell_type": "code", - "execution_count": 12, + "execution_count": null, "id": "c2f86c2f", "metadata": {}, "outputs": [], @@ -568,25 +1052,10 @@ }, { "cell_type": "code", - "execution_count": 13, + "execution_count": null, "id": "1aa7bd4b", "metadata": {}, - "outputs": [ - { - "data": { - "text/plain": [ - "array([[ 1.00010000e+00, 2.35830457e-16],\n", - " [ 1.55431223e-15, 1.00010000e+00],\n", - " [-1.00010000e+00, -1.58206781e-15],\n", - " [-8.65092273e-16, -1.00010000e+00],\n", - " [ 1.60000000e+01, 1.60000000e+01]])" - ] - }, - "execution_count": 13, - "metadata": {}, - "output_type": "execute_result" - } - ], + "outputs": [], "source": [ "params = OverfocusParams(\n", " overfocus=0.0001,\n", @@ -605,7 +1074,7 @@ }, { "cell_type": "code", - "execution_count": 14, + "execution_count": null, "id": "f7857d5e", "metadata": {}, "outputs": [], @@ -628,211 +1097,10 @@ }, { "cell_type": "code", - "execution_count": 15, + "execution_count": null, "id": "f89fa72d", "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "f2f098809dc947b491585e45fbd21010", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "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eeDAAd166606ePCgWrdurZCQwH0Hbdq0kfT3n0tlEhISAu6XfZzhxIkTioqKuuT5AVQPAQhcwTp37uzfc5WamqoePXropz/9qXbv3q369eurtLRUkvRv//Zv6tu3b4XP8U//9E8XfH6Px6OmTZtq+/btlc6xfft2NWvWzP8faLfbrdTUVOXk5OjVV1/V0aNH9bvf/U7Tp0/3P+ZSZouIiKh0jppyoRgrKSkpt93SpUu1adMmrVy5Uh988IFGjx6t559/Xps2bVL9+vX9Z79+//33FT5n2QkP1TlLtuykmsp+lrXFhfbwGmOCPAlgNwIQqCVCQ0OVlZWlXr166ZVXXtHkyZP9l2WpU6fOJe8JuvPOO7VgwQJt2LBBPXr0KLf+008/1YEDBwIOD0p/PQycnZ2tNWvWaOfOnTLG+A//Sross11I2RnNu3fvLrdu165daty4sSIjIxUREaGoqKiAs5IrUrYX6uTJkwGXm7nQHq1bb71Vt956q6ZNm6ZFixZpyJAhevfdd/Xggw+qSZMmqlevXoWzlc1cr149NW7cuCrfqkpKSrRo0SLVq1evwp/P5XL48GH/pXfK7NmzR5L8J9S0aNFC27dvV2lpacBewF27dvnXXw7VPTQPoPr4DCBQiyQnJ6tz586aPXu2zp49q5iYGCUnJ2vevHn65ptvym1fdu2/ykycOFERERF6+OGH9e233was++677/TII4+oXr16mjhxYsC6lJQURUdHa/HixVq8eLE6d+4ccAj3csx2IU2bNlXHjh2VnZ2tkydP+pfv2LFDH374oe644w5JUkhIiFJTU7Vy5Upt3bq13POU7XUqO8t0/fr1/nVllyL5oRMnTpTbU9WxY0dJUnFxsaS/hnqfPn20cuVKff311wHbfv3111q5cqX69OlTpc86lpSUKCMjQzt37lRGRka1DpFW5zIwkvSXv/xF8+bN898/d+6c5s2bpyZNmujmm2+WJN1xxx06cuSIFi9eHPC4l19+WfXr1y93VvilioyMDPi5Arj82AMI1DITJ07UoEGDtHDhQj3yyCOaM2eOevToofbt2+uhhx5Sy5YtdfToUW3cuFF//vOf9fnnn1f6fK1bt1Z2draGDBmi9u3bl/tLIMePH9c777xT7lIcderU0b333qt3331XRUVFFf7ps390tsrMnDlT/fr1U9euXfXAAw/4LwPj8XgCTnyYPn26PvzwQ/Xs2VNjxoxRmzZt9M033+i9997Thg0b1LBhQ/Xp00cJCQl64IEHNHHiRIWGhur1119XkyZNAiIuOztbr776qu655x61atVKp06d0oIFCxQVFeWPzrKveeutt+onP/mJxowZo8TERB04cEDz58+Xy+UKOFReprCwUG+99Zakv8Zb2V8C+eqrr3T//ffrqaeeqtbrU93LwHi9Xs2YMUMHDhzQtddeq8WLFysvL0/z58/3/wWSMWPGaN68eRo5cqS2bdumxMRELV26VL/73e80e/bsi55MVFU333yzPvroI82aNUter1dJSUnq0qXLZXluAH/j4BnIAC6g7PIjFV1upKSkxLRq1cq0atXKf8mUr776ygwfPtzExcWZOnXqmGbNmpk777zTLF261P+4i12eZPv27SYtLc00bdrU1KlTx8TFxZm0tDTzxRdfXHDO1atXG0nG5XIFXJrmh6oyW2Xf74UuA2OMMR999JHp3r27iYiIMFFRUWbAgAHmj3/8Y7ntDh48aIYPH+6/jE7Lli1Nenq6KS4u9m+zbds206VLFxMeHm4SEhLMrFmzyl0GJjc316SlpZmEhATjdrtNTEyMufPOO83WrVvLfc2dO3ea++67z8TExJiwsDATExNj7r//frNz585y25ZdhqXsVr9+fdO6dWszdOhQ8+GHH1b4urZo0cL079+/wnU/fN2qehmYtm3bmq1bt5quXbuaunXrmhYtWphXXnml3LZHjx41o0aNMo0bNzbh4eGmffv25o033ii33Y+/dtllYI4dOxaw3Y9fY2OM2bVrl7n99ttNRESEkcQlYYAa4DKGT94CgM2Sk5N1/Pjxi35WEsDVg88AAgAAWIYABAAAsAwBCAAAYBk+AwgAAGAZ9gACAABYhgAEAACwDAEIAABgGf4SCC5JaWmpDh8+rAYNGvB3OwGgFjLG6NSpU/J6vQF/2xl2IABxSQ4fPqz4+HinxwAA/IPy8/PVvHlzp8dAkBGAuCRlf/MzPz+/Wn+gHgBwZfD5fIqPj79sf8MZtQsBiEtSdtg3KiqKAASAWoyP8diJg/4AAACWIQABAAAsQwACAABYhgAEAACwDAFouTlz5igxMVF169ZVly5dtHnzZqdHAgAANYwAtNjixYs1YcIETZkyRbm5uerQoYP69u2rgoICp0cDAAA1iAC02KxZ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", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "e4c38a70e2374d30b6008c667a63e90e", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "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qlevniZOnKiffvpJ06dPV5s2bZSenu4tuEeOHFHLli114sQJ3X///WrQoIEOHz6sJUuW6PTp02WalcrMzFSnTp1Uo0YNjR07VlWqVNGBAwe0dOnSUj9GWQUGBqpPnz5KTU3Vpk2b1LlzZ++6c+fOFSp4lSpVUqVKlbRlyxZ16NBBEyZMKLK0FDh79qySkpKUm5urhx9+WFFRUTp8+LBWrlypEydOyOPxeLfdtGmTli5dqgcffFBhYWF66aWX1KNHDx06dEjVqlUr8vFfe+01zZkzR1u2bNGf//xnSVL9+vX1xBNPaPz48br//vu9773WrVtL+rnYJycn68Ybb9SECRMUEBCgefPm6d///d/1wQcfqGXLlpKkzz77zPvzmDhxos6fP68JEyZ43yNl0aNHD33++ed6+OGHFRcXp8zMTK1evVqHDh3yvpfKqmB/Pv7449q8ebPmzJmjKlWq6MMPP1RsbKwmT56sv/3tb5o6daoaN26sAQMGXNTzAFcMA6BE8+bNM5LM+++/b7777juTkZFhlixZYmrUqGHcbrfJyMjwbtuxY0fTpEkTc+bMGe9Yfn6+ad26talfv753bP/+/UaSmTp1qnfsxIkTRpLp1q1biXluv/12I8lkZ2cbY4zp06ePiYyMNOfPn/du8+2335qAgADzxBNPlDlbwett27atz2MaY8y6deuMJPPXv/7VZ7xZs2YmMjLSfP/9996xnTt3moCAADNgwADv2IABA0xAQIDZunVrodeVn59vjDFmwoQJpqh/mgpy7d+/3xhjzLJly4ykIh+rQFH7+ZemTp3q85jGGNOuXTvTqFGjYh+z4HlffPFF71jdunWNpELLhAkTjDH/v98Kbhfnk08+KXL//pokU7FiRbNv3z7v2M6dO40kM336dO/Yr/eZMcYMHDjQhIaG+jze1q1bjSQzb948n/H8/HxTv359k5SU5P35GGPM6dOnTXx8vLntttu8Y927dzfBwcHm4MGD3rEvvvjCBAYGFvnzLM6PP/5Y4s+sQHH7s27dumbgwIHe2wX74Nev4eabbzYul8sMGzbMO3b+/HlTp04d065du1LnBa5UHAIGSikxMVE1atRQTEyM7rrrLoWGhuqdd95RnTp1JEk//PCD1q5dq169eunkyZM6fvy4jh8/ru+//15JSUnau3dvid8aPnnypCQpLCysxBwF67OzsyVJd999tzIzM7V+/XrvNkuWLFF+fr7uvvvui8523333FTp/rCjffvutduzYoUGDBikiIsI7fv311+u2227T3/72N0lSfn6+li9frq5du/p847lAWS8VUnAe4sqVK3Xu3Lky3fe3KJitLfh5FWjVqpVWr17tsxTMIrVv317GmBJn/yR5Z/hWrVql06dPl7htYmKiEhISvLevv/56hYeH65tvvinrSyrWjh07tHfvXt1zzz36/vvvve+bnJwcdezYURs3blR+fr7y8vK0atUqde/eXbGxsd77X3fddUpKSirTcxacn7h+/Xr9+OOPl+y1DB061Oc91qpVKxljNHToUO9YYGCgmjdvfkn3IXC54hAwUEozZszQNddco6ysLL366qvauHGjz7cr9+3bJ2OMUlNTlZqaWuRjZGZmqnbt2kWuKyh2vy4Wv/brolhwbtbixYvVsWNHST8f/m3WrJmuueaai84WHx9fYo4CBw8elCRde+21hdZdd911WrVqlXJycnTq1CllZ2d7D0n/Vu3atVOPHj30+OOP64UXXlD79u3VvXt33XPPPT4/l9IoS/k8deqUpMJFvXr16kpMTCzT8/5afHy8Ro4cqeeff15vvPGGbrnlFt1+++3q16+fz+FfST5Fq0DVqlUvaWnau3evpJ8vWVScrKws5ebm6qefflL9+vULrb/22mu9/wkoDbfbrSlTpmjUqFGqWbOmbrrpJnXp0kUDBgxQVFRU2V/Ev/x6fxXsz5iYmELjl3IfApcrCiBQSi1btvTOXHXv3l1t27bVPffcoz179qhy5crKz8+XJP3nf/5nsbMe//Zv/1bs43s8HtWqVUuffvppiTk+/fRT1a5dW+Hh4ZJ+/oXZvXt3LVu2TK+88oqOHTumf/zjH5o8ebL3PheTLSQkpMQc5aW4MpaXl1douyVLlmjz5s1asWKFVq1apSFDhui5557T5s2bVblyZe/leX766aciH7Nglq0sl/Ep+FJNST/L3+K5557ToEGD9Pbbb+u9997T8OHDlZaWps2bN3tnmyUVOztrLuEXGAreN1OnTi328jCVK1dWbm7uJXtOSRoxYoS6du2q5cuXa9WqVUpNTVVaWprWrl2rG264ocT7/vp9UqC4/VXU+KXch8DligIIXITAwEClpaWpQ4cOevnllzV27FjvZVkqVKhw0TNBXbp00dy5c7Vp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sGFDn7HrrrtOhw4dcihR6YwePVpjx45V79691aRJE/Xv31+PPvqo0tLSnI5WagWfxSv5c1pQ/g4ePKjVq1df9rN/H3zwgTIzMxUbG+v9rB48eFCjRo1SXFyc0/FgCQogyk3FihV14403as2aNd6x/Px8rVmzRjfffLODyS7MGKOHHnpIy5Yt09q1axUfH+90pAvq2LGjPvvsM+3YscO7NG/eXH379tWOHTsUGBjodMRitWnTptBldr766ivVrVvXoUSlc/r0aQUE+P4zGhgYqPz8fIcSlV18fLyioqJ8PqfZ2dn6+OOPL/vPqfT/5W/v3r16//33Va1aNacjXVD//v316aef+nxWo6OjNXr0aK1atcrpeLAEh4BRrkaOHKmBAweqefPmatmypaZNm6acnBwNHjzY6WglSklJ0cKFC/X2228rLCzMey6Ux+NRSEiIw+mKFhYWVugcxdDQUFWrVu2yP3fx0UcfVevWrTV58mT16tVLW7Zs0Zw5czRnzhyno5Woa9eumjRpkmJjY9WoUSN98sknev755zVkyBCno/k4deqU9u3b5729f/9+7dixQxEREYqNjdWIESP01FNPqX79+oqPj1dqaqqio6PVvXt350L/S0nZa9Wqpbvuukvp6elauXKl8vLyvJ/ViIgIVaxY0anYF9znvy6qFSpUUFRUlK699lp/R4WtnP4aMq5+06dPN7GxsaZixYqmZcuWZvPmzU5HuiBJRS7z5s1zOlqZXCmXgTHGmBUrVpjGjRsbt9ttGjRoYObMmeN0pAvKzs42jzzyiImNjTXBwcGmXr165o9//KPJzc11OpqPdevWFfl+HjhwoDHm50vBpKammpo1axq32206duxo9uzZ42zofykp+/79+4v9rK5bt+6yzV0ULgMDf3MZc5ldsh4AAADlinMAAQAALEMBBAAAsAwFEAAAwDIUQAAAAMtQAAEAACxDAQQAALAMBRAAAMAyFEAAAADLUAABAAAsQwEEAACwDAUQAADAMhRAAAAAy1AAAQAALEMBBAAAsAwFEAAAwDIUQAAAAMtQAAEAACxDAQQAALAMBRAAAMAyFEAAAADLUAABAAAsQwEEAACwDAUQAADAMhRAAAAAy1AAAQAALEMBBAAAsAwFEAAAwDIUQAAAAMtQAAEAACxDAQQAALAMBRAAAMAy/wdMeTAyUv7fDAAAAABJRU5ErkJggg==", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "7fd8763831f143a19b42ab9ec7afc212", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "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9OhiP9jw008/qUOHDsrNzdXDDz+s6OhoHTx4UEuXLtXx48fl8XgkSWPGjFFqaqp69OihwYMH67vvvtOrr76qW2+9VVu3bi32CO2QIUM0ffp0DRw4UCkpKdq3b59ee+01bd26VR9//LHv1Pb06dM1aNAgNWjQQKNGjVLFihW1detWffDBB+rdu7eeeOIJZWVl6ZtvvtGECRMkyfdz7PV61aVLF61fv17333+/rrvuOu3YsUMTJkzQF1984feBp8GDB2vmzJnq3bu3WrZsqVWrVvm9rgCKYQCUmrfeestIMitWrDDfffedyczMNPPnzzdVq1Y1brfbZGZm+vZt166dSUhIMGfOnPGt83q9pmXLlqZevXq+dfv27TOSzAsvvOBbd/z4cSPJdO3atdh5unTpYiSZ7OxsY4wxvXr1MlFRUebs2bO+fb799lsTFBRk/vrXv17wbAVfb6tWrfwe0xhjVq9ebSSZd999129948aNTVRUlPn+++9967Zv326CgoJM//79fev69+9vgoKCzKZNmwp9XV6v1xhjzOjRo01Rf9YK5tq3b58xxpiFCxcaSUU+VoGiXudfeuGFF/we0xhjWrdubRo0aHDOxyx43pdfftm3rlatWkZSoWX06NHGmP+8bgW3z2Xr1q1Fvr6/tH//fhMcHGzGjBnjt37Hjh0mJCTEb/2AAQNMrVq1fLc/+ugjI8nMmjXL774ffPCB3/rjx4+b8PBw06JFC3P69Gm/fQu+T8YY06lTJ7/HL/D222+boKAg89FHH/mtnzJlipFkPv74Y2OMMdu2bTOSzIMPPui3X+/evUv0egG24xQwEABJSUmqWrWqYmNjdddddyksLEyLFy9WzZo1JUk//PCDVq1apR49eujEiRM6duyYjh07pu+//14dOnRQRkZGsZ8aPnHihCQpPDy82DkKtmdnZ0uS7r77bh09elRr1qzx7TN//nx5vV7dfffdFz3bfffdp+Dg4PO+Lt9++622bdume+65R5GRkb71N9xwg/7whz/oH//4h6SfjwotWrRInTt39vvEc4GiTvsWp+Ao19KlS5WXl3dB9/0tCo5yFXy/CrRo0ULLly/3W/r37y/p59OlxpjzXtak4AjfsmXLdOrUqSL3WbBggbxer3r06OH7Ph47dkzR0dGqV6+eVq9efc7Hf/fdd+XxePSHP/zB775NmjRRhQoV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", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "23ffc7a615984b8fa7ae1ffdf3987127", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAsO0lEQVR4nO3de3hU9Z3H8c/kwiSEZDCEkAQSElgKChFsIyigQM3CRkDwAspyiYCiNRoRywLbBmwVAt6KF+S2W2BVBMsKCm1VRC6yFblERCxXBUxBCChkIEgMyW//aDN1TAgJkjmE3/v1POePOefM5DsDk+f9nDNz4jLGGAEAAMAaQU4PAAAAgMAiAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACltqzZ4969uwpj8cjl8ulZcuWOT1StWzatEmdO3dWRESEXC6Xtm7d6vRIAFDnEIDAJW7+/PlyuVy+JSQkRE2bNtXdd9+tgwcPXvDjZmZm6tNPP9XkyZP18ssvKy0tzbfts88+05AhQ9S0aVO53W4lJCRo8ODB+uyzzy7GU7pgJSUlGjBggL755hv97ne/08svv6zmzZs7OlNV9u/fL5fLpaeffrrS7U8//bRcLpf279/vW9e9e3ffv3VQUJCioqLUunVrDR06VCtXrqz0cZKTk/3+j3x/OXPmTG08NQB1XIjTAwCont/+9rdKSUnRmTNntGHDBs2fP1/r16/X9u3bFRYWVqPH+vbbb/Xhhx/qV7/6lR588EG/bW+88YYGDRqk6OhojRw5UikpKdq/f7/++7//W0uWLNGiRYt06623XsynVm2ff/65Dhw4oLlz5+qee+5xZIZAaNasmXJzcyVJRUVF2rt3r9544w298sorGjhwoF555RWFhob63adDhw569NFHKzxWvXr1AjIzgLqFAATqiIyMDN9RunvuuUcxMTGaNm2a3nrrLQ0cOLBGj3X06FFJUsOGDf3Wf/755xo6dKhatGihdevWqXHjxr5tDz/8sG644QYNHTpU27ZtU4sWLX7cE6qBoqIiRUREqKCgoNK5Lzcej0dDhgzxWzd16lRlZ2frpZdeUnJysqZNm+a3vWnTphXuAwDnwilgoI664YYbJP092r5v586duuOOOxQdHa2wsDClpaXprbfe8m1/7LHHfKdNx44dK5fLpeTkZEnSU089pdOnT2vOnDl+8SdJMTExmj17toqKivTkk09KkpYsWSKXy6W1a9dWmG/27NlyuVzavn17tWeT/nnKe+3atXrggQcUGxurZs2a6e6771a3bt0kSQMGDJDL5VL37t1993v//fd1ww03KCIiQg0bNlS/fv20Y8eOCnMdPHhQI0eOVEJCgtxut1JSUvSLX/xC3333ne/1cblcFe5XPtf3T9du3rxZvXr1UkxMjMLDw5WSkqIRI0ZUuO/FEBwcrOeff15XXXWVXnzxRRUWFlb7vqdPn9bOnTt17Nix8+67Z88e3X777YqLi1NYWJiaNWumu+66y/fzyk9rz58/v8J9XS6XHnvsMd/t8tdy9+7dGjJkiDwejxo3bqycnBwZY5Sfn69+/fopKipKcXFxeuaZZ6r9nAD8OBwBBOqo8hC54oorfOs+++wzdenSRU2bNtX48eMVERGh119/Xf3799f//u//6tZbb9Vtt92mhg0b6pFHHtGgQYN08803q0GDBpKk5cuXKzk52ReXP3TjjTcqOTlZf/zjHyVJvXv3VoMGDfT666/74qzc4sWL1bZtW7Vr167as33fAw88oMaNG2vixIkqKirSjTfeqKZNm2rKlCnKzs7WtddeqyZNmkiS3nvvPWVkZKhFixZ67LHH9O233+qFF15Qly5dlJeX5wvcQ4cOqWPHjjpx4oRGjRqlNm3a6ODBg1qyZIlOnz5do9OlBQUF6tmzpxo3bqzx48erYcOG2r9/v954441qP0ZNBQcHa9CgQcrJydH69evVu3dv37aSkpIKgVe/fn3Vr19fGzduVI8ePTRp0iS/QPuh7777Tr169VJxcbEeeughxcXF6eDBg1qxYoVOnDghj8dzQXPfeeeduvLKKzV16lT98Y9/1BNPPKHo6GjNnj1bP//5zzVt2jS9+uqr+uUvf6lrr71WN9544wX9HAA1YABc0ubNm2ckmffee88cPXrU5OfnmyVLlpjGjRsbt9tt8vPzffvedNNNJjU11Zw5c8a3rqyszHTu3Nm0atXKt27fvn1Gknnqqad8606cOGEkmX79+lU5zy233GIkGa/Xa4wxZtCgQSY2NtacPXvWt89XX31lgoKCzG9/+9saz1b+fLt27er3mMYYs3r1aiPJ/OEPf/Bb36FDBxMbG2u+/vpr37pPPvnEBAUFmWHDhvnWDRs2zAQFBZlNmzZVeF5lZWXGGGMmTZpkKvvVWD7Xvn37jDHGLF261Eiq9LHKVfY6f99TTz3l95jGGNOtWzfTtm3bcz5m+c997rnnfOuaN29uJFVYJk2aZIz55+tWfvtcPv7440pf38qe07x58yps++HPKH8tR40a5Vt39uxZ06xZM+NyuczUqVN9648fP27Cw8NNZmZmlTMCuDg4BQzUEenp6WrcuLESExN1xx13KCIiQm+99ZaaNWsmSfrmm2/0/vvva+DAgTp58qSOHTumY8eO6euvv1avXr20Z8+eKr81fPLkSUlSZGRklXOUb/d6vZL+fnSnoKBAa9as8e2zZMkSlZWV6c4777zg2e69914FBwef93X56quvtHXrVt19992Kjo72rb/66qv1r//6r/rTn/4kSSorK9OyZcvUt29fv288l6vstG9Vyj+HuGLFCpWUlNTovj9G+dHa8n+vcp06ddLKlSv9lmHDhkn6+zeLjTFVHv2T5DvC98477+j06dMXbebvf2EnODhYaWlpMsZo5MiRvvUNGzZU69at9cUXX1y0nwvg3AhAoI6YMWOGVq5cqSVLlujmm2/WsWPH5Ha7fdv37t0rY4xycnLUuHFjv2XSpEmS5PsSRWXKw+6HYfFDPwzFf/u3f5PH49HixYt9+yxevFgdOnTQT37ykwueLSUlpVqvy4EDByRJrVu3rrDtyiuv1LFjx1RUVKSjR4/K6/X6Tkn/WN26ddPtt9+u3/zmN4qJiVG/fv00b948FRcX1/ixahKfp06dklQx1GNiYpSenu631PSLOikpKRozZoz+67/+SzExMerVq5dmzJhRo88bViYpKcnvtsfjUVhYmGJiYiqsP378+I/6WQCqh88AAnVEx44dfUeu+vfvr65du+rf//3ftWvXLjVo0EBlZWWSpF/+8pfq1atXpY/xL//yL+d8fI/Ho/j4eG3btq3KObZt26amTZsqKipKkuR2u9W/f38tXbpU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", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "dfb85c3ea0514622a5cec9a4cf93760d", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "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Kjo6OuBdyVWpOAp1+vTpgPWXOqL1ox/9SDNnzlROTo5ef/11ffrpp1q5cqUkKTY2VvXr169ytoqZ69evryZNmlx2pgplZWVasWKF6tevrx49elTrPtfi2LFjKikpCVh38OBBSfK/oaZFixY6dOiQP+4r7N+/37/9erjaU/MAgocABOqISZMmKTIyUo8++qi+/PLLgG1fffWVHnvsMdWvX1+TJk0K2JaamqqYmBitWrVKq1atUufOnQNO4cbFxalXr15atGiRvvjii0o/9+TJk9c8c9OmTdWxY0ctW7YsINr27t2rd999V/fee68kKSQkRIMGDdL69euVk5NT6XEqjjpVvMt069at/m0VH0Xy977++utKR6o6duwoSf7TwKGhoerTp4/Wr1+vzz//PGDfzz//XOvXr1efPn2qda1jWVmZMjIytG/fPmVkZPiPwFbH1XwMjCR9++23WrRokf/2hQsXtGjRIsXGxuqOO+6QJN177706fvx4wKn/b7/9Vi+//LIaNGhQ6V3h1yoqKqpSjAO4MXAKGKgjWrVqpWXLlmno0KFq3759pW8COXXqlN54441KH8VRr149/fjHP9bKlStVUlJS5VefzZ8/Xz169FD79u31yCOPqGXLljpx4oS2b9+uv/zlL/r444+vee45c+aoX79+6tq1q8aOHev/GBiPxxPwxodZs2bp3XffVc+ePTVu3Di1adNGX3zxhd58801t27ZNjRo1Up8+fZSUlKSxY8dq0qRJCg0N1a9+9SvFxsYGRNyyZcv06quv6oEHHtDNN9+sM2fOaMmSJYqOjvZHZ8XP/NGPfqQf/vCHGjdunJKTk3XkyBEtXrxYLpcr4FR5heLiYi1fvlzSX+Ot4ptAPvvsMz388MN6+umnr+r5udqPgfF6vZo9e7aOHDmiH/zgB1q1apXy8vK0ePFi/zeQjBs3TosWLdKoUaO0e/duJScna82aNfr973+vefPmXfMR3e+644479N5772nu3Lnyer1KSUlRly5drstjA/ienHwLMoDrb8+ePSYtLc00bdrU1KtXzyQkJJi0tDTzySefXPI+GzduNJKMy+UyhYWFVe7z2WefmREjRpiEhARTr14906xZM3PfffeZNWvW+Pep+LiVqj5e5VIfA2OMMe+9957p3r27iYyMNNHR0WbAgAHmT3/6U6X9CgoKzIgRI0xsbKxx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", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "603a594e4fe34320aac65d874f6fa4c1", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAvGUlEQVR4nO3df1xUdb7H8fcAOiDBKCoCCoJcNxNJ2/xRUqlXkss107JMrymp/dooMrum3rv+aCvJrNYy81e76q1MW68/0rtl5s/cMn+QlmWm5Q9WU7ISFBIRvvePltkdARVX5qjf1/PxmD/mnDPDh8Ogr8c5ZwaXMcYIAAAA1ghwegAAAAD4FwEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIGCpTZs2qWPHjgoNDZXL5dLWrVudHsk6LpdLDz/88Fm3mz17tlwul/bu3euzfOLEiWrWrJkCAwPVpk2bmhnyb8aNGyeXy1WjXwOA/xCAQA364osvdPfdd6tx48Zyu92KiYlR//799cUXXzg6V0lJie688079+OOP+v3vf6/XX39dTZs2dXSmM9m7d69cLpeef/75Stc///zzFQKpc+fOcrlccrlcCggIUHh4uK688koNGDBAK1asqPR54uPjvY85/XbixIma+NbO2/vvv68nnnhCKSkpmjVrlsaPH6+DBw9q3LhxxDyAswpyegDgcrVw4UL169dPERERGjJkiBISErR371794Q9/0IIFCzRv3jzddtttjsz2zTffaN++fZo5c6buvfdeR2bwhyZNmig7O1uSVFhYqN27d2vhwoV644031KdPH73xxhuqVauWz2PatGmjxx9/vMJz1a5d2y8zV2bAgAHq27ev3G63d9mqVasUEBCgP/zhD97ZNm/erCeffFLx8fE1fkQQwKWNAARqwDfffKMBAwaoWbNmWrdunRo2bOhd9+ijj+rGG2/UgAED9Nlnn6lZs2Z+m6uwsFChoaHKy8uTJNWtW9dvX9sJHo9Hd999t8+yZ599VllZWXr11VcVHx+vCRMm+Kxv3Lhxhcc4LTAwUIGBgT7L8vLyFBIS4miYArh0cQoYqAETJ05UUVGRZsyY4RN/ktSgQQNNnz5dhYWFeu655yRJCxYskMvl0tq1ays81/Tp0+VyubR9+3bvsq+++kp33HGHIiIiFBwcrLZt2+qdd97xeVz5dWNr167VQw89pMjISDVp0kT33HOPOnXqJEm688475XK51LlzZ+/jVq1apRtvvFGhoaGqW7euevbsqR07dlSY68CBAxoyZIhiYmLkdruVkJCg3/zmNzp58qSkqq8Zq+x6ts2bNystLU0NGjRQSEiIEhISNHjw4LPs5fMTGBiol19+WS1bttQrr7yi/Pz8c35sUVGRvvrqKx05cuSs2+7atUu9e/dWVFSUgoOD1aRJE/Xt27fSr7d48WK1atVKbrdbSUlJeu+993zWn77PXC6XZs2apcLCQu8p6tmzZ6tdu3aSpEGDBvksL/fJJ5/o3/7t3+TxeFSnTh116tRJf/nLXyrMs379erVr107BwcFKTEzU9OnTz3kf/aNDhw5p0KBBatKkidxut6Kjo9WzZ0+fn73L5dK4ceMqPDY+Pl733HNPhX2wfv16ZWVlqWHDhqpbt64eeOABnTx5UkePHtXAgQNVr1491atXT0888YSMMec1N2ADjgACNWDp0qWKj4/XjTfeWOn6m266SfHx8fq///s/SVL37t11xRVX6O233/bGWbn58+crKSlJrVq1kvTLdYUpKSlq3LixRo4cqdDQUL399tvq1auX/vd//7fCaeWHHnpIDRs21JgxY1RYWKibbrpJjRs31vjx45WVlaV27dqpUaNGkqQPPvhA6enpatasmcaNG6eff/5ZkydPVkpKinJychQfHy9JOnjwoNq3b6+jR4/q/vvvV4sWLXTgwAEtWLBARUVF1ToqlZeXp27duqlhw4YaOXKk6tatq71792rhwoXn/BzVFRgYqH79+mn06NFav369unfv7l1XUlJSIfDq1KmjOnXqaOPGjerSpYvGjh1babSUO3nypNLS0lRcXKxHHnlEUVFROnDggJYtW6ajR4/K4/F4t12/fr0WLlyohx56SGFhYXr55ZfVu3dv7d+/X/Xr16/0+V9//XXNmDFDGzdu1GuvvSZJat68uX73u99pzJgxuv/++72vvY4dO0r6JezT09N17bXXauzYsQoICNCsWbP0r//6r/rwww/Vvn17SdLnn3/u/XmMGzdOp06d0tixY72vkero3bu3vvjiCz3yyCOKj49XXl6eVqxYof3793tfS9VVvj+ffPJJbdiwQTNmzFDdunX10UcfKS4uTuPHj9ef//xnTZw4Ua1atdLAgQPP6+sAlz0D4II6evSokWR69ux5xu1uvfVWI8kUFBQYY4zp16+fiYyMNKdOnfJu891335mAgADzu9/9zrusa9euJjk52Zw4ccK7rKyszHTs2NE0b97cu2zWrFlGkrnhhht8ntMYY1avXm0kmT/96U8+y9u0aWMiIyPNDz/84F22bds2ExAQYAYOHOhdNnDgQBMQEGA2bdpU4fsqKyszxhgzduxYU9k/MeVz7dmzxxhjzKJFi4ykSp+r3J49e4wkM3HixErXT5w40ec5jTGmU6dOJikpqcrnLP+6L730kndZ06ZNjaQKt7Fjxxpj/r7fyu9X5dNPP610/55Okqldu7bZvXu3d9m2bduMJDN58mTvstP3mTHGZGRkmNDQUJ/n27Rpk5FkZs2a5bO8rKzMNG/e3KSlpXl/PsYYU1RUZBISEszNN9/sXdarVy8THBxs9u3b51325ZdfmsDAwEp/nlX56aefzvgzK1fV/mzatKnJyMjw3i/fB6d/D9dff71xuVzmwQcf9C47deqUadKkienUqdM5zwvYhlPAwAV27NgxSVJYWNgZtytfX1BQIEm66667lJeXpzVr1ni3WbBggcrKynTXXXdJkn788UetWrVKffr00bFjx3TkyBEdOXJEP/zwg9LS0rRr1y4dOHDA5+vcd999Fa4fq8x3332nrVu36p577lFERIR3+dVXX62bb75Zf/7znyVJZWVlWrx4sXr06KG2bdtWeJ7qflRI+XWIy5YtU0lJSbUe+8+44oorJP3951WuQ4cOWrFihc+t/ChS586dZYw549E/Sd4jfMuXL1dRUdEZt01NTVViYqL3/tVXX63w8HB9++231f2WqrR161bt2rVL//Ef/6EffvjB+7opLCxU165dtW7dOpWVlam0tFTLly9Xr169FBcX5338VVddpbS0tGp9zfLrE9esWaOffvrpgn0vQ4YM8XmNdejQQcYYDRkyxLssMDBQbdu2vaD7ELjcEIDABVYedqeHxelOD8Xya7Pmz5/v3Wb+/Plq06aNfvWrX0mSdu/eLWOMRo8erYYNG/rcxo4dK0neN3iUS0hIOKe59+3bJ0m68sorK6y76qqrvMHw/fffq6CgwHtK+p/VqVMn9e7dW08++aQaNGignj17atasWSouLq72c1UnPo8fPy6pYqg3aNBAqampPrfqvlEnISFBw4YN02uvvaYGDRooLS1NU6ZMqfT6v38MrXL16tW7oNG0a9cuSVJGRkaF181rr72m4uJi5efn6/vvv9fPP/+s5s2bV3iOyl4XZ+J2uzVhwgS9++67atSokW666SY999xzOnTo0D/1vZy+v8pjOzY2tsLyC7kPgcsN1wACF5jH41F0dLQ+++yzM2732WefqXHjxgoPD5f0y3+YvXr10qJFi/Tqq6/q8OHD+stf/qLx48d7H1NWViZJ+s///M8qj8j8y7/8i8/9kJCQf+bbOW9VxVhpaWmF7RYsWKANGzZo6dKlWr58uQYPHqwXXnhBGzZs0BVXXKHg4GBJ0s8//1zpc5YfZSvf7lyUv6nm9P11obzwwgu65557tGTJEr3//vvKyspSdna2NmzYoCZNmni3q+rorLmAb2Aof91MnDixyo+HueKKK84rus9k6NCh6tGjhxYvXqzly5dr9OjRys7O1qpVq3TNNdec8bGnv07KVbW/Klt+IfchcLkhAIEacMstt2jmzJlav369brjhhgrrP/zwQ+3du1cPPPCAz/K77rpLc+bM0cqVK7Vjxw4ZY7ynfyV5j0TVqlVLqampF3Tm8g+C3rlzZ4V1X331lRo0aKDQ0FCFhIQoPDzc513JlalXr54k6ejRoz4fN1N+pPF01113na677jo988wzmjt3rvr376958+bp3nvvVcOGDVWnTp1KZyufuU6dOmrQoMG5fKsqLS3V3LlzVadOnUp/PhdKcnKykpOT9dvf/lYfffSRUlJSNG3aND399NM18vWqiu7yU8zh4eFnfN00bNhQISEh3iOG/6iqfX82iYmJevzxx/X4449r165datOmjV544QW98cYbkn55nRw9etTnMSdPntR33313Xl8PwLnhFDBQA4YPH66QkBA98MAD+uGHH3zW/fjjj3rwwQdVp04dDR8+3GddamqqIiIiNH/+fM2fP1/t27f3OYUbGRmpzp07a/r06ZX+B/n999+f98zR0dFq06aN5syZ4/Mf8vbt2/X+++/r3//93yVJAQEB6tWrl5YuXarNmzdXeJ7yoy7l0bFu3TrvusLCQs2ZM8dn+59++qnCkZryo1TlR6QCAwPVrVs3LV26VPv37/fZdv/+/Vq6dKm6det2Ttc6lpaWKisrSzt27FBWVpb3COy5ONePgSkoKNCpU6d8liUnJysgIOCCH2X7R6GhoZJUIaiuvfZaJSYm6vnnn/ee+v5H5a+bwMBApaWlafHixT77eceOHVq+fHm1ZikqKqrw11MSExMVFhbmsw8SExN9XiOSNGPGjCqPAAK4MDgCCNSA5s2ba86cOerfv7+Sk5Mr/CWQI0eO6K233vK5+F/65cje7bffrnnz5qmwsLDSP302ZcoU3XDDDUpOTtZ9992nZs2a6fDhw/r444/117/+Vdu2bTvvuSdOnKj09HRdf/31GjJkiPdjYDwej88bH8aPH6/3339fnTp10v3336+rrrpK3333nf70pz9p/fr1qlu3rrp166a4uDgNGTJEw4cPV2BgoP74xz+qYcOGPnExZ84cvfrqq7rtttuUmJioY8eOaebMmQoPD/dGZ/nXvO666/TrX/9a999/v+Lj47V3717NmDFDLpfL51R5ufz8fO+RpqKiIu9fAvnmm2/Ut29fPfXUU9XaP+f6MTCrVq3Sww8/rDvvvFO/+tWvdOrUKb3++usKDAxU7969q/U1qyMxMVF169bVtGnTFBYWptDQUHXo0EEJCQl67bXXlJ6erqSkJA0aNEiNGzfWgQMHtHr1aoWHh2vp0qWSpCeffFLvvfeebrzxRj300EM6deqUJk+erKSkpLNe1vCPvv76a3Xt2lV9+vRRy5YtFRQUpEWLFunw4cPq27evd7t7771XDz74oHr37q2bb75Z27Zt0/Lly8/5aC6A8+TcG5CBy99nn31m+vXrZ6Kjo02tWrVMVFSU6devn/n888+rfMyKFSuMJONyuUxubm6l23zzzTdm4MCBJioqytSqVcs0btzY3HLLLWbBggXebco/NqOyj1ep6mNgjDHmgw8+MCkpKSYkJMSEh4ebHj16mC+//LLCdvv27TMDBw40DRs2NG632zRr1sxkZmaa4uJi7zZbtmwxHTp0MLVr1zZxcXHmxRdfrPCRJjk5OaZfv34mLi7OuN1uExkZaW655RazefPmCl9zx44d5q677jKRkZEmKCjIREZGmr59+5odO3ZU2LZTp04+H+VyxRVXmObNm5u7777bvP/++5Xu16ZNm5ru3btXuu4f99vZPgbm22+/NYMHDzaJiYkmODjYREREmC5dupgPPvjAZztJJjMzs9I5KvsIlLN9DIwxxixZssS0bNnSBAUFVfhImE8//dTcfvvtpn79+sbtdpumTZuaPn36mJUrV/o8x9q1a821115rateubZo1a2amTZtW5cf6VOXIkSMmMzPTtGjRwoSGhhqPx2M6dOhg3n77bZ/tSktLzYgRI0yDBg1MnTp1TFpamtm9e3eV++D013P5XN9//73P8qr2D4BfuIzhKlkAAACbcA0gAACAZbgGEABQLfn5+VV+JE+5qKgoP00D4HxwChgAUC333HNPhXdzn47/WoCLGwEIAKiWL7/8UgcPHjzjNhf6cyoBXFgEIAAAgGV4EwgAAIBleBMIzktZWZkOHjyosLCwKv/8FADg4mWM0bFjxxQTE6OAAI4H2YYAxHk5ePCgYmNjnR4DAPBPys3NVZMmTZweA35GAOK8hIWFSZJu0L8rSLUcngYAUF2nVKL1+rP333PYhQDEeSk/7RukWgpyEYAAcMn521tAuYzHTpz0BwAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQMtNmTJF8fHxCg4OVocOHbRx40anRwIAADWMALTY/PnzNWzYMI0dO1Y5OTlq3bq10tLSlJeX5/RoAACgBhGAFnvxxRd13333adCgQWrZsqWmTZumOnXq6I9//KPTowEAgBpEAFrq5MmT2rJli1JTU73LAgIClJqaqo8//rjC9sXFxSooKPC5AQCASxMBaKkjR46otLRUjRo18lneqFEjHTp0qML22dnZ8ng83ht/Bg4AgEsXAYhzMmrUKOXn53tvubm5To8EAADOE38KzlINGjRQYGCgDh8+7LP88OHDioqKqrC92+2W2+3213gAAKAGcQTQUrVr19a1116rlStXepeVlZVp5cqVuv766x2cDAAA1DSOAFps2LBhysjIUNu2bdW+fXtNmjRJhYWFGjRokNOjAQCAGkQAWuyuu+7S999/rzFjxujQoUNq06aN3nvvvQpvDAEAAJcXlzHGOD0ELj0FBQXyeDzqrJ4KctVyehwAQDWdMiVaoyXKz89XeHi40+PAz7gGEAAAwDIEIAAAgGUIQAAA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", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "e9814e14e8f449c189f9479d0d99c0ea", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAuP0lEQVR4nO3de3jMd97/8dfkYEQkQxAREglrqyWl69SKFrcst1sdelJnpQfdpk1VV/HbTbV3S6oH9KCU695yF0UtWnZbVYeqbtUhorWLoqEpJdVWhqg0Mp/fH93MvdNEHFbmi8/zcV3zx3y/35l5ZyKu5/X5zsFljDECAACANUKcHgAAAADBRQACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABHDeNm/erPbt2ysyMlIul0s5OTlOj4QzuOuuu5SUlOT0GBfE5XLpiSeecHoM4IpEAAKXqL///e8aNGiQ6tevL7fbrfj4eA0cOFB///vfHZ2ruLhYd9xxh77//ntNmTJFb7zxhho2bOjoTBXZv3+/XC6Xnn/++XL3P//883K5XNq/f79/W6dOneRyueRyuRQSEqLo6GhdddVVGjx4sFatWlXu/SQlJflv88vLqVOnKuNHuyTMnz9fU6dOdXoMAOcpzOkBAJS1ZMkS9e/fXzExMbr77ruVnJys/fv363/+53+0ePFiLViwQLfccosjs+3bt08HDhzQrFmzdM899zgyQzA0aNBAWVlZkqTCwkLt3btXS5Ys0dy5c9W3b1/NnTtX4eHhAbdp2bKlHn300TL3VaVKlaDM7IT58+drx44dGjlypNOjADgPBCBwidm3b58GDx6sRo0aaf369apTp45/38MPP6wbb7xRgwcP1meffaZGjRoFba7CwkJFRkYqPz9fklSjRo2gPbYTPB6PBg0aFLDtmWeeUUZGhl599VUlJSVp0qRJAfvr169f5jYAcCniFDBwiXnuued08uRJzZw5MyD+JKl27dp67bXXVFhYqGeffVaStHjxYrlcLn344Ydl7uu1116Ty+XSjh07/Nt27dql22+/XTExMapatapat26td955J+B2s2fP9t/nAw88oNjYWDVo0EB33XWXOnbsKEm644475HK51KlTJ//t1qxZoxtvvFGRkZGqUaOGevfurZ07d5aZ6+DBg7r77rsVHx8vt9ut5ORk/e53v9NPP/0kSXriiSfkcrnK3K50rn89XbtlyxZ169ZNtWvXVkREhJKTkzV8+PCzPMsXJjQ0VC+99JKuueYavfLKKyooKDjn2548eVK7du3S0aNHz3rsnj17dNtttykuLk5Vq1ZVgwYN1K9fvzKPN3fuXLVq1UoRERGKiYlRv379lJeXd9b79/l8mjp1qpo1a6aqVauqbt26GjFihH744Ycyx7777rvq2LGjoqKiFB0drTZt2mj+/PmSfj5V/pe//EUHDhzwn+7+19cbFhUVafz48frVr34lt9uthIQEPfbYYyoqKgp4jKKiIj3yyCOqU6eOoqKi1KtXL3399ddn/TkAXDhWAIFLzPLly5WUlKQbb7yx3P033XSTkpKS9Je//EWS1KNHD1WvXl2LFi3yx1mphQsXqlmzZmrevLmkn19XmJqaqvr162vs2LGKjIzUokWL1KdPH/35z38uc1r5gQceUJ06dfT444+rsLBQN910k+rXr6+JEycqIyNDbdq0Ud26dSVJH3zwgbp3765GjRrpiSee0I8//qiXX35Zqampys7O9ofBoUOH1LZtWx07dkz33XefmjZtqoMHD2rx4sU6efLkeZ0uzc/PV9euXVWnTh2NHTtWNWrU0P79+7VkyZJzvo/zFRoaqv79+yszM1MbNmxQjx49/PuKi4vLBF61atVUrVo1bdq0SZ07d9b48eMrfGPDTz/9pG7duqmoqEgPPfSQ4uLidPDgQa1YsULHjh2Tx+ORJE2YMEGZmZnq27ev7rnnHn377bd6+eWXddNNN2nbtm0VrtCOGDFCs2fP1rBhw5SRkaHc3Fy98sor2rZtmz7++GP/qe3Zs2dr+PDhatasmcaNG6caNWpo27Zteu+99zRgwAD94Q9/UEFBgb7++mtNmTJFklS9enVJP0dmr169tGHDBt133326+uqr9fnnn2vKlCn64osvtGzZMv8899xzj+bOnasBAwao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wsJCSVL37t0lSS+99FLAMXy7CFC5WAEELjFNmjTRnDlzNHDgQKWkpJT5JpCjR4/qzTffLPOaqfDwcN16661asGCBCgsLy/3qs2nTpqlDhw5KSUnRvffeq0aNGunIkSP65JNP9PXXX2v79u0XPPdzzz2n7t2764YbbtDdd9/t/xgYj8cT8MaHiRMn6v3331fHjh39Hw/yzTff6K233tKGDRtUo0YNde3aVYmJibr77rs1evRohYaG6k9/+pPq1KkTEHFz5szRq6++qltuuUWNGzfW8ePHNWvWLEVHR/ujs/Qxr7/+ev3mN7/Rfffdp6SkJO3fv18zZ86Uy+UKOFVeqqCgQHPnzpX0c7yVfhPIvn371K9fv3IDqiLn+jEwa9as0YMPPqg77rhDv/71r3X69Gm98cYbCg0N1W233Sbp50B++umnNW7cOO3fv199+vRRVFSUcnNztXTpUt133336/e9/X+79d+zYUSNGjFBWVpZycnLUtWtXhYeHa8+ePXrrrbf04osv6vbbb1d0dLSmTJmie+65R23atNGAAQNUs2ZNbd++XSdPnvTHeKtWrbRw4UKNGjVKbdq0UfXq1dWzZ08NHjxYixYt0v3336+1a9cqNTVVJSUl2rVrlxYtWqSVK1eqdevWatmypfr3769XX31VBQUFat++vVavXq29e/ee1/ML4Dw59fZjABX77LPPTP/+/U29evVMeHi4iYuLM/379zeff/75GW+zatUqI8m4XC6Tl5dX7jH79u0zQ4YMMXFxcSY8PNzUr1/f3HzzzWbx4sX+Y0o/bqW8j1c508fAGGPMBx98YFJTU01ERISJjo42PXv2NP/4xz/KHHfgwAEzZMgQU6dOHeN2u02jRo1Menq6KSoq8h+zdetW065dO1OlShWTmJhoJk+eXOZjYLKzs03//v1NYmKicbvdJjY21tx8881my5YtZR5z586d5s477zSxsbEmLCzMxMbGmn79+pmdO3eWObZjx44BH+VSvXp106RJEzNo0CDz/vvvl/u8NmzY0PTo0aPcff/6vJ3tY02+/PJLM3z4cNO4cWNTtWpVExMTYzp37mw++OCDMsf++c9/Nh06dDCRkZEmMjLSNG3a1KSnp5vdu3f7j/nlx8CUmjlzpmnVqpWJiIgwUVFRJiUlxTz22GPm0KFDAce98847pn379v7fadu2bc2bb77p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GQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEALXbw4EENGjRItWrVUkREhFJSUrRlyxanxwIAAJUszOkB4IwffvhBqamp6ty5s959913VqVNHe/bsUc2aNZ0eDQAAVDIC0FKTJk1SQkKCXn/9df+25ORkBycCAADBwilgS73zzjtq3bq17rjjDsXGxuq6667TrFmznB4LAAAEAQFoqS+//FLTp09XkyZNtHLlSv3ud79TRkaG5syZU+7xRUVF8nq9ARcAAHB54hSwpXw+n1q3bq2JEydKkq677jrt2LFDM2bM0NChQ8scn5WVpSeffDLYYwIAgErACqCl6tWrp2uuuSZg29VXX62vvvqq3OPHjRungoIC/yUvLy8YYwIAgErACqClUlNTtXv37oBtX3zxhRo2bFju8W63W263OxijAQCASsYKoKUeeeQRbdy4URMnTtTevXs1f/58zZw5U+np6U6PBgAAKhkBaKk2bdpo6dKlevPNN9W8eXM99dRTmjp1qgYOHOj0aAAAoJJxCthiN998s26++WanxwAAAEHGCiAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEALVVSUqLMzEwlJycrIiJCjRs31lNPPSVjjNOjAQCAShbm9ABwxqRJkzR9+nTNmTNHzZo105YtWzRs2DB5PB5lZGQ4PR4AAKhEBKCl/va3v6l3797q0aOHJCkpKUlvvvmmNm3a5PBkAACgsnEK2FLt27fX6tWr9cUXX0iS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", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "7de9ffc913f5458abaf687e0f3fce4ae", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAqk0lEQVR4nO3de3hU9Z3H8c/kwiTEZDCEkAQSElgKCAjWABVQYM3CpoBgldvDrYBSazAglgW6jdhVCIhavCC33QJbQVAWUGirIlfZBblERCxXDRCDEFHIQJAYkt/+YTPtmHAtmQP5vV/Pc/6Yc87MfDManvfzOzMTlzHGCAAAANYIcnoAAAAABBYBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhCAY7Zv36727dsrIiJCLpdLu3btcnokALACAQhUc59++qkGDRqkevXqye12KyEhQQMHDtSnn37q6FwlJSXq06ePvvnmG/3ud7/TH/7wBzVo0MDRmS7l8OHDcrlceu655yo9/txzz8nlcunw4cO+fZ07d5bL5ZLL5VJQUJCioqLUpEkTDR48WGvWrKn0cZKTk333+eF2/vz5qvjRAFgoxOkBAFSd5cuXa8CAAYqOjtaIESOUkpKiw4cP67/+67+0bNkyLVmyRPfff78js3322Wc6cuSI5s2bp4ceesiRGQKhfv36ys7OliQVFRXp0KFDWr58uV577TX17dtXr732mkJDQ/3u07p1az3xxBMVHqtGjRoBmRlA9UcAAtXUZ599psGDB6thw4batGmT6tSp4zs2evRo3X333Ro8eLB2796thg0bBmyuoqIiRUREqKCgQJJUq1atgD23EzwejwYNGuS3b+rUqcrMzNSrr76q5ORkTZs2ze94vXr1KtwHAK4nLgED1dT06dN17tw5zZ071y/+JCkmJkZz5sxRUVGRnn32WUnSsmXL5HK5tHHjxgqPNWfOHLlcLu3Zs8e3b9++fXrwwQcVHR2tsLAwpaam6u233/a734IFC3yP+eijjyo2Nlb169fXz3/+c3Xq1EmS1KdPH7lcLnXu3Nl3v3Xr1unuu+9WRESEatWqpV69emnv3r0V5srPz9eIESOUkJAgt9utlJQU/fKXv9R3330nSXrqqafkcrkq3K98rr+/XLtjxw5169ZNMTExCg8PV0pKioYPH36ZV/naBAcH66WXXtJtt92mV155RYWFhVd833Pnzmnfvn06efLkZc89ePCgHnjgAcXFxSksLEz169dX//79fc9Xfll7wYIFFe7rcrn01FNP+W6Xv5YHDhzQoEGD5PF4VKdOHWVlZckYo7y8PPXq1UtRUVGKi4vT888/f8U/E4DAYwUQqKZWrVql5ORk3X333ZUev+eee5ScnKw//vGPkqTu3bvrlltu0RtvvOGLs3JLly5V8+bN1aJFC0nfv6+wQ4cOqlevniZMmKCIiAi98cYb6t27t/7nf/6nwmXlRx99VHXq1NGTTz6poqIi3XPPPapXr56mTJmizMxMtWnTRnXr1pUkvf/++0pPT1fDhg311FNP6dtvv9XLL7+sDh06KCcnR8nJyZKkY8eOqW3btjp9+rRGjhyppk2bKj8/X8uWLdO5c+eu6nJpQUGBunbtqjp16mjChAmqVauWDh8+rOXLl1/xY1yt4OBgDRgwQFlZWdq8ebO6d+/uO1ZSUlIh8GrWrKmaNWtq27Zt6tKliyZNmuQXaD/03XffqVu3biouLtZjjz2muLg45efna/Xq1Tp9+rQ8Hs81zd2vXz81a9ZMU6dO1R//+Ec988wzio6O1pw5c/TP//zPmjZtmhYtWqRf/epXatOmje65555reh4AVcwAqHZOnz5tJJlevXpd8rz77rvPSDJer9cYY8yAAQNMbGysuXDhgu+cL7/80gQFBZn/+I//8O279957TcuWLc358+d9+8rKykz79u1N48aNffvmz59vJJmOHTv6PaYxxqxfv95IMm+++abf/tatW5vY2Fjz9ddf+/Z9/PHHJigoyAwZMsS3b8iQISYoKMhs3769ws9VVlZmjDFm0qRJprJ/5srnys3NNcYYs2LFCiOp0scql5ubaySZ6dOnV3p8+vTpfo9pjDGdOnUyzZs3v+hjlj/viy++6NvXoEEDI6nCNmnSJGPM31638tsX89FHH1X6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", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "%autoreload\n", "size = 16\n", @@ -862,254 +1130,10 @@ }, { "cell_type": "code", - "execution_count": 16, + "execution_count": null, "id": "8a47c3a8", "metadata": {}, - "outputs": [ - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "bafb0b2b57c94f2383b338343eae4595", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "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", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "6fdb0b413ef745458b1fa588d170eb4a", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAtsElEQVR4nO3de1SVdb7H8c8GZIsIeANvICDj/ZLmhQxNTdPDqKPmqJkm3ioLM7OayXVOqc2M2LGapjJvFbpyHDWPonYqvKVm5fE2lpqZWiqjplkJirVV+J0/OuzTjotgwCP93q+19lrtZz9svmxY8u73PPvBZYwxAgAAgDX8nB4AAAAA5YsABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhBwyOHDh9WrVy+FhYXJ5XIpLS3N6ZGKZefOnbr11lsVHBwsl8ulvXv3Oj2SdVwulyZMmHDN/RYuXCiXy6Vjx475bJ81a5YaNmwof39/tWnTpmyG/D/Tpk2Ty+Uq088BoOQIQOAa8n6J5t0CAgJUv359jRo1SidPnrzu501KStK+ffv0l7/8RW+88Ybat2/vfezAgQMaMWKE6tevL7fbrXr16mn48OE6cOBAaXxJ1+3KlSsaPHiwvv32W/31r3/VG2+8oejoaEdnKsqxY8fkcrn07LPPFvj4s88+my+QunXr5v1e+/n5KTQ0VE2aNNE999yj9evXF/g8MTExPj8jP7398MMPZfGlXbd169bpD3/4gxISEpSamqoZM2bo1KlTmjZtGjEPWCTA6QGAiuLpp59WbGysfvjhB23fvl0LFy7Utm3btH//flWuXLlEz/X999/ro48+0r//+7/nW8lZuXKlhg0bpho1amjs2LGKjY3VsWPH9Nprr2nFihVaunSpBg4cWJpfWrEdPXpUx48f14IFCzRu3DhHZigPkZGRSklJkSRlZ2fryJEjWrlypRYvXqwhQ4Zo8eLFqlSpks/HtGnTRo8++mi+5woMDCyXmQtyzz336K677pLb7fZu27Rpk/z8/PTaa695Z9u1a5emT5+umJiYMl8RBHBjIACBYkpMTPSu0o0bN061atXSM888ozVr1mjIkCEleq6vv/5aklStWjWf7UePHtU999yjhg0bauvWrQoPD/c+9vDDD6tLly6655579Mknn6hhw4a/7AsqgezsbAUHB+vs2bMFzv1rExYWphEjRvhsmzlzpiZOnKhXXnlFMTExeuaZZ3wer1+/fr6PcZq/v7/8/f19tp09e1ZBQUGOhikA53EIGLhOXbp0kfRjtP3UZ599pt///veqUaOGKleurPbt22vNmjXex6dNm+Y9bPr444/L5XIpJiZG0o/nZl26dEnz58/3iT9JqlWrlubNm6fs7Gz953/+pyRpxYoVcrlc2rJlS7755s2bJ5fLpf379xd7Nun/D3lv2bJFDz74oCIiIhQZGalRo0apa9eukqTBgwfL5XKpW7du3o/btGmTunTpouDgYFWrVk39+/fXwYMH88118uRJjR07VvXq1ZPb7VZsbKweeOABXb582fv6FHTOWEHns+3atUu9e/dWrVq1FBQUpNjYWI0ZMybfx5YGf39/vfjii2revLlefvllZWZmFvtjL126pM8++0znzp275r6HDx/WoEGDVKdOHVWuXFmRkZG66667Cvx8aWlpatmypdxut1q0aKF3333X5/Gfv2Yul0upqanKzs72HqJeuHChOnToIEkaPXq0z/Y8//M//6N/+7d/U1hYmKpUqaKuXbvqgw8+yDfPtm3b1KFDB1WuXFlxcXGaN29esV+jn/rqq680evRoRUZGyu12q27duurfv7/P997lcmnatGn5PjYmJkajRo3K9xps27ZNEydOVHh4uKpVq6b7779fly9f1vnz5zVy5EhVr15d1atX1x/+8AcZY65rbqAiYQUQuE55v4yqV6/u3XbgwAElJCSofv36euKJJxQcHKzly5drwIAB+q//+i8NHDhQd955p6pVq6ZHHnlEw4YN029/+1tVrVpVkrR27VrFxMR44/LnbrvtNsXExOi///u/JUl9+vRR1apVtXz5cm+c5Vm2bJlatGihli1bFnu2n3rwwQcVHh6up556StnZ2brttttUv359zZgxQxMnTlSHDh1Uu3ZtSdKGDRuUmJiohg0batq0afr+++/10ksvKSEhQXv27PEG7qlTp9SxY0edP39e9913n5o2baqTJ09qxYoVunTpUolWpc6ePatevXopPDxcTzzxhKpVq6Zjx45p5cqVxX6OkvL399ewYcP05JNPatu2berTp4/3sStXruQLvCpVqqhKlSrasWOHunfvrqlTpxYYLXkuX76s3r17y+Px6KGHHlKdOnV08uRJvfXWWzp//rzCwsK8+27btk0rV67Ugw8+qJCQEL344osaNGiQTpw4oZo1axb4/G+88Ybmz5+vHTt26NVXX5UkNWrUSE8//bSeeuop3Xfffd6fvVtvvVXSj2GfmJiodu3aaerUqfLz81Nqaqpuv/12vf/+++rYsaMkad++fd7vx7Rp03T16lVNnTrV+zNSEoMGDdKBAwf00EMPKSYmRmfPntX69et14sQJ789SSeW9ntOnT9f27ds1f/58VatWTR9++KEaNGigGTNm6O2339asWbPUsmVLjRw58ro+D1BhGABFSk1NNZLMhg0bzNdff20yMjLMihUrTHh4uHG73SYjI8O7b48ePUyrVq3MDz/84N2Wm5trbr31VtOoUSPvti+//NJIMrNmzfJuO3/+vJFk+vfvX+Q8v/vd74wkk5WVZYwxZtiwYSYiIsJcvXrVu8/p06eNn5+fefrpp0s8W97X27lzZ5/nNMaY9957z0gyb775ps/2Nm3amIiICPPNN994t3388cfGz8/PjBw50rtt5MiRxs/Pz+zcuTPf15Wbm2uMMWbq1KmmoH+a8ub68ssvjTHGrFq1ykgq8LnyFPQ6/9SsWbN8ntMYY7p27WpatGhR6HPmfd6//e1v3m3R0dFGUr7b1KlTjTH//7rl3S/MP//5zwJf35+TZAIDA82RI0e82z7++GMjybz00kvebT9/zYwxJikpyQQHB/s8386dO40kk5qa6rM9NzfXNGrUyPTu3dv7/THGmEuXLpnY2Fhzxx13eLcNGDDAVK5c2Rw/fty77dNPPzX+/v4Ffj8L89133xX5PctT2OsZHR1tkpKSvPfzXoOffw2dOnUyLpfLjB8/3rvt6tWrJjIy0nTt2rXY8wIVFYeAgWLq2bOnwsPDFRUVpd///vcKDg7WmjVrFBkZKUn69ttvtWnTJg0ZMkQXLlzQuXPndO7cOX3zzTfq3bu3Dh8+XOS7hi9cuCBJCgkJKXKOvMezsrIkSUOHDtXZs2e1efNm7z4rVqxQbm6uhg4det2z3XvvvfnOHyvI6dOntXfvXo0aNUo1atTwbm/durXuuOMOvf3225Kk3NxcpaWlqV+/fj7veM5T0kuF5J2H+NZbb+nKlSsl+thfIm+1Nu/7lSc+Pl7r16/3ueWtInXr1k3GmCJX/yR5V/jS09N16dKlIvft2bOn4uLivPdbt26t0NBQffHFFyX9kgq1d+9eHT58WHfffbe++eYb789Ndna2evTooa1btyo3N1c5OTlKT0/XgAED1KBBA+/HN2vWTL179y7R58w7P3Hz5s367rvvSu1rGTt2rM/PWHx8vIwxGjt2rHebv7+/2rdvX6qvIXCj4hAwUEyzZ89W48aNlZmZqddff11bt271eXflkSNHZIzRk08+qSeffLLA5zh79qzq169f4GN5YffzsPi5n4di3rlZy5YtU48ePST9ePi3TZs2aty48XXPFhsbW+QceY4fPy5JatKkSb7HmjVrpvT0dGVnZ+vixYvKysryHpL+pbp27apBgwZp+vTp+utf/6pu3bppwIABuvvuu32+L8VRkvi8ePGipPyhXqtWLfXs2bNEn/fnYmNjNXnyZD3//PP6+9//ri5duuh3v/udRowY4XP4V5JPaOWpXr16qUbT4cOHJf14yaLCZGZmyuPx6Pvvv1ejRo3yPd6kSRPv/wQUh9vt1jPPPKNHH31UtWvX1i233KK+fftq5MiRqlOnTsm/iP/z89cr7/WMiorKt700X0PgRkUAAsXUsWNH78rVgAED1LlzZ9199906dOiQqlatqtzcXEnSY489Vuiqx29+85tCnz8sLEx169bVJ598UuQcn3zyierXr6/Q0FBJP/7CHDBggFatWqVXXnlFZ86c0QcffKAZM2Z4P+Z6ZgsKCipyjrJSWIzl5OTk22/FihXavn271q5dq/T0dI0ZM0bPPfectm/frqpVq3ovz/P9998X+Jx5q2wluYxP3ptqivpe/hLPPfecRo0apdWrV2vdunWaOHGiUlJStH37du9qs6RCV2dNKb6BIe/nZtasWYVeHqZq1aryeDyl9jkladKkSerXr5/S0tKUnp6uJ598UikpKdq0aZPatm1b5Mf+/OckT2GvV0HbS/M1BG5UBCBwHfz9/ZWSkqLu3bvr5Zdf1hNPPOG9LEulSpWueyWob9++WrBg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", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "2d976575634b41b3afbc9a522ae35f7d", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAAsyUlEQVR4nO3de3RNd/7/8ddJwhGRhFTilghSqiVoBSWUlvI1KL2gQcWt1Taaqm/NlzXfDmZa0a9pqxdVfFusqrpNKZ3RFC2qU6su1YpRDXVJUZe2TiL0IOfz+6O/nG9PExEq2fTzfKy115qz9z7nvHNZ+py999lxGWOMAAAAYI0gpwcAAABA+SIAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAALXoOzsbHXt2lWRkZFyuVxavny50yOVyubNm9WuXTuFhYXJ5XJp+/btTo+ECxgyZIjq1avn9BiXxeVyaeLEiU6PAVzVCECgDM2dO1cul8u/hISEqE6dOhoyZIgOHTp02a+bmpqqHTt26JlnntGbb76ppKQk/7adO3dq0KBBqlOnjtxut2rXrq2BAwdq586dV+JLumznzp1T37599cMPP+iFF17Qm2++qfj4eEdnKsn+/fvlcrn0t7/9rdjtf/vb3+RyubR//37/uk6dOvl/1kFBQYqIiNANN9ygBx54QKtXry72derVqxfwO/LL5aeffiqLL+2qsGDBAk2bNs3pMQBrhTg9AGCDv/zlL6pfv75++uknbdq0SXPnztXGjRuVlZWlSpUqXdJrnTlzRp9++qn+9Kc/adSoUQHb3nnnHaWkpCgqKkrDhw9X/fr1tX//fr3++utaunSpFi5cqLvvvvtKfmmltnfvXh04cECzZ8/WiBEjHJmhPMTGxiojI0OSlJ+frz179uidd97R/Pnz1a9fP82fP18VKlQIeE6LFi30n//5n0Veq2LFiuUysxMWLFigrKwsjR492ulRACsRgEA56N69u/8o3YgRI1S9enU9++yzWrFihfr163dJr3X8+HFJUtWqVQPW7927Vw888IAaNGigDRs2KDo62r/t8ccfV4cOHfTAAw/oyy+/VIMGDX7bF3QJ8vPzFRYWpmPHjhU79+9NZGSkBg0aFLBuypQpSk9P16uvvqp69erp2WefDdhep06dIs8BgLLEKWDAAR06dJD0c7T90ldffaX77rtPUVFRqlSpkpKSkrRixQr/9okTJ/pPm44dO1Yul8t/ndbUqVN1+vRpzZo1KyD+JKl69eqaOXOm8vPz9T//8z+SpKVLl8rlcmn9+vVF5ps5c6ZcLpeysrJKPZv0f6e8169fr0cffVQxMTGKjY3VkCFD1LFjR0lS37595XK51KlTJ//zPvzwQ3Xo0EFhYWGqWrWqevfurV27dhWZ69ChQxo+fLhq164tt9ut+vXr65FHHtHZs2f93x+Xy1XkeYVz/fJ07ZYtW9StWzdVr15doaGhql+/voYNG1bkuVdCcHCwXnrpJd1000165ZVX5PF4Sv3c06dP66uvvtKJEycuum92drbuvfde1axZU5UqVVJsbKzuv//+Iu83f/58tWzZUqGhoYqKitL999+vnJyci76+z+fTtGnT1KRJE1WqVEk1atTQyJEj9eOPPxbZd9WqVerYsaPCw8MVERGhVq1aacGCBZJ+PlX+j3/8QwcOHPCf7v7l9YZer1cTJkzQ9ddfL7fbrbi4OP3xj3+U1+sNeA+v16snnnhC0dHRCg8P11133aVvv/32ol8HAI4AAo4oDJFq1ar51+3cuVPJycmqU6eOxo0bp7CwMC1evFh9+vTR3//+d91999265557VLVqVT3xxBNKSUnRH/7wB1WpUkWStHLlStWrV88fl7922223qV69evrHP/4hSerRo4eqVKmixYsX++Os0KJFi9SkSRM1bdq01LP90qOPPqro6Gj9+c9/Vn5+vm677TbVqVNHkydPVnp6ulq1aqUaNWpIktasWaPu3burQYMGmjhxos6cOaOXX35ZycnJ2rZtmz8MDh8+rNatW+vkyZN66KGH1LhxYx06dEhLly7V6dOnL+l06bFjx9S1a1dFR0dr3Lhxqlq1qvbv36933nmn1K9xqYKDg5WSkqKnnnpKGzduVI8ePfzbzp07VyTwKleurMqVK+uzzz7T7bffrgkTJpT4wYazZ8+qW7du8nq9euyxx1SzZk0dOnRI7733nk6ePKnIyEhJ0jPPPKOnnnpK/fr104gRI3T8+HG9/PLLuu222/T555+XeIR25MiRmjt3roYOHar09HTt27dPr7zyij7//HN98skn/lPbc+fO1bBhw9SkSRONHz9eVatW1eeff673339fAwYM0J/+9Cd5PB59++23euGFFyTJ/3vs8/l01113aePGjXrooYd04403aseOHXrhhRf09ddfB3zgacSIEZo/f74GDBigdu3a6cMPPwz4vgIogQFQZubMmWMkmTVr1pjjx4+bnJwcs3TpUhMdHW3cbrfJycnx79u5c2eTmJhofvrpJ/86n89n2rVrZxo2bOhft2/fPiPJTJ061b/u5MmTRpLp3bt3ifPcddddRpLJzc01xhiTkpJiYmJizPnz5/37HDlyxAQFBZm//OUvlzxb4dfbvn37gNc0xpiPPvrISDJLliwJWN+iRQsTExNjvv/+e/+6L774wgQFBZnBgwf71w0ePNgEBQWZzZs3F/m6fD6fMcaYCRMmmOL+WSuca9++fcYYY5YtW2YkFftahYr7Pv/S1KlTA17TGGM6duxomjRpcsHXLHzfF1980b8uPj7eSCqyTJgwwRjzf9+3wscX8vnnnxf7/f2l/fv3m+DgYPPMM88ErN+xY4cJCQkJWJ+ammri4+P9jz/++GMjybz11lsBz33//fcD1p88edKEh4ebNm3amDNnzgTsW/hzMsaYHj16BLx+oTfffNMEBQWZjz/+OGD9a6+9ZiSZTz75xBhjzPbt240k8+ijjwbsN2DAgFJ9vwDbcQoYKAddunRRdHS04uLidN999yksLEwrVqxQbGysJOmHH37Qhx9+qH79+ikvL08nTpzQiRMn9P3336tbt27Kzs4u8VPDeXl5kqTw8PAS5yjcnpubK0nq37+/jh07pnXr1vn3Wbp0qXw+n/r373/Zsz344IMKDg6+6PflyJEj2r59u4YMGaKoqCj/+mbNmunOO+/UP//5T0k/HxVavny5evXqFfCJ50LFnfYtSeFRrvfee0/nzp27pOf+FoVHuQp/XoXatGmj1atXByyDBw+W9PPpUmPMRW9rUniELzMzU6dPny52n3feeUc+n0/9+vXz/xxPnDihmjVrqmHDhvroo48u+PpLlixRZGSk7rzzzoDntmzZUlWqVPE/d/Xq1crLy9O4ceOKfMCpND+nJUuW6MYbb1Tjxo0D3ueOO+6QJP/7FP5upKenBzyfD5UApcMpYKAcTJ8+XY0aNZLH49Ebb7yhDRs2yO12+7fv2bNHxhg99dRTeuqpp4p9jWPHjqlOnTrFbisMu1+Hxa/9OhT/4z/+Q5GRkVq0aJE6d+4s6efTvy1atFCjRo0ue7b69euXOEehAwcOSJJuuOGGIttuvPFGZWZmKj8/X6dOnVJubq7/lPRv1bFjR917772aNGmSXnjhBXXq1El9+vTRgAEDAn4upXEp8Xnq1ClJRUO9evXq6tKlyyW976/Vr19fY8aM0fPPP6+33npLHTp00F133aVBgwb54zA7O1vGGDVs2LDY1/j1p5N/KTs7Wx6PRzExMcVuL/yQT+F1rZf7s8rOztauXbuKXMf66/c5cOCAgoKClJCQELC9uN8lAEURgEA5aN26tf/IVZ8+fdS+fXsNGDBAu3fvVpUqVeTz+SRJTz75pLp161bsa1x//fUXfP3IyEjVqlVLX375ZYlzfPnll6pTp44iIiIkSW63W3369NGyZcv06quv6ujRo/rkk080efJk/3MuZ7bQ0NAS5ygrF4qxgoKCIvstXbpUmzZt0sqVK5WZmalhw4bpueee06ZNm1SlShX/0aszZ84U+5qFR9ku5TY+hR+qKeln+Vs899xzGjJkiN5991198MEHSk9PV0ZGhjZt2qTY2Fj5fD65XC6tWrWq2CO0hUcoi+Pz+RQTE6O33nqr2O0XCrZL5fP5lJiYqOeff77Y7XFxcVfkfQDbEYBAOQsODlZGRoZuv/12vfLKKxo3bpz/tiwVKlS47CNBPXv21OzZs7Vx40a1b9++yPaPP/5Y+/fv18iRIwPW9+/fX/PmzdPatWu1a9cuGWP8p38lXZHZLqTwE827d+8usu2rr75S9erVFRYWptDQUEVERAR8Krk4hR+qOXnyZMCHGQqPNP7arbfeqltvvVXPPPOMFixYoIEDB2rhwoUaMWKEoqOjVbly5WJnK5y5cuXKql69emm+VBUUFGjBggWqXLlysT+fKyUxMVGJiYn67//+b/3rX/9ScnKyXnvtNT399NNKSEiQMUb169f3H+EtrYSEBK1Zs0bJycklBn7hEbmsrKwSQ/dCsZ6QkKAvvvhCnTt3LvHoanx8vHw+n/bu3Rtw1O9CPy8AgbgGEHBAp06d1Lp1a02bNk0//fSTYmJi1KlTJ82cOVNHjhwpsn/hvf9KMnbsWIWGhmrkyJH6/vvvA7b98MMPevjhh1W5cmWNHTs2YFuXLl0UFRWlRYsWadGiRWrdunXAKdwrMduF1KpVSy1atNC8efN08uRJ//qsrCx98MEH+sMf/iBJCgoKUp8+fbRy5Upt2bKlyOsYYyT9X3xs2LDBvy0/P1/z5s0L2P/HH3/0P6dQixYtJMl/q5Hg4GB17dpVK1eu1MGDBwP2PXjwoFauXKmuXbuW6lrHgoICpaena9euXUpPT/cfgS2N0t4GJjc3V+fPnw9Yl5iYqKCgIP/XdM899yg4OFiTJk0q8vUbY4r83vxSv379VFBQoL/+9a9Ftp0/f97/8+vatavCw8OVkZFR5C+Z/PI9w8LCir0dTr9+/XTo0CHNnj27yLYzZ84oPz9f0s/31pSkl156KWAf/roIUDocAQQcMnbsWPXt21dz587Vww8/rOnTp6t9+/ZKTEzUgw8+qAYNGujo0aP69NNP9e233+qLL74o8fUaNmyoefPmaeDAgUpMTCzyl0BOnDiht99+u8g1UxUqVNA999yjhQsXKj8/v9g/ffZbZyvJ1KlT1b17d7Vt21bDhw/33wYmMjIy4IMPkydP1gcffKCOHTv6bw9y5MgRLVmyRBs3blTVqlXVtWtX1a1bV8OHD9fYsWMVHBysN954Q9HR0QERN2/ePL366qu6++67lZCQoLy8PM2ePVsRERH+6Cx8z1tvvVW33HKLHnroIdWrV0/79+/XrFmz5HK5Ak6VF/J4PJo/f76kn+Ot8C+B7N27V/fff3+xAVWS0t4G5sMPP9SoUaPUt29fNWrUSOfPn9ebb76p4OBg3XvvvZJ+DuSnn35a48eP1/79+9WnTx+Fh4dr3759WrZsmR566CE9+eSTxb5+x44dNXLkSGVkZGj79u3q2rWrKlSooOzsbC1ZskQvvvii7rvvPkVEROiFF17QiBEj1KpVKw0YMEDVqlXTF198odOnT/tjvGXLllq0aJHGjBmjVq1aqUqVKurVq5ceeOABLV68WA8//LA++ugjJScnq6CgQF999ZUWL16szMxMJSUlqUWLFkpJSdGrr74qj8ejdu3aae3atdqzZ88lfX8Bazn06WPACoW3HynudiMFBQUmISHBJCQk+G+ZsnfvXjN48GBTs2ZNU6FCBVOnTh3Ts2dPs3TpUv/zLnZ7ki+//NKkpKSYWrVqmQoVKpiaNWualJQUs2PHjgvOuXr1aiPJuFyugFvT/FJpZivp673QbWCMMWbNmjUmOTnZhIaGmoiICNOrVy/z73//u8h+Bw4cMIMHD/bfRqdBgwYmLS3NeL1e/z5bt241bdq0MRUrVjR169Y1zz//fJHbwGzbts2kpKSYunXrGrfbbWJiYkzPnj3Nli1birznrl27TP/+/U1MTIwJCQkxMTEx5v777ze7du0qsm/Hjh0DbuVSpUoV07BhQzNo0CDzwQcfFPt9jY+PNz169Ch22y+/bxe7rck333xjhg0bZhISEkylSpVMVFSUuf32282aNWuK7Pv3v//dtG/f3oSFhZmwsDDTuHFjk5aWZnbv3u3f59e3gSk0a9Ys07JlSxMaGmrCw8NNYmKi+eMf/2gOHz4csN+KFStMu3bt/D/T1q1bm7ffftu//dSpU2bAgAGmatWqRlLAe509e9Y8++yzpkmTJsbtdptq1aqZli1bmkmTJhmPx+Pf78yZMyY9Pd1cd911JiwszPTq1cvk5ORwGxigFFzG/Oo8AAAAAH7XuAYQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAx/CQSXxefz6fDhwwoPDy/x73UCAK5Oxhjl5eWpdu3aCgrieJBtCEBclsOHDysuLs7pMQAAv1FOTo5iY2OdHgPljADEZQkPD5cktdcfFKIKDk8DALhU53VOG/VP/7/nsAsBiMtSeNo3RBUU4iIAAeCa8///ECyX8diJk/4AAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQMtNnz5d9erVU6VKldSmTRt99tlnTo8EAADKGAFosUWLFmnMmDGaMGGCtm3bpubNm6tbt246duyY06MBAIAyRABa7Pnnn9eDDz6ooUOH6qabbtJrr72mypUr64033nB6NAAAUIYIQEudPXtWW7duVZcuXfzrgoKC1KVLF3366acOTgYAAMpaiNMDwBknTpxQQUGBatSoEbC+Ro0a+uqrr4rs7/V65fV6/Y9zc3PLfEYAAFA2OAKIUsnIyFBkZKR/iYuLc3okAABwmQhAS1WvXl3BwcE6evRowPqjR4+qZs2aRfYfP368PB6Pf8nJySmvUQEAwBVGAFqqYsWKatmypdauXetf5/P5tHbtWrVt27bI/m63WxEREQELAAC4NnENoMXGjBmj1NRUJSUlqXXr1po2bZry8/M1dOhQp0cDAABliAC0WP/+/XX8+HH9+c9/1nfffacWLVro/fffL/LBEAAA8PviMsYYp4fAtSc3N1eRkZHqpN4KcVVwehwAwCU6b85pnd6Vx+Phsh4LcQ0gAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAC21YcMG9erVS7Vr15bL5dLy5cudHgkAAJQTAtBS+fn5at68uaZPn+70KAAAoJyFOD0AnNG9e3d1797d6TEAAIADOAIIAABgGY4AolS8Xq+8Xq//cW5uroPTAACA34IjgCiVjIwMRUZG+pe4uDinRwIAAJeJAESpjB8/Xh6Px7/k5OQ4PRIAALhMnAJGqbjdbrndbqfHAAAAVwABaKlTp05pz549/sf79u3T9u3bFRUVpbp16zo4GQAAKGsEoKW2bNmi22+/3f94zJgxkqTU1FTNnTvXoakAAEB5IAAt1alTJxljnB4DAAA4gA+BAAAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBKClMjIy1KpVK4WHhysmJkZ9+vTR7t27nR4LAACUAwLQUuvXr1daWpo2bdqk1atX69y5c+ratavy8/OdHg0AAJSxEKcHgDPef//9gMdz585VTEyMtm7dqttuu82hqQAAQHkgACFJ8ng8kqSoqKhit3u9Xnm9Xv/j3NzccpkLAABceZwChnw+n0aPHq3k5GQ1bdq02H0yMjIUGRnpX+Li4sp5SgAAcKUQgFBaWpqysrK0cOHCC+4zfvx4eTwe/5KTk1OOEwIAgCuJU8CWGzVqlN577z1t2LBBsbGxF9zP7XbL7XaX42QAAKCsEICWMsboscce07Jly7Ru3TrVr1/f6ZEAAEA5IQAtlZaWpgULFujdd99VeHi4vvvuO0lSZGSkQkNDHZ4OAACUJa4BtNSMGTPk8XjUqVMn1apVy78sWrTI6dEAAEAZ4wigpYwxTo8AAAAcwhFAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAFpqxowZatasmSIiIhQREaG2bdtq1apVTo8FAADKAQFoqdjYWE2ZMkVbt27Vli1bdMcdd6h3797auXOn06MBAIAy5jLGGKeHwNUhKipKU6dO1fDhwy+6b25uriIjI9VJvRXiqlAO0wEArqTz5pzW6V15PB5FREQ4PQ7KWYjTA8B5BQUFWrJkifLz89W2bdti9/F6vfJ6vf7Hubm55TUeAAC4wjgFbLEdO3aoSpUqcrvdevjhh7Vs2TLddNNNxe6bkZGhyMhI/xIXF1fO0wIAgCuFU8AWO3v2rA4ePCiPx6OlS5fqf//3f7V+/fpiI7C4I4BxcXGcAgaAaxSngO1GAMKvS5cuSkhI0MyZMy+6L9cAAsC1jQC0G6eA4efz+QKO8gEAgN8nPgRiqfHjx6t79+6qW7eu8vLytGDBAq1bt06ZmZlOjwYAAMoYAWipY8eOafDgwTpy5IgiIyPVrFkzZWZm6s4773R6NAAAUMYIQEu9/vrrTo8AAAAcwjWAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAISmTJkil8ul0aNHOz0KAAAoBwSg5TZv3qyZM2eqWbNmTo8CAADKCQFosVOnTmngwIGaPXu2qlWr5vQ4AACgnBCAFktLS1OPHj3UpUsXp0cBAADlKMTpAeCMhQsXatu2bdq8eXOp9vd6vfJ6vf7Hubm5ZTUaAAAoYxwBtFBOTo4ef/xxvfXWW6pUqVKpnpORkaHIyEj/EhcXV8ZTAgCAsuIyxhinh0D5Wr58ue6++24FBwf71xUUFMjlcikoKEherzdgm1T8EcC4uDh1Um+FuCqU2+wAgCvjvDmndXpXHo9HERERTo+DcsYpYAt17txZO3bsCFg3dOhQNW7cWP/1X/9VJP4kye12y+12l9eIAACgDBGAFgoPD1fTpk0D1oWFhem6664rsh4AAPz+cA0gAACAZTgCCEnSunXrnB4BAACUE44AAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAtBSEydOlMvlClgaN27s9FgAAKAchDg9AJzTpEkTrVmzxv84JIRfBwAAbMB/8S0WEhKimjVrOj0GAAAoZ5wCtlh2drZq166tBg0aaODAgTp48KDTIwEAgHLAEUBLtWnTRnPnztUNN9ygI0eOaNKkSerQoYOysrIUHh5eZH+v1yuv1+t/nJubW57jAgCAK4gAtFT37t39/7tZs2Zq06aN4uPjtXjxYg0fPrzI/hkZGZo0aVJ5jggAAMoIp4AhSapataoaNWqkPXv2FLt9/Pjx8ng8/iUnJ6ecJwQAAFcKAQhJ0qlTp7R3717VqlWr2O1ut1sREREBCwAAuDYRgJZ68skntX79eu3fv1//+te/dPfddys4OFgpKSlOjwYAAMoY1wBa6ttvv1VKSoq+//57RUdHq3379tq0aZOio6OdHg0AAJQxAtBSCxcudHoEAADgEE4BAwAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAtBihw4d0qBBg3TdddcpNDRUiYmJ2rJli9NjAQCAMhbi9ABwxo8//qjk5GTdfvvtWrVqlaKjo5Wdna1q1ao5PRoAAChjBKClnn32WcXFxWnOnDn+dfXr13dwIgAAUF44BWypFStWKCkpSX379lVMTIxuvvlmzZ492+mxAABAOSAALfXNN99oxowZatiwoTIzM/XII48oPT1d8+bNK3Z/r9er3NzcgAUAAFybOAVsKZ/Pp6SkJE2ePFmSdPPNNysrK0uvvfaaUlNTi+yfkZGhSZMmlfeYAACgDHAE0FK1atXSTTfdFLDuxhtv1MGDB4vdf/z48fJ4PP4lJyenPMYEAABlgCOAlkpOTtbu3bsD1n399deKj48vdn+32y23210eowEAgDLGEUBLPfHEE9q0aZMmT56sPXv2aMGCBZo1a5bS0tKcHg0AAJQxAtBSrVq10rJly/T222+radOm+utf/6pp06Zp4MCBTo8GAADKGKeALdazZ0/17NnT6TEAAEA54wggAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAFqqXr16crlcRZa0tDSnRwMAAGUsxOkB4IzNmzeroKDA/zgrK0t33nmn+vbt6+BUAACgPBCAloqOjg54PGXKFCUkJKhjx44OTQQAAMoLAQidPXtW8+fP15gxY+RyuYrdx+v1yuv1+h/n5uaW13gAAOAK4xpAaPny5Tp58qSGDBlywX0yMjIUGRnpX+Li4spvQAAAcEW5jDHG6SHgrG7duqlixYpauXLlBfcp7ghgXFycOqm3QlwVymNMAMAVdN6c0zq9K4/Ho4iICKfHQTnjFLDlDhw4oDVr1uidd94pcT+32y23211OUwEAgLLEKWDLzZkzRzExMerRo4fTowAAgHJCAFrM5/Npzpw5Sk1NVUgIB4MBALAFAWixNWvW6ODBgxo2bJjTowAAgHLEYR+Lde3aVXwGCAAA+3AEEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwTIjTA+DaZIyRJJ3XOck4PAwA4JKd1zlJ//fvOexCAOKy5OXlSZI26p8OTwIA+C3y8vIUGRnp9BgoZy5D+uMy+Hw+HT58WOHh4XK5XFf0tXNzcxUXF6ecnBxFRERc0dcuS9fq3NK1Oztzl69rdW7p2p29LOc2xigvL0+1a9dWUBBXhNmGI4C4LEFBQYqNjS3T94iIiLim/qEudK3OLV27szN3+bpW55au3dnLam6O/NmL5AcAALAMAQgAAGAZAhBXHbfbrQkTJsjtdjs9yiW5VueWrt3Zmbt8XatzS9fu7Nfq3Lj68SEQAAAAy3AEEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAHHVmT59uurVq6dKlSqpTZs2+uyzz5we6aI2bNigXr16qXbt2nK5XFq+fLnTI11URkaGWrVqpfDwcMXExKhPnz7avXu302OVyowZM9SsWTP/zXHbtm2rVatWOT3WJZkyZYpcLpdGjx7t9CgXNXHiRLlcroClcePGTo9VKocOHdKgQYN03XXXKTQ0VImJidqyZYvTY5WoXr16Rb7fLpdLaWlpTo+G3xECEFeVRYsWacyYMZowYYK2bdum5s2bq1u3bjp27JjTo5UoPz9fzZs31/Tp050epdTWr1+vtLQ0bdq0SatXr9a5c+fUtWtX5efnOz3aRcXGxmrKlCnaunWrtmzZojvuuEO9e/fWzp07nR6tVDZv3qyZM2eqWbNmTo9Sak2aNNGRI0f8y8aNG50e6aJ+/PFHJScnq0KFClq1apX+/e9/67nnnlO1atWcHq1EmzdvDvher169WpLUt29fhyfD7wm3gcFVpU2bNmrVqpVeeeUVST//zeG4uDg99thjGjdunMPTlY7L5dKyZcvUp08fp0e5JMePH1dMTIzWr1+v2267zelxLllUVJSmTp2q4cOHOz1KiU6dOqVbbrlFr776qp5++mm1aNFC06ZNc3qsEk2cOFHLly/X9u3bnR7lkowbN06ffPKJPv74Y6dH+U1Gjx6t9957T9nZ2Vf8b6/DXhwBxFXj7Nmz2rp1q7p06eJfFxQUpC5duujTTz91cDI7eDweST+H1LWkoKBACxcuVH5+vtq2bev0OBeVlpamHj16BPyeXwuys7NVu3ZtNWjQQAMHDtTBgwedHumiVqxYoaSkJPXt21cxMTG6+eabNXv2bKfHuiRnz57V/PnzNWzYMOIPVxQBiKvGiRMnVFBQoBo1agSsr1Gjhr777juHprKDz+fT6NGjlZycrKZNmzo9Tqns2LFDVapUkdvt1sMPP6xly5bppptucnqsEi1cuFDbtm1TRkaG06NckjZt2mju3Ll6//33NWPGDO3bt08dOnRQXl6e06OV6JtvvtGMGTPUsGFDZWZm6pFHHlF6errmzZvn9Giltnz5cp08eVJDhgxxehT8zoQ4PQAA56WlpSkrK+uauK6r0A033KDt27fL4/Fo6dKlSk1N1fr166/aCMzJydHjjz+u1atXq1KlSk6Pc0m6d+/u/9/NmjVTmzZtFB8fr8WLF1/Vp9x9Pp+SkpI0efJkSdLNN9+srKwsvfbaa0pNTXV4utJ5/fXX1b17d9WuXdvpUfA7wxFAXDWqV6+u4OBgHT16NGD90aNHVbNmTYem+v0bNWqU3nvvPX300UeKjY11epxSq1ixoq6//nq1bNlSGRkZat68uV588UWnx7qgrVu36tixY7rlllsUEhKikJAQrV+/Xi+99JJCQkJUUFDg9IilVrVqVTVq1Eh79uxxepQS1apVq8j/IbjxxhuvidPXknTgwAGtWbNGI0aMcHoU/A4RgLhqVKxYUS1bttTatWv963w+n9auXXtNXNt1rTHGaNSoUVq2bJk+/PBD1a9f3+mRfhOfzyev1+v0GBfUuXNn7dixQ9u3b/cvSUlJGjhwoLZv367g4GCnRyy1U6dOae/evapVq5bTo5QoOTm5yK2Nvv76a8XHxzs00aWZM2eOYmJi1KNHD6dHwe8Qp4BxVRkzZoxSU1OVlJSk1q1ba9q0acrPz9fQoUOdHq1Ep06dCjgasm/fPm3fvl1RUVGqW7eug5NdWFpamhYsWKB3331X4eHh/ussIyMjFRoa6vB0JRs/fry6d++uunXrKi8vTwsWLNC6deuUmZnp9GgXFB4eXuT6yrCwMF133XVX/XWXTz75pHr16qX4+HgdPnxYEyZMUHBwsFJSUpwerURPPPGE2rVrp8mTJ6tfv3767LPPNGvWLM2aNcvp0S7K5/Npzpw5Sk1NVUgI/6lGGTDAVebll182devWNRUrVjStW7c2mzZtcnqki/roo4+MpCJLamqq06NdUHHzSjJz5sxxerSLGjZsmImPjzcVK1Y00dHRpnPnzuaDDz5weqxL1rFjR/P44487PcZF9e/f39SqVctUrFjR1KlTx/Tv39/s2bPH6bFKZeXKlaZp06bG7Xabxo0bm1mzZjk9UqlkZmYaSWb37t1Oj4LfKe4DCAAAYBmuAQQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAs8/8ADL2RjVtoed0AAAAASUVORK5CYII=", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "name": "stderr", - "output_type": "stream", - "text": [ - "/home/weber/LiberTEM/LiberTEM/src/libertem/viz/mpl.py:92: 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", - " self.fig, self.axes = plt.subplots()\n" - ] - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "5e16e2d7c1db45ff930fcdf3ca3d5500", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAApQklEQVR4nO3df3RU9Z3/8dckgSFAMhiTACGBBIr8kF9qADH81AgbgQVqAbMgQUCrDSKychbOrgVbS3CpXdoKCNQCR0pBs4JAq/xSoLRy5MdSgSIC8iMF5IdCEoIOkNzvH/1m6pgQEkxyie/n45x7jnPnzuQ9gweffu6dicdxHEcAAAAwI8TtAQAAAFC9CEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEAAAABjCEDAqEOHDqlv377y+XzyeDxatWqV2yOVy44dO3TfffepXr168ng82rNnj9sjAUCNQwACt7jFixfL4/EEtrCwMDVp0kSjR4/WyZMnb/p5MzIytHfvXv3sZz/T66+/ruTk5MB9+/fv18iRI9WkSRN5vV7FxcVpxIgR2r9/f2W8pJt29epVDR06VF988YX+53/+R6+//rqaNWvm6kxlOXbsmDwej37+85+Xev/Pf/5zeTweHTt2LLCvd+/egT/rkJAQRUZGqlWrVnr00Ue1YcOGUp8nMTEx6N+Rr29fffVVVbw0ADVcmNsDACifn/zkJ0pKStJXX32l7du3a/Hixdq2bZv27dunOnXqVOi5vvzyS33wwQf6z//8T40fPz7ovrfeekvp6emKiorS2LFjlZSUpGPHjum1115Tdna2li9friFDhlTmSyu3I0eO6Pjx41q4cKHGjRvnygzVIT4+XllZWZKkgoICHT58WG+99ZaWLl2qYcOGaenSpapVq1bQYzp16qR///d/L/FctWvXrpaZAdQsBCBQQ6SlpQVW6caNG6fo6Gi99NJLWr16tYYNG1ah5zp37pwkqUGDBkH7jxw5okcffVTNmzfX1q1bFRMTE7jvmWeeUY8ePfToo4/qo48+UvPmzb/dC6qAgoIC1atXT2fPni117u8an8+nkSNHBu2bOXOmJkyYoLlz5yoxMVEvvfRS0P1NmjQp8RgAuB5OAQM1VI8ePST9I9q+7uOPP9YPfvADRUVFqU6dOkpOTtbq1asD90+fPj1w2nTy5MnyeDxKTEyUJM2aNUuXL1/WggULguJPkqKjozV//nwVFBTov//7vyVJ2dnZ8ng82rJlS4n55s+fL4/Ho3379pV7Numfp7y3bNmiH/3oR4qNjVV8fLxGjx6tXr16SZKGDh0qj8ej3r17Bx733nvvqUePHqpXr54aNGigQYMG6cCBAyXmOnnypMaOHau4uDh5vV4lJSXpqaee0pUrVwLvj8fjKfG44rm+frp2586d6tevn6KjoxUeHq6kpCSNGTOmxGMrQ2hoqH71q1+pbdu2euWVV5Sbm1vux16+fFkff/yxzp8/f8NjDx06pIcffliNGjVSnTp1FB8fr0ceeSTw84pPay9evLjEYz0ej6ZPnx64XfxefvLJJxo5cqR8Pp9iYmL0/PPPy3Ec5eTkaNCgQYqMjFSjRo308ssvl/s1Afh2WAEEaqjiELntttsC+/bv36+UlBQ1adJEU6ZMUb169fTGG29o8ODB+t///V8NGTJE3//+99WgQQM9++yzSk9P10MPPaT69etLktasWaPExMRAXH5Tz549lZiYqD/84Q+SpP79+6t+/fp64403AnFWbMWKFbrzzjvVrl27cs/2dT/60Y8UExOjH//4xyooKFDPnj3VpEkTzZgxQxMmTFDnzp3VsGFDSdLGjRuVlpam5s2ba/r06fryyy/161//WikpKdq9e3cgcE+dOqUuXbro4sWLeuKJJ9S6dWudPHlS2dnZunz5coVOl549e1Z9+/ZVTEyMpkyZogYNGujYsWN66623yv0cFRUaGqr09HQ9//zz2rZtm/r37x+47+rVqyUCr27duqpbt64+/PBD9enTR9OmTQsKtG+6cuWK+vXrJ7/fr6efflqNGjXSyZMntXbtWl28eFE+n++m5h4+fLjatGmjmTNn6g9/+INefPFFRUVFaf78+br//vv10ksv6Xe/+52ee+45de7cWT179rypnwOgAhwAt7RFixY5kpyNGzc6586dc3Jycpzs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sGFDffzxxyWO9/v98vv9gdt5eXlVPiMAAKgarACiXLKysuTz+QJbQkKC2yMBAICbRAAaFR0drdDQUJ05cyZo/5kzZ9SoUaMSx0+dOlW5ubmBLScnp7pGBQAAlYwANKp27dq65557tGnTpsC+oqIibdq0Sd26dStxvNfrVWRkZNAGAABqJq4BNGzSpEnKyMhQcnKyunTpotmzZ6ugoECPPfaY26MBAIAqRAAaNnz4cJ07d04//vGP9dlnn6lTp0569913S3wwBAAAfLd4HMdx3B4CNU9eXp58Pp96a5DCPLXcHgcAUEHXnKvarLeVm5vLZT0GcQ0gAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQQgAACAMQSgUVu3btXAgQMVFxcnj8ejVatWuT0SAACoJgSgUQUFBerYsaPmzJnj9igAAKCahbk9ANyRlpamtLQ0t8cAAAAuYAUQAADAGFYAUS5+v19+vz9wOy8vz8VpAADAt8EKIMolKytLPp8vsCUkJLg9EgAAuEkEIMpl6tSpys3NDWw5OTlujwQAAG4Sp4BRLl6vV16v1+0xAABAJSAAjbp06ZIOHz4cuH306FHt2bNHUVFRatq0qYuTAQCAqkYAGrVz50716dMncHvSpEmSpIyMDC1evNilqQAAQHUgAI3q3bu3HMdxewwAAOACPgQCAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAEIAABgDAFoVFZWljp37qyIiAjFxsZq8ODBOnjwoNtjAQCAakAAGrVlyxZlZmZq+/bt2rBhg65evaq+ffuqoKDA7dEAAEAVC3N7ALjj3XffDbq9ePFixcbGateuXerZs6dLUwEAgOpAAEKSlJubK0mKiooq9X6/3y+/3x+4nZeXVy1zAQCAyscpYKioqEgTJ05USkqK2rVrV+oxWVlZ8vl8gS0hIaGapwQAAJWFAIQyMzO1b98+LV++/LrHTJ06Vbm5uYEtJyenGicEAACViVPAxo0fP15r167V1q1bFR8ff93jvF6vvF5vNU4GAACqCgFolOM4evrpp7Vy5Upt3rxZSUlJbo8EAACqCQFoVGZmppYtW6a3335bERER+uyzzyRJPp9P4eHhLk8HAACqEtcAGjVv3jzl5uaqd+/eaty4cWBbsWKF26MBAIAqxgqgUY7juD0CAABwCSuAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCAAAAAxhCARs2bN08dOnRQZGSkIiMj1a1bN73zzjtujwUAAKoBAWhUfHy8Zs6cqV27dmnnzp26//77NWjQIO3fv9/t0QAAQBXzOI7juD0Ebg1RUVGaNWuWxo4de8Nj8/Ly5PP51FuDFOapVQ3TAQAq0zXnqjbrbeXm5ioyMtLtcVDNwtweAO4rLCzUm2++qYKCAnXr1q3UY/x+v/x+f+B2Xl5edY0HAAAqGaeADdu7d6/q168vr9erJ598UitXrlTbtm1LPTYrK0s+ny+wJSQkVPO0AACgsnAK2LArV67oxIkTys3NVXZ2tn7zm99oy5YtpUZgaSuACQkJnAIGgBqKU8C2EYAISE1NVYsWLTR//vwbHss1gABQsxGAtnEKGAFFRUVBq3wAAOC7iQ+BGDV16lSlpaWpadOmys/P17Jly7R582atW7fO7dEAAEAVIwCNOnv2rEaNGqXTp0/L5/OpQ4cOWrdunR588EG3RwMAAFWMADTqtddec3sEAADgEq4BBAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYABAAAMIYAhGbOnCmPx6OJEye6PQoAAKgGBKBxO3bs0Pz589WhQwe3RwEAANWEADTs0qVLGjFihBYuXKjbbrvN7XEAAEA1IQANy8zMVP/+/ZWamur2KAAAoBqFuT0A3LF8+XLt3r1bO3bsKNfxfr9ffr8/cDsvL6+qRgMAAFWMFUCDcnJy9Mwzz+h3v/ud6tSpU67HZGVlyefzBbaEhIQqnhIAAFQVj+M4jttDoHqtWrVKQ4YMUWhoaGBfYWGhPB6PQkJC5Pf7g+6TSl8BTEhIUG8NUpinVrXNDgCoHNecq9qst5Wbm6vIyEi3x0E14xSwQQ888ID27t0btO+xxx5T69at9R//8R8l4k+SvF6vvF5vdY0IAACqEAFoUEREhNq1axe0r169err99ttL7AcAAN89XAMIAABgDCuAkCRt3rzZ7REAAEA1YQUQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGALQqOnTp8vj8QRtrVu3dnssAABQDcLcHgDuufPOO7Vx48bA7bAw/nUAAMAC/otvWFhYmBo1auT2GAAAoJpxCtiwQ4cOKS4uTs2bN9eIESN04sQJt0cCAADVgBVAo7p27arFixerVatWOn36tF544QX16NFD+/btU0RERInj/X6//H5/4HZeXl51jgsAACoRAWhUWlpa4J87dOigrl27qlmzZnrjjTc0duzYEsdnZWXphRdeqM4RAQBAFeEUMCRJDRo00B133KHDhw+Xev/UqVOVm5sb2HJycqp5QgAAUFkIQEiSLl26pCNHjqhx48al3u/1ehUZGRm0AQCAmokANOq5557Tli1bdOzYMf3lL3/RkCFDFBoaqvT0dLdHAwAAVYxrAI36+9//rvT0dH3++eeKiYlR9+7dtX37dsXExLg9GgAAqGIEoFHLly93ewQAAOASTgEDAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwAadvLkSY0cOVK33367wsPD1b59e+3cudPtsQAAQBULc3sAuOPChQtKSUlRnz599M477ygmJkaHDh3Sbbfd5vZoAACgihGARr300ktKSEjQokWLAvuSkpJcnAgAAFQXTgEbtXr1aiUnJ2vo0KGKjY3VXXfdpYULF7o9FgAAqAYEoFGffvqp5s2bp5YtW2rdunV66qmnNGHCBC1ZsqTU4/1+v/Ly8oI2AABQM3EK2KiioiIlJydrxowZkqS77rpL+/bt06uvvqqMjIwSx2dlZemFF16o7jEBAEAVYAXQqMaNG6tt27ZB+9q0aaMTJ06UevzUqVOVm5sb2HJycqpjTAAAUAVYATQqJSVFBw8eDNr3ySefqFmzZqUe7/V65fV6q2M0AABQxVgBNOrZZ5/V9u3bNWPGDB0+fFjLli3TggULlJmZ6fZoAACgihGARnXu3FkrV67U73//e7Vr104//elPNXv2bI0YMcLt0QAAQBXjFLBhAwYM0IABA9weAwAAVDNWAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAI1KTEyUx+MpsWVmZro9GgAAqGJhbg8Ad+zYsUOFhYWB2/v27dODDz6ooUOHujgVAACoDgSgUTExMUG3Z86cqRYtWqhXr14uTQQAAKoLAQhduXJFS5cu1aRJk+TxeEo9xu/3y+/3B27n5eVV13gAAKCScQ0gtGrVKl28eFGjR4++7jFZWVny+XyBLSEhofoGBAAAlcrjOI7j9hBwV79+/VS7dm2tWbPmuseUtgKYkJCg3hqkME+t6hgTAFCJrjlXtVlvKzc3V5GRkW6Pg2rGKWDjjh8/ro0bN+qtt94q8ziv1yuv11tNUwEAgKrEKWDjFi1apNjYWPXv39/tUQAAQDUhAA0rKirSokWLlJGRobAwFoMBALCCADRs48aNOnHihMaMGeP2KAAAoBqx7GNY3759xWeAAACwhxVAAAAAYwhAAAAAYwhAAAAAYwhAAAAAYwhAAAAAYwhAAAAAYwhAAAAAYwhAAAAAYwhAAAAAYwhAAAAAYwhAAAAAYwhAAAAAYwhAAAAAYwhAAAAAYwhAAAAAY8LcHgA1k+M4kqRruio5Lg8DAKiwa7oq6Z9/n8MWAhA3JT8/X5K0TX90eRIAwLeRn58vn8/n9hioZh6H9MdNKCoq0qlTpxQRESGPx1Opz52Xl6eEhATl5OQoMjKyUp+7KtXUuaWaOztzV6+aOrdUc2evyrkdx1F+fr7i4uIUEsIVYdawAoibEhISovj4+Cr9GZGRkTXqL+piNXVuqebOztzVq6bOLdXc2atqblb+7CL5AQAAjCEAAQAAjCEAccvxer2aNm2avF6v26NUSE2dW6q5szN39aqpc0s1d/aaOjdufXwIBAAAwBhWAAEAAIwhAAEAAIwhAAEAAIwhAAEAAIwhAHHLmTNnjhITE1WnTh117dpVH374odsj3dDWrVs1cOBAxcXFyePxaNWqVW6PdENZWVnq3LmzIiIiFBsbq8GDB+vgwYNuj1Uu8+bNU4cOHQJfjtutWze98847bo9VITNnzpTH49HEiRPdHuWGpk+fLo/HE7S1bt3a7bHK5eTJkxo5cqRuv/12hYeHq3379tq5c6fbY5UpMTGxxPvt8XiUmZnp9mj4DiEAcUtZsWKFJk2apGnTpmn37t3q2LGj+vXrp7Nnz7o9WpkKCgrUsWNHzZkzx+1Rym3Lli3KzMzU9u3btWHDBl29elV9+/ZVQUGB26PdUHx8vGbOnKldu3Zp586duv/++zVo0CDt37/f7dHKZceOHZo/f746dOjg9ijlduedd+r06dOBbdu2bW6PdEMXLlxQSkqKatWqpXfeeUd/+9vf9PLLL+u2225ze7Qy7dixI+i93rBhgyRp6NChLk+G7xK+Bga3lK5du6pz58565ZVXJP3jdw4nJCTo6aef1pQpU1yernw8Ho9WrlypwYMHuz1KhZw7d06xsbHasmWLevbs6fY4FRYVFaVZs2Zp7Nixbo9SpkuXLunuu+/W3Llz9eKLL6pTp06aPXu222OVafr06Vq1apX27Nnj9igVMmXKFP35z3/Wn/70J7dH+VYmTpyotWvX6tChQ5X+u9dhFyuAuGVcuXJFu3btUmpqamBfSEiIUlNT9cEHH7g4mQ25ubmS/hFSNUlhYaGWL1+ugoICdevWze1xbigzM1P9+/cP+ve8Jjh06JDi4uLUvHlzjRgxQidOnHB7pBtavXq1kpOTNXToUMXGxuquu+7SwoUL3R6rQq5cuaKlS5dqzJgxxB8qFQGIW8b58+dVWFiohg0bBu1v2LChPvvsM5emsqGoqEgTJ05USkqK2rVr5/Y45bJ3717Vr19fXq9XTz75pFauXKm2bdu6PVaZli9frt27dysrK8vtUSqka9euWrx4sd59913NmzdPR48eVY8ePZSfn+/2aGX69NNPNW/ePLVs2VLr1q3TU089pQkTJmjJkiVuj1Zuq1at0sWLFzV69Gi3R8F3TJjbAwBwX2Zmpvbt21cjrusq1qpVK+3Zs0e5ubnKzs5WRkaGtmzZcstGYE5Ojp555hlt2LBBderUcXucCklLSwv8c4cOHdS1a1c1a9ZMb7zxxi19yr2oqEjJycmaMWOGJOmuu+7Svn379OqrryojI8Pl6crntddeU1pamuLi4tweBd8xrADilhEdHa3Q0FCdOXMmaP+ZM2fUqFEjl6b67hs/frzWrl2r999/X/Hx8W6PU261a9fW9773Pd1zzz3KyspSx44d9ctf/tLtsa5r165dOnv2rO6++26FhYUpLCxMW7Zs0a9+9SuFhYWpsLDQ7RHLrUGDBrrjjjt0+PBht0cpU+PGjUv8D0GbNm1qxOlrSTp+/Lg2btyocePGuT0KvoMIQNwyateurXvuuUebNm0K7CsqKtKmTZtqxLVdNY3jOBo/frxWrlyp9957T0lJSW6P9K0UFRXJ7/e7PcZ1PfDAA9q7d6/27NkT2JKTkzVixAjt2bNHoaGhbo9YbpcuXdKRI0fUuHFjt0cpU0pKSomvNvrkk0/UrFkzlyaqmEWLFik2Nlb9+/d3exR8B3EKGLeUSZMmKSMjQ8nJyerSpYtmz56tgoICPfbYY26PVqZLly4FrYYcPXpUe/bsUVRUlJo2beriZNeXmZmpZcuW6e2331ZERETgOkufz6fw8HCXpyvb1KlTlZaWpqZNmyo/P1/Lli3T5s2btW7dOrdHu66IiIgS11fWq1dPt99++y1/3eVzzz2ngQMHqlmzZjp16pSmTZum0NBQpaenuz1amZ599lndd999mjFjhoYNG6YPP/xQCxYs0IIFC9we7YaKioq0aNEiZWRkKCyM/1SjCjjALebXv/6107RpU6d27dpOly5dnO3bt7s90g29//77jqQSW0ZGhtujXVdp80pyFi1a5PZoNzRmzBinWbNmTu3atZ2YmBjngQcecNavX+/2WBXWq1cv55lnnnF7jBsaPny407hxY6d27dpOkyZNnOHDhzuHDx92e6xyWbNmjdOuXTvH6/U6rVu3dhYsWOD2SOWybt06R5Jz8OBBt0fBdxTfAwgAAGAM1wACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAYQwACAAAY8/8AB7C5/ZBpztgAAAAASUVORK5CYII=", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "e8ed7369587346a3bddc276db5e84481", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "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7eDBg2rWrJni4uKUmJiohISECp9Krkr5UahLly5VWH+1I1rf/va39R//8R/Kz8/Xr3/9ax04cECrVq2SJCUmJqphw4ZVzlY+c8OGDdWsWbNrzlSutLRUK1euVMOGDXX//fdX6z434/Tp0youLq6w7pNPPpGk8AdqUlNTdfjw4XDclzt48GB4e0240VPzACKHAARuE88884waNGigJ554QhcvXqyw7bPPPtOTTz6phg0b6plnnqmwbdCgQWrSpIlWr16t1atXq1evXhVO4SYlJWngwIFasmSJzpw5U+l5z58/f9Mzt2zZUt27d9fy5csrRNv+/fv1zjvv6OGHH5YkRUVFaeTIkdqwYYPy8/MrPU75UafyT5lu3749vK38q0j+v88//7zSkaru3btLUvg0cHR0tAYPHqwNGzbo5MmTFfY9efKkNmzYoMGDB1frWsfS0lJNnz5dH3/8saZPnx4+AlsdN/I1MJL01VdfacmSJeHbJSUlWrJkiRITE9WjRw9J0sMPP6xPP/20wqn/r776Si+99JIaNWpU6VPhNysuLq5SjAO4NXAKGLhNtGvXTsuXL9e4cePUpUuXSr8EcuHCBf3mN7+p9FUc9erV0z/90z9p1apVKi4urvKnzxYtWqT7779fXbp00eOPP662bdvq7Nmz+uCDD/TXv/5Vf/rTn2567gULFmjo0KHq06ePpkyZEv4amEAgUOGDD/PmzdM777yjAQMGaOrUqerQoYPOnDmjNWvWaMeOHWrcuLEGDx6sNm3aaMqUKXrmmWcUHR2tX/7yl0pMTKwQccuXL9crr7yiUaNG6c4771RRUZGWLVumhISEcHSWP+e3v/1t3XvvvZo6darS0tJ0/PhxLV26VD6fr8Kp8nKFhYVasWKFpL/HW/kvgRw9elTf+9739JOf/OSGXp8b/RqY5ORkPf/88zp+/LjuuusurV69Wnv37tXSpUvDv0AydepULVmyRBMnTtTu3buVlpamtWvX6v3339fChQtv+oju1/Xo0UNbtmzRiy++qOTkZKWnp6t379418tgAviEvP4IMoOZ99NFHLjMz07Vs2dLVq1fPtWjRwmVmZrp9+/Zd9T6bN292kpzP53MFBQVV7nP06FE3YcIE16JFC1evXj3XqlUr98gjj7i1a9eG9yn/upWqvl7lal8D45xzW7ZscX379nUNGjRwCQkJbvjw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Wz179tTLL78s6e+/OZySkqIf/OAHevbZZz2ernp8Pp/WrVunkSNHej3KDTl//rySkpKUl5en/v37ez3ODWvSpIkWLFigKVOmeD3KNV2+fFn33nuvXnnlFf37v/+7unfvroULF3o91jXNnTtX69ev1969e70e5YY8++yzev/99/WHP/zB61G+kZkzZ+rtt9/W4cOHa/y312EXRwBxyygpKdHu3bs1aNCg8LqoqCgNGjRIH3zwgYeT2VBYWCjp7yFVl5SWlmrVqlUqLi5Wnz59vB7nurKzszVs2LAKf8/rgsOHDys5OVlt27bVuHHjdPLkSa9Huq633npLGRkZGj16tJKSknTPPfdo2bJlXo91Q0pKSrRixQpNnjyZ+EONIgBxy7hw4YJKS0vVvHnzCuubN2+uTz/91KOpbCgrK9PMmTPVt29fde7c2etxqmXfvn1q1KiR/H6/nnzySa1bt04dO3b0eqxrWrVqlfbs2aOcnByvR7khvXv31uuvv67f//73Wrx4sY4dO6Z+/fqpqKjI69Gu6S9/+YsWL16sdu3aadOmTZo2bZqmT5+u5cuXez1ata1fv16XLl3SxIkTvR4Ft5kYrwcA4L3s7Gzt37+/TlzXVe7uu+/W3r17VVhYqLVr1yorK0t5eXm3bAQWFBRoxowZ2rx5s+rXr+/1ODdk6NCh4f/dtWtX9e7dW6mpqXrjjTdu6VPuZWVlysjI0Lx58yRJ99xzj/bv369XX31VWVlZHk9XPa+99pqGDh2q5ORkr0fBbYYjgLhlNGvWTNHR0Tp79myF9WfPnlWLFi08mur299RTT+ntt9/We++9p9atW3s9TrXFxsbqW9/6lnr06KGcnBx169ZNP/vZz7we66p2796tc+fO6d5771VMTIxiYmKUl5enn//854qJiVFpaanXI1Zb48aNddddd+nIkSNej3JNLVu2rPR/CDp06FAnTl9L0okTJ7RlyxY99thjXo+C2xABiFtGbGysevTooa1bt4bXlZWVaevWrXXi2q66xjmnp556SuvWrdO7776r9PR0r0f6RsrKyhQKhbwe46oefPBB7du3T3v37g0vGRkZGjdunPbu3avo6GivR6y2y5cv6+jRo2rZsqXXo1xT3759K3210SeffKLU1FSPJroxubm5SkpK0rBhw7weBbchTgHjljJr1ixlZWUpIyNDvXr10sKFC1VcXKxJkyZ5Pdo1Xb58ucLRkGPHjmnv3r1q0qSJ2rRp4+FkV5edna2VK1fqt7/9reLj48PXWQYCATVo0MDj6a5t9uzZGjp0qNq0aaOioiKtXLlS27Zt06ZNm7we7ari4+MrXV8ZFxenpk2b3vLXXT799NMaPny4UlNTdfr0ac2ZM0fR0dHKzMz0erRr+uEPf6j77rtP8+bN05gxY/Thhx9q6dKlWrp0qdejXVdZWZlyc3OVlZWlmBj+qUYtcMAt5qWXXnJt2rRxsbGxrlevXm7nzp1ej3Rd7733npNUacnKyvJ6tKuqal5JLjc31+vRrmvy5MkuNTXVxcbGusTERPfggw+6d955x+uxbtiAAQPcjBkzvB7jusaOHetatmzpYmNjXatWrdzYsWPdkSNHvB6rWjZs2OA6d+7s/H6/a9++vVu6dKnXI1XLpk2bnCR36NAhr0fBbYrvAQQAADCGawABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACM+V9+RKoIqzg7fAAAAABJRU5ErkJggg==", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "553ebee3269b4d9492e1941be0b25e11", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "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", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "46b3017bc2914cb0bc7d82c37551b534", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "iVBORw0KGgoAAAANSUhEUgAAAoAAAAHgCAYAAAA10dzkAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjYuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/av/WaAAAACXBIWXMAAA9hAAAPYQGoP6dpAAArSElEQVR4nO3de3xNd77/8fdOwhaRhJC4JRJU604rpITSUo5B6XTQoO6ttmlTddo5PM7p4EwrekxLL+6ng0c1dRu0zLhfq1OPujStdFDUJUWptnYizEb29/dHf9lndhOEShb9vp6Px3o8utdae+1PEg9eXWvtHZcxxggAAADWCHJ6AAAAAJQuAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQgAACAZQhAAAAAyxCAAAAAliEAAQAALEMAAgAAWIYABAAAsAwBCAAAYBkCEAAAwDIEIAAAgGUIQAAAAMsQgAAAAJYhAAEAACxDAAIAAFiGAAQAALAMAQgAAGAZAhAAAMAyBCAAAIBlCEAAAADLEIAAAACWIQABAAAsQwACAABYhgAEAACwDAEIAABgGQIQAADAMgQggOu2Y8cOtWnTRmFhYXK5XMrMzHR6JFzB4MGDlZCQ4PQYN8TlcmncuHFOjwH8KhGAwC3qyy+/1IABA1SzZk253W7VqFFD/fv315dffunoXJcuXVLv3r31ww8/aPLkyXr33XcVHx/v6ExXc+TIEblcLv3pT38qcvuf/vQnuVwuHTlyxL+uQ4cOcrlccrlcCgoKUkREhO666y499thjWrduXZHHSUhI8D/n58s///nPkvjSbgkZGRmaMmWK02MAuE4hTg8AoLClS5cqJSVFUVFRGjZsmGrXrq0jR47onXfe0ZIlS7RgwQI9/PDDjsx26NAhHT16VLNnz9bw4cMdmaE0xMbGKj09XZKUl5engwcPaunSpZo/f7769Omj+fPnq0yZMgHPad68uf793/+90LHKli1bKjM7ISMjQ1lZWRo5cqTTowC4DgQgcIs5dOiQHnvsMdWpU0dbt25VdHS0f9tzzz2ndu3a6bHHHtMXX3yhOnXqlNpceXl5CgsL0+nTpyVJFStWLLXXdkJkZKQGDBgQsG7ixIlKS0vTtGnTlJCQoFdffTVge82aNQs9BwBuRVwCBm4xkyZN0vnz5zVr1qyA+JOkKlWqaObMmcrLy9P//M//SJKWLFkil8ulLVu2FDrWzJkz5XK5lJWV5V+3b98+/e53v1NUVJTKlSunxMREffjhhwHPmzt3rv+YTz/9tGJiYhQbG6vBgwerffv2kqTevXvL5XKpQ4cO/udt3LhR7dq1U1hYmCpWrKiePXtq7969heY6fvy4hg0bpho1asjtdqt27dp66qmndPHiRUnSuHHj5HK5Cj2vYK5/vVy7c+dOdenSRVWqVFFoaKhq166toUOHXuO7fGOCg4P15ptvqmHDhnr77bfl8XiK/dzz589r3759OnPmzDX3PXDggB555BFVq1ZN5cqVU2xsrB599NFCrzd//ny1aNFCoaGhioqK0qOPPqrs7OxrHt/n82nKlClq1KiRypUrp6pVq2rEiBH68ccfC+27atUqtW/fXuHh4YqIiFDLli2VkZEh6adL5X/961919OhR/+Xuf73f0Ov1auzYsbrjjjvkdrsVFxen3//+9/J6vQGv4fV69fzzzys6Olrh4eF66KGH9M0331zz6wBw4zgDCNxiVqxYoYSEBLVr167I7ffdd58SEhL017/+VZLUrVs3VahQQYsWLfLHWYGFCxeqUaNGaty4saSf7itMTk5WzZo1NXr0aIWFhWnRokXq1auX/vKXvxS6rPz0008rOjpaf/jDH5SXl6f77rtPNWvW1IQJE5SWlqaWLVuqatWqkqT169era9euqlOnjsaNG6cLFy7orbfeUnJysnbv3u0PgxMnTqhVq1Y6e/asnnjiCdWvX1/Hjx/XkiVLdP78+eu6XHr69Gl17txZ0dHRGj16tCpWrKgjR45o6dKlxT7G9QoODlZKSopeeuklbdu2Td26dfNvu3TpUqHAK1++vMqXL69PP/1U999/v8aOHXvVNzZcvHhRXbp0kdfr1bPPPqtq1arp+PHjWrlypc6ePavIyEhJ0iuvvKKXXnpJffr00fDhw/Xdd9/prbfe0n333afPPvvsqmdoR4wYoblz52rIkCFKS0vT4cOH9fbbb+uzzz7Txx9/7L+0PXfuXA0dOlSNGjXSmDFjVLFiRX322WdavXq1+vXrp//8z/+Ux+PRN998o8mTJ0uSKlSoIOmnyHzooYe0bds2PfHEE2rQoIH27NmjyZMn66uvvtLy5cv98wwfPlzz589Xv3791KZNG23cuDHg+wqgBBgAt4yzZ88aSaZnz55X3e+hhx4ykkxOTo4xxpiUlBQTExNjLl++7N/n5MmTJigoyPz3f/+3f13Hjh1NkyZNzD//+U//Op/PZ9q0aWPq1avnXzdnzhwjybRt2zbgmMYYs2nTJiPJLF68OGB98+bNTUxMjPn+++/96z7//HMTFBRkBg4c6F83cOBAExQUZHbs2FHo6/L5fMYYY8aOHWuK+uupYK7Dhw8bY4xZtmyZkVTksQocPnzYSDKTJk0qcvukSZMCjmmMMe3btzeNGjW64jELXveNN97wr4uPjzeSCi1jx441xvzf963g8ZV89tlnRX5//9WRI0dMcHCweeWVVwLW79mzx4SEhASsHzRokImPj/c//uijj4wk89577wU8d/Xq1QHrz549a8LDw01SUpK5cOFCwL4FPydjjOnWrVvA8Qu8++67JigoyHz00UcB62fMmGEkmY8//tgYY0xmZqaRZJ5++umA/fr161es7xeAG8MlYOAWkpubK0kKDw+/6n4F23NyciRJffv21enTp7V582b/PkuWLJHP51Pfvn0lST/88IM2btyoPn36KDc3V2fOnNGZM2f0/fffq0uXLjpw4ICOHz8e8DqPP/64goODrzn3yZMnlZmZqcGDBysqKsq/vmnTpnrwwQf1t7/9TdJPZ4WWL1+uHj16KDExsdBxirrsezUFZ7lWrlypS5cuXddzf4mCs1wFP68CSUlJWrduXcAycOBAST9dLjXGXPNjTQrO8K1Zs0bnz58vcp+lS5fK5/OpT58+/p/jmTNnVK1aNdWrV0+bNm264vEXL16syMhIPfjggwHPbdGihSpUqOB/7rp165Sbm6vRo0erXLlyAccozs9p8eLFatCggerXrx/wOg888IAk+V+n4M9GWlpawPN5UwlQsrgEDNxCCsLu52Hxcz8PxX/7t39TZGSkFi5cqI4dO0r66fJv8+bNdeedd0qSDh48KGOMXnrpJb300ktFHvf06dOqWbOm/3Ht2rWLNffRo0clSXfddVehbQ0aNNCaNWuUl5enc+fOKScnx39J+pdq3769HnnkEY0fP16TJ09Whw4d1KtXL/Xr109ut/u6jnU98Xnu3DlJhUO9SpUq6tSp03W97s/Vrl1bo0aN0uuvv6733ntP7dq100MPPaQBAwb44/DAgQMyxqhevXpFHuPn707+VwcO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", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "df5e46b015344ffc95d40e1b314834f7", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "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JkyY4HTo0MGJiopy4uLinDvuuMNZs2ZN0HFnzpxx8vPzHZ/P58TExDj33Xefc+zYsQt+Dczx48eDHp+Xl+e0aNGi3p/9Yl+BA8BdHsfhKl0AAABLuAYQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGAIQAADAGH4TCK5ITU2NDh8+rJiYmAv+QnkAwLXLcRxVVlYqOTlZYWGsB1lDAOKKHD58WKmpqW6PAQD4jkpLS5WSkuL2GAgxAhBXJCYmRpJ0u36gCDVzeRoAwOU6r3PaqD8G/jyHLQQgrkjtad8INVOEhwAEgCbn//8iWC7jsYmT/gAAAMYQgAAAAMYQgAAAAMYQgAAAAMYQgAAAAMYQgAAAAMYQgAAAAMYQgAAAAMYQgAAAAMYQgAAAAMYQgAAAAMYQgAAAAMYQgAAAAMYQgAAAAMYQgAAAAMYQgMbNmjVLGRkZioqKUlZWlj766CO3RwIAAI2MADRsyZIlmjJliqZNm6atW7eqV69eGjp0qI4dO+b2aAAAoBERgIb9/Oc/1yOPPKKHHnpIXbt21csvv6zmzZvrt7/9rdujAQCARkQAGnX27Flt2bJFgwcPDuwLCwvT4MGD9eGHH7o4GQAAaGwRbg8Ad5w4cULV1dVq3bp10P7WrVvrk08+qXO83++X3+8P3K6oqGj0GQEAQONgBRANUlhYKJ/PF9hSU1PdHgkAAFwhAtCo+Ph4hYeH6+jRo0H7jx49qjZt2tQ5furUqSovLw9spaWloRoVAABcZQSgUZGRkbr11lu1du3awL6amhqtXbtW/fr1q3O81+tVbGxs0AYAAJomrgE0bMqUKcrLy1NmZqb69u2rF198UVVVVXrooYfcHg0AADQiAtCwMWPG6Pjx4/rxj3+sL774Qr1799Y777xT54MhAADg+uJxHMdxewg0PRUVFfL5fBqkkYrwNHN7HADAZTrvnNM6vany8nIu6zGIawABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQABAACMIQCN2rBhg0aMGKHk5GR5PB4tX77c7ZEAAECIEIBGVVVVqVevXpo1a5bbowAAgBCLcHsAuCMnJ0c5OTlujwEAAFzACiAAAIAxrACiQfx+v/x+f+B2RUWFi9MAAIDvghVANEhhYaF8Pl9gS01NdXskAABwhQhANMjUqVNVXl4e2EpLS90eCQAAXCFOAaNBvF6vvF6v22MAAICrgAA06vTp09q7d2/g9v79+7Vt2zbFxcUpLS3NxckAAEBjIwCNKikp0R133BG4PWXKFElSXl6e5s+f79JUAAAgFAhAowYNGiTHcdweAwAAuIAPgQAAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDABpVWFioPn36KCYmRomJiRo1apR2797t9lgAACAECECj1q9fr4KCAm3atEmrV6/WuXPnNGTIEFVVVbk9GgAAaGQRbg8Ad7zzzjtBt+fPn6/ExERt2bJFAwYMcGkqAAAQCgQgJEnl5eWSpLi4uHrv9/v98vv9gdsVFRUhmQsAAFx9nAKGampqNHnyZGVnZ6t79+71HlNYWCifzxfYUlNTQzwlAAC4WghAqKCgQDt37tTixYsveMzUqVNVXl4e2EpLS0M4IQAAuJo4BWzcxIkTtXLlSm3YsEEpKSkXPM7r9crr9YZwMgAA0FgIQKMcx9ETTzyhZcuWad26dWrXrp3bIwEAgBAhAI0qKCjQokWL9OabbyomJkZffPGFJMnn8yk6Otrl6QAAQGPiGkCjZs+erfLycg0aNEhJSUmBbcmSJW6PBgAAGhkrgEY5juP2CAAAwCWsAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhDAAIAABhD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", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - }, - { - "data": { - "text/plain": [ - "" - ] - }, - "execution_count": 16, - "metadata": {}, - "output_type": "execute_result" - }, - { - "data": { - "application/vnd.jupyter.widget-view+json": { - "model_id": "d175c18e06ae402bb8df57910873ccbf", - "version_major": 2, - "version_minor": 0 - }, - "image/png": "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+OKLyx6D/5BpbxSF3VE19kY1uQI4gvbt2xebN2+OuXPnDp0bNWpUzJ07N55//vkSJzs6+vr6IiJi3LhxJU8yvLq6uuKqq6464M+xWTz++OMxc+bMuO6662LChAkxY8aMuP/++8seK7VseyPC7qgae6OaBOAIeuutt2JgYCAmTpx4wPmJEyfGzp07S5rq6BgcHIxFixbFnDlzYtq0aWWPM2xWrlwZW7ZsiZ6enrJHOSpef/31WLZsWZx55pmxevXquPnmm+PWW2+NBx54oOzR0sq0NyLsjiqyN6qptewBaE5dXV2xbdu2eO6558oeZdj09vbGbbfdFmvWrImxY8eWPc5RMTg4GDNnzow777wzIiJmzJgR27Zti3vuuScWLlxY8nRkYHdUj71RTa4AjqCTTjopRo8eHbt27Trg/K5du+Lkk08uaarhd8stt8STTz4Zv/vd72LKlClljzNsNm/eHLt3747zzz8/Wltbo7W1NdavXx8//OEPo7W1NQYGBsoe8YhNmjQppk6desC5s88+O7Zv317SRGTZGxF2R1XZG9UkAEfQmDFj4oILLoi1a9cOnRscHIy1a9fG7NmzS5xseBRFEbfcckusWrUqfvvb38bpp59e9kjD6vLLL48XX3wxtm7dOnTMnDkzFixYEFu3bo3Ro0eXPeIRmzNnzvt+/MYrr7wSp556akkT0ex7I8LuqPrusDcqquzvQslm5cqVRa1WK1asWFG89NJLxVe+8pXi+OOPL3bu3Fn2aEfs5ptvLjo6Oop169YVb7755tDxr3/9q+zRjppm+k6+oiiKF154oWhtbS2+853vFK+++mrx0EMPFccdd1zx4IMPlj1aas28N4rC7qg6e6OaBGAJfvSjHxWnnHJKMWbMmOKiiy4qNmzYUPZIwyIiDnosX7687NGOmmZa4v/2xBNPFNOmTStqtVpx1llnFffdd1/ZI1E0794oCrujGdgb1dNSFEVRzrVHAADK4DOAAADJCEAAgGQEIABAMgIQACAZAQgAkIwABABIRgACACQjAAEAkhGAAADJCEAAgGQEIABAMgIQACAZAQgAkIwABABIRgACACQjAAEAkhGAAADJCEAAgGQEIABAMgIQACAZAQgAkIwABABIRgACACQjAAEAkhGAAADJCEAAgGQEIABAMgIQACAZAQgAkIwABABIRgACACQjAAEAkhGAAADJCEAAgGQEIABAMgIQACAZAQgAkIwABABIRgACACQjAAEAkhGAAADJCEAAgGQEIABAMgIQACAZAQgAkIwABABIRgACACQjAAEAkhGAAADJCEAAgGQEIABAMgIQACAZAQgAkIwABABIRgACACQjAAEAkhGAAADJCEAAgGQEIABAMgIQACAZAQgAkIwABABIRgACACQjAAEAkhGAAADJCEAAgGQEIABAMgIQACAZAQgAkIwABABIRgACACQjAAEAkhGAAADJCEAAgGQEIABAMgIQACAZAQgAkIwABABIRgACACQjAAEAkhGAAADJCEAAgGQEIABAMgIQACAZAQgAkIwABABIRgACACQjAAEAkhGAAADJCEAAgGQEIABAMgIQACAZAQgAkIwABABIRgACACQjAAEAkhGAAADJCEAAgGQEIABAMgIQACAZAQgAkIwABABIRgACACTz31c0oPcs+vDuAAAAAElFTkSuQmCC", - "text/html": [ - "\n", - "
\n", - "
\n", - " Figure\n", - "
\n", - " \n", - "
\n", - " " - ], - "text/plain": [ - "Canvas(toolbar=Toolbar(toolitems=[('Home', 'Reset original view', 'home', 'home'), ('Back', 'Back to previous …" - ] - }, - "metadata": {}, - "output_type": "display_data" - } - ], + "outputs": [], "source": [ "params = OverfocusParams(\n", " overfocus=0.0001,\n", @@ -1151,9 +1175,9 @@ ], "metadata": { "kernelspec": { - "display_name": "Python (calib311)", + "display_name": "Python 3 (ipykernel)", "language": "python", - "name": "calib311" + "name": "python3" }, "language_info": { "codemirror_mode": { @@ -1165,7 +1189,7 @@ "name": "python", "nbconvert_exporter": "python", "pygments_lexer": "ipython3", - "version": "3.11.5" + "version": "3.13.5" } }, "nbformat": 4, diff --git a/pyproject.toml b/pyproject.toml index 9624daa..108d8cb 100644 --- a/pyproject.toml +++ b/pyproject.toml @@ -7,16 +7,15 @@ name = "microscope-calibration" description = "Tools to calibrate a microscope" license = {file = "LICENSE"} keywords = ["microscopy", "LiberTEM", "TEM", "STEM"] -requires-python = ">=3.9" +requires-python = ">=3.10" dynamic = ["version", "readme"] dependencies = [ "numpy", "libertem", "typing-extensions", - "temgymbasic@git+https://github.com/TemGym/TemGym@c7a851ce2d6719acc47d36d31d91df27b1e9590b", + "temgym_core @ https://github.com/TemGym/TemGymCore/archive/refs/heads/main.zip", # Minimum constraints of numba for all Python versions we support # See https://numba.readthedocs.io/en/stable/release-notes-overview.html - "numba>=0.53;python_version < '3.10'", "numba>=0.55;python_version < '3.11'", "numba>=0.57;python_version < '3.12'", "numba>=0.59;python_version < '3.13'", @@ -30,10 +29,12 @@ dependencies = [ # to make tests pass for the time being # TODO release pin ASAP "scipy<1.16", + "jax", + "optax", + "optimistix", ] classifiers = [ "Programming Language :: Python :: 3", - "Programming Language :: Python :: 3.9", "Programming Language :: Python :: 3.10", "Programming Language :: Python :: 3.11", "Programming Language :: Python :: 3.12", @@ -49,6 +50,7 @@ repository = "https://github.com/LiberTEM/Microscope-Calibration" [project.optional-dependencies] test = ["pytest", "pytest-cov"] examples = ["ipywidgets", "libertem[bqplot]", "jupyter-ui-poll"] +diffraction = ["pycifrw", "diffpy.structure", "orix", "diffsims"] [tool.setuptools.dynamic] version = {attr = "microscope_calibration.__version__"} diff --git a/src/microscope_calibration/common/model.py b/src/microscope_calibration/common/model.py new file mode 100644 index 0000000..4f0b429 --- /dev/null +++ b/src/microscope_calibration/common/model.py @@ -0,0 +1,705 @@ +from typing import Optional, NamedTuple, Union +from collections import OrderedDict + +import jax; jax.config.update("jax_enable_x64", True) # noqa +import jax_dataclasses as jdc +import jax.numpy as jnp +from jax.errors import TracerBoolConversionError + +from temgym_core.ray import Ray +from temgym_core import PixelYX, CoordXY +from temgym_core.components import Component, Plane, Descanner, Scanner, DescanError +from temgym_core.run import run_iter +from temgym_core.source import Source, PointSource +from temgym_core.propagator import Propagator, FreeSpaceParaxial + + +# Jax-compatible versions of libertem.corrections.coordinates functions +def scale(factor): + return jnp.eye(2) * factor + + +def rotate(radians): + # https://en.wikipedia.org/wiki/Rotation_matrix + # y, x instead of x, y + radians = jnp.astype(radians, jnp.float64) + return jnp.array( + [(jnp.cos(radians), jnp.sin(radians)), (-jnp.sin(radians), jnp.cos(radians))] + ) + + +# The flip_factor is introduced to make it differentiable +def flip_y(flip_factor: float = -1.0): + return jnp.array([(flip_factor, 0), (0, 1)], dtype=jnp.float64) + + +def identity(): + return jnp.eye(2, dtype=jnp.float64) + + +def scale_rotate_flip(mat: jnp.ndarray): + """ + Deconstruct a matrix generated with scale() @ rotate() @ flip_y() + into the individual parameters + """ + scale_y = jnp.linalg.norm(mat[:, 0]) + scale_x = jnp.linalg.norm(mat[:, 1]) + if not jnp.allclose(scale_y, scale_x): + raise ValueError(f"y scale {scale_y} and x scale {scale_x} are different.") + + scan_rot_flip = mat / scale_y + # 2D cross product + flip_factor = ( + scan_rot_flip[0, 0] * scan_rot_flip[1, 1] + - scan_rot_flip[0, 1] * scan_rot_flip[1, 0] + ) + # undo flip_y + rot = scan_rot_flip.copy() + rot = rot.at[:, 0].set(rot[:, 0] * flip_factor) + + angle1 = jnp.arctan2(-rot[1, 0], rot[0, 0]) + angle2 = jnp.arctan2(rot[0, 1], rot[1, 1]) + + # So far not reached in tests since inconsistencies are caught as shear before + if not jnp.allclose( + jnp.array((jnp.sin(angle1), jnp.cos(angle1))), + jnp.array((jnp.sin(angle2), jnp.cos(angle2))), + ): + raise ValueError( + f"Rotation angle 1 {angle1} and rotation angle 2 {angle2} are inconsistent." + ) + + return (scale_y, angle1, flip_factor) + + +# TODO use LiberTEM-schema later +@jdc.pytree_dataclass +class Parameters4DSTEM: + overfocus: float # m + scan_pixel_pitch: float # m + scan_center: PixelYX + scan_rotation: float # rad + camera_length: float # m + detector_pixel_pitch: float # m + detector_center: PixelYX + semiconv: float # rad + flip_factor: float # 1.: no flip; -1.: flip + descan_error: DescanError = DescanError() + detector_rotation: float = 0.0 # rad + + def derive( + self, + overfocus: float | None = None, # m + scan_pixel_pitch: float | None = None, # m + scan_center: PixelYX | None = None, + scan_rotation: float | None = None, # rad + camera_length: float | None = None, # m + detector_pixel_pitch: float | None = None, # m + detector_center: PixelYX | None = None, + detector_rotation: float | None = None, # rad + semiconv: float | None = None, # rad + flip_y: bool | None = None, + flip_factor: float | None = None, + descan_error: DescanError | None = None, + ) -> "Parameters4DSTEM": + if flip_factor is not None: + assert flip_y is None + if flip_y is not None: + flip_factor = -1. if flip_y else 1. + + return Parameters4DSTEM( + overfocus=overfocus if overfocus is not None else self.overfocus, + scan_pixel_pitch=( + scan_pixel_pitch + if scan_pixel_pitch is not None + else self.scan_pixel_pitch + ), + scan_center=scan_center if scan_center is not None else self.scan_center, + scan_rotation=scan_rotation + if scan_rotation is not None + else self.scan_rotation, + camera_length=camera_length + if camera_length is not None + else self.camera_length, + detector_pixel_pitch=( + detector_pixel_pitch + if detector_pixel_pitch is not None + else self.detector_pixel_pitch + ), + detector_center=( + detector_center if detector_center is not None else self.detector_center + ), + detector_rotation=( + detector_rotation + if detector_rotation is not None + else self.detector_rotation + ), + semiconv=semiconv if semiconv is not None else self.semiconv, + flip_factor=flip_factor if flip_factor is not None else self.flip_factor, + descan_error=descan_error + if descan_error is not None + else self.descan_error, + ) + + def normalize_types(self): + return self.derive( + overfocus=float(self.overfocus), + scan_pixel_pitch=float(self.scan_pixel_pitch), + scan_center=PixelYX( + y=float(self.scan_center.y), + x=float(self.scan_center.x), + ), + scan_rotation=float(self.scan_rotation), + camera_length=float(self.camera_length), + detector_pixel_pitch=float(self.detector_pixel_pitch), + detector_center=PixelYX( + y=float(self.detector_center.y), + x=float(self.detector_center.x), + ), + detector_rotation=float(self.detector_rotation), + semiconv=float(self.semiconv), + flip_factor=float(self.flip_factor), + descan_error=DescanError( + pxo_pyi=float(self.descan_error.pxo_pyi), + pyo_pyi=float(self.descan_error.pyo_pyi), + pxo_pxi=float(self.descan_error.pxo_pxi), + pyo_pxi=float(self.descan_error.pyo_pxi), + sxo_pyi=float(self.descan_error.sxo_pyi), + syo_pyi=float(self.descan_error.syo_pyi), + sxo_pxi=float(self.descan_error.sxo_pxi), + syo_pxi=float(self.descan_error.syo_pxi), + offpxi=float(self.descan_error.offpxi), + offpyi=float(self.descan_error.offpyi), + offsxi=float(self.descan_error.offsxi), + offsyi=float(self.descan_error.offsyi), + ), + ) + + def adjust_scan_rotation(self, scan_rotation: float) -> "Parameters4DSTEM": + """ + Adjust the scan rotation while keeping the effective descan error + compensation the same. + + This allows first compensating descan error and then adjusting other parameters. + """ + de = self.descan_error + angle = scan_rotation - self.scan_rotation + # Rotate the input direction + pxo_pyi, pxo_pxi = rotate(angle) @ jnp.array((de.pxo_pyi, de.pxo_pxi)) + pyo_pyi, pyo_pxi = rotate(angle) @ jnp.array((de.pyo_pyi, de.pyo_pxi)) + sxo_pyi, sxo_pxi = rotate(angle) @ jnp.array((de.sxo_pyi, de.sxo_pxi)) + syo_pyi, syo_pxi = rotate(angle) @ jnp.array((de.syo_pyi, de.syo_pxi)) + new_de = DescanError( + pxo_pyi=pxo_pyi, + pyo_pyi=pyo_pyi, + pxo_pxi=pxo_pxi, + pyo_pxi=pyo_pxi, + sxo_pyi=sxo_pyi, + syo_pyi=syo_pyi, + sxo_pxi=sxo_pxi, + syo_pxi=syo_pxi, + offpxi=de.offpxi, + offpyi=de.offpyi, + offsxi=de.offsxi, + offsyi=de.offsyi, + ) + return self.derive( + scan_rotation=scan_rotation, + descan_error=new_de, + ) + + def adjust_scan_pixel_pitch(self, scan_pixel_pitch: float) -> "Parameters4DSTEM": + """ + Adjust the scan pixel pitch while keeping the effective descan error + compensation the same. + + This allows first compensating descan error and then adjusting other parameters. + """ + de = self.descan_error + ratio = self.scan_pixel_pitch / scan_pixel_pitch + + new_de = DescanError( + pxo_pyi=de.pxo_pyi * ratio, + pyo_pyi=de.pyo_pyi * ratio, + pxo_pxi=de.pxo_pxi * ratio, + pyo_pxi=de.pyo_pxi * ratio, + sxo_pyi=de.sxo_pyi * ratio, + syo_pyi=de.syo_pyi * ratio, + sxo_pxi=de.sxo_pxi * ratio, + syo_pxi=de.syo_pxi * ratio, + offpxi=de.offpxi, + offpyi=de.offpyi, + offsxi=de.offsxi, + offsyi=de.offsyi, + ) + return self.derive( + scan_pixel_pitch=scan_pixel_pitch, + descan_error=new_de, + ) + + def adjust_scan_center(self, scan_center: PixelYX) -> "Parameters4DSTEM": + # Compensate effect of different scan centers with + # constant offsets of the descanner. We simply measure how much these offsets should be + # by comparing rays along the optical axis + res1 = trace(self, scan_pos=self.scan_center, source_dx=0.0, source_dy=0.0) + res2 = trace(self, scan_pos=scan_center, source_dx=0.0, source_dy=0.0) + + de = self.descan_error + offpxi = de.offpxi + res2["descanner"].ray.x - res1["descanner"].ray.x + offpyi = de.offpyi + res2["descanner"].ray.y - res1["descanner"].ray.y + offsxi = de.offsxi + res2["descanner"].ray.dx - res1["descanner"].ray.dx + offsyi = de.offsyi + res2["descanner"].ray.dy - res1["descanner"].ray.dy + + new_de = DescanError( + pxo_pyi=de.pxo_pyi, + pyo_pyi=de.pyo_pyi, + pxo_pxi=de.pxo_pxi, + pyo_pxi=de.pyo_pxi, + sxo_pyi=de.sxo_pyi, + syo_pyi=de.syo_pyi, + sxo_pxi=de.sxo_pxi, + syo_pxi=de.syo_pxi, + offpxi=offpxi, + offpyi=offpyi, + offsxi=offsxi, + offsyi=offsyi, + ) + return self.derive( + scan_center=scan_center, + descan_error=new_de, + ) + + def adjust_detector_rotation(self, detector_rotation: float) -> "Parameters4DSTEM": + de = self.descan_error + angle = detector_rotation - self.detector_rotation + # rotate the output direction + pyo_pyi, pxo_pyi = rotate(angle) @ jnp.array((de.pyo_pyi, de.pxo_pyi)) + pyo_pxi, pxo_pxi = rotate(angle) @ jnp.array((de.pyo_pxi, de.pxo_pxi)) + syo_pyi, sxo_pyi = rotate(angle) @ jnp.array((de.syo_pyi, de.sxo_pyi)) + syo_pxi, sxo_pxi = rotate(angle) @ jnp.array((de.syo_pxi, de.sxo_pxi)) + offpyi, offpxi = rotate(angle) @ jnp.array((de.offpyi, de.offpxi)) + offsyi, offsxi = rotate(angle) @ jnp.array((de.offsyi, de.offsxi)) + new_de = DescanError( + pxo_pyi=pxo_pyi, + pyo_pyi=pyo_pyi, + pxo_pxi=pxo_pxi, + pyo_pxi=pyo_pxi, + sxo_pyi=sxo_pyi, + syo_pyi=syo_pyi, + sxo_pxi=sxo_pxi, + syo_pxi=syo_pxi, + offpxi=offpxi, + offpyi=offpyi, + offsxi=offsxi, + offsyi=offsyi, + ) + return self.derive( + detector_rotation=detector_rotation, + descan_error=new_de, + ) + + def adjust_flip_factor(self, flip_factor: float) -> "Parameters4DSTEM": + # Some import gymnastic to keep the naming clean + from .model import flip_y + + de = self.descan_error + angle = self.detector_rotation + + if flip_factor != self.flip_factor: + # Rotate into detector directions, flip, then rotate back + trans = rotate(angle) @ flip_y(flip_factor/self.flip_factor) @ rotate(-angle) + # transform the output direction + pyo_pyi, pxo_pyi = trans @ jnp.array((de.pyo_pyi, de.pxo_pyi)) + pyo_pxi, pxo_pxi = trans @ jnp.array((de.pyo_pxi, de.pxo_pxi)) + syo_pyi, sxo_pyi = trans @ jnp.array((de.syo_pyi, de.sxo_pyi)) + syo_pxi, sxo_pxi = trans @ jnp.array((de.syo_pxi, de.sxo_pxi)) + offpyi, offpxi = trans @ jnp.array((de.offpyi, de.offpxi)) + offsyi, offsxi = trans @ jnp.array((de.offsyi, de.offsxi)) + new_de = DescanError( + pxo_pyi=pxo_pyi, + pyo_pyi=pyo_pyi, + pxo_pxi=pxo_pxi, + pyo_pxi=pyo_pxi, + sxo_pyi=sxo_pyi, + syo_pyi=syo_pyi, + sxo_pxi=sxo_pxi, + syo_pxi=syo_pxi, + offpxi=offpxi, + offpyi=offpyi, + offsxi=offsxi, + offsyi=offsyi, + ) + return self.derive( + flip_factor=flip_factor, + descan_error=new_de, + ) + else: + return self + + def adjust_detector_center(self, detector_center: PixelYX) -> "Parameters4DSTEM": + cls = Model4DSTEM + de = self.descan_error + zero = PixelYX(0, 0) + model1 = cls.build(params=self, scan_pos=zero) + model2 = cls.build( + params=self.derive( + detector_center=detector_center, + ), + scan_pos=zero, + ) + physical_1 = model1.detector_to_real(zero) + physical_2 = model2.detector_to_real(zero) + offpyi = de.offpyi + physical_2.y - physical_1.y + offpxi = de.offpxi + physical_2.x - physical_1.x + new_de = DescanError( + pxo_pyi=de.pxo_pyi, + pyo_pyi=de.pyo_pyi, + pxo_pxi=de.pxo_pxi, + pyo_pxi=de.pyo_pxi, + sxo_pyi=de.sxo_pyi, + syo_pyi=de.syo_pyi, + sxo_pxi=de.sxo_pxi, + syo_pxi=de.syo_pxi, + offpxi=offpxi, + offpyi=offpyi, + offsxi=de.offsxi, + offsyi=de.offsyi, + ) + return self.derive( + detector_center=detector_center, + descan_error=new_de, + ) + + def adjust_detector_pixel_pitch( + self, detector_pixel_pitch: float + ) -> "Parameters4DSTEM": + de = self.descan_error + ratio = detector_pixel_pitch / self.detector_pixel_pitch + + new_de = DescanError( + pxo_pyi=de.pxo_pyi * ratio, + pyo_pyi=de.pyo_pyi * ratio, + pxo_pxi=de.pxo_pxi * ratio, + pyo_pxi=de.pyo_pxi * ratio, + sxo_pyi=de.sxo_pyi * ratio, + syo_pyi=de.syo_pyi * ratio, + sxo_pxi=de.sxo_pxi * ratio, + syo_pxi=de.syo_pxi * ratio, + offpxi=de.offpxi * ratio, + offpyi=de.offpyi * ratio, + offsxi=de.offsxi * ratio, + offsyi=de.offsyi * ratio, + ) + return self.derive( + detector_pixel_pitch=detector_pixel_pitch, + descan_error=new_de, + ) + + def adjust_camera_length(self, camera_length: float) -> "Parameters4DSTEM": + de = self.descan_error + ratio = self.camera_length / camera_length + + new_de = DescanError( + pxo_pyi=de.pxo_pyi, + pyo_pyi=de.pyo_pyi, + pxo_pxi=de.pxo_pxi, + pyo_pxi=de.pyo_pxi, + sxo_pyi=de.sxo_pyi * ratio, + syo_pyi=de.syo_pyi * ratio, + sxo_pxi=de.sxo_pxi * ratio, + syo_pxi=de.syo_pxi * ratio, + offpxi=de.offpxi, + offpyi=de.offpyi, + offsxi=de.offsxi * ratio, + offsyi=de.offsyi * ratio, + ) + return self.derive( + camera_length=camera_length, + descan_error=new_de, + ) + + +# "Layer" of a beam passing through a model +class ResultSection(NamedTuple): + component: Union[Component, Source, Propagator] + ray: Ray + sampling: Optional[dict] = None + + +# Layer stack, result of tracing a ray through a model +Result4DSTEM = OrderedDict[str, ResultSection] + + +@jdc.pytree_dataclass +class Model4DSTEM: + source: PointSource + scanner: Scanner + specimen: Plane + descanner: Descanner + detector: Plane + + _scan_to_real: jnp.ndarray # 2x2 matrix from libertem.corrections.coordinates + _real_to_scan: jnp.ndarray # 2x2 matrix from libertem.corrections.coordinates + _detector_to_real: jnp.ndarray # 2x2 matrix from libertem.corrections.coordinates + _real_to_detector: jnp.ndarray # 2x2 matrix from libertem.corrections.coordinates + + scan_center: PixelYX + detector_center: PixelYX + + @property + def overfocus(self) -> float: + return self.specimen.z - self.source.z + + @property + def camera_length(self) -> float: + return self.detector.z - self.specimen.z + + def scan_to_real(self, pixels: PixelYX, _one: float = 1.0) -> CoordXY: + (y, x) = self._scan_to_real @ jnp.array( + (pixels.y - self.scan_center.y * _one, pixels.x - self.scan_center.x * _one) + ) + return CoordXY(y=y, x=x) + + def real_to_scan(self, coords: CoordXY, _one: float = 1.0) -> PixelYX: + (y, x) = self._real_to_scan @ jnp.array((coords.y, coords.x)) + return PixelYX(y=y + self.scan_center.y * _one, x=x + self.scan_center.x * _one) + + def detector_to_real(self, pixels: PixelYX, _one: float = 1.0) -> CoordXY: + (y, x) = self._detector_to_real @ jnp.array( + ( + pixels.y - self.detector_center.y * _one, + pixels.x - self.detector_center.x * _one, + ) + ) + return CoordXY(y=y, x=x) + + def real_to_detector(self, coords: CoordXY, _one: float = 1.0) -> PixelYX: + (y, x) = self._real_to_detector @ jnp.array((coords.y, coords.x)) + return PixelYX( + y=y + self.detector_center.y * _one, x=x + self.detector_center.x * _one + ) + + @classmethod + def build( + cls, + params: Parameters4DSTEM, + scan_pos: PixelYX, + specimen: Optional[Component] = None, + ) -> "Model4DSTEM": + scan_to_real = rotate(params.scan_rotation) @ scale(params.scan_pixel_pitch) + real_to_scan = scale(1 / params.scan_pixel_pitch) @ rotate( + -params.scan_rotation + ) + scan_y, scan_x = scan_to_real @ jnp.array( + ( + scan_pos.y - params.scan_center.y, + scan_pos.x - params.scan_center.x, + ) + ) + detector_to_real = ( + scale(params.detector_pixel_pitch) + @ rotate(params.detector_rotation) + @ flip_y(flip_factor=params.flip_factor) + ) + real_to_detector = ( + flip_y(flip_factor=1 / params.flip_factor) + @ rotate(-params.detector_rotation) + @ scale(1 / params.detector_pixel_pitch) + ) + if specimen is None: + specimen = Plane(z=params.overfocus) + else: + try: + # FIXME better solution later? + assert jnp.allclose(specimen.z, params.overfocus) + except TracerBoolConversionError: + pass + return cls( + source=PointSource(z=0, semi_conv=params.semiconv), + _scan_to_real=scan_to_real, + _real_to_scan=real_to_scan, + _detector_to_real=detector_to_real, + _real_to_detector=real_to_detector, + scanner=Scanner(z=params.overfocus, scan_pos_x=scan_x, scan_pos_y=scan_y), + specimen=specimen, + descanner=Descanner( + z=params.overfocus, + scan_pos_x=scan_x, + scan_pos_y=scan_y, + descan_error=params.descan_error, + ), + detector=Plane(z=params.overfocus + params.camera_length), + scan_center=params.scan_center, + detector_center=params.detector_center, + ) + + @property + def params(self) -> Parameters4DSTEM: + scan_scale, scan_rotation, scan_flip = scale_rotate_flip(self._scan_to_real) + # FIXME assert close to 1 + # assert scan_flip is False + detector_scale, detector_rotation, detector_flip = scale_rotate_flip( + self._detector_to_real + ) + assert jnp.allclose(detector_rotation, 0.0) + return Parameters4DSTEM( + overfocus=self.specimen.z - self.source.z, + scan_pixel_pitch=scan_scale, + scan_center=self.scan_center, + scan_rotation=scan_rotation, + camera_length=self.detector.z - self.specimen.z, + detector_pixel_pitch=detector_scale, + detector_center=self.detector_center, + semiconv=self.source.semi_conv, + flip_factor=detector_flip, + descan_error=self.descanner.descan_error, + ) + + @property + def scan_pos(self): + y = self.scanner.scan_pos_y + x = self.scanner.scan_pos_x + + assert self.scanner.scan_tilt_y == 0.0 + assert self.scanner.scan_tilt_x == 0.0 + + assert self.scanner.scan_pos_y == self.descanner.scan_pos_y + assert self.scanner.scan_pos_x == self.descanner.scan_pos_x + assert self.descanner.scan_tilt_y == 0.0 + assert self.descanner.scan_tilt_x == 0.0 + + return self.real_to_scan(CoordXY(x=x, y=y)) + + def make_source_ray( + self, source_dx: float, source_dy: float, _one: float = 1.0 + ) -> ResultSection: + ray = Ray( + x=self.source.offset_xy.x, + y=self.source.offset_xy.y, + dx=source_dx, + dy=source_dy, + z=self.source.z, + pathlength=0.0, + _one=_one, + ) + return ResultSection(component=self.source, ray=ray) + + @property + def components(self): + return (self.source, self.scanner, self.specimen, self.descanner, self.detector) + + def trace(self, ray: Ray) -> Result4DSTEM: + result = OrderedDict() + + # run_iter() currently inserts a propagation if two subsequent + # components have a non-zero distance, but skips for equal z. We + # therefore check meticulously that we are actually getting the + # components and rays we expect. Furthermore, we make sure that our + # result ALWAYS has the same schema independent of parameters by + # inserting gaps of zero length manually. + run_result = list(run_iter(ray=ray, components=self.components)) + + # skip the first propagation, which should be zero distance + comp, r = run_result.pop(0) + try: + assert isinstance(comp, Propagator) + assert comp.distance == 0.0 + assert r == ray + except TracerBoolConversionError: + pass + + comp, r = run_result.pop(0) + try: + assert comp == self.source + assert r == ray + except TracerBoolConversionError: + pass + result["source"] = ResultSection(component=comp, ray=r) + + comp, r = run_result.pop(0) + assert isinstance(comp, Propagator) + assert isinstance(comp.propagator, FreeSpaceParaxial) + assert isinstance(r, Ray) + result["overfocus"] = ResultSection(component=comp, ray=r) + + comp, r = run_result.pop(0) + try: + assert comp == self.scanner + assert isinstance(r, Ray) + except TracerBoolConversionError: + pass + result["scanner"] = ResultSection(component=comp, ray=r) + + # Skip zero distance propagation between scanner and specimen + comp, r = run_result.pop(0) + try: + assert isinstance(comp, Propagator) + assert comp.distance == 0.0 + assert isinstance(r, Ray) + assert r == result["scanner"].ray + except TracerBoolConversionError: + pass + + comp, r = run_result.pop(0) + try: + assert comp == self.specimen + assert isinstance(r, Ray) + except TracerBoolConversionError: + pass + scan_px = self.real_to_scan(CoordXY(x=r.x, y=r.y), _one=ray._one) + result["specimen"] = ResultSection( + component=comp, + ray=r, + sampling={"scan_px": scan_px}, + ) + + # Skip zero distance propagation between specimen and descanner + comp, r = run_result.pop(0) + try: + assert isinstance(comp, Propagator) + assert comp.distance == 0.0 + assert r == result["specimen"].ray + except TracerBoolConversionError: + pass + comp, r = run_result.pop(0) + try: + assert comp == self.descanner + assert isinstance(r, Ray) + except TracerBoolConversionError: + pass + result["descanner"] = ResultSection(component=comp, ray=r) + + comp, r = run_result.pop(0) + assert isinstance(comp, Propagator) + assert isinstance(comp.propagator, FreeSpaceParaxial) + assert isinstance(r, Ray) + result["camera_length"] = ResultSection(component=comp, ray=r) + + comp, r = run_result.pop(0) + try: + assert comp == self.detector + assert isinstance(r, Ray) + except TracerBoolConversionError: + pass + detector_px = self.real_to_detector(CoordXY(x=r.x, y=r.y), _one=ray._one) + result["detector"] = ResultSection( + component=comp, + ray=r, + sampling={"detector_px": detector_px}, + ) + + assert len(run_result) == 0 + return result + + +def trace( + params: Parameters4DSTEM, + scan_pos: PixelYX, + source_dx: float, + source_dy: float, + specimen: Component | None = None, + _one: float = 1.0, +) -> Result4DSTEM: + model = Model4DSTEM.build(params, scan_pos=scan_pos, specimen=specimen) + ray = model.make_source_ray(source_dy=source_dy, source_dx=source_dx, _one=_one).ray + return model.trace(ray) diff --git a/src/microscope_calibration/common/stem_overfocus.py b/src/microscope_calibration/common/stem_overfocus.py index 1b3b0da..a8336ef 100644 --- a/src/microscope_calibration/common/stem_overfocus.py +++ b/src/microscope_calibration/common/stem_overfocus.py @@ -1,98 +1,452 @@ -from typing import TypedDict, TYPE_CHECKING +from typing import Callable, Optional +import jax; jax.config.update("jax_enable_x64", True) # noqa +import jax.numpy as jnp import numpy as np -from temgymbasic.model import STEMModel import numba -if TYPE_CHECKING: - from libertem.common import Shape - - -class OverfocusParams(TypedDict): - overfocus: float # m - scan_pixel_size: float # m - camera_length: float # m - detector_pixel_size: float # m - semiconv: float # rad - cy: float - cx: float - scan_rotation: float # deg - flip_y: bool - - -def make_model(params: OverfocusParams, dataset_shape: 'Shape') -> STEMModel: - model = STEMModel() - model.set_stem_params( - overfocus=params['overfocus'], - semiconv_angle=params['semiconv'], - scan_step_yx=(params['scan_pixel_size'], params['scan_pixel_size']), - scan_shape=dataset_shape.nav.to_tuple(), - camera_length=params['camera_length'], - ) - model.detector.pixel_size = params['detector_pixel_size'] - model.detector.shape = dataset_shape.sig.to_tuple() - model.detector.flip_y = params['flip_y'] - model.detector.rotation = params['scan_rotation'] - model.detector.set_center_px((params['cy'], params['cx'])) - return model - - -def get_translation_matrix(model: STEMModel) -> np.ndarray: - yxs = ( - (0, 0), - (model.sample.scan_shape[0], model.sample.scan_shape[1]), - (0, model.sample.scan_shape[1]), - (model.sample.scan_shape[0], 0), - ) - num_rays = 7 - - a = [] - b = [] - - for yx in yxs: - for rays in model.scan_point_iter(num_rays=num_rays, yx=yx): - if rays.location is model.sample: - yyxx = np.stack( - model.sample.on_grid(rays, as_int=False), - axis=-1, +from microscope_calibration.common.model import ( + Parameters4DSTEM, + PixelYX, + CoordXY, + DescanError, + Scanner, + trace, +) + + +# Define here to facilitate mocking in order to test +# the code that checks for float64 support in JAX as a probable cause +# for discrepancies +target_dtype = jnp.float64 + +CoordMappingT = Callable[[CoordXY], PixelYX] + + +class FittingError(RuntimeError): + pass + + +def _do_lstsq(input_samples, output_samples): + output_samples = np.array(output_samples) + input_samples = np.array(input_samples) + + x, residuals, rank, s = np.linalg.lstsq(input_samples, output_samples) + + # FIXME include test also based on singular values + if len(residuals) != output_samples.shape[1]: + raise FittingError( + "Mismatch between residuals and samples, likely ill-posed or sth." + ) + # Confirm that the solution is exact, in particular that + # the model is linear + assert rank == input_samples.shape[1] + + no_residuals = np.allclose(residuals, 0.0, rtol=1e-12, atol=1e-11) + + test_samples = np.empty_like(output_samples) + for i in range(len(input_samples)): + test_samples[i] = input_samples[i] @ x + + reproduced = np.allclose(output_samples, test_samples, rtol=1e-9, atol=1e-9) + + if not (no_residuals and reproduced): + test = jnp.array((1, 2, 3), dtype=jnp.float64) + if test.dtype != target_dtype: + raise RuntimeError( + f"No float64 support activated in JAX. Downcasting to {test.dtype} is " + "leading to inaccuracies that are " + "much larger than permissible for electron optics calculations." + ) + else: + if not no_residuals: + raise RuntimeError( + f"Model seems not linear: Residuals {residuals} exceeding tolerance of 1e-12" ) - coordinates = np.tile( - np.asarray((*yx, 1)).reshape(-1, 3), - (rays.num, 1), + # Currently not sure if this can be reached in tests without also having residuals + elif not reproduced: # pragma: no cover + raise RuntimeError( # pragma: no cover + f"Discrepancies between model output {output_samples} " # pragma: no cover + f"and equivalent linear transformation {test_samples} " # pragma: no cover + "exceed tolerance of 1e-12." # pragma: no cover + ) # pragma: no cover + else: # pragma: no cover + raise RuntimeError( # pragma: no cover + "If this code is reached, logic is broken." # pragma: no cover + ) # pragma: no cover + + return x + + +def get_backward_transformation_matrix( + rec_params: Parameters4DSTEM, specimen_to_image: Optional[CoordMappingT] = None +): + """ + Calculate a transformation matrix that maps from scan position in scan pixel + coordinates and specimen pixel coordinates to detector coordinates in pixel + coordinates and tilt of the ray at the source. + + Using a matrix multiplication instead of solving for ray solutions for each + pixel greatly improves performance. + + The detector positions from the output can be used to pick the right value + from a detector frame to superimpose an image of the specimen resp. an image + of the beam-shaping aperture. The tilt can be used to determine if the beam + passes through through the microscope or if it is blocked by the + beam-shaping aperture. + + It may be possible to derive this matrix from partial derivatives of the + model. However, this is postponed for now since this matrix mixes input and + output values with respect of the model, so one may have to work with a + combination of forward and inverse derivatives. + + For the time being this method traces a number of sample rays and deduces + the mapping matrix from these samples. + """ + + # scan position y/x, source tilt y/x + test_parameters = np.array( + ( + [0.0, 0.0, 0.0, 0.0], + [100.0, 100.0, 0.0, 0.0], + [-100.0, 100.0, 0.0, 0.0], + [10.0, 0.0, 0.0, 0.0], + [0.0, 10.0, 0.0, 0.0], + [0.0, 0.0, 0.1, 0.0], + [0.0, 0.0, 0.0, 0.1], + [1.0, 1.0, 1.0, 1.0], + [1.0, 2.0, 3.0, 4.0], + ) + ) + + input_samples = [] + output_samples = [] + + for test_param_raw in test_parameters: + # We are paranoid and confirm that the model is linear + for factor in (1.0, 2.0): + test_param = test_param_raw * factor + scan_pos = PixelYX(x=test_param[0], y=test_param[1]) + source_dy = test_param[2] + source_dx = test_param[3] + res = trace( + params=rec_params, + scan_pos=scan_pos, + source_dy=source_dy, + source_dx=source_dx, + ) + + if specimen_to_image is None: + spec_px = res["specimen"].sampling["scan_px"] + else: + spec_px = specimen_to_image( + CoordXY(x=res["specimen"].ray.x, y=res["specimen"].ray.y) ) - a.append(np.concatenate((yyxx, coordinates), axis=-1)) - elif rays.location is model.detector: - yy, xx = model.detector.on_grid(rays, as_int=False) - b.append(np.stack((yy, xx), axis=-1)) + input_sample = (scan_pos.y, scan_pos.x, spec_px.y, spec_px.x, 1.0) + output_sample = ( + res["detector"].sampling["detector_px"].y, + res["detector"].sampling["detector_px"].x, + source_dy, + source_dx, + 1.0, + ) + output_samples.append(output_sample) + input_samples.append(input_sample) + + return _do_lstsq(input_samples, output_samples) + + +# Separate functions spun out to facilitate re-use of coordinate calculations +# for other purposes +@numba.njit(inline="always", cache=True) +def project_tilt_y(image_y, image_x, scan_y, scan_x, mat): + return ( + scan_y * mat[0, 2] + + scan_x * mat[1, 2] + + image_y * mat[2, 2] + + image_x * mat[3, 2] + + mat[4, 2] + ) + + +@numba.njit(inline="always", cache=True) +def project_tilt_x(image_y, image_x, scan_y, scan_x, mat): + return ( + scan_y * mat[0, 3] + + scan_x * mat[1, 3] + + image_y * mat[2, 3] + + image_x * mat[3, 3] + + mat[4, 3] + ) + - res, *_ = np.linalg.lstsq( - np.concatenate(a, axis=0), - np.concatenate(b, axis=0), - rcond=None, +@numba.njit(inline="always", cache=True) +def project_det_y(image_y, image_x, scan_y, scan_x, mat): + return ( + scan_y * mat[0, 0] + + scan_x * mat[1, 0] + + image_y * mat[2, 0] + + image_x * mat[3, 0] + + mat[4, 0] ) - return res -@numba.njit(cache=True, fastmath=True) -def project_frame(frame, scan_y, scan_x, translation_matrix, result_out): - for t_y in range(result_out.shape[0]): - for t_x in range(result_out.shape[1]): - s_y = t_y * translation_matrix[0, 0] - s_x = t_y * translation_matrix[0, 1] +@numba.njit(inline="always", cache=True) +def project_det_x(image_y, image_x, scan_y, scan_x, mat): + return ( + scan_y * mat[0, 1] + + scan_x * mat[1, 1] + + image_y * mat[2, 1] + + image_x * mat[3, 1] + + mat[4, 1] + ) + + +@numba.njit(cache=True) +def project_frame_backwards(frame, source_semiconv, mat, scan_y, scan_x, image_out): + limit = np.abs(np.tan(source_semiconv)) ** 2 + for image_y in range(image_out.shape[0]): + for image_x in range(image_out.shape[1]): + # Manually unrolled matrix-vector product to allow skipping before + # calculating all values and facilitate auto-vectorization of the + # loop + + # _one = ( + # scan_y * mat[0, 4] + scan_x * mat[1, 4] + # + det_y * mat[2, 4] + det_x * mat[3, 4] + mat[4, 4] + # ) + # assert np.allclose(_one, 1) + tilt_y = project_tilt_y(image_y, image_x, scan_y, scan_x, mat) + tilt_x = project_tilt_x(image_y, image_x, scan_y, scan_x, mat) + if np.abs(tilt_y) ** 2 + np.abs(tilt_x) ** 2 < limit: + det_y = project_det_y(image_y, image_x, scan_y, scan_x, mat) + det_x = project_det_x(image_y, image_x, scan_y, scan_x, mat) + det_y = int(np.round(det_y)) + det_x = int(np.round(det_x)) + if ( + det_y >= 0 + and det_y < frame.shape[0] + and det_x >= 0 + and det_x < frame.shape[1] + ): + image_out[image_y, image_x] += frame[det_y, det_x] - s_y += t_x * translation_matrix[1, 0] - s_x += t_x * translation_matrix[1, 1] - s_y += scan_y * translation_matrix[2, 0] - s_x += scan_y * translation_matrix[2, 1] +def get_detector_correction_matrix( + rec_params: Parameters4DSTEM, ref_params: Optional[Parameters4DSTEM] = None +): + """ + Calculate a transformation matrix that maps from scan position in scan pixel + coordinates and output detector pixel coordinates in a reference system to + detector pixel coordinates in the reconstruction system and tilt of the ray + at the source. - s_y += scan_x * translation_matrix[3, 0] - s_x += scan_x * translation_matrix[3, 1] + If no reference parameters are specified, it derives the reference from the + reconstruction parameters by setting scan rotation and descan error to 0, + and flip_factor to 1.. - s_y += translation_matrix[4, 0] - s_x += translation_matrix[4, 1] + Using a matrix multiplication instead of solving for ray solutions for each + pixel greatly improves performance. - ss_y = int(np.round(s_y)) - ss_x = int(np.round(s_x)) - if ss_y >= 0 and ss_x >= 0 and ss_y < frame.shape[0] and ss_x < frame.shape[1]: - result_out[t_y, t_x] += frame[ss_y, ss_x] + The detector positions from the output can be used to pick the right value + from a detector frame to superimpose an image of the beam-shaping aperture + or create corrected detector frames for further processing. The tilt can be + used to determine if the beam passes through through the microscope or if it + is blocked by the beam-shaping aperture, or to calculate virtual detector + images etc. + + It may be possible to derive this matrix from partial derivatives of the + model. However, this is postponed for now since this matrix mixes input and + output values with respect of the model, so one may have to work with a + combination of forward and inverse derivatives. + + For the time being this method traces a number of sample rays and deduces + the mapping matrix from these samples. + """ + + # scan position y/x, source tilt y/x + test_parameters = np.array( + ( + [0.0, 0.0, 0.0, 0.0], + [100.0, 100.0, 0.0, 0.0], + [-100.0, 100.0, 0.0, 0.0], + [10.0, 0.0, 0.0, 0.0], + [0.0, 10.0, 0.0, 0.0], + [0.0, 0.0, 0.1, 0.0], + [0.0, 0.0, 0.0, 0.1], + [1.0, 1.0, 1.0, 1.0], + [1.0, 2.0, 3.0, 4.0], + ) + ) + + input_samples = [] + output_samples = [] + + if ref_params is None: + ref_params = rec_params.derive( + scan_rotation=0.0, + flip_factor=1., + descan_error=DescanError(), + detector_rotation=rec_params.scan_rotation, + ) + + for test_param_raw in test_parameters: + # We are paranoid and confirm that the model is linear + for factor in (1.0, 2.0): + test_param = test_param_raw * factor + scan_pos = PixelYX(x=test_param[0], y=test_param[1]) + source_dy = test_param[2] + source_dx = test_param[3] + res = trace( + params=rec_params, + scan_pos=scan_pos, + source_dy=source_dy, + source_dx=source_dx, + ) + + ref_res = trace( + params=ref_params, + scan_pos=scan_pos, + source_dy=source_dy, + source_dx=source_dx, + ) + + input_sample = ( + scan_pos.y, + scan_pos.x, + ref_res["detector"].sampling["detector_px"].y, + ref_res["detector"].sampling["detector_px"].x, + 1.0, + ) + output_sample = ( + res["detector"].sampling["detector_px"].y, + res["detector"].sampling["detector_px"].x, + source_dy, + source_dx, + 1.0, + ) + output_samples.append(output_sample) + input_samples.append(input_sample) + + return _do_lstsq(input_samples, output_samples) + + +# Separate functions spun out to facilitate re-use of coordinate calculations +# for other purposes, such as corrected virtual detectors +@numba.njit(inline="always", cache=True) +def corrected_det_y(det_corr_y, det_corr_x, scan_y, scan_x, mat): + return ( + scan_y * mat[0, 0] + + scan_x * mat[1, 0] + + det_corr_y * mat[2, 0] + + det_corr_x * mat[3, 0] + + mat[4, 0] + ) + + +@numba.njit(inline="always", cache=True) +def corrected_det_x(det_corr_y, det_corr_x, scan_y, scan_x, mat): + return ( + scan_y * mat[0, 1] + + scan_x * mat[1, 1] + + det_corr_y * mat[2, 1] + + det_corr_x * mat[3, 1] + + mat[4, 1] + ) + + +@numba.njit(cache=True) +def correct_frame(frame, mat, scan_y, scan_x, detector_out): + for det_corr_y in range(detector_out.shape[0]): + for det_corr_x in range(detector_out.shape[1]): + # Manually unrolled matrix-vector product to allow skipping before + # calculating all values and facilitate auto-vectorization of the + # loop + det_y = corrected_det_y(det_corr_y, det_corr_x, scan_y, scan_x, mat) + det_x = corrected_det_x(det_corr_y, det_corr_x, scan_y, scan_x, mat) + det_y = int(np.round(det_y)) + det_x = int(np.round(det_x)) + if ( + det_y >= 0 + and det_y < frame.shape[0] + and det_x >= 0 + and det_x < frame.shape[1] + ): + detector_out[det_corr_y, det_corr_x] += frame[det_y, det_x] + + +@jax.jit +def get_diffraction_pixel_radius(params: Parameters4DSTEM, twotheta: float): + diffractor = Scanner( + z=params.overfocus, + scan_pos_x=0.0, + scan_pos_y=0.0, + scan_tilt_x=jnp.tan(twotheta), + ) + center_res = trace( + params=params, + scan_pos=PixelYX(0.0, 0.0), + source_dx=0.0, + source_dy=0.0, + ) + diff_res = trace( + params=params, + scan_pos=PixelYX(0.0, 0.0), + source_dx=0.0, + source_dy=0.0, + specimen=diffractor, + ) + return jnp.linalg.norm( + jnp.array(center_res["detector"].sampling["detector_px"]) + - jnp.array(diff_res["detector"].sampling["detector_px"]) + ) + + +@jax.jit +def get_primary_beam_radius(params: Parameters4DSTEM): + center_res = trace( + params=params, + scan_pos=PixelYX(0.0, 0.0), + source_dx=0.0, + source_dy=0.0, + ) + border_res = trace( + params=params, + scan_pos=PixelYX(0.0, 0.0), + source_dx=params.semiconv, + source_dy=0.0, + ) + return jnp.linalg.norm( + jnp.array(center_res["detector"].sampling["detector_px"]) + - jnp.array(border_res["detector"].sampling["detector_px"]) + ) + + +@jax.jit +def ring_radii(params: Parameters4DSTEM, twothetas): + pixel_radii = jnp.array( + [ + get_diffraction_pixel_radius(params=params, twotheta=twotheta) + for twotheta in twothetas + ] + ) + beam_radius = get_primary_beam_radius(params) + ri = jnp.maximum(pixel_radii - beam_radius, 0) + ro = pixel_radii + beam_radius + return ri, ro + + +@jax.jit +def get_center(params: Parameters4DSTEM, scan_pos: PixelYX): + center_res = trace( + params=params, + scan_pos=scan_pos, + source_dx=0.0, + source_dy=0.0, + ) + y = center_res["detector"].sampling["detector_px"].y + x = center_res["detector"].sampling["detector_px"].x + return PixelYX( + y=y, + x=x, + ) diff --git a/src/microscope_calibration/udf/stem_overfocus.py b/src/microscope_calibration/udf/stem_overfocus.py index 839f06c..e57b382 100644 --- a/src/microscope_calibration/udf/stem_overfocus.py +++ b/src/microscope_calibration/udf/stem_overfocus.py @@ -1,85 +1,239 @@ +import logging +from functools import lru_cache + import numpy as np + +from libertem.common.math import prod, count_nonzero from libertem.udf.base import UDF +from microscope_calibration.common.model import Parameters4DSTEM from microscope_calibration.common.stem_overfocus import ( - get_translation_matrix, OverfocusParams, make_model, project_frame + get_backward_transformation_matrix, + get_detector_correction_matrix, + project_frame_backwards, + correct_frame, + corrected_det_y, + corrected_det_x, + FittingError, ) -class OverfocusUDF(UDF): +log = logging.getLogger(__name__) + + +class BaseCorrectionUDF(UDF): def __init__( - self, overfocus_params: OverfocusParams): - super().__init__( + self, + overfocus_params: dict, + *args, + back_mat=None, + corr_mat=None, + ref_params=None, + **kwargs, + ): + """ + Params are wrapped in a dict since that allows in-place updates, see + https://github.com/LiberTEM/LiberTEM/issues/1780 + """ + # Detect changes so that the mapping matrices are recalculated + if overfocus_params["params"] != ref_params: + back_mat = self._back_mat(rec_params=overfocus_params["params"]) + corr_mat = self._corr_mat(rec_params=overfocus_params["params"]) + return super().__init__( + *args, overfocus_params=overfocus_params, + back_mat=back_mat, + corr_mat=corr_mat, + ref_params=overfocus_params["params"], + **kwargs, ) + @staticmethod + @lru_cache + def _back_mat(*args, **kwargs): + try: + return get_backward_transformation_matrix(*args, **kwargs) + except FittingError: + return None + + @staticmethod + @lru_cache + def _corr_mat(*args, **kwargs): + try: + return get_detector_correction_matrix(*args, **kwargs) + except FittingError: + return None + def _get_fov(self): fov_size_y = int(self.meta.dataset_shape.nav[0]) fov_size_x = int(self.meta.dataset_shape.nav[1]) return fov_size_y, fov_size_x - def get_task_data(self): - overfocus_params = self.params.overfocus_params - translation_matrix = get_translation_matrix( - make_model(overfocus_params, self.meta.dataset_shape) - ) - select_roi = np.zeros(self.meta.dataset_shape.nav, dtype=bool) - nav_y, nav_x = self.meta.dataset_shape.nav - select_roi[nav_y//2, nav_x//2] = True - return { - 'translation_matrix': translation_matrix, - 'select_roi': select_roi - } + @property + def has_correction(self): + return self.params.corr_mat is not None + + @property + def has_backprojection(self): + return self.params.back_mat is not None + +class OverfocusUDF(BaseCorrectionUDF): def get_result_buffers(self): fov = self._get_fov() dtype = np.result_type(self.meta.input_dtype, np.float32) return { - 'point': self.buffer(kind='nav', dtype=dtype, where='device'), - 'shifted_sum': self.buffer(kind='single', dtype=dtype, extra_shape=fov, where='device'), - 'selected': self.buffer( - kind='single', dtype=dtype, extra_shape=fov, where='device' + "backprojected_sum": self.buffer( + kind="single", dtype=dtype, extra_shape=fov, where="device" ), - 'sum': self.buffer(kind='single', dtype=dtype, extra_shape=fov, where='device'), + "corrected_point": self.buffer(kind="nav", dtype=dtype, where="device"), + "corrected_sum": self.buffer(kind="sig", dtype=dtype, where="device"), } def process_frame(self, frame): scan_y, scan_x = self.meta.coordinates[0] - center_y = self.meta.dataset_shape.nav[0] // 2 - center_x = self.meta.dataset_shape.nav[1] // 2 - overfocus_params = self.params.overfocus_params - if self.task_data.select_roi[scan_y, scan_x]: - buf = np.zeros_like(self.results.shifted_sum) - project_frame( + overfocus_params: Parameters4DSTEM = self.params.overfocus_params["params"] + if self.has_backprojection: + project_frame_backwards( frame=frame, + source_semiconv=overfocus_params.semiconv, + scan_y=scan_y, + scan_x=scan_x, + mat=self.params.back_mat, + image_out=self.results.backprojected_sum, + ) + center = overfocus_params.detector_center + if self.has_correction: + det_y = corrected_det_y( + det_corr_y=center.y, + det_corr_x=center.x, scan_y=scan_y, scan_x=scan_x, - translation_matrix=self.task_data.translation_matrix, - result_out=buf + mat=self.params.corr_mat, ) - self.results.shifted_sum += buf - self.results.selected += buf - else: # This saves allocation of buf and a copy - project_frame( + det_x = corrected_det_x( + det_corr_y=center.y, + det_corr_x=center.x, + scan_y=scan_y, + scan_x=scan_x, + mat=self.params.corr_mat, + ) + det_y = int(np.round(det_y)) + det_x = int(np.round(det_x)) + if ( + det_y >= 0 + and det_y < frame.shape[0] + and det_x >= 0 + and det_x < frame.shape[1] + ): + self.results.corrected_point[:] = frame[det_y, det_x] + + correct_frame( frame=frame, scan_y=scan_y, scan_x=scan_x, - translation_matrix=self.task_data.translation_matrix, - result_out=self.results.shifted_sum + mat=self.params.corr_mat, + detector_out=self.results.corrected_sum, ) - self.results.point[:] = frame[int(overfocus_params['cy']), int(overfocus_params['cx'])] + def merge(self, dest, src): + dest.backprojected_sum += src.backprojected_sum + dest.corrected_sum += src.corrected_sum + dest.corrected_point[:] = src.corrected_point - project_frame( - frame=frame, - scan_y=center_y, - scan_x=center_x, - translation_matrix=self.task_data.translation_matrix, - result_out=self.results.sum + +# Copied and adapted from libertem.udf.raw.PickUDF +# to allow re-using the correction basics and +# not run into inheritance complications +class CorrectedPickUDF(BaseCorrectionUDF): + def __init__( + self, + overfocus_params, + back_mat=None, + corr_mat=None, + ref_params=None, + ): + super().__init__( + overfocus_params, + back_mat=back_mat, + corr_mat=corr_mat, + ref_params=ref_params, ) + def get_preferred_input_dtype(self): + "" + return self.USE_NATIVE_DTYPE + + def get_result_buffers(self): + "" + dtype = self.meta.input_dtype + sigshape = tuple(self.meta.dataset_shape.sig) + backprojection_fov = self._get_fov() + if self.meta.roi is not None: + navsize = count_nonzero(self.meta.roi) + else: + navsize = prod(self.meta.dataset_shape.nav) + warn_limit = 2**28 + loaded_size = prod(sigshape) * navsize * np.dtype(dtype).itemsize + if loaded_size > warn_limit: + log.warning( + "CorrectedPickUDF is loading %s bytes per buffer, exceeding warning limit %s. " + "Consider using or implementing an UDF to process data on the worker " + "nodes instead." % (loaded_size, warn_limit) + ) + # We are using a "single" buffer since we mostly load single frames. A + # "sig" buffer would work as well, but would require a transpose to + # accomodate multiple frames in the last and not first dimension. + # A "nav" buffer would allocate a NaN-filled buffer for the whole dataset. + return { + "corrected": self.buffer( + kind="single", extra_shape=(navsize,) + sigshape, dtype=dtype + ), + "backprojected": self.buffer( + kind="single", extra_shape=(navsize,) + backprojection_fov, dtype=dtype + ), + } + + def process_frame(self, frame): + "" + scan_y, scan_x = self.meta.coordinates[0] + overfocus_params: Parameters4DSTEM = self.params.overfocus_params["params"] + # We work in flattened nav space with ROI applied + sl = self.meta.slice.get() + if self.has_correction: + correct_frame( + frame=frame, + scan_y=scan_y, + scan_x=scan_x, + mat=self.params.corr_mat, + detector_out=self.results.corrected[sl][0], + ) + if self.has_backprojection: + project_frame_backwards( + frame=frame, + source_semiconv=overfocus_params.semiconv, + scan_y=scan_y, + scan_x=scan_x, + mat=self.params.back_mat, + image_out=self.results.backprojected[sl][0], + ) + def merge(self, dest, src): - dest.shifted_sum += src.shifted_sum - dest.selected += src.selected - dest.sum += src.sum - dest.point[:] = src.point + "" + # We receive full-size buffers from each node that + # contributes at least one frame and rely on the rest being filled + # with zeros correctly. + dest.corrected[:] += src.corrected + dest.backprojected[:] += src.backprojected + + def merge_all(self, ordered_results): + "" + res = {} + for attr in ("corrected", "backprojected"): + chunks = [getattr(b, attr) for b in ordered_results.values()] + # We receive full-size buffers from each node that + # contributes at least one frame and rely on the rest being filled + # with zeros correctly. + ssum = np.stack(chunks, axis=0).sum(axis=0) + res[attr] = ssum + return res diff --git a/src/microscope_calibration/ui.py b/src/microscope_calibration/ui.py new file mode 100644 index 0000000..9f2490a --- /dev/null +++ b/src/microscope_calibration/ui.py @@ -0,0 +1,1111 @@ +from typing import Literal +import concurrent.futures + +import numpy as np +import sparse +import panel as pn +import flax +import jax.numpy as jnp +import pandas as pd + +from libertem.io.dataset.base import DataSet +from libertem.api import Context +from libertem.udf.sumsigudf import SumSigUDF +from libertem.udf.masks import ApplyMasksUDF +from libertem.udf.raw import PickUDF + +from libertem_blobfinder.udf.correlation import FastCorrelationUDF, run_fastcorrelation +from libertem_blobfinder.common.patterns import BackgroundSubtraction + +from libertem_ui.display.points import RingSet +from libertem_ui.figure import ApertureFigure +from libertem_ui.display.cursor import Cursor +from libertem_ui.display.points import PointSet +from libertem_ui.display.lines import Curve + +from bokeh.plotting import ColumnDataSource +from bokeh.events import DoubleTap, Tap + +from .common.model import Parameters4DSTEM, DescanError, PixelYX, trace +from .util.optimize import ( + solve_tilt_descan_error_points, + solve_tilt_descan_error, + solve_coords_points, + solve_hit_specimen, +) +from .common.stem_overfocus import ( + get_detector_correction_matrix, + corrected_det_y, + corrected_det_x, + ring_radii, + get_center, +) +from .udf.stem_overfocus import CorrectedPickUDF, OverfocusUDF + + +NavModeT = Literal["point", "sumsig"] + + +class CoordinateCorrectionLayout: + descan_columns = ["scan_y", "scan_x", "detector_cy", "detector_cx"] + descan_index_cols = descan_columns[:2] + + coord_columns = [ + "scan_y", + "scan_x", + "specimen_y", + "specimen_x", + "detector_y", + "detector_x", + ] + coord_index_cols = coord_columns[:4] + + def __init__( + self, + dataset: DataSet, + ctx: Context, + nav_mode: NavModeT = "point", + twothetas: np.ndarray | None = None, + start_params=None, + ): + # # Stuff + self.executor = concurrent.futures.ThreadPoolExecutor(max_workers=1) + self.dataset = dataset + self.ctx = ctx + self.nav_mode = nav_mode + + if start_params is None: + start_params = self.default_params() + self.start_params = start_params + + if twothetas is None: + twothetas = np.array((0.0,)) + + self.coords_adjusted = False + + # # GUI state + self.model_params = ColumnDataSource( + data=( + self.params_update(self.start_params) + | self.scan_pos_update(self.start_params.scan_center) + | self.twothetas_update(twothetas) + ), + ) + + self.scalebar_params = ColumnDataSource( + data=self.scale_update( + start=PixelYX( + y=self.start_params.scan_center.y * 1.7, + x=self.start_params.scan_center.x * 0.3, + ), + stop=PixelYX( + y=self.start_params.scan_center.y * 1.7, + x=self.start_params.scan_center.x * 1.7, + ), + ), + ) + + self.ring_params = ColumnDataSource( + data=self.ring_update(self.model_params.data) + ) + self.centered_ring_params = ColumnDataSource( + data=self.ring_update( + self.model_params.data, + detector_center=self.start_params.detector_center, + ) + ) + self.descan_fixpoints = pd.DataFrame(columns=self.descan_columns).set_index( + self.descan_index_cols + ) + # Don't use scan center because the glyphs cannot be moved separately + feature_start = PixelYX( + y=self.start_params.scan_center.y + 5, + x=self.start_params.scan_center.x + 5, + ) + self.feature_params = ColumnDataSource( + data=self.scan_pos_update(feature_start) + ) + if self.start_params.overfocus != 0: + feature_select_start = self.get_feature_on_detector( + params=self.start_params, + scan_pos=self.start_params.scan_center, + specimen_px=feature_start, + ) + else: + feature_select_start = self.start_params.detector_center + self.feature_select_params = ColumnDataSource( + data=self.feature_update(feature_select_start) + ) + + self.coord_fixpoints = pd.DataFrame(columns=self.coord_columns).set_index( + self.coord_index_cols + ) + + # # GUI elements + preview = self.get_preview() + self.nav_fig = ApertureFigure.new(preview["nav"], title="Nav map") + self.adjust_layout(self.nav_fig, shape=preview["nav"].shape) + + self.cursor = ( + Cursor(cds=self.model_params, x="scan_x", y="scan_y") + .on(self.nav_fig.fig) + # this adds the necessary components to make the cursor draggable + .editable(selected=True) + ) + # The cursor Glyph is accessed via the .cursor property, until the API is unified + self.cursor.cursor.line_color = "red" + + frames = self.get_frames(pos=self.scan_pos) + self.pick_fig = ApertureFigure.new(frames["raw"], title="Picked detector frame") + self.adjust_layout(self.pick_fig, shape=frames["raw"].shape) + + self.beam_centre = ( + Cursor(cds=self.ring_params, x="detector_cx", y="detector_cy") + .on(self.pick_fig.fig) + .editable(selected=True) + ) + self.beam_centre.glyph.line_color = "red" + self.diffraction_ringsets = [] + for i in range(self.ring_params.data["num_rings"][0]): + rikey = f"ri_{i}" + rokey = f"ro_{i}" + self.diffraction_ringsets.append( + RingSet( + cds=self.ring_params, + x="detector_cx", + y="detector_cy", + inner_radius=rikey, + outer_radius=rokey, + ).on(self.pick_fig.fig) + ) + + self.corr_point_fig = ApertureFigure.new( + preview["corrected_point"], title="Corrected point analysis" + ) + self.adjust_layout(self.corr_point_fig, shape=preview["corrected_point"].shape) + self.cursor_2 = ( + Cursor(cds=self.model_params, x="scan_x", y="scan_y") + .on(self.corr_point_fig.fig) + # this adds the necessary components to make the cursor draggable + .editable(selected=True) + ) + # The cursor Glyph is accessed via the .cursor property, until the API is unified + self.cursor_2.cursor.line_color = "red" + + self.nav_feature_cursor = ( + Cursor(cds=self.feature_params, x="scan_x", y="scan_y") + .on(self.corr_point_fig.fig) + # this adds the necessary components to make the cursor draggable + .editable(selected=True) + ) + # The cursor Glyph is accessed via the .cursor property, until the API is unified + self.nav_feature_cursor.cursor.line_color = "lightgreen" + + self.scalebar_handles = ( + PointSet(cds=self.scalebar_params, x="scalebar_x", y="scalebar_y") + .on(self.corr_point_fig.fig) + .editable(drag=True, tag_name="cursor") + ) + self.scalebar_line = Curve( + cds=self.scalebar_params, xkey="scalebar_x", ykey="scalebar_y" + ).on(self.corr_point_fig.fig) + self.scalebar_handles.glyph.line_color = "yellow" + self.scalebar_handles.glyph.fill_color = None + self.scalebar_line.glyph.line_color = "yellow" + + self.corr_pick_fig = ApertureFigure.new( + frames["corrected"], title="Frame corrected for descan error" + ) + self.adjust_layout(self.corr_pick_fig, shape=frames["corrected"].shape) + + self.corr_beam_centre = Cursor( + cds=self.centered_ring_params, x="detector_cx", y="detector_cy" + ).on(self.corr_pick_fig.fig) + self.corr_beam_centre.glyph.line_color = "red" + self.corr_diffraction_ringsets = [] + for i in range(self.centered_ring_params.data["num_rings"][0]): + rikey = f"ri_{i}" + rokey = f"ro_{i}" + self.corr_diffraction_ringsets.append( + RingSet( + cds=self.centered_ring_params, + x="detector_cx", + y="detector_cy", + inner_radius=rikey, + outer_radius=rokey, + ).on(self.corr_pick_fig.fig) + ) + + self.corr_sum_fig = ApertureFigure.new( + preview["corrected_sum"], title="Sum of frames corrected for descan error" + ) + self.adjust_layout(self.corr_sum_fig, shape=preview["corrected_sum"].shape) + self.corr_beam_centre_2 = Cursor( + cds=self.centered_ring_params, x="detector_cx", y="detector_cy" + ).on(self.corr_sum_fig.fig) + self.corr_beam_centre_2.glyph.line_color = "red" + self.corr_diffraction_ringsets_2 = [] + for i in range(self.centered_ring_params.data["num_rings"][0]): + rikey = f"ri_{i}" + rokey = f"ro_{i}" + self.corr_diffraction_ringsets_2.append( + RingSet( + cds=self.centered_ring_params, + x="detector_cx", + y="detector_cy", + inner_radius=rikey, + outer_radius=rokey, + ).on(self.corr_sum_fig.fig) + ) + + self.nav_fig_2 = ApertureFigure.new(preview["nav"], title="Nav map") + self.adjust_layout(self.nav_fig_2, shape=preview["nav"].shape) + + self.cursor_3 = ( + Cursor(cds=self.model_params, x="scan_x", y="scan_y") + .on(self.nav_fig_2.fig) + # this adds the necessary components to make the cursor draggable + .editable(selected=True) + ) + # The cursor Glyph is accessed via the .cursor property, until the API is unified + self.cursor_3.cursor.line_color = "red" + + self.pick_fig_2 = ApertureFigure.new( + frames["raw"], title="Picked detector frame" + ) + self.adjust_layout(self.pick_fig_2, shape=frames["raw"].shape) + + self.nav_feature_select_cursor = ( + Cursor(cds=self.feature_select_params, x="detector_x", y="detector_y") + .on(self.pick_fig_2.fig) + # this adds the necessary components to make the cursor draggable + .editable(selected=True) + ) + # The cursor Glyph is accessed via the .cursor property, until the API is unified + self.nav_feature_select_cursor.cursor.line_color = "lightgreen" + + self.back_sum_fig = ApertureFigure.new( + preview["backprojected_sum"], + title="Frames back-projected to scan coordinate system", + ) + self.adjust_layout(self.back_sum_fig, shape=preview["backprojected_sum"].shape) + + self.back_pick_fig = ApertureFigure.new( + frames["backprojected"], + title="Current frame back-projected to scan coordinate system", + ) + self.adjust_layout(self.back_pick_fig, shape=frames["backprojected"].shape) + + self.cl_input = pn.widgets.FloatInput( + name="Camera length / m", step=0.01, value=self.start_params.camera_length + ) + self.semiconv_input = pn.widgets.FloatInput( + name="Convergence semi-angle / mrad", + step=0.01, + value=start_params.semiconv * 1000, + ) + self.scalebar_input = pn.widgets.FloatInput( + name="Scale bar / nm", + step=0.01, + value=( + self.start_params.scan_pixel_pitch + * self.get_scalebar_length(self.scalebar_params.data) + * 1e9 + ), + ) + self.scan_rotation_input = pn.widgets.FloatInput( + name="Scan rotation / degrees", + step=0.1, + value=self.start_params.scan_rotation * 180 / np.pi, + ) + self.detector_pitch_input = pn.widgets.FloatInput( + name="Detector pixel pitch / µm", + step=0.1, + value=self.start_params.detector_pixel_pitch * 1e6, + ) + + self.descan_fixpoint_table = pn.widgets.Tabulator( + self.descan_fixpoints, + buttons={ + "select": '', + "delete": '', + }, + # See https://github.com/holoviz/panel/pull/8256 + selectable=False, + ) + + self.record_button = pn.widgets.Button(name="Record") + self.apply_button = pn.widgets.Button(name="Apply correction from table") + self.clear_button = pn.widgets.Button(name="Clear") + self.correlate_button = pn.widgets.Button( + name="Refine correction with cross-correlation" + ) + + self.coord_fixpoint_table = pn.widgets.Tabulator( + self.coord_fixpoints, + buttons={ + "select": '', + "delete": '', + }, + # See https://github.com/holoviz/panel/pull/8256 + selectable=False, + ) + + self.coord_record_button = pn.widgets.Button(name="Record") + self.coord_apply_button = pn.widgets.Button( + name="Derive coordinate system from table" + ) + self.coord_clear_button = pn.widgets.Button(name="Clear") + self.optimize_button = pn.widgets.Button( + name="Optimize sharpness of back-projection" + ) + + # # Event handler setup + + # ## state + # trigger whenever the "data" attribute of the cursor ColumnDataSource changes + self.model_params.on_change("data", self.on_model_params_change) + # self.model_params.on_change("data", lambda attr, old, new: print(attr, old, new)) + self.scalebar_params.on_change("data", self.on_scalebar_params_change) + self.feature_params.on_change("data", self.on_feature_params_change) + + # ## nav_fig + self.nav_fig.fig.on_event(Tap, self.move_scan_to) + self.corr_point_fig.fig.on_event(Tap, self.move_feature_to) + self.nav_fig_2.fig.on_event(Tap, self.move_scan_to) + + # ## pick_fig + self.pick_fig.fig.on_event(Tap, self.move_rings_to) + self.pick_fig.fig.on_event(DoubleTap, self.move_rings_to) + self.pick_fig.fig.on_event(DoubleTap, lambda e: self.descan_add_row()) + + self.pick_fig_2.fig.on_event(Tap, self.move_feature_select_to) + self.pick_fig_2.fig.on_event(DoubleTap, self.move_feature_select_to) + self.pick_fig_2.fig.on_event(DoubleTap, lambda e: self.coord_add_row()) + + # ## Model param controls + self.cl_input.param.watch(self.update_cl, "value") + self.semiconv_input.param.watch(self.update_semiconv, "value") + self.scalebar_input.param.watch(self.update_scale, "value") + self.detector_pitch_input.param.watch(self.update_detector_pitch, "value") + self.scan_rotation_input.param.watch(self.update_scan_rotation, "value") + + # ## descan fixpoints table + self.descan_fixpoint_table.on_click( + lambda e: self.descan_delete_row(e.row) if e.column == "delete" else None, + column="delete", + ) + self.descan_fixpoint_table.on_click( + lambda e: self.descan_move_to_row(e.row) if e.column == "select" else None, + column="select", + ) + + # ## descan correction buttons + self.record_button.on_click(lambda e: self.descan_add_row()) + self.apply_button.on_click(lambda e: self.perform_descan_update()) + self.clear_button.on_click(lambda e: self.descan_drop()) + self.correlate_button.on_click(lambda e: self.center_correlation_regression()) + + # ## coord fixpoints table + self.coord_fixpoint_table.on_click( + lambda e: self.coord_delete_row(e.row) if e.column == "delete" else None, + column="delete", + ) + self.coord_fixpoint_table.on_click( + lambda e: self.coord_move_to_row(e.row) if e.column == "select" else None, + column="select", + ) + + # ## descan correction buttons + self.coord_record_button.on_click(lambda e: self.coord_add_row()) + self.coord_apply_button.on_click(lambda e: self.perform_coord_update()) + self.coord_clear_button.on_click(lambda e: self.coord_drop()) + self.optimize_button.on_click(lambda e: self.sharpen()) + + @staticmethod + def adjust_layout(plot, shape): + plot.fig.y_range.bounds = (0, shape[0]) + plot.fig.x_range.bounds = (0, shape[1]) + plot.fig.sizing_mode = "scale_width" + plot.layout.max_width = 350 + plot.layout.sizing_mode = "stretch_width" + + def on_model_params_change(self, attr, old, new): + # This is a "bokeh-style" callback because it will trigger directly from a ColumnDataSource + # The callback must have three arguments [attr, old, new] + # attr will be "data" + # old will be the CDS dict before the trigger + # new will be the CDS dict after the trigger + assert attr == "data" + new_params = self.get_params(new) + + # Doesn't work, likely because not all changes trigger this callback, + # see https://github.com/holoviz/panel/issues/8275 + # If the coordinate system calibration is current + # if self.coords_adjusted: + # # Check if parameters have changed that invalidate the + # # calibration, and re-calibrate in that case + # old_params = self.get_params(old) + # new_params = self.get_params(new) + # # These should be parameters that are NOT changed by + # # self.perform_coord_update() + # relevant = ('scan_pixel_pitch', 'camera_length', 'scan_rotation') + # if any(getattr(old_params, r) != getattr(new_params, r) for r in relevant): + # print("changed") + # self.perform_coord_update() + # else: + # print("unchanged") + + new_pos = self.get_scan_pos(new) + # Somehow doesn't work with all the event handling confusion + # Just update always and be done with it *sigh* + # if old_pos != new_pos: + frames = self.get_frames(pos=new_pos) + self.pick_fig.update(frames["raw"]) + self.pick_fig_2.update(frames["raw"]) + self.corr_pick_fig.update(frames["corrected"]) + self.back_pick_fig.update(frames["backprojected"]) + + previews = self.get_preview() + self.corr_point_fig.update(previews["corrected_point"]) + self.corr_sum_fig.update(previews["corrected_sum"]) + self.back_sum_fig.update(previews["backprojected_sum"]) + + self.update_with_force( + self.ring_params, + self.ring_update(model_data=new), + ) + self.update_with_force( + self.centered_ring_params, + self.ring_update( + model_data=new, detector_center=new_params.detector_center + ), + ) + detector_pos = self.get_feature_on_detector( + params=new_params, + scan_pos=new_pos, + specimen_px=self.get_scan_pos(self.feature_params.data), + ) + self.update_with_force( + self.feature_select_params, self.feature_update(detector_pos) + ) + + def on_scalebar_params_change(self, attr, old, new): + # This is a "bokeh-style" callback because it will trigger directly from a ColumnDataSource + # The callback must have three arguments [attr, old, new] + # attr will be "data" + # old will be the CDS dict before the trigger + # new will be the CDS dict after the trigger + assert attr == "data" + # For some reason we can't get change events from the scale bar CDS, + # but receive model_params CDS changes + length = self.get_scalebar_length(self.scalebar_params.data) + # TODO use microscope_calibration.util.optimize.solve_scan_pixel_pitch + # instead to not make assumption about linearity + self.scalebar_input.value = length * self.params.scan_pixel_pitch * 1e9 + self.push() + + def on_feature_params_change(self, attr, old, new): + # This is a "bokeh-style" callback because it will trigger directly from a ColumnDataSource + # The callback must have three arguments [attr, old, new] + # attr will be "data" + # old will be the CDS dict before the trigger + # new will be the CDS dict after the trigger + assert attr == "data" + params = self.params + if params.overfocus != 0: + feature_pos = self.get_feature_on_detector( + params=params, + scan_pos=self.get_scan_pos(self.model_params.data), + specimen_px=self.get_scan_pos(new), + ) + self.update_with_force( + self.feature_select_params, self.feature_update(feature_pos) + ) + + def update_cl(self, event): + base = self.params + params = base.adjust_camera_length(camera_length=event.new) + self.update_with_force(self.model_params, self.params_update(params)) + + def update_semiconv(self, event): + params = self.params.derive(semiconv=event.new / 1000) + self.update_with_force(self.model_params, self.params_update(params)) + + def update_scale(self, event): + base = self.params + # TODO use microscope_calibration.util.optimize.solve_scan_pixel_pitch + # instead to not make assumption about linearity + length_px = self.get_scalebar_length(self.scalebar_params.data) + scan_pixel_pitch = event.new / 1e9 / length_px + params = base.adjust_scan_pixel_pitch(scan_pixel_pitch) + self.update_with_force(self.model_params, self.params_update(params)) + + def update_scan_rotation(self, event): + params = self.params.adjust_scan_rotation(scan_rotation=event.new / 180 * np.pi) + self.update_with_force(self.model_params, self.params_update(params)) + + def update_detector_pitch(self, event): + params = self.params.adjust_detector_pixel_pitch( + detector_pixel_pitch=event.new / 1e6 + ) + self.update_with_force(self.model_params, self.params_update(params)) + + def move_scan_to(self, event): + self.update_with_force( + self.model_params, + self.scan_pos_update( + PixelYX(y=float(event.y), x=float(event.x)), + ), + ) + + def move_feature_to(self, event): + self.update_with_force( + self.feature_params, + self.scan_pos_update( + PixelYX(y=float(event.y), x=float(event.x)), + ), + ) + + def move_feature_select_to(self, event): + self.update_with_force( + self.feature_select_params, + self.feature_update( + PixelYX(y=float(event.y), x=float(event.x)), + ), + ) + + def move_rings_to(self, event): + self.update_with_force( + self.ring_params, + self.detector_center_update( + PixelYX(y=float(event.y), x=float(event.x)), + ), + ) + + def descan_add_row(self): + scan_pos = self.scan_pos + center_pos = self.get_detector_center(self.ring_params.data) + idx = (int(np.round(scan_pos.y)), int(np.round(scan_pos.x))) + new_df = pd.DataFrame( + [idx + (center_pos.y, center_pos.x)], columns=self.descan_columns + ) + new_df = new_df.set_index(self.descan_index_cols) + t = self.descan_fixpoint_table + if idx in t.value.index: + t.value.update(new_df) + # Make sure the change is registered + t.value = t.value + else: + t.value = pd.concat((t.value, new_df)) + + def descan_delete_row(self, row): + df = self.descan_fixpoint_table.value + key = df.index[row] + self.descan_fixpoint_table.value = df.drop(index=key) + + def descan_move_to_row(self, row): + df = self.descan_fixpoint_table.value + key = df.index[row] + assert len(key) == 2 + scan_pos = PixelYX(y=key[0], x=key[1]) + self.update_with_force(self.model_params, self.scan_pos_update(scan_pos)) + + def descan_drop(self): + t = self.descan_fixpoint_table + t.value = t.value.drop(t.value.index) + + def coord_add_row(self): + scan_pos = self.scan_pos + feature_nav_pos = self.get_scan_pos(self.feature_params.data) + feature_pos = self.get_feature(self.feature_select_params.data) + idx = ( + int(np.round(scan_pos.y)), + int(np.round(scan_pos.x)), + float(feature_nav_pos.y), + float(feature_nav_pos.x), + ) + new_df = pd.DataFrame( + [idx + (feature_pos.y, feature_pos.x)], columns=self.coord_columns + ) + new_df = new_df.set_index(self.coord_index_cols) + t = self.coord_fixpoint_table + if idx in t.value.index: + t.value.update(new_df) + # Make sure the change is registered + t.value = t.value + else: + t.value = pd.concat((t.value, new_df)) + self.coords_adjusted = False + + def coord_delete_row(self, row): + df = self.coord_fixpoint_table.value + key = df.index[row] + self.coord_fixpoint_table.value = df.drop(index=key) + self.coords_adjusted = False + + def coord_move_to_row(self, row): + df = self.coord_fixpoint_table.value + key = df.index[row] + detector = df.values[row] + assert len(key) == 4 + scan_pos = PixelYX(y=key[0], x=key[1]) + specimen_pos = PixelYX(y=key[2], x=key[3]) + self.update_with_force(self.model_params, self.scan_pos_update(scan_pos)) + self.update_with_force(self.feature_params, self.scan_pos_update(specimen_pos)) + detector_pos = PixelYX(y=detector[0], x=detector[1]) + self.update_with_force( + self.feature_select_params, self.feature_update(detector_pos) + ) + + def coord_drop(self): + t = self.coord_fixpoint_table + t.value = t.value.drop(t.value.index) + self.coords_adjusted = False + + def default_params(self) -> Parameters4DSTEM: + ds = self.dataset + if ds is None: + scan_center = PixelYX(0.0, 0.0) + detector_center = PixelYX(0.0, 0.0) + else: + scan_center = PixelYX( + y=ds.shape.nav[0] / 2, + x=ds.shape.nav[1] / 2, + ) + detector_center = PixelYX( + y=ds.shape.sig[0] / 2, + x=ds.shape.sig[1] / 2, + ) + return Parameters4DSTEM( + overfocus=0.0, + scan_pixel_pitch=1e-6, + scan_center=scan_center, + scan_rotation=0.0, + camera_length=1.0, + detector_pixel_pitch=50e-6, + detector_center=detector_center, + semiconv=1e-3, # radian + flip_factor=1.0, + # descan_error=DescanError(sxo_pxi=1, syo_pyi=-3) + ) + + def get_params(self, model_data) -> Parameters4DSTEM: + return self.deserialize(model_data["params"][0]) + + @staticmethod + def get_scan_pos(model_data): + return PixelYX(y=model_data["scan_y"][0], x=model_data["scan_x"][0]) + + @staticmethod + def get_model_twothetas(model_data): + # return np.array((0.01, 0.02, 0.03.)) + return model_data["twothetas"][0] + + @staticmethod + def get_detector_center(ring_data): + return PixelYX( + y=ring_data["detector_cy"][0], + x=ring_data["detector_cx"][0], + ) + + @staticmethod + def get_feature(feature_select_data): + return PixelYX( + y=feature_select_data["detector_y"][0], + x=feature_select_data["detector_x"][0], + ) + + @staticmethod + def get_scalebar_length(scalebar_data): + start = np.array( + (scalebar_data["scalebar_y"][0], scalebar_data["scalebar_x"][0]) + ) + stop = np.array( + (scalebar_data["scalebar_y"][1], scalebar_data["scalebar_x"][1]) + ) + return np.linalg.norm(stop - start) + + @staticmethod + def get_feature_on_detector( + params: Parameters4DSTEM, scan_pos: PixelYX, specimen_px: PixelYX + ) -> PixelYX: + slope, residual = solve_hit_specimen( + params=params, + scan_pos=scan_pos, + specimen_px=specimen_px, + ) + res = trace( + params=params, + scan_pos=scan_pos, + source_dy=slope.dy, + source_dx=slope.dx, + ) + return res["detector"].sampling["detector_px"] + + @property + def params(self) -> Parameters4DSTEM: + return self.get_params(self.model_params.data) + + @property + def scan_pos(self): + return self.get_scan_pos(self.model_params.data) + + def get_preview(self): + if self.nav_mode == "sumsig": + nav_udf = SumSigUDF() + elif self.nav_mode == "point": + cy = self.params.detector_center.y + cx = self.params.detector_center.x + sig_shape = tuple(self.dataset.shape.sig) + + def get_mask(): + a = sparse.COO( + data=np.array([1]), + coords=np.array(([int(cy)], [int(cx)])), + shape=sig_shape, + ) + return a + + nav_udf = ApplyMasksUDF( + mask_factories=[get_mask], + use_sparse=True, + ) + else: + raise NotImplementedError() + overfocus_udf = OverfocusUDF(overfocus_params={"params": self.params}) + + res = self.ctx.run_udf(dataset=self.dataset, udf=(nav_udf, overfocus_udf)) + result = {} + if self.nav_mode == "sumsig": + result["nav"] = res[0]["intensity"].data + elif self.nav_mode == "point": + result["nav"] = res[0]["intensity"].data[..., 0] + result["backprojected_sum"] = res[1]["backprojected_sum"].data + result["corrected_point"] = res[1]["corrected_point"].data + result["corrected_sum"] = res[1]["corrected_sum"].data + return result + + def get_frames(self, pos: PixelYX): + y = int(round(pos.y)) + x = int(round(pos.x)) + roi = self.dataset.roi[y, x] + udfs = ( + PickUDF(), + CorrectedPickUDF(overfocus_params={"params": self.params}), + ) + res = self.ctx.run_udf(dataset=self.dataset, udf=udfs, roi=roi) + return { + "raw": res[0]["intensity"].raw_data[0], + "corrected": res[1]["corrected"].raw_data[0], + "backprojected": res[1]["backprojected"].raw_data[0], + } + + @staticmethod + def serialize(params: Parameters4DSTEM): + return flax.serialization.to_state_dict(params.normalize_types()) + + def deserialize(self, state_dict): + res = flax.serialization.from_state_dict( + target=self.start_params, state=state_dict + ).normalize_types() + return res + + def params_update(self, params: Parameters4DSTEM): + return {"params": [self.serialize(params)]} + + @staticmethod + def scan_pos_update(scan_pos: PixelYX): + return { + "scan_y": [float(scan_pos.y)], + "scan_x": [float(scan_pos.x)], + } + + @staticmethod + def twothetas_update(twothetas): + return { + "twothetas": [twothetas], + } + + @staticmethod + def scale_update(start: PixelYX, stop: PixelYX): + return { + "scalebar_x": [float(start.x), float(stop.x)], + "scalebar_y": [float(start.y), float(stop.y)], + } + + def ring_update(self, model_data, detector_center=None): + params = self.get_params(model_data) + ri, ro = ring_radii( + params=params, twothetas=self.get_model_twothetas(model_data) + ) + if detector_center is None: + detector_center = get_center( + params=params, + scan_pos=self.get_scan_pos(model_data), + ) + return ( + { + "detector_cy": [float(detector_center.y)], + "detector_cx": [float(detector_center.x)], + "num_rings": [len(ri)], + } + | {f"ri_{i}": [float(rii)] for i, rii in enumerate(ri)} + | {f"ro_{i}": [float(roo)] for i, roo in enumerate(ro)} + ) + + def feature_update(self, detector_pos: PixelYX): + return { + "detector_y": [float(detector_pos.y)], + "detector_x": [float(detector_pos.x)], + } + + @staticmethod + def detector_center_update(detector_center: PixelYX): + return { + "detector_cy": [float(detector_center.y)], + "detector_cx": [float(detector_center.x)], + } + + def perform_descan_update(self): + points = ( + self.descan_fixpoint_table.value.reset_index().to_numpy().astype(np.float32) + ) + if len(points): + new_params, residual = solve_tilt_descan_error_points( + ref_params=self.params, points=jnp.array(points) + ) + self.update_with_force(self.model_params, self.params_update(new_params)) + + def perform_coord_update(self): + points = ( + self.coord_fixpoint_table.value.reset_index().to_numpy().astype(np.float32) + ) + if len(points): + new_params, residual = solve_coords_points( + ref_params=self.params, points=jnp.array(points) + ) + self.update_with_force(self.model_params, self.params_update(new_params)) + self.coords_adjusted = True + + def _push(self): + self.nav_fig.push( + self.pick_fig, + self.corr_point_fig, + self.corr_pick_fig, + self.corr_sum_fig, + self.nav_fig_2, + self.pick_fig_2, + self.back_sum_fig, + self.back_pick_fig, + ) + + def push(self): + self._push() + self.executor.submit(self._push) + + def update_with_force(self, cds: ColumnDataSource, update): + cds.data.update(**update) + self.push() + holding = cds.document.callbacks._hold + cds.document.callbacks.unhold() + cds.data.update(**update) + self.push() + cds.document.callbacks.hold(holding) + + def center_correlation_regression(self): + # Delicious! 🍝🍝🍝 + params = self.params + ri, ro = ring_radii(params, self.get_model_twothetas(self.model_params.data)) + radius_outer = 1.2 * ro[0] + if len(ri) >= 2: + radius_outer = max(radius_outer, ri[1] / 2) + # Make sure we stay away from other peaks + pattern = BackgroundSubtraction(radius=ro[0], radius_outer=radius_outer) + # Correction to same parameters, except descan error of 0 + ref_params = params.derive(descan_error=DescanError()) + mat = get_detector_correction_matrix(rec_params=params, ref_params=ref_params) + # Scan positions in the dataset + nav_shape = self.dataset.shape.nav + y, x = np.mgrid[: nav_shape[0], : nav_shape[1]] + # Calculate where the nominal center actually is on the detector + expected_x = corrected_det_x( + det_corr_x=params.detector_center.x, + det_corr_y=params.detector_center.y, + scan_x=x, + scan_y=y, + mat=mat, + ) + expected_y = corrected_det_y( + det_corr_x=params.detector_center.x, + det_corr_y=params.detector_center.y, + scan_x=x, + scan_y=y, + mat=mat, + ) + # Subtract the expected position so that only the deviation remains + dc = params.detector_center + shifts = np.stack((expected_y - dc.y, expected_x - dc.x), axis=-1) + aux_shifts = FastCorrelationUDF.aux_data( + data=shifts, + kind="nav", + extra_shape=(2,), + dtype=shifts.dtype, + ) + res = run_fastcorrelation( + ctx=self.ctx, + dataset=self.dataset, + peaks=np.array([params.detector_center]), + match_pattern=pattern, + zero_shift=aux_shifts, + upsample=True, + ) + + # Following CoMUDF regression + field = res["refineds"].data[:, :, 0, :] + # Only keep deviation from expected value in regression + field[..., 0] -= params.detector_center.y + field[..., 1] -= params.detector_center.x + + inp = np.ones(field.shape[:-1] + (3,)) + y, x = np.ogrid[: field.shape[0], : field.shape[1]] + inp[..., 1] = y + inp[..., 2] = x + reg_res = np.linalg.lstsq( + inp.reshape((-1, 3)), field.reshape((-1, 2)), rcond=None + ) + new_params, residual = solve_tilt_descan_error( + ref_params=params, regression=reg_res[0] + ) + self.model_params.data.update(**self.params_update(new_params)) + self.push() + + @property + def layout(self): + self.section_1_label = pn.pane.Markdown( + """ + # 4D STEM coordinate system calibration + + This tool helps to check and adjust the geometry of a 4D STEM + experiment. A nominal value for the scan rotation as well as the + detector pixel pitch should be known. + + ## Descan error, convergence semi-angle and effective camera length + + First, confirm or calibrate the shift of the beam center as a + function of scan position (descan error). + + 1. Change the selected scan position on the left + 1. Observe if the cursor on the right stays at the beam center. + 1. Observe if the plot "Corrected point analysis" shows a bright + field image of the specimen. + 1. Observe if the plots "Frame corrected for descan error" and "Sum + of frames corrected for descan error" show the primary beam + exactly at the cursor position. + 1. If the positions don't match or the plot is distorted, move the + cursor to the beam center and record the position. Do this for at + least three different scan positions. + 1. Press the button "Apply correction from table" to re-calibrate + the descan error. + 1. Observe if the descan error is calibrated correctly now by + repeating the first three steps. + + In case the frames show diffraction rings or spots and a list of + "twotheta" angles was provided, now calibrate the camera length so + that the ring glyphs match the peaks or rings in the detector + frames. + + Finally, adjust the convergence semi-angle so that the innermost + glyph matches the size of the diffraction disk. + """, + max_width=500, + ) + inputs_1 = pn.layout.Row( + self.scan_rotation_input, + self.detector_pitch_input, + self.cl_input, + self.semiconv_input, + ) + inputs_2 = pn.layout.Row( + self.scalebar_input, + ) + raw_figs = pn.layout.Row(self.nav_fig.layout, self.pick_fig.layout) + corrected_figs = pn.layout.Row( + self.corr_point_fig.layout, + self.corr_pick_fig.layout, + self.corr_sum_fig.layout, + ) + self.section_2_label = pn.pane.Markdown( + """ + ## Scan step + + Move the yellow line handles in the plot "Corrected point analysis" + so that the line spans a feature of known physical size. Check the + size in the "Scale bar" input field and adjust if necessary. Note + that for defocused data the scale is only correct if the descan + error was compensated correctly. + + ## Detector rotation, overfocus and handedness + + These parameters can only be calibrated in a dataset that was + recorded with a strong defocus so that the detector shows a shadow + image projection of the specimen. + + 1. Move the green cursor in the plot "Corrected point analysis" to a + prominent feature. + 1. Select a scan position where this feature is also visible on a + detector frame. + 1. Observe if the green cursor in the second plot "Picked detector + frame" points to the same feature. + 1. Observe if the plot "Frames back-projected to scan coordinate + system" shows a sharp image of the specimen that matches the plot + "Corrected point analysis". + 1. If the positions don't match or the plot is distorted, move the + green cursor in the second plot "Picked detector frame" to the + feature and record the position. Do this for at least three + different features or scan positions. + 1. Press the button "Derive coordinate system from table from table" + to re-calibrate the descan error. + 1. Observe if the descan error is calibrated correctly now by + repeating the first four steps. + """, + max_width=500, + ) + raw_figs_2 = pn.layout.Row(self.nav_fig_2.layout, self.pick_fig_2.layout) + back_figs = pn.layout.Row(self.back_sum_fig.layout, self.back_pick_fig.layout) + descan_buttons = pn.layout.Row( + self.record_button, + self.apply_button, + self.clear_button, + self.correlate_button, + ) + self.descan_label = pn.pane.Markdown( + "### Descan correction table", + ) + descan_section = pn.layout.Column( + self.descan_label, self.descan_fixpoint_table, descan_buttons + ) + coord_buttons = pn.layout.Row( + self.coord_record_button, + self.coord_apply_button, + self.coord_clear_button, + self.optimize_button, + ) + self.coord_label = pn.pane.Markdown( + "### Coordinate system calibration table", + ) + coord_section = pn.layout.Column( + self.coord_label, self.coord_fixpoint_table, coord_buttons + ) + return pn.layout.Column( + self.section_1_label, + inputs_1, + raw_figs, + descan_section, + self.section_2_label, + corrected_figs, + inputs_2, + raw_figs_2, + coord_section, + back_figs, + ) diff --git a/src/microscope_calibration/util/diffraction.py b/src/microscope_calibration/util/diffraction.py new file mode 100644 index 0000000..d34f3d4 --- /dev/null +++ b/src/microscope_calibration/util/diffraction.py @@ -0,0 +1,34 @@ +import numpy as np + +from CifFile import ReadCif +from diffpy.structure import loadStructure +from orix.crystal_map import Phase +from orix.quaternion import Rotation +from diffsims.generators.simulation_generator import SimulationGenerator + + +# See also +# https://github.com/py4dstem/py4DSTEM_tutorials/blob/main/notebooks/basics_03_calibration.ipynb +def get_twothetas(cif_filename, acceleration_voltage_V, reciprocal_radius=1): + gen = SimulationGenerator( + accelerating_voltage=acceleration_voltage_V / 1000, + ) + structure_raw = ReadCif(cif_filename) + key = list(structure_raw.keys())[0] + space_group = int(structure_raw[key]['_space_group_IT_number']) + structure = loadStructure('EntryWithCollCode163723.cif') + p = Phase(structure=structure, space_group=space_group) + twothetas = set() + rng = np.random.default_rng(seed=0) + eulers = rng.uniform(0.0, 2 * np.pi, (10, 3)) + for euler in eulers: + rot = Rotation.from_euler(euler) + sim = gen.calculate_diffraction2d( + phase=p, rotation=rot, + reciprocal_radius=reciprocal_radius, + # Large excitation error to capture many peaks + max_excitation_error=1, + ) + sim.coordinates.calculate_theta(voltage=acceleration_voltage_V) + twothetas.update(np.round(sim.coordinates.theta, decimals=5)) + return np.array(sorted(twothetas)) diff --git a/src/microscope_calibration/util/optimize.py b/src/microscope_calibration/util/optimize.py index fbd0044..74e6928 100644 --- a/src/microscope_calibration/util/optimize.py +++ b/src/microscope_calibration/util/optimize.py @@ -1,10 +1,21 @@ +from typing import NamedTuple + import numpy as np -from scipy. optimize import shgo +from scipy.optimize import shgo from skimage.measure import blur_effect from typing import TYPE_CHECKING, Callable, Optional from collections.abc import Iterable -from microscope_calibration.common.stem_overfocus import OverfocusParams +import jax; jax.config.update("jax_enable_x64", True) # noqa +import jax.numpy as jnp +import optimistix + +from microscope_calibration.common.model import ( + Parameters4DSTEM, + PixelYX, + DescanError, + trace, +) if TYPE_CHECKING: from libertem.udf.base import UDF @@ -15,15 +26,16 @@ def make_overfocus_loss_function( - params: OverfocusParams, - ctx: 'Context', - dataset: 'DataSet', - overfocus_udf: 'OverfocusUDF', - blur_function: Optional[Callable] = None, - extra_udfs: Iterable['UDF'] = (), - callback: Optional[Callable] = None, - **kwargs): - ''' + params: Parameters4DSTEM, + ctx: "Context", + dataset: "DataSet", + overfocus_udf: "OverfocusUDF", + blur_function: Optional[Callable] = None, + extra_udfs: Iterable["UDF"] = (), + callback: Optional[Callable] = None, + **kwargs, +): + """ Build a parameter mapping and loss function to optimize This maps the :code:`scan_rotation` and :code:`overfocus` parameters @@ -70,20 +82,20 @@ def make_overfocus_loss_function( loss Function that can be called with :func:`scipy.optimize.minimize`. Starting value is [0, 0], sensible range is ([-10, 10], [-10, 10]). - ''' + """ # Rotate and scale the angle so that the optimizer works between +-10, # corresponding to +- 5 deg - rotation_diff = params['scan_rotation'] + rotation_diff = params.scan_rotation * 180 / np.pi rotation_scale = 1 # Values to shift and scale the overfocus so that the optimizer works between +-10 - overfocus_diff = params['overfocus'] - overfocus_scale = 40 / np.abs(params['overfocus']) + overfocus_diff = params.overfocus + overfocus_scale = 40 / np.abs(params.overfocus) if blur_function is None: blur_function = blur_effect - def make_new_params(args) -> OverfocusParams: - ''' + def make_new_params(args) -> Parameters4DSTEM: + """ Map parameters from +-10 to original range Parameters @@ -91,17 +103,17 @@ def make_new_params(args) -> OverfocusParams: args (scan_rotation, overfocused) mapped to +- 10 - ''' + """ transformed_rotation, transformed_overfocus = args rotation = transformed_rotation / rotation_scale + rotation_diff overfocus = transformed_overfocus / overfocus_scale + overfocus_diff - param_copy = params.copy() - param_copy['overfocus'] = overfocus - param_copy['scan_rotation'] = rotation - return param_copy + return params.derive( + overfocus=overfocus, + scan_rotation=rotation / 180 * np.pi, + ) def loss(args) -> float: - ''' + """ Loss function for optimizer to call This calls the UDF with the appropriate parameters @@ -114,36 +126,600 @@ def loss(args) -> float: args (scan_rotation, overfocused) mapped to +-10 range - ''' - param_copy = make_new_params(args) - overfocus_udf.params.overfocus_params.update(param_copy) - res = ctx.run_udf(dataset=dataset, udf=[overfocus_udf] + list(extra_udfs), **kwargs) - blur = blur_function(res[0]['shifted_sum'].data) + """ + params = make_new_params(args) + # Hack to make parameter update work + overfocus_udf.params.overfocus_params["params"] = params + res = ctx.run_udf( + dataset=dataset, udf=[overfocus_udf] + list(extra_udfs), **kwargs + ) + blur = blur_function(res[0]["backprojected_sum"].data) if callback is not None: - callback(args, overfocus_udf.params.overfocus_params, res, blur) + callback(args, overfocus_udf.params.overfocus_params["params"], res, blur) return blur return make_new_params, loss def optimize(loss, bounds=None, minimizer_kwargs=None, **kwargs): - ''' + """ Convenience function to call :func:`scipy.optimize.shgo` This calls :func:`scipy.optimize.shgo` with sensible bounds and minimizer method for a loss function created with :func:`make_overfocus_loss_function`. Additional kwargs are passed to :func:`scipy.optimize.shgo`. - ''' + """ if bounds is None: bounds = [(-10, 10), (-10, 10)] if minimizer_kwargs is None: - minimizer_kwargs = {'method': 'COBYLA'} - res = shgo( - func=loss, - bounds=bounds, - minimizer_kwargs=minimizer_kwargs, - **kwargs - ) + minimizer_kwargs = {"method": "COBYLA"} + res = shgo(func=loss, bounds=bounds, minimizer_kwargs=minimizer_kwargs, **kwargs) return res + + +class _CLArgs(NamedTuple): + ref_params: Parameters4DSTEM + test_dx: float + radius_px: float + + +@jax.jit +def _cl_loss(y, args: _CLArgs): + opt_params = args.ref_params.derive(camera_length=y[0], overfocus=0.0) + opt_res_1 = trace( + opt_params, + scan_pos=PixelYX(y=0.0, x=0.0), + source_dx=args.test_dx, + source_dy=0.0, + ) + opt_res_2 = trace( + opt_params, + scan_pos=PixelYX(y=0.0, x=0.0), + source_dx=-args.test_dx, + source_dy=0.0, + ) + px_1 = opt_res_1["detector"].sampling["detector_px"] + px_2 = opt_res_2["detector"].sampling["detector_px"] + distance = jnp.linalg.norm(jnp.array(px_2) - jnp.array(px_1)) + return distance - 2 * args.radius_px + + +# FIXME include wavelength calculation etc for more practical +# input parameters +def solve_camera_length(ref_params: Parameters4DSTEM, diffraction_angle, radius_px): + args = _CLArgs( + radius_px=radius_px, test_dx=jnp.tan(diffraction_angle), ref_params=ref_params + ) + start = jnp.array((ref_params.camera_length,)) + opt_res = optimistix.least_squares( + fn=_cl_loss, args=args, solver=optimistix.BFGS(atol=1e-12, rtol=1e-12), y0=start + ) + residual = _cl_loss(opt_res.value, args) + # The loss function has minima at camera_length and -camera_length. + # we take the positive side since a negative camera length doesn't make sense + # for a classical TEM, only for reflection. + return ref_params.derive( + camera_length=jnp.abs(opt_res.value[0]), + ).normalize_types(), residual + + +class _SPPArgs(NamedTuple): + ref_params: Parameters4DSTEM + point_1: PixelYX + point_2: PixelYX + physical_distance: float + + +@jax.jit +def _spp_loss(y, args: _SPPArgs): + opt_params = args.ref_params.derive(scan_pixel_pitch=y[0], overfocus=0.0) + opt_res_1 = trace(opt_params, scan_pos=args.point_1, source_dx=0.0, source_dy=0.0) + opt_res_2 = trace(opt_params, scan_pos=args.point_2, source_dx=0.0, source_dy=0.0) + dx = opt_res_2["specimen"].ray.x - opt_res_1["specimen"].ray.x + dy = opt_res_2["specimen"].ray.y - opt_res_1["specimen"].ray.y + opt_distance = jnp.linalg.norm(jnp.array((dy, dx))) + return opt_distance - args.physical_distance + + +def solve_scan_pixel_pitch( + ref_params: Parameters4DSTEM, + point_1: PixelYX, + point_2: PixelYX, + physical_distance: float, +): + args = _SPPArgs( + ref_params=ref_params, + point_1=point_1, + point_2=point_2, + physical_distance=physical_distance, + ) + start = jnp.array((ref_params.scan_pixel_pitch,)) + opt_res = optimistix.least_squares( + fn=_spp_loss, + args=args, + solver=optimistix.BFGS(atol=1e-12, rtol=1e-12), + y0=start, + ) + residual = _spp_loss(opt_res.value, args) + # The loss function has minima at scan_pixel_pitch and -scan_pixel_pitch. we + # take the positive side since the inversion can be better expressed with a + # scan rotation. + return ref_params.derive( + scan_pixel_pitch=jnp.abs(opt_res.value[0]), + ).normalize_types(), residual + + +# As returned by CoMUDF in the 'regression' buffer with +# RegressionOptions.SUBTRACT_LINEAR This allows preliminary calibration of +# descan error for a single camera length by adjusting constant tilt offset and +# tilt as a function of scan. +CoMRegression = np.ndarray[tuple[3, 2], np.floating] + + +# Type specification for dictionary where keys are calibrated camera lengths and +# values regression specifiers. This allows full calibration of descan error if at +# least two different camera lengths are provided. +CoMRegressions = dict[float, CoMRegression] + + +class _DEFullArgs(NamedTuple): + # Aligned with the CoM regression coordinate system. + # Currently only tested for no scan rotation and no flip_y + aligned_params: Parameters4DSTEM + regressions: CoMRegressions + + +@jax.jit +def _de_full_loss(y, args: _DEFullArgs): + de = DescanError(*y) + distances = [] + for cl, reg in args.regressions.items(): + opt_params = args.aligned_params.derive( + camera_length=cl, + descan_error=de, + ) + for scan_y in (0.0, 1.0): + for scan_x in (0.0, 1.0): + dy = reg[0, 0] + dx = reg[0, 1] + dydy = reg[1, 0] + dxdy = reg[1, 1] + dydx = reg[2, 0] + dxdx = reg[2, 1] + det_y = opt_params.detector_center.y + ( + dy + dydy * scan_y + dydx * scan_x + ) + det_x = opt_params.detector_center.x + ( + dx + dxdy * scan_y + dxdx * scan_x + ) + res = trace( + opt_params, + scan_pos=PixelYX(y=scan_y, x=scan_x), + source_dx=0.0, + source_dy=0.0, + ) + distances.extend( + ( + det_y - res["detector"].sampling["detector_px"].y, + det_x - res["detector"].sampling["detector_px"].x, + ) + ) + return jnp.array(distances) + + +def solve_full_descan_error(ref_params: Parameters4DSTEM, regressions: CoMRegressions): + # Caveat: scan and detector center of ref_params and of regressions should + # match. + + # Align coordinate system directions with native CoM coordinate + # system without corrections + aligned_params = ref_params.derive( + flip_factor=1.0, + scan_rotation=0.0, + detector_rotation=0.0, + ) + args = _DEFullArgs( + aligned_params=aligned_params, + regressions=regressions, + ) + + # Start with a small epsilon to prevent NaN results of yet unknown origin + # for some parameter combinations + start = jnp.full(shape=(len(DescanError()),), fill_value=1e-6) + opt_res = optimistix.least_squares( + fn=_de_full_loss, + args=args, + solver=optimistix.BFGS(atol=1e-12, rtol=1e-12), + y0=start, + ) + residual = _de_full_loss(opt_res.value, args) + + # Bring descan error back to original coordinate system + res_params = ( + aligned_params.derive(descan_error=DescanError(*opt_res.value)) + .adjust_scan_rotation(ref_params.scan_rotation) + .adjust_detector_rotation(ref_params.detector_rotation) + .adjust_flip_factor(ref_params.flip_factor) + .normalize_types() + ) + + return res_params, residual + + +class _NormArgs(NamedTuple): + ref_params: Parameters4DSTEM + + +def _zero_const(de: DescanError) -> DescanError: + return DescanError( + pxo_pxi=de.pxo_pxi, + pxo_pyi=de.pxo_pyi, + pyo_pxi=de.pyo_pxi, + pyo_pyi=de.pyo_pyi, + sxo_pxi=de.sxo_pxi, + sxo_pyi=de.sxo_pyi, + syo_pxi=de.syo_pxi, + syo_pyi=de.syo_pyi, + offpxi=0.0, + offpyi=0.0, + offsxi=0.0, + offsyi=0.0, + ) + + +@jax.jit +def _norm_loss(y, args: _NormArgs): + distances = [] + scy, scx, dcy, dcx = y + de_new = _zero_const(args.ref_params.descan_error) + for cl in (0, 1, 2): + opt_params = args.ref_params.derive( + camera_length=cl, + descan_error=de_new, + scan_center=PixelYX(y=scy, x=scx), + detector_center=PixelYX(y=dcy, x=dcx), + ) + ref_params = args.ref_params.derive( + camera_length=cl, + ) + for scan_y in ( + 0.0, + 1.0, + ): + for scan_x in (0.0, 1.0): + res = trace( + opt_params, + scan_pos=PixelYX(y=scan_y, x=scan_x), + source_dy=0.0, + source_dx=0.0, + ) + ref = trace( + ref_params, + scan_pos=PixelYX(y=scan_y, x=scan_x), + source_dy=0.0, + source_dx=0.0, + ) + distances.append( + ( + res["detector"].sampling["detector_px"].y + - ref["detector"].sampling["detector_px"].y, + res["detector"].sampling["detector_px"].x + - ref["detector"].sampling["detector_px"].x, + ) + ) + return jnp.array(distances) + + +def normalize_descan_error(ref_params: Parameters4DSTEM): + args = _NormArgs( + ref_params=ref_params, + ) + start = jnp.array( + ( + ref_params.scan_center.y, + ref_params.scan_center.x, + ref_params.detector_center.y, + ref_params.detector_center.x, + ) + ) + opt_res = optimistix.least_squares( + fn=_norm_loss, + args=args, + solver=optimistix.BFGS(atol=1e-12, rtol=1e-12), + y0=start, + ) + residual = _norm_loss(opt_res.value, args) + scy, scx, dcy, dcx = opt_res.value + res_params = ref_params.derive( + scan_center=PixelYX(y=scy, x=scx), + detector_center=PixelYX(y=dcy, x=dcx), + descan_error=_zero_const(ref_params.descan_error), + ).normalize_types() + return res_params, residual + + +class _DETiltArgs(NamedTuple): + # Aligned with the CoM regression coordinate system. + # Currently only tested for no scan rotation and no flip_y + aligned_params: Parameters4DSTEM + regression: CoMRegression + + +def _tilt_descan(de: DescanError, y) -> DescanError: + return DescanError( + pxo_pxi=de.pxo_pxi, + pxo_pyi=de.pxo_pyi, + pyo_pxi=de.pyo_pxi, + pyo_pyi=de.pyo_pyi, + sxo_pxi=y[0], + sxo_pyi=y[1], + syo_pxi=y[2], + syo_pyi=y[3], + offpxi=de.offpxi, + offpyi=de.offpyi, + offsxi=y[4], + offsyi=y[5], + ) + + +@jax.jit +def _de_tilt_loss(y, args: _DETiltArgs): + opt_params = args.aligned_params.derive( + descan_error=_tilt_descan(de=args.aligned_params.descan_error, y=y) + ) + + distances = [] + reg = args.regression + for scan_y in (0.0, 1.0): + for scan_x in (0.0, 1.0): + dy = reg[0, 0] + dx = reg[0, 1] + dydy = reg[1, 0] + dxdy = reg[1, 1] + dydx = reg[2, 0] + dxdx = reg[2, 1] + det_y = opt_params.detector_center.y + (dy + dydy * scan_y + dydx * scan_x) + det_x = opt_params.detector_center.x + (dx + dxdy * scan_y + dxdx * scan_x) + res = trace( + opt_params, + scan_pos=PixelYX(y=scan_y, x=scan_x), + source_dx=0.0, + source_dy=0.0, + ) + distances.extend( + ( + det_y - res["detector"].sampling["detector_px"].y, + det_x - res["detector"].sampling["detector_px"].x, + ) + ) + return jnp.array(distances) + + +def solve_tilt_descan_error(ref_params: Parameters4DSTEM, regression: CoMRegression): + # Caveat: scan and detector center of ref_params and of regressions should + # match. + + # Align coordinate system directions with native CoM coordinate + # system without corrections + # We make sure that the offset-based descan error components are preserved + aligned_params = ( + ref_params.adjust_flip_factor( + flip_factor=1.0, + ) + .adjust_scan_rotation( + scan_rotation=0.0, + ) + .adjust_detector_rotation( + detector_rotation=0.0, + ) + ) + args = _DETiltArgs( + aligned_params=aligned_params, + regression=regression, + ) + + # Start with a small epsilon to prevent NaN results of yet unknown origin + # for some parameter combinations + start = jnp.full(shape=(6,), fill_value=1e-6) + opt_res = optimistix.least_squares( + fn=_de_tilt_loss, + args=args, + solver=optimistix.BFGS(atol=1e-12, rtol=1e-12), + y0=start, + max_steps=10000, + ) + residual = _de_tilt_loss(opt_res.value, args) + + # Bring descan error back to original coordinate system + res_params = ( + aligned_params.derive( + descan_error=_tilt_descan(aligned_params.descan_error, opt_res.value) + ) + .adjust_detector_rotation(ref_params.detector_rotation) + .adjust_scan_rotation(ref_params.scan_rotation) + .adjust_flip_factor(ref_params.flip_factor) + .normalize_types() + ) + + return res_params, residual + + +class _DETiltPointArgs(NamedTuple): + params: Parameters4DSTEM + # [(scan_y, scan_x, detector_cy, detector_cx) * n] + points: jnp.ndarray + + +@jax.jit +def _de_tilt_point_loss(y, args: _DETiltPointArgs): + opt_params = args.params.derive( + descan_error=_tilt_descan(de=args.params.descan_error, y=y) + ) + + distances = [] + for scan_y, scan_x, det_y, det_x in args.points: + res = trace( + opt_params, + scan_pos=PixelYX(y=scan_y, x=scan_x), + source_dx=0.0, + source_dy=0.0, + ) + distances.extend( + ( + det_y - res["detector"].sampling["detector_px"].y, + det_x - res["detector"].sampling["detector_px"].x, + ) + ) + return jnp.array(distances) + + +def solve_tilt_descan_error_points(ref_params: Parameters4DSTEM, points: jnp.ndarray): + args = _DETiltPointArgs( + params=ref_params, + points=points, + ) + + # Start with a small epsilon to prevent NaN results of yet unknown origin + # for some parameter combinations + start = jnp.full(shape=(6,), fill_value=1e-6) + opt_res = optimistix.least_squares( + fn=_de_tilt_point_loss, + args=args, + # FIXME Doesn't reach 1e-12 like the others, for unknown reasons + solver=optimistix.BFGS(atol=1e-11, rtol=1e-11), + y0=start, + # FIXME needs more steps than others, for unknown reasons + max_steps=10000, + ) + residual = _de_tilt_point_loss(opt_res.value, args) + # Write the new tilts and offsets into the previous descan error + new_descan = _tilt_descan(ref_params.descan_error, opt_res.value) + res_params = ref_params.derive(descan_error=new_descan).normalize_types() + + return res_params, residual + + +class _CoordPointArgs(NamedTuple): + params: Parameters4DSTEM + # [(scan_y, scan_x, specimen_y (px), specimen_x (px), detector_y, detector_x) * n] + points: jnp.array + + +@jax.jit +def _coords_point_loss(y, args: _CoordPointArgs): + detector_rotation, overfocus, flip_factor = y[:3] + # We need to co-optimize the source tilts that hit the detector pixel for + # each point set because we can't easily calculate that directly + tilts = y[3:] + + assert len(tilts) == 2 * len(args.points) + + opt_params = args.params.derive( + detector_rotation=detector_rotation, + overfocus=overfocus, + flip_factor=flip_factor, + ) + + detector_distances = [] + specimen_distances = [] + for i, (scan_y, scan_x, spec_y, spec_x, det_y, det_x) in enumerate(args.points): + dy, dx = tilts[2 * i:2 * i + 2] + res = trace( + opt_params, scan_pos=PixelYX(y=scan_y, x=scan_x), source_dx=dx, source_dy=dy + ) + detector_distances.extend( + ( + res["detector"].sampling["detector_px"].y - det_y, + res["detector"].sampling["detector_px"].x - det_x, + ) + ) + specimen_distances.extend( + ( + res["specimen"].sampling["scan_px"].y - spec_y, + res["specimen"].sampling["scan_px"].x - spec_x, + ) + ) + + # Strongly encourage flip_factor in (-1., 1.) + aspect = jnp.array((jnp.abs(jnp.abs(flip_factor) - 1) * 100,)) + return jnp.concatenate( + (jnp.array(detector_distances), jnp.array(specimen_distances), aspect) + ) + + +def solve_coords_points(ref_params: Parameters4DSTEM, points: jnp.ndarray): + args = _CoordPointArgs( + params=ref_params, + points=points, + ) + + start = jnp.array( + [ref_params.detector_rotation, ref_params.overfocus, ref_params.flip_factor] + + [0.0, 0.0] * len(points) + ) + opt_res = optimistix.least_squares( + fn=_coords_point_loss, + args=args, + solver=optimistix.BFGS(atol=1e-12, rtol=1e-12), + y0=start, + max_steps=10000, + ) + residual = _coords_point_loss(opt_res.value, args) + # Write the new values into the previous parameters + detector_rotation, overfocus, flip_factor = opt_res.value[:3] + res_params = ref_params.derive( + detector_rotation=detector_rotation, + overfocus=overfocus, + flip_factor=flip_factor, + ).normalize_types() + + return res_params, residual + + +class _HitSpecimenArgs(NamedTuple): + params: Parameters4DSTEM + scan_pos: PixelYX + specimen_px: PixelYX + + +@jax.jit +def _hit_specimen_loss(y, args: _HitSpecimenArgs): + dy, dx = y + opt_params = args.params + + res = trace(opt_params, scan_pos=args.scan_pos, source_dx=dx, source_dy=dy) + specimen_px = res["specimen"].sampling["scan_px"] + return jnp.array( + (specimen_px.x - args.specimen_px.x, specimen_px.y - args.specimen_px.y) + ) + + +class SlopeYX(NamedTuple): + dy: float + dx: float + + +def solve_hit_specimen( + params: Parameters4DSTEM, scan_pos: PixelYX, specimen_px: PixelYX +): + args = _HitSpecimenArgs( + params=params, + scan_pos=scan_pos, + specimen_px=specimen_px, + ) + + start = jnp.array([0.0, 0.0]) + opt_res = optimistix.least_squares( + fn=_hit_specimen_loss, + args=args, + solver=optimistix.BFGS(atol=1e-12, rtol=1e-12), + y0=start, + max_steps=10000, + ) + residual = _hit_specimen_loss(opt_res.value, args) + # Write the new values into the previous parameters + dy, dx = opt_res.value + + return SlopeYX(dy=dy, dx=dx), residual diff --git a/src/microscope_calibration/util/stem_overfocus_sim.py b/src/microscope_calibration/util/stem_overfocus_sim.py index be1f6fa..778162b 100644 --- a/src/microscope_calibration/util/stem_overfocus_sim.py +++ b/src/microscope_calibration/util/stem_overfocus_sim.py @@ -1,16 +1,13 @@ -''' -Independent reference implementation of the ray tracing from detector to object -to allow simulating a dataset. - -This can then be used to test the UDF that performs the inverse projection. -''' +from typing import Optional +import jax; jax.config.update("jax_enable_x64", True) # noqa: E702 import numpy as np import numba -from libertem.analysis import com as com_analysis - -from microscope_calibration.common.stem_overfocus import OverfocusParams +from microscope_calibration.common.stem_overfocus import CoordMappingT, _do_lstsq +from microscope_calibration.common.model import ( + Parameters4DSTEM, Model4DSTEM, PixelYX, CoordXY, trace +) def smiley(size): @@ -54,129 +51,147 @@ def smiley(size): return obj -def get_transformation_matrix(sim_params: OverfocusParams): +def get_forward_transformation_matrix( + sim_params: Parameters4DSTEM, specimen_to_image: Optional[CoordMappingT] = None): ''' - Calculate a transformation matrix for :func:`detector_px_to_specimen_px` - from the provided parameters. + Calculate a transformation matrix that maps from scan position in scan pixel + coordinates and detector pixel coordinates to specimen coordinates in scan + pixel coordinates and tilt of the ray at the source. + + Using a matrix multiplication instead of solving for ray solutions for each + pixel greatly improves performance. + + The input values for that matrix correspond to the pixel indices in a 4D + STEM dataset. - Internally this uses :func:`libertem.analysis.com.apply_correction` to - transform unit vectors in order to determine the matrix. + The specimen position from the output can be used to pick the right value + from an object. The tilt can be used to determine if the beam passes through + through the microscope or if it is blocked by the beam-shaping aperture. + + It may be possible to derive this matrix from partial derivatives of the + model. However, this is postponed for now since this matrix mixes input and + output values with respect of the model, so one may have to work with a + combination of forward and inverse derivatives. + + For the time being this method traces a number of sample rays and deduces the + mapping matrix from these samples. ''' - transformation_matrix = np.array(com_analysis.apply_correction( - y_centers=np.array((1, 0)), - x_centers=np.array((0, 1)), - scan_rotation=sim_params['scan_rotation'], - flip_y=sim_params['flip_y'], + + # scan position y/x, source tilt y/x + test_parameters = np.array(( + [0., 0., 0., 0.], + [100., 100., 0., 0.], + [-100., 100., 0., 0.], + [10., 0., 0., 0.], + [0., 10., 0., 0.], + [0., 0., 0.1, 0.], + [0., 0., 0., 0.1], + [1., 1., 1., 1.], + [1., 2., 3., 4.], )) - return transformation_matrix + input_samples = [] + output_samples = [] + + for test_param_raw in test_parameters: + # We are paranoid and confirm that the model is linear + for factor in (1., 2.): + test_param = test_param_raw * factor + scan_pos = PixelYX(x=test_param[0], y=test_param[1]) + source_dy = test_param[2] + source_dx = test_param[3] + res = trace( + params=sim_params, + scan_pos=scan_pos, + source_dy=source_dy, + source_dx=source_dx + ) + if specimen_to_image is None: + spec_px = res['specimen'].sampling['scan_px'] + else: + spec_px = specimen_to_image(CoordXY( + x=res['specimen'].ray.x, + y=res['specimen'].ray.y + )) + input_sample = ( + scan_pos.y, + scan_pos.x, + res['detector'].sampling['detector_px'].y, + res['detector'].sampling['detector_px'].x, + 1. + ) + output_sample = ( + spec_px.y, + spec_px.x, + source_dy, + source_dx, + 1., + ) + output_samples.append(output_sample) + input_samples.append(input_sample) -@numba.njit(inline='always', cache=True) -def detector_px_to_specimen_px( - y_px, x_px, cy, cx, detector_pixel_size, scan_pixel_size, camera_length, - overfocus, transformation_matrix, fov_size_y, fov_size_x): - ''' - Model Figure 2 of https://arxiv.org/abs/2403.08538 - - The pixel coordinates refer to the center of a pixel: In :func:`_project` - they are rounded to the nearest integer. This function is just transforming - coordinates independent of actual scan and detector sizes. Rounding and - bounds checks are performed in :func:`_project`. - - The specimen pixel coordinates calculated by this function are combined with - the scan coordinates in :func:`_project` to model the scan. - - Parameters - ---------- - - y_px, x_px : float - Detector pixel coordinates to project. They are relative to (cy, cx), - where specifying pixel coordinates (0.0, 0.0) maps to physical - coordinates (-cy * detector_pixel_size, -cx *detector_pixel_size), and - pixel coordinates (cy, cx) map to physical coordinates (0.0. 0.0). - cy, cx : float - Detector center in detector pixel coordinates. This defines the position - of the "straight through" beam on the detector. - detector_pixel_size, scan_pixel_size : float - Physical pixel sizes in m. This assumes a uniform scan and detector grid - in x and y direction - camera_length : float - Virtual distance from specimen to detector in m - overfocus : float - Virtual distance from focus point to specimen in m. Underfocus is - specified as a negative overfocus. - transformation_matrix : np.ndarray[float] - 2x2 transformation matrix for detector coordinates. It acts around (cy, - cx). This is used to specify rotation and handedness change consistent - with other methods in LiberTEM. It can be calculated with - :fun:`get_transformation_matrix`. - fov_size_y, fov_size_x : float - Size of the scan area (field of view) in scan pixels. The scan - coordinate system is centered in the middle of this field of view, - meaning that the "straight through" beam (y_px, x_px) == (cy, cx) is - mapped to (fov_size_y/2, fov_size_x/2). Please note that the actual scan - coordinates are not calculated in this function, but added as an offset - in :func:`_project`. The field of view specified here is just used to calculate - the center of the "straight through" beam in the middle of the scan. - - Returns - ------- - specimen_px_y, specimen_px_x : float - Beam position on the specimen in scan pixel coordinates. - ''' - position_y, position_x = (y_px - cy) * detector_pixel_size, (x_px - cx) * detector_pixel_size - position_y, position_x = transformation_matrix @ np.array((position_y, position_x)) - specimen_position_y = position_y / (overfocus + camera_length) * overfocus - specimen_position_x = position_x / (overfocus + camera_length) * overfocus - specimen_px_x = specimen_position_x / scan_pixel_size + fov_size_x / 2 - specimen_px_y = specimen_position_y / scan_pixel_size + fov_size_y / 2 - return specimen_px_y, specimen_px_x + output_samples = np.array(output_samples) + input_samples = np.array(input_samples) + + return _do_lstsq(input_samples, output_samples) @numba.njit(cache=True) -def _project( - image, cy, cx, detector_pixel_size, scan_pixel_size, camera_length, - overfocus, transformation_matrix, result_out): - scan_shape = result_out.shape[:2] - for det_y in range(result_out.shape[2]): - for det_x in range(result_out.shape[3]): - specimen_px_y, specimen_px_x = detector_px_to_specimen_px( - y_px=det_y, - x_px=det_x, - cy=cy, - cx=cx, - detector_pixel_size=detector_pixel_size, - scan_pixel_size=scan_pixel_size, - camera_length=camera_length, - overfocus=overfocus, - transformation_matrix=transformation_matrix, - fov_size_y=image.shape[0], - fov_size_x=image.shape[1], +def project_frame_forward(obj, source_semiconv, mat, scan_y, scan_x, out): + limit = np.abs(np.tan(source_semiconv))**2 + for det_y in range(out.shape[0]): + for det_x in range(out.shape[1]): + # Manually unrolled matrix-vector product to allow skipping before + # calculating all values and facilitate auto-vectorization of the + # loop + + # _one = ( + # scan_y * mat[0, 4] + scan_x * mat[1, 4] + # + det_y * mat[2, 4] + det_x * mat[3, 4] + mat[4, 4] + # ) + # assert np.allclose(_one, 1) + tilt_y = ( + scan_y * mat[0, 2] + scan_x * mat[1, 2] + + det_y * mat[2, 2] + det_x * mat[3, 2] + mat[4, 2] + ) + tilt_x = ( + scan_y * mat[0, 3] + scan_x * mat[1, 3] + + det_y * mat[2, 3] + det_x * mat[3, 3] + mat[4, 3] ) - for scan_y in range(scan_shape[0]): - for scan_x in range(scan_shape[1]): - offset_y = scan_y - scan_shape[0] // 2 - offset_x = scan_x - scan_shape[1] // 2 - image_px_y = int(np.round(specimen_px_y + offset_y)) - image_px_x = int(np.round(specimen_px_x + offset_x)) - if image_px_y < 0 or image_px_y >= image.shape[0]: - continue - if image_px_x < 0 or image_px_x >= image.shape[1]: - continue - result_out[scan_y, scan_x, det_y, det_x] = image[image_px_y, image_px_x] - - -def project(image, scan_shape, detector_shape, sim_params: OverfocusParams): + if np.abs(tilt_y)**2 + np.abs(tilt_x)**2 < limit: + spec_y = ( + scan_y * mat[0, 0] + scan_x * mat[1, 0] + + det_y * mat[2, 0] + det_x * mat[3, 0] + mat[4, 0] + ) + spec_x = ( + scan_y * mat[0, 1] + scan_x * mat[1, 1] + + det_y * mat[2, 1] + det_x * mat[3, 1] + mat[4, 1] + ) + spec_y = int(np.round(spec_y)) + spec_x = int(np.round(spec_x)) + if spec_y >= 0 and spec_y < obj.shape[0] and spec_x >= 0 and spec_x < obj.shape[1]: + out[det_y, det_x] = obj[spec_y, spec_x] + else: + out[det_y, det_x] = 0. + + +def project( + image, scan_shape, detector_shape, + sim_params: Parameters4DSTEM, + specimen_to_image: Optional[CoordMappingT] = None): result = np.zeros(tuple(scan_shape) + tuple(detector_shape), dtype=image.dtype) - _project( - image=image, - cy=sim_params['cy'], - cx=sim_params['cx'], - detector_pixel_size=sim_params['detector_pixel_size'], - scan_pixel_size=sim_params['scan_pixel_size'], - camera_length=sim_params['camera_length'], - overfocus=sim_params['overfocus'], - transformation_matrix=get_transformation_matrix(sim_params), - result_out=result + mat = get_forward_transformation_matrix( + sim_params=sim_params, specimen_to_image=specimen_to_image ) + model = Model4DSTEM.build(params=sim_params, scan_pos=PixelYX(x=0., y=0.)) + for scan_y in range(result.shape[0]): + for scan_x in range(result.shape[1]): + project_frame_forward( + obj=image, + source_semiconv=model.source.semi_conv, + mat=mat, + scan_y=scan_y, + scan_x=scan_x, + out=result[scan_y, scan_x] + ) return result diff --git a/test_requirements.txt b/test_requirements.txt new file mode 100644 index 0000000..462c26e --- /dev/null +++ b/test_requirements.txt @@ -0,0 +1 @@ +optax diff --git a/tests/conftest.py b/tests/conftest.py new file mode 100644 index 0000000..273ae5a --- /dev/null +++ b/tests/conftest.py @@ -0,0 +1,30 @@ +import pytest + +import numpy as np + +from microscope_calibration.common.model import Parameters4DSTEM, PixelYX, DescanError + + +@pytest.fixture +def random_params() -> Parameters4DSTEM: + return Parameters4DSTEM( + overfocus=np.random.uniform(0.1, 2), + scan_pixel_pitch=np.random.uniform(0.01, 2), + scan_center=PixelYX( + y=np.random.uniform(-10, 10), + x=np.random.uniform(-10, 10), + ), + scan_rotation=np.random.uniform(-np.pi, np.pi), + camera_length=np.random.uniform(0.1, 2), + detector_pixel_pitch=np.random.uniform(0.01, 2), + detector_center=PixelYX( + y=np.random.uniform(-10, 10), + x=np.random.uniform(-10, 10), + ), + semiconv=np.random.uniform(0.0001, np.pi/2), + flip_factor=np.random.choice([-1., 1.]), + descan_error=DescanError( + *np.random.uniform(-1, 1, size=len(DescanError())) + ), + detector_rotation=np.random.uniform(-np.pi, np.pi), + ) diff --git a/tests/test_calibration.py b/tests/test_calibration.py deleted file mode 100644 index 4a50232..0000000 --- a/tests/test_calibration.py +++ /dev/null @@ -1,24 +0,0 @@ -from libertem.api import Context - -from microscope_calibration.udf.stem_overfocus import ( - OverfocusUDF, OverfocusParams, -) - - -def test_smoke(): - ctx = Context.make_with('inline') - ds = ctx.load('memory', datashape=(6, 7, 8, 9)) - udf = OverfocusUDF( - overfocus_params=OverfocusParams( - overfocus=0.0001, - camera_length=0.15, - scan_pixel_size=1e-6, - detector_pixel_size=55e-6, - semiconv=0.02, - cy=3, - cx=4, - flip_y=False, - scan_rotation=23, - ), - ) - ctx.run_udf(dataset=ds, udf=udf) diff --git a/tests/test_model.py b/tests/test_model.py new file mode 100644 index 0000000..7934062 --- /dev/null +++ b/tests/test_model.py @@ -0,0 +1,1305 @@ +import pytest +from numpy.testing import assert_allclose + +import jax; jax.config.update("jax_enable_x64", True) # noqa: E702 +import jax_dataclasses as jdc +from libertem.udf.com import guess_corrections, apply_correction +import numpy as np +import jax.numpy as jnp + +from temgym_core.ray import Ray +from temgym_core.components import DescanError, Component +from temgym_core.propagator import Propagator +from temgym_core.source import Source +from temgym_core import PixelYX + +from microscope_calibration.common.model import Parameters4DSTEM, Model4DSTEM, trace + + +def test_params(): + params = Parameters4DSTEM( + overfocus=0.7, + scan_pixel_pitch=0.005, + scan_center=PixelYX(y=17, x=13), + scan_rotation=1.234, + camera_length=2.3, + detector_pixel_pitch=0.0247, + detector_center=PixelYX(y=11, x=19), + semiconv=0.023, + flip_factor=-1., + descan_error=DescanError(offpxi=.345, pxo_pxi=948) + ) + model = Model4DSTEM.build(params=params, scan_pos=PixelYX(y=13, x=7)) + assert model.params == params + + +def test_inverse(): + params = Parameters4DSTEM( + overfocus=0.7, + scan_pixel_pitch=0.005, + scan_center=PixelYX(y=17, x=13), + scan_rotation=1.234, + camera_length=2.3, + detector_pixel_pitch=0.0247, + detector_center=PixelYX(y=11, x=19), + detector_rotation=2.134, + semiconv=0.023, + flip_factor=-1., + descan_error=DescanError(offpxi=.345, pxo_pxi=948) + ) + model = Model4DSTEM.build(params=params, scan_pos=PixelYX(y=13, x=7)) + assert_allclose( + model._scan_to_real, + jnp.linalg.inv(model._real_to_scan) + ) + assert_allclose( + model._detector_to_real, + jnp.linalg.inv(model._real_to_detector) + ) + + +def test_trace_smoke(): + params = Parameters4DSTEM( + overfocus=0.7, + scan_pixel_pitch=0.005, + scan_center=PixelYX(y=17, x=13), + scan_rotation=1.234, + camera_length=2.3, + detector_pixel_pitch=0.0247, + detector_center=PixelYX(y=11, x=19), + semiconv=0.023, + flip_factor=-1., + descan_error=DescanError() + ) + res = trace(params=params, scan_pos=PixelYX(y=13, x=7), source_dx=0.034, source_dy=0.042) + keys = ( + 'source', 'overfocus', 'scanner', 'specimen', 'descanner', + 'camera_length', 'detector' + ) + for key in keys: + assert key in res + sect = res[key] + assert isinstance(sect.ray, Ray) + components = ('scanner', 'specimen', 'descanner', 'detector') + propagators = ('camera_length', 'camera_length') + for key in components: + sect = res[key] + assert isinstance(sect.component, Component) + for key in propagators: + sect = res[key] + assert isinstance(sect.component, Propagator) + assert isinstance(res['source'].component, Source) + assert isinstance(res['specimen'].sampling['scan_px'], PixelYX) + assert isinstance(res['detector'].sampling['detector_px'], PixelYX) + + +def test_trace_focused(): + params = Parameters4DSTEM( + overfocus=0., + scan_pixel_pitch=0.005, + scan_center=PixelYX(y=17, x=13), + scan_rotation=1.234, + camera_length=2.3, + detector_pixel_pitch=0.0247, + detector_center=PixelYX(y=11, x=19), + semiconv=0.023, + flip_factor=-1., + descan_error=DescanError() + ) + res1 = trace(params=params, scan_pos=PixelYX(y=13, x=7), source_dx=0.034, source_dy=0.042) + res2 = trace(params=params, scan_pos=PixelYX(y=13, x=7), source_dx=0., source_dy=0.) + assert_allclose(res1['specimen'].ray.x, res2['specimen'].ray.x) + assert_allclose(res1['specimen'].ray.y, res2['specimen'].ray.y) + assert_allclose(res1['specimen'].sampling['scan_px'].x, 7) + assert_allclose(res1['specimen'].sampling['scan_px'].y, 13) + + +def test_trace_noproject(): + params = Parameters4DSTEM( + overfocus=0.123, + scan_pixel_pitch=0.005, + scan_center=PixelYX(y=17, x=13), + scan_rotation=1.234, + camera_length=0., + detector_pixel_pitch=0.0247, + detector_center=PixelYX(y=11, x=19), + semiconv=0.023, + flip_factor=-1., + descan_error=DescanError() + ) + trace(params=params, scan_pos=PixelYX(y=13, x=7), source_dx=0.034, source_dy=0.042) + + +def test_trace_underfocused_smoke(): + params = Parameters4DSTEM( + overfocus=-0.23, + scan_pixel_pitch=0.005, + scan_center=PixelYX(y=17, x=13), + scan_rotation=1.234, + camera_length=2.3, + detector_pixel_pitch=0.0247, + detector_center=PixelYX(y=11, x=19), + semiconv=0.023, + flip_factor=-1., + descan_error=DescanError() + ) + trace(params=params, scan_pos=PixelYX(y=13, x=7), source_dx=0.034, source_dy=0.042) + + +# Beam straight along the optical axis, no scan deflection, scan and detector +# coordinate system identical with physical coordinates. +def test_straight(): + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + scan_center=PixelYX(y=0., x=0.), + scan_rotation=0., + camera_length=1, + detector_pixel_pitch=1, + detector_center=PixelYX(y=0., x=0.), + semiconv=0.023, + flip_factor=1., + descan_error=DescanError() + ) + res = trace(params=params, scan_pos=PixelYX(y=0., x=0.), source_dx=0., source_dy=0.) + + for key, sect in res.items(): + if isinstance(sect.component, Component) or isinstance(sect.component, Source): + assert sect.component.z == sect.ray.z + assert sect.component.z == sect.ray.pathlength + assert sect.ray.x == 0. + assert sect.ray.y == 0. + assert res['detector'].ray.z == params.overfocus + params.camera_length + assert res['source'].ray.z == 0. + assert res['specimen'].sampling['scan_px'] == PixelYX(x=0., y=0.) + assert res['detector'].sampling['detector_px'] == PixelYX(x=0., y=0.) + + +# Scan deflection test: beam is shifted +@pytest.mark.parametrize( + 'dy', (-0.2, 0., 0.34) +) +@pytest.mark.parametrize( + 'dx', (-0.7, 0., 0.42) +) +@pytest.mark.parametrize( + 'scan_y', (-17, 0., 23.4) +) +@pytest.mark.parametrize( + 'scan_x', (-23, 0., 29) +) +def test_scan(dy, dx, scan_y, scan_x): + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + scan_center=PixelYX(y=0., x=0.), + scan_rotation=0., + camera_length=1, + detector_pixel_pitch=1, + detector_center=PixelYX(y=0., x=0.), + semiconv=0.023, + flip_factor=1., + descan_error=DescanError() + ) + res_straight = trace(params=params, scan_pos=PixelYX(y=0., x=0.), source_dx=dx, source_dy=dy) + res = trace(params=params, scan_pos=PixelYX(y=scan_y, x=scan_x), source_dx=dx, source_dy=dy) + + for key in res.keys(): + sect = res[key] + sect_straight = res_straight[key] + assert sect.ray.z == sect_straight.ray.z + assert sect.ray.pathlength == sect_straight.ray.pathlength + if isinstance(sect.component, Component) or isinstance(sect.component, Source): + assert sect.component.z == sect.ray.z + assert sect.component.z == sect.ray.pathlength + # Beam is deflected + if key in ('scanner', 'specimen'): + assert sect.ray.x - sect_straight.ray.x == scan_x + assert sect.ray.y - sect_straight.ray.y == scan_y + # Beam is not deflected + else: + assert_allclose(sect.ray.x, sect_straight.ray.x) + assert_allclose(sect.ray.y, sect_straight.ray.y) + # Ray propagates straight + assert_allclose(sect.ray.x, sect.ray.z * dx) + assert_allclose(sect.ray.y, sect.ray.z * dy) + assert_allclose(res['detector'].ray.z, params.overfocus + params.camera_length) + assert_allclose(res['source'].ray.z, 0.) + # Correct scan deflection + assert_allclose( + res['specimen'].sampling['scan_px'], + PixelYX( + x=scan_x + res_straight['specimen'].sampling['scan_px'].x, + y=scan_y + res_straight['specimen'].sampling['scan_px'].y + ) + ) + # Check that central ray goes through scan position + if dx == 0. and dy == 0.: + assert_allclose( + res['specimen'].sampling['scan_px'], + PixelYX( + x=scan_x, + y=scan_y, + ), + rtol=1e-12, atol=1e-12 + ) + # check physical coords equals pixel coords + assert_allclose( + res['specimen'].sampling['scan_px'], + PixelYX( + x=res['specimen'].ray.x, + y=res['specimen'].ray.y, + ) + ) + assert_allclose(res['detector'].sampling['detector_px'], PixelYX( + x=dx*(params.overfocus + params.camera_length), + y=dy*(params.overfocus + params.camera_length) + )) + # check physical coords equals pixel coords + assert_allclose( + res['detector'].sampling['detector_px'], + PixelYX( + x=res['detector'].ray.x, + y=res['detector'].ray.y, + ) + ) + + +# detector coordinate systems +@pytest.mark.parametrize( + 'detector_cycx', ((-0.11, 43.), (0., 0.)) +) +@pytest.mark.parametrize( + 'detector_pixel_pitch', (0.09, 1., 1.53) +) +@pytest.mark.parametrize( + 'flip_factor', (-1., 1.) +) +@pytest.mark.parametrize( + 'dydx', ((0., 0.), (-0.2, 0.42)) +) +def test_detector_coordinate_shift_scale_flip( + detector_cycx, detector_pixel_pitch, flip_factor, dydx): + detector_cy, detector_cx = detector_cycx + scan_cy = -0.7 + scan_cx = 23. + scan_pixel_pitch = 1.34 + dy, dx = dydx + scan_y = -17 + scan_x = 29 + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=scan_pixel_pitch, + scan_center=PixelYX(y=scan_cy, x=scan_cx), + scan_rotation=0., + camera_length=1, + detector_pixel_pitch=detector_pixel_pitch, + detector_center=PixelYX(y=detector_cy, x=detector_cx), + semiconv=0.023, + flip_factor=flip_factor, + descan_error=DescanError() + ) + res = trace(params=params, scan_pos=PixelYX(y=scan_y, x=scan_x), source_dx=dx, source_dy=dy) + # check physical coords vs pixel coords scale and shift + assert_allclose( + res['specimen'].sampling['scan_px'], + PixelYX( + x=res['specimen'].ray.x/scan_pixel_pitch + scan_cx, + y=res['specimen'].ray.y/scan_pixel_pitch + scan_cy, + ), + rtol=1e-12, atol=1e-12 + ) + # check physical coords vs pixel coords scale and shift + assert_allclose( + res['detector'].sampling['detector_px'], + PixelYX( + x=res['detector'].ray.x/detector_pixel_pitch + detector_cx, + y=flip_factor*(res['detector'].ray.y/detector_pixel_pitch + flip_factor*detector_cy), + ), + rtol=1e-12, atol=1e-12 + ) + if dy == 0.: + assert_allclose( + res['detector'].sampling['detector_px'].y, + detector_cy + ) + if dx == 0.: + assert_allclose( + res['detector'].sampling['detector_px'].x, + detector_cx + ) + + +# scan coordinate systems +@pytest.mark.parametrize( + 'scan_cy', (-0.7, 0., 21) +) +@pytest.mark.parametrize( + 'scan_cx', (-0.22, 0., 23) +) +@pytest.mark.parametrize( + 'scan_pixel_pitch', (0.07, 1., 1.34) +) +def test_scan_coordinate_shift_scale(scan_cy, scan_cx, scan_pixel_pitch): + detector_cy = -11. + detector_cx = 43. + detector_pixel_pitch = 0.09 + flip_factor = -1. + dy = -0.2 + dx = 0.42 + scan_y = -17 + scan_x = 29 + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=scan_pixel_pitch, + scan_center=PixelYX(y=scan_cy, x=scan_cx), + scan_rotation=0., + camera_length=1, + detector_pixel_pitch=detector_pixel_pitch, + detector_center=PixelYX(y=detector_cy, x=detector_cx), + semiconv=0.023, + flip_factor=flip_factor, + descan_error=DescanError() + ) + res = trace(params=params, scan_pos=PixelYX(y=scan_y, x=scan_x), source_dx=dx, source_dy=dy) + # check physical coords vs pixel coords scale and shift + assert_allclose( + res['specimen'].sampling['scan_px'], + PixelYX( + x=res['specimen'].ray.x/scan_pixel_pitch + scan_cx, + y=res['specimen'].ray.y/scan_pixel_pitch + scan_cy, + ), + rtol=1e-12, atol=1e-12 + ) + flip_factor = -1. if flip_factor else 1. + # check physical coords vs pixel coords scale and shift + assert_allclose( + res['detector'].sampling['detector_px'], + PixelYX( + x=res['detector'].ray.x/detector_pixel_pitch + detector_cx, + y=flip_factor*res['detector'].ray.y/detector_pixel_pitch + detector_cy, + ), + rtol=1e-12, atol=1e-12 + ) + + +@pytest.mark.parametrize( + # work in exact degree values since guess_corrections() can only + # find these exactly. Otherwise we have larger residuals + 'scan_rotation', (73/180*np.pi, 0, 23/180*np.pi) +) +@pytest.mark.parametrize( + 'flip_factor', (1., -1.) +) +@pytest.mark.parametrize( + 'detector_cy', (-13, 0., 7) +) +@pytest.mark.parametrize( + 'detector_cx', (-11, 0., 5) +) +def test_com_validation(scan_rotation, flip_factor, detector_cy, detector_cx): + @jdc.pytree_dataclass + class PointChargeComponent(Component): + z: float + + def __call__(self, ray: Ray) -> Ray: + distance = np.linalg.norm(np.array((ray.y, ray.x))) + if distance > 1e-6: + # field strength is 1/distance**2, + # additionally normalize displacement to unit vector + dx = -ray.x / distance**3 * 1e-2 + dy = -ray.y / distance**3 * 1e-2 + return ray.derive(dx=ray.dx+dx, dy=ray.dy+dy) + else: + return ray + + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + scan_center=PixelYX(y=0., x=0.), + scan_rotation=scan_rotation, + camera_length=1, + detector_pixel_pitch=1, + detector_center=PixelYX(y=detector_cy, x=detector_cx), + semiconv=0.023, + flip_factor=flip_factor, + descan_error=DescanError() + ) + + y_deflections = np.linspace(start=-1, stop=1, num=3) + x_deflections = np.linspace(start=-1, stop=1, num=3) + com_y = np.empty((len(y_deflections), len(x_deflections))) + com_x = np.empty((len(y_deflections), len(x_deflections))) + for y, scan_y in enumerate(y_deflections): + for x, scan_x in enumerate(x_deflections): + model = Model4DSTEM.build( + params=params, + scan_pos=PixelYX(x=float(scan_x), y=float(scan_y)), + specimen=PointChargeComponent(z=params.overfocus) + ) + ray = model.make_source_ray(source_dx=0., source_dy=0.).ray + res = model.trace(ray) + # Validate that the ray is deflected towards the center + # by the point charge component + phys_y = res['detector'].ray.y + phys_x = res['detector'].ray.x + pass_y = res['specimen'].ray.y + pass_x = res['specimen'].ray.x + if phys_y != 0 or phys_x != 0: + assert_allclose( + # The displacement in the detector plane in corrected pixel + # coordinates is pointing in the opposite direction of the + # displacement from the center when passing through the + # specimen plane, i.e. the beam is deflected towards the + # center + np.array((phys_y, phys_x))/np.linalg.norm((phys_y, phys_x)), + -np.array((pass_y, pass_x))/np.linalg.norm((pass_y, pass_x)) + ) + com_y[y, x] = res['detector'].sampling['detector_px'].y + com_x[y, x] = res['detector'].sampling['detector_px'].x + + guess_result = guess_corrections(y_centers=com_y, x_centers=com_x) + corrected_y, corrected_x = apply_correction( + y_centers=com_y-detector_cy, x_centers=com_x-detector_cx, + scan_rotation=guess_result.scan_rotation, + flip_y=guess_result.flip_y, + ) + # Make sure the correction actually corrected + for y, scan_y in enumerate(y_deflections): + for x, scan_x in enumerate(x_deflections): + if corrected_y[y, x] != 0 or corrected_x[y, x] != 0: + assert_allclose( + # The corrected displacement in corrected pixel coordinates + # in the detector plane is pointing in the opposite + # direction of the displacement from the center in scan + # coordinates + np.array((scan_y, scan_x))/np.linalg.norm((scan_y, scan_x)), + -np.array(( + corrected_y[y, x], corrected_x[y, x] + ))/np.linalg.norm(( + corrected_y[y, x], corrected_x[y, x] + )), + atol=1e-12, rtol=1e-12 + ) + + assert_allclose( + -guess_result.scan_rotation / 180 * np.pi, + scan_rotation, + atol=1e-12, + rtol=1e-4 + ) + if flip_factor == 1.: + flip_y = False + elif flip_factor == -1.: + flip_y = True + else: + raise ValueError(0) + assert guess_result.flip_y == flip_y + assert_allclose(guess_result.cy, detector_cy, atol=1e-2, rtol=1e-2) + assert_allclose(guess_result.cx, detector_cx, atol=1e-2, rtol=1e-2) + assert_allclose(guess_result.cy, detector_cy, atol=1e-2, rtol=1e-2) + assert_allclose(guess_result.cx, detector_cx, atol=1e-2, rtol=1e-2) + + +def test_rotation_direction_0(): + # Check conformance with + # https://libertem.github.io/LiberTEM/concepts.html#coordinate-system: y + # points down, x to the right, z away, and therefore positive scan rotation + # rotates the scan points to the right. + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + scan_center=PixelYX(y=0., x=0.), + scan_rotation=0., + camera_length=1, + detector_pixel_pitch=1, + detector_center=PixelYX(y=0., x=0.), + semiconv=0.023, + flip_factor=1., + descan_error=DescanError() + ) + res = trace(params=params, scan_pos=PixelYX(y=0., x=1.), source_dx=0., source_dy=0.) + assert_allclose(res['specimen'].sampling['scan_px'].x, 1., atol=1e-12, rtol=1e-12) + assert_allclose(res['specimen'].sampling['scan_px'].y, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['specimen'].ray.x, 1., atol=1e-12, rtol=1e-12) + assert_allclose(res['specimen'].ray.y, 0., atol=1e-12, rtol=1e-12) + + res = trace(params=params, scan_pos=PixelYX(y=1., x=0.), source_dx=0., source_dy=0.) + assert_allclose(res['specimen'].sampling['scan_px'].x, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['specimen'].sampling['scan_px'].y, 1., atol=1e-12, rtol=1e-12) + assert_allclose(res['specimen'].ray.x, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['specimen'].ray.y, 1., atol=1e-12, rtol=1e-12) + + +@pytest.mark.parametrize( + 'flip_factor', (1., -1.) +) +def test_rotation_direction_90(flip_factor): + # Check conformance with + # https://libertem.github.io/LiberTEM/concepts.html#coordinate-system: y + # points down, x to the right, z away, and therefore positive scan rotation + # rotates the scan points to the right in physical coordinates + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + scan_center=PixelYX(y=0., x=0.), + scan_rotation=np.pi/2, + camera_length=1, + detector_pixel_pitch=1, + detector_center=PixelYX(y=0., x=0.), + semiconv=0.023, + flip_factor=flip_factor, + descan_error=DescanError() + ) + res = trace(params=params, scan_pos=PixelYX(y=0., x=1.), source_dx=0., source_dy=0.) + + assert_allclose(res['specimen'].sampling['scan_px'].x, 1., atol=1e-12, rtol=1e-12) + assert_allclose(res['specimen'].sampling['scan_px'].y, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['specimen'].ray.x, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['specimen'].ray.y, 1., atol=1e-12, rtol=1e-12) + + res = trace(params=params, scan_pos=PixelYX(y=1., x=0.), source_dx=0., source_dy=0.) + assert_allclose(res['specimen'].sampling['scan_px'].x, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['specimen'].sampling['scan_px'].y, 1., atol=1e-12, rtol=1e-12) + assert_allclose(res['specimen'].ray.x, -1., atol=1e-12, rtol=1e-12) + assert_allclose(res['specimen'].ray.y, 0., atol=1e-12, rtol=1e-12) + + +def test_detector_px(): + # Check conformance with + # https://libertem.github.io/LiberTEM/concepts.html#coordinate-system: y + # points down, x to the right, z away. + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + scan_center=PixelYX(y=0., x=0.), + scan_rotation=0., + camera_length=1, + detector_pixel_pitch=1, + detector_center=PixelYX(y=0., x=0.), + semiconv=0.023, + flip_factor=1., + descan_error=DescanError() + ) + res = trace(params=params, scan_pos=PixelYX(y=0., x=0.), source_dx=0.5, source_dy=0.) + assert_allclose(res['detector'].sampling['detector_px'].x, 1., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].sampling['detector_px'].y, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.x, 1., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.y, 0., atol=1e-12, rtol=1e-12) + + res = trace( + params=params, + scan_pos=PixelYX(y=0., x=0.), + source_dx=0., source_dy=0.5 + ) + assert_allclose(res['detector'].sampling['detector_px'].x, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].sampling['detector_px'].y, 1., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.x, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.y, 1., atol=1e-12, rtol=1e-12) + + +def test_detector_px_flipy(): + # Check conformance with + # https://libertem.github.io/LiberTEM/concepts.html#coordinate-system: y + # points down, x to the right, z away. + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + scan_center=PixelYX(y=0., x=0.), + scan_rotation=0., + camera_length=1, + detector_pixel_pitch=1, + detector_center=PixelYX(y=0., x=0.), + detector_rotation=0., + semiconv=0.023, + flip_factor=-1., + descan_error=DescanError() + ) + model = Model4DSTEM.build( + params=params, + scan_pos=PixelYX(y=0., x=0.) + ) + ray = model.make_source_ray(source_dx=0.5, source_dy=0.).ray + res = model.trace(ray) + assert_allclose(res['detector'].sampling['detector_px'].x, 1., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].sampling['detector_px'].y, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.x, 1., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.y, 0., atol=1e-12, rtol=1e-12) + + model = Model4DSTEM.build( + params=params, + scan_pos=PixelYX(y=0., x=0.) + ) + ray = model.make_source_ray(source_dx=0., source_dy=0.5).ray + res = model.trace(ray) + assert_allclose(res['detector'].sampling['detector_px'].x, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].sampling['detector_px'].y, -1., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.x, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.y, 1., atol=1e-12, rtol=1e-12) + + +def test_detector_px_rotate(): + # Check conformance with + # https://libertem.github.io/LiberTEM/concepts.html#coordinate-system: y + # points down, x to the right, z away. + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + scan_center=PixelYX(y=0., x=0.), + scan_rotation=0., + camera_length=1, + detector_pixel_pitch=1, + detector_center=PixelYX(y=0., x=0.), + detector_rotation=np.pi/2, + semiconv=0.023, + flip_factor=1., + descan_error=DescanError() + ) + model = Model4DSTEM.build( + params=params, + scan_pos=PixelYX(y=0., x=0.) + ) + ray = model.make_source_ray(source_dx=0.5, source_dy=0.).ray + res = model.trace(ray) + assert_allclose(res['detector'].sampling['detector_px'].x, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].sampling['detector_px'].y, -1., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.x, 1., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.y, 0., atol=1e-12, rtol=1e-12) + + model = Model4DSTEM.build( + params=params, + scan_pos=PixelYX(y=0., x=0.) + ) + ray = model.make_source_ray(source_dx=0., source_dy=0.5).ray + res = model.trace(ray) + assert_allclose(res['detector'].sampling['detector_px'].x, 1., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].sampling['detector_px'].y, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.x, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.y, 1., atol=1e-12, rtol=1e-12) + + +def test_detector_px_rotate_flipy(): + # Check conformance with + # https://libertem.github.io/LiberTEM/concepts.html#coordinate-system: y + # points down, x to the right, z away. + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + scan_center=PixelYX(y=0., x=0.), + scan_rotation=0., + camera_length=1, + detector_pixel_pitch=1, + detector_center=PixelYX(y=0., x=0.), + detector_rotation=np.pi/2, + semiconv=0.023, + flip_factor=-1., + descan_error=DescanError() + ) + model = Model4DSTEM.build( + params=params, + scan_pos=PixelYX(y=0., x=0.) + ) + ray = model.make_source_ray(source_dx=0.5, source_dy=0.).ray + res = model.trace(ray) + assert_allclose(res['detector'].sampling['detector_px'].x, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].sampling['detector_px'].y, 1., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.x, 1., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.y, 0., atol=1e-12, rtol=1e-12) + + model = Model4DSTEM.build( + params=params, + scan_pos=PixelYX(y=0., x=0.) + ) + ray = model.make_source_ray(source_dx=0., source_dy=0.5).ray + res = model.trace(ray) + assert_allclose(res['detector'].sampling['detector_px'].x, 1., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].sampling['detector_px'].y, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.x, 0., atol=1e-12, rtol=1e-12) + assert_allclose(res['detector'].ray.y, 1., atol=1e-12, rtol=1e-12) + + +@pytest.mark.parametrize( + 'scan', (PixelYX(y=0., x=0.), PixelYX(y=-3., x=5.), ) +) +@pytest.mark.parametrize( + 'overfocus', (-2., 0., 0.1) +) +@pytest.mark.parametrize( + 'camera_length', (-4., 0., 1.2) +) +@pytest.mark.parametrize( + 'dydx', ((-4., 13.), (0., 0.)) +) +def test_geometry(scan, overfocus, camera_length, dydx): + dy, dx = dydx + params = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=1, + scan_center=PixelYX(y=0., x=0.), + scan_rotation=0., + camera_length=camera_length, + detector_pixel_pitch=1, + detector_center=PixelYX(y=0., x=0.), + semiconv=0.023, + flip_factor=1., + descan_error=DescanError() + ) + model = Model4DSTEM.build( + params=params, + scan_pos=scan + ) + ray = model.make_source_ray(source_dx=dx, source_dy=dy).ray + res = model.trace(ray) + # No descan error means rays not bent + for key, sect in res.items(): + assert sect.ray.dy == dy + assert sect.ray.dx == dx + if scan.x == 0. or key not in ('scanner', 'specimen'): + assert_allclose(sect.ray.x, dx*sect.ray.z) + if scan.y == 0. or key not in ('scanner', 'specimen'): + assert_allclose(sect.ray.y, dy*sect.ray.z) + assert res['source'].ray.z == 0 + for key in ('overfocus', 'scanner', 'specimen', 'descanner'): + assert_allclose(res[key].ray.z, overfocus) + for key in ('camera_length', 'detector'): + assert_allclose(res[key].ray.z, overfocus+camera_length) + + +def test_descan_offset(): + params_ref = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + scan_center=PixelYX(y=0., x=0.), + scan_rotation=0., + camera_length=1, + detector_pixel_pitch=1, + detector_center=PixelYX(y=0., x=0.), + semiconv=0.023, + flip_factor=1., + descan_error=DescanError() + ) + model_ref = Model4DSTEM.build( + params=params_ref, + scan_pos=PixelYX(y=23., x=-13.) + ) + ray_ref = model_ref.make_source_ray(source_dx=0.5, source_dy=-0.1).ray + res_ref = model_ref.trace(ray_ref) + + offpxi = 0.11 + offpyi = 0.13 + offsxi = 0.17 + offsyi = 0.19 + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + scan_center=PixelYX(y=0., x=0.), + scan_rotation=0., + camera_length=1, + detector_pixel_pitch=1, + detector_center=PixelYX(y=0., x=0.), + semiconv=0.023, + flip_factor=1., + descan_error=DescanError( + offpxi=offpxi, + offpyi=offpyi, + offsxi=offsxi, + offsyi=offsyi + ) + ) + model = Model4DSTEM.build( + params=params, + scan_pos=PixelYX(y=23., x=-13.) + ) + ray = model.make_source_ray(source_dx=0.5, source_dy=-0.1).ray + res = model.trace(ray) + + for key in ('source', 'overfocus', 'scanner', 'specimen'): + sect_ref = res_ref[key] + sect = res[key] + for attr in ('y', 'x', 'dy', 'dx', 'z'): + assert_allclose( + getattr(sect.ray, attr), + getattr(sect_ref.ray, attr), + ) + sect_ref = res_ref['descanner'] + sect = res['descanner'] + assert_allclose( + sect.ray.x, + sect_ref.ray.x + offpxi + ) + assert_allclose( + sect.ray.y, + sect_ref.ray.y + offpyi + ) + assert_allclose( + sect.ray.dx, + sect_ref.ray.dx + offsxi + ) + assert_allclose( + sect.ray.dy, + sect_ref.ray.dy + offsyi + ) + assert_allclose( + sect.ray.z, + sect_ref.ray.z + ) + # Straight propagation + for key in ('camera_length', 'detector'): + start = res['descanner'] + stop = res[key] + assert_allclose( + stop.ray.x, + start.ray.x + start.ray.dx*(stop.ray.z - start.ray.z) + ) + assert_allclose( + stop.ray.y, + start.ray.y + start.ray.dy*(stop.ray.z - start.ray.z) + ) + assert_allclose( + stop.ray.dx, + start.ray.dx + ) + assert_allclose( + stop.ray.dy, + start.ray.dy + ) + + +@pytest.mark.parametrize( + 'scan', (PixelYX(y=0., x=0.), PixelYX(y=-3., x=5.), ) +) +def test_descan_position(scan): + params_ref = Parameters4DSTEM( + overfocus=1., + scan_pixel_pitch=1., + scan_center=PixelYX(y=0., x=0.), + scan_rotation=0., + camera_length=1., + detector_pixel_pitch=1., + detector_center=PixelYX(y=0., x=0.), + semiconv=0.023, + flip_factor=1., + descan_error=DescanError() + ) + model_ref = Model4DSTEM.build( + params=params_ref, + scan_pos=scan + ) + ray_ref = model_ref.make_source_ray(source_dx=0.5, source_dy=-0.1).ray + res_ref = model_ref.trace(ray_ref) + + pxo_pxi = 0.11 + pxo_pyi = 0.13 + pyo_pxi = 0.17 + pyo_pyi = 0.19 + params = Parameters4DSTEM( + overfocus=1., + scan_pixel_pitch=1., + scan_center=PixelYX(y=0., x=0.), + scan_rotation=0., + camera_length=1., + detector_pixel_pitch=1, + detector_center=PixelYX(y=0., x=0.), + semiconv=0.023, + flip_factor=1., + descan_error=DescanError( + pxo_pxi=pxo_pxi, + pxo_pyi=pxo_pyi, + pyo_pxi=pyo_pxi, + pyo_pyi=pyo_pyi + ) + ) + model = Model4DSTEM.build( + params=params, + scan_pos=scan + ) + ray = model.make_source_ray(source_dx=0.5, source_dy=-0.1).ray + res = model.trace(ray) + + # no descan error contribution from p*o_p*i parameters + # if beam is not deflected by scanner + if scan.x == 0 and scan.y == 0: + keys = ( + 'source', 'overfocus', 'scanner', 'specimen', + 'descanner', 'camera_length', 'detector' + ) + else: + keys = ('source', 'overfocus', 'scanner', 'specimen') + for key in keys: + sect_ref = res_ref[key] + sect = res[key] + for attr in ('y', 'x', 'dy', 'dx', 'z'): + assert_allclose( + getattr(sect.ray, attr), + getattr(sect_ref.ray, attr), + ) + sect_ref = res_ref['descanner'] + sect = res['descanner'] + assert_allclose( + sect.ray.x, + sect_ref.ray.x + pxo_pxi * scan.x + pxo_pyi * scan.y + ) + assert_allclose( + sect.ray.y, + sect_ref.ray.y + pyo_pxi * scan.x + pyo_pyi * scan.y + ) + assert_allclose( + sect.ray.dx, + sect_ref.ray.dx + ) + assert_allclose( + sect.ray.dy, + sect_ref.ray.dy + ) + assert_allclose( + sect.ray.z, + sect_ref.ray.z + ) + # Straight propagation + for key in ('camera_length', 'detector'): + start = res['descanner'] + stop = res[key] + assert_allclose( + stop.ray.x, + start.ray.x + start.ray.dx*(stop.ray.z - start.ray.z) + ) + assert_allclose( + stop.ray.y, + start.ray.y + start.ray.dy*(stop.ray.z - start.ray.z) + ) + assert_allclose( + stop.ray.dx, + start.ray.dx + ) + assert_allclose( + stop.ray.dy, + start.ray.dy + ) + + +@pytest.mark.parametrize( + 'scan', (PixelYX(y=0., x=0.), PixelYX(y=-3., x=5.), ) +) +def test_descan_slope(scan): + params_ref = Parameters4DSTEM( + overfocus=1., + scan_pixel_pitch=1., + scan_center=PixelYX(y=0., x=0.), + scan_rotation=0., + camera_length=1., + detector_pixel_pitch=1., + detector_center=PixelYX(y=0., x=0.), + semiconv=0.023, + flip_factor=1., + descan_error=DescanError() + ) + model_ref = Model4DSTEM.build( + params=params_ref, + scan_pos=scan + ) + ray_ref = model_ref.make_source_ray(source_dx=0.5, source_dy=-0.1).ray + res_ref = model_ref.trace(ray_ref) + + sxo_pxi = 0.11 + sxo_pyi = 0.13 + syo_pxi = 0.17 + syo_pyi = 0.19 + params = Parameters4DSTEM( + overfocus=1., + scan_pixel_pitch=1., + scan_center=PixelYX(y=0., x=0.), + scan_rotation=0., + camera_length=1., + detector_pixel_pitch=1, + detector_center=PixelYX(y=0., x=0.), + semiconv=0.023, + flip_factor=1., + descan_error=DescanError( + sxo_pxi=sxo_pxi, + sxo_pyi=sxo_pyi, + syo_pxi=syo_pxi, + syo_pyi=syo_pyi + ) + ) + model = Model4DSTEM.build( + params=params, + scan_pos=scan + ) + ray = model.make_source_ray(source_dx=0.5, source_dy=-0.1).ray + res = model.trace(ray) + + # no descan error contribution from s*o_p*i parameters + # if beam is not deflected by scanner + if scan.x == 0 and scan.y == 0: + keys = ( + 'source', 'overfocus', 'scanner', 'specimen', + 'descanner', 'camera_length', 'detector' + ) + else: + keys = ('source', 'overfocus', 'scanner', 'specimen') + for key in keys: + sect_ref = res_ref[key] + sect = res[key] + for attr in ('y', 'x', 'dy', 'dx', 'z'): + assert_allclose( + getattr(sect.ray, attr), + getattr(sect_ref.ray, attr), + ) + sect_ref = res_ref['descanner'] + sect = res['descanner'] + assert_allclose( + sect.ray.dx, + sect_ref.ray.dx + sxo_pxi * scan.x + sxo_pyi * scan.y + ) + assert_allclose( + sect.ray.dy, + sect_ref.ray.dy + syo_pxi * scan.x + syo_pyi * scan.y + ) + assert_allclose( + sect.ray.x, + sect_ref.ray.x + ) + assert_allclose( + sect.ray.y, + sect_ref.ray.y + ) + assert_allclose( + sect.ray.z, + sect_ref.ray.z + ) + # Straight propagation + for key in ('camera_length', 'detector'): + start = res['descanner'] + stop = res[key] + assert_allclose( + stop.ray.x, + start.ray.x + start.ray.dx*(stop.ray.z - start.ray.z) + ) + assert_allclose( + stop.ray.y, + start.ray.y + start.ray.dy*(stop.ray.z - start.ray.z) + ) + assert_allclose( + stop.ray.dx, + start.ray.dx + ) + assert_allclose( + stop.ray.dy, + start.ray.dy + ) + + +def test_jax_smoke(): + params = Parameters4DSTEM( + overfocus=0.7, + scan_pixel_pitch=0.005, + scan_center=PixelYX(y=17, x=13), + scan_rotation=1.234, + camera_length=2.3, + detector_pixel_pitch=0.0247, + detector_center=PixelYX(y=11, x=19), + semiconv=0.023, + flip_factor=-1., + descan_error=DescanError(offpxi=.345, pxo_pxi=948) + ) + + def test_func(arr): + scan_y, scan_x, tilt_y, tilt_x, _one = arr + scan_pos = PixelYX(x=scan_x, y=scan_y) + model = Model4DSTEM.build(params=params, scan_pos=scan_pos) + ray = model.make_source_ray(source_dy=tilt_y, source_dx=tilt_x, _one=_one).ray + res = model.trace(ray) + return jnp.array(( + res['specimen'].sampling['scan_px'].y, + res['specimen'].sampling['scan_px'].x, + res['detector'].sampling['detector_px'].y, + res['detector'].sampling['detector_px'].x, + res['detector'].ray._one + )) + + sample = jnp.array((0., 0., 0., 0., 1.)) + test_func(sample) + jax.jacobian(test_func)(sample) + + +def measure_descan_deviation(params, target_params): + distances = [] + for scan_y in (0, 1): + for scan_x in (0, 1): + for cl in (0, 1): + ref_params = params.derive( + camera_length=cl + ) + ref_model = Model4DSTEM.build( + params=ref_params, scan_pos=PixelYX(y=scan_y, x=scan_x)) + ref_ray = ref_model.make_source_ray(source_dy=0., source_dx=0.).ray + ref = ref_model.trace(ref_ray) + opt_params = target_params.derive( + camera_length=cl, + ) + opt_model = Model4DSTEM.build( + params=opt_params, scan_pos=PixelYX(y=scan_y, x=scan_x)) + opt_ray = opt_model.make_source_ray(source_dy=0., source_dx=0.).ray + opt = opt_model.trace(opt_ray) + distances.append(( + opt['detector'].sampling['detector_px'].y + - ref['detector'].sampling['detector_px'].y, + opt['detector'].sampling['detector_px'].x + - ref['detector'].sampling['detector_px'].x, + )) + return jnp.linalg.norm(jnp.array(distances)) + + +def test_adjust_scan_rotation(random_params: Parameters4DSTEM): + scan_rotation = np.random.uniform(-np.pi, np.pi) + modified = random_params.adjust_scan_rotation( + scan_rotation=scan_rotation, + ) + print(random_params, scan_rotation, modified) + assert_allclose(0, + measure_descan_deviation( + random_params, + modified, + ), + atol=1e-12, + ) + assert modified.scan_rotation == scan_rotation + + +def test_adjust_scan_pixel_pitch(random_params): + scan_pixel_pitch = np.random.uniform(0.0001, 2) + modified = random_params.adjust_scan_pixel_pitch( + scan_pixel_pitch=scan_pixel_pitch, + ) + print(random_params, scan_pixel_pitch, modified) + assert_allclose(0, + measure_descan_deviation( + random_params, + modified, + ), + atol=1e-12, + ) + assert modified.scan_pixel_pitch == scan_pixel_pitch + + +def test_adjust_scan_center(random_params): + scan_center = PixelYX( + y=np.random.uniform(-10, 10), + x=np.random.uniform(-10, 10), + ) + modified = random_params.adjust_scan_center( + scan_center=scan_center, + ) + print(random_params, scan_center, modified) + assert_allclose(0, + measure_descan_deviation( + random_params, + modified, + ), + atol=1e-12, + ) + assert modified.scan_center == scan_center + + +def test_adjust_detector_rotation(random_params): + detector_rotation = np.random.uniform(-np.pi, np.pi) + modified = random_params.adjust_detector_rotation( + detector_rotation=detector_rotation, + ) + print(random_params, detector_rotation, modified) + assert_allclose(0, + measure_descan_deviation( + random_params, + modified, + ), + atol=1e-12, + ) + assert modified.detector_rotation == detector_rotation + + +def test_adjust_flip_y(random_params): + for flip_factor in (-1., 1.): + modified = random_params.adjust_flip_factor( + flip_factor=flip_factor, + ) + print(random_params, flip_factor, modified) + assert_allclose(0, + measure_descan_deviation( + random_params, + modified, + ), + atol=1e-12, + ) + assert modified.flip_factor == flip_factor + + +def test_adjust_detector_center(random_params): + detector_center = PixelYX( + y=np.random.uniform(-10, 10), + x=np.random.uniform(-10, 10), + ) + modified = random_params.adjust_detector_center( + detector_center=detector_center, + ) + print(random_params, detector_center, modified) + assert_allclose(0, + measure_descan_deviation( + random_params, + modified, + ), + atol=1e-12, + ) + assert modified.detector_center == detector_center + + +def test_adjust_detector_pixel_pitch(random_params): + detector_pixel_pitch = np.random.uniform(0.0001, 2) + modified = random_params.adjust_detector_pixel_pitch( + detector_pixel_pitch=detector_pixel_pitch, + ) + print(random_params, detector_pixel_pitch, modified) + assert_allclose(0, + measure_descan_deviation( + random_params, + modified, + ), + atol=1e-12, + ) + assert modified.detector_pixel_pitch == detector_pixel_pitch + + +def test_adjust_camera_length(random_params): + camera_length = np.random.uniform(0.0001, 2) + modified = random_params.adjust_camera_length(camera_length) + ratio = modified.camera_length / random_params.camera_length + print(random_params, camera_length, modified) + + distances = [] + # We check that the model produces the same pixel offsets + # at the camera length scaled by `ratio` + for scan_y in (0, 1): + for scan_x in (0, 1): + for cl in (0, 1): + ref_params = random_params.derive( + camera_length=cl + ) + ref_model = Model4DSTEM.build( + params=ref_params, scan_pos=PixelYX(y=scan_y, x=scan_x)) + ref_ray = ref_model.make_source_ray(source_dy=0., source_dx=0.).ray + ref = ref_model.trace(ref_ray) + # Scale by `ratio` + opt_params = modified.derive( + camera_length=cl * ratio, + ) + opt_model = Model4DSTEM.build( + params=opt_params, scan_pos=PixelYX(y=scan_y, x=scan_x)) + opt_ray = opt_model.make_source_ray(source_dy=0., source_dx=0.).ray + opt = opt_model.trace(opt_ray) + distances.append(( + opt['detector'].sampling['detector_px'].y + - ref['detector'].sampling['detector_px'].y, + opt['detector'].sampling['detector_px'].x + - ref['detector'].sampling['detector_px'].x, + )) + assert_allclose(0, np.linalg.norm(distances), atol=1e-12) + assert modified.camera_length == camera_length diff --git a/tests/test_optimize.py b/tests/test_optimize.py new file mode 100644 index 0000000..00fd899 --- /dev/null +++ b/tests/test_optimize.py @@ -0,0 +1,660 @@ +from numpy.testing import assert_allclose +import pytest + +import jax; jax.config.update("jax_enable_x64", True) # noqa: E702 +import numpy as np +from skimage.measure import blur_effect +from libertem.api import Context +from libertem.udf.sum import SumUDF +from libertem.udf.com import CoMUDF, RegressionOptions +import optax +import jax.numpy as jnp + +from microscope_calibration.util.stem_overfocus_sim import project +from microscope_calibration.udf.stem_overfocus import OverfocusUDF +from microscope_calibration.common.model import ( + Parameters4DSTEM, PixelYX, DescanError, trace +) +from microscope_calibration.util.optimize import ( + optimize, make_overfocus_loss_function, + solve_camera_length, solve_scan_pixel_pitch, + solve_full_descan_error, normalize_descan_error, + solve_tilt_descan_error, _tilt_descan, + solve_tilt_descan_error_points, +) + + +def test_optimize(): + scan_rotation = np.pi/2 + flip_factor = -1. + detector_rotation = 0. + + scan_pixel_pitch = 0.1 + detector_pixel_pitch = 0.2 + overfocus = 1. + camera_length = 1. + propagation_distance = overfocus + camera_length + obj_half_size = 16 + angle = np.arctan2(obj_half_size*detector_pixel_pitch/2 + 0.00314157, propagation_distance) + + params = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + scan_rotation=scan_rotation, + flip_factor=flip_factor, + # Simulate detector larger than object to avoid clipping at the borders + detector_center=PixelYX(x=obj_half_size * 2, y=obj_half_size * 2), + detector_rotation=detector_rotation, + # Descan error designed to give whole pixel shifts + descan_error=DescanError( + offpxi=detector_pixel_pitch, + offpyi=detector_pixel_pitch * 2, + offsxi=-1 * detector_pixel_pitch/camera_length, + offsyi=-2 * detector_pixel_pitch/camera_length, + pxo_pxi=2 * detector_pixel_pitch/scan_pixel_pitch, + pyo_pyi=3 * detector_pixel_pitch/scan_pixel_pitch, + sxo_pxi=-3 * detector_pixel_pitch/scan_pixel_pitch/camera_length, + syo_pyi=-4 * detector_pixel_pitch/scan_pixel_pitch/camera_length, + ) + ) + obj = np.zeros((obj_half_size * 2, obj_half_size * 2)) + obj[obj_half_size, obj_half_size] = 1 + sim = project( + obj, + scan_shape=(2*obj_half_size, 2*obj_half_size), + detector_shape=(4*obj_half_size, 4*obj_half_size), + sim_params=params + ) + ctx = Context.make_with('inline') + ds = ctx.load('memory', data=sim) + udf = OverfocusUDF(overfocus_params={'params': params}) + make_new_params, loss = make_overfocus_loss_function( + params=params, + ctx=ctx, + dataset=ds, + overfocus_udf=udf, + ) + res = optimize(loss=loss) + res_params = make_new_params(res.x) + assert_allclose(res_params.scan_rotation, params.scan_rotation, atol=0.1) + assert_allclose(res_params.overfocus, params.overfocus, rtol=0.1) + + valdict = {'val': False} + + def callback(args, new_params, udf_results, current_loss): + if valdict['val']: + pass + else: + valdict['val'] = True + assert_allclose(args, [0, 0]) + assert params == new_params + assert_allclose(udf_results[0]['backprojected_sum'].data.astype(bool), obj.astype(bool)) + + make_new_params, loss = make_overfocus_loss_function( + params=params, + ctx=ctx, + dataset=ds, + overfocus_udf=udf, + callback=callback, + blur_function=blur_effect, + extra_udfs=(SumUDF(), ), + plots=(), + ) + res = optimize( + loss=loss, minimizer_kwargs={'method': 'SLSQP'}, + bounds=[(-10, 10), (-10, 10)], + ) + res_params = make_new_params(res.x) + assert_allclose(res_params.scan_rotation, params.scan_rotation, atol=0.1) + assert_allclose(res_params.overfocus, params.overfocus, rtol=0.1) + + +def test_descan_error(): + scan_pixel_pitch = 0.1 + detector_pixel_pitch = 0.2 + overfocus = 1. + camera_length = 1. + propagation_distance = overfocus + camera_length + obj_half_size = 16 + angle = np.arctan2(obj_half_size*detector_pixel_pitch/2 + 0.00314157, propagation_distance) + + params = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=0., y=0.), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=2*obj_half_size, y=2*obj_half_size), + detector_rotation=0., + descan_error=DescanError( + sxo_pyi=1 * detector_pixel_pitch/scan_pixel_pitch, + syo_pxi=1 * detector_pixel_pitch/scan_pixel_pitch, + sxo_pxi=-2 * detector_pixel_pitch/scan_pixel_pitch/camera_length, + syo_pyi=-1 * detector_pixel_pitch/scan_pixel_pitch/camera_length, + ) + ) + test_positions = jnp.array(( + (0, 0), + (100, 0), + (0, 100) + )) + + target_px = [] + for scan_y, scan_x in test_positions: + target_res = trace( + params=params, scan_pos=PixelYX(y=scan_y, x=scan_x), source_dy=0, source_dx=0) + target_px.append(( + target_res['detector'].sampling['detector_px'].x, + target_res['detector'].sampling['detector_px'].y, + )) + + target_px = jnp.array(target_px) + + @jax.jit + def loss(args): + sxo_pyi, syo_pxi, sxo_pxi, syo_pyi = args + opt_params = params.derive(descan_error=DescanError( + sxo_pyi=sxo_pyi, + syo_pxi=syo_pxi, + sxo_pxi=sxo_pxi, + syo_pyi=syo_pyi, + )) + res = [] + for scan_y, scan_x in test_positions: + opt_res = trace( + params=opt_params, scan_pos=PixelYX(y=scan_y, x=scan_x), source_dy=0, source_dx=0) + res.append(( + opt_res['detector'].sampling['detector_px'].x, + opt_res['detector'].sampling['detector_px'].y, + )) + return jnp.linalg.norm(jnp.array(res) - target_px) + + start = jnp.zeros(4) + correct = jnp.array(( + 1 * detector_pixel_pitch/scan_pixel_pitch, + 1 * detector_pixel_pitch/scan_pixel_pitch, + -2 * detector_pixel_pitch/scan_pixel_pitch/camera_length, + -1 * detector_pixel_pitch/scan_pixel_pitch/camera_length, + )) + + assert_allclose(loss(correct), 0.) + assert not np.allclose(loss(start), 0) + + solver = optax.lbfgs() + optargs = start.copy() + opt_state = solver.init(optargs) + value_and_grad = optax.value_and_grad_from_state(loss) + + @jax.jit + def optstep(optargs, opt_state): + + value, grad = value_and_grad(optargs, state=opt_state) + updates, opt_state = solver.update( + grad, opt_state, optargs, value=value, grad=grad, value_fn=loss + ) + optargs = optax.apply_updates(optargs, updates) + return optargs, opt_state + + for i in range(10): + print(f'Objective function: {loss(optargs)}, distance {optargs - correct}') + optargs, opt_state = optstep(optargs, opt_state) + print(f'Objective function: {loss(optargs)}, distance {optargs - correct}') + assert_allclose(optargs, correct) + + +def test_camera_length(): + # Determine camera length from a known diffraction angle in radians, + # corresponding detector pixel offset, and detector pixel pitch + scan_pixel_pitch = 0.1 + detector_pixel_pitch = 0.2 + overfocus = 0.01 + camera_length = 1.234 + propagation_distance = overfocus + camera_length + obj_half_size = 16 + # This is known, e.g. from crystal structure, diffraction order and + # wavelength + angle = np.arctan2(obj_half_size*detector_pixel_pitch/2 + 0.00314157, propagation_distance) + params = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=2*obj_half_size, y=2*obj_half_size), + ) + # This is observed on the detector + px_radius = jnp.tan(angle) * propagation_distance / detector_pixel_pitch + + res, residual = solve_camera_length( + # Start with a negative value on purpose + ref_params=params.derive(camera_length=-2*camera_length), + diffraction_angle=angle, + radius_px=px_radius, + ) + assert_allclose(res.camera_length, propagation_distance) + assert_allclose(residual, 0., atol=1e-12) + + +def test_scan_pixel_pitch(): + scan_pixel_pitch = 0.1 + detector_pixel_pitch = 0.2 + overfocus = 0.01 + camera_length = 1.234 + propagation_distance = overfocus + camera_length + obj_half_size = 16 + angle = np.arctan2(obj_half_size*detector_pixel_pitch/2 + 0.00314157, propagation_distance) + params = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=2*obj_half_size, y=2*obj_half_size), + ) + + point_1 = PixelYX(1., 2.) + point_2 = PixelYX(7., 9.) + distance = np.linalg.norm(np.array(point_2) - np.array(point_1)) * scan_pixel_pitch + + res, residual = solve_scan_pixel_pitch( + ref_params=params.derive(scan_pixel_pitch=.3543), + point_1=point_1, + point_2=point_2, + physical_distance=distance, + ) + assert_allclose(res.scan_pixel_pitch, scan_pixel_pitch) + assert_allclose(residual, 0., atol=1e-12) + + +@pytest.mark.parametrize( + 'scan_rotation, flip_factor, detector_rotation', [ + (-np.pi, 1., np.pi/7), + (0., -1., 0.), + (np.pi/7*3, -1., -np.pi/3) + ] +) +@pytest.mark.parametrize( + 'descans', ( + np.zeros(12), + np.linspace(-1, 1, 12), + # alternating -0.5, and 0.5 + (np.full(12, -1) ** np.array(range(12))) * 0.25, + # Alternating mishmash + (np.full(12, -1) ** np.array(range(12))) * np.linspace(-1, 1, 12) % 0.11, + ) +) +def test_full_descan_error(scan_rotation, flip_factor, detector_rotation, descans): + scan_pixel_pitch = 0.1 + detector_pixel_pitch = scan_pixel_pitch + overfocus = 0. + camera_length = 1. + propagation_distance = overfocus + camera_length + obj_half_size = 8 + # Small epsilon to combat aliasing + angle = np.arctan2(obj_half_size*detector_pixel_pitch/2*2 + 0.001, propagation_distance) + + params = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + scan_rotation=scan_rotation, + flip_factor=flip_factor, + detector_center=PixelYX(x=obj_half_size*8-2, y=obj_half_size*8+1), + detector_rotation=detector_rotation, + descan_error=DescanError( + offpxi=descans[0] * detector_pixel_pitch, + offpyi=descans[1] * detector_pixel_pitch, + offsxi=-descans[2] * detector_pixel_pitch/camera_length, + offsyi=-descans[3] * detector_pixel_pitch/camera_length, + pxo_pxi=descans[4] * detector_pixel_pitch/scan_pixel_pitch, + pyo_pyi=descans[5] * detector_pixel_pitch/scan_pixel_pitch, + pyo_pxi=-descans[6] * detector_pixel_pitch/scan_pixel_pitch, + pxo_pyi=-descans[7] * detector_pixel_pitch/scan_pixel_pitch, + sxo_pxi=descans[8] * detector_pixel_pitch/scan_pixel_pitch/camera_length, + syo_pyi=descans[9] * detector_pixel_pitch/scan_pixel_pitch/camera_length, + syo_pxi=-descans[10] * detector_pixel_pitch/scan_pixel_pitch/camera_length, + sxo_pyi=-descans[11] * detector_pixel_pitch/scan_pixel_pitch/camera_length, + ), + ) + + # we simulate a vacuum reference scan + obj = np.ones((2*obj_half_size, 2*obj_half_size)) + sims = {} + for cl in (1, 2, 3): + sims[cl] = project( + image=obj, + detector_shape=(16*obj_half_size, 16*obj_half_size), + scan_shape=(2*obj_half_size, 2*obj_half_size), + sim_params=params.derive(camera_length=cl), + ) + + # Calculate CoM regressions with LiberTEM + ctx = Context.make_with('inline') + udf = CoMUDF.with_params( + regression=RegressionOptions.SUBTRACT_LINEAR, + cy=params.detector_center.y, + cx=params.detector_center.x, + ) + regs = {} + for (cl, sim) in sims.items(): + ds = ctx.load('memory', data=sim) + res = ctx.run_udf(dataset=ds, udf=udf) + regs[cl] = res['regression'].raw_data + + # The regressions from CoM suffer from imprecision due to aliasing + # To check optimization accuracy and precision we calculate what the exact + # values of there regressions should be + exact_regs = {} + for cl in sims.keys(): + exact_params = params.derive( + camera_length=cl + ) + res_0 = trace(params=exact_params, scan_pos=PixelYX(y=0., x=0.), source_dy=0., source_dx=0.) + res_y = trace(params=exact_params, scan_pos=PixelYX(y=1., x=0.), source_dy=0., source_dx=0.) + res_x = trace(params=exact_params, scan_pos=PixelYX(y=0., x=1.), source_dy=0., source_dx=0.) + dy = res_0['detector'].sampling['detector_px'].y - params.detector_center.y + dx = res_0['detector'].sampling['detector_px'].x - params.detector_center.x + dydy = ( + res_y['detector'].sampling['detector_px'].y + - res_0['detector'].sampling['detector_px'].y + ) + dxdy = ( + res_y['detector'].sampling['detector_px'].x + - res_0['detector'].sampling['detector_px'].x + ) + dydx = ( + res_x['detector'].sampling['detector_px'].y + - res_0['detector'].sampling['detector_px'].y + ) + dxdx = ( + res_x['detector'].sampling['detector_px'].x + - res_0['detector'].sampling['detector_px'].x + ) + + reg = np.array(( + (dy, dx), + (dydy, dxdy), + (dydx, dxdx) + )) + exact_regs[cl] = reg + + # We make sure the exact results approximate the results obtained with CoM. + # 1-5 % of a pixel is about as good as the approximation gets + for cl in sims.keys(): + assert_allclose(regs[cl], exact_regs[cl], rtol=5e-2, atol=5e-2) + + opt_res, residual = solve_full_descan_error( + ref_params=params.derive( + descan_error=DescanError(), + ), + regressions=exact_regs, + ) + + assert_allclose(params.descan_error, opt_res.descan_error, atol=1e-11) + assert_allclose(residual, 0., atol=1e-11) + + +def test_normalize_descan(random_params): + print(random_params) + normalized, residual = normalize_descan_error(random_params) + assert_allclose(residual, 0, atol=1e-11) + + for cl in (0.1, 3): + for sy in (0, 1): + for sx in (-1, 3): + print(cl, sy, sx) + pr = random_params.derive( + camera_length=cl, + ) + pn = normalized.derive( + camera_length=cl, + ) + ref = trace(params=pr, scan_pos=PixelYX(y=sy, x=sx), source_dy=0., source_dx=0.) + norm = trace(params=pn, scan_pos=PixelYX(y=sy, x=sx), source_dy=0., source_dx=0.) + assert_allclose( + ref['detector'].sampling['detector_px'].x, + norm['detector'].sampling['detector_px'].x, + atol=1e-12 + ) + assert_allclose( + ref['detector'].sampling['detector_px'].y, + norm['detector'].sampling['detector_px'].y, + atol=1e-12 + ) + + +@pytest.mark.parametrize( + 'scan_rotation, flip_factor, detector_rotation', [ + (-np.pi, 1., np.pi/7), + (0., -1., 0.), + (np.pi/7*3, -1., -np.pi/3) + ] +) +@pytest.mark.parametrize( + 'descans', ( + np.zeros(12), + np.linspace(-1, 1, 12), + # alternating -0.5, and 0.5 + (np.full(12, -1) ** np.array(range(12))) * 0.25, + # Alternating mishmash + (np.full(12, -1) ** np.array(range(12))) * np.linspace(-1, 1, 12) % 0.11, + ) +) +def test_tilt_descan_error(scan_rotation, flip_factor, detector_rotation, descans): + scan_pixel_pitch = 0.1 + detector_pixel_pitch = scan_pixel_pitch + overfocus = 0. + camera_length = 1. + propagation_distance = overfocus + camera_length + obj_half_size = 8 + # Small epsilon to combat aliasing + angle = np.arctan2(obj_half_size*detector_pixel_pitch/2*2 + 0.001, propagation_distance) + + params = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + scan_rotation=scan_rotation, + flip_factor=flip_factor, + detector_center=PixelYX(x=obj_half_size*8+2, y=obj_half_size*8-1), + detector_rotation=detector_rotation, + descan_error=DescanError( + offpxi=descans[0] * detector_pixel_pitch, + offpyi=descans[1] * detector_pixel_pitch, + offsxi=-descans[2] * detector_pixel_pitch/camera_length, + offsyi=-descans[3] * detector_pixel_pitch/camera_length, + pxo_pxi=descans[4] * detector_pixel_pitch/scan_pixel_pitch, + pyo_pyi=descans[5] * detector_pixel_pitch/scan_pixel_pitch, + pyo_pxi=-descans[6] * detector_pixel_pitch/scan_pixel_pitch, + pxo_pyi=-descans[7] * detector_pixel_pitch/scan_pixel_pitch, + sxo_pxi=descans[8] * detector_pixel_pitch/scan_pixel_pitch/camera_length, + syo_pyi=descans[9] * detector_pixel_pitch/scan_pixel_pitch/camera_length, + syo_pxi=-descans[10] * detector_pixel_pitch/scan_pixel_pitch/camera_length, + sxo_pyi=-descans[11] * detector_pixel_pitch/scan_pixel_pitch/camera_length, + ), + ) + + # we simulate a vacuum reference scan + obj = np.ones((2*obj_half_size, 2*obj_half_size)) + sim = project( + image=obj, + detector_shape=(16*obj_half_size, 16*obj_half_size), + scan_shape=(2*obj_half_size, 2*obj_half_size), + sim_params=params, + ) + + # Calculate CoM regressions with LiberTEM + ctx = Context.make_with('inline') + udf = CoMUDF.with_params( + regression=RegressionOptions.SUBTRACT_LINEAR, + cy=params.detector_center.y, + cx=params.detector_center.x, + ) + ds = ctx.load('memory', data=sim) + res = ctx.run_udf(dataset=ds, udf=udf) + reg = res['regression'].raw_data + + # The regressions from CoM suffer from imprecision due to aliasing + # To check optimization accuracy and precision we calculate what the exact + # values of there regressions should be + res_0 = trace(params=params, scan_pos=PixelYX(y=0., x=0.), source_dy=0., source_dx=0.) + res_y = trace(params=params, scan_pos=PixelYX(y=1., x=0.), source_dy=0., source_dx=0.) + res_x = trace(params=params, scan_pos=PixelYX(y=0., x=1.), source_dy=0., source_dx=0.) + dy = res_0['detector'].sampling['detector_px'].y - params.detector_center.y + dx = res_0['detector'].sampling['detector_px'].x - params.detector_center.x + dydy = ( + res_y['detector'].sampling['detector_px'].y + - res_0['detector'].sampling['detector_px'].y + ) + dxdy = ( + res_y['detector'].sampling['detector_px'].x + - res_0['detector'].sampling['detector_px'].x + ) + dydx = ( + res_x['detector'].sampling['detector_px'].y + - res_0['detector'].sampling['detector_px'].y + ) + dxdx = ( + res_x['detector'].sampling['detector_px'].x + - res_0['detector'].sampling['detector_px'].x + ) + + exact_reg = np.array(( + (dy, dx), + (dydy, dxdy), + (dydx, dxdx) + )) + + # We make sure the exact results approximate the results obtained with CoM. + # 1-5 % of a pixel is about as good as the approximation gets + assert_allclose(reg, exact_reg, rtol=5e-2, atol=5e-2) + + opt_res, residual = solve_tilt_descan_error( + ref_params=params.derive( + descan_error=_tilt_descan(de=params.descan_error, y=np.zeros(6)), + ), + regression=exact_reg, + ) + assert_allclose(residual, 0., atol=1e-11) + for key in ('pxo_pxi', 'pxo_pyi', 'pyo_pxi', 'pyo_pyi', 'offpxi', 'offpyi', + 'sxo_pxi', 'syo_pyi', 'syo_pxi', 'sxo_pyi'): + print(key) + assert_allclose( + getattr(params.descan_error, key), + getattr(opt_res.descan_error, key), + atol=1e-11 + ) + + +@pytest.mark.parametrize( + 'scan_rotation, flip_factor, detector_rotation', [ + (0., 1., 0.), + (np.pi/7*3, -1., -np.pi/3) + ] +) +@pytest.mark.parametrize( + 'descans', ( + np.zeros(12), + # Alternating mishmash + (np.full(12, -1) ** np.array(range(12))) * np.linspace(-1, 1, 12) % 0.11, + ) +) +@pytest.mark.parametrize( + 'scan_pos, works', ( + (tuple(), False), + (((0., 0.),), False), + (((0., 0.), (0., 1.), (1., 0.)), True), + (((1., 2.), (3., 5.), (7., 11.), (13., 17.)), True), + ) +) +def test_tilt_descan_error_points( + scan_rotation, flip_factor, detector_rotation, descans, scan_pos, works): + scan_pixel_pitch = 0.1 + detector_pixel_pitch = scan_pixel_pitch + overfocus = 0. + camera_length = 1. + propagation_distance = overfocus + camera_length + obj_half_size = 8 + # Small epsilon to combat aliasing + angle = np.arctan2(obj_half_size*detector_pixel_pitch/2*2 + 0.001, propagation_distance) + + params = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + scan_rotation=scan_rotation, + flip_factor=flip_factor, + detector_center=PixelYX(x=obj_half_size*8+2, y=obj_half_size*8-1), + detector_rotation=detector_rotation, + descan_error=DescanError( + offpxi=descans[0] * detector_pixel_pitch, + offpyi=descans[1] * detector_pixel_pitch, + offsxi=-descans[2] * detector_pixel_pitch/camera_length, + offsyi=-descans[3] * detector_pixel_pitch/camera_length, + pxo_pxi=descans[4] * detector_pixel_pitch/scan_pixel_pitch, + pyo_pyi=descans[5] * detector_pixel_pitch/scan_pixel_pitch, + pyo_pxi=-descans[6] * detector_pixel_pitch/scan_pixel_pitch, + pxo_pyi=-descans[7] * detector_pixel_pitch/scan_pixel_pitch, + sxo_pxi=descans[8] * detector_pixel_pitch/scan_pixel_pitch/camera_length, + syo_pyi=descans[9] * detector_pixel_pitch/scan_pixel_pitch/camera_length, + syo_pxi=-descans[10] * detector_pixel_pitch/scan_pixel_pitch/camera_length, + sxo_pyi=-descans[11] * detector_pixel_pitch/scan_pixel_pitch/camera_length, + ), + ) + + points = [] + for (scan_y, scan_x) in scan_pos: + res = trace( + params=params, + scan_pos=PixelYX(y=scan_y, x=scan_x), + source_dx=0., source_dy=0., + ) + detector_center = res['detector'].sampling['detector_px'] + points.append((scan_y, scan_x, detector_center.y, detector_center.x)) + opt_res, residual = solve_tilt_descan_error_points( + ref_params=params.derive( + # Blank out the tilt parts of the descan error + descan_error=_tilt_descan(de=params.descan_error, y=np.zeros(6)), + ), + points=points, + ) + default_attrs = ('pxo_pxi', 'pxo_pyi', 'pyo_pxi', 'pyo_pyi', 'offpxi', 'offpyi') + opt_attrs = ('sxo_pxi', 'syo_pyi', 'syo_pxi', 'sxo_pyi') + if works: + attrs = default_attrs + opt_attrs + # For some reason less accurate than in other tests + assert_allclose(residual, 0., atol=1e-8) + else: + attrs = default_attrs + for key in attrs: + print(key) + assert_allclose( + getattr(params.descan_error, key), + getattr(opt_res.descan_error, key), + # For some reason less accurate than in other tests + atol=1e-8 + ) + assert isinstance(getattr(params.descan_error, key), float) + assert isinstance(getattr(opt_res.descan_error, key), float) diff --git a/tests/test_overfocus.py b/tests/test_overfocus.py index f36628d..f20b0c5 100644 --- a/tests/test_overfocus.py +++ b/tests/test_overfocus.py @@ -1,686 +1,718 @@ -import numpy as np import pytest from numpy.testing import assert_allclose -from skimage.measure import blur_effect -from microscope_calibration.util.stem_overfocus_sim import ( - get_transformation_matrix, detector_px_to_specimen_px, project, smiley -) +import jax.numpy as jnp +import numpy as np + from microscope_calibration.common.stem_overfocus import ( - OverfocusParams, make_model, get_translation_matrix + get_backward_transformation_matrix, get_detector_correction_matrix, + project_frame_backwards, correct_frame +) +from microscope_calibration.util.stem_overfocus_sim import project +from microscope_calibration.common.model import ( + Parameters4DSTEM, Model4DSTEM, PixelYX, DescanError, + scale, rotate, trace ) -from microscope_calibration.util.optimize import make_overfocus_loss_function, optimize -from microscope_calibration.udf.stem_overfocus import OverfocusUDF -from libertem.api import Context -from libertem.common import Shape +def test_model_consistency_backproject(): + params = Parameters4DSTEM( + overfocus=0.123, + scan_pixel_pitch=0.234, + camera_length=0.73, + detector_pixel_pitch=0.0321, + semiconv=0.023, + scan_center=PixelYX(x=0.13, y=0.23), + scan_rotation=0.752, + flip_factor=-1., + detector_center=PixelYX(x=23, y=42), + detector_rotation=2.134, + descan_error=DescanError( + pxo_pxi=0.2, + pxo_pyi=0.3, + pyo_pxi=0.5, + pyo_pyi=0.7, + sxo_pxi=0.11, + sxo_pyi=0.13, + syo_pxi=0.17, + syo_pyi=0.19, + offpxi=0.23, + offpyi=0.29, + offsxi=0.31, + offsyi=0.37 + ) + ) + mat = get_backward_transformation_matrix(rec_params=params) -@pytest.mark.parametrize( - 'params', [ - ({'scan_rotation': 0, 'flip_y': False}, ((1, 0), (0, 1))), - ({'scan_rotation': 180, 'flip_y': False}, ((-1, 0), (0, -1))), - ({'scan_rotation': 90, 'flip_y': True}, ((0, 1), (1, 0))), - ({'scan_rotation': 0, 'flip_y': True}, ((-1, 0), (0, 1))), - ( - {'scan_rotation': 45, 'flip_y': False}, - ((1/np.sqrt(2), 1/np.sqrt(2)), (-1/np.sqrt(2), 1/np.sqrt(2))) - ), - ] -) -def test_get_transformation_matrix(params): - inp, ref = params - sim_params = OverfocusParams( - overfocus=1, - scan_pixel_size=1, - camera_length=1, - detector_pixel_size=2, - semiconv=0.004, - cy=8, - cx=8, - scan_rotation=0, - flip_y=False + inp = np.array((2, 3, 5, 7, 1)) + out = inp @ mat + scan_pos = PixelYX( + y=inp[0], + x=inp[1], + ) + source_dy = out[2] + source_dx = out[3] + + assert_allclose(out[4], 1) + res = trace( + params=params, scan_pos=scan_pos, source_dx=source_dx, source_dy=source_dy) + assert_allclose(out[0], res['detector'].sampling['detector_px'].y, rtol=1e-12, atol=1e-12) + assert_allclose(out[1], res['detector'].sampling['detector_px'].x, rtol=1e-12, atol=1e-12) + assert_allclose(inp[2], res['specimen'].sampling['scan_px'].y, rtol=1e-12, atol=1e-12) + assert_allclose(inp[3], res['specimen'].sampling['scan_px'].x, rtol=1e-12, atol=1e-12) + + +def test_model_consistency_correct(): + params = Parameters4DSTEM( + overfocus=0.123, + scan_pixel_pitch=0.234, + camera_length=0.73, + detector_pixel_pitch=0.0321, + semiconv=0.023, + scan_center=PixelYX(x=0.13, y=0.23), + scan_rotation=0.752, + flip_factor=-1., + detector_center=PixelYX(x=23, y=42), + detector_rotation=2.134, + descan_error=DescanError( + pxo_pxi=0.2, + pxo_pyi=0.3, + pyo_pxi=0.5, + pyo_pyi=0.7, + sxo_pxi=0.11, + sxo_pyi=0.13, + syo_pxi=0.17, + syo_pyi=0.19, + offpxi=0.23, + offpyi=0.29, + offsxi=0.31, + offsyi=0.37 + ) + ) + ref_params = Parameters4DSTEM( + overfocus=1.1523, + scan_pixel_pitch=0.4234, + camera_length=0.7453, + detector_pixel_pitch=0.03421, + semiconv=0.042, + scan_center=PixelYX(x=0.4, y=0.345), + scan_rotation=0.75, + flip_factor=1., + detector_center=PixelYX(x=2, y=4), + detector_rotation=2.4134, + descan_error=DescanError( + pxo_pxi=0.234, + pxo_pyi=0.3345, + pyo_pxi=0.534, + pyo_pyi=0.735, + sxo_pxi=0.1134, + sxo_pyi=0.134, + syo_pxi=0.173, + syo_pyi=0.194, + offpxi=0.234, + offpyi=0.293, + offsxi=0.313, + offsyi=0.373 + ) ) - sim_params.update(inp) - res = get_transformation_matrix(sim_params) - assert_allclose(res, ref, atol=1e-8) - for vec in res: - assert_allclose(np.linalg.norm(vec), 1) + mat = get_detector_correction_matrix(rec_params=params, ref_params=ref_params) + inp = np.array((2, 3, 5, 7, 1)) + out = inp @ mat + scan_pos = PixelYX( + y=inp[0], + x=inp[1], + ) + source_dy = out[2] + source_dx = out[3] -@pytest.mark.parametrize( - # params are relative to default parameters in function below - 'params', [ - ( - { - 'overfocus': 1, - 'scan_pixel_size': 1, - 'camera_length': 1, - 'detector_pixel_size': 1, - 'cy': 0, - 'cx': 0, - 'y_px': 0., - 'x_px': 0., - # fov_size_* == 0 means that (0, 0) in scan coordinates is - # (0, 0) in physical coordinates. - 'fov_size_y': 0, - 'fov_size_x': 0, - 'transformation_matrix': np.array(((1., 0.), (0., 1.))), - }, - # Straight through central beam - (0, 0) - ), - ( - { - 'overfocus': 0.1234, - 'scan_pixel_size': 0.987, - 'camera_length': 2.34, - 'detector_pixel_size': 0.71, - 'cy': 13, - 'cx': 14, - 'y_px': 13., - 'x_px': 14., - 'fov_size_y': 5, - 'fov_size_x': 6, - 'transformation_matrix': np.array(((0., 1.), (-1., 0.))), - }, - # Straight through central beam goes through center of fov. The - # straight through beam is not affected by scan rotation, flip_y, - # overfocus, scan pixel size, detector pixel size, or camera length - # fov_size_y/2, fov_size_x/2 - (2.5, 3) - ), - ( - { - 'overfocus': 1, - 'scan_pixel_size': 1, - 'camera_length': 0, - 'detector_pixel_size': 1, - 'cy': 0, - 'cx': 0, - 'y_px': 3., - 'x_px': -7., - 'fov_size_y': 0, - 'fov_size_x': 0, - 'transformation_matrix': np.array(((1., 0.), (0., 1.))), - }, - # Camera length 0, same grid and not transformation means detector - # and scan pixels are the same - (3., -7.) - ), - ( - { - 'overfocus': 1, - 'scan_pixel_size': 1, - 'camera_length': 1, - 'detector_pixel_size': 1, - 'cy': 0, - 'cx': 0, - 'y_px': 3., - 'x_px': -7., - 'fov_size_y': 0, - 'fov_size_x': 0, - 'transformation_matrix': np.array(((1., 0.), (0., 1.))), - }, - # 2x demagnification from detector to specimen - (1.5, -3.5) - ), - ( - { - 'overfocus': -1, - 'scan_pixel_size': 1, - 'camera_length': 2, - 'detector_pixel_size': 1, - 'cy': 0, - 'cx': 0, - 'y_px': 3., - 'x_px': -7., - 'fov_size_y': 0, - 'fov_size_x': 0, - 'transformation_matrix': np.array(((1., 0.), (0., 1.))), - }, - # Negative overfocus means coordinates are inverted compared to positive - # overfocus - # Magnification overfocus/(overfocus + camera_length) is -1 here - (-3, 7) - ), - ( - { - 'overfocus': 1, - 'scan_pixel_size': 1, - 'camera_length': 1, - 'detector_pixel_size': 1, - 'cy': 0, - 'cx': 0, - 'y_px': 3., - 'x_px': -7., - 'fov_size_y': 0, - 'fov_size_x': 0, - 'transformation_matrix': np.array(((-1., 0.), (0., -1.))), - }, - # Transformation inverts both axes, 180 deg rotation - (-1.5, 3.5) - ), - ( - { - 'overfocus': 1, - 'scan_pixel_size': 1, - 'camera_length': 1, - 'detector_pixel_size': 2, - 'cy': 0, - 'cx': 0, - 'y_px': 3., - 'x_px': -7., - 'fov_size_y': 0, - 'fov_size_x': 0, - 'transformation_matrix': np.array(((1., 0.), (0., 1.))), - }, - # 2x demagnification and half the pixel size from detector to scan - (3, -7) - ), - ( - { - 'overfocus': 1, - 'scan_pixel_size': 0.5, - 'camera_length': 2, - 'detector_pixel_size': 1, - 'cy': 0, - 'cx': 0, - 'y_px': 3., - 'x_px': -7., - 'fov_size_y': 0, - 'fov_size_x': 0, - 'transformation_matrix': np.array(((1., 0.), (0., 1.))), - }, - # Factor 2 magnification from pixel size ratio, factor 3 - # demagnification from overfocus / (camera length + overfocus) - (3*2/3, -7*2/3) - ), - ( - { - 'overfocus': 0.1, - 'scan_pixel_size': 0.1, - 'camera_length': 1, - 'detector_pixel_size': 1, - 'cy': 0, - 'cx': 0, - 'y_px': 3., - 'x_px': -7., - 'fov_size_y': 0, - 'fov_size_x': 0, - 'transformation_matrix': np.array(((1., 0.), (0., 1.))), - }, - # Factor 10 magnification from pixel size ratio, factor 0.11 - # demagnification from overfocus / (camera length + overfocus) - (3*10*0.1/1.1, -7*10*0.1/1.1) - ), - ( - { - 'overfocus': 1, - 'scan_pixel_size': 1, - 'camera_length': 1, - 'detector_pixel_size': 1, - 'cy': 1, - 'cx': 5, - 'y_px': 3., - 'x_px': -7., - 'fov_size_y': 0, - 'fov_size_x': 0, - 'transformation_matrix': np.array(((1., 0.), (0., 1.))), - }, - # (y_px - cy) * overfocus / (camera length + overfocus) - ((3 - 1)*1/(1 + 1), (-7 - 5)*1/(1 + 1)) - ), - ( - { - 'overfocus': 1, - 'scan_pixel_size': 1, - 'camera_length': 1, - 'detector_pixel_size': 1, - 'cy': 0, - 'cx': 0, - 'y_px': 3., - 'x_px': -7., - 'fov_size_y': 4, - 'fov_size_x': 6, - 'transformation_matrix': np.array(((1., 0.), (0., 1.))), - }, - # y_px * overfocus / (camera length + overfocus) + fov_size / 2 - (3/2 + 4/2, -7/2 + 6/2) - ), - ( - { - 'overfocus': 1, - 'scan_pixel_size': 0.5, - 'camera_length': 1, - 'detector_pixel_size': 1, - 'cy': 17, - 'cx': 19, - 'y_px': 3., - 'x_px': -7., - 'fov_size_y': 4, - 'fov_size_x': 10, - 'transformation_matrix': np.array(((-1., 0.), (0., -1.))), - }, - # (y_px + cy) * detector_pixel_size / scan_pixel_size * \ - # overfocus / (camera length + overfocus) + fov_size / 2 - ((-3 + 17) * 2/2 + 2, (7 + 19) * 2/2 + 5) - ), - ( - { - 'overfocus': 0.1, - 'scan_pixel_size': 0.1, - 'camera_length': 1, - 'detector_pixel_size': 1, - 'cy': 0, - 'cx': 0, - 'y_px': 3., - 'x_px': -7., - 'fov_size_y': 0, - 'fov_size_x': 0, - 'transformation_matrix': np.array(((-1., 0.), (0., 1.))), - }, - # flip_y: y axis inverted - # -1 * y_px * detector_pixel_size / scan_pixel_size * \ - # overfocus / (camera length + overfocus) - (-1 * 3 * 1/0.1 * 0.1/1.1, 1 * -7 * 1/0.1 * 0.1/1.1) - ), - ( - { - 'overfocus': 0.1, - 'scan_pixel_size': 0.1, - 'camera_length': 1, - 'detector_pixel_size': 1, - 'cy': 6, - 'cx': 5, - 'y_px': 3., - 'x_px': -7., - 'fov_size_y': 4, - 'fov_size_x': 10, - 'transformation_matrix': np.array(((-1., 0.), (0., 1.))), - }, - # flip_y: y axis inverted - # -1 * (y_px - cy) * detector_pixel_size / scan_pixel_size * \ - # overfocus / (camera length + overfocus) + fov_size / 2 - (-1 * (3 - 6) * 1/0.1 * 0.1/1.1 + 4/2, 1 * (-7 - 5) * 1/0.1 * 0.1 / 1.1 + 10/2), - ), - ] -) -def test_detector_specimen_px(params): - inp, ref = params - res = detector_px_to_specimen_px(**inp) - assert_allclose(res, ref, atol=1e-8) + assert_allclose(out[4], 1) + model = Model4DSTEM.build(params=params, scan_pos=scan_pos) + ray = model.make_source_ray(source_dx=source_dx, source_dy=source_dy).ray + res = model.trace(ray) + + ref_model = Model4DSTEM.build(params=ref_params, scan_pos=scan_pos) + ref_ray = ref_model.make_source_ray(source_dx=source_dx, source_dy=source_dy).ray + ref_res = ref_model.trace(ref_ray) + + assert_allclose(inp[2], ref_res['detector'].sampling['detector_px'].y, rtol=1e-12, atol=1e-12) + assert_allclose(inp[3], ref_res['detector'].sampling['detector_px'].x, rtol=1e-12, atol=1e-12) + assert_allclose(out[0], res['detector'].sampling['detector_px'].y, rtol=1e-12, atol=1e-12) + assert_allclose(out[1], res['detector'].sampling['detector_px'].x, rtol=1e-12, atol=1e-12) -def test_project(): - size = 16 - params = OverfocusParams( +def test_backproject_identity(): + # 1:1 size mapping between detector and specimen + params = Parameters4DSTEM( overfocus=1, - scan_pixel_size=0.5, + scan_pixel_pitch=1, camera_length=1, - detector_pixel_size=1, - semiconv=0.004, - cy=size/2, - cx=size/2, - scan_rotation=0, - flip_y=False - ) - obj = smiley(size) - projected = project( - image=obj, - scan_shape=(size, size), - detector_shape=(size, size), - sim_params=params, + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=7.1, y=16.), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=7.1, y=16.), + descan_error=DescanError() ) - assert_allclose(obj, projected[size//2, size//2]) - assert_allclose(obj, projected[:, :, size//2, size//2]) + obj = np.random.random((32, 13)) + res = np.zeros_like(obj) + mat = get_backward_transformation_matrix(rec_params=params) + project_frame_backwards( + frame=obj, + source_semiconv=np.pi/2, + mat=mat, + scan_y=16, + scan_x=7, + image_out=res, + ) + assert_allclose(obj, res) -def test_project_zerocl(): - # Camera length is zero, 1:1 match of scan and detector - size = 16 - params = OverfocusParams( +def test_backproject_counterrotate(): + # 1:1 size mapping between detector and specimen + # Rotating detector and scan rotates the whole reference frame + # so that the result is identity + params = Parameters4DSTEM( overfocus=1, - scan_pixel_size=1, - camera_length=0, - detector_pixel_size=1, - semiconv=0.004, - cy=size/2, - cx=size/2, - scan_rotation=0, - flip_y=False - ) - obj = smiley(size) - projected = project( - image=obj, - scan_shape=(size, size), - detector_shape=(size, size), - sim_params=params, + scan_pixel_pitch=1, + camera_length=1, + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=16, y=16.), + scan_rotation=np.pi/2, + flip_factor=1., + detector_center=PixelYX(x=16, y=16.), + detector_rotation=np.pi/2, + descan_error=DescanError() + ) + obj = np.random.random((32, 32)) + res = np.zeros_like(obj) + mat = get_backward_transformation_matrix(rec_params=params) + project_frame_backwards( + frame=obj, + source_semiconv=np.pi/2, + mat=mat, + scan_y=16, + scan_x=16, + image_out=res, ) - assert_allclose(obj, projected[size//2, size//2]) - assert_allclose(obj, projected[:, :, size//2, size//2]) + assert_allclose(obj, res) -def test_project_scale(): - # With overfocus == 1 and cl == 1, the image is 2x magnified on the - # detector. With same pixel size and twice the number of pixels, every - # second detector pixel maps to a single scan pixel - size = 16 - detector_size = 2 * size - params = OverfocusParams( +@pytest.mark.parametrize( + 'rotate_scan', (False, True) +) +@pytest.mark.parametrize( + 'rotate_detector', (False, True) +) +@pytest.mark.parametrize( + 'fixed_reference', (False, True) +) +@pytest.mark.parametrize( + 'flip_factor', (1., -1.) +) +def test_backproject_rot90_flip(rotate_scan, rotate_detector, fixed_reference, flip_factor): + # 1:1 size mapping between detector and specimen + # rotating scan and detector in fixed reference frame and + # scan reference frame. + # Projecting into 4D STEM dataset and then back-projecting a + # detector frame into the reference coordinate system restores the object, + # i.e. rotation and flip are canceled out. + if rotate_detector: + detector_rotation = np.pi/2 + else: + detector_rotation = 0. + if rotate_scan: + scan_rotation = np.pi/2 + else: + scan_rotation = 0. + + params = Parameters4DSTEM( overfocus=1, - scan_pixel_size=1, + scan_pixel_pitch=1, camera_length=1, - detector_pixel_size=1, - semiconv=0.004, - cy=detector_size/2, - cx=detector_size/2, - scan_rotation=0, - flip_y=False - ) - obj = smiley(size) + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=16, y=16.), + scan_rotation=scan_rotation, + flip_factor=flip_factor, + detector_center=PixelYX(x=16, y=16.), + detector_rotation=detector_rotation, + descan_error=DescanError() + ) + + if fixed_reference: + def map_coord(inp): + cy = obj.shape[0] / 2 + cx = obj.shape[1] / 2 + inp_vec = jnp.array((inp.y, inp.x)) + y, x = scale(1) @ inp_vec + return PixelYX(y=y+cy, x=x+cx) + else: + map_coord = None + + obj = np.random.random((32, 32)) + projected = project( image=obj, - scan_shape=(size, size), - detector_shape=(detector_size, detector_size), + scan_shape=((32, 32)), + detector_shape=((32, 32)), sim_params=params, + specimen_to_image=map_coord, ) - # Center of the scan, every second detector pixel - assert_allclose(obj, projected[size//2, size//2, ::2, ::2]) - # Scan area, trace of center of detector - assert_allclose(obj, projected[:, :, detector_size//2, detector_size//2]) + mat = get_backward_transformation_matrix( + rec_params=params, + specimen_to_image=map_coord, + ) + # We back-project several scan positions and confirm that + # we are getting back the object in the chosen reference coordinate system, + # minus clipping at the borders + for pick_y in (15, 16, 17): + for pick_x in (15, 16, 17): + res = np.zeros_like(obj) + project_frame_backwards( + frame=projected[pick_y, pick_x], + source_semiconv=np.pi/2, + mat=mat, + scan_y=pick_y, + scan_x=pick_x, + image_out=res, + ) + assert_allclose(obj[2:-2, 2:-2], res[2:-2, 2:-2]) -def test_project_2(): - size = 16 - params = OverfocusParams( + +def test_backproject_scale_fixed(): + # scan coordinates are 2x detector coordinates relative to object, + # but we project from and back-project into fixed 1:1 reference coordinates + params = Parameters4DSTEM( overfocus=1, - scan_pixel_size=0.5, + scan_pixel_pitch=2, camera_length=1, - detector_pixel_size=1, - semiconv=0.004, - cy=size/2 + 3, - cx=size/2 - 7, - scan_rotation=0, - flip_y=False - ) - obj = smiley(size) + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=16., y=16.), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=32, y=32.), + detector_rotation=0., + descan_error=DescanError() + ) + obj = np.random.random((64, 64)) + res = np.zeros((64, 64)) + + def map_coord(inp): + cy = obj.shape[0] / 2 + cx = obj.shape[1] / 2 + inp_vec = jnp.array((inp.y, inp.x)) + y, x = scale(1) @ inp_vec + return PixelYX(y=y+cy, x=x+cx) + projected = project( image=obj, - scan_shape=(size, size), - detector_shape=(size, size), + scan_shape=((32, 32)), + detector_shape=((64, 64)), sim_params=params, + specimen_to_image=map_coord, ) - assert_allclose(obj, projected[size//2 + 3, size//2 - 7]) - assert_allclose(obj, projected[:, :, size//2 + 3, size//2 - 7]) + mat = get_backward_transformation_matrix( + rec_params=params, + specimen_to_image=map_coord + ) + project_frame_backwards( + frame=projected[16, 16], + source_semiconv=np.pi/2, + mat=mat, + scan_y=16, + scan_x=16, + image_out=res, + ) + + assert_allclose(obj, res) -def test_project_3(): - size = 16 - params = OverfocusParams( + +def test_backproject_scale_scanref(): + # scan coordinates are 2x detector coordinates, + # and we project from and back-project into that coordinate system + params = Parameters4DSTEM( overfocus=1, - scan_pixel_size=0.5, + scan_pixel_pitch=2, camera_length=1, - detector_pixel_size=0.5, - semiconv=0.004, - cy=size/2, - cx=size/2, - scan_rotation=0, - flip_y=False - ) - obj = smiley(size) + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=16., y=16.), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=32, y=32.), + detector_rotation=0., + descan_error=DescanError() + ) + obj = np.random.random((64, 64)) + res = np.zeros((32, 32)) + projected = project( image=obj, - scan_shape=(size, size), - detector_shape=(size, size), + scan_shape=((32, 32)), + detector_shape=((64, 64)), sim_params=params, + specimen_to_image=None, + ) + + mat = get_backward_transformation_matrix( + rec_params=params, + specimen_to_image=None ) - assert_allclose( - obj[size//4:size//4*3, size//4:size//4*3], - projected[size//2, size//2, ::2, ::2] + project_frame_backwards( + frame=projected[16, 16], + source_semiconv=np.pi/2, + mat=mat, + scan_y=16, + scan_x=16, + image_out=res, ) - assert_allclose(obj, projected[:, :, size//2, size//2]) + # The back-projection result corresponds to the trace + # of the central pixel, i.e. scan coordinates + assert_allclose(projected[:, :, 32, 32], res) -def test_project_rotate(): - size = 16 - params = OverfocusParams( - overfocus=1, - scan_pixel_size=0.5, - camera_length=1, - detector_pixel_size=1, - semiconv=0.004, - cy=size/2, - cx=size/2, - scan_rotation=180, - flip_y=False - ) - obj = smiley(size) +@pytest.mark.parametrize( + 'scan_rotation', (0., np.pi/2) +) +@pytest.mark.parametrize( + 'detector_rotation', (0., np.pi/2) +) +@pytest.mark.parametrize( + 'flip_factor', (1., -1.) +) +@pytest.mark.parametrize( + 'manual_reference', (False, True) +) +def test_correct(scan_rotation, detector_rotation, flip_factor, manual_reference): + scan_pixel_pitch = 0.1 + detector_pixel_pitch = 0.2 + overfocus = 1. + camera_length = 1. + propagation_distance = overfocus + camera_length + obj_half_size = 16 + angle = np.arctan2(obj_half_size*detector_pixel_pitch/2 + 0.00314157, propagation_distance) + + params = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + scan_rotation=scan_rotation, + flip_factor=flip_factor, + # Simulate detector larger than object to avoid clipping at the borders + detector_center=PixelYX(x=obj_half_size * 2, y=obj_half_size * 2), + detector_rotation=detector_rotation, + # Descan error designed to give whole pixel shifts + descan_error=DescanError( + offpxi=detector_pixel_pitch, + offpyi=detector_pixel_pitch * 2, + offsxi=-1 * detector_pixel_pitch/camera_length, + offsyi=-2 * detector_pixel_pitch/camera_length, + pxo_pxi=2 * detector_pixel_pitch/scan_pixel_pitch, + pyo_pyi=3 * detector_pixel_pitch/scan_pixel_pitch, + sxo_pxi=-3 * detector_pixel_pitch/scan_pixel_pitch/camera_length, + syo_pyi=-4 * detector_pixel_pitch/scan_pixel_pitch/camera_length, + ) + ) + # Manual reference parametes to check that code path + # Should be identical to the default calculated by get_detector_correction_matrix() + # Note that this rotates the detector to follow the scan in order to cancel out + # the scan rotation. + params_ref_manual = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=obj_half_size * 2, y=obj_half_size * 2), + detector_rotation=scan_rotation, + descan_error=DescanError() + ) + # Parameters for simulated result without aberrations + params_ref_sim = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=obj_half_size * 2, y=obj_half_size * 2), + detector_rotation=0., + descan_error=DescanError() + ) + # Obtain correction matrix for 4D STEM dataset, i.e. transform the data as + # if the rotations were 0, no flip, and the descan error was 0. + mat = get_detector_correction_matrix( + rec_params=params, + ref_params=params_ref_manual if manual_reference else None, + ) + obj = np.random.random((obj_half_size * 2, obj_half_size * 2)) projected = project( image=obj, - scan_shape=(size, size), - detector_shape=(size, size), + detector_shape=(obj_half_size * 4, obj_half_size * 4), + scan_shape=(obj_half_size * 2, obj_half_size * 2), sim_params=params, ) - # Rotated around "pixel corner", so shifted by 1 - assert_allclose(obj, projected[size//2 - 1, size//2 - 1, ::-1, ::-1]) - assert_allclose(obj, projected[:, :, size//2, size//2]) - - -def test_project_odd(): - det_y = 29 - det_x = 31 - scan_y = 17 - scan_x = 13 - obj_y = 19 - obj_x = 23 - size = 32 - params = OverfocusParams( - overfocus=0.01, - scan_pixel_size=0.01, - camera_length=1., - detector_pixel_size=1, - semiconv=0.004, - cy=det_y/2, - cx=det_x/2, + # Calculate corrected 4D STEM dataset, i.e. as if the rotations were 0, + # no flip, and the descan error was 0. + out = np.zeros_like(projected) + for scan_y in range(out.shape[0]): + for scan_x in range(out.shape[1]): + correct_frame( + frame=projected[scan_y, scan_x], + mat=mat, + scan_y=scan_y, + scan_x=scan_x, + detector_out=out[scan_y, scan_x], + ) + projected_ref = project( + image=obj, + detector_shape=(obj_half_size * 4, obj_half_size * 4), + scan_shape=(obj_half_size * 2, obj_half_size * 2), + sim_params=params_ref_sim, + ) + # 100 % match between corrected frames and simulated reference without aberrations + assert_allclose(projected_ref, out) + # no descan error left: Trace of central pixel is the object + assert_allclose(obj, out[:, :, obj_half_size * 2, obj_half_size * 2]) + # Counter-test: Trace of central pixel of simulate ddataset with descan + # error doesn't match the object + assert not np.allclose(obj, projected[:, :, obj_half_size * 2, obj_half_size * 2]) + + +@pytest.mark.parametrize( + 'scan_rotation', (0., np.pi/2) +) +@pytest.mark.parametrize( + 'detector_rotation', (0., np.pi/2) +) +def test_correct_flip(scan_rotation, detector_rotation): + scan_pixel_pitch = 0.1 + detector_pixel_pitch = 0.2 + overfocus = 1. + camera_length = 1. + propagation_distance = overfocus + camera_length + obj_half_size = 16 + angle = np.arctan2(obj_half_size*detector_pixel_pitch/2 + 0.00314157, propagation_distance) + + params = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + scan_rotation=scan_rotation, + flip_factor=1., + # Simulate detector larger than object to avoid clipping at the borders + detector_center=PixelYX(x=obj_half_size * 2, y=obj_half_size * 2), + detector_rotation=detector_rotation, + # Descan error designed to give whole pixel shifts + descan_error=DescanError( + offpxi=detector_pixel_pitch, + offpyi=detector_pixel_pitch * 2, + offsxi=-1 * detector_pixel_pitch/camera_length, + offsyi=-2 * detector_pixel_pitch/camera_length, + pxo_pxi=2 * detector_pixel_pitch/scan_pixel_pitch, + pyo_pyi=3 * detector_pixel_pitch/scan_pixel_pitch, + sxo_pxi=-3 * detector_pixel_pitch/scan_pixel_pitch/camera_length, + syo_pyi=-4 * detector_pixel_pitch/scan_pixel_pitch/camera_length, + ) + ) + # Manual reference parametes that introduce flip_y + # and compensate the rotations + params_ref_manual = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + scan_rotation=0., + flip_factor=-1., + detector_center=PixelYX(x=obj_half_size * 2, y=obj_half_size * 2), + detector_rotation=scan_rotation, + descan_error=DescanError() + ) + # Parameters for simulated result with flip_y + params_ref_sim = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), scan_rotation=0., - flip_y=False + flip_factor=-1., + detector_center=PixelYX(x=obj_half_size * 2, y=obj_half_size * 2), + detector_rotation=0., + descan_error=DescanError() ) - obj = smiley(size)[:obj_y, :obj_x] + # Obtain correction matrix for 4D STEM dataset that transforms the data as + # if the rotations were 0, flip_y, and the descan error was 0. + mat = get_detector_correction_matrix( + rec_params=params, + ref_params=params_ref_manual, + ) + obj = np.random.random((obj_half_size * 2, obj_half_size * 2)) projected = project( image=obj, - scan_shape=(scan_y, scan_x), - detector_shape=(det_y, det_x), + detector_shape=(obj_half_size * 4, obj_half_size * 4), + scan_shape=(obj_half_size * 2, obj_half_size * 2), sim_params=params, ) - dy = (obj_y-scan_y)//2 - dx = (obj_x - scan_x)//2 - assert_allclose(obj[dy:scan_y+dy, dx:scan_x+dx], projected[:, :, det_y//2, det_x//2]) - dy = (det_y - obj_y) // 2 - dx = (det_x - obj_x) // 2 - assert_allclose(obj, projected[scan_y//2, scan_x//2, dy:obj_y+dy, dx:obj_x+dx]) - - -def get_ref_translation_matrix(params: OverfocusParams, nav_shape): - a = [] - b = [] - - for det_y in (0, 1): - for det_x in (0, 1): - spec_y, spec_x = detector_px_to_specimen_px( - y_px=float(det_y), - x_px=float(det_x), - fov_size_y=float(nav_shape[0]), - fov_size_x=float(nav_shape[1]), - transformation_matrix=get_transformation_matrix(params), - cy=params['cy'], - cx=params['cx'], - detector_pixel_size=float(params['detector_pixel_size']), - scan_pixel_size=float(params['scan_pixel_size']), - camera_length=float(params['camera_length']), - overfocus=float(params['overfocus']), + # Calculate corrected 4D STEM dataset with the rotations were 0, + # flip, and no descan error. + out = np.zeros_like(projected) + for scan_y in range(out.shape[0]): + for scan_x in range(out.shape[1]): + correct_frame( + frame=projected[scan_y, scan_x], + mat=mat, + scan_y=scan_y, + scan_x=scan_x, + detector_out=out[scan_y, scan_x], ) - # Code lifted from util.stem_overfocus_sim._project - for scan_y in (0, 1): - for scan_x in (0, 1): - offset_y = scan_y - nav_shape[0] / 2 - offset_x = scan_x - nav_shape[1] / 2 - image_px_y = spec_y + offset_y - image_px_x = spec_x + offset_x - a.append(( - image_px_y, - image_px_x, - scan_y, - scan_x, - 1 - )) - b.append((det_y, det_x)) - res = np.linalg.lstsq(a, b, rcond=None) - return res[0] - - -class RefOverfocusUDF(OverfocusUDF): - def get_task_data(self): - overfocus_params = self.params.overfocus_params - translation_matrix = get_ref_translation_matrix( - params=overfocus_params, - nav_shape=self._get_fov() - ) - select_roi = np.zeros(self.meta.dataset_shape.nav, dtype=bool) - nav_y, nav_x = self.meta.dataset_shape.nav - select_roi[nav_y//2, nav_x//2] = True - return { - 'translation_matrix': translation_matrix, - 'select_roi': select_roi - } + projected_ref = project( + image=obj, + detector_shape=(obj_half_size * 4, obj_half_size * 4), + scan_shape=(obj_half_size * 2, obj_half_size * 2), + sim_params=params_ref_sim, + ) + # 100 % match between corrected frames and simulated reference without aberrations + assert_allclose(projected_ref, out) @pytest.mark.parametrize( - # make sure the test is sensitive enough - 'fail', [False, True] + 'scan_rotation', (0., np.pi/2) ) -def test_translation_ref(fail): - fail_factor = 1.001 if fail else 1 - - nav_shape = (8, 8) - sig_shape = (8, 8) - - params = OverfocusParams( - overfocus=0.0001, - scan_pixel_size=0.00000001, - camera_length=1, - detector_pixel_size=0.0001, - semiconv=0.01, - cy=3, - cx=3, - scan_rotation=33.3, - flip_y=True, - ) - fail_params = params.copy() - fail_params['overfocus'] /= fail_factor - fail_params['scan_pixel_size'] *= fail_factor - fail_params['camera_length'] *= fail_factor - fail_params['detector_pixel_size'] /= fail_factor - fail_params['cy'] *= fail_factor - fail_params['cx'] /= fail_factor - fail_params['scan_rotation'] *= fail_factor - - ref_translation_matrix = get_ref_translation_matrix( - params=fail_params, - nav_shape=nav_shape, - ) - - model = make_model(params, Shape(nav_shape + sig_shape, sig_dims=2)) - translation_matrix = get_translation_matrix(model) - if fail: - with pytest.raises(AssertionError): - assert translation_matrix == pytest.approx(ref_translation_matrix, rel=0.001) - else: - assert translation_matrix == pytest.approx(ref_translation_matrix, rel=0.001) - - -def test_udf_ref(): - params = OverfocusParams( - overfocus=0.0001, - scan_pixel_size=0.00000001, - camera_length=1, - detector_pixel_size=0.0001, - semiconv=0.001, - cy=3., - cx=3., - scan_rotation=0, - flip_y=False +@pytest.mark.parametrize( + 'detector_rotation', (0., np.pi/2) +) +def test_correct_fixed_manualref(scan_rotation, detector_rotation): + scan_pixel_pitch = 0.1 + detector_pixel_pitch = 0.2 + overfocus = 1. + camera_length = 1. + propagation_distance = overfocus + camera_length + obj_half_size = 16 + angle = np.arctan2(obj_half_size*detector_pixel_pitch/2 + 0.00314157, propagation_distance) + + # Fixed mapping from physical to image for forward simulations + def map_coord(inp): + cy = obj.shape[0] / 2 + cx = obj.shape[1] / 2 + inp_vec = jnp.array((inp.y, inp.x)) + y, x = rotate(-np.pi/2) @ scale(1/scan_pixel_pitch) @ inp_vec + return PixelYX(y=y+cy + 2, x=x+cx - 3) + + params = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + scan_rotation=scan_rotation, + flip_factor=1., + # Simulate detector larger than object to avoid clipping at the borders + detector_center=PixelYX(x=obj_half_size * 2, y=obj_half_size * 2), + detector_rotation=detector_rotation, + # Descan error designed to give whole pixel shifts + descan_error=DescanError( + offpxi=detector_pixel_pitch, + offpyi=detector_pixel_pitch * 2, + offsxi=-1 * detector_pixel_pitch/camera_length, + offsyi=-2 * detector_pixel_pitch/camera_length, + pxo_pxi=2 * detector_pixel_pitch/scan_pixel_pitch, + pyo_pyi=3 * detector_pixel_pitch/scan_pixel_pitch, + sxo_pxi=-3 * detector_pixel_pitch/scan_pixel_pitch/camera_length, + syo_pyi=-4 * detector_pixel_pitch/scan_pixel_pitch/camera_length, + ) ) - obj = np.zeros((8, 8)) - obj[3, 3] = 1 - sim = project(obj, scan_shape=(8, 8), detector_shape=(8, 8), sim_params=params) - assert sim[3, 3, 3, 3] == 1 - - ctx = Context.make_with('inline') - ds = ctx.load('memory', data=sim) - - ref_udf = RefOverfocusUDF(params) - res_udf = OverfocusUDF(params) - - res = ctx.run_udf(dataset=ds, udf=(ref_udf, res_udf)) - assert_allclose(res[0]['shifted_sum'].data.astype(bool), obj.astype(bool)) - assert_allclose(res[1]['shifted_sum'].data.astype(bool), obj.astype(bool)) - - -def test_optimize(): - params = OverfocusParams( - overfocus=0.0001, - scan_pixel_size=0.00000001, - camera_length=1, - detector_pixel_size=0.0001, - semiconv=np.pi, - cy=3., - cx=3., - scan_rotation=0, - flip_y=False - ) - obj = np.zeros((8, 8)) - obj[3, 3] = 1 - sim = project(obj, scan_shape=(8, 8), detector_shape=(8, 8), sim_params=params) - ctx = Context.make_with('inline') - ds = ctx.load('memory', data=sim) - ref_udf = RefOverfocusUDF(params) - make_new_params, loss = make_overfocus_loss_function( - params=params, - ctx=ctx, - dataset=ds, - overfocus_udf=ref_udf, - ) - res = optimize(loss=loss) - res_params = make_new_params(res.x) - assert_allclose(res_params['scan_rotation'], params['scan_rotation'], atol=0.1) - assert_allclose(res_params['overfocus'], params['overfocus'], rtol=0.1) - - valdict = {'val': False} - - def callback(args, new_params, udf_results, current_loss): - if valdict['val']: - pass - else: - valdict['val'] = True - assert_allclose(args, [0, 0]) - assert params == new_params - assert_allclose(udf_results[0]['shifted_sum'].data.astype(bool), obj.astype(bool)) - - make_new_params, loss = make_overfocus_loss_function( - params=params, - ctx=ctx, - dataset=ds, - overfocus_udf=ref_udf, - callback=callback, - blur_function=blur_effect, - extra_udfs=(OverfocusUDF(params), ), - plots=(), - ) - res = optimize( - loss=loss, minimizer_kwargs={'method': 'SLSQP'}, - bounds=[(-10, 10), (-10, 10)], - ) - res_params = make_new_params(res.x) - assert_allclose(res_params['scan_rotation'], params['scan_rotation'], atol=0.1) - assert_allclose(res_params['overfocus'], params['overfocus'], rtol=0.1) + # Manual reference parametes that introduce flip_y + # and compensate the rotations + params_ref_manual = Parameters4DSTEM( + overfocus=overfocus, + # No impact on correction + scan_pixel_pitch=scan_pixel_pitch * 42, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch * 2, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + # Has no impact since we don't remap the scan dimension, + # only the projection after the specimen + scan_rotation=np.pi/23, + flip_factor=-1., + detector_center=PixelYX(x=obj_half_size * 2 - 1, y=obj_half_size * 2 + 2), + detector_rotation=0., + descan_error=DescanError() + ) + # Parameters for simulated result with flip_y + params_ref_sim = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch * 2, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + # Has to match the input scan rotation since we don't + # remap the scan dimension + scan_rotation=scan_rotation, + flip_factor=-1., + detector_center=PixelYX(x=obj_half_size * 2 - 1, y=obj_half_size * 2 + 2), + detector_rotation=0., + descan_error=DescanError() + ) + # Obtain correction matrix for 4D STEM dataset that transforms the data as + # if the rotations were 0, flip_y, and the descan error was 0. + mat = get_detector_correction_matrix( + rec_params=params, + ref_params=params_ref_manual, + ) + obj = np.random.random((obj_half_size * 2, obj_half_size * 2)) + projected = project( + image=obj, + detector_shape=(obj_half_size * 4, obj_half_size * 4), + scan_shape=(obj_half_size * 2, obj_half_size * 2), + sim_params=params, + # Detector image correction doesn't interfere with + # how scan positions are mapped + specimen_to_image=map_coord, + ) + # Calculate corrected 4D STEM dataset with the rotations were 0, + # flip, and no descan error. + out = np.zeros_like(projected) + for scan_y in range(out.shape[0]): + for scan_x in range(out.shape[1]): + correct_frame( + frame=projected[scan_y, scan_x], + mat=mat, + scan_y=scan_y, + scan_x=scan_x, + detector_out=out[scan_y, scan_x], + ) + projected_ref = project( + image=obj, + detector_shape=(obj_half_size * 4, obj_half_size * 4), + scan_shape=(obj_half_size * 2, obj_half_size * 2), + sim_params=params_ref_sim, + # Detector image correction doesn't interfere with + # how scan positions are mapped, so we have to use the same mapping here + specimen_to_image=map_coord, + ) + # 100 % match between corrected frames and simulated reference without aberrations + assert_allclose(projected_ref, out) diff --git a/tests/test_overfocus_udf.py b/tests/test_overfocus_udf.py new file mode 100644 index 0000000..3fe730d --- /dev/null +++ b/tests/test_overfocus_udf.py @@ -0,0 +1,113 @@ +from numpy.testing import assert_allclose + +import numpy as np +import jax +from libertem.api import Context + +from microscope_calibration.common.stem_overfocus import ( + get_backward_transformation_matrix, get_detector_correction_matrix, + project_frame_backwards, correct_frame +) +from microscope_calibration.udf.stem_overfocus import OverfocusUDF +from microscope_calibration.common.model import ( + Parameters4DSTEM, PixelYX, DescanError, trace +) + + +@jax.jit +def get_beam_center(params: Parameters4DSTEM, scan_y, scan_x): + res = trace( + params=params, + scan_pos=PixelYX(y=scan_y, x=scan_x), + source_dx=0., + source_dy=0. + ) + center = res['detector'].sampling['detector_px'] + return (center.y, center.x) + + +def test_udf(): + params = Parameters4DSTEM( + overfocus=0.123, + scan_pixel_pitch=0.234, + camera_length=0.73, + detector_pixel_pitch=0.0321, + semiconv=0.023, + scan_center=PixelYX(x=0.13, y=0.23), + scan_rotation=0.752, + flip_factor=-1., + detector_center=PixelYX(x=5, y=7), + detector_rotation=2.134, + descan_error=DescanError( + pxo_pxi=0.2, + pxo_pyi=0.3, + pyo_pxi=0.5, + pyo_pyi=0.7, + sxo_pxi=0.11, + sxo_pyi=0.13, + syo_pxi=0.17, + syo_pyi=0.19, + offpxi=0.23, + offpyi=0.29, + offsxi=0.31, + offsyi=0.37 + ) + ) + back_mat = get_backward_transformation_matrix(rec_params=params) + corr_mat = get_detector_correction_matrix(rec_params=params) + + data = np.random.random((9, 11, 13, 17)) + + ctx = Context.make_with('inline') + ds = ctx.load('memory', data=data) + + ref_back = np.zeros_like(data[:, :, 0, 0]) + ref_corr = np.zeros_like(data[0, 0]) + ref_point = np.zeros_like(data[:, :, 0, 0]) + + for scan_y in range(ds.shape.nav[0]): + for scan_x in range(ds.shape.nav[1]): + (y, x) = get_beam_center(params=params, scan_y=scan_y, scan_x=scan_x) + y = int(np.round(y)) + x = int(np.round(x)) + if y >= 0 and y < data.shape[2] and x >= 0 and x < data.shape[3]: + ref_point[scan_y, scan_x] = data[ + scan_y, scan_x, y, x + ] + ref_select = np.zeros_like(ref_back) + + select_y = data.shape[0]//2 + select_x = data.shape[1]//2 + + for scan_y in range(data.shape[0]): + for scan_x in range(data.shape[1]): + project_frame_backwards( + frame=data[scan_y, scan_x], + source_semiconv=params.semiconv, + mat=back_mat, + scan_y=scan_y, + scan_x=scan_x, + image_out=ref_back, + ) + if select_y == scan_y and select_x == scan_x: + project_frame_backwards( + frame=data[scan_y, scan_x], + source_semiconv=params.semiconv, + mat=back_mat, + scan_y=scan_y, + scan_x=scan_x, + image_out=ref_select, + ) + correct_frame( + frame=data[scan_y, scan_x], + mat=corr_mat, + scan_y=scan_y, + scan_x=scan_x, + detector_out=ref_corr, + ) + + res = ctx.run_udf(dataset=ds, udf=OverfocusUDF(overfocus_params={'params': params})) + + assert_allclose(ref_back, res['backprojected_sum']) + assert_allclose(ref_corr, res['corrected_sum']) + assert_allclose(ref_point, res['corrected_point']) diff --git a/tests/test_sim.py b/tests/test_sim.py new file mode 100644 index 0000000..d598527 --- /dev/null +++ b/tests/test_sim.py @@ -0,0 +1,720 @@ +import pytest +from numpy.testing import assert_allclose + +import jax; jax.config.update("jax_enable_x64", True) # noqa +import numpy as np +import jax.numpy as jnp + +from microscope_calibration.util.stem_overfocus_sim import ( + get_forward_transformation_matrix, project_frame_forward, + project +) +from microscope_calibration.common.model import ( + Parameters4DSTEM, Model4DSTEM, PixelYX, DescanError, Result4DSTEM, ResultSection, + identity, scale, rotate, flip_y +) + + +def test_project_frame_forward(): + for repeat in range(10): + scan_y = np.random.random() + scan_x = np.random.random() + semiconv = np.random.random() + + def ref_project(obj, source_semiconv, mat, scan_y, scan_x, out): + for det_y in range(out.shape[0]): + for det_x in range(out.shape[1]): + inp = np.array((scan_y, scan_x, det_y, det_x, 1.)) + spec_y, spec_x, tilt_y, tilt_x, _one = inp @ mat + if np.linalg.norm((tilt_y, tilt_x)) < np.tan(source_semiconv): + spec_y = int(np.round(spec_y)) + spec_x = int(np.round(spec_x)) + if ( + spec_y >= 0 and spec_y < obj.shape[0] + and spec_x >= 0 and spec_x < obj.shape[1]): + out[det_y, det_x] = obj[spec_y, spec_x] + else: + out[det_y, det_x] = 0. + + mat = np.random.random((5, 5)) + obj = np.random.random((13, 17)) + out = np.empty((19, 23)) + out_ref = out.copy() + + project_frame_forward( + obj=obj, + source_semiconv=semiconv, + mat=mat, + scan_y=scan_y, + scan_x=scan_x, + out=out + ) + ref_project( + obj=obj, + source_semiconv=semiconv, + mat=mat, + scan_y=scan_y, + scan_x=scan_x, + out=out_ref + ) + assert_allclose(out, out_ref) + + +def test_model_consistency(): + params = Parameters4DSTEM( + overfocus=0.123, + scan_pixel_pitch=0.234, + camera_length=0.73, + detector_pixel_pitch=0.0321, + semiconv=0.023, + scan_center=PixelYX(x=0.13, y=0.23), + scan_rotation=0.752, + flip_factor=-1., + detector_center=PixelYX(x=23, y=42), + descan_error=DescanError( + pxo_pxi=0.2, + pxo_pyi=0.3, + pyo_pxi=0.5, + pyo_pyi=0.7, + sxo_pxi=0.11, + sxo_pyi=0.13, + syo_pxi=0.17, + syo_pyi=0.19, + offpxi=0.23, + offpyi=0.29, + offsxi=0.31, + offsyi=0.37 + ) + ) + mat = get_forward_transformation_matrix(sim_params=params) + + inp = np.array((2, 3, 5, 7, 1)) + out = inp @ mat + scan_pos = PixelYX( + y=inp[0], + x=inp[1], + ) + source_dy = out[2] + source_dx = out[3] + + assert_allclose(out[4], 1) + model = Model4DSTEM.build(params=params, scan_pos=scan_pos) + ray = model.make_source_ray(source_dx=source_dx, source_dy=source_dy).ray + res = model.trace(ray) + assert_allclose(inp[2], res['detector'].sampling['detector_px'].y, rtol=1e-12, atol=1e-12) + assert_allclose(inp[3], res['detector'].sampling['detector_px'].x, rtol=1e-12, atol=1e-12) + assert_allclose(out[0], res['specimen'].sampling['scan_px'].y, rtol=1e-12, atol=1e-12) + assert_allclose(out[1], res['specimen'].sampling['scan_px'].x, rtol=1e-12, atol=1e-12) + + +def distort(x): + return np.sign(x) * np.abs(x)**1.0001 + + +class BadModel(Model4DSTEM): + def trace(self, ray): + sup = super().trace(ray) + res = Result4DSTEM() + for key, val in sup.items(): + r = val.ray + bad_ray = r.derive( + x=distort(r.x), + y=distort(r.y), + dx=distort(r.dx), + dy=distort(r.dy), + ) + if key == 'specimen': + s = val.sampling['scan_px'] + res[key] = ResultSection( + component=val.component, + ray=bad_ray, + sampling={ + 'scan_px': PixelYX( + x=distort(s.x), + y=distort(s.y), + ) + } + ) + elif key == 'detector': + s = val.sampling['detector_px'] + res[key] = ResultSection( + component=val.component, + ray=bad_ray, + sampling={ + 'detector_px': PixelYX( + x=distort(r.x), + y=distort(r.y), + ) + } + ) + else: + res[key] = ResultSection( + component=val.component, + ray=bad_ray + ) + return res + + +def test_nonlinear_model(monkeypatch): + params = Parameters4DSTEM( + overfocus=0.123, + scan_pixel_pitch=0.234, + camera_length=0.73, + detector_pixel_pitch=0.0321, + semiconv=0.023, + scan_center=PixelYX(x=0.13, y=0.23), + scan_rotation=0.752, + flip_factor=-1., + detector_center=PixelYX(x=23, y=42), + descan_error=DescanError( + pxo_pxi=0.2, + pxo_pyi=0.3, + pyo_pxi=0.5, + pyo_pyi=0.7, + sxo_pxi=0.11, + sxo_pyi=0.13, + syo_pxi=0.17, + syo_pyi=0.19, + offpxi=0.23, + offpyi=0.29, + offsxi=0.31, + offsyi=0.37 + ) + ) + + import microscope_calibration.common.model + monkeypatch.setattr( + target=microscope_calibration.common.model, + name='Model4DSTEM', + value=BadModel + ) + with pytest.raises(RuntimeError, match="not linear"): + get_forward_transformation_matrix(sim_params=params) + + +def test_no_precision(monkeypatch): + params = Parameters4DSTEM( + overfocus=0.123, + scan_pixel_pitch=0.234, + camera_length=0.73, + detector_pixel_pitch=0.0321, + semiconv=0.023, + scan_center=PixelYX(x=0.13, y=0.23), + scan_rotation=0.752, + flip_factor=-1., + detector_center=PixelYX(x=23, y=42), + descan_error=DescanError( + pxo_pxi=0.2, + pxo_pyi=0.3, + pyo_pxi=0.5, + pyo_pyi=0.7, + sxo_pxi=0.11, + sxo_pyi=0.13, + syo_pxi=0.17, + syo_pyi=0.19, + offpxi=0.23, + offpyi=0.29, + offsxi=0.31, + offsyi=0.37 + ) + ) + # We cause discrepancies and "blame" it on lack of precision + # to test this code path + import microscope_calibration.common.model + monkeypatch.setattr( + target=microscope_calibration.common.model, + name='Model4DSTEM', + value=BadModel + ) + import microscope_calibration.common.stem_overfocus + monkeypatch.setattr( + target=microscope_calibration.common.stem_overfocus, + name='target_dtype', + value=jnp.float32 + ) + with pytest.raises(RuntimeError, match='No float64 support'): + get_forward_transformation_matrix(sim_params=params) + + +def test_project_identity(): + # 1:1 size mapping between detector and specimen + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + camera_length=1, + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=6.9, y=16.), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=7.1, y=16.), + descan_error=DescanError() + ) + obj = np.random.random((32, 13)) + res = project( + image=obj, + detector_shape=(32, 13), + scan_shape=(32, 13), + sim_params=params, + ) + assert_allclose(obj, res[16, 7]) + assert_allclose(obj, res[:, :, 16, 7]) + + +def test_project_scale(): + # 1:2 upscaling on the detector + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + camera_length=1, + detector_pixel_pitch=1, + semiconv=np.pi/2, + scan_center=PixelYX(x=16, y=16.), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=32, y=32.), + descan_error=DescanError() + ) + obj = np.random.random((32, 32)) + res = project( + image=obj, + detector_shape=(64, 64), + scan_shape=(32, 32), + sim_params=params, + ) + assert_allclose(obj, res[16, 16, ::2, ::2]) + + +def test_project_shift(): + # 1:1 size mapping between detector and specimen + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + camera_length=1, + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=6.9, y=16.), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=8.1, y=15.), + descan_error=DescanError() + ) + obj = np.random.random((32, 13)) + res = project( + image=obj, + detector_shape=(32, 13), + scan_shape=(32, 13), + sim_params=params, + ) + assert_allclose(obj, res[15, 8]) + + +def test_project_rotate(): + # 1:1 size mapping between detector and specimen + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + camera_length=1, + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=16, y=16.), + scan_rotation=np.pi/2, + flip_factor=1., + detector_center=PixelYX(x=16, y=16.), + descan_error=DescanError() + ) + obj = np.random.random((32, 32)) + res = project( + image=obj, + detector_shape=(32, 32), + scan_shape=(32, 32), + sim_params=params, + ) + assert_allclose(obj, np.rot90(res[15, 16], k=1)) + + +def test_project_flip(): + # 1:1 size mapping between detector and specimen + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + camera_length=1, + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=16, y=16.), + scan_rotation=0., + flip_factor=-1., + detector_center=PixelYX(x=16, y=16.), + descan_error=DescanError() + ) + obj = np.random.random((32, 32)) + res = project( + image=obj, + detector_shape=(32, 32), + scan_shape=(32, 32), + sim_params=params, + ) + assert_allclose(obj, np.flip(res[15, 16], axis=0)) + + +def test_project_detector_rotate(): + # 1:1 size mapping between detector and specimen + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + camera_length=1, + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=16, y=16.), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=16, y=16.), + detector_rotation=np.pi/2, + descan_error=DescanError() + ) + obj = np.random.random((32, 32)) + res = project( + image=obj, + detector_shape=(32, 32), + scan_shape=(32, 32), + sim_params=params, + ) + assert_allclose(obj, np.rot90(res[16, 15], k=-1)) + + +def test_project_map_identity(): + # 1:1 size mapping between detector and specimen + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + camera_length=1, + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=16, y=16.), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=16., y=16.), + descan_error=DescanError() + ) + obj = np.random.random((32, 32)) + + def map_coord(inp): + cy = obj.shape[0] / 2 + cx = obj.shape[1] / 2 + inp_vec = jnp.array((inp.y, inp.x)) + y, x = identity() @ inp_vec + return PixelYX(y=y+cy, x=x+cx) + + res = project( + image=obj, + detector_shape=(32, 32), + scan_shape=(32, 32), + sim_params=params, + specimen_to_image=map_coord + ) + assert_allclose(obj, res[16, 16]) + assert_allclose(obj, res[:, :, 16, 16]) + + +def test_project_map_scale(): + # 1:1 size mapping between detector and specimen + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + camera_length=1, + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=16, y=16.), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=16., y=16.), + descan_error=DescanError() + ) + obj = np.random.random((64, 64)) + obj_ref = obj[::2, ::2] + + def map_coord(inp): + cy = obj.shape[0] / 2 + cx = obj.shape[1] / 2 + inp_vec = jnp.array((inp.y, inp.x)) + y, x = scale(2) @ inp_vec + return PixelYX(y=y+cy, x=x+cx) + + res = project( + image=obj, + detector_shape=(32, 32), + scan_shape=(32, 32), + sim_params=params, + specimen_to_image=map_coord + ) + assert_allclose(obj_ref, res[16, 16]) + assert_allclose(obj_ref, res[:, :, 16, 16]) + + +def test_project_map_rotate(): + # 1:1 size mapping between detector and specimen + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + camera_length=1, + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=16, y=16.), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=16., y=16.), + descan_error=DescanError() + ) + obj = np.random.random((32, 32)) + + def map_coord(inp): + cy = obj.shape[0] / 2 + cx = obj.shape[1] / 2 + inp_vec = jnp.array((inp.y, inp.x)) + y, x = rotate(np.pi/2) @ inp_vec + return PixelYX(y=y+cy, x=x+cx) + + res = project( + image=obj, + detector_shape=(32, 32), + scan_shape=(32, 32), + sim_params=params, + specimen_to_image=map_coord + ) + assert_allclose(obj, np.rot90(res[17, 16], k=-1)) + assert_allclose(obj, np.rot90(res[:, :, 17, 16], k=-1)) + + +def test_project_map_flip(): + # 1:1 size mapping between detector and specimen + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + camera_length=1, + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=16, y=16.), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=16., y=16.), + descan_error=DescanError() + ) + obj = np.random.random((32, 32)) + + def map_coord(inp): + cy = obj.shape[0] / 2 + cx = obj.shape[1] / 2 + inp_vec = jnp.array((inp.y, inp.x)) + y, x = flip_y() @ inp_vec + return PixelYX(y=y+cy, x=x+cx) + + res = project( + image=obj, + detector_shape=(32, 32), + scan_shape=(32, 32), + sim_params=params, + specimen_to_image=map_coord + ) + assert_allclose(np.flip(obj, axis=0), res[17, 16]) + assert_allclose(np.flip(obj, axis=0), res[:, :, 17, 16]) + + +def test_project_fixref_scanscale(): + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=2, # <-- + camera_length=1, + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=16, y=16.), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=16., y=16.), + descan_error=DescanError() + ) + obj = np.random.random((64, 64)) + scan_ref = obj[::2, ::2] + det_ref = obj[16:48, 16:48] + + def map_coord(inp): + cy = obj.shape[0] / 2 + cx = obj.shape[1] / 2 + inp_vec = jnp.array((inp.y, inp.x)) + y, x = identity() @ inp_vec + return PixelYX(y=y+cy, x=x+cx) + + res = project( + image=obj, + detector_shape=(32, 32), + scan_shape=(32, 32), + sim_params=params, + specimen_to_image=map_coord + ) + assert_allclose(det_ref, res[16, 16]) + assert_allclose(scan_ref, res[:, :, 16, 16]) + + +def test_project_fixref_scanshift(): + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + camera_length=1, + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=17, y=15.), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=16., y=16.), + descan_error=DescanError() + ) + obj = np.random.random((32, 32)) + + def map_coord(inp): + cy = obj.shape[0] / 2 + cx = obj.shape[1] / 2 + inp_vec = jnp.array((inp.y, inp.x)) + y, x = identity() @ inp_vec + return PixelYX(y=y+cy, x=x+cx) + + res = project( + image=obj, + detector_shape=(32, 32), + scan_shape=(32, 32), + sim_params=params, + specimen_to_image=map_coord + ) + assert_allclose(obj, res[15, 17]) + assert_allclose(obj, res[:, :, 15, 17]) + + +def test_project_fixref_scanrotate(): + params = Parameters4DSTEM( + overfocus=1, + scan_pixel_pitch=1, + camera_length=1, + detector_pixel_pitch=2, + semiconv=np.pi/2, + scan_center=PixelYX(x=16, y=16.), + scan_rotation=np.pi/2, + flip_factor=1., + detector_center=PixelYX(x=16., y=16.), + descan_error=DescanError() + ) + obj = np.random.random((32, 32)) + + def map_coord(inp): + cy = obj.shape[0] / 2 + cx = obj.shape[1] / 2 + inp_vec = jnp.array((inp.y, inp.x)) + y, x = identity() @ inp_vec + return PixelYX(y=y+cy, x=x+cx) + + res = project( + image=obj, + detector_shape=(32, 32), + scan_shape=(32, 32), + sim_params=params, + specimen_to_image=map_coord + ) + assert_allclose(obj, res[16, 16]) + assert_allclose(np.rot90(obj), res[:, :, 16, 15]) + + +def test_project_aperture(): + scan_pixel_pitch = 0.1 + detector_pixel_pitch = 2 * scan_pixel_pitch + overfocus = 1. + camera_length = 1. + propagation_distance = overfocus + camera_length + obj_half_size = 16 + # Small epsilon to avoid hitting numerical errors at exactly the pixel boundary + angle = np.arctan2(obj_half_size*detector_pixel_pitch/2 + 0.001, propagation_distance) + + params = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=obj_half_size, y=obj_half_size), + ) + obj = np.random.random((32, 32)) + det_ref = obj.copy() + + ys, xs = np.ogrid[:obj.shape[0], :obj.shape[1]] + ys -= obj_half_size + xs -= obj_half_size + dist = np.sqrt(ys**2 + xs**2) + + det_ref[dist > obj_half_size/2 + 0.001] = 0 + + res = project( + image=obj, + detector_shape=(2*obj_half_size, 2*obj_half_size), + scan_shape=(2*obj_half_size, 2*obj_half_size), + sim_params=params, + ) + assert_allclose(det_ref, res[obj_half_size, obj_half_size]) + assert_allclose(obj, res[:, :, obj_half_size, obj_half_size]) + + +def test_project_descan(): + scan_pixel_pitch = 0.1 + detector_pixel_pitch = 2 * scan_pixel_pitch + overfocus = 1. + camera_length = 1. + propagation_distance = overfocus + camera_length + obj_half_size = 16 + # Small epsilon to avoid hitting numerical errors at exactly the pixel boundary + angle = np.arctan2(obj_half_size*detector_pixel_pitch/2 + 0.001, propagation_distance) + + params = Parameters4DSTEM( + overfocus=overfocus, + scan_pixel_pitch=scan_pixel_pitch, + camera_length=camera_length, + detector_pixel_pitch=detector_pixel_pitch, + semiconv=angle, + scan_center=PixelYX(x=obj_half_size, y=obj_half_size), + scan_rotation=0., + flip_factor=1., + detector_center=PixelYX(x=obj_half_size, y=obj_half_size), + descan_error=DescanError( + offpxi=detector_pixel_pitch, + offpyi=2 * detector_pixel_pitch, + offsxi=-3 * detector_pixel_pitch/camera_length, + offsyi=-5 * detector_pixel_pitch/camera_length, + pxo_pxi=7 * detector_pixel_pitch/scan_pixel_pitch, + pyo_pyi=11 * detector_pixel_pitch/scan_pixel_pitch, + sxo_pxi=-13 * detector_pixel_pitch/scan_pixel_pitch/camera_length, + syo_pyi=-17 * detector_pixel_pitch/scan_pixel_pitch/camera_length, + ) + ) + obj = np.ones((32, 32)) + det_ref = obj.copy() + + ys, xs = np.ogrid[:obj.shape[0], :obj.shape[1]] + ys -= obj_half_size + 2 - 5 + xs -= obj_half_size + 1 - 3 + dist = np.sqrt(ys**2 + xs**2) + + det_ref[dist > obj_half_size/2 + 0.001] = 0 + + det_ref2 = obj.copy() + ys, xs = np.ogrid[:obj.shape[0], :obj.shape[1]] + ys -= obj_half_size + 2 - 5 + 11 - 17 + xs -= obj_half_size + 1 - 3 + 7 - 13 + dist = np.sqrt(ys**2 + xs**2) + + det_ref2[dist > obj_half_size/2 + 0.001] = 0 + + res = project( + image=obj, + detector_shape=(2*obj_half_size, 2*obj_half_size), + scan_shape=(2*obj_half_size, 2*obj_half_size), + sim_params=params, + ) + assert_allclose(det_ref, res[obj_half_size, obj_half_size]) + assert_allclose(det_ref2, res[obj_half_size+1, obj_half_size+1])