pychemstation 0.5.4__tar.gz → 0.5.6.dev1__tar.gz

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.
Files changed (40) hide show
  1. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/PKG-INFO +10 -8
  2. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/README.md +10 -8
  3. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/control/__init__.py +0 -1
  4. {pychemstation-0.5.4/pychemstation/control/table → pychemstation-0.5.6.dev1/pychemstation/control/controllers}/__init__.py +1 -0
  5. {pychemstation-0.5.4/pychemstation/control → pychemstation-0.5.6.dev1/pychemstation/control/controllers}/comm.py +2 -2
  6. {pychemstation-0.5.4/pychemstation/control/table → pychemstation-0.5.6.dev1/pychemstation/control/controllers}/method.py +24 -14
  7. {pychemstation-0.5.4/pychemstation/control/table → pychemstation-0.5.6.dev1/pychemstation/control/controllers}/sequence.py +22 -19
  8. {pychemstation-0.5.4/pychemstation/control/table → pychemstation-0.5.6.dev1/pychemstation/control/controllers}/table_controller.py +35 -25
  9. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/control/hplc.py +6 -7
  10. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/chromatogram.py +8 -27
  11. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/PKG-INFO +10 -8
  12. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/SOURCES.txt +5 -5
  13. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/setup.py +1 -1
  14. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/tests/test_comb.py +2 -2
  15. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/LICENSE +0 -0
  16. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/__init__.py +0 -0
  17. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/analysis/__init__.py +0 -0
  18. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/analysis/base_spectrum.py +0 -0
  19. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/analysis/spec_utils.py +0 -0
  20. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/analysis/utils.py +0 -0
  21. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/generated/__init__.py +0 -0
  22. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/generated/dad_method.py +0 -0
  23. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/generated/pump_method.py +0 -0
  24. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/__init__.py +0 -0
  25. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/macro.py +0 -0
  26. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/method_types.py +0 -0
  27. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/parsing.py +0 -0
  28. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/sequence_types.py +0 -0
  29. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/table_types.py +0 -0
  30. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation/utils/tray_types.py +0 -0
  31. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/dependency_links.txt +0 -0
  32. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/requires.txt +0 -0
  33. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pychemstation.egg-info/top_level.txt +0 -0
  34. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/pyproject.toml +0 -0
  35. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/setup.cfg +0 -0
  36. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/tests/__init__.py +0 -0
  37. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/tests/constants.py +0 -0
  38. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/tests/test_comm.py +0 -0
  39. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/tests/test_method.py +0 -0
  40. {pychemstation-0.5.4 → pychemstation-0.5.6.dev1}/tests/test_sequence.py +0 -0
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pychemstation
3
- Version: 0.5.4
3
+ Version: 0.5.6.dev1
4
4
  Summary: Library to interact with Chemstation software, primarily used in Hein lab
5
5
  Home-page: https://gitlab.com/heingroup/device-api/pychemstation
6
6
  Author: Lucy Hao
@@ -41,7 +41,7 @@ pip install pychemstation
41
41
  where you will put your
42
42
  MACRO file(s).
