feat(omny): drop redundant tomo auth code, cap type-3 step at 2.5 deg
CI for csaxs_bec / test (push) Successful in 1m45s
CI for csaxs_bec / test (push) Successful in 1m45s
The "Enter authorization code" (x12sa) prompt gating advanced tomo modes (types 2-5) predates the account-based _SUPERUSER_ACCOUNTS gate added earlier this branch, and is now fully redundant with it -- Mirko asked to remove it. Each mode still prints the existing "significant wear" warning unconditionally instead of only after entering the code. Also added a hard 2.5 degree ceiling on tomo type 3's angular step (golden ratio starting angle mode), replacing its old minimum-100-projections floor with an explicit wear-motivated cap; if the requested projection count implies a larger step, it's clamped down to 2.5 degrees. Type 2's golden_ratio_bunch_size minimum stays at 100 per Mirko's call -- wear avoidance there is handled by the warning message, not a lower floor. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QLrD7sVYGLAzsQjLVJpCgt
This commit is contained in:
@@ -16,11 +16,15 @@ full trace of each. GUI flows (`omny.omnygui_show_progress()`, `omnygui_show_xey
|
||||
`omnygui_show_omnycam_parking()`/`omnygui_show_omnycam_samplestage()`) also work now, ported onto
|
||||
flomni's current `gui_tools.py` API.
|
||||
|
||||
**Not yet started**: testing the advanced tomo modes (golden ratio, 4/8 sub-tomogram) added
|
||||
earlier this branch — this is the next thing being tested live. `holler` (Mirko's account) was
|
||||
added to `_SUPERUSER_ACCOUNTS` (`omny.py`) alongside `gac-x01dc` so `tomo_parameters()` shows the
|
||||
advanced options when testing from his own machine, where `bec.active_account` is unset and the
|
||||
superuser check falls back to the OS login.
|
||||
**Now being tested**: the advanced tomo modes (golden ratio, 4/8 sub-tomogram) added earlier this
|
||||
branch. `holler` (Mirko's account) was added to `_SUPERUSER_ACCOUNTS` (`omny.py`) alongside
|
||||
`gac-x01dc` so `tomo_parameters()` shows the advanced options when testing from his own machine,
|
||||
where `bec.active_account` is unset and the superuser check falls back to the OS login. The old
|
||||
`x12sa` authorization-code prompt gating tomo types 2-5 was removed — it predates the
|
||||
`_SUPERUSER_ACCOUNTS` account check and was fully redundant with it; see "Authorization code
|
||||
removed" below. Tomo type 3 also gained a hard cap of 2.5 degrees on the angular step (previously
|
||||
only a minimum-100-projections floor, which happened to already satisfy this but wasn't expressed
|
||||
as a wear limit).
|
||||
|
||||
**Still open / deferred** (unchanged from before, not touched this pass):
|
||||
- `x_ray_eye_align.py` is still LamNI-derived, unadapted code beyond the two call-site renames
|
||||
@@ -244,6 +248,32 @@ explicit `laser_tracker_check_and_wait_for_signalstrength()` call in `prepare_se
|
||||
(pure duplication of the per-axis checks the rtx/rtz `set()` calls already trigger). Net effect:
|
||||
quieter output, one less redundant tracker-check wait per scan setup, same safety behavior.
|
||||
|
||||
## tomo_parameters(): authorization code removed, type-3 step cap added (fixed)
|
||||
|
||||
Advanced tomo modes (types 2-5) used to require entering a hardcoded string (`x12sa`) at an "Enter
|
||||
authorization code" prompt, on top of already being hidden from non-superuser accounts by
|
||||
`_is_superuser_account()`/`_SUPERUSER_ACCOUNTS` (added earlier this branch). Once account-based
|
||||
gating existed, the code prompt was pure redundancy — Mirko pointed this out directly ("we can
|
||||
remove that now that it is based on the user account") — so it's been removed from all three
|
||||
blocks (types 2, 3, 4/5). Each block still prints the same "This mode causes significant wear in
|
||||
OMNY" wear warning as before (now unconditional, not gated behind entering the code), reworded
|
||||
slightly to explicitly address the power user.
|
||||
|
||||
Also added: tomo type 3 (equally spaced tomography, golden ratio starting angle) now enforces a
|
||||
hard ceiling of 2.5 degrees on the angular step, in addition to just deriving the step from the
|
||||
requested projection count. Previously it only enforced a minimum-100-projections floor (step
|
||||
≤1.8°), which happened to already satisfy a 2.5° ceiling — but expressed the constraint as a
|
||||
projection-count floor rather than a wear-motivated angular ceiling. If the requested projection
|
||||
count yields a step above 2.5°, the step is clamped down to 2.5° and a message is printed; the
|
||||
actual number of projections used ends up higher than what was typed. Type 2's
|
||||
`golden_ratio_bunch_size` minimum was left at 100 (unchanged) — the wear-avoidance goal there is
|
||||
served by the warning message, not by loosening that floor.
|
||||
|
||||
Test coverage: `tests/tests_bec_ipython_client/test_omny_tomo_angles.py`'s
|
||||
`test_tomo_parameters_allows_superuser_to_unlock_8_subtomo_mode` updated to drop the now-removed
|
||||
`"x12sa"` canned answer; new
|
||||
`test_tomo_parameters_clamps_type_3_step_size_to_max_2_5_degrees` covers the clamp.
|
||||
|
||||
## Environment note (not code, but will bite again if forgotten)
|
||||
|
||||
Both `csaxs_bec` and `bec_widgets` were pip-installed editable pointing at pre-repo-
|
||||
|
||||
@@ -1448,85 +1448,69 @@ class OMNY(
|
||||
print(f"The angular step in a subtomogram it will be {self.tomo_angle_stepsize}")
|
||||
|
||||
if self.tomo_type == 2:
|
||||
code = self._get_val(
|
||||
"This mode causes significant wear in OMNY. Enter authorization code.", 0, str
|
||||
print(
|
||||
"This mode causes significant wear in OMNY. You are a power user -- please"
|
||||
" avoid unnecessarily many rotations and be gentle to the setup."
|
||||
)
|
||||
self.golden_ratio_bunch_size = self._get_val(
|
||||
"Number of projections sorted per bunch (minimum 100)",
|
||||
self.golden_ratio_bunch_size,
|
||||
int,
|
||||
)
|
||||
if self.golden_ratio_bunch_size < 100:
|
||||
print("Minimum of 100 selected.")
|
||||
self.golden_ratio_bunch_size = 100
|
||||
self.golden_max_number_of_projections = self._get_val(
|
||||
"Stop after number of projections (zero for endless)",
|
||||
self.golden_max_number_of_projections,
|
||||
int,
|
||||
)
|
||||
self.golden_projections_at_0_deg_for_damage_estimation = self._get_val(
|
||||
"Repeat projections at 0 deg every second subtomo 1/0 ?",
|
||||
self.golden_projections_at_0_deg_for_damage_estimation,
|
||||
int,
|
||||
)
|
||||
if code == "x12sa":
|
||||
self.golden_ratio_bunch_size = self._get_val(
|
||||
"Number of projections sorted per bunch (minimum 100)",
|
||||
self.golden_ratio_bunch_size,
|
||||
int,
|
||||
)
|
||||
if self.golden_ratio_bunch_size < 100:
|
||||
print("Minimum of 100 selected.")
|
||||
self.golden_ratio_bunch_size = 100
|
||||
self.golden_max_number_of_projections = self._get_val(
|
||||
"Stop after number of projections (zero for endless)",
|
||||
self.golden_max_number_of_projections,
|
||||
int,
|
||||
)
|
||||
self.golden_projections_at_0_deg_for_damage_estimation = self._get_val(
|
||||
"Repeat projections at 0 deg every second subtomo 1/0 ?",
|
||||
self.golden_projections_at_0_deg_for_damage_estimation,
|
||||
int,
|
||||
)
|
||||
else:
|
||||
print(
|
||||
"Wrong authorization code. Tomo type 1 selected: 2 sub-tomograms selected."
|
||||
)
|
||||
self.tomo_type = 1
|
||||
|
||||
if self.tomo_type == 3:
|
||||
code = self._get_val(
|
||||
"This mode causes significant wear in OMNY. Enter authorization code.", 0, str
|
||||
print(
|
||||
"This mode causes significant wear in OMNY. You are a power user -- please"
|
||||
" avoid unnecessarily many rotations and be gentle to the setup."
|
||||
)
|
||||
if code == "x12sa":
|
||||
numprj = self._get_val(
|
||||
"Number of projections per sub-tomogram (minimum 100)",
|
||||
int(180 / self.tomo_angle_stepsize),
|
||||
int,
|
||||
)
|
||||
if numprj < 100:
|
||||
numprj = 100
|
||||
print("Minimum of 100 selected.")
|
||||
self.tomo_angle_stepsize = 180 / numprj
|
||||
self.golden_max_number_of_projections = self._get_val(
|
||||
"Stop after number of projections (zero for endless)",
|
||||
self.golden_max_number_of_projections,
|
||||
int,
|
||||
)
|
||||
self.golden_projections_at_0_deg_for_damage_estimation = self._get_val(
|
||||
"Repeat projections at 0 deg every second subtomo",
|
||||
self.golden_projections_at_0_deg_for_damage_estimation,
|
||||
int,
|
||||
)
|
||||
else:
|
||||
numprj = self._get_val(
|
||||
"Number of projections per sub-tomogram",
|
||||
int(180 / self.tomo_angle_stepsize),
|
||||
int,
|
||||
)
|
||||
self.tomo_angle_stepsize = 180 / numprj
|
||||
if self.tomo_angle_stepsize > 2.5:
|
||||
self.tomo_angle_stepsize = 2.5
|
||||
print(
|
||||
"Wrong authorization code. Tomo type 1 selected: 2 sub-tomograms selected."
|
||||
"Angular step exceeded the maximum of 2.5 degrees; clamped to 2.5 degrees"
|
||||
f" ({int(180 / 2.5)} projections per sub-tomogram)."
|
||||
)
|
||||
self.tomo_type = 1
|
||||
self.golden_max_number_of_projections = self._get_val(
|
||||
"Stop after number of projections (zero for endless)",
|
||||
self.golden_max_number_of_projections,
|
||||
int,
|
||||
)
|
||||
self.golden_projections_at_0_deg_for_damage_estimation = self._get_val(
|
||||
"Repeat projections at 0 deg every second subtomo",
|
||||
self.golden_projections_at_0_deg_for_damage_estimation,
|
||||
int,
|
||||
)
|
||||
|
||||
if self.tomo_type in (4, 5):
|
||||
n_subtomos = {4: 4, 5: 8}[self.tomo_type]
|
||||
code = self._get_val(
|
||||
"This mode causes significant wear in OMNY. Enter authorization code.", 0, str
|
||||
print(
|
||||
"This mode causes significant wear in OMNY. You are a power user -- please"
|
||||
" avoid unnecessarily many rotations and be gentle to the setup."
|
||||
)
|
||||
if code == "x12sa":
|
||||
tomo_numberofprojections = self._get_val(
|
||||
"Total number of projections",
|
||||
180 / self.tomo_angle_stepsize * n_subtomos,
|
||||
int,
|
||||
)
|
||||
print(f"The angular step will be {180/tomo_numberofprojections}")
|
||||
self.tomo_angle_stepsize = 180 / tomo_numberofprojections * n_subtomos
|
||||
print(
|
||||
f"The angular step in a subtomogram it will be {self.tomo_angle_stepsize}"
|
||||
)
|
||||
else:
|
||||
print(
|
||||
"Wrong authorization code. Tomo type 1 selected: 2 sub-tomograms selected."
|
||||
)
|
||||
self.tomo_type = 1
|
||||
tomo_numberofprojections = self._get_val(
|
||||
"Total number of projections", 180 / self.tomo_angle_stepsize * n_subtomos, int
|
||||
)
|
||||
print(f"The angular step will be {180/tomo_numberofprojections}")
|
||||
self.tomo_angle_stepsize = 180 / tomo_numberofprojections * n_subtomos
|
||||
print(f"The angular step in a subtomogram it will be {self.tomo_angle_stepsize}")
|
||||
|
||||
@staticmethod
|
||||
def _get_val(msg: str, default_value, data_type):
|
||||
|
||||
@@ -244,8 +244,9 @@ def test_tomo_parameters_forces_type_1_for_non_superuser(monkeypatch, fake_bec):
|
||||
|
||||
|
||||
def test_tomo_parameters_allows_superuser_to_unlock_8_subtomo_mode(monkeypatch, fake_bec):
|
||||
"""A superuser account can select and unlock tomo_type 5 (8 sub-tomograms)
|
||||
with the correct authorization code."""
|
||||
"""A superuser account can select and unlock tomo_type 5 (8 sub-tomograms).
|
||||
No authorization code is required -- access is gated purely by the account
|
||||
check (_is_superuser_account()), which is already exercised above."""
|
||||
monkeypatch.setattr(omny_module, "_SUPERUSER_ACCOUNTS", frozenset({"e99999"}))
|
||||
fake_bec.active_account = "e99999" # superuser
|
||||
omny = make_omny()
|
||||
@@ -265,9 +266,9 @@ def test_tomo_parameters_allows_superuser_to_unlock_8_subtomo_mode(monkeypatch,
|
||||
omny.OMNYTools = types.SimpleNamespace(yesno=lambda *a, **k: False)
|
||||
|
||||
# canned answers for: ctime, step, fovx, fovy, stitch_x, stitch_y,
|
||||
# reconstruct_foldername, tomo_type (=5, 8 sub-tomograms), authorization
|
||||
# code, total number of projections
|
||||
canned = iter([1.0, 0.1, 20, 20, 1, 1, "queue", 5, "x12sa", 144])
|
||||
# reconstruct_foldername, tomo_type (=5, 8 sub-tomograms), total number of
|
||||
# projections
|
||||
canned = iter([1.0, 0.1, 20, 20, 1, 1, "queue", 5, 144])
|
||||
monkeypatch.setattr(OMNY, "_get_val", staticmethod(lambda *a, **k: next(canned)))
|
||||
|
||||
omny.tomo_parameters()
|
||||
@@ -275,3 +276,39 @@ def test_tomo_parameters_allows_superuser_to_unlock_8_subtomo_mode(monkeypatch,
|
||||
assert omny.tomo_type == 5
|
||||
# 144 total projections / 8 sub-tomograms -> stepsize 180/(144/8) = 10.0
|
||||
assert omny.tomo_angle_stepsize == pytest.approx(10.0)
|
||||
|
||||
|
||||
def test_tomo_parameters_clamps_type_3_step_size_to_max_2_5_degrees(monkeypatch, fake_bec):
|
||||
"""tomo_type 3 (equally spaced, golden ratio starting angle) enforces a
|
||||
maximum angular step of 2.5 degrees, to limit wear from too many
|
||||
rotations. A superuser requesting too few projections per sub-tomogram
|
||||
(i.e. too large a step) gets clamped down to 2.5 degrees."""
|
||||
monkeypatch.setattr(omny_module, "_SUPERUSER_ACCOUNTS", frozenset({"e99999"}))
|
||||
fake_bec.active_account = "e99999" # superuser
|
||||
omny = make_omny()
|
||||
omny.tomo_countingtime = 1.0
|
||||
omny.tomo_shellstep = 0.1
|
||||
omny.fovx = 20
|
||||
omny.fovy = 20
|
||||
omny.stitch_x = 1
|
||||
omny.stitch_y = 1
|
||||
omny.ptycho_reconstruct_foldername = "queue"
|
||||
omny.tomo_angle_stepsize = 10.0
|
||||
omny.tomo_type = 1
|
||||
fake_dev = types.SimpleNamespace(
|
||||
omny_samples=types.SimpleNamespace(get_sample_name_in_samplestage=lambda: "test_sample")
|
||||
)
|
||||
monkeypatch.setattr(omny_module, "dev", fake_dev, raising=False)
|
||||
omny.OMNYTools = types.SimpleNamespace(yesno=lambda *a, **k: False)
|
||||
|
||||
# canned answers for: ctime, step, fovx, fovy, stitch_x, stitch_y,
|
||||
# reconstruct_foldername, tomo_type (=3), projections per sub-tomogram
|
||||
# (=10 -> would be an 18 degree step, far above the 2.5 degree cap),
|
||||
# stop-after-projections, repeat-at-0-deg
|
||||
canned = iter([1.0, 0.1, 20, 20, 1, 1, "queue", 3, 10, 0, 0])
|
||||
monkeypatch.setattr(OMNY, "_get_val", staticmethod(lambda *a, **k: next(canned)))
|
||||
|
||||
omny.tomo_parameters()
|
||||
|
||||
assert omny.tomo_type == 3
|
||||
assert omny.tomo_angle_stepsize == pytest.approx(2.5)
|
||||
|
||||
Reference in New Issue
Block a user