pychemstation 0.10.7__py3-none-any.whl → 0.10.8.dev1__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- pychemstation/analysis/base_spectrum.py +14 -15
- pychemstation/analysis/chromatogram.py +7 -8
- pychemstation/analysis/process_report.py +7 -15
- pychemstation/control/README.md +1 -1
- pychemstation/control/controllers/__init__.py +2 -1
- pychemstation/control/controllers/comm.py +33 -27
- pychemstation/control/controllers/data_aq/method.py +13 -13
- pychemstation/control/controllers/data_aq/sequence.py +12 -24
- pychemstation/control/controllers/devices/injector.py +3 -3
- pychemstation/control/hplc.py +24 -39
- pychemstation/utils/__init__.py +23 -0
- pychemstation/{control/controllers → utils}/abc_tables/abc_comm.py +8 -9
- pychemstation/{control/controllers → utils}/abc_tables/device.py +9 -2
- pychemstation/{control/controllers → utils}/abc_tables/run.py +35 -28
- pychemstation/{control/controllers → utils}/abc_tables/table.py +14 -16
- pychemstation/utils/macro.py +2 -0
- pychemstation/utils/method_types.py +12 -13
- pychemstation/utils/num_utils.py +3 -3
- pychemstation/utils/sequence_types.py +31 -13
- pychemstation/utils/spec_utils.py +42 -66
- pychemstation/utils/table_types.py +13 -2
- pychemstation/utils/tray_types.py +28 -16
- {pychemstation-0.10.7.dist-info → pychemstation-0.10.8.dev1.dist-info}/METADATA +1 -7
- pychemstation-0.10.8.dev1.dist-info/RECORD +41 -0
- pychemstation/utils/pump_types.py +0 -7
- pychemstation-0.10.7.dist-info/RECORD +0 -42
- /pychemstation/{control/controllers → utils}/abc_tables/__init__.py +0 -0
- {pychemstation-0.10.7.dist-info → pychemstation-0.10.8.dev1.dist-info}/WHEEL +0 -0
- {pychemstation-0.10.7.dist-info → pychemstation-0.10.8.dev1.dist-info}/licenses/LICENSE +0 -0
pychemstation/control/hplc.py
CHANGED
@@ -32,8 +32,6 @@ class HPLCController:
|
|
32
32
|
|
33
33
|
INJECTOR_TABLE = Table(register="RCWLS1Pretreatment[1]", name="InstructionTable")
|
34
34
|
|
35
|
-
DAD_TABLE = Table(register="RCDAD1Method[1]", name="Timetable")
|
36
|
-
|
37
35
|
MSD_TABLE = Table(register="MSACQINFO[1]", name="SprayChamber")
|
38
36
|
|
39
37
|
def __init__(
|
@@ -63,7 +61,7 @@ class HPLCController:
|
|
63
61
|
if extra_data_dirs:
|
64
62
|
data_dirs.extend(extra_data_dirs)
|
65
63
|
data_dirs = list(set([os.path.normpath(p) for p in data_dirs]))
|
66
|
-
if method_dir and sequence_dir and data_dirs:
|
64
|
+
if (method_dir and sequence_dir and data_dirs and not offline) or offline:
|
67
65
|
self.method_controller: MethodController = MethodController(
|
68
66
|
controller=self.comm,
|
69
67
|
src=method_dir,
|
@@ -82,14 +80,15 @@ class HPLCController:
|
|
82
80
|
method_controller=self.method_controller,
|
83
81
|
offline=offline,
|
84
82
|
)
|
85
|
-
|
83
|
+
elif not offline and (not method_dir or not sequence_dir or not data_dirs):
|
86
84
|
raise ValueError(
|
87
|
-
"Expected a method dir, sequence dir and data dirs but
|
85
|
+
f"Expected a method dir: {method_dir}, sequence dir: {sequence_dir} and data dirs:{data_dirs} but one was None."
|
88
86
|
)
|
87
|
+
else:
|
88
|
+
raise ValueError("Expected error occured, please try again.")
|
89
89
|
|
90
90
|
def send(self, cmd: Union[Command, str]):
|
91
|
-
"""
|
92
|
-
Sends any Command or string to Chemstation.
|
91
|
+
"""Sends any Command or string to Chemstation.
|
93
92
|
|
94
93
|
:param cmd: the macro to send to Chemstation
|
95
94
|
"""
|
@@ -100,10 +99,9 @@ class HPLCController:
|
|
100
99
|
self.comm.send(cmd)
|
101
100
|
|
102
101
|
def receive(self) -> None | Response | str:
|
103
|
-
"""
|
104
|
-
Get the most recent response from Chemstation.
|
102
|
+
"""Get the most recent response from Chemstation.
|
105
103
|
|
106
|
-
:return: most recent response from
|
104
|
+
:return: most recent response from the most recently sent MACRO that returned a response.
|
107
105
|
"""
|
108
106
|
if not self.comm:
|
109
107
|
raise RuntimeError(
|
@@ -112,8 +110,7 @@ class HPLCController:
|
|
112
110
|
return self.comm.receive().value
|
113
111
|
|
114
112
|
def status(self) -> Status:
|
115
|
-
"""
|
116
|
-
Get the current status of the HPLC machine.
|
113
|
+
"""Get the current status of the HPLC machine.
|
117
114
|
|
118
115
|
:return: current status of the HPLC machine; Status types can be found in `pychemstation.utils.macro`
|
119
116
|
"""
|
@@ -124,8 +121,7 @@ class HPLCController:
|
|
124
121
|
return self.comm.get_status()
|
125
122
|
|
126
123
|
def switch_method(self, method_name: str):
|
127
|
-
"""
|
128
|
-
Allows the user to switch between pre-programmed methods. No need to append '.M'
|
124
|
+
"""Allows the user to switch between pre-programmed methods. No need to append '.M'
|
129
125
|
to the end of the method name. For example. for the method named 'General-Poroshell.M',
|
130
126
|
only 'General-Poroshell' is needed.
|
131
127
|
|
@@ -136,8 +132,7 @@ class HPLCController:
|
|
136
132
|
self.method_controller.switch(method_name)
|
137
133
|
|
138
134
|
def switch_sequence(self, sequence_name: str):
|
139
|
-
"""
|
140
|
-
Allows the user to switch between pre-programmed sequences. The sequence name does not need the '.S' extension.
|
135
|
+
"""Allows the user to switch between pre-programmed sequences. The sequence name does not need the '.S' extension.
|
141
136
|
For example: for the method named 'mySeq.S', only 'mySeq' is needed.
|
142
137
|
|
143
138
|
:param sequence_name: The name of the sequence file
|
@@ -150,8 +145,7 @@ class HPLCController:
|
|
150
145
|
add_timestamp: bool = True,
|
151
146
|
stall_while_running: bool = True,
|
152
147
|
):
|
153
|
-
"""
|
154
|
-
This is the preferred method to trigger a run.
|
148
|
+
"""This is the preferred method to trigger a run.
|
155
149
|
Starts the currently selected method, storing data
|
156
150
|
under the <data_dir>/<experiment_name>.D folder.
|
157
151
|
Device must be ready.
|
@@ -171,8 +165,7 @@ class HPLCController:
|
|
171
165
|
self.method_controller.stop()
|
172
166
|
|
173
167
|
def run_sequence(self, stall_while_running: bool = True):
|
174
|
-
"""
|
175
|
-
Starts the currently loaded sequence, storing data
|
168
|
+
"""Starts the currently loaded sequence, storing data
|
176
169
|
under one of the data_dirs/<sequence table name> folder.
|
177
170
|
Device must be ready.
|
178
171
|
|
@@ -181,24 +174,21 @@ class HPLCController:
|
|
181
174
|
self.sequence_controller.run(stall_while_running=stall_while_running)
|
182
175
|
|
183
176
|
def check_method_complete(self) -> Tuple[float, int]:
|
184
|
-
"""
|
185
|
-
Check if the currently running method (if any) is done.
|
177
|
+
"""Check if the currently running method (if any) is done.
|
186
178
|
|
187
|
-
:returns the percent of the method run completed, and whether the run is complete.
|
179
|
+
:returns: the percent of the method run completed, and whether the run is complete.
|
188
180
|
"""
|
189
181
|
return self.method_controller.check_hplc_run_finished()
|
190
182
|
|
191
183
|
def check_sequence_complete(self) -> Tuple[float, int]:
|
192
|
-
"""
|
193
|
-
Check if the currently running sequence (if any) is done.
|
184
|
+
"""Check if the currently running sequence (if any) is done.
|
194
185
|
|
195
186
|
:return: the percent of the sequence run completed, and whether the run is complete.
|
196
187
|
"""
|
197
188
|
return self.sequence_controller.check_hplc_run_finished()
|
198
189
|
|
199
190
|
def edit_method(self, updated_method: MethodDetails, save: bool = False):
|
200
|
-
"""
|
201
|
-
Updated the currently loaded method in ChemStation with provided values.
|
191
|
+
"""Updated the currently loaded method in ChemStation with provided values.
|
202
192
|
|
203
193
|
:param updated_method: the method with updated values, to be sent to Chemstation to modify the currently loaded method.
|
204
194
|
:param save: whether this method should be saved to disk, or just modified.
|
@@ -206,8 +196,7 @@ class HPLCController:
|
|
206
196
|
self.method_controller.edit(updated_method, save)
|
207
197
|
|
208
198
|
def edit_sequence(self, updated_sequence: SequenceTable):
|
209
|
-
"""
|
210
|
-
Updates the currently loaded sequence table with the provided table, and saves the sequence.
|
199
|
+
"""Updates the currently loaded sequence table with the provided table, and saves the sequence.
|
211
200
|
|
212
201
|
:param updated_sequence: The sequence table to be written to the currently loaded sequence table.
|
213
202
|
"""
|
@@ -218,8 +207,7 @@ class HPLCController:
|
|
218
207
|
custom_path: Optional[str] = None,
|
219
208
|
report_type: ReportType = ReportType.CSV,
|
220
209
|
) -> AgilentReport:
|
221
|
-
"""
|
222
|
-
Return data contained in the REPORT files. Use `aghplctools` if you want more report processing utility.
|
210
|
+
"""Return data contained in the REPORT files. Use `aghplctools` if you want more report processing utility.
|
223
211
|
|
224
212
|
:param custom_path: path to sequence folder
|
225
213
|
:param report_type: read either the TXT or CSV version
|
@@ -232,8 +220,7 @@ class HPLCController:
|
|
232
220
|
def get_last_run_method_data(
|
233
221
|
self, read_uv: bool = False, custom_path: Optional[str] = None
|
234
222
|
) -> Dict[int, AgilentHPLCChromatogram] | AgilentChannelChromatogramData:
|
235
|
-
"""
|
236
|
-
Returns the last run method data.
|
223
|
+
"""Returns the last run method data.
|
237
224
|
|
238
225
|
:param custom_path: If you want to just load method data but from a file path. This file path must be the complete file path.
|
239
226
|
:param read_uv: whether to also read the UV file
|
@@ -248,8 +235,7 @@ class HPLCController:
|
|
248
235
|
custom_path: Optional[str] = None,
|
249
236
|
report_type: ReportType = ReportType.CSV,
|
250
237
|
) -> List[AgilentReport]:
|
251
|
-
"""
|
252
|
-
Return data contained in the REPORT files. Use `aghplctools` if you want more report processing utility.
|
238
|
+
"""Return data contained in the REPORT files. Use `aghplctools` if you want more report processing utility.
|
253
239
|
|
254
240
|
:param custom_path: path to sequence folder
|
255
241
|
:param report_type: read either the TXT or CSV version
|
@@ -264,8 +250,7 @@ class HPLCController:
|
|
264
250
|
) -> (
|
265
251
|
List[Dict[int, AgilentHPLCChromatogram]] | List[AgilentChannelChromatogramData]
|
266
252
|
):
|
267
|
-
"""
|
268
|
-
Returns data for all rows in the last run sequence data.
|
253
|
+
"""Returns data for all rows in the last run sequence data.
|
269
254
|
|
270
255
|
:param custom_path: If you want to just load sequence data but from a file path. This file path must be the complete file path.
|
271
256
|
:param read_uv: whether to also read the UV file
|
@@ -277,11 +262,11 @@ class HPLCController:
|
|
277
262
|
|
278
263
|
def check_loaded_sequence(self) -> str:
|
279
264
|
"""Returns the name of the currently loaded sequence."""
|
280
|
-
return self.sequence_controller.
|
265
|
+
return self.sequence_controller.get_current_sequence_name()
|
281
266
|
|
282
267
|
def check_loaded_method(self) -> str:
|
283
268
|
"""Returns the name of the currently loaded method."""
|
284
|
-
return self.method_controller.
|
269
|
+
return self.method_controller.get_current_method_name()
|
285
270
|
|
286
271
|
def load_method(self) -> MethodDetails:
|
287
272
|
"""Returns details of the currently loaded method, such as its starting modifier conditions and timetable."""
|
pychemstation/utils/__init__.py
CHANGED
@@ -0,0 +1,23 @@
|
|
1
|
+
from . import abc_tables
|
2
|
+
from . import injector_types
|
3
|
+
from . import macro
|
4
|
+
from . import method_types
|
5
|
+
from . import num_utils
|
6
|
+
from . import parsing
|
7
|
+
from . import sequence_types
|
8
|
+
from . import spec_utils
|
9
|
+
from . import table_types
|
10
|
+
from . import tray_types
|
11
|
+
|
12
|
+
__all__ = [
|
13
|
+
"abc_tables",
|
14
|
+
"injector_types",
|
15
|
+
"macro",
|
16
|
+
"method_types",
|
17
|
+
"num_utils",
|
18
|
+
"parsing",
|
19
|
+
"sequence_types",
|
20
|
+
"spec_utils",
|
21
|
+
"table_types",
|
22
|
+
"tray_types",
|
23
|
+
]
|
@@ -18,12 +18,17 @@ from typing import Union
|
|
18
18
|
|
19
19
|
from result import Err, Ok, Result
|
20
20
|
|
21
|
-
from
|
21
|
+
from ..macro import HPLCAvailStatus, Command, Response, Status
|
22
22
|
|
23
23
|
|
24
24
|
class ABCCommunicationController(abc.ABC):
|
25
|
-
"""
|
26
|
-
|
25
|
+
"""Abstract class representing the communication controller.
|
26
|
+
|
27
|
+
:param comm_dir: the complete directory path that was used in the MACRO file, common file that pychemstation and Chemstation use to communicate.
|
28
|
+
:param cmd_file: name of the write file that pychemstation writes MACROs to, in `comm_dir`
|
29
|
+
:param reply_file: name of the read file that Chemstation replies to, in `comm_dir
|
30
|
+
:param offline: whether or not communication with Chemstation is to be established
|
31
|
+
:param debug: if True, prints all send MACROs to an out.txt file
|
27
32
|
"""
|
28
33
|
|
29
34
|
# maximum command number
|
@@ -37,12 +42,6 @@ class ABCCommunicationController(abc.ABC):
|
|
37
42
|
offline: bool = False,
|
38
43
|
debug: bool = False,
|
39
44
|
):
|
40
|
-
"""
|
41
|
-
:param comm_dir:
|
42
|
-
:param cmd_file: Name of command file
|
43
|
-
:param reply_file: Name of reply file
|
44
|
-
:param debug: whether to save log of sent commands
|
45
|
-
"""
|
46
45
|
if not offline:
|
47
46
|
self.debug = debug
|
48
47
|
if os.path.isdir(comm_dir):
|
@@ -2,12 +2,19 @@ from __future__ import annotations
|
|
2
2
|
|
3
3
|
from abc import ABC
|
4
4
|
|
5
|
-
from ....control.controllers import CommunicationController
|
6
|
-
from ....utils.table_types import Table
|
7
5
|
from .table import ABCTableController
|
6
|
+
from ..table_types import Table
|
7
|
+
from ...control.controllers import CommunicationController
|
8
8
|
|
9
9
|
|
10
10
|
class DeviceController(ABCTableController, ABC):
|
11
|
+
"""Abstract controller representing tables that contain device information.
|
12
|
+
|
13
|
+
:param controller: controller for sending MACROs
|
14
|
+
:param table: contains register keys for accessing table in Chemstation
|
15
|
+
:param offline: whether the communication controller is online.
|
16
|
+
"""
|
17
|
+
|
11
18
|
def __init__(
|
12
19
|
self, controller: CommunicationController, table: Table, offline: bool
|
13
20
|
):
|
@@ -17,33 +17,42 @@ import polling
|
|
17
17
|
import rainbow as rb
|
18
18
|
from result import Err, Ok, Result
|
19
19
|
|
20
|
-
from
|
20
|
+
from ..macro import HPLCRunningStatus, Command
|
21
|
+
from ..method_types import MethodDetails
|
22
|
+
from ..sequence_types import SequenceTable
|
23
|
+
from ..table_types import Table, T
|
24
|
+
from ...analysis.chromatogram import (
|
21
25
|
AgilentChannelChromatogramData,
|
22
26
|
AgilentHPLCChromatogram,
|
23
27
|
)
|
24
28
|
|
25
|
-
from
|
29
|
+
from .table import ABCTableController
|
30
|
+
from ...analysis.process_report import (
|
31
|
+
ReportType,
|
26
32
|
AgilentReport,
|
27
33
|
CSVProcessor,
|
28
|
-
ReportType,
|
29
34
|
TXTProcessor,
|
30
35
|
)
|
31
|
-
from
|
32
|
-
from ....utils.macro import Command, HPLCRunningStatus
|
33
|
-
from ....utils.method_types import MethodDetails
|
34
|
-
from ....utils.sequence_types import SequenceTable
|
35
|
-
from ....utils.table_types import T, Table
|
36
|
-
from .table import ABCTableController
|
36
|
+
from ...control.controllers import CommunicationController
|
37
37
|
|
38
38
|
TableType = Union[MethodDetails, SequenceTable]
|
39
39
|
|
40
40
|
|
41
41
|
class RunController(ABCTableController, abc.ABC):
|
42
|
+
"""Abstract controller for all tables that can trigger runs on Chemstation.
|
43
|
+
|
44
|
+
:param controller: the controller for sending MACROs, must be initialized for a run to be triggered.
|
45
|
+
:param src: complete directory path where files containing run parameters are stored.
|
46
|
+
:param data_dirs: list of complete directories that Chemstation will write data to.
|
47
|
+
:param table: contains register keys for accessing table in Chemstation.
|
48
|
+
:param offline: whether the communication controller is online.
|
49
|
+
"""
|
50
|
+
|
42
51
|
def __init__(
|
43
52
|
self,
|
44
53
|
controller: Optional[CommunicationController],
|
45
|
-
src: str,
|
46
|
-
data_dirs: List[str],
|
54
|
+
src: Optional[str],
|
55
|
+
data_dirs: Optional[List[str]],
|
47
56
|
table: Table,
|
48
57
|
offline: bool = False,
|
49
58
|
):
|
@@ -56,14 +65,15 @@ class RunController(ABCTableController, abc.ABC):
|
|
56
65
|
if not offline:
|
57
66
|
if src and not os.path.isdir(src):
|
58
67
|
raise FileNotFoundError(f"dir: {src} not found.")
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
68
|
+
if data_dirs:
|
69
|
+
for d in data_dirs:
|
70
|
+
if not os.path.isdir(d):
|
71
|
+
raise FileNotFoundError(f"dir: {d} not found.")
|
72
|
+
if r"\\" in d:
|
73
|
+
raise ValueError("Data directories should not be raw strings!")
|
74
|
+
if src and data_dirs:
|
75
|
+
self.src: str = src
|
76
|
+
self.data_dirs: List[str] = data_dirs
|
67
77
|
|
68
78
|
self.spectra: dict[str, AgilentHPLCChromatogram] = {
|
69
79
|
"A": AgilentHPLCChromatogram(),
|
@@ -84,8 +94,8 @@ class RunController(ABCTableController, abc.ABC):
|
|
84
94
|
return object.__new__(cls)
|
85
95
|
|
86
96
|
@abc.abstractmethod
|
87
|
-
def
|
88
|
-
self, most_recent_folder: T,
|
97
|
+
def _fuzzy_match_most_recent_folder(
|
98
|
+
self, most_recent_folder: T, child_dirs: Set[str]
|
89
99
|
) -> Result[T, str]:
|
90
100
|
pass
|
91
101
|
|
@@ -148,8 +158,7 @@ class RunController(ABCTableController, abc.ABC):
|
|
148
158
|
raise ValueError("Controller is offline!")
|
149
159
|
|
150
160
|
def check_hplc_done_running(self) -> Ok[T] | Err[str]:
|
151
|
-
"""
|
152
|
-
Checks if ChemStation has finished running and can read data back
|
161
|
+
"""Checks if ChemStation has finished running and can read data back
|
153
162
|
|
154
163
|
:return: Data file object containing most recent run file information.
|
155
164
|
"""
|
@@ -183,7 +192,7 @@ class RunController(ABCTableController, abc.ABC):
|
|
183
192
|
else:
|
184
193
|
raise ValueError("Timeout value is None, no comparison can be made.")
|
185
194
|
|
186
|
-
check_folder = self.
|
195
|
+
check_folder = self._fuzzy_match_most_recent_folder(
|
187
196
|
self.data_files[-1], self.current_run_child_files
|
188
197
|
)
|
189
198
|
if check_folder.is_ok() and finished_run:
|
@@ -198,7 +207,7 @@ class RunController(ABCTableController, abc.ABC):
|
|
198
207
|
except Exception:
|
199
208
|
self._reset_time()
|
200
209
|
return self.data_files[-1]
|
201
|
-
return Err("Run
|
210
|
+
return Err("Run not may not have completed.")
|
202
211
|
|
203
212
|
def get_uv_spectrum(self, path: str):
|
204
213
|
data_uv = rb.agilent.chemstation.parse_file(os.path.join(path, "DAD1.UV"))
|
@@ -227,9 +236,7 @@ class RunController(ABCTableController, abc.ABC):
|
|
227
236
|
raise ValueError("Expected one of ReportType.TXT or ReportType.CSV")
|
228
237
|
|
229
238
|
def get_spectrum_at_channels(self, data_path: str):
|
230
|
-
"""
|
231
|
-
Load chromatogram for any channel in spectra dictionary.
|
232
|
-
"""
|
239
|
+
"""Load chromatogram for any channel in spectra dictionary."""
|
233
240
|
for channel, spec in self.spectra.items():
|
234
241
|
try:
|
235
242
|
spec.load_spectrum(data_path=data_path, channel=channel)
|
@@ -11,16 +11,21 @@ from typing import Optional, Union
|
|
11
11
|
|
12
12
|
from result import Err, Result
|
13
13
|
|
14
|
-
from
|
15
|
-
from
|
16
|
-
from
|
17
|
-
from
|
18
|
-
from
|
14
|
+
from ..macro import Command, Response
|
15
|
+
from ..method_types import MethodDetails
|
16
|
+
from ..sequence_types import SequenceTable
|
17
|
+
from ..table_types import Table, RegisterFlag, TableOperation
|
18
|
+
from ...control.controllers import CommunicationController
|
19
19
|
|
20
20
|
TableType = Union[MethodDetails, SequenceTable]
|
21
21
|
|
22
22
|
|
23
23
|
class ABCTableController(abc.ABC):
|
24
|
+
"""Abstract controller for all table-like objects in Chemstation.
|
25
|
+
:param controller: controller for sending MACROs to Chemstation
|
26
|
+
:param table: contains register keys needed for accessing table in Chemstation.
|
27
|
+
"""
|
28
|
+
|
24
29
|
def __init__(
|
25
30
|
self,
|
26
31
|
controller: Optional[CommunicationController],
|
@@ -60,8 +65,7 @@ class ABCTableController(abc.ABC):
|
|
60
65
|
raise ValueError("Controller is offline")
|
61
66
|
|
62
67
|
def sleep(self, seconds: int):
|
63
|
-
"""
|
64
|
-
Tells the HPLC to wait for a specified number of seconds.
|
68
|
+
"""Tells the HPLC to wait for a specified number of seconds.
|
65
69
|
|
66
70
|
:param seconds: number of seconds to wait
|
67
71
|
"""
|
@@ -173,9 +177,7 @@ class ABCTableController(abc.ABC):
|
|
173
177
|
)
|
174
178
|
|
175
179
|
def add_row(self):
|
176
|
-
"""
|
177
|
-
Adds a row to the provided table for currently loaded method or sequence.
|
178
|
-
"""
|
180
|
+
"""Adds a row to the provided table for currently loaded method or sequence."""
|
179
181
|
self.sleepy_send(
|
180
182
|
TableOperation.NEW_ROW.value.format(
|
181
183
|
register=self.table_locator.register, table_name=self.table_locator.name
|
@@ -183,9 +185,7 @@ class ABCTableController(abc.ABC):
|
|
183
185
|
)
|
184
186
|
|
185
187
|
def delete_table(self):
|
186
|
-
"""
|
187
|
-
Deletes the table for the current loaded method or sequence.
|
188
|
-
"""
|
188
|
+
"""Deletes the table."""
|
189
189
|
self.sleepy_send(
|
190
190
|
TableOperation.DELETE_TABLE.value.format(
|
191
191
|
register=self.table_locator.register, table_name=self.table_locator.name
|
@@ -193,9 +193,7 @@ class ABCTableController(abc.ABC):
|
|
193
193
|
)
|
194
194
|
|
195
195
|
def new_table(self):
|
196
|
-
"""
|
197
|
-
Creates the table for the currently loaded method or sequence.
|
198
|
-
"""
|
196
|
+
"""Creates the table."""
|
199
197
|
self.send(
|
200
198
|
TableOperation.CREATE_TABLE.value.format(
|
201
199
|
register=self.table_locator.register, table_name=self.table_locator.name
|
pychemstation/utils/macro.py
CHANGED
@@ -4,8 +4,6 @@ from dataclasses import dataclass
|
|
4
4
|
from enum import Enum
|
5
5
|
from typing import Any, Optional, Union
|
6
6
|
|
7
|
-
from ..generated import Signal
|
8
|
-
from .injector_types import InjectorTable
|
9
7
|
from .table_types import RegisterFlag
|
10
8
|
|
11
9
|
|
@@ -23,6 +21,8 @@ class Param:
|
|
23
21
|
|
24
22
|
@dataclass
|
25
23
|
class HPLCMethodParams:
|
24
|
+
"""The starting conditions of a run that are displayed in the Chemstation GUI for the pump."""
|
25
|
+
|
26
26
|
organic_modifier: float
|
27
27
|
flow: float
|
28
28
|
pressure: Optional[float] = None # TODO: find this
|
@@ -30,6 +30,8 @@ class HPLCMethodParams:
|
|
30
30
|
|
31
31
|
@dataclass
|
32
32
|
class TimeTableEntry:
|
33
|
+
"""Row in a method timetable."""
|
34
|
+
|
33
35
|
start_time: float
|
34
36
|
organic_modifer: Optional[float]
|
35
37
|
flow: Optional[float] = None
|
@@ -37,21 +39,18 @@ class TimeTableEntry:
|
|
37
39
|
|
38
40
|
@dataclass
|
39
41
|
class MethodDetails:
|
40
|
-
"""An Agilent Chemstation method
|
41
|
-
|
42
|
-
:
|
43
|
-
:
|
44
|
-
:
|
45
|
-
:
|
46
|
-
based on settings in the first row of the timetable.
|
47
|
-
:
|
48
|
-
:attribute dad_wavelengthes:
|
42
|
+
"""An Agilent Chemstation method
|
43
|
+
|
44
|
+
:param name: the name of the method, should be the same as the Chemstation method name.
|
45
|
+
:param timetable: list of entries in the method timetable
|
46
|
+
:param stop_time: the time the method stops running after the last timetable entry. If `None`, won't be set.
|
47
|
+
:param post_time: the amount of time after the stoptime that the pumps keep running,
|
48
|
+
based on settings in the first row of the timetable. If `None`, won't be set.
|
49
|
+
:param params: the organic modifier (pump B) and flow rate displayed for the method (the time 0 settings)
|
49
50
|
"""
|
50
51
|
|
51
52
|
name: str
|
52
53
|
params: HPLCMethodParams
|
53
54
|
timetable: list[TimeTableEntry]
|
54
|
-
injector_program: Optional[InjectorTable] = None
|
55
55
|
stop_time: Optional[float] = None
|
56
56
|
post_time: Optional[float] = None
|
57
|
-
dad_wavelengthes: Optional[list[Signal]] = None
|
pychemstation/utils/num_utils.py
CHANGED
@@ -18,7 +18,7 @@ def find_nearest_value_index(array, value) -> Tuple[float, int]:
|
|
18
18
|
return array[index_], index_
|
19
19
|
|
20
20
|
|
21
|
-
def interpolate_to_index(array, ids, precision: int = 100) -> np.
|
21
|
+
def interpolate_to_index(array, ids, precision: int = 100) -> np.ndarray:
|
22
22
|
"""Find value in between arrays elements.
|
23
23
|
|
24
24
|
Constructs linspace of size "precision" between index+1 and index to
|
@@ -37,8 +37,8 @@ def interpolate_to_index(array, ids, precision: int = 100) -> np.array:
|
|
37
37
|
:return: New array with interpolated values according to provided indexes "ids".
|
38
38
|
|
39
39
|
Example:
|
40
|
-
>>> interpolate_to_index(np.array([1.5]), np.array([1,2,3], 100))
|
41
|
-
array([2.50505051])
|
40
|
+
>>> interpolate_to_index(np.array([1.5]), np.array([1, 2, 3], 100))
|
41
|
+
... array([2.50505051])
|
42
42
|
"""
|
43
43
|
|
44
44
|
# breaking ids into fractional and integral parts
|
@@ -9,6 +9,14 @@ from pychemstation.utils.tray_types import Tray
|
|
9
9
|
|
10
10
|
@dataclass
|
11
11
|
class SequenceDataFiles:
|
12
|
+
"""Class to represent files generated during a sequence.
|
13
|
+
|
14
|
+
:param sequence_name: the name of the sequence that is running
|
15
|
+
:param dir: the complete path of the directory generated for the sequence
|
16
|
+
:param _data_files: the names of the files of the sequence runs, ends with ".D"
|
17
|
+
:param child_dirs: the complete path of the files for sequence runs, contains the Chemstation data, `dir` and the sample run file.
|
18
|
+
"""
|
19
|
+
|
12
20
|
sequence_name: str
|
13
21
|
dir: str
|
14
22
|
_data_files: List[str] = field(default_factory=list)
|
@@ -39,6 +47,8 @@ class InjectionSource(Enum):
|
|
39
47
|
|
40
48
|
@dataclass
|
41
49
|
class SequenceEntry:
|
50
|
+
"""Class to represent each row of a sequence file, maps one to one to Chemstation."""
|
51
|
+
|
42
52
|
data_file: str
|
43
53
|
vial_location: Tray
|
44
54
|
sample_name: Optional[str] = None
|
@@ -51,23 +61,31 @@ class SequenceEntry:
|
|
51
61
|
|
52
62
|
@dataclass
|
53
63
|
class SequenceTable:
|
64
|
+
"""Class to represent a sequence file.
|
65
|
+
|
66
|
+
:param name: name of the sequence
|
67
|
+
:param rows: the entries
|
68
|
+
"""
|
69
|
+
|
54
70
|
name: str
|
55
71
|
rows: list[SequenceEntry]
|
56
72
|
|
57
|
-
def __eq__(self, other):
|
58
|
-
equal = False
|
73
|
+
def __eq__(self, other) -> bool:
|
59
74
|
if not isinstance(other, SequenceTable):
|
60
75
|
return False
|
61
76
|
|
77
|
+
equal = True
|
62
78
|
for self_row, other_row in zip(self.rows, other.rows):
|
63
|
-
equal
|
64
|
-
equal
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
equal
|
71
|
-
equal
|
72
|
-
equal
|
73
|
-
equal
|
79
|
+
equal &= self_row.vial_location == other_row.vial_location
|
80
|
+
equal &= self_row.data_file == other_row.data_file
|
81
|
+
if self_row.method and other_row.method:
|
82
|
+
equal &= (
|
83
|
+
os.path.split(os.path.normpath(self_row.method))[-1]
|
84
|
+
== os.path.split(os.path.normpath(other_row.method))[-1]
|
85
|
+
)
|
86
|
+
equal &= self_row.num_inj == other_row.num_inj
|
87
|
+
equal &= self_row.inj_vol == other_row.inj_vol
|
88
|
+
equal &= self_row.inj_source == other_row.inj_source
|
89
|
+
equal &= self_row.sample_name == other_row.sample_name
|
90
|
+
equal &= self_row.sample_type == other_row.sample_type
|
91
|
+
return equal
|