Input/output

The I/O subsystem is a small registry of format-specific loaders behind a single entry point: asymmetry.core.io.load() infers the format from the file extension and dispatches to the appropriate BaseLoader subclass. The current loaders are NexusLoader (ISIS muon NeXus V1 and V2, including multi-period files, which return a list of MuonDataset), PsiLoader (PSI BIN and MDU raw histograms, with discovery of PSI .mon temperature sidecars), and RootLoader (MusrRoot and LEM ROOT files, including slow-control histograms). The format-specific quirks each loader handles — bin-index conventions, per-detector \(t_0\), deadtime and background metadata — are documented in Loading Data. Custom formats can be added by subclassing BaseLoader and registering it with the LoaderRegistry.

Main interface

asymmetry.core.io.load(filepath: str, fmt: str | None = None, period: int | str | PeriodMode | None = None) MuonDataset | list[MuonDataset][source]

Load a μSR data file and return a MuonDataset.

Parameters:
  • filepath (str) – Path to the data file.

  • fmt (str, optional) – Force a specific format (e.g. "nxs"). If None, the format is auto-detected from the file extension.

  • period (int or str or PeriodMode, optional) – For period-mode (multi-period) files, select a single period and return just that MuonDataset. Accepts a 1-based period number or, for two-period files, a "red"/"green" label. When None (default) the historical behaviour is preserved: single/two-period files return one MuonDataset and 3+ period files a list. See asymmetry.core.io.periods.

Raises:

ValueError – If period is out of range or an unknown label.

Period selection

Period-mode (multi-period) runs — photo-μSR light-OFF/ON, RF on/off, ALC — expose a scriptable selection API in asymmetry.core.io.periods. The same helpers back the GUI red/green (“RG”) selector, so scripts and the desktop app share one implementation. See Selecting periods (Red / Green) for a worked example.

asymmetry.core.io.periods.select_period(data: MuonDataset | list[MuonDataset], period: int | str | PeriodMode) MuonDataset[source]

Return a reduced MuonDataset for a single period.

Parameters:
  • data – A loaded run: either a single MuonDataset (single-period file, or a combined two-period file) or the list returned for 3+ period files.

  • period – Period selector — see resolve_period_index().

Returns:

The requested period with its own time/asymmetry/error and per-period provenance (period_number, run_label, good_frames, dead_time_us). t0, good-bin window, grouping, field and temperature are preserved from the parent run.

Return type:

MuonDataset

Notes

The arrays returned are the loader’s default reduction (alpha = 1.0, no deadtime/background correction), identical to what the loader produces for a single-period file.

asymmetry.core.io.periods.period_count(data: MuonDataset | list[MuonDataset] | Run) int[source]

Return the number of periods reachable from data.

Accepts a loaded MuonDataset, a list of datasets (as returned for 3+ period files), or a Run.

asymmetry.core.io.periods.period_labels(data: MuonDataset | list[MuonDataset] | Run) list[str][source]

Return human-facing labels for each selectable period.

Two-period runs return ["red", "green"]; otherwise the 1-based period numbers as strings.

asymmetry.core.io.periods.resolve_period_index(period: int | str | PeriodMode, count: int) int[source]

Translate a user-supplied period selector to a 0-based index.

period may be a 1-based integer period number, a numeric string, or — when count == 2 — a "red"/"green" label (or PeriodMode member). Raises ValueError for unknown labels or out-of-range numbers and TypeError for unsupported types.

Registry

class asymmetry.core.io.base.LoaderRegistry[source]

Bases: object

Central registry of available file-format loaders.

classmethod register(loader_cls: type[BaseLoader]) None[source]
classmethod get_loader(filepath: str, fmt: str | None = None) BaseLoader[source]
classmethod supported_extensions() list[str][source]
classmethod file_dialog_filter() str[source]

Build a Qt file-dialog filter string from registered loaders.

Returns:

Filter string suitable for QFileDialog, including an aggregate “All Supported Files” entry, one entry per loader format, and a trailing “All files (*)” fallback.

Return type:

str

Loaders

Base loader

class asymmetry.core.io.base.BaseLoader[source]

Bases: ABC

Interface that every file-format loader must implement.

extensions: list[str] = []

File extensions this loader claims (e.g. [".nxs"]).

format_name: str = ''

Short human-readable name (e.g. "ISIS NeXus (.nxs/.nexus)").

abstractmethod load(filepath: str) MuonDataset | list[MuonDataset][source]

