id4_common.utils.experiment_utils#
Experiment session setup.
Public API#
Module Contents#
- id4_common.utils.experiment_utils.logger#
- id4_common.utils.experiment_utils.PERSIST_FILENAME = '.polar_experiment.yml'#
- id4_common.utils.experiment_utils.RESET_SCAN_ID_NOOP = -1#
- class id4_common.utils.experiment_utils.ExperimentClass(*, prompt: Callable[[str], str] = input, printer: Callable[Ellipsis, None] = print)#
Drives interactive experiment setup, server/path resolution, and optional Data Management (DM) integration.
The class accepts
promptandprintercallables so it can be driven deterministically from tests; the module-level singletonexperimentusesinput()andprint().- base_experiment_path#
Server root + run + experiment_name.
- Type:
Path | None
- windows_base_experiment_path#
Windows-mounted equivalent (only set when running on dserv).
- Type:
Path | None
- start_daq#
If True,
setup_dm_daqwill start the DAQ. Off by default because the DAQ start changes file permissions and can prevent new files being written (TODO 2025-07-15).- Type:
- base_experiment_path: pathlib.Path | None = None#
- windows_base_experiment_path: pathlib.Path | None = None#
- dm_experiment = None#
- property experiment_path: pathlib.Path#
base_experiment_path / sample.- Type:
Linux-side experiment folder
- property windows_experiment_path: pathlib.Path | None#
Windows-mounted experiment folder, or None when DM owns the data.
- esaf_input(esaf_id: int | str | None = None) None#
Resolve the ESAF; accepts
"dev"to skip DM lookup.
- proposal_input(proposal_id: int | str | None = None) None#
Resolve the proposal; accepts
"dev"to skip DM lookup.
- experiment_name_input(experiment_name: str | None = None) None#
Set (or prompt for) the DM experiment name.
- scan_number_input(reset_scan_id: int | None = RESET_SCAN_ID_NOOP) None#
Set
RE.md["scan_id"]to the last completed scan number.Semantics: -
reset_scan_idis a non-negative int → write that value.Next scan = value + 1.
-1(default sentinel) → leaveRE.md["scan_id"]alone. Used byload_from_bluesky.None→ interactive prompt (defaultno).any other int → log a warning and leave it alone.
- dm_experiment_setup(experiment_name: str) bool#
Configure (or look up + reuse) the DM experiment.
Returns False if the user wants to pick a different name. On any DM error, demotes to
server="dserv"and returns True so the caller continues without DM.
- setup_dm_daq() None#
Optionally start the DM voyager DAQ for this experiment.
Disabled by default (
start_daq=False) because starting the DAQ changes file permissions and prevents new files being written (TODO 2025-07-15). Enable per-class instance viaexperiment.start_daq = True.Wrapped in try/except so a transient DM failure here does not abort the whole setup — we log a warning and demote to no-DM mode.
- save_params_to_yaml() None#
Write a minimal snapshot of current state to the experiment dir.
Best-effort — any write error is logged and swallowed so failure here never aborts a setup.
- load_params_from_yaml(path: str | pathlib.Path) dict | None#
Load a previously-saved snapshot. Returns the parsed dict or None.
- resume(path: str | pathlib.Path | None = None) None#
Restore an experiment after a Bluesky restart.
With no
path, restores singleton state fromRE.md(the PersistentDict bluesky already loaded at startup). With an explicitpath, loads the snapshot YAML at that location and populates both singleton state andRE.mdfrom it.Does NOT contact DM either way.
- load_from_bluesky(scan_id: int = -1, reset_scan_id: int = RESET_SCAN_ID_NOOP, useRE: bool = False) None#
Restore experiment state from a previous Bluesky run document.
- setup(esaf_id: int | str | None = None, proposal_id: int | str | None = None, base_name: str | None = None, sample: str | None = None, server: str | None = None, experiment_name: str | None = None, reset_scan_id: int | None = RESET_SCAN_ID_NOOP) None#
Run the full experiment setup.
DM availability is auto-detected. When DM is unreachable, the ESAF/proposal prompts are skipped,
serveris forced to"dserv", and metadata is stamped as"dev". To force bypass even when DM is up, passserver="dserv"or useesaf_id="dev"/proposal_id="dev".
- id4_common.utils.experiment_utils.experiment#
- id4_common.utils.experiment_utils.experiment_setup(esaf_id: int | str | None = None, proposal_id: int | str | None = None, base_name: str | None = None, sample: str | None = None, server: str | None = None, experiment_name: str | None = None, reset_scan_id: int | None = RESET_SCAN_ID_NOOP) None#
Run the full experiment setup (delegates to
experiment.setup).
- id4_common.utils.experiment_utils.experiment_change_sample(sample_name: str | None = None, base_name: str | None = None, reset_scan_id: int | None = RESET_SCAN_ID_NOOP) None#
Switch sample (delegates to
experiment.change_sample).
- id4_common.utils.experiment_utils.experiment_load_from_scan(scan_id: int = -1, reset_scan_id: int = RESET_SCAN_ID_NOOP) None#
Restore experiment state from a previous Bluesky run.
- id4_common.utils.experiment_utils.experiment_resume(path: str | pathlib.Path | None = None) None#
Restore experiment state after a Bluesky restart.
With no argument, restores from
RE.md(the PersistentDict bluesky already loaded at startup). With an explicitpath, loads the YAML snapshot at that location instead.