Grouped time-domain fitting
Grouped time-domain Knight-shift workflow on a synthetic YBa₂Cu₃O₇₋δ
run in the normal state (T = 100 K, B = 200 G). The central plot is in
the Individual Groups domain so the lifetime-corrected counts
N_d(t)·exp(t/τ_μ) for each of the four detectors are shown as separate
subplots (zoomed to the first 1.5 μs so the ~2.72 MHz precession
resolves), and the fit dock has auto-engaged the Multi-Group Fit
window. The grouped fit of the damped-precession polarisation model
cos(2*pi*gamma_mu*field*t + phase) * exp(-Lambda*t) has
completed — the log reports average χ²ᵣ = 0.997 and each subplot
carries its fitted count curve. Per-group N₀, background, amplitude and
phase fit as local nuisance parameters while the field magnitude and
damping are shared — the canonical workflow for extracting the muon
Knight shift in the normal state of a superconductor (Sonier, Rev. Mod.
Phys. 72, 769 (2000)).
Grouped time-domain fitting is the right tool whenever the physically meaningful quantity you are extracting depends on detector geometry, and collapsing the raw counts onto a single forward/backward asymmetry would average that geometry away. The canonical use is a paramagnetic Knight-shift measurement, where a ppm-precision TF frequency shift is recovered by sharing the Larmor frequency across every detector group while letting per-group amplitudes and phases fit locally (Sonier, Rev. Mod. Phys. 72, 769 (2000)). Vortex-state second-moment analyses benefit from the same machinery — per-group \(\sigma\) values expose calibration drifts in the vortex-lattice signal that a single asymmetry would hide — and any time a shared-physics fit returns inconsistent results across groups, the diagnosis is almost always a calibration problem (alpha mismatch, per-detector time-zero drift) rather than a model problem. For ordinary F-B asymmetry fits with no geometry-sensitive observable, the regular single-fit panel is faster and imposes no grouped overhead. For a full worked example on a rotated single crystal, see Angle-dependent Knight shift.
What this mode fits
Grouped time-domain mode works on the detector groups defined in the Grouping dialog for the active dataset. For each included group, Asymmetry builds a lifetime-corrected grouped count trace of the form
where \(\tau_\mu\) is the fixed physical muon lifetime.
The fitted count-domain model is
where:
\(P(t)\) is the shared physical polarisation function from the chosen fit function
\(N_0\) is the group normalisation
\(A\) is the group amplitude scale
\(B\) is the group background term
the optional group
relative_phaseis added onto the modelphaseparameter when the model supports phase
Current GUI workflow
Single-run grouped fit
Open a raw dataset in FB Asymmetry.
Configure detector groups in Grouping.
Select the dataset you want to fit.
In the central workspace, switch to Individual Groups.
Launch Fit — the fit dock switches to the Multi-Group Fit window.
Ensure the Single tab is selected.
Adjust the fit function with Edit Function… if needed.
Configure the two parameter blocks described below.
Click Run Grouped Fit.
The grouped plot view shows stacked lifetime-corrected grouped traces for the
active dataset. Switching back to the FB Asymmetry tab restores the regular
fit dock content. After the fit completes, each subplot receives its fitted
grouped count curve, and the result is saved as a FitSeries entry for
parameter trending.
Multi-run grouped batch fit
Select two or more runs in the Data Browser.
Switch to Individual Groups in the central workspace.
Launch Fit — the Batch tab in the Multi-Group Fit window accepts a multi-run member list fed from the current selection.
Adjust the fit function and classify physics parameters (see below).
Click Run Grouped Fit.
The Batch tab fits each run’s detector groups with the same polarisation model
and records the results as a single FitSeries, making parameter
trending available across the run series. Individual runs’ results can be
piped back to the Single tab for inspection.
The Grouping dialog now includes an Include checkbox per group. Only checked groups appear in the Individual Groups viewer and in grouped time-domain fitting. At least two groups must remain included for grouped plotting and grouped fitting to stay available.
Parameter blocks
The grouped GUI mode separates parameters into two blocks.
Per-group (nuisance) parameters
These nuisance parameters are attached to each detector group and are always estimated independently per (run, group):
N0backgroundamplituderelative_phase
They do not appear in the physics-role table and are not trended.
Physics (fit-function) parameters
These are the parameters of the selected composite polarisation function. Each can be classified as:
Global: one shared value across all runs in the batch (cross-run shared)
Local: one fitted value per run, shared across that run’s detector groups
Fixed: held constant at the table value
A fit is called a global grouped fit when at least one physics parameter carries the Global role; otherwise it is a batch grouped fit (N independent per-run fits recorded together). The relationship is derived automatically from the parameter-role table — there is no separate scope selector.
Note
The engine limit for grouped fits is that physics roles must be homogeneous: all physics parameters must be either all Global or all Local/Fixed for a given fit. Mixed cross-run-global + per-run-local physics is not yet supported and is rejected with a clear error message.
Interaction with existing plot controls
Grouped time-domain mode follows the same GUI data-preparation conventions as the existing fit path where practical:
grouping definitions come from the active dataset’s Grouping payload
detector deadtime correction is applied first when the grouping payload has it enabled
grouped detector traces honour the grouping good-bin limits and bunching factor
the active fit range still decides which part of the active dataset is sent to the grouped fitter
The grouped plot view itself shows the grouped lifetime-corrected traces built from the current grouped analysis dataset, while the grouped fit uses the active fit-range restricted dataset.
Cross-run global fits from the API
Sharing fit-function (physics) parameters across several runs — for example
a global Keren fit that shares \(\Delta\) and \(\nu\) across a set of LF
fields measured at one temperature — is done programmatically with
fit_grouped_series(). This is
the count-domain path: it operates on the raw, lifetime-corrected grouped
counts (Cash/Poisson cost by default), the same
\(N_0[1 + A\,P(t)] + B e^{t/\tau_\mu}\) model documented above — it does
not take .asymmetry arrays.
The relationship argument selects the sharing mode. The valid values are
GROUPED_SERIES_RELATIONSHIPS — ("individual", "batch", "global"):
"individual"/"batch"— one independent grouped fit per run (recorded together for trending)."global"— shares the physics (fit-function) parameters inglobal_paramsacross all runs at once, whilelocal_params(the per-group nuisance parametersN0,background,amplitude,relative_phase) stay free per group.
Build each run’s grouped count traces with
build_grouped_time_domain_groups()
(it returns a list of GroupedTimeDomainGroup objects per dataset), assemble
the members and initial_params maps keyed by a per-run id, then call
fit_grouped_series:
import numpy as np
from asymmetry.core.io import load
from asymmetry.core.fitting import Parameter, ParameterSet
from asymmetry.core.fitting.grouped_time_domain import (
build_grouped_time_domain_groups,
fit_grouped_series,
GROUP_NUISANCE_PARAMS,
)
# Shared physics polarization P(t; ...). First arg is time; the rest are the
# fit-function parameters. The engine wraps it in N0[1 + A·P(t)] + B·e^(t/τ).
def keren(t, Delta, nu):
... # return the Keren polarization for these parameters
# One LF field per run; the key is any per-run id (here the run number).
runs = {44000: load("run_44000.nxs"), 44001: load("run_44001.nxs")}
members = {
run_id: build_grouped_time_domain_groups(ds, t_min=0.1, t_max=8.0)
for run_id, ds in runs.items()
}
def seed():
return ParameterSet([
Parameter("N0", 1000.0, min=0.0),
Parameter("background", 0.0),
Parameter("amplitude", 0.2, min=0.0),
Parameter("relative_phase", 0.0),
Parameter("Delta", 0.3, min=0.0), # physics — shared below
Parameter("nu", 0.5, min=0.0), # physics — shared below
])
initial_params = {
run_id: {group.group_id: seed() for group in groups}
for run_id, groups in members.items()
}
result = fit_grouped_series(
"global",
members,
keren,
global_params=["Delta", "nu"], # shared across ALL runs
local_params=list(GROUP_NUISANCE_PARAMS), # per-group nuisance
initial_params=initial_params,
cost="poisson",
)
print(result.success, result.shared_parameters)
The returned GroupedSeriesFitResult carries the cross-run
shared_parameters plus per-member member_results.
Note
This API shares parameters in the count domain. It fits lifetime-corrected
grouped detector counts with a Cash/Poisson statistic — the statistically
faithful choice for low-count data. To share parameters across several
.asymmetry traces in a single call instead, use the asymmetry-domain
fit_global() (Gaussian weighted least squares);
see Asymmetry-domain global fit (scripting). In the GUI, the asymmetry-domain
shared-parameter workflow is the interactive Global fit wizard.
Current limitations
The Global Fit Wizard is not available in grouped mode.
Physics parameter roles must be homogeneous: all Global or all Local/Fixed. Mixed-role fits (some physics shared cross-run, others per-run) are not yet expressible in the engine.
The grouped plot shows group traces, not detector-by-detector traces.
Detector phase tables and detector quadrature workflows are out of scope.
The count-domain lifetime term is fixed to the physical muon lifetime.
Practical notes
Choose an oscillatory model with a
phaseparameter if you want non-zerorelative_phasevalues to matter.For non-phase models, keep
relative_phaseat zero.If grouped mode reports that no valid grouped traces are available, check the active dataset has raw histograms plus at least two detector groups defined in Grouping.