pychemstation 0.8.4__py3-none-any.whl → 0.8.7__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/__init__.py +1 -1
- pychemstation/analysis/__init__.py +4 -1
- pychemstation/analysis/base_spectrum.py +4 -4
- pychemstation/{utils → analysis}/chromatogram.py +4 -7
- pychemstation/analysis/process_report.py +173 -77
- pychemstation/control/README.md +22 -46
- pychemstation/control/__init__.py +5 -0
- pychemstation/control/controllers/__init__.py +2 -0
- pychemstation/control/controllers/comm.py +41 -18
- pychemstation/control/controllers/devices/device.py +27 -14
- pychemstation/control/controllers/devices/injector.py +33 -89
- pychemstation/control/controllers/tables/method.py +266 -111
- pychemstation/control/controllers/tables/ms.py +7 -4
- pychemstation/control/controllers/tables/sequence.py +171 -82
- pychemstation/control/controllers/tables/table.py +192 -116
- pychemstation/control/hplc.py +117 -83
- pychemstation/generated/__init__.py +0 -2
- pychemstation/generated/dad_method.py +1 -1
- pychemstation/generated/pump_method.py +15 -19
- pychemstation/utils/injector_types.py +1 -1
- pychemstation/utils/macro.py +12 -11
- pychemstation/utils/method_types.py +3 -2
- pychemstation/{analysis/utils.py → utils/num_utils.py} +2 -2
- pychemstation/utils/parsing.py +1 -11
- pychemstation/utils/sequence_types.py +4 -5
- pychemstation/{analysis → utils}/spec_utils.py +1 -2
- pychemstation/utils/table_types.py +10 -9
- pychemstation/utils/tray_types.py +48 -38
- {pychemstation-0.8.4.dist-info → pychemstation-0.8.7.dist-info}/METADATA +64 -23
- pychemstation-0.8.7.dist-info/RECORD +37 -0
- pychemstation-0.8.4.dist-info/RECORD +0 -37
- {pychemstation-0.8.4.dist-info → pychemstation-0.8.7.dist-info}/WHEEL +0 -0
- {pychemstation-0.8.4.dist-info → pychemstation-0.8.7.dist-info}/licenses/LICENSE +0 -0
@@ -1,6 +1,7 @@
|
|
1
1
|
import os
|
2
2
|
import time
|
3
|
-
|
3
|
+
import warnings
|
4
|
+
from typing import Dict, List, Optional, Union
|
4
5
|
|
5
6
|
from result import Err, Ok, Result
|
6
7
|
from xsdata.formats.dataclass.parsers import XmlParser
|
@@ -8,14 +9,20 @@ from xsdata.formats.dataclass.parsers import XmlParser
|
|
8
9
|
from ....analysis.process_report import AgilentReport, ReportType
|
9
10
|
from ....control.controllers import CommunicationController
|
10
11
|
from ....generated import DadMethod, PumpMethod, SolventElement
|
11
|
-
from
|
12
|
+
from pychemstation.analysis.chromatogram import (
|
12
13
|
TIME_FORMAT,
|
13
14
|
AgilentChannelChromatogramData,
|
14
15
|
AgilentHPLCChromatogram,
|
15
16
|
)
|
16
|
-
from ....utils.macro import
|
17
|
-
from ....utils.method_types import
|
18
|
-
|
17
|
+
from ....utils.macro import Command
|
18
|
+
from ....utils.method_types import (
|
19
|
+
HPLCMethodParams,
|
20
|
+
MethodDetails,
|
21
|
+
Param,
|
22
|
+
PType,
|
23
|
+
TimeTableEntry,
|
24
|
+
)
|
25
|
+
from ....utils.table_types import RegisterFlag, T, Table, TableOperation
|
19
26
|
from ..devices.injector import InjectorController
|
20
27
|
from .table import TableController
|
21
28
|
|
@@ -25,15 +32,24 @@ class MethodController(TableController):
|
|
25
32
|
Class containing method related logic
|
26
33
|
"""
|
27
34
|
|
28
|
-
def __init__(
|
29
|
-
|
30
|
-
|
31
|
-
|
32
|
-
|
33
|
-
|
35
|
+
def __init__(
|
36
|
+
self,
|
37
|
+
controller: CommunicationController,
|
38
|
+
src: str,
|
39
|
+
data_dirs: List[str],
|
40
|
+
table: Table,
|
41
|
+
offline: bool,
|
42
|
+
injector_controller: InjectorController,
|
43
|
+
):
|
34
44
|
self.injector_controller = injector_controller
|
35
45
|
self.data_files: List[str] = []
|
36
|
-
super().__init__(
|
46
|
+
super().__init__(
|
47
|
+
controller=controller,
|
48
|
+
src=src,
|
49
|
+
data_dirs=data_dirs,
|
50
|
+
table=table,
|
51
|
+
offline=offline,
|
52
|
+
)
|
37
53
|
|
38
54
|
def check(self) -> str:
|
39
55
|
time.sleep(2)
|
@@ -45,16 +61,17 @@ class MethodController(TableController):
|
|
45
61
|
return "ERROR"
|
46
62
|
|
47
63
|
def get_method_params(self) -> HPLCMethodParams:
|
48
|
-
return HPLCMethodParams(
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
64
|
+
return HPLCMethodParams(
|
65
|
+
organic_modifier=self.controller.get_num_val(
|
66
|
+
cmd=TableOperation.GET_OBJ_HDR_VAL.value.format(
|
67
|
+
register=self.table_locator.register,
|
68
|
+
register_flag=RegisterFlag.SOLVENT_B_COMPOSITION,
|
69
|
+
)
|
70
|
+
),
|
54
71
|
flow=self.controller.get_num_val(
|
55
72
|
cmd=TableOperation.GET_OBJ_HDR_VAL.value.format(
|
56
73
|
register=self.table_locator.register,
|
57
|
-
register_flag=RegisterFlag.FLOW
|
74
|
+
register_flag=RegisterFlag.FLOW,
|
58
75
|
)
|
59
76
|
),
|
60
77
|
)
|
@@ -72,9 +89,11 @@ class MethodController(TableController):
|
|
72
89
|
except RuntimeError:
|
73
90
|
pass
|
74
91
|
|
75
|
-
return TimeTableEntry(
|
76
|
-
|
77
|
-
|
92
|
+
return TimeTableEntry(
|
93
|
+
start_time=self.get_num(row, RegisterFlag.TIME),
|
94
|
+
organic_modifer=om,
|
95
|
+
flow=flow,
|
96
|
+
)
|
78
97
|
|
79
98
|
def get_timetable(self, rows: int):
|
80
99
|
uncoalesced_timetable_rows = [self.get_row(r + 1) for r in range(rows)]
|
@@ -82,9 +101,11 @@ class MethodController(TableController):
|
|
82
101
|
for row in uncoalesced_timetable_rows:
|
83
102
|
time_key = str(row.start_time)
|
84
103
|
if time_key not in timetable_rows.keys():
|
85
|
-
timetable_rows[time_key] = TimeTableEntry(
|
86
|
-
|
87
|
-
|
104
|
+
timetable_rows[time_key] = TimeTableEntry(
|
105
|
+
start_time=row.start_time,
|
106
|
+
flow=row.flow,
|
107
|
+
organic_modifer=row.organic_modifer,
|
108
|
+
)
|
88
109
|
else:
|
89
110
|
if row.flow:
|
90
111
|
timetable_rows[time_key].flow = row.flow
|
@@ -102,11 +123,13 @@ class MethodController(TableController):
|
|
102
123
|
params = self.get_method_params()
|
103
124
|
stop_time = self.get_stop_time()
|
104
125
|
post_time = self.get_post_time()
|
105
|
-
self.table_state = MethodDetails(
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
126
|
+
self.table_state = MethodDetails(
|
127
|
+
name=method_name,
|
128
|
+
timetable=timetable_rows,
|
129
|
+
stop_time=stop_time,
|
130
|
+
post_time=post_time,
|
131
|
+
params=params,
|
132
|
+
)
|
110
133
|
return self.table_state
|
111
134
|
else:
|
112
135
|
raise RuntimeError(rows.err_value)
|
@@ -121,13 +144,21 @@ class MethodController(TableController):
|
|
121
144
|
return self.controller.get_num_val(
|
122
145
|
cmd=TableOperation.GET_OBJ_HDR_VAL.value.format(
|
123
146
|
register=self.table_locator.register,
|
124
|
-
register_flag=RegisterFlag.POST_TIME
|
147
|
+
register_flag=RegisterFlag.POST_TIME,
|
148
|
+
)
|
149
|
+
)
|
125
150
|
|
126
151
|
def get_stop_time(self) -> Union[int, float]:
|
127
152
|
return self.controller.get_num_val(
|
128
153
|
cmd=TableOperation.GET_OBJ_HDR_VAL.value.format(
|
129
154
|
register=self.table_locator.register,
|
130
|
-
register_flag=RegisterFlag.MAX_TIME
|
155
|
+
register_flag=RegisterFlag.MAX_TIME,
|
156
|
+
)
|
157
|
+
)
|
158
|
+
|
159
|
+
def get_total_runtime(self) -> Union[int, float]:
|
160
|
+
"""Returns total method runtime in minutes."""
|
161
|
+
return self.get_post_time() + self.get_stop_time()
|
131
162
|
|
132
163
|
def current_method(self, method_name: str):
|
133
164
|
"""
|
@@ -152,7 +183,11 @@ class MethodController(TableController):
|
|
152
183
|
:raise AssertionError: The desired method is not selected. Try again.
|
153
184
|
"""
|
154
185
|
method_dir = self.src if not alt_method_dir else alt_method_dir
|
155
|
-
self.send(
|
186
|
+
self.send(
|
187
|
+
Command.SWITCH_METHOD_CMD_SPECIFIC.value.format(
|
188
|
+
method_dir=method_dir, method_name=method_name
|
189
|
+
)
|
190
|
+
)
|
156
191
|
|
157
192
|
time.sleep(2)
|
158
193
|
self.send(Command.GET_METHOD_CMD)
|
@@ -173,9 +208,16 @@ class MethodController(TableController):
|
|
173
208
|
:raises FileNotFoundError: Method does not exist
|
174
209
|
:return: method details
|
175
210
|
"""
|
211
|
+
warnings.warn("This method is not actively maintained.")
|
176
212
|
method_folder = f"{method_name}.M"
|
177
|
-
method_path = os.path.join(
|
178
|
-
|
213
|
+
method_path = os.path.join(
|
214
|
+
self.src, method_folder, "AgilentPumpDriver1.RapidControl.MethodXML.xml"
|
215
|
+
)
|
216
|
+
dad_path = os.path.join(
|
217
|
+
self.src,
|
218
|
+
method_folder,
|
219
|
+
"Agilent1200erDadDriver1.RapidControl.MethodXML.xml",
|
220
|
+
)
|
179
221
|
|
180
222
|
if os.path.exists(os.path.join(self.src, f"{method_name}.M")):
|
181
223
|
parser = XmlParser()
|
@@ -183,25 +225,29 @@ class MethodController(TableController):
|
|
183
225
|
dad = parser.parse(dad_path, DadMethod)
|
184
226
|
|
185
227
|
organic_modifier: Optional[SolventElement] = None
|
186
|
-
aq_modifier: Optional[SolventElement] = None
|
187
228
|
|
188
229
|
if len(method.solvent_composition.solvent_element) == 2:
|
189
230
|
for solvent in method.solvent_composition.solvent_element:
|
190
|
-
if solvent.channel == "
|
191
|
-
aq_modifier = solvent
|
192
|
-
elif solvent.channel == "Channel_B":
|
231
|
+
if solvent.channel == "Channel_B":
|
193
232
|
organic_modifier = solvent
|
194
233
|
|
195
|
-
self.table_state = MethodDetails(
|
196
|
-
|
197
|
-
|
198
|
-
|
199
|
-
|
200
|
-
|
201
|
-
|
202
|
-
|
203
|
-
|
204
|
-
|
234
|
+
self.table_state = MethodDetails(
|
235
|
+
name=method_name,
|
236
|
+
params=HPLCMethodParams(
|
237
|
+
organic_modifier=organic_modifier.percentage, flow=method.flow
|
238
|
+
),
|
239
|
+
stop_time=method.stop_time.stop_time_value,
|
240
|
+
post_time=method.post_time.post_time_value,
|
241
|
+
timetable=[
|
242
|
+
TimeTableEntry(
|
243
|
+
start_time=tte.time,
|
244
|
+
organic_modifer=tte.percent_b,
|
245
|
+
flow=method.flow,
|
246
|
+
)
|
247
|
+
for tte in method.timetable.timetable_entry
|
248
|
+
],
|
249
|
+
dad_wavelengthes=dad.signals.signal,
|
250
|
+
)
|
205
251
|
return self.table_state
|
206
252
|
else:
|
207
253
|
raise FileNotFoundError
|
@@ -213,43 +259,90 @@ class MethodController(TableController):
|
|
213
259
|
:param save: if false only modifies the method, otherwise saves to disk
|
214
260
|
"""
|
215
261
|
self.table_state = updated_method
|
216
|
-
initial_organic_modifier: Param = Param(val=updated_method.params.organic_modifier,
|
217
|
-
chemstation_key=RegisterFlag.SOLVENT_B_COMPOSITION,
|
218
|
-
ptype=PType.NUM)
|
219
|
-
max_time: Param = Param(val=updated_method.stop_time,
|
220
|
-
chemstation_key=RegisterFlag.MAX_TIME,
|
221
|
-
ptype=PType.NUM)
|
222
|
-
post_time: Param = Param(val=updated_method.post_time,
|
223
|
-
chemstation_key=RegisterFlag.POST_TIME,
|
224
|
-
ptype=PType.NUM)
|
225
|
-
flow: Param = Param(val=updated_method.params.flow,
|
226
|
-
chemstation_key=RegisterFlag.FLOW,
|
227
|
-
ptype=PType.NUM)
|
228
|
-
|
229
262
|
# Method settings required for all runs
|
230
|
-
self.update_method_params(
|
231
|
-
|
263
|
+
self.update_method_params(
|
264
|
+
new_flow=updated_method.params.flow,
|
265
|
+
new_initial_om=updated_method.params.organic_modifier,
|
266
|
+
new_stop_time=updated_method.stop_time,
|
267
|
+
new_post_time=updated_method.post_time,
|
268
|
+
)
|
269
|
+
self.edit_method_timetable(updated_method.timetable)
|
232
270
|
|
233
271
|
if save:
|
234
|
-
self.send(
|
235
|
-
|
236
|
-
|
272
|
+
self.send(
|
273
|
+
Command.SAVE_METHOD_CMD.value.format(
|
274
|
+
commit_msg=f"saved method at {str(time.time())}"
|
275
|
+
)
|
276
|
+
)
|
237
277
|
|
238
|
-
def
|
239
|
-
|
278
|
+
def edit_initial_om(self, new_om: Union[int, float]):
|
279
|
+
initial_organic_modifier: Param = Param(
|
280
|
+
val=new_om,
|
281
|
+
chemstation_key=RegisterFlag.SOLVENT_B_COMPOSITION,
|
282
|
+
ptype=PType.NUM,
|
283
|
+
)
|
240
284
|
self._update_param(initial_organic_modifier)
|
285
|
+
|
286
|
+
def edit_flow(self, new_flow: Union[int, float]):
|
287
|
+
flow: Param = Param(
|
288
|
+
val=new_flow, chemstation_key=RegisterFlag.FLOW, ptype=PType.NUM
|
289
|
+
)
|
241
290
|
self._update_param(flow)
|
291
|
+
|
292
|
+
def edit_stop_time(self, new_stop_time: Union[int, float]):
|
293
|
+
stop_time: Param = Param(
|
294
|
+
val=new_stop_time,
|
295
|
+
chemstation_key=RegisterFlag.MAX_TIME,
|
296
|
+
ptype=PType.NUM,
|
297
|
+
)
|
298
|
+
self._update_param(
|
299
|
+
Param(
|
300
|
+
val="Set", chemstation_key=RegisterFlag.STOPTIME_MODE, ptype=PType.STR
|
301
|
+
)
|
302
|
+
)
|
303
|
+
self._update_param(stop_time)
|
304
|
+
|
305
|
+
def edit_post_time(self, new_post_time: Union[int, float]):
|
306
|
+
post_time: Param = Param(
|
307
|
+
val=new_post_time,
|
308
|
+
chemstation_key=RegisterFlag.POST_TIME,
|
309
|
+
ptype=PType.NUM,
|
310
|
+
)
|
311
|
+
self._update_param(
|
312
|
+
Param(val="Set", chemstation_key=RegisterFlag.POSTIME_MODE, ptype=PType.STR)
|
313
|
+
)
|
314
|
+
self._update_param(post_time)
|
315
|
+
|
316
|
+
def update_method_params(
|
317
|
+
self,
|
318
|
+
new_flow: Union[int, float],
|
319
|
+
new_initial_om: Union[int, float],
|
320
|
+
new_stop_time: Union[int, float],
|
321
|
+
new_post_time: Union[int, float],
|
322
|
+
):
|
323
|
+
self.delete_table()
|
324
|
+
self.edit_initial_om(new_initial_om)
|
325
|
+
self.edit_flow(new_flow)
|
242
326
|
if self.table_state.stop_time:
|
243
|
-
self.
|
244
|
-
self._update_param(max_time)
|
327
|
+
self.edit_stop_time(new_stop_time)
|
245
328
|
else:
|
246
|
-
self._update_param(
|
329
|
+
self._update_param(
|
330
|
+
Param(
|
331
|
+
val="Off",
|
332
|
+
chemstation_key=RegisterFlag.STOPTIME_MODE,
|
333
|
+
ptype=PType.STR,
|
334
|
+
)
|
335
|
+
)
|
247
336
|
if self.table_state.post_time:
|
248
|
-
self.
|
249
|
-
self._update_param(post_time)
|
337
|
+
self.edit_post_time(new_post_time)
|
250
338
|
else:
|
251
|
-
self._update_param(
|
252
|
-
|
339
|
+
self._update_param(
|
340
|
+
Param(
|
341
|
+
val="Off",
|
342
|
+
chemstation_key=RegisterFlag.POSTIME_MODE,
|
343
|
+
ptype=PType.STR,
|
344
|
+
)
|
345
|
+
)
|
253
346
|
|
254
347
|
def _update_param(self, method_param: Param):
|
255
348
|
"""Change a method parameter, changes what is visibly seen in Chemstation GUI.
|
@@ -258,34 +351,55 @@ class MethodController(TableController):
|
|
258
351
|
:param method_param: a parameter to update for currently loaded method.
|
259
352
|
"""
|
260
353
|
register = self.table_locator.register
|
261
|
-
setting_command =
|
354
|
+
setting_command = (
|
355
|
+
TableOperation.UPDATE_OBJ_HDR_VAL
|
356
|
+
if method_param.ptype == PType.NUM
|
357
|
+
else TableOperation.UPDATE_OBJ_HDR_TEXT
|
358
|
+
)
|
262
359
|
if isinstance(method_param.chemstation_key, list):
|
263
360
|
for register_flag in method_param.chemstation_key:
|
264
|
-
self.send(
|
265
|
-
|
266
|
-
|
361
|
+
self.send(
|
362
|
+
setting_command.value.format(
|
363
|
+
register=register,
|
364
|
+
register_flag=register_flag,
|
365
|
+
val=method_param.val,
|
366
|
+
)
|
367
|
+
)
|
267
368
|
else:
|
268
|
-
self.send(
|
269
|
-
|
270
|
-
|
369
|
+
self.send(
|
370
|
+
setting_command.value.format(
|
371
|
+
register=register,
|
372
|
+
register_flag=method_param.chemstation_key,
|
373
|
+
val=method_param.val,
|
374
|
+
)
|
375
|
+
)
|
271
376
|
time.sleep(2)
|
377
|
+
self.download()
|
272
378
|
|
273
379
|
def download(self):
|
274
|
-
self.send(
|
380
|
+
self.send("Sleep 1")
|
275
381
|
self.sleepy_send("DownloadRCMethod PMP1")
|
276
|
-
self.send(
|
382
|
+
self.send("Sleep 1")
|
277
383
|
|
278
|
-
def
|
384
|
+
def _edit_row(self, row: TimeTableEntry, first_row: bool = False):
|
279
385
|
if first_row:
|
280
386
|
if row.organic_modifer:
|
281
387
|
self.add_row()
|
282
|
-
self.add_new_col_text(
|
388
|
+
self.add_new_col_text(
|
389
|
+
col_name=RegisterFlag.FUNCTION,
|
390
|
+
val=RegisterFlag.SOLVENT_COMPOSITION.value,
|
391
|
+
)
|
283
392
|
self.add_new_col_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
284
|
-
self.add_new_col_num(
|
393
|
+
self.add_new_col_num(
|
394
|
+
col_name=RegisterFlag.TIMETABLE_SOLVENT_B_COMPOSITION,
|
395
|
+
val=row.organic_modifer,
|
396
|
+
)
|
285
397
|
if row.flow:
|
286
398
|
self.add_row()
|
287
399
|
self.get_num_rows()
|
288
|
-
self._edit_row_text(
|
400
|
+
self._edit_row_text(
|
401
|
+
col_name=RegisterFlag.FUNCTION, val=RegisterFlag.FLOW.value
|
402
|
+
)
|
289
403
|
self.add_new_col_num(col_name=RegisterFlag.TIMETABLE_FLOW, val=row.flow)
|
290
404
|
self._edit_row_num(col_name=RegisterFlag.TIMETABLE_FLOW, val=row.flow)
|
291
405
|
self.download()
|
@@ -293,19 +407,27 @@ class MethodController(TableController):
|
|
293
407
|
if row.organic_modifer:
|
294
408
|
self.add_row()
|
295
409
|
self.get_num_rows()
|
296
|
-
self._edit_row_text(
|
410
|
+
self._edit_row_text(
|
411
|
+
col_name=RegisterFlag.FUNCTION,
|
412
|
+
val=RegisterFlag.SOLVENT_COMPOSITION.value,
|
413
|
+
)
|
297
414
|
self._edit_row_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
298
|
-
self._edit_row_num(
|
415
|
+
self._edit_row_num(
|
416
|
+
col_name=RegisterFlag.TIMETABLE_SOLVENT_B_COMPOSITION,
|
417
|
+
val=row.organic_modifer,
|
418
|
+
)
|
299
419
|
self.download()
|
300
420
|
if row.flow:
|
301
421
|
self.add_row()
|
302
422
|
self.get_num_rows()
|
303
|
-
self._edit_row_text(
|
423
|
+
self._edit_row_text(
|
424
|
+
col_name=RegisterFlag.FUNCTION, val=RegisterFlag.FLOW.value
|
425
|
+
)
|
304
426
|
self._edit_row_num(col_name=RegisterFlag.TIMETABLE_FLOW, val=row.flow)
|
305
427
|
self._edit_row_num(col_name=RegisterFlag.TIME, val=row.start_time)
|
306
428
|
self.download()
|
307
429
|
|
308
|
-
def
|
430
|
+
def edit_method_timetable(self, timetable_rows: List[TimeTableEntry]):
|
309
431
|
self.get_num_rows()
|
310
432
|
self.delete_table()
|
311
433
|
res = self.get_num_rows()
|
@@ -317,7 +439,7 @@ class MethodController(TableController):
|
|
317
439
|
self.get_num_rows()
|
318
440
|
|
319
441
|
for i, row in enumerate(timetable_rows):
|
320
|
-
self.
|
442
|
+
self._edit_row(row=row, first_row=i == 0)
|
321
443
|
|
322
444
|
def stop(self):
|
323
445
|
"""
|
@@ -325,7 +447,12 @@ class MethodController(TableController):
|
|
325
447
|
"""
|
326
448
|
self.send(Command.STOP_METHOD_CMD)
|
327
449
|
|
328
|
-
def run(
|
450
|
+
def run(
|
451
|
+
self,
|
452
|
+
experiment_name: str,
|
453
|
+
add_timestamp: bool = True,
|
454
|
+
stall_while_running: bool = True,
|
455
|
+
):
|
329
456
|
"""
|
330
457
|
:param experiment_name: Name of the experiment
|
331
458
|
:param stall_while_running: whether to stall or immediately return
|
@@ -337,9 +464,19 @@ class MethodController(TableController):
|
|
337
464
|
tries = 0
|
338
465
|
while tries < 10 and not hplc_is_running:
|
339
466
|
timestamp = time.strftime(TIME_FORMAT)
|
340
|
-
self.send(
|
341
|
-
|
342
|
-
|
467
|
+
self.send(
|
468
|
+
Command.RUN_METHOD_CMD.value.format(
|
469
|
+
data_dir=self.data_dirs[0],
|
470
|
+
experiment_name=f"{experiment_name}_{timestamp}"
|
471
|
+
if add_timestamp
|
472
|
+
else experiment_name,
|
473
|
+
)
|
474
|
+
)
|
475
|
+
folder_name = (
|
476
|
+
f"{experiment_name}_{timestamp}.D"
|
477
|
+
if add_timestamp
|
478
|
+
else f"{experiment_name}.D"
|
479
|
+
)
|
343
480
|
hplc_is_running = self.check_hplc_is_running()
|
344
481
|
tries += 1
|
345
482
|
|
@@ -347,35 +484,53 @@ class MethodController(TableController):
|
|
347
484
|
raise RuntimeError("Method failed to start.")
|
348
485
|
|
349
486
|
self.data_files.append(os.path.join(self.data_dirs[0], folder_name))
|
487
|
+
self.timeout = (self.get_total_runtime()) * 60
|
350
488
|
|
351
489
|
if stall_while_running:
|
352
|
-
self.timeout = (self.get_stop_time() + self.get_post_time()) * 60
|
353
490
|
run_completed = self.check_hplc_done_running()
|
354
491
|
if run_completed.is_ok():
|
355
492
|
self.data_files[-1] = run_completed.ok_value
|
356
493
|
else:
|
357
494
|
raise RuntimeError("Run error has occurred.")
|
358
495
|
else:
|
359
|
-
self.data_files[-1]
|
496
|
+
folder = self.fuzzy_match_most_recent_folder(self.data_files[-1])
|
497
|
+
while folder.is_err():
|
498
|
+
folder = self.fuzzy_match_most_recent_folder(self.data_files[-1])
|
499
|
+
if folder.is_ok():
|
500
|
+
self.data_files[-1] = folder.ok_value
|
501
|
+
else:
|
502
|
+
warning = f"Data folder {self.data_files[-1]} may not exist, returning and will check again after run is done."
|
503
|
+
warnings.warn(warning)
|
360
504
|
|
361
505
|
def fuzzy_match_most_recent_folder(self, most_recent_folder: T) -> Result[T, str]:
|
362
506
|
if os.path.exists(most_recent_folder):
|
363
507
|
return Ok(most_recent_folder)
|
364
508
|
return Err("Folder not found!")
|
365
509
|
|
366
|
-
def get_data(
|
367
|
-
|
368
|
-
|
369
|
-
|
370
|
-
|
371
|
-
|
372
|
-
|
373
|
-
|
374
|
-
|
375
|
-
|
510
|
+
def get_data(
|
511
|
+
self, custom_path: Optional[str] = None
|
512
|
+
) -> AgilentChannelChromatogramData:
|
513
|
+
custom_path = custom_path if custom_path else self.data_files[-1]
|
514
|
+
self.get_spectrum_at_channels(custom_path)
|
515
|
+
return AgilentChannelChromatogramData(**self.spectra)
|
516
|
+
|
517
|
+
def get_data_uv(
|
518
|
+
self, custom_path: Optional[str] = None
|
519
|
+
) -> Dict[str, AgilentHPLCChromatogram]:
|
520
|
+
custom_path = custom_path if custom_path else self.data_files[-1]
|
521
|
+
self.get_uv_spectrum(custom_path)
|
522
|
+
return self.uv
|
523
|
+
|
524
|
+
def get_report(
|
525
|
+
self,
|
526
|
+
custom_path: Optional[str] = None,
|
527
|
+
report_type: ReportType = ReportType.TXT,
|
528
|
+
) -> List[AgilentReport]:
|
376
529
|
custom_path = self.data_files[-1] if not custom_path else custom_path
|
377
530
|
metd_report = self.get_report_details(custom_path, report_type)
|
378
|
-
chrom_data: List[AgilentHPLCChromatogram] = list(
|
531
|
+
chrom_data: List[AgilentHPLCChromatogram] = list(
|
532
|
+
self.get_data(custom_path).__dict__.values()
|
533
|
+
)
|
379
534
|
for i, signal in enumerate(metd_report.signals):
|
380
535
|
possible_data = chrom_data[i]
|
381
536
|
if len(possible_data.x) > 0:
|
@@ -2,13 +2,14 @@ from typing import Union
|
|
2
2
|
|
3
3
|
from ....control.controllers import CommunicationController
|
4
4
|
from ....control.controllers.tables.table import TableController
|
5
|
-
from
|
5
|
+
from pychemstation.analysis.chromatogram import AgilentChannelChromatogramData
|
6
6
|
from ....utils.table_types import Table
|
7
7
|
|
8
8
|
|
9
9
|
class MassSpecController(TableController):
|
10
|
-
|
11
|
-
|
10
|
+
def __init__(
|
11
|
+
self, controller: CommunicationController, src: str, data_dir: str, table: Table
|
12
|
+
):
|
12
13
|
super().__init__(controller, src, data_dir, table)
|
13
14
|
|
14
15
|
def get_row(self, row: int):
|
@@ -17,5 +18,7 @@ class MassSpecController(TableController):
|
|
17
18
|
def retrieve_recent_data_files(self):
|
18
19
|
pass
|
19
20
|
|
20
|
-
def get_data(
|
21
|
+
def get_data(
|
22
|
+
self,
|
23
|
+
) -> Union[list[AgilentChannelChromatogramData], AgilentChannelChromatogramData]:
|
21
24
|
pass
|