From 6876badb3e3fdbcc83b8283f48e55927eb02c406 Mon Sep 17 00:00:00 2001 From: "t.latour" Date: Tue, 29 Apr 2025 10:06:55 +0200 Subject: [PATCH 1/4] Improve `DWData` type hints --- detl/core.py | 161 ++++++++++++++++++++++++++------------------------- 1 file changed, 81 insertions(+), 80 deletions(-) diff --git a/detl/core.py b/detl/core.py index 71f7a42..6744163 100644 --- a/detl/core.py +++ b/detl/core.py @@ -2,6 +2,7 @@ import abc import enum import pathlib +from typing import Dict import numpy import pandas @@ -12,7 +13,86 @@ class DASwareVersion(enum.Enum): V5 = "v5" -class DWData(dict): +class ReactorData(object): + """Data structure containing data from one reactor.""" + + def __init__(self, id: int): + self._id = id + self._setup = None + self._unit = None + self._requirements = None + self._sensor_elements = None + self._device_channels = None + self._profiles = None + self._trackdata = None + self._dataframe = None + + @property + def id(self) -> int: + """Number of the reactor.""" + return self._id + + @property + def setup(self) -> pandas.DataFrame: + """Dataframe of overall process information.""" + return self._setup + + @property + def unit(self) -> pandas.DataFrame: + """Properties of the reactor.""" + return self._unit + + @property + def requirements(self) -> pandas.DataFrame: + return self._requirements + + @property + def sensor_elements(self) -> pandas.DataFrame: + """Table of connected sensors.""" + return self._sensor_elements + + @property + def device_channels(self) -> pandas.DataFrame: + return self._device_channels + + @property + def profiles(self) -> pandas.DataFrame: + return self._profiles + + @property + def trackdata(self) -> pandas.DataFrame: + """Contains timeseries of mass flows.""" + return self._trackdata + + @property + def dataframe(self) -> pandas.DataFrame: + """Primary table of setpoint (SP) and actual (PV) control parameters.""" + return self._dataframe + + def get_closest_data( + self, points: numpy.array, reference: str = "process_time" + ) -> pandas.DataFrame: + """Returns a subset of the reactor data at points closest to the given ones. + + Args: + points (numpy.array): the data from readings closest to these points will be returned + reference (str): name of the column to look for points + + Returns: + filtered_data: DataFrame containing data closest to the given points + + Raises: + KeyError: when the reference column is not in the DataFrame + """ + if reference not in self.dataframe.columns: + raise KeyError("Reference column not in DataFrame") + + idx = [abs(self.dataframe.loc[:, reference] - p).idxmin() for p in points] + + return self.dataframe.loc[idx] + + +class DWData(Dict[str, ReactorData]): """Standardized data type for DASGIP data.""" def __init__(self, version: DASwareVersion): @@ -152,85 +232,6 @@ def get_narrow_data(self, kdim: str = "process_time"): return narrow_data -class ReactorData(object): - """Data structure containing data from one reactor.""" - - def __init__(self, id: int): - self._id = id - self._setup = None - self._unit = None - self._requirements = None - self._sensor_elements = None - self._device_channels = None - self._profiles = None - self._trackdata = None - self._dataframe = None - - @property - def id(self) -> int: - """Number of the reactor.""" - return self._id - - @property - def setup(self) -> pandas.DataFrame: - """Dataframe of overall process information.""" - return self._setup - - @property - def unit(self) -> pandas.DataFrame: - """Properties of the reactor.""" - return self._unit - - @property - def requirements(self) -> pandas.DataFrame: - return self._requirements - - @property - def sensor_elements(self) -> pandas.DataFrame: - """Table of connected sensors.""" - return self._sensor_elements - - @property - def device_channels(self) -> pandas.DataFrame: - return self._device_channels - - @property - def profiles(self) -> pandas.DataFrame: - return self._profiles - - @property - def trackdata(self) -> pandas.DataFrame: - """Contains timeseries of mass flows.""" - return self._trackdata - - @property - def dataframe(self) -> pandas.DataFrame: - """Primary table of setpoint (SP) and actual (PV) control parameters.""" - return self._dataframe - - def get_closest_data( - self, points: numpy.array, reference: str = "process_time" - ) -> pandas.DataFrame: - """Returns a subset of the reactor data at points closest to the given ones. - - Args: - points (numpy.array): the data from readings closest to these points will be returned - reference (str): name of the column to look for points - - Returns: - filtered_data: DataFrame containing data closest to the given points - - Raises: - KeyError: when the reference column is not in the DataFrame - """ - if reference not in self.dataframe.columns: - raise KeyError("Reference column not in DataFrame") - - idx = [abs(self.dataframe.loc[:, reference] - p).idxmin() for p in points] - - return self.dataframe.loc[idx] - - class DASwareParser(object): """Abstract type for parsers that read DASware CSV files.""" From 40ff780a24a7ddd6f323a49d7b1b89f107a43bb9 Mon Sep 17 00:00:00 2001 From: "t.latour" Date: Tue, 29 Apr 2025 14:05:36 +0200 Subject: [PATCH 2/4] add tests covering `ReactorData` properties --- tests/test_detl.py | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/tests/test_detl.py b/tests/test_detl.py index ee34f14..66285a5 100644 --- a/tests/test_detl.py +++ b/tests/test_detl.py @@ -259,5 +259,23 @@ def test_kdim_setting(self): ddata.get_narrow_data(kdim="volume_pv") +class TestReactorDataProps(unittest.TestCase): + def test_reactor_data(self): + ddata = detl.parse(v4_testfiles[0]) + rdata = ddata.values()[0] + self.assertIsInstance(rdata, detl.ReactorData) + + # check properties + rdata.id + rdata.setup + rdata.unit + rdata.requirements + rdata.sensor_elements + rdata.device_channels + rdata.profiles + rdata.trackdata + rdata.dataframe + + if __name__ == "__main__": unittest.main() From ca74b812ecfe0c68cb97e925539e31a308d19e68 Mon Sep 17 00:00:00 2001 From: "t.latour" Date: Tue, 29 Apr 2025 14:12:49 +0200 Subject: [PATCH 3/4] fix `test_reactor_data` --- tests/test_detl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_detl.py b/tests/test_detl.py index 66285a5..b5f34f4 100644 --- a/tests/test_detl.py +++ b/tests/test_detl.py @@ -262,7 +262,7 @@ def test_kdim_setting(self): class TestReactorDataProps(unittest.TestCase): def test_reactor_data(self): ddata = detl.parse(v4_testfiles[0]) - rdata = ddata.values()[0] + rdata = list(ddata.values())[0] self.assertIsInstance(rdata, detl.ReactorData) # check properties From 0df77b752f6ed01920baf82bf0d4c7c6252b0f01 Mon Sep 17 00:00:00 2001 From: "t.latour" Date: Tue, 29 Apr 2025 14:15:29 +0200 Subject: [PATCH 4/4] fix TestReactorData assertion --- tests/test_detl.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/tests/test_detl.py b/tests/test_detl.py index b5f34f4..595d1ba 100644 --- a/tests/test_detl.py +++ b/tests/test_detl.py @@ -263,7 +263,7 @@ class TestReactorDataProps(unittest.TestCase): def test_reactor_data(self): ddata = detl.parse(v4_testfiles[0]) rdata = list(ddata.values())[0] - self.assertIsInstance(rdata, detl.ReactorData) + self.assertIsInstance(rdata, detl.core.ReactorData) # check properties rdata.id