Read filepath and return one or more MuonDataset objects.

Most formats return a single dataset. Multi-period NeXus files may return multiple datasets (one per period).

NeXus loader

class asymmetry.core.io.nexus.NexusLoader[source]

Bases: BaseLoader

Read ISIS muon .nxs files and return one or more datasets.

extensions: list[str] = ['.nxs', '.nexus']

File extensions this loader claims (e.g. [".nxs"]).

format_name: str = 'ISIS NeXus (.nxs, .nexus)'

Short human-readable name (e.g. "ISIS NeXus (.nxs/.nexus)").

load(filepath: str) MuonDataset | list[MuonDataset][source]

Load a NeXus file and return reduced asymmetry dataset(s).

Parameters:

filepath – Path to a NeXus file.

Returns:

Single dataset for single-period and two-period files. Files with more than two periods return one dataset per period.

Return type:

MuonDataset or list[MuonDataset]

PSI loader

Loads PSI BIN/MDU raw histogram files using the musrfit-compatible binary metadata interpretation. PSI-BIN .mon temperature sidecars are discovered and parsed using Mantid LoadPSIMuonBin-compatible rules, then exposed as metadata["nexus_time_series"] and in the Get Info metadata tables.

class asymmetry.core.io.psi.PsiLoader[source]

Bases: BaseLoader

Read PSI .bin and .mdu raw histogram files.

extensions: list[str] = ['.bin', '.mdu']

File extensions this loader claims (e.g. [".nxs"]).

format_name: str = 'PSI BIN/MDU (.bin, .mdu)'

Short human-readable name (e.g. "ISIS NeXus (.nxs/.nexus)").

load(filepath: str) MuonDataset[source]

Read filepath and return one or more MuonDataset objects.

Most formats return a single dataset. Multi-period NeXus files may return multiple datasets (one per period).

ROOT loader

Loads MusrRoot/LEM ROOT histograms and header metadata. MusrRoot slow-control histograms under histos/SCAnaModule are exposed through metadata["nexus_time_series"] and Get Info, including sample-temperature logs such as hSampleTemperature.

class asymmetry.core.io.root.RootLoader[source]

Bases: BaseLoader

Read MusrRoot and PSI LEM ROOT files.

extensions: list[str] = ['.root']

File extensions this loader claims (e.g. [".nxs"]).

format_name: str = 'MusrRoot / LEM ROOT (.root)'

Short human-readable name (e.g. "ISIS NeXus (.nxs/.nexus)").

load(filepath: str) MuonDataset[source]

Read filepath and return one or more MuonDataset objects.

Most formats return a single dataset. Multi-period NeXus files may return multiple datasets (one per period).

NeXus writer

Writes synthetic or derived runs (see Synthetic runs and degraded statistics) as loadable ISIS muon NeXus V1 files. Built from the Run alone — any loaded run, PSI and ROOT formats included, can act as the instrument template — with the simulation provenance stored in a /run/simulation group.

Minimal ISIS muon NeXus V1 writer for synthetic and derived runs.

Writes a fresh HDF5 file containing exactly the layout NexusLoader consumes for legacy /run files (see docs/porting/simulate-mode/implementation-options.md for the field table), plus a /run/simulation provenance group that the loader surfaces through metadata["nexus_fields"]. Unlike WiMDA’s template-copy save, the file is built from the Run alone, so any loaded run — PSI .bin/.mdu included — can act as the instrument template, and no stale sample logs leak into the synthetic file.

Notes on the V1 contract (verified against nexus.py):

  • histogram_data_1/time_zero is interpreted as a bin index; writing one value per detector preserves PSI-style staggered t0.

  • The loader treats the two lowest group ids in grouping as forward and backward, so the writer renumbers the run’s forward group to 1 and backward to 2 (further groups follow in stable order).

  • ISIS NeXus V1 has no balance-factor field, so α does not survive a round trip — the generating α is recorded in /run/simulation for reference only, exactly as with real data where α is an analysis-side calibration.

asymmetry.core.io.nexus_writer.write_nexus_v1(run: Run, path: str | Path) None[source]

Write run as a loadable ISIS muon NeXus V1 (HDF5) file.

The file reloads through asymmetry.core.io.load() with identical per-detector counts, bin width, per-detector t0 bins, good-bin window, grouping (forward/backward renumbered to 1/2) and good frames. Raises ValueError for runs without histograms or with ragged histogram lengths, and ImportError when h5py is unavailable.