diff --git a/docs/src/_static/css/layout.css b/docs/src/_static/css/layout.css new file mode 100644 index 0000000..1109e29 --- /dev/null +++ b/docs/src/_static/css/layout.css @@ -0,0 +1,61 @@ +/* Let the page content use the whole browser width instead of the + theme's fixed 800px column. */ +.wy-nav-content { + max-width: none; +} + +/* Table cells wrap their text instead of pushing the table out of the page. */ +.rst-content table.docutils td, +.rst-content table.docutils th, +.wy-table-responsive table td, +.wy-table-responsive table th { + white-space: normal; +} + +/* Button showing/hiding the navigation sidebar (see sidebar_toggle.js). */ +.pmq-sidebar-toggle { + position: fixed; + top: 8px; + left: 308px; + z-index: 300; + width: 32px; + height: 32px; + padding: 0; + border: 1px solid #c9c9c9; + border-radius: 4px; + background: #fcfcfc; + color: #404040; + font-size: 18px; + line-height: 30px; + text-align: center; + cursor: pointer; + opacity: 0.8; +} +.pmq-sidebar-toggle:hover { + opacity: 1; + background: #e7f2fa; +} + +body.pmq-sidebar-hidden .wy-nav-side { + display: none; +} +body.pmq-sidebar-hidden .wy-nav-content-wrap { + margin-left: 0; +} +body.pmq-sidebar-hidden .pmq-sidebar-toggle { + left: 8px; +} + +/* On small screens the theme already has its own menu button. */ +@media screen and (max-width: 768px) { + .pmq-sidebar-toggle { + display: none; + } +} + +/* Keep the breadcrumbs clear of the toggle button. */ +@media screen and (min-width: 769px) { + .wy-breadcrumbs { + padding-left: 36px; + } +} diff --git a/docs/src/_static/css/overflow.css b/docs/src/_static/css/overflow.css new file mode 100644 index 0000000..bf7156a --- /dev/null +++ b/docs/src/_static/css/overflow.css @@ -0,0 +1,11 @@ +.rst-content img { + max-width: none !important; + height: auto; +} +.wy-table-responsive { + overflow: visible; +} + +.dataTables_wrapper { + overflow: auto; +} diff --git a/docs/src/_static/js/sidebar_toggle.js b/docs/src/_static/js/sidebar_toggle.js new file mode 100644 index 0000000..2f9f04c --- /dev/null +++ b/docs/src/_static/js/sidebar_toggle.js @@ -0,0 +1,44 @@ +// Adds a button to show/hide the navigation sidebar of the Read the Docs theme. +// The choice is remembered between pages. +(function () { + var KEY = "beamshaping-docs-sidebar-hidden"; + + function stored() { + try { + return window.localStorage.getItem(KEY) === "1"; + } catch (e) { + return false; + } + } + + function store(hidden) { + try { + window.localStorage.setItem(KEY, hidden ? "1" : "0"); + } catch (e) { + // storage unavailable: the choice only lasts for this page + } + } + + document.addEventListener("DOMContentLoaded", function () { + var button = document.createElement("button"); + button.type = "button"; + button.className = "pmq-sidebar-toggle"; + + function apply(hidden) { + document.body.classList.toggle("pmq-sidebar-hidden", hidden); + button.innerHTML = hidden ? "☰" : "«"; + button.title = hidden ? "Show the navigation sidebar" : "Hide the navigation sidebar"; + button.setAttribute("aria-label", button.title); + button.setAttribute("aria-expanded", hidden ? "false" : "true"); + } + + button.addEventListener("click", function () { + var hidden = !document.body.classList.contains("pmq-sidebar-hidden"); + apply(hidden); + store(hidden); + }); + + apply(stored()); + document.body.appendChild(button); + }); +})(); diff --git a/docs/src/acknowledgments.rst b/docs/src/acknowledgments.rst index 3522825..8def9ed 100644 --- a/docs/src/acknowledgments.rst +++ b/docs/src/acknowledgments.rst @@ -41,7 +41,7 @@ Main Sources - `GitHub: pymodaq_plugins_beam_shaping `_ * - **Scientific Article** - Full manuscript (PDF/LaTeX) provided by the authors (Rollo, Arbouet, Weber) - - `To be cited <>`_ + - To be cited * - **PyMoDAQ Documentation** - Official guide for extensions and documentation style - `pymodaq.cnrs.fr `_ @@ -54,10 +54,10 @@ Main Sources Tools Used ---------- +---------- - **Sphinx** (with ``sphinx-rtd-theme``) for documentation generation. - **reStructuredText** (``.rst``) for writing. -- **LaTeX** for mathematical equations (integrated via ``sphinx.ext.imgmath``). +- **LaTeX** syntax for mathematical equations (rendered in the browser by MathJax via ``sphinx.ext.mathjax``). - **HDF5** for describing the structure of ``.h5beam`` files. diff --git a/docs/src/bibtex.bib b/docs/src/bibtex.bib index 3a1af97..9825aee 100644 --- a/docs/src/bibtex.bib +++ b/docs/src/bibtex.bib @@ -208,6 +208,7 @@ @Article{gerchberg_practical_1972 year = {1972}, pages = {237}, volume = {35}, + url = {https://web.archive.org/web/20160328053000/http://www.u.arizona.edu/~ppoon/GerchbergandSaxton1972.pdf}, abstract = {An algorithm is presented for the rapid solution of the phase of the complete wave function whose intensity in the diffraction and imaging planes of an imaging system are known. A proof is given showing that a defined error between the estimated function and the correct function must decrease as the algorithm iterates. The problem of uniqueness is discussed and results are presented demonstrating the power of the method.}, groups = {pulse shaping}, } diff --git a/docs/src/conf.py b/docs/src/conf.py index 0c36a56..de4ae0f 100644 --- a/docs/src/conf.py +++ b/docs/src/conf.py @@ -33,7 +33,7 @@ "sphinx_autodoc_typehints", 'sphinx.ext.doctest', 'sphinx.ext.coverage', - 'sphinx.ext.imgmath', + 'sphinx.ext.mathjax', # equations rendered in the browser, no LaTeX needed on the build machine (Read the Docs) 'sphinx.ext.githubpages', 'sphinx.ext.autosummary', 'releases', @@ -53,19 +53,9 @@ 'section': 'Section %s', } -html_css_files = [ - 'https://fonts.googleapis.com/icon?family=Material+Icons', - 'css/custom.css', # Pour styliser les icônes -] - bibtex_bibfiles = ['bibtex.bib'] # Chemin relatif à docs/ bibtex_reference_style = 'author_year' # Style de citation (ex: "Weber 2021") -# Configuration pour imgmath (équations LaTeX) -imgmath_image_format = 'png' # ou 'svg' -imgmath_font_size = 14 -imgmath_dpi = 150 - # -- Options for autodocumentation --------------------------------------------- autodoc_member_order = "groupwise" autoclass_content = "class" @@ -120,7 +110,12 @@ } html_css_files = [ + 'https://fonts.googleapis.com/icon?family=Material+Icons', 'css/overflow.css', + 'css/layout.css', # full-width content, tables kept within it +] +html_js_files = [ + 'js/sidebar_toggle.js', # button to hide the navigation sidebar ] html_static_path = ["_static", "_images"] # NOUVEAU: Ajout de "_images" @@ -134,6 +129,10 @@ 'paging': True, } +# -- Options for rediraffe ----------------------------------------------------- +# Redirections of the pages that are renamed or removed, one "old_page new_page" per line (without the extension) +rediraffe_redirects = 'redirects.txt' + # -- Options for intersphinx --------------------------------------------------- intersphinx_mapping = { 'python': ('https://docs.python.org/3', None), diff --git a/docs/src/introduction.rst b/docs/src/introduction.rst index 6926b3c..1a79a49 100644 --- a/docs/src/introduction.rst +++ b/docs/src/introduction.rst @@ -37,6 +37,7 @@ Applications - Wavefront correction (aberration compensation). .. _FIG-schema: + .. figure:: /_images/layout.png :alt: General Beam-Shaping Problem :width: 90% diff --git a/docs/src/quick_start.rst b/docs/src/quick_start.rst index f210001..53ee702 100644 --- a/docs/src/quick_start.rst +++ b/docs/src/quick_start.rst @@ -7,7 +7,7 @@ Quick Start :alt: Save :align: middle -.. |file_open| image:: /_static/icons/folder_open.png +.. |file_open| image:: /_static/icons/file_open.png :height: 20pt :alt: Load :align: middle @@ -22,7 +22,7 @@ Quick Start :alt: Input :align: middle -.. |deblur| image:: /_static/icons/tune.png +.. |deblur| image:: /_static/icons/deblur.png :height: 20pt :alt: Corrections :align: middle @@ -128,6 +128,7 @@ Follow these steps to perform your first beam shaping: For more details on the interface, see :numref:`FIG-quick-start`. .. _FIG-quick-start: + .. figure:: /_images/main_app.png :alt: BeamShaping User Interface :width: 100% diff --git a/docs/src/redirects.txt b/docs/src/redirects.txt new file mode 100644 index 0000000..82d3140 --- /dev/null +++ b/docs/src/redirects.txt @@ -0,0 +1 @@ +# "old_page new_page" for each page that is renamed or removed (paths relative to docs/src, without extension) diff --git a/docs/src/references.rst b/docs/src/references.rst index cf28ff0..c81967b 100644 --- a/docs/src/references.rst +++ b/docs/src/references.rst @@ -1,45 +1,22 @@ References -========= +========== PyMoDAQ Documentation --------------------- +- To cite PyMoDAQ: :cite:p:`Weber2021` - `PyMoDAQ Official Documentation `_ - `Extension Plugins Guide `_ - `Plugin Template Repository `_ Beam Shaping Literature ----------------------- -.. [Gerchberg1972] - Gerchberg, R. W., & Saxton, W. O. (1972). - *A practical algorithm for the determination of the phase from image and diffraction plane pictures*. - **Optik**, *35*, 237–246. - `DOI:10.1088/0030-3946/35/1/002 `_ +----------------------- +The articles cited in this documentation: -.. [Pasienski2008] - Pasienski, M., & DeMarco, B. (2008). - *High-accuracy modal beam shaping*. - **Optics Letters**, *33*(15), 1719–1721. - `DOI:10.1364/OL.33.001719 `_ - -.. [Wu2021] - Wu, Y., et al. (2021). - *Adaptive beam shaping with weighted Gerchberg-Saxton algorithm*. - **Optics Express**, *29*(12), 18345–18356. - `DOI:10.1364/OE.424917 `_ - -.. [MendozaYero2014] - Mendoza-Yero, O., et al. (2014). - *Encoding amplitude and phase information in a single phase-only spatial light modulator*. - **Optics Express**, *22*(13), 16336–16347. - `DOI:10.1364/OE.22.016336 `_ - -.. [Weber2021] - Weber, S., et al. (2021). - *PyMoDAQ: An open-source, Python-based software for modular data acquisition*. - **Journal of Open Source Software**, *6*(60), 2940. - `DOI:10.21105/joss.02940 `_ +.. bibliography:: + :cited: + :style: plain Plugin Repository ----------------- +----------------- - `PyMoDAQ-BeamShaping GitHub `_ diff --git a/docs/src/theory.rst b/docs/src/theory.rst index 753819f..cf3e86f 100644 --- a/docs/src/theory.rst +++ b/docs/src/theory.rst @@ -1,5 +1,5 @@ Theoretical Background -===================== +====================== .. _sec-theory-intro: @@ -21,13 +21,13 @@ PyMoDAQ-BeamShaping distinguishes **four planes** in the optical setup: * - **Plane** - **Description** * - **Input** - - Where the **incident field** \( U_{in} \) is defined. + - Where the **incident field** :math:`U_{in}` is defined. * - **Modulator** - Where the **SLM** applies a constraint (e.g., phase modulation). * - **Intermediate** - **Fourier plane** in a 4f system (where filtering can be applied). * - **Output** - - Where the **shaped field** \( U_{out} \) is required to match the target. + - Where the **shaped field** :math:`U_{out}` is required to match the target. In most cases, the **input** and **modulator** planes coincide physically. In this situation, the "incident field" and the "modulated field" refer to the optical field defined on that same plane, @@ -40,22 +40,22 @@ For a visual representation of the optical planes, see {numref}`FIG-schema`. Optical Field Representation ---------------------------- In a plane perpendicular to the optical axis, the **complex field** of a quasi-monochromatic scalar optical field -at wavelength \( \lambda \) is defined as: +at wavelength :math:`\lambda` is defined as: .. math:: U(\mathbf{r}_{k}) = A(\mathbf{r}_{k})\,e^{i\phi(\mathbf{r}_{k})}, where: -- \( \mathbf{r}_{k} = (x_{k}, y_{k}) \): Transverse coordinates in plane \( k \). -- \( A(\mathbf{r}_{k}) \ge 0 \): **Amplitude** (real and non-negative). -- \( \phi(\mathbf{r}_{k}) \): **Phase** (in radians). +- :math:`\mathbf{r}_{k} = (x_{k}, y_{k})`: Transverse coordinates in plane :math:`k`. +- :math:`A(\mathbf{r}_{k}) \ge 0`: **Amplitude** (real and non-negative). +- :math:`\phi(\mathbf{r}_{k})`: **Phase** (in radians). .. _sec-theory-problem-formulation: Beam Shaping as an Inverse Problem --------------------------------- +---------------------------------- The **computational beam shaping task** can be stated as an **inverse problem**: -Find a set of parameters \( \theta \) such that the propagated field \( U_{out} \) satisfies a desired constraint in the output plane. +Find a set of parameters :math:`\theta` such that the propagated field :math:`U_{out}` satisfies a desired constraint in the output plane. The two common cases are: @@ -70,8 +70,8 @@ The two common cases are: U_{out}(\mathbf{r}_{out}) \approx U_{\mathrm{target}}(\mathbf{r}_{out}). In either case, the feasible solutions are restricted by: -- The **modulator physics** encoded in \( \mathcal{M} \). -- The **optical configuration** encoded in \( \mathcal{P} \). +- The **modulator physics** encoded in :math:`\mathcal{M}`. +- The **optical configuration** encoded in :math:`\mathcal{P}`. - The **limitations of the algorithm** used to solve the inverse problem. .. _sec-theory-modulators: @@ -79,35 +79,39 @@ In either case, the feasible solutions are restricted by: Types of Spatial Light Modulation --------------------------------- .. _sec-phase-only: + **Phase-Only Modulation** The field immediately after the modulator can be written as (Equation 5 in the article): .. math:: U_m(\mathbf{r}_{m}) = A_{\mathrm{in}}(\mathbf{r}_{m})\,e^{i\phi(\mathbf{r}_{m})}, - where \( A_{\mathrm{in}} = |U_{\mathrm{in}}| \) is the **incident amplitude** (preserved), - and \( \phi(\mathbf{r}_{m}) \) is the **phase pattern** applied by the modulator. + where :math:`A_{\mathrm{in}} = |U_{\mathrm{in}}|` is the **incident amplitude** (preserved), + and :math:`\phi(\mathbf{r}_{m})` is the **phase pattern** applied by the modulator. **Implementation**: + - **Liquid-Crystal SLMs** (e.g., Holoeye Pluto, Hamamatsu LCOS): Each pixel modulates the optical path length via voltage-controlled liquid crystal orientation. **Transfer Function** (Equation 12 in the article): - The modulator transformation \( \mathcal{M} \) is modeled as a pointwise multiplication by a unitary complex transfer function \( T(\mathbf{r}) \): + The modulator transformation :math:`\mathcal{M}` is modeled as a pointwise multiplication by a unitary complex transfer function :math:`T(\mathbf{r})`: .. math:: U_m(\mathbf{r}_{m}) = T(\mathbf{r}_{m})\,U_{\mathrm{in}}(\mathbf{r}_{m}). .. _sec-amplitude-only: + **Amplitude-Only Modulation** The field immediately after the modulator can be written as (Equation 16 in the article): .. math:: U_m(\mathbf{r}_{m}) = U_{\mathrm{in}}(\mathbf{r}_{m})\, t(\mathbf{r}_{m}), - where \( t(\mathbf{r}_{m}) \) is a **real transmission coefficient** (0 ≤ t ≤ 1). + where :math:`t(\mathbf{r}_{m})` is a **real transmission coefficient** (0 ≤ t ≤ 1). .. _sec-binary-amplitude: + **Binary Amplitude Modulation (DMD)** In the case of **Digital Micromirror Devices (DMD)**, the transmission coefficient can only take the values 0 or 1 (Equation 17 in the article): @@ -118,6 +122,7 @@ Types of Spatial Light Modulation Often used with a **4f system** to encode **effective complex modulation** in a selected diffraction order. .. _sec-complex-modulation: + **Complex Modulation** Uses **multiple modulators** (e.g., one for amplitude, one for phase) to achieve **full complex control**: @@ -129,6 +134,7 @@ Types of Spatial Light Modulation - Higher cost (multiple devices). .. _sec-theory-fresnel: + **Fresnel Propagation (Future Work)** Fresnel propagation (near-field) is **not yet implemented** in the current version of the toolbox, but the architecture supports its future integration. The mathematical formulation is (Equation 8 in the article): @@ -139,8 +145,8 @@ Types of Spatial Light Modulation \mathcal{F}\!\left\{ U_m(\mathbf{r}_{m})\, \exp\!\left(\frac{ik}{2z}\|\mathbf{r}_{m}\|^2\right) \right\} where: - - \( k = 2\pi/\lambda \): Wave number. - - \( z \): Propagation distance. + - :math:`k = 2\pi/\lambda`: Wave number. + - :math:`z`: Propagation distance. **Use Case**: Assessing the **robustness** of shaped fields (e.g., how the pattern degrades when the observation plane is displaced). \ No newline at end of file diff --git a/docs/src/troubleshooting.rst b/docs/src/troubleshooting.rst index 5c7983b..fad2010 100644 --- a/docs/src/troubleshooting.rst +++ b/docs/src/troubleshooting.rst @@ -1,5 +1,5 @@ Troubleshooting -============== +=============== .. list-table:: **Common Issues and Solutions** :header-rows: 1 @@ -10,7 +10,8 @@ Troubleshooting - **Solution** * - SLM not responding - ``Shaper`` module not loaded in Dashboard. - - Load the ``Shaper`` module in PyMoDAQ’s Dashboard. + - Load the ``Shaper`` module in PyMoDAQ’s Dashboard and initialize it. Otherwise the default shaper of the + configuration file is used (see :doc:`user_guide/shapers`). * - Calibration error - Missing calibration file. - Run calibration via **Shaping > Calibration**. @@ -22,7 +23,7 @@ Troubleshooting - Apply Zernike/focal corrections or recalibrate the SLM. * - ``.h5beam`` file not loading - SLM size mismatch. - - Check ``sizing.py`` or recalibrate the SLM. + - Check that the size and pixel size of the Shaper actuator (``shaper_geometry`` group) are those of the file. * - Slow performance - Large field size or complex algorithm. - Reduce field size or use a simpler algorithm (e.g., ``DirectPhase``). diff --git a/docs/src/user_guide/algorithm_reference.rst b/docs/src/user_guide/algorithm_reference.rst new file mode 100644 index 0000000..3e96520 --- /dev/null +++ b/docs/src/user_guide/algorithm_reference.rst @@ -0,0 +1,135 @@ +Algorithm reference +=================== + +This page details every algorithm of the list of the extension (see :ref:`sec-algorithms-overview` for the overview +table): what it does, for which setup and the settings that appear in the *Algorithm* settings when it is selected. +Sizes of pixels in these settings follow the shaper (see :doc:`shapers`). + +Settings shared by the algorithms +--------------------------------- + +Most algorithms start from an *initial phase* of the modulator, which is also a choice in the settings: + +* **Random**: a random phase. +* **Quadratic**: a quadratic phase ``R (p² + q²) + D (p cos θ + q sin θ)`` (``p`` and ``q`` are the normalized pixel + indexes, see :cite:t:`bowman_high-fidelity_2017`) with the groups *Quadratic + Amplitude* (``Auto`` computes the X and Y amplitudes from the size of the target mask, ``X Quad.``, ``Y Quad.``, + ``Coeff`` as a multiplicative coefficient) and *Linear Shift* (``Auto`` computes the shift from the position of the + target mask, ``X Shift``, ``Y shift``). + +*Direct* does not use an initial phase. + +Direct +------ + +Sends the selected target field directly to the modulator: its phase, its amplitude or both depending on the type of +modulation of the shaper. No propagation model is involved (no lens) and the algorithm is not iterative. + +*Settings*: none. + +Diffractive +----------- + +Creates an amplitude image with a **phase-only** modulator in a **4f** line with a circular filter in the Fourier plane +that removes the undiffracted light. Not iterative. Implements the five methods A to E discussed in +:cite:t:`Clark2016`. + +*Settings*: + +* ``Gamma`` (default 4): period of the modulation grating, in pixels. +* ``Diffractive Models``: *Relative Amplitude* (method A), *Scattering* (B), *Davis* (C), *Bolduc* (D) or *Arrizon* (E). +* ``Order N`` (default 10). + +OL2014 - Amplitude/Phase Checkerboard +------------------------------------- + +Creates **amplitude and phase** images with a phase-only modulator in a **4f** line with a filter in the Fourier plane, +by encoding the complex field on a checkerboard (:cite:t:`mendoza-yero_encoding_2014`). Not iterative. + +*Settings*: + +* ``Mask block size (pxls)`` (default 5): size of the blocks of the checkerboard. +* ``amplitude divider`` (default 1). + +Gerchberg-Saxton +---------------- + +The classic iterative phase retrieval (:cite:t:`gerchberg_practical_1972`) for an amplitude image with a phase-only modulator +in the Fourier plane of a lens (**2f**). The wavelength and the focal length of the lens are those of the experimental +setup. + +*Settings*: none. + +Projections +----------- + +Gerchberg-Saxton with variants, **2f** setup, iterative. + +* **Weighting**: weights the target amplitude with the difference to the calculated output amplitude + (:cite:t:`Wu2021`). +* **MRAF** (Mixed-Region Amplitude Freedom, :cite:t:`pasienski_high-accuracy_2008`): the amplitude is imposed in a signal region and left free in the rest. A + region of interest (rectangular or elliptical) has to be selected in the target plane. + +*Settings*: + +* ``Weighting`` (default off). +* ``Mixing ratio`` (default 0.5, between 0 and 1): the MRAF parameter. 1 is the standard Gerchberg-Saxton algorithm. + +slmsuite Hologram +----------------- + +Gerchberg-Saxton and weighted Gerchberg-Saxton methods computed by slmsuite, **2f** setup, iterative. Provided by +``pymodaq_plugins_slmsuite`` (:doc:`slmsuite`). + +*Settings*: ``Method`` (GS, WGS-Leonardo, WGS-Kim, WGS-Nogrette, WGS-Wu, WGS-tanh), ``Iterations per step``, and the +settings of the chosen method (feedback exponent, feedback factor, iteration at which the phase is fixed) with the +defaults of slmsuite, see :doc:`slmsuite`. + +Minimize and TorchOptim +----------------------- + +* **Minimize** uses the minimizers of ``pytorch-minimize``. +* **TorchOptim** uses the L-BFGS optimizer of ``pytorch``. + +*Settings* (both): + +* ``Max Iterations`` (default 100) and ``Tolerance`` (default 1e-9). +* ``Loss``: the loss function and, in *Loss Parameters*, its own settings (the value of the loss is displayed in + ``Loss Value``). + + .. list-table:: + :header-rows: 1 + :widths: 28 17 55 + + * - **Loss** + - **Shapes** + - **Settings (default)** + * - LeastSquares + - amplitude + - none + * - MSELoss + - amplitude + - none + * - SmoothL1Loss + - amplitude + - ``Beta`` (0.5) + * - LeastExponent + - amplitude + - ``Loss exponent`` (4) + * - Chicken + - amplitude and phase + - ``Power exponent`` (9), ``Sum exponent`` (2) + * - ChickenArnaud + - amplitude and phase + - ``Ratio`` (1) + * - LSQAmplitudePhase + - amplitude and phase + - ``Amplitude exponent`` (1), ``Phase exponent`` (1) + + .. warning:: + The amplitude-only losses work well. The three losses that shape both amplitude and phase (*Chicken*, + *ChickenArnaud*, *LSQAmplitudePhase*, after :cite:t:`bowman_high-fidelity_2017`) give results that are **not satisfactory yet** and + do not seem to reproduce the ones of the paper. + +*Minimize* only: ``Method`` of the minimizer (default l-bfgs): bfgs, l-bfgs, cg, newton-cg, newton-exact, dogleg, +trust-ncg, trust-exact or trust-krylov. diff --git a/docs/src/user_guide/algorithms.rst b/docs/src/user_guide/algorithms.rst index 39b3763..c815b38 100644 --- a/docs/src/user_guide/algorithms.rst +++ b/docs/src/user_guide/algorithms.rst @@ -5,66 +5,93 @@ Algorithms for Beam Shaping Overview -------- -PyMoDAQ-BeamShaping implements **8 algorithms** for beam shaping, categorized into **3 families**: +PyMoDAQ-BeamShaping provides **8 algorithms** for beam shaping, categorized into **4 families**. The algorithm is chosen +by its name in the *Algorithm* settings of the extension. The list is built when the extension starts: the algorithms of +BeamShaping itself, then the ones provided by other installed packages (see :ref:`sec-algorithms-external`). -.. list-table:: **Implemented Algorithms** +.. list-table:: **Algorithms, as named in the interface** :header-rows: 1 - :widths: 25 10 10 10 10 35 + :widths: 17 14 7 9 9 9 35 - * - **Algorithm Family** + * - **Family** + - **Name in the interface** - **Setup** - **Iterative** - **Amplitude** - **Phase** - **Remarks** - * - Direct Application - - 2f + * - Direct application + - Direct + - no lens - ❌ - ✅ - ✅ - - Direct application of target phase/amplitude. - * - Direct Diffractive Modulation + - Sends the selected target field to the modulator (phase, amplitude or both depending on the shaper). + * - Direct diffractive modulation + - Diffractive - 4f - ❌ - ✅ - ❌ - - Various implementations (Clark 2016). - * - Direct Diffractive Modulation (CheckerBoard) + - Amplitude images with a phase-only modulator and a filter in the Fourier plane, several diffractive models + (:cite:t:`Clark2016`). + * - Direct diffractive modulation + - OL2014 - Amplitude/Phase Checkerboard - 4f - ❌ - ✅ - ✅ - - Encodes phase+amplitude (Mendoza-Yero 2014). - * - Gerchberg-Saxton (GS) + - Encodes phase and amplitude with a checkerboard (:cite:t:`mendoza-yero_encoding_2014`). + * - Iterative alternating projections + - Gerchberg-Saxton - 2f - ✅ - ✅ - ❌ - - Classic phase retrieval (Gerchberg 1972). - * - Weighted Gerchberg-Saxton + - Classic phase retrieval (:cite:t:`gerchberg_practical_1972`). + * - Iterative alternating projections + - Projections - 2f - ✅ - ✅ - ❌ - - Improved convergence (Wu 2021). - * - MRAF + - Gerchberg-Saxton with options: weighting (:cite:t:`Wu2021`) and Mixed-Region + Amplitude Freedom (MRAF, :cite:t:`pasienski_high-accuracy_2008`) with a region of interest. + * - Iterative alternating projections + - slmsuite Hologram - 2f - ✅ - ✅ - ❌ - - Mixed-Region Amplitude Freedom (Pasienski 2008). - * - Iterative Cost Function Minimization (PyTorch) + - GS and weighted GS methods (WGS-Leonardo, -Kim, -Nogrette, -Wu, -tanh), optionally on the GPU. Provided by + ``pymodaq_plugins_slmsuite``, listed once installed with its ``beamshaping`` extra + (see :doc:`slmsuite`). + * - Iterative cost function minimization + - Minimize - 2f - ✅ - ✅ - ✅ - - Gradient-based optimization. - * - Iterative Cost Function Minimization (Scipy) + - Minimization of a loss function with ``pytorch`` and ``pytorch-minimize`` + (:cite:t:`bowman_high-fidelity_2017`). The modulated quantity depends on the loss. + * - Iterative cost function minimization + - TorchOptim - 2f - ✅ - ✅ - ✅ - - Scipy-based optimization. + - Minimization of a loss function with the L-BFGS optimizer of ``pytorch`` (same reference as *Minimize*). + +The settings of each algorithm are detailed in :doc:`algorithm_reference`. + +With *Minimize* and *TorchOptim*, the losses that shape the amplitude only (*LeastSquares*, *MSELoss*, *SmoothL1Loss*, +*LeastExponent*) work well. The three losses that try to shape the amplitude **and** the phase (*Chicken*, +*ChickenArnaud*, *LSQAmplitudePhase*, after :cite:t:`bowman_high-fidelity_2017`) give results that are not satisfactory yet and do not +seem to reproduce the ones of the paper. + +*Minimize* and *TorchOptim* are only listed if ``pytorch`` is installed (``pip install +pymodaq_plugins_beam_shaping[pytorch]``). **Setup** is the propagation model assumed between the modulator and the +output plane (see :ref:`sec-algorithms-propagation`). .. _sec-algorithms-theory: @@ -190,6 +217,7 @@ shaping for the MRAF algorithm using different initial phase type and mixing par \eta = \frac{\sum_{\mathbf{r}_{out}\in S} I_{out}(\mathbf{r}_{out})}{\sum_{\mathbf{r}_{in}} I_{in}(\mathbf{r}_{in})}. .. _FIG-metrics: + .. figure:: /_images/measurement_amplitude.png :alt: Intensity-Only Shaping Results :width: 100% @@ -205,7 +233,9 @@ shaping for the MRAF algorithm using different initial phase type and mixing par .. note:: The metrics (NRMSE, Fidelity, Efficiency) are **automatically saved** in the ``.h5beam`` file under - ``/RawData/Algorithm/``. See :numref:`sec-h5beam-structure` for details. + ``/RawData/Algorithm/``. See :ref:`h5beam-structure` for details. + +.. _sec-algorithms-external: Algorithms provided by other packages ------------------------------------- diff --git a/docs/src/user_guide/calibration.rst b/docs/src/user_guide/calibration.rst index 5e5926d..f567fd4 100644 --- a/docs/src/user_guide/calibration.rst +++ b/docs/src/user_guide/calibration.rst @@ -19,7 +19,7 @@ SLM Calibration .. _sec-calibration-why: Why Calibrate? -------------- +-------------- SLMs do **not** linearly convert **gray levels** (0–255) to **optical phase** (0–2π). Calibration establishes the **gray-level-to-phase mapping** for accurate beam shaping. @@ -43,6 +43,7 @@ Calibration Procedure ~/.pymodaq/beam_shaping/calibration.h5 .. _FIG-calibration: + .. figure:: /_images/calibration.png :alt: SLM Calibration Module :width: 60% @@ -59,12 +60,14 @@ For a result on the calibration process, see :numref:`FIG-calibration`. .. _sec-calibration-using: Using Calibration ----------------- +----------------- If no calibration file is found, an error message will prompt you to calibrate first. .. note:: - Some SLMs (e.g., Holoeye Pluto) support **internal calibration**. - Enable this in the **Shaper** section of the preferences. In this case, no pymodaq calibration is needed - (but you'll have to trust the internal calibration) \ No newline at end of file + Some SLMs (e.g., Holoeye Pluto) support **internal calibration**. The Shaper actuator tells it to the extension + (``has_internal_calibration`` in its ``shaper_properties`` group, see :doc:`shapers`). Whether it is used is the + preference *use_internal_calibration* (``[calibration]``, checked by default), imposed by the extension to the + actuator: no pymodaq calibration is then needed (but you'll have to trust the internal calibration). Uncheck it to + use the calibration of BeamShaping. diff --git a/docs/src/user_guide/corrections.rst b/docs/src/user_guide/corrections.rst index de0af24..4b0ee58 100644 --- a/docs/src/user_guide/corrections.rst +++ b/docs/src/user_guide/corrections.rst @@ -69,6 +69,7 @@ To integrate corrections into PyMoDAQ’s **Dashboard** (e.g., for automation): - ``Zernike_1_1``, ``Zernike_2_0``, etc. (up to the configured order). .. _FIG-corrections: + .. figure:: /_images/corrections.png :alt: Phase Corrections Panel :width: 70% diff --git a/docs/src/user_guide/data_management.rst b/docs/src/user_guide/data_management.rst index 55f2887..bd4a19b 100644 --- a/docs/src/user_guide/data_management.rst +++ b/docs/src/user_guide/data_management.rst @@ -31,7 +31,7 @@ Both formats are **HDF5-based** and follow the **PyMoDAQ data model** (compatibl ~~~~~~~~~~~~~~~~ **Purpose**: Store a **single 2D field** (e.g., input beam, target beam). -**Generated by**: :ref:`Field Loader ` (Input or Target). +**Generated by**: Field Loader (Input or Target). .. _h5field-structure: @@ -104,7 +104,7 @@ The ``.h5field`` file has the following hierarchy: - Algorithm results (output field, modulator field, metrics). - Global configuration (wavelength, setup type, etc.). -**Generated by**: :ref:`Beam Shaping Extension `. +**Generated by**: Beam Shaping Extension. .. _h5beam-structure: diff --git a/docs/src/user_guide/fields.rst b/docs/src/user_guide/fields.rst index 844871e..9b32ed2 100644 --- a/docs/src/user_guide/fields.rst +++ b/docs/src/user_guide/fields.rst @@ -4,7 +4,7 @@ Field Loaders .. _sec-fields-parameters: Field Representation -------------------- +-------------------- A **Field** is an advanced python object encapsulating the data values (numpy array) for both the amplitude and phase. it also features attributes to add physical insight into the object such as the shape and the pixel width in microns. @@ -62,6 +62,7 @@ to apply th .. _FIG-field-loader: + .. figure:: /_images/field_loader.png :alt: Field Loader Portfolio :width: 90% diff --git a/docs/src/user_guide/index.rst b/docs/src/user_guide/index.rst index 52009a8..905929a 100644 --- a/docs/src/user_guide/index.rst +++ b/docs/src/user_guide/index.rst @@ -8,6 +8,9 @@ User Guide interface fields algorithms + algorithm_reference + shapers + slmsuite calibration corrections data_management \ No newline at end of file diff --git a/docs/src/user_guide/interface.rst b/docs/src/user_guide/interface.rst index 73d6619..a1d202f 100644 --- a/docs/src/user_guide/interface.rst +++ b/docs/src/user_guide/interface.rst @@ -61,11 +61,6 @@ The BeamShaping interface is organized into **dockable panels** for flexibility. :alt: Input :align: middle -.. |deblur| image:: /_static/icons/tune.png - :height: 20pt - :alt: Corrections - :align: middle - .. |equalizer| image:: /_static/icons/equalizer.png :height: 20pt :alt: Calibration @@ -98,7 +93,7 @@ The BeamShaping interface is organized into **dockable panels** for flexibility. .. |deblur| image:: /_static/icons/deblur.png :height: 20pt - :alt: Add Corrections + :alt: Corrections :align: middle diff --git a/docs/src/user_guide/shapers.rst b/docs/src/user_guide/shapers.rst new file mode 100644 index 0000000..eb833a5 --- /dev/null +++ b/docs/src/user_guide/shapers.rst @@ -0,0 +1,73 @@ +Shapers (SLM) and the Shaper actuator +===================================== + +.. _sec-shapers-overview: + +The Shaper actuator +------------------- + +The extension sends the computed mask to the actuator named **Shaper** in the Dashboard (a ``DAQ_Move`` module). Any +instrument plugin can be used, as long as its actuator accepts a 2D array of the size of the modulator as target +(a phase in radians, or grey levels when the data carries the attribute ``as_grey_levels=True``). + +The modulator can be of several kinds. Most spatial light modulators (SLM) are **phase only** (liquid crystal on silicon, +LCOS), but a shaper can also be **amplitude only**, such as a digital micromirror device (DMD) or other micromirror +arrays, or able to modulate both. The mask sent to the actuator is then a phase for a phase modulator and an amplitude +(or the binary pattern of a DMD) for an amplitude modulator, as declared by the ``modulator_type`` of the shaper +(see below). The algorithms must be chosen accordingly, see :doc:`algorithms`. + +The extension asks the actuator itself what the modulator is, once the actuator is initialized: number of pixels, size of +the pixels, name, type of modulation (phase, amplitude or both) and whether the shaper has an internal calibration +(conversion of a phase into grey levels done by the driver). This information is given by two read-only groups of +settings of the actuator, ``shaper_geometry`` and ``shaper_properties``, defined in the +``pymodaq_plugins_utils.hardware.shaper`` module of +`pymodaq_plugins_utils `_ (version 5.3.4 or later). A plugin that +wants to be used as a Shaper only needs to add these groups to its parameters (``shaper_params()``) and to fill them in +``ini_stage`` (``fill_shaper_settings``); it does not depend on BeamShaping. + +The shaper is read from the actuator when the experiment (preset) is set and whenever the actuator is initialized, and the +fields (input, target) are rebuilt for its number of pixels and pixel size. There is no list of shapers to configure. If +the actuator is absent, not initialized or does not provide these groups, the extension uses a **default shaper**, the +same for all the shapers, described in the ``[default_shaper]`` section of the configuration file of BeamShaping +(``name``, ``width``, ``height``, ``pixel_size`` in µm, ``has_internal_calibration``, +``modulator_type``). By default: 1920 x 1080 pixels of 8 µm, phase modulation, no internal calibration. Edit it there +for an instrument whose plugin does not tell what it is. + +The choice *use internal calibration* is a preference of BeamShaping (``use_internal_calibration`` in the +``[calibration]`` section, checked by default). When the shaper has an internal calibration, the extension imposes +this preference to the setting of the same name of the ``shaper_properties`` group of the actuator, at its start, when +the experiment is set, when the actuator is initialized and when the preferences change. If it differs, the setting of +the actuator is overwritten and a warning is logged. When it is checked, the phase is sent in radians and converted by +the driver, otherwise it is converted to grey levels with the calibration file of the :doc:`calibration` of +BeamShaping. A shaper without internal calibration is never concerned. + +.. _sec-shapers-list: + +Available shapers +----------------- + +.. list-table:: **Instrument plugins usable as Shaper** + :header-rows: 1 + :widths: 28 22 50 + + * - **Actuator** + - **Package** + - **Remarks** + * - MockShaper + - pymodaq_plugins_beam_shaping + - Simulated shaper using the default shaper of the configuration file. For tests without hardware. + * - Holoeye, HoloeyeFile, HoloeyeSplitScreen, HoloeyeMock + - `pymodaq_plugins_holoeye `_ + - Holoeye SLMs, with the SLM Display SDK 3 or 4. The phase is converted to grey levels by the SDK (internal + calibration). *HoloeyeMock* needs no hardware. + * - Slmsuite, SlmsuiteSimulated, SlmsuiteMeadowlark, SlmsuiteHoloeye + - `pymodaq_plugins_slmsuite `_ + - Any SLM supported by *slmsuite*: Holoeye, Meadowlark, Santec, Hamamatsu, mirrored screens... (see :doc:`slmsuite`). + +.. _sec-shapers-slmsuite: + +slmsuite +-------- + +Any SLM supported by `slmsuite `_ can be used as Shaper through the actuators of +``pymodaq_plugins_slmsuite``. See the page :doc:`slmsuite`. diff --git a/docs/src/user_guide/slmsuite.rst b/docs/src/user_guide/slmsuite.rst new file mode 100644 index 0000000..5d9d8fa --- /dev/null +++ b/docs/src/user_guide/slmsuite.rst @@ -0,0 +1,86 @@ +slmsuite +======== + +.. _sec-slmsuite: + +`slmsuite `_ is an open source Python package (MIT license, *slmsuite +Developers*, maintained by Holodyne Labs, `documentation `_) for the control of spatial +light modulators (SLM) and the computation of holograms. If you use it through BeamShaping, please cite slmsuite (see +the reference to use on its project page) together with this package. + +The package `pymodaq_plugins_slmsuite `_ makes it available in +PyMoDAQ, for the two roles it plays in BeamShaping: the **Shaper** (hardware) and an **algorithm** (computation). + +Installation +------------ + +:: + + pip install pymodaq_plugins_slmsuite[beamshaping] + +The ``beamshaping`` extra installs BeamShaping together with the plugin; without it the actuators work but the algorithm +is not available. The driver (SDK) of the SLM has to be installed separately, see the slmsuite documentation of each +manufacturer. + +.. _sec-slmsuite-shaper: + +Shaper actuators +---------------- + +All the actuators follow the interface of the Shaper described in :doc:`shapers`: the target is a 2D array of the size of +the SLM (or one value spread over the SLM), displayed as a **phase in radians** converted to grey levels by slmsuite +(wrapping, look-up table, wavefront correction if loaded), or as raw **grey levels** if the ``Input as grey levels`` +setting is checked or the data carries ``as_grey_levels=True``. + +* **Slmsuite**: generic, choose the slmsuite class (``SLM type``) and give its constructor arguments as a Python + dictionary +* **SlmsuiteSimulated**: simulated SLM of slmsuite, no hardware needed +* **SlmsuiteMeadowlark**: Meadowlark SLM (Windows only, Blink SDK) +* **SlmsuiteHoloeye**: Holoeye SLM (SLM Display SDK) + +Name the actuator **Shaper** in the Dashboard. It tells the extension the number of pixels, the size of the pixels and +whether the SLM has an internal calibration: the Meadowlark SLMs (look-up table loaded from the hardware) or any SLM for +which slmsuite knows a look-up table. The working wavelength is a setting of the actuator. The Meadowlark and Holoeye +actuators have been validated on real devices by the maintainer. + +.. _sec-slmsuite-algorithm: + +The slmsuite Hologram algorithm +------------------------------- + +Once installed, ``slmsuite Hologram`` appears in the list of the algorithms of BeamShaping +(:ref:`sec-algorithms-overview`). It computes the phase with ``slmsuite.holography.algorithms.Hologram.optimize``, in the +Fourier plane of a lens (2f setup, as for *Gerchberg-Saxton*): the amplitude of the input beam is the nearfield +amplitude and the target amplitude is the farfield one. It is iterative: each step runs ``Iterations per step`` +iterations of the chosen ``Method`` and keeps the state of the optimization (weights, fixed farfield phase for WGS-Kim) +from step to step. Changing the input beam, the target or the initial phase restarts the optimization. + +.. list-table:: **Methods** + :header-rows: 1 + :widths: 18 40 42 + + * - **Method** + - **Reference** + - **Specific settings (default)** + * - GS + - Gerchberg-Saxton + - none + * - WGS-Leonardo + - https://doi.org/10.1364/OE.15.001913 + - ``Feedback exponent`` (0.8) + * - WGS-Kim + - https://doi.org/10.1364/OL.44.003178 + - ``Feedback exponent`` (0.8), ``Fix phase at iteration`` (10) + * - WGS-Nogrette + - https://doi.org/10.1103/PhysRevX.4.021034 + - ``Feedback factor`` (0.1) + * - WGS-Wu + - https://doi.org/10.1364/OE.413723 + - ``Feedback exponent`` (0.5) + * - WGS-tanh + - weights updated with a hyperbolic tangent + - ``Feedback factor`` (0.2), ``Feedback exponent`` (0.5) + +The defaults are the ones of slmsuite, restored when the method is changed. The weighted (WGS) methods give a more +uniform intensity on a set of spots or regions than GS. The GPU is used if ``cupy`` is installed. The conjugate gradient +method of slmsuite is not exposed yet. See the slmsuite documentation (``Hologram.optimize``) for the parameters.