diff --git a/doc/callbacks/docs_logging_callback.md b/doc/callbacks/docs_logging_callback.md index 057702d4..31ff688f 100644 --- a/doc/callbacks/docs_logging_callback.md +++ b/doc/callbacks/docs_logging_callback.md @@ -1,5 +1,5 @@ # Document Logging Callback -The document logger is a callback that the BlueSky RunEngine subscribes to unconditionally. After receiving each document, if they share the same start document (in the same run) then it will write them to the same file. These logs are stored under `C:/instrument/var/logs/bluesky/raw_documents` and are handled by the log rotation. +The [`document_logger`](ibex_bluesky_core.callbacks.document_logger) is a callback that the BlueSky RunEngine subscribes to unconditionally. After receiving each document, if they share the same start document (in the same run) then it will write them to the same file. These logs are stored under `C:/instrument/var/logs/bluesky/raw_documents` and are handled by the log rotation. Each document is stored in a JSON format so can be both machine and human readable. It is in the format `{"type": name, "document": document}` whereby `name` is the type of the document, e.g start, stop, event, descriptor and the `document` is the [document from BlueSky in JSON format](https://blueskyproject.io/bluesky/main/documents.html). As these files are produced per BlueSky run, these will be useful for debugging. diff --git a/doc/callbacks/file_writing.md b/doc/callbacks/file_writing.md index bbba1be8..83208992 100644 --- a/doc/callbacks/file_writing.md +++ b/doc/callbacks/file_writing.md @@ -1,7 +1,7 @@ # File writing callbacks ## Human readable files -A callback (`HumanReadableFileCallback`) exists to write all documents to a separate human-readable file which contains the specified fields. +A callback ([`HumanReadableFileCallback`](ibex_bluesky_core.callbacks.file_logger.HumanReadableFileCallback)) exists to write all documents to a separate human-readable file which contains the specified fields. This callback will add units and honour precision for each field as well as add some metadata ie. the `uid` of each scan as well as the RB number, which is injected using the {doc}`/preprocessors/rbnumberpp` diff --git a/doc/callbacks/plotting.md b/doc/callbacks/plotting.md index 899e94d0..510391c1 100644 --- a/doc/callbacks/plotting.md +++ b/doc/callbacks/plotting.md @@ -1,12 +1,12 @@ # Plotting Bluesky has good integration with `matplotlib` for data visualization, and data from scans -may be easily plotted using the `LivePlot` callback. +may be easily plotted using the [`LivePlot`](ibex_bluesky_core.callbacks.plotting.LivePlot) callback. `ibex_bluesky_core` provides a thin wrapper over bluesky's default `LivePlot` callback, which ensures that plots are promptly displayed in IBEX. -In order to use the wrapper, import `LivePlot` from `ibex_bluesky_core` rather than +In order to use the wrapper, import [`LivePlot`](ibex_bluesky_core.callbacks.plotting.LivePlot) from [`ibex_bluesky_core`](ibex_bluesky_core) rather than `bluesky` directly: ``` from ibex_bluesky_core.callbacks.plotting import LivePlot @@ -14,13 +14,13 @@ from ibex_bluesky_core.callbacks.plotting import LivePlot ## Configuration -A range of configuration options for `LivePlot` are available - see the +A range of configuration options for [`LivePlot`](ibex_bluesky_core.callbacks.plotting.LivePlot) are available - see the [bluesky `LivePlot` documentation](https://blueskyproject.io/bluesky/main/callbacks.html#bluesky.callbacks.mpl_plotting.LivePlot) for more details about available options. -The `LivePlot` object allows an arbitrary set of matplotlib `Axes` to be passed in, onto +The [`LivePlot`](ibex_bluesky_core.callbacks.plotting.LivePlot) object allows an arbitrary set of matplotlib `Axes` to be passed in, onto which it will plot. This can be used to configure properties which are not directly exposed -on the `LivePlot` object, for example log-scaled axes. +on the [`LivePlot`](ibex_bluesky_core.callbacks.plotting.LivePlot) object, for example log-scaled axes. See the [matplotlib `Axes` documentation](https://matplotlib.org/stable/api/_as_gen/matplotlib.axes.Axes.html) for a full range of options on how to configure an `Axes` object. @@ -50,7 +50,7 @@ See [docs for `call_qt_aware`](../plan_stubs/matplotlib_helpers.md) for a descri `yield from call_qt_aware` rather than calling `matplotlib` functions directly. ``` -By providing a signal name to the `yerr` argument you can pass uncertainties to LivePlot, by not providing anything for this argument means that no errorbars will be drawn. Errorbars are drawn after each point collected, displaying their standard deviation- uncertainty data is collected from Bluesky event documents and errorbars are updated after every new point added. +By providing a signal name to the `yerr` argument you can pass uncertainties to [`LivePlot`](ibex_bluesky_core.callbacks.plotting.LivePlot), by not providing anything for this argument means that no errorbars will be drawn. Errorbars are drawn after each point collected, displaying their standard deviation- uncertainty data is collected from Bluesky event documents and errorbars are updated after every new point added. The `plot_callback` object can then be subscribed to the run engine, using either: - An explicit callback when calling the run engine: `RE(some_plan(), plot_callback)` diff --git a/doc/dev/logging.md b/doc/dev/logging.md index 7a2806bf..8e9d72f1 100644 --- a/doc/dev/logging.md +++ b/doc/dev/logging.md @@ -1,5 +1,5 @@ # Logging -To invoke the `ibex_bluesky_core` logger, create and use a `logger` object in [the standard way](https://docs.python.org/3/library/logging.html): +To invoke the [`ibex_bluesky_core`](ibex_bluesky_core) logger, create and use a `logger` object in [the standard way](https://docs.python.org/3/library/logging.html): ```python import logging diff --git a/doc/devices/blocks.md b/doc/devices/blocks.md index 9788e7cd..6f7ec04c 100644 --- a/doc/devices/blocks.md +++ b/doc/devices/blocks.md @@ -3,7 +3,7 @@ Blocks are one of IBEX's central abstractions, which present a uniform interface to any scientifically interesting PV. -`ibex_bluesky_core` has support for four types of blocks: +[`ibex_bluesky_core`](ibex_bluesky_core) has support for four types of blocks: - Read-only - Read/write - Read/write with setpoint readback @@ -25,7 +25,7 @@ mot: NotConnected: ## Block types -### `block_r` (read-only) +### [`block_r`](ibex_bluesky_core.devices.block.block_r) (read-only) This is a read-only block. It supports `bluesky`'s `Readable` protocol, as well as basic metadata protocols such as `HasName`. @@ -35,10 +35,10 @@ This type of block is usable by: - Plan stubs like `bluesky.plan_stubs.rd()`, which plans may use to get the current value of a block easily for use in the plan. -A `BlockR` object does not implement any logic on read - it simply returns the most recent +A [`BlockR`](ibex_bluesky_core.devices.block.BlockR) object does not implement any logic on read - it simply returns the most recent value of the block. -A simple constructor, `block_r`, is available, which assumes the current instrument's PV +A simple constructor, [`block_r`](ibex_bluesky_core.devices.block.block_r), is available, which assumes the current instrument's PV prefix: ```python @@ -46,9 +46,9 @@ from ibex_bluesky_core.devices.block import block_r readable_block = block_r(float, "my_block_name") ``` -### `block_rw` (read, write) +### [`block_rw`](ibex_bluesky_core.devices.block.block_rw) (read, write) -This is a read-write block. It supports all of the same protocols as `BlockR`, with the +This is a read-write block. It supports all of the same protocols as [`BlockR`](ibex_bluesky_core.devices.block.BlockR), with the addition of the `Movable` protocol. The addition of the movable protocol means that this type of block can be moved by plan @@ -65,7 +65,7 @@ It can also be used as the `Movable` in full plans like `bluesky.plans.scan()`. are not motors, even if the documentation tends to use motors as the examples. ``` -Like `block_r`, a simple constructor is available: +Like [`block_r`](ibex_bluesky_core.devices.block.block_r), a simple constructor is available: ```python from ibex_bluesky_core.devices.block import block_rw, BlockWriteConfig @@ -79,9 +79,9 @@ writable_block = block_rw( ``` -### `block_rw_rbv` (read, write, setpoint readback) +### [`block_rw_rbv`](ibex_bluesky_core.devices.block.block_rw_rbv) (read, write, setpoint readback) -This is a block with full support for reading and writing as per `BlockRw`, but with +This is a block with full support for reading and writing as per [`BlockRw`](ibex_bluesky_core.devices.block.BlockRw), but with the addition of `bluesky`'s `Locatable` protocol, which allows you to read back the current setpoint. Where possible, the setpoint will be read back from hardware. @@ -91,7 +91,7 @@ This object is also more suitable for use in plans which use relative moves - th relative move will be calculated with respect to the setpoint readback from hardware (if available). -Just like `block_rw`, a simple constructor is available: +Just like [`block_rw`](ibex_bluesky_core.devices.block.block_rw), a simple constructor is available: ```python from ibex_bluesky_core.devices.block import block_rw_rbv, BlockWriteConfig @@ -104,7 +104,7 @@ rw_rbv_block = block_rw_rbv( ) ``` -### `block_mot` (motor-specific) +### [`block_mot`](ibex_bluesky_core.devices.block.block_mot) (motor-specific) This represents a block pointing at a motor record. This has support for: - Reading (`Readable`) @@ -123,7 +123,7 @@ the plan is executed against hardware. `Stoppable` means that the motor can be asked to stop by bluesky. Plans may choose to execute a `stop()` on failure, or explicitly during a plan. -A `block_mot` can be made in a similar way to the other block types; however, it does not +A [`block_mot`](ibex_bluesky_core.devices.block.block_mot) can be made in a similar way to the other block types; however, it does not require an explicit type as motors are always of `float` data type: ```python @@ -132,20 +132,20 @@ mot_block = block_mot("motor_block") ``` A motor block does not need an explicit write config: it always waits for the requested motion -to complete. See {py:obj}`ibex_bluesky_core.devices.block.BlockMot` for a detailed mapping of +to complete. See [`BlockMot`](ibex_bluesky_core.devices.block.BlockMot) for a detailed mapping of the usual write-configuration options and how these are instead achieved by a motor block. ## Configuring block write behaviour -`BlockRw` and `BlockRwRbv` both take a `write_config` argument, which can be used to configure +[`BlockRw`](ibex_bluesky_core.devices.block.BlockRw) and [`BlockRwRbv`](ibex_bluesky_core.devices.block.BlockRwRbv) both take a `write_config` argument, which can be used to configure the behaviour on writing to a block, for example tolerances and settle times. -See {py:class}`ibex_bluesky_core.devices.block.BlockWriteConfig` for a detailed +See [`BlockWriteConfig`](ibex_bluesky_core.devices.block.BlockWriteConfig) for a detailed description of all the options which are available. -## Run control +## Run Control -Run control information is available via the `block.run_control` sub-device. +[`RunControl`](ibex_bluesky_core.devices.block.RunControl) information is available via the [`block.RunControl`](ibex_bluesky_core.devices.block.RunControl) sub-device. Both configuring and reading the current status of run control are permitted. diff --git a/doc/devices/dae.md b/doc/devices/dae.md index bdfb8f4c..49e1fcfb 100644 --- a/doc/devices/dae.md +++ b/doc/devices/dae.md @@ -1,20 +1,20 @@ # DAE (Data Acquisition Electronics) -The `SimpleDae` class is designed to be a configurable DAE object, which will cover the +The [`SimpleDae`](ibex_bluesky_core.devices.simpledae.SimpleDae) class is designed to be a configurable DAE object, which will cover the majority of DAE use-cases within bluesky. This class uses several objects to configure its behaviour: -- The `Controller` is responsible for beginning and ending acquisitions. -- The `Waiter` is responsible for waiting for an acquisition to be "complete". -- The `Reducer` is responsible for publishing data from an acquisition that has +- The [`Controller`](ibex_bluesky_core.devices.simpledae.strategies.Controller) is responsible for beginning and ending acquisitions. +- The [`Waiter`](ibex_bluesky_core.devices.simpledae.strategies.Waiter) is responsible for waiting for an acquisition to be "complete". +- The [`Reducer`](ibex_bluesky_core.devices.simpledae.strategies.Reducer) is responsible for publishing data from an acquisition that has just been completed. -This means that `SimpleDae` is generic enough to cope with most typical DAE use-casess, for +This means that [`SimpleDae`](ibex_bluesky_core.devices.simpledae.SimpleDae) is generic enough to cope with most typical DAE use-casess, for example running using either one DAE run per scan point, or one DAE period per scan point. For complex use-cases, particularly those where the DAE may need to start and stop multiple -acquisitions per scan point (e.g. polarization measurements), `SimpleDae` is unlikely to be -suitable; instead the `Dae` class should be subclassed directly to allow for finer control. +acquisitions per scan point (e.g. polarization measurements), [`SimpleDae`](ibex_bluesky_core.devices.simpledae.SimpleDae) is unlikely to be +suitable; instead the [`Dae`](ibex_bluesky_core.devices.dae.dae.Dae) class should be subclassed directly to allow for finer control. ## Example configurations @@ -91,39 +91,39 @@ plan using `yield from bps.mv(dae.number_of_periods, num_points)` before startin ### Start of scan (`stage`) -`SimpleDae` will call `controller.setup()` to allow any pre-scan setup to be done. +[`SimpleDae`](ibex_bluesky_core.devices.simpledae) will call [`controller.setup()`](ibex_bluesky_core.devices.simpledae.strategies.Controller.setup) to allow any pre-scan setup to be done. For example, this is where the period-per-point controller object will begin a DAE run. ### Each scan point (`trigger`) -`SimpleDae` will call: -- `controller.start_counting()` to begin counting for a single scan point. -- `waiter.wait()` to wait for that acquisition to complete -- `controller.stop_counting()` to finish counting for a single scan point. -- `reducer.reduce_data()` to do any necessary post-processing on +[`SimpleDae`](ibex_bluesky_core.devices.simpledae) will call: +- [`controller.start_counting()`](ibex_bluesky_core.devices.simpledae.strategies.Controller.start_counting) to begin counting for a single scan point. +- [`waiter.wait()`](ibex_bluesky_core.devices.simpledae.strategies.Waiter.wait) to wait for that acquisition to complete +- [`controller.stop_counting()`](ibex_bluesky_core.devices.simpledae.strategies.Controller.stop_counting) to finish counting for a single scan point. +- [`reducer.reduce_data()`](ibex_bluesky_core.devices.simpledae.strategies.Reducer.reduce_data) to do any necessary post-processing on the raw DAE data (e.g. normalization) ### Each scan point (`read`) Any signals marked as "interesting" by the controller, reducer or waiter will be published -in the top-level documents published when `read()`ing the `SimpleDae` object. +in the top-level documents published when `read()`ing the [`SimpleDae`](ibex_bluesky_core.devices.simpledae) object. These may correspond to EPICS signals directly from the DAE (e.g. good frames), or may be soft signals derived at runtime (e.g. normalized intensity). -This means that the `SimpleDae` object is suitable for use as a detector in most bluesky +This means that the [`SimpleDae`](ibex_bluesky_core.devices.simpledae) object is suitable for use as a detector in most bluesky plans, and will make an appropriate set of data available in the emitted documents. ### End of scan (`unstage`) -`SimpleDae` will call `controller.teardown()` to allow any post-scan teardown to be done. +[`SimpleDae`](ibex_bluesky_core.devices.simpledae) will call [`controller.teardown()`](ibex_bluesky_core.devices.simpledae.strategies.Controller.teardown) to allow any post-scan teardown to be done. For example, this is where the period-per-point controller object will end a DAE run. ## Controllers -The `Controller` class is responsible for starting and stopping acquisitions, in a generic +The [`Controller`]( ibex_bluesky_core.devices.simpledae.controllers) class is responsible for starting and stopping acquisitions, in a generic way. ### RunPerPointController @@ -133,7 +133,7 @@ either end runs or abort them on completion. This controller causes the following signals to be published by `SimpleDae`: -- `controller.run_number` - The run number into which data was collected. Only published +- [`controller.run_number`](ibex_bluesky_core.devices.simpledae.controllers.RunPerPointController) - The run number into which data was collected. Only published if runs are being saved. ### PeriodPerPointController @@ -159,19 +159,21 @@ def plan(): yield from bp.scan([dae], block, 0, 10, num=num_points) ``` -The controller causes the following signals to be published by `SimpleDae`: +The controller causes the following signals to be published by [`SimpleDae`](ibex_bluesky_core.devices.simpledae) : -- `simpledae.period_num` - the period number into which this scan point was counted. +- [`simpledae.period_num`]( ibex_bluesky_core.devices.simpledae.controllers.PeriodPerPointController) - the period number into which this scan point was counted. ## Reducers -A `Reducer` for a `SimpleDae` is responsible for publishing any data derived from the raw +A [`Reducer`](ibex_bluesky_core.devices.simpledae.reducers) for a [`SimpleDae`](ibex_bluesky_core.devices.simpledae) is responsible for publishing any data derived from the raw DAE signals. For example, normalizing intensities are implemented as a reducer. A reducer may produce any number of reduced signals. ### GoodFramesNormalizer +[`GoodFramesNormalizer`](ibex_bluesky_core.devices.simpledae.reducers.GoodFramesNormalizer) + This normalizer sums a set of user-defined detector spectra, and then divides by the number of good frames. @@ -184,6 +186,8 @@ Published signals: ### PeriodGoodFramesNormalizer +[`PeriodGoodFramesNormalizer`](ibex_bluesky_core.devices.simpledae.reducers.PeriodGoodFramesNormalizer) + Equivalent to the `GoodFramesNormalizer` above, but uses good frames only from the current period. This should be used if a controller which counts into multiple periods is being used. @@ -196,6 +200,8 @@ Published signals: ### DetectorMonitorNormalizer +[`DetectorMonitorNormalizer`](ibex_bluesky_core.devices.simpledae.reducers.MonitorNormalizer) + This normalizer sums a set of user-defined detector spectra, and then divides by the sum of a set of user-defined monitor spectra. @@ -223,7 +229,7 @@ Published signals: Scalar Normalizers (such as PeriodGoodFramesNormalizer, GoodFramesNormalizer) can be passed a summing function which can optionally sum spectra between provided time of flight or wavelength bounds. -{py:obj}`ibex_bluesky_core.devices.simpledae.reducers.PeriodGoodFramesNormalizer` +[`PeriodGoodFramesNormalizer`](ibex_bluesky_core.devices.simpledae.reducers.PeriodGoodFramesNormalizer) Here is an example showing creating a scalar normalizer with time of flight bounds from 15000 to 25000 μs, and summing 2 detectors: @@ -239,7 +245,7 @@ reducer = PeriodGoodFramesNormalizer( ) ``` -{py:obj}`ibex_bluesky_core.devices.simpledae.reducers.tof_bounded_spectra` +[`tof_bounded_spectra`](ibex_bluesky_core.devices.simpledae.reducers.tof_bounded_spectra) Monitor Normalizers, which have both a monitor as well as detector, can be passed a summing function for each of these components independently, e.g. the detector can use time of flight while the monitor uses wavelength. tof_bounded_spectra assumes that all pixels being summed share the same flight-path length. Where two separate instances of tof_bounded_spectra are used, such as in DetectorMonitorNormalizer, these may have different flight path lengths from each other. @@ -261,7 +267,7 @@ reducer = MonitorNormalizer( monitor_summer=tof_bounded_spectra(tof_bounds) ) ``` -{py:obj}`ibex_bluesky_core.devices.simpledae.reducers.wavelength_bounded_spectra` +[`wavelength_bounded_spectra`](ibex_bluesky_core.devices.simpledae.reducers.wavelength_bounded_spectra) - In either case, the bounds are passed as a scipp array, which needs a `dims` attribute, `values` passed @@ -272,7 +278,7 @@ as a list, and `units` (μs/microseconds for time of flight bounding, and angstr ## Waiters -A `waiter` defines an arbitrary strategy for how long to count at each point. +A [`waiter`](ibex_bluesky_core.devices.simpledae.waiters) defines an arbitrary strategy for how long to count at each point. Some waiters may be very simple, such as waiting for a fixed amount of time or for a number of good frames or microamp-hours. However, it is also possible to define much more @@ -280,6 +286,8 @@ sophisticated waiters, for example waiting until sufficient statistics have been ### GoodUahWaiter +[`GoodUahWaiter`](ibex_bluesky_core.devices.simpledae.waiters.GoodUahWaiter) + Waits for a user-specified number of microamp-hours. Published signals: @@ -287,12 +295,16 @@ Published signals: ### GoodFramesWaiter +[`GoodFramesWaiter`](ibex_bluesky_core.devices.simpledae.waiters.GoodFramesWaiter) + Waits for a user-specified number of good frames (in total for the entire run) Published signals: - `simpledae.good_frames` - actual good frames for this run. -### GoodFramesWaiter +### PeriodGoodFramesWaiter + +[`PeriodGoodFramesWaiter`](ibex_bluesky_core.devices.simpledae.waiters.PeriodGoodFramesWaiter) Waits for a user-specified number of good frames (in the current period) @@ -301,6 +313,8 @@ Published signals: ### MEventsWaiter +[`MEventsWaiter`](ibex_bluesky_core.devices.simpledae.waiters.MEventsWaiter) + Waits for a user-specified number of millions of events Published signals: @@ -308,6 +322,8 @@ Published signals: ### TimeWaiter +[`TimeWaiter`](ibex_bluesky_core.devices.simpledae.waiters.TimeWaiter) + Waits for a user-specified time duration, irrespective of DAE state. Does not publish any additional signals. @@ -316,9 +332,9 @@ Does not publish any additional signals. ## `Dae` (base class, advanced) -`Dae` is the principal class in ibex_bluesky_core which exposes configuration settings -and controls from the ISIS data acquisition electronics (DAE). `SimpleDae` derives from -DAE, so all of the signals available on `Dae` are also available on `SimpleDae`. +[`Dae`](ibex_bluesky_core.devices.dae) is the principal class in ibex_bluesky_core which exposes configuration settings +and controls from the ISIS data acquisition electronics (DAE). [`SimpleDae`](ibex_bluesky_core.devices.simpledae) derives from +DAE, so all of the signals available on [`Dae`](ibex_bluesky_core.devices.dae) are also available on [`SimpleDae`](ibex_bluesky_core.devices.simpledae). ```{note} The `Dae` class is not intended to be used directly in scans - it is a low-level class @@ -338,7 +354,7 @@ DAE, so all of the signals available on `Dae` are also available on `SimpleDae`. ### Top-level signals Some DAE parameters, particularly metadata parameters, are exposed as simple signals, -for example `dae.title` or `dae.good_uah`. +for example [`dae.title`](ibex_bluesky_core.devices.dae) or [`dae.good_uah`](ibex_bluesky_core.devices.dae). These signals are directly readable and settable from plans: @@ -353,26 +369,26 @@ def plan(dae: Dae): ### Period-specific signals -For signals which apply to the current period, see `dae.period`, which contains signals -such as `dae.period.good_uah` (the number of good uamp-hours collected in the current period). +For signals which apply to the current period, see [`dae.period`](ibex_bluesky_core.devices.dae.dae_period), which contains signals +such as [`dae.period.good_uah`](ibex_bluesky_core.devices.dae.dae_period) (the number of good uamp-hours collected in the current period). ### Controlling the DAE directly -It is possible to control the DAE directly using the signals provided by `dae.controls`. +It is possible to control the DAE directly using the signals provided by [`dae.controls`](ibex_bluesky_core.devices.dae.dae_controls). The intention is that these signals should be used by higher-level _devices_, rather than being used by plans directly. -For example, beginning a run is possible via `dae.controls.begin_run.trigger()`. +For example, beginning a run is possible via [`dae.controls.begin_run.trigger()`](ibex_bluesky_core.devices.dae.dae_controls). ### Additional begin_run flags Options on `begin` (for example, beginning a run in paused mode) can be specified -using the `dae.controls.begin_run_ex` signal. +using the [`dae.controls.begin_run_ex`](ibex_bluesky_core.devices.dae.dae_controls) signal. Unlike the standard `begin_run` signal, this needs to be `set()` rather than simply -`trigger()`ed, the value on set is a combination of flags from `BeginRunExBits`. +`trigger()`ed, the value on set is a combination of flags from [`BeginRunExBits`](ibex_bluesky_core.devices.dae.dae_controls.BeginRunExBits) . ### DAE Settings @@ -382,11 +398,11 @@ configuration parameters which are available under the "experiment setup" tab in example wiring/detector/spectra tables, tcb settings, or vetos. The classes implemented in this way are: -- `DaeTCBSettings` (`dae.tcb_settings`) +- `DaeTCBSettings` ([`dae.tcb_settings`](ibex_bluesky_core.devices.dae.dae_tcb_settings)) - Parameters which appear under the "time channels" tab in IBEX -- `DaeSettings` (`dae.dae_settings`) +- `DaeSettings` ([`dae.dae_settings`](ibex_bluesky_core.devices.dae.dae_settings)) - Parameters which appear under the "data acquisition" tab in IBEX -- `DaePeriodSettings` (`dae.period_settings`): +- `DaePeriodSettings` ([`dae.period_settings`](ibex_bluesky_core.devices.dae.dae_period_settings)): - Parameters which appear under the "periods" tab in IBEX To read or change these settings from plans, use the associated dataclasses, which are @@ -412,11 +428,11 @@ def plan(dae: Dae): ### DAE Spectra -Raw spectra are provided by the `DaeSpectra` class. Not all spectra are automatically available +Raw spectra are provided by the [`DaeSpectra`](ibex_bluesky_core.devices.dae.dae_spectra) class. Not all spectra are automatically available on the base DAE object - user classes will define the specific set of spectra which they are interested in. -A `DaeSpectrum` object provides 3 arrays: +A [`DaeSpectra`](ibex_bluesky_core.devices.dae.dae_spectra) object provides 3 arrays: - `tof` (x-axis): time of flight. - `counts` (y-axis): number of counts - Suitable for summing counts @@ -425,7 +441,7 @@ A `DaeSpectrum` object provides 3 arrays: - Not suitable for summing counts directly - Gives a continuous plot when plotted against x directly. -The `Dae` base class does not provide any spectra by default. User-level classes should specify +The [`Dae`](ibex_bluesky_core.devices.dae) base class does not provide any spectra by default. User-level classes should specify the set of spectra which they are interested in. @@ -440,4 +456,4 @@ or wavelength bounds. - `monitor_summer` (MonitorNormalizer only): sums counts using pre-existing bounds, or sums using time of flight bounds, or wavelength bounds. -For both options, the default, if none is specified, is to use pre-existing bounds. \ No newline at end of file +For both options, the default, if none is specified, is to use pre-existing bounds. diff --git a/doc/fitting/fitting.md b/doc/fitting/fitting.md index 9a4ce8ef..e6bd4d9a 100644 --- a/doc/fitting/fitting.md +++ b/doc/fitting/fitting.md @@ -1,13 +1,13 @@ # Fitting Callback -Similar to [`LivePlot`](../callbacks/plotting.md), `ibex_bluesky_core` provides a thin wrapper around Bluesky's LiveFit class, enhancing it with additional functionality to better support real-time data fitting. This wrapper not only offers a wide selection of models to fit your data on, but also introduces guess generation for fit parameters. As new data points are acquired, the wrapper refines these guesses dynamically, improving the accuracy of the fit with each additional piece of data, allowing for more efficient and adaptive real-time fitting workflows. +Similar to [`LivePlot`](../callbacks/plotting.md), [`ibex_bluesky_core`](ibex_bluesky_core) provides a thin wrapper around Bluesky's [`LiveFit`](ibex_bluesky_core.callbacks.fitting.LiveFit) class, enhancing it with additional functionality to better support real-time data fitting. This wrapper not only offers a wide selection of models to fit your data on, but also introduces guess generation for fit parameters. As new data points are acquired, the wrapper refines these guesses dynamically, improving the accuracy of the fit with each additional piece of data, allowing for more efficient and adaptive real-time fitting workflows. -In order to use the wrapper, import `LiveFit` from `ibex_bluesky_core` rather than +In order to use the wrapper, import[`LiveFit`](ibex_bluesky_core.callbacks.fitting.LiveFit from [`ibex_bluesky_core`](ibex_bluesky_core) rather than `bluesky` directly: ```py from ibex_bluesky_core.callbacks.fitting import LiveFit ``` -**Note:** that you do not *need* `LivePlot` for `LiveFit` to work but it may be useful to know visaully how well the model fits to the raw data. +**Note:** that you do not *need* [`LivePlot`](ibex_bluesky_core.callbacks.plotting.LivePlot) for [`LiveFit`](ibex_bluesky_core.callbacks.fitting.LiveFit) to work but it may be useful to know visaully how well the model fits to the raw data. ## Configuration @@ -31,9 +31,9 @@ fit_callback = LiveFit(Gaussian.fit(), y="y_signal", x="x_signal", yerr="yerr_si fit_plot_callback = LiveFitPlot(fit_callback, ax=ax, color="r") ``` -**Note:** that the `LiveFit` callback doesn't directly do the plotting, it will return function parameters of the model its trying to fit to; a `LiveFit` object must be passed to `LiveFitPlot` which can then be subscribed to the `RunEngine`. See the [Bluesky Documentation](https://blueskyproject.io/bluesky/main/callbacks.html#livefitplot) for information on the various arguments that can be passed to the `LiveFitPlot` class. +**Note:** that the [`LiveFit`](ibex_bluesky_core.callbacks.fitting.LiveFit) callback doesn't directly do the plotting, it will return function parameters of the model its trying to fit to; a [`LiveFit`](ibex_bluesky_core.callbacks.fitting.LiveFit) object must be passed to `LiveFitPlot` which can then be subscribed to the `RunEngine`. See the [Bluesky Documentation](https://blueskyproject.io/bluesky/main/callbacks.html#livefitplot) for information on the various arguments that can be passed to the `LiveFitPlot` class. -Using the `yerr` argument allows you to pass uncertainties via a signal to LiveFit, so that the "weight" of each point influences the fit produced. By not providing a signal name you choose not to use uncertainties/weighting in the fitting calculation. Each weight is computed as `1/(standard deviation at point)` and is taken into account to determine how much a point affects the overall fit of the data. Same as the rest of `LiveFit`, the fit will be updated after every new point collected now taking into account the weights of each point. Uncertainty data is collected from Bluesky event documents after each new point. +Using the `yerr` argument allows you to pass uncertainties via a signal to LiveFit, so that the "weight" of each point influences the fit produced. By not providing a signal name you choose not to use uncertainties/weighting in the fitting calculation. Each weight is computed as `1/(standard deviation at point)` and is taken into account to determine how much a point affects the overall fit of the data. Same as the rest of [`LiveFit`](ibex_bluesky_core.callbacks.fitting.LiveFit), the fit will be updated after every new point collected now taking into account the weights of each point. Uncertainty data is collected from Bluesky event documents after each new point. The `plot_callback` and `fit_plot_callback` objects can then be subscribed to the `RunEngine`, using the same methods as described in [`LivePlot`](../callbacks/plotting.md). See the following example using `@subs_decorator`: @@ -66,16 +66,16 @@ We support **standard fits** for the following trends in data. See [Standard Fit | Trapezoid | [Trapezoid](./standard_fits.md#trapezoid) | None | | PeakStats (COM) **\*** | - | - -\* Native to Bluesky there is support for `PeakStats` which "computes peak statsitics after a run finishes." See [Bluesky docs](https://blueskyproject.io/bluesky/main/callbacks.html#peakstats) for more information on this. Similar to `LiveFit` and `LiveFitPLot`, `PeakStats` is a callback and must be passed to `PeakStatsPlot` to be plotted on a set of axes, which is subscribed to by the `RunEngine`. +\* Native to Bluesky there is support for `PeakStats` which "computes peak statsitics after a run finishes." See [Bluesky docs](https://blueskyproject.io/bluesky/main/callbacks.html#peakstats) for more information on this. Similar to [`LiveFit`](ibex_bluesky_core.callbacks.fitting.LiveFit) and `LiveFitPLot`, `PeakStats` is a callback and must be passed to `PeakStatsPlot` to be plotted on a set of axes, which is subscribed to by the `RunEngine`. ------- -Each of the above fit classes has a `.fit()` which returns an object of type `FitMethod`. This tells `LiveFit` how to perform fitting on the data. `FitMethod` is defined in `ibex_bluesky_core.callbacks.fitting`. +Each of the above fit classes has a `.fit()` which returns an object of type [`FitMethod`](ibex_bluesky_core.callbacks.fitting.FitMethod). This tells [`LiveFit`](ibex_bluesky_core.callbacks.fitting.LiveFit) how to perform fitting on the data. [`FitMethod`](ibex_bluesky_core.callbacks.fitting.FitMethod) is defined in `ibex_bluesky_core.callbacks.fitting`. There are *two* ways that you can choose how to fit a model to your data: ### Option 1: Use the standard fits -When only using the standard fits provided by `ibex_bluesky_core`, the following syntax can be used, replacing `[FIT]` with your chosen one from `ibex_bluesky_core.callbacks.fitting.fitting_utils`: +When only using the standard fits provided by [`ibex_bluesky_core`](ibex_bluesky_core), the following syntax can be used, replacing `[FIT]` with your chosen one from `ibex_bluesky_core.callbacks.fitting.fitting_utils`: ```py from bluesky.callbacks import LiveFitPlot @@ -87,7 +87,7 @@ lf = LiveFit([FIT].fit(), y="y_signal", x="x_signal", update_every=0.5) # Then subscribe to LiveFitPlot(lf, ...) ``` -The `[FIT].fit()` function will pass the `FitMethod` object straight to the `LiveFit` class. +The `[FIT].fit()` function will pass the [`FitMethod`](ibex_bluesky_core.callbacks.fitting.FitMethod) object straight to the [`LiveFit`](ibex_bluesky_core.callbacks.fitting.LiveFit) class. **Note:** that for the fits in the above table that require parameters, you will need to pass value(s) to their `.fit` method. For example Polynomial fitting: @@ -98,7 +98,7 @@ lf = LiveFit(Polynomial.fit(3), y="y_signal", x="x_signal", update_every=0.5) ### Option 2: Use custom fits -If you wish, you can define your own non-standard `FitMethod` object. The `FitMethod` class takes two function arguments as follows: +If you wish, you can define your own non-standard [`FitMethod`](ibex_bluesky_core.callbacks.fitting.FitMethod) object. The [`FitMethod`](ibex_bluesky_core.callbacks.fitting.FitMethod) class takes two function arguments as follows: - `model` - A function representing the behaviour of the model. diff --git a/doc/fitting/livefit_logger.md b/doc/fitting/livefit_logger.md index d92aff5b..3dbeb293 100644 --- a/doc/fitting/livefit_logger.md +++ b/doc/fitting/livefit_logger.md @@ -1,7 +1,7 @@ # Fitting Files Callback ## Fitting Files -The callback ({py:obj}`ibex_bluesky_core.callbacks.fitting.livefit_logger.LiveFitLogger`) exists to write all fitting metrics from `LiveFit` to file. These are designed to be human readable files rather than machine readable. +The callback ([`LiveFitLogger`](ibex_bluesky_core.callbacks.fitting.livefit_logger)) exists to write all fitting metrics from [`LiveFit`](ibex_bluesky_core.callbacks.fitting.LiveFit) to file. These are designed to be human readable files rather than machine readable. This callback provides you with useful metrics such as `R-squared` and `chi-square`, then providing you with a table of the raw collected data included modelled `y` data and `y` uncertainty. @@ -32,4 +32,4 @@ def some_plan() -> Generator[Msg, None, None]: This will put the all fitting data collected over the run into a `.csv` file, named after the `uid` of the scan, in the `C:\\Instrument\\Var\\logs\\bluesky\\fitting` path provided to the callback. You should provide a `postfix` to append to the end of the filename to disambiguate different fits and to avoid overwriting fitting files- it is only one file per fit completed. -If you provide a signal name for the `yerr` argument then an extra column for `y uncertainty` will be displayed in the fitting file. You have the option to not provide anything for this argument if you do not want to have uncertainty information in your fitting file. Keep in mind that even if you provide `yerr` in `LiveFitLogger`, you will still need to provide `yerr` in `LiveFit` if you want uncertainty/weight per point to influence the fit. +If you provide a signal name for the `yerr` argument then an extra column for `y uncertainty` will be displayed in the fitting file. You have the option to not provide anything for this argument if you do not want to have uncertainty information in your fitting file. Keep in mind that even if you provide `yerr` in [`LiveFitLogger`](ibex_bluesky_core.callbacks.fitting.livefit_logger), you will still need to provide `yerr` in [`LiveFit`](ibex_bluesky_core.callbacks.fitting.LiveFit) if you want uncertainty/weight per point to influence the fit. diff --git a/doc/fitting/standard_fits.md b/doc/fitting/standard_fits.md index 3ea4530a..4009e887 100644 --- a/doc/fitting/standard_fits.md +++ b/doc/fitting/standard_fits.md @@ -2,6 +2,8 @@ ## Linear +API Reference: [`Linear`](ibex_bluesky_core.callbacks.fitting.fitting_utils.Linear) + - `c1` - Gradient - `c0` - (y) Intercept @@ -11,6 +13,8 @@ y = c_1x + c_0 ## Polynomial +API Reference: [`Polynomial`](ibex_bluesky_core.callbacks.fitting.fitting_utils.Polynomial) + - `cn` ... `c0` - Polynomial coefficients For a polynomial degree `n`: @@ -20,6 +24,8 @@ y = c_{n}x^n + c_{n-1}x^n-1 + ... + c_1 * x^1 + c_0 ## Gaussian +API Reference: [`Gaussian`](ibex_bluesky_core.callbacks.fitting.fitting_utils.Gaussian) + - `amp` - The maximum height of the Gaussian above `background` - `sigma` - A scalar for Gaussian width - `x0` - The centre (x) of the Gaussian @@ -33,6 +39,8 @@ y = \text{amp} * e^{-\frac{(x - x0) ^ 2}{2 * \text{sigma}^2}} + \text{background ## Lorentzian +API Reference: [`Lorentzian`](ibex_bluesky_core.callbacks.fitting.fitting_utils.Lorentzian) + - `amp` - The maximum height of the Lorentzian above `background` - `sigma` - A scalar for Lorentzian width - `center` - The centre (x) of the Lorentzian @@ -46,6 +54,8 @@ y = \frac{\text{amp}}{1 + \frac{x - \text{center}}{\text{sigma}}^2} + \text{back ## Damped Oscillator (DampedOsc) +API Reference: [`DampedOsc`](ibex_bluesky_core.callbacks.fitting.fitting_utils.DampedOsc) + - `center` - The centre (x) of the oscillation - `amp` - The maximum height of the curve above 0 - `freq` - The frequency of the oscillation @@ -59,6 +69,8 @@ y = \text{amp} * \cos((x - \text{center}) * \text{freq}) * e^{-\frac{x - \text{c ## Slit Scan (SlitScan) +API Reference: [`SlitScan`](ibex_bluesky_core.callbacks.fitting.fitting_utils.SlitScan) + - `background` $b$ - The minimum value (y) of the model - `inflection0` $i_0$ - The x coord of the first inflection point - `gradient` $g$ - The gradient of the sloped-linear section of the model @@ -81,6 +93,8 @@ y = \min(\text{lin_seg}, \text{exp_seg}) ## Error Function (ERF) +API Reference: [`ERF`](ibex_bluesky_core.callbacks.fitting.fitting_utils.ERF) + - `cen` - The centre (x) of the model - `stretch` - A horizontal stretch factor for the model - `scale` - A vertical stretch factor for the model @@ -94,6 +108,8 @@ y = background + scale * erf(stretch * (x - cen)) ## Complementary Error Function (ERFC) +API Reference: [`ERFC`](ibex_bluesky_core.callbacks.fitting.fitting_utils.ERFC) + - `cen` - The centre (x) of the model - `stretch` - A horizontal stretch factor for the model - `scale` - A vertical stretch factor for the model @@ -107,6 +123,8 @@ y = background + scale * erfc(stretch * (x - cen)) ## Top Hat (TopHat) +API Reference: [`TopHat`](ibex_bluesky_core.callbacks.fitting.fitting_utils.TopHat) + - `cen` - The centre (x) of the model - `width` - How wide the 'hat' is - `height` - The maximum height of the model above `background` @@ -124,6 +142,8 @@ y = ## Trapezoid +API Reference: [`Trapezoid`](ibex_bluesky_core.callbacks.fitting.fitting_utils.Trapezoid) + - `cen` - The centre (x) of the model - `gradient` - How steep the edges of the trapezoid are - `height` - The maximum height of the model above `background` diff --git a/doc/plan_stubs/external_code.md b/doc/plan_stubs/external_code.md index e5e20315..745400e9 100644 --- a/doc/plan_stubs/external_code.md +++ b/doc/plan_stubs/external_code.md @@ -1,6 +1,6 @@ # `call_sync` (calling external code) -API reference: {py:obj}`ibex_bluesky_core.plan_stubs.call_sync` +API reference: [`call_sync`](ibex_bluesky_core.plan_stubs.call_sync) All interaction with the "outside world" should be via bluesky messages, and **not** directly called from within a plan. For example, the following is **bad**: @@ -44,7 +44,7 @@ def good_plan(): ``` However, if the functionality you want to use is not yet natively available in bluesky, a fallback option -for synchronous functions is available using the `call_sync` plan stub: +for synchronous functions is available using the [`call_sync`](ibex_bluesky_core.plan_stubs.call_sync) plan stub: ```python import bluesky.plan_stubs as bps diff --git a/doc/plan_stubs/matplotlib_helpers.md b/doc/plan_stubs/matplotlib_helpers.md index 74d66b1f..1eb5845f 100644 --- a/doc/plan_stubs/matplotlib_helpers.md +++ b/doc/plan_stubs/matplotlib_helpers.md @@ -1,4 +1,4 @@ -# `call_qt_aware` (matplotlib helpers) +# [`call_qt_aware`](ibex_bluesky_core.plan_stubs.call_qt_aware) (matplotlib helpers) When attempting to use `matplotlib` UI functions directly in a plan, and running `matplotlib` using a `Qt` backend (e.g. in a standalone shell outside IBEX), you may see a hang or an error of the form: @@ -11,7 +11,7 @@ UserWarning: Starting a Matplotlib GUI outside of the main thread will likely fa This is because the `RunEngine` runs plans in a worker thread, not in the main thread, which then requires special handling when calling functions that will update a UI. -The {py:obj}`ibex_bluesky_core.plan_stubs.call_qt_aware` plan stub can call `matplotlib` functions in a +The [`call_qt_aware`](ibex_bluesky_core.plan_stubs.call_qt_aware) plan stub can call `matplotlib` functions in a Qt-aware context, which allows them to be run directly from a plan. It allows the same arguments and keyword-arguments as the underlying matplotlib function it is passed. diff --git a/doc/tutorial/overview.md b/doc/tutorial/overview.md index e4110395..f60c6325 100644 --- a/doc/tutorial/overview.md +++ b/doc/tutorial/overview.md @@ -1,6 +1,6 @@ # Getting started -`ibex_bluesky_core` is a library which bridges the +[`ibex_bluesky_core`](ibex_bluesky_core) is a library which bridges the [IBEX control system](https://github.com/ISISComputingGroup/ibex_user_manual/wiki/What-Is-IBEX) and the [bluesky data acquisition framework](https://blueskyproject.io/). @@ -44,7 +44,7 @@ def plan(): ## Devices -`ibex_bluesky_core` provides built-in support for a number of ISIS-specific devices. For example, +[`ibex_bluesky_core`](ibex_bluesky_core) provides built-in support for a number of ISIS-specific devices. For example, blocks are available as devices: ```python @@ -55,7 +55,7 @@ det = block_r(float, "p5") # A readback block with float datatype ``` Block objects provide several mechanisms for configuring write behaviour - see -{py:obj}`ibex_bluesky_core.devices.block.BlockWriteConfig` for detailed options. +[`BlockWriteConfig`](ibex_bluesky_core.devices.block.BlockWriteConfig) for detailed options. Likewise, the DAE is available as a bluesky device: see [the DAE Documentation](../devices/dae.md) for full examples including example configurations. @@ -112,7 +112,7 @@ For details about plans which are available directly from `bluesky` - like `bp.s ## The `RunEngine` -The `RunEngine` is the central "conductor" in bluesky - it is responsible for reading a plan and +The [`RunEngine`](ibex_bluesky_core.run_engine) is the central "conductor" in bluesky - it is responsible for reading a plan and performing the associated actions on the hardware. To get a run engine instance, use: ```python @@ -124,18 +124,18 @@ RE = get_run_engine() In the IBEX GUI, manually getting a runengine is unnecessary - it is done automatically. ``` -Then execute a plan using the RunEngine: +Then execute a plan using the [`RunEngine`](ibex_bluesky_core.run_engine): ``` RE(my_plan("det", "mot", 0, 10, 5)) ``` -Noth that typing `my_plan("det", "mot", 0, 10, 5)` does not do anything by itself. +Note that typing `my_plan("det", "mot", 0, 10, 5)` does not do anything by itself. That is because `my_plan` is a python generator - which does nothing until iterated. -To actually execute the plan, it must be passed to the `RunEngine`, which is conventionally +To actually execute the plan, it must be passed to the [`RunEngine`](ibex_bluesky_core.run_engine), which is conventionally called `RE`. -For more detail about the RunEngine, see: +For more detail about the [`RunEngine`](ibex_bluesky_core.run_engine), see: - [bluesky RunEngine docs](https://blueskyproject.io/bluesky/main/tutorial.html#the-runengine) - [bluesky RunEngine API docs](https://blueskyproject.io/bluesky/main/run_engine_api.html) @@ -179,7 +179,7 @@ def my_plan(det_block_name: str, mot_block_name: str, start: float, stop: float, yield from _inner() ``` -The above will show a `LiveTable` by default, any time `my_plan` is executed. The same mechanism can +The above will show a `LiveTable`[`ibex_bluesky_core`](ibex_bluesky_core) by default, any time `my_plan` is executed. The same mechanism can be used for example to always configure a particular scan with plots and a fit with a specific type. As this is fairly common functionality for most plans, we have created a "standard callbacks" collection which should suit the needs of most plans. This includes the ability to fit, plot, add human-readable file output and show a live table of scanned fields. See {py:obj}`ibex_bluesky_core.callbacks.ISISCallbacks` for API reference on how to use this. @@ -205,4 +205,4 @@ runnable example plans) **External documentation** - [bluesky](https://blueskyproject.io/bluesky) -- [ophyd-async](https://blueskyproject.io/ophyd-async) \ No newline at end of file +- [ophyd-async](https://blueskyproject.io/ophyd-async)