Offline Analysis
The Analysis page (sidebar: Records → Analysis) builds graph workflows against the active experiment’s run database and converted ROOT event trees. It does not issue acquisition commands, and it never competes with a run: while a run is going, Run pipeline and Batch convert are disabled and the server answers them with 409. A job that is running when a run starts stops at its next chunk of events with Stopped: a run started; a batch conversion finishes the run it is converting (RUReader cannot be paused) and starts no other. Start with the supplied spectrum/yield graph, or add nodes from the library. Click a node to edit its parameters in the inspector. Drag between compatible ports to connect nodes; select a node or edge and press Delete to remove it. Zoom, pan, fit view, and the minimap work in the graph canvas.
Prepare runs
Open Runs, filter by run number, target or type, and select completed runs.
Use Batch convert to ROOT for runs with
.caendatdata. SIS3316 runs are skipped with SIS3316 runs are HDF5 files; RUReader converts .caendat only, and the run list marks them as not analysable here. It uses the same RUReader conversion manager as the logbook and processes runs serially. Existing ROOT output is preserved. Per-run status and the conversion log remain visible in the batch panel. For advanced converter options or retrying failed conversions, open the run’s logbook conversion tab.Inspect ROOT shows filenames, tree names, event counts and branch names.
Use selected runs fills the selected Load Run(s) node, or the first one if another kind of node is selected. Run lists also accept
10,12-15.
The Runs panel has exact, case-insensitive Target and Run type filters, combined with AND. Use query in Load Run(s) stores those criteria in the node, so each execution queries the current database snapshot for completed runs. The inspector also allows combining the filters with an explicit run list/range (intersection). A query with no matches or more than 100 matches reports an error; it never silently truncates. Use selected runs instead saves a fixed list and clears the node’s query. ROOT conversion is still required for all matching runs. The text search only filters the displayed list, not the saved target/type query.
ROOT files are read from data/run<N>/ in the current experiment. A blank ROOT
filename loads every .root file in that run directory: useful for split
output, but do not put alternative conversions or duplicate files there. Enter
a filename to read only that file. The default tree is Data, falling back to
legacy DataR. Set an explicit tree name if needed. Choose Energy for PHA or
EnergyLong (or EnergyShort) for PSD. Energy branches must contain scalar
values, not waveform arrays. A legacy tree without Board is treated as board
0. ROOT histograms alone are not event-tree inputs in this first version.
Nodes and scientific conventions
Every node supports one run or a list of runs; results retain run-number keys. There is no separate list-only node family. Drag library items onto the canvas to add them.
Node |
Operation |
|---|---|
Load Run(s) |
Select completed runs and ROOT event trees. |
Run Database |
Read the active experiment’s metadata; no external DB path. |
Calibrate Energy |
|
Channel Energy |
Select both board ID and detector channel. Required before ROI/histogram nodes. |
ROI Counts |
Count events strictly inside |
Yield |
|
Beam Energy |
|
Histogram |
One spectrum per run, on shared, explicit bins and energy range. NumPy bin convention: left-inclusive/right-exclusive, final upper edge inclusive. |
Plot Series |
Match X and Y by run number, sort by X, and show Y error bars. Different run sets are rejected. |
Calibrated integer energies. Energy is an integer channel number k, and
the calibration of the Histograms page treats it as the channel’s centre. A
calibrated value is computed from k + u, with u uniform in [−0.5, 0.5): the
event is spread over its channel. Without it, a slope that is not a whole
number of output bins puts one channel in some bins and two in others
(picket-fence artefacts). The generator is seeded per run, file and chunk, so a
workflow gives the same numbers every time and every node sees the same values.
Raw (uncalibrated) energies and floating-point branches are not spread. Choose
ROI bounds as usual; an event within half a channel of a bound can fall either
side of it, as it would in a real spectrum of that resolution. (The other
remedy, output bins aligned to channel boundaries, does not work when runs or
channels have different calibrations but share one histogram.)
Raw ROI uncertainty is Poisson counting statistics. Extracted areas carry their subtraction or fit variance into Yield. Charge uncertainty, dead time, pile-up, and calibration-coefficient uncertainty are not propagated. Efficiencies can include an explicit relative systematic uncertainty.
Spectrum analysis
Histogram provides a spectrum output containing bin edges, counts and variances, while still drawing a chart. Connect it to:
Rebin: merge adjacent bins; the integer factor must divide the bin count. Counts and variances are summed.
Background subtraction: identical bins and independent runs are required. Background runs are summed. Scale by signal elapsed measurement time / summed background time, signal charge / summed background charge, or a manual factor. Net counts are
S − aB; variance isVar(S) + a² Var(B). Negative net bins are retained. Time is the wall-clock run duration (Start Time to Stop Time), not the live time: with different dead time in signal and background runs, use charge or a manual factor. (SIS3316 runs record live time, but they are not analysable here yet.) Exposure errors are not included. A shared background correlates different signal runs.Peak area: integrate bins whose centres are strictly inside the bounds.
Sideband subtraction: subtract a flat continuum from two non-overlapping flanking sidebands, weighted by actual included bin widths. Propagates sideband counting variance; assumes locally flat background.
Peak fit: bin-integrated Gaussian plus linear background. When any bin of the window holds fewer than 20 counts it maximises the Poisson likelihood (minimises the Cash statistic
C = 2 Σ (μ − n + n ln(n/μ))), starting from the least-squares solution; the covariance is the inverse Fisher informationJᵀ diag(1/μ) J, so an absent peak (area at zero) still has a real error (with centroid and width then held fixed). Otherwise, and always for spectra that are no longer plain counts (background-subtracted: variance ≠ counts), it is weighted least squares withsqrt(max(variance, 1))bin errors. Output is the total Gaussian area, not just its part inside the fit window. Summary diagnostics name the method and give centroid, sigma, covariance, residuals andcash_per_doforreduced_chi_square.Calibration fit: a straight line through supplied
[ADC, energy_keV]reference points, with residual plots. Covariance uses residual scatter for more than two points; two-point covariance is unavailable. Reference-point errors are not modelled. Connect to Apply fitted calibration with events.Efficiency correction: divide by a piecewise-linear absolute efficiency curve at the specified peak energy. Rejects extrapolation and nonpositive efficiencies. Relative efficiency uncertainty adds a shared systematic, separately recorded in output.
Ratio / arithmetic: add, subtract, multiply or divide matching run-keyed series. Errors use an explicit correlation coefficient (default independent). Division by zero is rejected. A full cross-run covariance matrix is not propagated for shared backgrounds or efficiency curves.
Peak area, Sideband subtraction and Peak fit provide counts for Yield and values for arithmetic/efficiency. Existing unbinned ROI workflows still work.
In a spectrum chart, select the destination ROI/fit node, then drag across the chart or edit its two bounds. This updates the node and marks results stale; Run pipeline recalculates. Choose a spectrum in the same calibrated energy coordinates as the destination. Sideband bounds remain inspector parameters.
Time analysis and ROOT trees
Inspect ROOT → Use tree sets filename, tree and run on the selected source
(or the first source). Energy/timestamp branches remain editable. The unit of
the Timestamp branch is read from each file: RUReader stores it as the title of
the TimestampUnit object (ps, ns, us, ms, s, or raw, whose tick per
board comes from the Boards object). A file without it is read as ps, and the
result says so in its warnings. A nonzero Timestamp to seconds in Load
Run(s) overrides the file (with a warning when they differ). Event time 0 is the
acquisition start, which is the run’s Start Time to within the time the boards
take to start; Time offset shifts it if needed.
Counting rate over time bins detector-selected ROI events and divides by
actual bin duration, including the final short bin. Zero stop uses run duration.
Load current reads the same runs’ current.txt with an explicit recorded column
such as Ch0(uA) or Current(uA); no physical channel is assumed. Its times
count from the file’s Start time line, written when the current recording
began; they are shifted onto the run’s clock with the run’s Start Time from
metadata.json (run_data.run_window), so current and events share one time
base. When that is not possible the result warns and the log’s time 0 is taken
as the run start. Yield over time divides each bin’s counts by the charge in
the same interval, with the rule used everywhere else in WebDAQ (the Data page,
the run record, RUReader): readings joined by straight lines, a step of more
than 10 s without a reading carries no charge, the first and last readings are
held to the run’s start and stop for at most 10 s, nothing outside the run
counts. The bins of a run add up to its charge. A bin without charge is left
out (with a warning); a bin partly in a gap is kept, its charge leaving the
silent time out, and the result counts such bins. Empty count bins get the
Gehrels error. Current uncertainty is not included. Plot nodes retain run IDs. This analyses recorded runs, not live DAQ.
Richer run queries support ranges, exclusions, flags, start-date bounds and terminal-voltage ranges, combined with AND. Date-only upper bounds include the whole date; timestamp upper bounds are exclusive. Preview matches before applying.
Example workflows
Workflows → Examples contains eight experiment-independent draft templates. A fresh experiment with no saved workflow starts with Spectrum & ROI counts.
Template |
Required inputs beyond converted detector events |
|---|---|
Spectrum & ROI counts |
Measured calibration and chosen energy/ROI ranges; no charge or beam metadata. |
Time-normalised background |
Independent background runs, matching spectrum bins, valid start/end times. Uses elapsed time, not live time. |
Background → peak yield |
Independent background, positive signal/background charge, signal terminal/probe voltages, fit settings. |
Sideband yield scan |
Positive charge, terminal/probe voltages, two sidebands around a locally flat continuum. |
Fit energy calibration |
At least two measured ADC-centroid / known-energy pairs from the same detector settings. |
Counting rate over time |
Event timestamps with known unit/origin and valid run start/end times; no current log needed. |
Rate, current & yield over time |
Rate inputs plus a recorded current column in µA, overlapping time coverage and positive time-bin charge. |
Efficiency & peak ratios |
Two disjoint peak windows, peak energies and measured absolute-efficiency curves; no charge or beam metadata. Gross areas and their ratio appear in Summary. |
All run selections and queries start blank, so no template assumes demo run IDs or automatically analyses existing data. Loading and saving a draft works on an empty installation; executing it requires choosing actual completed runs first. For workflows with two sources, select the intended Load Run(s) node before applying a run selection/query. No acquisition or sample data is created by loading a template.
Expand Setup requirements on each template for its prerequisites. These instructions are also copied into its description when saving a new workflow. Calibrate Energy uses each run’s own calibration; board/channel 0, the 0–2000 keV spectrum and 400–600 keV ROI are explicit starting settings, not measured values. Adjust both paths of a background workflow consistently. Calibration reference points, efficiency curves and the current-log column are deliberately blank. The Timestamp unit comes from the file; verify the time origin. Time stop 0 uses each run’s duration; narrow it to current-log coverage for time yields. Beam Energy uses neutral scale 1 and offset 0 in templates; configure your accelerator’s voltage calibration and ion charge state. Existing saved workflows and their settings are not migrated or overwritten.
The peak-ratio template assumes independent errors by default. Common efficiency systematics can correlate the two corrected areas; set an appropriate correlation or use a fuller covariance treatment before interpreting ratio uncertainties.
Workflows and results
Drag the grip between the library and graph to resize the left panel. Its width is remembered in this browser. A second grip resizes Results: width on wide screens, height when the panel is below the graph. Both sizes are remembered. The focused grips also support arrow keys and Home/End.
Workflows, beside Node library and Runs, lists saved workflows with names
and descriptions. Save workflow creates a named entry or updates the current
one; Save a copy creates a variant. Loading another workflow asks before
replacing unsaved edits. The library is stored atomically in
conf/analysis-workflows.json (up to 50 workflows) of the working directory,
which is the experiment’s directory when the server is started from the page,
so every experiment has its own. A single-workflow
conf/analysis-workflow.json from the first version is read as Previous
workflow and left untouched.
Drafts may have disconnected nodes. Saving is shared by browsers using that
experiment (last save wins). Export workflow JSON for portable backups. Import accepts
LUNAdaq version 1 JSON; prototype NucleoFlow JSON is not directly compatible.
The source reference application is unchanged.
Run pipeline validates ports, required inputs, graph cycles, ranges and parameters before starting a background job. The page remains responsive. It resumes polling an active job after a reload in the same browser tab. Completed results are held in memory (latest ten jobs), so export them before restarting the server. Draft/result changes are indicated separately.
Charts have CSV export; Export results includes numeric results, workflow, source filenames/sizes/modification times, and the run metadata snapshot used. No raw event arrays are sent to the browser. If a source file changes during analysis, the result is rejected. The metadata database is never modified.
Workflows are limited to 50 nodes, 150 edges, 100 runs per source node, 4096 histogram bins per spectrum (one million output bins total), and five minutes of event processing. ROOT input is streamed in 100,000-event chunks. Only one analysis job or batch conversion runs at once; individual logbook conversions remain independent. Jobs/queues are not durable across backend restarts. A failed batch preserves per-run failure information; it does not pretend partially converted output is ready for analysis.
Install and test
environment.yml includes uproot>=5,<6 (scipy was already there); install it
into the luna environment between runs (conda install -n luna -c conda-forge 'uproot>=5,<6'). Without it the server starts as before and the Analysis page
says that uproot is missing. Frontend dependencies include
@xyflow/react. The offline reader does not require a working PyROOT import,
but RUReader still needs its compiled ROOT libraries for conversion.
cd server
TEST_FLAG=True ./tests/run_tests.sh analysis
The tests use temporary data directories, an in-memory metadata DB, and small ROOT files written with uproot. They cover detector selection, calibration, exclusive ROI boundaries, histogram counts, yields/errors, run alignment, invalid graphs, input confinement, authentication and batch conversion orchestration.
Numerical references: SciPy curve_fit and NumPy polyfit.
Editor rendering and layout
On wide screens the editor fills the window below the header (the page uses the layout’s full-height mode); results scroll inside their own panel. At narrower widths the panels stack, with a separately resizable results height. On a phone the panels stack in one column: library and runs, a shorter graph (view and edit parameters by tapping a node), then results. More results never increase that panel’s height. Library nodes show short descriptions and styled help opens on hover after 150 ms or on keyboard focus.
Charts mount only near the visible results area and release their chart DOM when scrolled away. Unchanged results and nodes are memoized so moving nodes does not redraw plots or mark scientific results stale. Current traces render as lines without per-sample markers; nonzero time-bin uncertainties still have error bars. Numeric exports retain every sample. Summary sections render on expansion; raw previews cap arrays at 200 entries and text at 100,000 characters, with a truncation notice and a full-data export.