From 9198638f9b851fbc5d46553a8b7399bf507bdb05 Mon Sep 17 00:00:00 2001 From: x01dc Date: Tue, 21 Jul 2026 16:38:00 +0200 Subject: [PATCH] docs/add file-loaded at_each_angle hook example (exposure + step size) Adds a worked example to both lamni.md and flomni.md showing a hook loaded from a file that temporarily bumps tomo_countingtime and tomo_shellstep every 5th projection within sub-tomogram 2 (tomo_type 1), restoring both in a finally block -- demonstrating that a hook can change any scan parameter, not just move devices like the existing polarizer example. Notes that progress["subtomo"]/["subtomo_projection"] work the same way for tomo_types 2/3, just with an open-ended sub-tomogram count there instead of type 1's fixed 8. Co-Authored-By: Claude Sonnet 5 --- docs/user/ptychography/flomni.md | 41 ++++++++++++++++++++++++++++++++ docs/user/ptychography/lamni.md | 41 ++++++++++++++++++++++++++++++++ 2 files changed, 82 insertions(+) diff --git a/docs/user/ptychography/flomni.md b/docs/user/ptychography/flomni.md index 661948b..5796480 100644 --- a/docs/user/ptychography/flomni.md +++ b/docs/user/ptychography/flomni.md @@ -532,6 +532,47 @@ namespace, same as a cell). **Avoid plain `%run myhooks.py`** (without `-i`): it executes in a fresh, throwaway namespace each time, so an edit-and-rerun is *not* picked up automatically and the old version keeps running silently. +**Example — hook loaded from a file, changing exposure and step size for a subset of +projections:** a hook can also read `flomni.progress` and temporarily change any scan +parameter (e.g. `tomo_countingtime`, `tomo_shellstep`) just for specific projections, +then restore it. This example (tomo_type 1) takes a longer exposure at a finer +real-space step every 5th projection within sub-tomogram 2, and a normal projection +everywhere else. `~/hooks/my_hooks.py`: +```python +def high_res_every_5th(flomni, angle): + if flomni.progress["subtomo"] == 2 and flomni.progress["subtomo_projection"] % 5 == 0: + orig_countingtime = flomni.tomo_countingtime + orig_shellstep = flomni.tomo_shellstep + flomni.tomo_countingtime = 0.5 # longer exposure + flomni.tomo_shellstep = 0.2 # finer real-space step + try: + flomni.tomo_scan_projection(angle) + finally: + # restore even if the scan above raises, so a retry or the next + # projection doesn't silently keep running with these settings + flomni.tomo_countingtime = orig_countingtime + flomni.tomo_shellstep = orig_shellstep + else: + flomni.tomo_scan_projection(angle) +``` +Load and use it: +```python +import my_hooks +flomni.register_at_each_angle_hook("high_res_every_5th", my_hooks.high_res_every_5th) + +flomni.tomo_parameters() # set up the scan parameters as usual +flomni.at_each_angle_hook = "high_res_every_5th" # activate the hook +flomni.tomo_queue_add("subtomo 2 high-res every 5th") + +flomni.at_each_angle_hook = None # reset the session default for whatever's queued next +flomni.tomo_queue_execute() +``` +`progress["subtomo"]`/`progress["subtomo_projection"]` are populated the same way for +tomo_types 2/3, so the same pattern works there too — just note that unlike type 1's +fixed 8 sub-tomograms, those types have no fixed sub-tomogram count (see +[Tomography](user.ptychography.flomni.tomography) above), so "sub-tomogram 2" means +something different (and open-ended) for them. + **`tomo_scan_projection()` vs `tomo_acquire_at_angle()`:** these are not interchangeable. `tomo_scan_projection(angle)` always runs a full Fermat-scan projection; `tomo_acquire_at_angle(angle)` always runs a single-point acquisition. diff --git a/docs/user/ptychography/lamni.md b/docs/user/ptychography/lamni.md index a44ba62..590f538 100644 --- a/docs/user/ptychography/lamni.md +++ b/docs/user/ptychography/lamni.md @@ -299,6 +299,47 @@ namespace, same as a cell). **Avoid plain `%run myhooks.py`** (without `-i`): it executes in a fresh, throwaway namespace each time, so an edit-and-rerun is *not* picked up automatically and the old version keeps running silently. +**Example — hook loaded from a file, changing exposure and step size for a subset of +projections:** a hook can also read `lamni.progress` and temporarily change any scan +parameter (e.g. `tomo_countingtime`, `tomo_shellstep`) just for specific projections, +then restore it. This example (tomo_type 1) takes a longer exposure at a finer +real-space step every 5th projection within sub-tomogram 2, and a normal projection +everywhere else. `~/hooks/my_hooks.py`: +```python +def high_res_every_5th(lamni, angle): + if lamni.progress["subtomo"] == 2 and lamni.progress["subtomo_projection"] % 5 == 0: + orig_countingtime = lamni.tomo_countingtime + orig_shellstep = lamni.tomo_shellstep + lamni.tomo_countingtime = 0.5 # longer exposure + lamni.tomo_shellstep = 0.2 # finer real-space step + try: + lamni.tomo_scan_projection(angle) + finally: + # restore even if the scan above raises, so a retry or the next + # projection doesn't silently keep running with these settings + lamni.tomo_countingtime = orig_countingtime + lamni.tomo_shellstep = orig_shellstep + else: + lamni.tomo_scan_projection(angle) +``` +Load and use it: +```python +import my_hooks +lamni.register_at_each_angle_hook("high_res_every_5th", my_hooks.high_res_every_5th) + +lamni.tomo_parameters() # set up the scan parameters as usual +lamni.at_each_angle_hook = "high_res_every_5th" # activate the hook +lamni.tomo_queue_add("subtomo 2 high-res every 5th") + +lamni.at_each_angle_hook = None # reset the session default for whatever's queued next +lamni.tomo_queue_execute() +``` +`progress["subtomo"]`/`progress["subtomo_projection"]` are populated the same way for +tomo_types 2/3, so the same pattern works there too — just note that unlike type 1's +fixed 8 sub-tomograms, those types have no fixed sub-tomogram count (see +[Laminography scan](user.ptychography.lamni.laminography) above), so "sub-tomogram 2" +means something different (and open-ended) for them. + **GUI:** the tomo parameters panel has an "At-each-angle hook" dropdown, listing whatever is currently registered from the CLI (`register_at_each_angle_hook()`) — the GUI process can't register hooks itself, only select one by name for the job