FitResult is a new Drawable in damaris.data with x-values independent of
the measured points, so fits can be sampled on a dense grid. It is stored
as its own data pool entry (e.g. "measurement/fit"), written to and read
from the HDF5 data pool (damaris_type "FitResult", params as attributes),
and drawn by the GUI as overlay on its measurement, including a fit
parameter text box. Fits get no entry in the display tree, so measurement
rows stay directly selectable. Result scripts create them via
FitResult(x, y, title, source, params).
Additionally, HDF5 files that experiment or result scripts left open
(e.g. after a script failure) are closed when the experiment stops.
pytables keeps such handles registered process-wide, which blocked
reopening the dump file and the scripts' own files on the next run.
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
Establish one invariant across the Drawable hierarchy: x is always a
numpy ndarray, y is always a list of per-channel ndarrays, and empty
data is the same types with zero length.
- Drawable: x starts as empty ndarray; min/max helpers return 0 on
empty data instead of raising; drop contradictory isinstance(self.y,
list) branches
- ADC_Result/Accumulation: empty constructors build ndarray x; full
constructors coerce x/y/y_square with numpy.asarray; Accumulation
get_ydata/get_yerr return empty ndarrays and no longer crash on
empty statistics-less accumulations
- MeasurementResult: fix get_lineplotdata to return the accumulated
means (previously the never-populated self.y, so the GUI line plot
could never draw); remove dead float/int branches in CSV and HDF
writers
- Error_Result: get_xdata/get_ydata return ndarrays
Add unittest coverage for the invariant, empty-state accessors,
constructor coercion, line plot data, CSV output and HDF round-trip.
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
time_period is list[datetime] | None at runtime (None from old-format
HDF5 files, [] from the constructor), but several sites subscripted
it unguarded and crashed with TypeError/IndexError.
- annotate time_period as list[datetime.datetime] | None
- copy paths (get_accu_by_index, __iadd__ self-empty) use the guarded
pattern already present in _copy_provenance
- merges in __add__/__iadd__ only combine min/max when both sides carry
time information; otherwise the result is None (provenance unknown)
- write_to_tecmag raises ValueError when no time information is
available instead of crashing while writing the header
Clears all remaining time_period pyrefly errors (72 -> 63). Unit tests
reproduce the crashes and pass with the fix.
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
Accumulation.__neg__ passed y_2 = numpy.array(self.y_square), storing a
2D ndarray. A later __iadd__ on an accumulation with ndarray y_square
crashed with AttributeError at the y_square.append sites (992, 1064).
- __neg__ now passes a per-channel copy (values unchanged: sums of
squares are invariant under negation)
- __init__ normalizes ndarray y_2 to a list, so external callers cannot
reintroduce the bug
- y_square annotated as _YChannels
Clears the remaining pyrefly errors at Accumulation.py:992 and :1064
(74 -> 72). Unit tests reproduce both crashes and pass with the fix.
Generated by Mistral Vibe.
Co-Authored-By: Mistral Vibe <vibe@mistral.ai>
- raise instead of silent None for unsupported operands and empty negation
- validate before acquiring lock in Accumulation operators (no RLock leak)
- Accumulation._copy_provenance helper, ADC_Result._copy_metadata for all result paths
- shared _sandbox_stdout_redirect contextmanager for sandboxed scripts
- TemperatureMonitor dead code removal (gtk helper, traceback, unused properties)
- new unit tests incl. lock-freedom regression test
- gitignore sphinx generated doc/_autosummary/ and doc/damaris/
phase() overwrote the underlying channel arrays (y[i] *= -1) and returned
self, so rotated copies aliased the original object and negative phase
angles garbled shared data. It now returns a copy with new arrays and
uses numpy.deg2rad for arbitrary angles.
Add unittests for phase() including negative angles and non-mutation.
operations in the experiments.
- Identified and fixed multiple logic and syntax errors in the `Accumulation` class similar to those recently found in `ADC_Result`.
- Implemented missing arithmetic operators (`*`, `/`, `//`) and their inplace/reverse counterparts for the `Accumulation` class.
- Verified that all arithmetic operations correctly maintain statistical data (sum of squares) where mathematically possible.