ibex_bluesky_core.devices.muon

Muon specific bluesky device helpers.

Members

MuonAsymmetryReducer

DAE reducer which exposes a fitted asymmetry quantity.

damped_oscillator

Equation for a damped oscillator with an offset, as a function of time \(t\).

double_damped_oscillator

Equation for two damped oscillators with an offset, as a function of time \(t\).

class ibex_bluesky_core.devices.muon.MuonAsymmetryReducer(*, prefix: str, forward_detectors: ndarray[tuple[Any, ...], dtype[int32]], backward_detectors: ndarray[tuple[Any, ...], dtype[int32]], alpha: float = 1.0, time_bin_edges: Variable | None = None, model: Model, fit_parameters: Parameters)[source]

Bases: Reducer, StandardReadable

DAE reducer which exposes a fitted asymmetry quantity.

This reducer takes two lists of detectors; a forward scattering set of detectors, \(F\), and a backward scattering set, \(B\).

The spin-asymmetry is computed with:

\[a = \frac{F - \alpha B}{F + \alpha B}\]

Where \(\alpha\) is a user-specified scalar constant, \(F\) is an array of total forward-scattering detector counts against time, and \(B\) is an array of backward-scattering detector counts against time. This results in an array of asymmetry (\(a\)) against time.

Finally, the array of asymmetry (\(a\)) against time (\(t\), in nanoseconds) is fitted using a user-specified model - for example, one of the two models below (which are implemented by damped_oscillator and double_damped_oscillator).

\[ \begin{align}\begin{aligned}a = B + A_0 cos({ω_0} {t} + {φ_0}) e^{-λ_0 t}\\a = B + A_0 cos({ω_0} {t} + {φ_0}) e^{-λ_0 t} + A_1 cos({ω_1} {t} + {φ_1}) e^{-λ_1 t}\end{aligned}\end{align} \]

The resulting fit parameters, along with their uncertainties, are exposed as signals from this reducer. For example, for a model like:

def my_model(t, m, c):
    return m * t + c

model = lmfit.Model(my_model)

The exposed signals will include m, m_err, c, and c_err.

Note

The independent variable must be called t (time).

An example setup showing how to fit a linear model to asymmetry using this reducer is:

def linear(t, m, c):
    return m * t + c

# lmfit Parameters describing initial guesses and fitting constraints
parameters = lmfit.Parameters()
parameters.add("m", 0)
parameters.add("c", 0, min=0, max=1000)

controller = RunPerPointController(save_run=True)
waiter = PeriodGoodFramesWaiter(500)
reducer = MuonAsymmetryReducer(
    prefix=prefix,
    # Selects spectra 1-4 for forwards-scattering, spectra 5-8 for backwards-scattering
    forward_detectors=np.array([1, 2, 3, 4]),
    backward_detectors=np.array([5, 6, 7, 8]),
    # Optional: rebin the muon data to these time bins before fitting.
    time_bin_edges=sc.linspace(
        start=0, stop=200, num=100, unit=sc.units.ns, dtype="float64", dim="tof"
    ),
    # Scalar multiplier applied to backwards detectors in asymmetry calculation.
    alpha=1.0,
    model=lmfit.Model(linear),
    fit_parameters=parameters,
)

dae = SimpleDae(
    prefix=prefix,
    controller=controller,
    waiter=waiter,
    reducer=reducer,
)

Create a new Muon asymmetry reducer.

Parameters:
  • prefix – PV prefix for the SimpleDae.

  • forward_detectors – numpy array of detector spectra to select for forward-scattering. For example, np.array([1, 2, 3]) selects spectra 1-3 inclusive. All detectors in this list are assumed to have the same time channel boundaries.

  • backward_detectors – numpy array of detector spectra to select for backward-scattering.

  • alpha – Scaling factor used in asymmetry calculation, applied to backward detector counts. Defaults to 1.

  • time_bin_edges – Optional scipp Variable describing bin-edges for rebinning the data before fitting. This must be bin edge coordinates, aligned along a scipp dimension label of “tof”, have a unit of time, for example nanoseconds, and must be strictly ascending. Use None to not apply any rebinning to the data.

  • modellmfit.model.Model object describing the model to fit to the muon data. The independent variable must be \(t\) (time, in nanoseconds).

  • fit_parameterslmfit.parameter.Parameters object describing the initial parameters (and contraints) for each fit parameter.

additional_readable_signals(dae: Dae) list[Device][source]

Publish interesting signals derived or used by this reducer.

async reduce_data(dae: Dae) None[source]

Fitting asymmetry to a set of DAE data.

ibex_bluesky_core.devices.muon.damped_oscillator(t: ndarray[tuple[Any, ...], dtype[floating]], B: float, A_0: float, omega_0: float, phi_0: float, lambda_0: float) ndarray[tuple[Any, ...], dtype[floating]][source]

Equation for a damped oscillator with an offset, as a function of time \(t\).

\[B + A_0 \cos(\omega_0 t + \phi_0) e^{-\lambda_0 t}\]
ibex_bluesky_core.devices.muon.double_damped_oscillator(t: ndarray[tuple[Any, ...], dtype[floating]], B: float, A_0: float, omega_0: float, phi_0: float, lambda_0: float, A_1: float, omega_1: float, phi_1: float, lambda_1: float) ndarray[tuple[Any, ...], dtype[floating]][source]

Equation for two damped oscillators with an offset, as a function of time \(t\).

\[B + A_0 \cos(\omega_0 t + \phi_0) e^{-\lambda_0 t} + A_1 \cos(\omega_1 t + \phi_1) e^{-\lambda_1 t}\]