43
43
  3. Download the [
44
- `hplc_talk.mac`](https://github.com/croningp/analyticallabware/blob/master/AnalyticalLabware/devices/Agilent/hplctalk.mac).
44
+ `hplc_talk.mac`](https://gitlab.com/heingroup/device-api/pychemstation/-/blob/main/tests/hplc_talk.mac).
45
45
  - On line 69, change the path name up to `\cmd` and `\reply`. For instance, you should have:
46
46
  `MonitorFile "[my path]\cmd", "[my path]\reply"`
47
47
  - and then add this file to the folder from the previous step.
@@ -78,13 +78,12 @@ hplc_controller = HPLCController(data_dir=DATA_DIR,
78
78
  hplc_controller.preprun()
79
79
  hplc_controller.switch_method(method_name=DEFAULT_METHOD)
80
80
  hplc_controller.run_method(experiment_name="Run 10")
81
- data_status_valid, chrom = hplc_controller.get_last_run_method_data()
81
+ chrom = hplc_controller.get_last_run_method_data()
82
82
 
83
- if data_status_valid:
84
- # afterwards, save, analyze or plot the data!
85
- values = {"x": chrom.x, "y": chrom.y}
86
- chromatogram_data = pd.DataFrame.from_dict(values)
87
- chromatogram_data.to_csv("Run 10.csv", index=False)
83
+ # afterwards, save, analyze or plot the data!
84
+ values = {"x": chrom.A.x, "y": chrom.A.y}
85
+ chromatogram_data = pd.DataFrame.from_dict(values)
86
+ chromatogram_data.to_csv("Run 10.csv", index=False)
88
87
  ```
89
88
 
90
89
  ## Adding your own MACROs
@@ -103,3 +102,6 @@ Lucy Hao
103
102
 
104
103
  - Adapted from [**AnalyticalLabware**](https://github.com/croningp/analyticallabware), created by members in the Cronin
105
104
  Group. Copyright © Cronin Group, used under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license.
105
+ - Adapted from the [MACROS](https://github.com/Bourne-Group/HPLCMethodOptimisationGUI)
106
+ used in [**Operator-free HPLC automated method development guided by Bayesian optimization**](https://pubs.rsc.org/en/content/articlelanding/2024/dd/d4dd00062e),
107
+ created by members in the Bourne Group. Copyright © Bourne Group, used under the [MIT](https://opensource.org/license/mit) license.
@@ -25,7 +25,7 @@ pip install pychemstation
25
25
  where you will put your
26
26
  MACRO file(s).
27
27
  3. Download the [
28
- `hplc_talk.mac`](https://github.com/croningp/analyticallabware/blob/master/AnalyticalLabware/devices/Agilent/hplctalk.mac).
28
+ `hplc_talk.mac`](https://gitlab.com/heingroup/device-api/pychemstation/-/blob/main/tests/hplc_talk.mac).
29
29
  - On line 69, change the path name up to `\cmd` and `\reply`. For instance, you should have:
30
30
  `MonitorFile "[my path]\cmd", "[my path]\reply"`
31
31
  - and then add this file to the folder from the previous step.
@@ -62,13 +62,12 @@ hplc_controller = HPLCController(data_dir=DATA_DIR,
62
62
  hplc_controller.preprun()
63
63
  hplc_controller.switch_method(method_name=DEFAULT_METHOD)
64
64
  hplc_controller.run_method(experiment_name="Run 10")
65
- data_status_valid, chrom = hplc_controller.get_last_run_method_data()
65
+ chrom = hplc_controller.get_last_run_method_data()
66
66
 
67
- if data_status_valid:
68
- # afterwards, save, analyze or plot the data!
69
- values = {"x": chrom.x, "y": chrom.y}
70
- chromatogram_data = pd.DataFrame.from_dict(values)
71
- chromatogram_data.to_csv("Run 10.csv", index=False)
67
+ # afterwards, save, analyze or plot the data!
68
+ values = {"x": chrom.A.x, "y": chrom.A.y}
69
+ chromatogram_data = pd.DataFrame.from_dict(values)
70
+ chromatogram_data.to_csv("Run 10.csv", index=False)
72
71
  ```
73
72
 
74
73
  ## Adding your own MACROs
@@ -86,4 +85,7 @@ our [GitLab](https://gitlab.com/heingroup/device-api/pychemstation)!
86
85
  Lucy Hao
87
86
 
88
87
  - Adapted from [**AnalyticalLabware**](https://github.com/croningp/analyticallabware), created by members in the Cronin
89
- Group. Copyright © Cronin Group, used under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license.
88
+ Group. Copyright © Cronin Group, used under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license.
89
+ - Adapted from the [MACROS](https://github.com/Bourne-Group/HPLCMethodOptimisationGUI)
90
+ used in [**Operator-free HPLC automated method development guided by Bayesian optimization**](https://pubs.rsc.org/en/content/articlelanding/2024/dd/d4dd00062e),
91
+ created by members in the Bourne Group. Copyright © Bourne Group, used under the [MIT](https://opensource.org/license/mit) license.
@@ -1,5 +1,4 @@
1
1
  """
2
2
  .. include:: README.md
3
3
  """
4
- from .comm import CommunicationController
5
4
  from .hplc import HPLCController
@@ -1,3 +1,4 @@
1
1
  from .method import MethodController
2
2
  from .sequence import SequenceController
3
3
  from .table_controller import TableController
4
+ from .comm import CommunicationController
@@ -14,8 +14,8 @@ import os
14
14
  import time
15
15
 
16
16
  from result import Result, Ok, Err
17
- from ..utils.macro import *
18
- from ..utils.method_types import *
17
+
18
+ from ...utils.macro import *
19
19
 
20
20
 
21
21
  class CommunicationController:
@@ -1,13 +1,13 @@
1
1
  import os
2
2
  import time
3
- from typing import Optional, Any
3
+ from typing import Optional
4
4
 
5
5
  from xsdata.formats.dataclass.parsers import XmlParser
6
6
 
7
- from .. import CommunicationController
8
- from ...control.table.table_controller import TableController
7
+ from ...control.controllers.table_controller import TableController
8
+ from ...control.controllers.comm import CommunicationController
9
9
  from ...generated import PumpMethod, DadMethod, SolventElement
10
- from ...utils.chromatogram import TIME_FORMAT, AgilentHPLCChromatogram
10
+ from ...utils.chromatogram import TIME_FORMAT, AgilentChannelChromatogramData
11
11
  from ...utils.macro import Command
12
12
  from ...utils.method_types import PType, TimeTableEntry, Param, MethodTimetable, HPLCMethodParams
13
13
  from ...utils.table_types import RegisterFlag, TableOperation, Table
@@ -51,9 +51,10 @@ class MethodController(TableController):
51
51
  rows = self.get_num_rows()
52
52
  if rows.is_ok():
53
53
  timetable_rows = [self.get_row(r + 1) for r in range(int(rows.ok_value.num_response))]
54
- return MethodTimetable(
54
+ self.table_state = MethodTimetable(
55
55
  first_row=self.get_method_params(),
56
56
  subsequent_rows=timetable_rows)
57
+ return self.table_state
57
58
  else:
58
59
  raise RuntimeError(rows.err_value)
59
60
 
@@ -88,6 +89,7 @@ class MethodController(TableController):
88
89
  if res.is_ok():
89
90
  parsed_response = res.ok_value.string_response
90
91
  assert parsed_response == f"{method_name}.M", "Switching Methods failed."
92
+ self.table_state = None
91
93
 
92
94
  def load_from_disk(self, method_name: str) -> MethodTimetable:
93
95
  """
@@ -118,7 +120,7 @@ class MethodController(TableController):
118
120
  elif solvent.channel == "Channel_B":
119
121
  organic_modifier = solvent
120
122
 
121
- return MethodTimetable(
123
+ self.table_state = MethodTimetable(
122
124
  first_row=HPLCMethodParams(
123
125
  organic_modifier=organic_modifier.percentage,
124
126
  flow=method.flow,
@@ -135,6 +137,7 @@ class MethodController(TableController):
135
137
  organic_modifier=organic_modifier,
136
138
  modifier_a=aq_modifier
137
139
  )
140
+ return self.table_state
138
141
  else:
139
142
  raise FileNotFoundError
140
143
 
@@ -242,7 +245,7 @@ class MethodController(TableController):
242
245
  """
243
246
  self.send(Command.STOP_METHOD_CMD)
244
247
 
245
- def run(self, experiment_name: str):
248
+ def run(self, experiment_name: str, stall_while_running: bool = True):
246
249
  """
247
250
  This is the preferred method to trigger a run.
248
251
  Starts the currently selected method, storing data
@@ -261,14 +264,21 @@ class MethodController(TableController):
261
264
  folder_name = f"{experiment_name}_{timestamp}.D"
262
265
  self.data_files.append(os.path.join(self.data_dir, folder_name))
263
266
 
264
- run_completed = self.check_hplc_done_running()
265
-
266
- if not run_completed.is_ok():
267
- raise RuntimeError("Run did not complete as expected")
267
+ if stall_while_running:
268
+ run_completed = self.check_hplc_done_running(method=self.table_state)
269
+ if run_completed.is_ok():
270
+ self.data_files[-1] = run_completed.value
271
+ else:
272
+ raise RuntimeError("Run error has occurred.")
273
+ else:
274
+ self.data_files[-1].dir = self.fuzzy_match_most_recent_folder(folder_name).ok_value
268
275
 
269
276
  def retrieve_recent_data_files(self) -> str:
270
277
  return self.data_files[-1]
271
278
 
272
- def get_data(self) -> dict[str, AgilentHPLCChromatogram]:
273
- self.get_spectrum(self.data_files[-1])
274
- return self.spectra
279
+ def get_data(self, custom_path: Optional[str] = None) -> AgilentChannelChromatogramData:
280
+ if not custom_path:
281
+ self.get_spectrum(self.data_files[-1])
282
+ else:
283
+ self.get_spectrum(custom_path)
284
+ return AgilentChannelChromatogramData(**self.spectra)
@@ -1,17 +1,15 @@
1
- from typing import Any
1
+ from typing import Optional
2
2
 
3
- from copy import deepcopy
4
3
 
5
4
  import os
6
5
  import time
7
6
 
8
- from .table_controller import TableController
9
- from ...control import CommunicationController
10
- from ...utils.chromatogram import SEQUENCE_TIME_FORMAT, AgilentHPLCChromatogram
7
+ from ...control.controllers.table_controller import TableController
8
+ from ...control.controllers.comm import CommunicationController
9
+ from ...utils.chromatogram import SEQUENCE_TIME_FORMAT, AgilentChannelChromatogramData
11
10
  from ...utils.macro import Command
12
11
  from ...utils.sequence_types import SequenceTable, SequenceEntry, SequenceDataFiles, InjectionSource, SampleType
13
12
  from ...utils.table_types import TableOperation, RegisterFlag, Table
14
- from ...utils.tray_types import TenColumn
15
13
 
16
14
 
17
15
  class SequenceController(TableController):
@@ -29,9 +27,10 @@ class SequenceController(TableController):
29
27
  seq_name = self.receive()
30
28
 
31
29
  if rows.is_ok() and seq_name.is_ok():
32
- return SequenceTable(
30
+ self.table_state = SequenceTable(
33
31
  name=seq_name.ok_value.string_response.partition(".S")[0],
34
32
  rows=[self.get_row(r + 1) for r in range(int(rows.ok_value.num_response))])
33
+ return self.table_state
35
34
  raise RuntimeError(rows.err_value)
36
35
 
37
36
  def get_row(self, row: int) -> SequenceEntry:
@@ -65,6 +64,7 @@ class SequenceController(TableController):
65
64
  parsed_response = self.receive().value.string_response
66
65
 
67
66
  assert parsed_response == f"{seq_name}.S", "Switching sequence failed."
67
+ self.table_state = None
68
68
 
69
69
  def edit(self, sequence_table: SequenceTable):
70
70
  """
@@ -171,7 +171,7 @@ class SequenceController(TableController):
171
171
 
172
172
  self.send(Command.SAVE_SEQUENCE_CMD)
173
173
 
174
- def run(self):
174
+ def run(self, stall_while_running: bool = True):
175
175
  """
176
176
  Starts the currently loaded sequence, storing data
177
177
  under the <data_dir>/<sequence table name> folder.
@@ -186,25 +186,28 @@ class SequenceController(TableController):
186
186
  self.data_files.append(SequenceDataFiles(dir=folder_name,
187
187
  sequence_name=seq_table.name))
188
188
 
189
- run_completed = self.check_hplc_done_running(sequence=seq_table)
190
-
191
- if run_completed.is_ok():
192
- self.data_files[-1].dir = run_completed.value
193
- else:
194
- raise RuntimeError("Run error has occured.")
189
+ if stall_while_running:
190
+ run_completed = self.check_hplc_done_running(sequence=seq_table)
191
+ if run_completed.is_ok():
192
+ self.data_files[-1].dir = run_completed.value
193
+ else:
194
+ raise RuntimeError("Run error has occurred.")
195
+ else:
196
+ self.data_files[-1].dir = self.fuzzy_match_most_recent_folder(folder_name).ok_value
195
197
 
196
198
  def retrieve_recent_data_files(self):
197
199
  sequence_data_files: SequenceDataFiles = self.data_files[-1]
198
200
  return sequence_data_files.dir
199
201
 
200
- def get_data(self) -> list[dict[str, AgilentHPLCChromatogram]]:
201
- parent_dir = self.data_files[-1].dir
202
+ def get_data(self, custom_path:Optional[str] = None ) -> list[AgilentChannelChromatogramData]:
203
+ parent_dir = self.data_files[-1].dir if not custom_path else custom_path
202
204
  subdirs = [x[0] for x in os.walk(self.data_dir)]
203
205
  potential_folders = sorted(list(filter(lambda d: parent_dir in d, subdirs)))
204
- self.data_files[-1].child_dirs = [f for f in potential_folders if parent_dir in f and ".M" not in f and ".D" in f]
206
+ self.data_files[-1].child_dirs = [f for f in potential_folders if
207
+ parent_dir in f and ".M" not in f and ".D" in f]
205
208
 
206
- spectra: list[dict[str, AgilentHPLCChromatogram]] = []
209
+ spectra: list[AgilentChannelChromatogramData] = []
207
210
  for row in self.data_files[-1].child_dirs:
208
211
  self.get_spectrum(row)
209
- spectra.append(deepcopy(self.spectra))
212
+ spectra.append(AgilentChannelChromatogramData(**self.spectra))
210
213
  return spectra
@@ -6,14 +6,13 @@ Authors: Lucy Hao
6
6
 
7
7
  import abc
8
8
  import os
9
- import time
10
9
  from typing import Union, Optional
11
10
 
12
11
  import polling
13
12
  from result import Result, Ok, Err
14
13
 
15
- from ...control import CommunicationController
16
- from ...utils.chromatogram import AgilentHPLCChromatogram
14
+ from ...control.controllers.comm import CommunicationController
15
+ from ...utils.chromatogram import AgilentHPLCChromatogram, AgilentChannelChromatogramData
17
16
  from ...utils.macro import Command, HPLCRunningStatus, Response
18
17
  from ...utils.method_types import MethodTimetable
19
18
  from ...utils.sequence_types import SequenceDataFiles, SequenceTable
@@ -25,6 +24,7 @@ class TableController(abc.ABC):
25
24
  def __init__(self, controller: CommunicationController, src: str, data_dir: str, table: Table):
26
25
  self.controller = controller
27
26
  self.table = table
27
+ self.table_state : Optional[TableController] = None
28
28
 
29
29
  if os.path.isdir(src):
30
30
  self.src: str = src
@@ -120,7 +120,7 @@ class TableController(abc.ABC):
120
120
  self.send(TableOperation.CREATE_TABLE.value.format(register=self.table.register,
121
121
  table_name=self.table.name))
122
122
 
123
- def get_num_rows(self) -> Result[int, str]:
123
+ def get_num_rows(self) -> Result[Response, str]:
124
124
  self.send(TableOperation.GET_NUM_ROWS.value.format(register=self.table.register,
125
125
  table_name=self.table.name,
126
126
  col_name=RegisterFlag.NUM_ROWS))
@@ -139,8 +139,8 @@ class TableController(abc.ABC):
139
139
  def check_hplc_is_running(self) -> bool:
140
140
  started_running = polling.poll(
141
141
  lambda: isinstance(self.controller.get_status(), HPLCRunningStatus),
142
- step=30,
143
- max_tries=10)
142
+ step=5,
143
+ max_tries=100)
144
144
  return started_running
145
145
 
146
146
  def check_hplc_done_running(self,
@@ -154,7 +154,7 @@ class TableController(abc.ABC):
154
154
  """
155
155
  timeout = 10 * 60
156
156
  if method:
157
- timeout = ((method.first_row.maximum_run_time + 2) * 60)
157
+ timeout = ((method.first_row.maximum_run_time + 5) * 60)
158
158
  if sequence:
159
159
  timeout *= len(sequence.rows)
160
160
 
@@ -162,32 +162,42 @@ class TableController(abc.ABC):
162
162
  finished_run = polling.poll(
163
163
  lambda: self.controller.check_if_running(),
164
164
  timeout=timeout,
165
- step=60
166
- )
167
-
168
- if finished_run:
169
- if os.path.exists(most_recent_folder):
170
- return Ok(most_recent_folder)
171
- else:
172
- subdirs = [x[0] for x in os.walk(self.data_dir)]
173
- potential_folders = sorted(list(filter(lambda d: most_recent_folder in d, subdirs)))
174
- parent_dirs = []
175
- for folder in potential_folders:
176
- path = os.path.normpath(folder)
177
- split_folder = path.split(os.sep)
178
- if most_recent_folder in split_folder[-1]:
179
- parent_dirs.append(folder)
180
- parent_dir = sorted(parent_dirs, reverse=True)[0]
181
- return Ok(parent_dir)
165
+ step=18)
166
+
167
+ check_folder = self.fuzzy_match_most_recent_folder(most_recent_folder)
168
+ if check_folder.is_ok() and finished_run:
169
+ return check_folder
170
+ elif check_folder.is_ok():
171
+ finished_run = polling.poll(
172
+ lambda: self.controller.check_if_running(),
173
+ timeout=timeout,
174
+ step=12)
175
+ if finished_run:
176
+ return check_folder
182
177
  else:
183
178
  return Err("Run did not complete as expected")
184
179
 
180
+ def fuzzy_match_most_recent_folder(self, most_recent_folder) -> Result[str, str]:
181
+ if os.path.exists(most_recent_folder):
182
+ return Ok(most_recent_folder)
183
+
184
+ subdirs = [x[0] for x in os.walk(self.data_dir)]
185
+ potential_folders = sorted(list(filter(lambda d: most_recent_folder in d, subdirs)))
186
+ parent_dirs = []
187
+ for folder in potential_folders:
188
+ path = os.path.normpath(folder)
189
+ split_folder = path.split(os.sep)
190
+ if most_recent_folder in split_folder[-1]:
191
+ parent_dirs.append(folder)
192
+ parent_dir = sorted(parent_dirs, reverse=True)[0]
193
+ return Ok(parent_dir)
194
+
185
195
  @abc.abstractmethod
186
196
  def retrieve_recent_data_files(self):
187
197
  pass
188
198
 
189
199
  @abc.abstractmethod
190
- def get_data(self) -> tuple[bool,]:
200
+ def get_data(self) -> Union[list[AgilentChannelChromatogramData], AgilentChannelChromatogramData]:
191
201
  pass
192
202
 
193
203
  def get_spectrum(self, data_file: str):
@@ -6,9 +6,8 @@ Authors: Lucy Hao
6
6
 
7
7
  from typing import Union, Optional
8
8
 
9
- from ..control import CommunicationController
10
- from ..control.table import MethodController, SequenceController
11
- from ..utils.chromatogram import AgilentHPLCChromatogram
9
+ from ..control.controllers import MethodController, SequenceController, CommunicationController
10
+ from ..utils.chromatogram import AgilentHPLCChromatogram, AgilentChannelChromatogramData
12
11
  from ..utils.macro import Command, HPLCRunningStatus, HPLCAvailStatus, HPLCErrorStatus, Response
13
12
  from ..utils.method_types import MethodTimetable
14
13
  from ..utils.sequence_types import SequenceTable, SequenceEntry
@@ -65,8 +64,8 @@ class HPLCController:
65
64
  only 'General-Poroshell' is needed.
66
65
 
67
66
  :param method_name: any available method in Chemstation method directory
68
- :raise IndexError: Response did not have expected format. Try again.
69
- :raise AssertionError: The desired method is not selected. Try again.
67
+ :raises IndexError: Response did not have expected format. Try again.
68
+ :raises AssertionError: The desired method is not selected. Try again.
70
69
  """
71
70
  self.method_controller.switch(method_name)
72
71
 
@@ -127,13 +126,13 @@ class HPLCController:
127
126
  """
128
127
  self.sequence_controller.edit_row(row, num)
129
128
 
130
- def get_last_run_method_data(self) -> dict[str, AgilentHPLCChromatogram]:
129
+ def get_last_run_method_data(self) -> AgilentChannelChromatogramData:
131
130
  """
132
131
  Returns the last run method data.
133
132
  """
134
133
  return self.method_controller.get_data()
135
134
 
136
- def get_last_run_sequence_data(self) -> list[dict[str, AgilentHPLCChromatogram]]:
135
+ def get_last_run_sequence_data(self) -> list[AgilentChannelChromatogramData]:
137
136
  """
138
137
  Returns data for all rows in the last run sequence data.
139
138
  """
@@ -1,17 +1,14 @@
1
1
  """Module for HPLC chromatogram data loading and manipulating"""
2
2
 
3
3
  import os
4
- import logging
5
4
  import time
5
+ from dataclasses import dataclass
6
6
 
7
7
  import numpy as np
8
8
 
9
9
  from .parsing import CHFile
10
10
  from ..analysis import AbstractSpectrum
11
11
 
12
- # Chemstation data path
13
- DATA_DIR = r"C:\Chem32\1\Data"
14
-
15
12
  # standard filenames for spectral data
16
13
  CHANNELS = {"A": "01", "B": "02", "C": "03", "D": "04"}
17
14
 
@@ -19,7 +16,7 @@ ACQUISITION_PARAMETERS = "acq.txt"
19
16
 
20
17
  # format used in acquisition parameters
21
18
  TIME_FORMAT = "%Y-%m-%d %H-%M-%S"
22
- SEQUENCE_TIME_FORMAT = "%Y-%m-%d %H"
19
+ SEQUENCE_TIME_FORMAT = "%Y-%m-%d %H-%M"
23
20
 
24
21
 
25
22
  class AgilentHPLCChromatogram(AbstractSpectrum):
@@ -105,26 +102,10 @@ class AgilentHPLCChromatogram(AbstractSpectrum):
105
102
  np.savez_compressed(npz_file, times=data.times, values=data.values)
106
103
  return np.array(data.times), np.array(data.values)
107
104
 
108
- def extract_peakarea(self, experiment_dir: str):
109
- """
110
- Reads processed data from Chemstation report files.
111
105
 
112
- Args:
113
- experiment_dir: .D directory with the report files
114
- """
115
- # filename = os.path.join(experiment_dir, f"REPORT{CHANNELS[channel]}.csv")
116
- # TODO parse file properly
117
- # data = np.genfromtxt(filename, delimiter=',')
118
- # return data
119
- pass
120
-
121
- def default_processing(self):
122
- """
123
- Processes the chromatogram in place.
124
- """
125
- # trim first 5 min and last 3 min of run
126
- self.trim(5, 25)
127
- # parameters found to work best for chromatogram data
128
- self.correct_baseline(lmbd=1e5, p=0.0001, n_iter=10)
129
- # get all peaks in processed chromatogram
130
- self.find_peaks()
106
+ @dataclass
107
+ class AgilentChannelChromatogramData:
108
+ A: AgilentHPLCChromatogram
109
+ B: AgilentHPLCChromatogram
110
+ C: AgilentHPLCChromatogram
111
+ D: AgilentHPLCChromatogram
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.1
2
2
  Name: pychemstation
3
- Version: 0.5.4
3
+ Version: 0.5.6.dev1
4
4
  Summary: Library to interact with Chemstation software, primarily used in Hein lab
5
5
  Home-page: https://gitlab.com/heingroup/device-api/pychemstation
6
6
  Author: Lucy Hao
@@ -41,7 +41,7 @@ pip install pychemstation
41
41
  where you will put your
42
42
  MACRO file(s).
43
43
  3. Download the [
44
- `hplc_talk.mac`](https://github.com/croningp/analyticallabware/blob/master/AnalyticalLabware/devices/Agilent/hplctalk.mac).
44
+ `hplc_talk.mac`](https://gitlab.com/heingroup/device-api/pychemstation/-/blob/main/tests/hplc_talk.mac).
45
45
  - On line 69, change the path name up to `\cmd` and `\reply`. For instance, you should have:
46
46
  `MonitorFile "[my path]\cmd", "[my path]\reply"`
47
47
  - and then add this file to the folder from the previous step.
@@ -78,13 +78,12 @@ hplc_controller = HPLCController(data_dir=DATA_DIR,
78
78
  hplc_controller.preprun()
79
79
  hplc_controller.switch_method(method_name=DEFAULT_METHOD)
80
80
  hplc_controller.run_method(experiment_name="Run 10")
81
- data_status_valid, chrom = hplc_controller.get_last_run_method_data()
81
+ chrom = hplc_controller.get_last_run_method_data()
82
82
 
83
- if data_status_valid:
84
- # afterwards, save, analyze or plot the data!
85
- values = {"x": chrom.x, "y": chrom.y}
86
- chromatogram_data = pd.DataFrame.from_dict(values)
87
- chromatogram_data.to_csv("Run 10.csv", index=False)
83
+ # afterwards, save, analyze or plot the data!
84
+ values = {"x": chrom.A.x, "y": chrom.A.y}
85
+ chromatogram_data = pd.DataFrame.from_dict(values)
86
+ chromatogram_data.to_csv("Run 10.csv", index=False)
88
87
  ```
89
88
 
90
89
  ## Adding your own MACROs
@@ -103,3 +102,6 @@ Lucy Hao
103
102
 
104
103
  - Adapted from [**AnalyticalLabware**](https://github.com/croningp/analyticallabware), created by members in the Cronin
105
104
  Group. Copyright © Cronin Group, used under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license.
105
+ - Adapted from the [MACROS](https://github.com/Bourne-Group/HPLCMethodOptimisationGUI)
106
+ used in [**Operator-free HPLC automated method development guided by Bayesian optimization**](https://pubs.rsc.org/en/content/articlelanding/2024/dd/d4dd00062e),
107
+ created by members in the Bourne Group. Copyright © Bourne Group, used under the [MIT](https://opensource.org/license/mit) license.
@@ -13,12 +13,12 @@ pychemstation/analysis/base_spectrum.py
13
13
  pychemstation/analysis/spec_utils.py
14
14
  pychemstation/analysis/utils.py
15
15
  pychemstation/control/__init__.py
16
- pychemstation/control/comm.py
17
16
  pychemstation/control/hplc.py
18
- pychemstation/control/table/__init__.py
19
- pychemstation/control/table/method.py
20
- pychemstation/control/table/sequence.py
21
- pychemstation/control/table/table_controller.py
17
+ pychemstation/control/controllers/__init__.py
18
+ pychemstation/control/controllers/comm.py
19
+ pychemstation/control/controllers/method.py
20
+ pychemstation/control/controllers/sequence.py
21
+ pychemstation/control/controllers/table_controller.py
22
22
  pychemstation/generated/__init__.py
23
23
  pychemstation/generated/dad_method.py
24
24
  pychemstation/generated/pump_method.py
@@ -5,7 +5,7 @@ with open("README.md", "r") as fh:
5
5
 
6
6
  setuptools.setup(
7
7
  name="pychemstation",
8
- version="0.5.4",
8
+ version="0.5.6.dev1",
9
9
  author="Lucy Hao",
10
10
  author_email="lhao03@student.ubc.ca",
11
11
  description="Library to interact with Chemstation software, primarily used in Hein lab",
@@ -28,14 +28,14 @@ class TestCombinations(unittest.TestCase):
28
28
  first_row=HPLCMethodParams(
29
29
  organic_modifier=5,
30
30
  flow=0.65,
31
- maximum_run_time=2),
31
+ maximum_run_time=1),
32
32
  subsequent_rows=[
33
33
  TimeTableEntry(
34
34
  start_time=0.10,
35
35
  organic_modifer=5,
36
36
  flow=0.34),
37
37
  TimeTableEntry(
38
- start_time=1,
38
+ start_time=0.5,
39
39
  organic_modifer=98,
40
40
  flow=0.55)])
41
41
  self.hplc_controller.edit_method(rand_method, save=True)