pychemstation 0.8.3__py3-none-any.whl → 0.10.0__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/__init__.py +4 -0
- pychemstation/analysis/base_spectrum.py +9 -9
- pychemstation/analysis/process_report.py +13 -7
- pychemstation/analysis/utils.py +1 -3
- pychemstation/control/__init__.py +4 -0
- pychemstation/control/comm.py +206 -0
- pychemstation/control/controllers/__init__.py +6 -0
- pychemstation/control/controllers/comm.py +12 -5
- pychemstation/control/controllers/devices/column.py +12 -0
- pychemstation/control/controllers/devices/dad.py +0 -0
- pychemstation/control/controllers/devices/device.py +10 -7
- pychemstation/control/controllers/devices/injector.py +18 -84
- pychemstation/control/controllers/devices/pump.py +43 -0
- pychemstation/control/controllers/method.py +338 -0
- pychemstation/control/controllers/sequence.py +190 -0
- pychemstation/control/controllers/table_controller.py +266 -0
- pychemstation/control/controllers/tables/method.py +35 -13
- pychemstation/control/controllers/tables/sequence.py +46 -37
- pychemstation/control/controllers/tables/table.py +46 -30
- pychemstation/control/hplc.py +27 -11
- pychemstation/control/table/__init__.py +3 -0
- pychemstation/control/table/method.py +274 -0
- pychemstation/control/table/sequence.py +210 -0
- pychemstation/control/table/table_controller.py +201 -0
- pychemstation/generated/dad_method.py +1 -1
- pychemstation/generated/pump_method.py +1 -1
- pychemstation/utils/chromatogram.py +2 -5
- pychemstation/utils/injector_types.py +1 -1
- pychemstation/utils/macro.py +3 -3
- pychemstation/utils/method_types.py +2 -2
- pychemstation/utils/num_utils.py +65 -0
- pychemstation/utils/parsing.py +1 -0
- pychemstation/utils/sequence_types.py +3 -3
- pychemstation/utils/spec_utils.py +304 -0
- {pychemstation-0.8.3.dist-info → pychemstation-0.10.0.dist-info}/METADATA +19 -8
- pychemstation-0.10.0.dist-info/RECORD +62 -0
- {pychemstation-0.8.3.dist-info → pychemstation-0.10.0.dist-info}/WHEEL +2 -1
- pychemstation-0.10.0.dist-info/top_level.txt +2 -0
- tests/__init__.py +0 -0
- tests/constants.py +134 -0
- tests/test_comb.py +136 -0
- tests/test_comm.py +65 -0
- tests/test_inj.py +39 -0
- tests/test_method.py +99 -0
- tests/test_nightly.py +80 -0
- tests/test_offline_stable.py +69 -0
- tests/test_online_stable.py +275 -0
- tests/test_proc_rep.py +52 -0
- tests/test_runs_stable.py +225 -0
- tests/test_sequence.py +125 -0
- tests/test_stable.py +276 -0
- pychemstation/control/README.md +0 -124
- pychemstation/control/controllers/README.md +0 -1
- pychemstation-0.8.3.dist-info/RECORD +0 -37
- {pychemstation-0.8.3.dist-info → pychemstation-0.10.0.dist-info}/licenses/LICENSE +0 -0
@@ -0,0 +1,304 @@
|
|
1
|
+
"""
|
2
|
+
Module contains various utility function for spectral data processing and
|
3
|
+
analysis.
|
4
|
+
"""
|
5
|
+
|
6
|
+
import numpy as np
|
7
|
+
import scipy
|
8
|
+
|
9
|
+
from ..utils.num_utils import find_nearest_value_index
|
10
|
+
|
11
|
+
|
12
|
+
def create_binary_peak_map(data):
|
13
|
+
"""Return binary map of the peaks within data points.
|
14
|
+
|
15
|
+
True values are assigned to potential peak points, False - to baseline.
|
16
|
+
|
17
|
+
Args:
|
18
|
+
data (:obj:np.array): 1D array with data points.
|
19
|
+
|
20
|
+
Returns:
|
21
|
+
:obj:np.array, dtype=bool: Mapping of data points, where True is
|
22
|
+
potential peak region point, False - baseline.
|
23
|
+
"""
|
24
|
+
# copying array
|
25
|
+
data_c = np.copy(data)
|
26
|
+
|
27
|
+
# placeholder for the peak mapping
|
28
|
+
peak_map = np.full_like(data_c, False, dtype=bool)
|
29
|
+
|
30
|
+
for _ in range(100500): # shouldn't take more iterations
|
31
|
+
|
32
|
+
# looking for peaks
|
33
|
+
peaks_found = np.logical_or(
|
34
|
+
data_c > np.mean(data_c) + np.std(data_c) * 3,
|
35
|
+
data_c < np.mean(data_c) - np.std(data_c) * 3,
|
36
|
+
)
|
37
|
+
|
38
|
+
# merging with peak mapping
|
39
|
+
np.logical_or(peak_map, peaks_found, out=peak_map)
|
40
|
+
|
41
|
+
# if no peaks found - break
|
42
|
+
if not peaks_found.any():
|
43
|
+
break
|
44
|
+
|
45
|
+
# setting values to 0 and iterating again
|
46
|
+
data_c[peaks_found] = 0
|
47
|
+
|
48
|
+
return peak_map
|
49
|
+
|
50
|
+
|
51
|
+
def combine_map_to_regions(mapping):
|
52
|
+
"""Combine True values into their indexes arrays.
|
53
|
+
|
54
|
+
Args:
|
55
|
+
mapping (:obj:np.array): Boolean mapping array to extract the indexes
|
56
|
+
from.
|
57
|
+
|
58
|
+
Returns:
|
59
|
+
:obj:np.array: 2D array with left and right borders of regions, where
|
60
|
+
mapping is True.
|
61
|
+
|
62
|
+
Example:
|
63
|
+
>>> combine_map_to_regions(np.array([True, True, False, True, False]))
|
64
|
+
array([[0, 1],
|
65
|
+
[3, 3]])
|
66
|
+
"""
|
67
|
+
|
68
|
+
# No peaks identified, i.e. mapping is all False
|
69
|
+
if not mapping.any():
|
70
|
+
return np.array([], dtype="int64")
|
71
|
+
|
72
|
+
# region borders
|
73
|
+
region_borders = np.diff(mapping)
|
74
|
+
|
75
|
+
# corresponding indexes
|
76
|
+
border_indexes = np.argwhere(region_borders)
|
77
|
+
|
78
|
+
lefts = border_indexes[::2] + 1 # because diff was used to get the index
|
79
|
+
|
80
|
+
# edge case, where first peak doesn't have left border
|
81
|
+
if mapping[border_indexes][0]:
|
82
|
+
# just preppend 0 as first left border
|
83
|
+
# mind the vstack, as np.argwhere produces a vector array
|
84
|
+
lefts = np.vstack((0, lefts))
|
85
|
+
|
86
|
+
rights = border_indexes[1::2]
|
87
|
+
|
88
|
+
# another edge case, where last peak doesn't have a right border
|
89
|
+
if mapping[-1]: # True if last point identified as potential peak
|
90
|
+
# just append -1 as last peak right border
|
91
|
+
rights = np.vstack((rights, -1))
|
92
|
+
|
93
|
+
# columns as borders, rows as regions, i.e.
|
94
|
+
# :output:[0] -> first peak region
|
95
|
+
return np.hstack((lefts, rights))
|
96
|
+
|
97
|
+
|
98
|
+
def filter_regions(x_data, peaks_regions):
|
99
|
+
"""Filter peak regions.
|
100
|
+
|
101
|
+
Peak regions are filtered to remove potential false positives (e.g. noise
|
102
|
+
spikes).
|
103
|
+
|
104
|
+
Args:
|
105
|
+
x_data (:obj:np.array): X data points, needed to pick up the data
|
106
|
+
resolution and map the region indexes to the corresponding data
|
107
|
+
points.
|
108
|
+
y_data (:obj:np.array): Y data points, needed to validate if the peaks
|
109
|
+
are actually present in the region and remove invalid regions.
|
110
|
+
peaks_regions (:obj:np.array): 2D Nx2 array with peak regions indexes
|
111
|
+
(rows) as left and right borders (columns).
|
112
|
+
|
113
|
+
Returns:
|
114
|
+
:obj:np.array: 2D Mx2 array with filtered peak regions indexes(rows) as
|
115
|
+
left and right borders (columns).
|
116
|
+
"""
|
117
|
+
|
118
|
+
# filter peaks where region is smaller than spectrum resolution
|
119
|
+
# like single spikes, e.g. noise
|
120
|
+
# compute the regions first
|
121
|
+
x_data_regions = np.copy(x_data[peaks_regions])
|
122
|
+
|
123
|
+
# get arguments where absolute difference is greater than data resolution
|
124
|
+
resolution = np.absolute(np.mean(np.diff(x_data)))
|
125
|
+
|
126
|
+
# (N, 1) array!
|
127
|
+
valid_regions_map = np.absolute(np.diff(x_data_regions)) > resolution
|
128
|
+
|
129
|
+
# get their indexes, mind the flattening of all arrays!
|
130
|
+
valid_regions_indexes = np.argwhere(valid_regions_map.flatten()).flatten()
|
131
|
+
|
132
|
+
# filtering!
|
133
|
+
peaks_regions = peaks_regions[valid_regions_indexes]
|
134
|
+
|
135
|
+
return peaks_regions
|
136
|
+
|
137
|
+
|
138
|
+
def filter_noisy_regions(y_data, peaks_regions):
|
139
|
+
"""Remove noisy regions from given regions array.
|
140
|
+
|
141
|
+
Peak regions are filtered to remove false positive noise regions, e.g.
|
142
|
+
incorrectly assigned due to curvy baseline. Filtering is performed by
|
143
|
+
computing average peak points/data points ratio.
|
144
|
+
|
145
|
+
Args:
|
146
|
+
y_data (:obj:np.array): Y data points, needed to validate if the peaks
|
147
|
+
are actually present in the region and remove invalid regions.
|
148
|
+
peaks_regions (:obj:np.array): 2D Nx2 array with peak regions indexes
|
149
|
+
(rows) as left and right borders (columns).
|
150
|
+
|
151
|
+
Returns:
|
152
|
+
:obj:np.array: 2D Mx2 array with filtered peak regions indexes(rows) as
|
153
|
+
left and right borders (columns).
|
154
|
+
"""
|
155
|
+
|
156
|
+
# compute the actual regions data points
|
157
|
+
y_data_regions = []
|
158
|
+
for region in peaks_regions:
|
159
|
+
y_data_regions.append(y_data[region[0]: region[-1]])
|
160
|
+
|
161
|
+
# compute noise data regions, i.e. in between peak regions
|
162
|
+
noise_data_regions = []
|
163
|
+
for row, _ in enumerate(peaks_regions):
|
164
|
+
try:
|
165
|
+
noise_data_regions.append(
|
166
|
+
y_data[peaks_regions[row][1]: peaks_regions[row + 1][0]]
|
167
|
+
)
|
168
|
+
except IndexError:
|
169
|
+
# exception for the last row -> discard
|
170
|
+
pass
|
171
|
+
|
172
|
+
# compute average peaks/data points ratio for noisy regions
|
173
|
+
noise_peaks_ratio = []
|
174
|
+
for region in noise_data_regions:
|
175
|
+
# protection from empty regions
|
176
|
+
if region.size != 0:
|
177
|
+
# minimum height is pretty low to ensure enough noise is picked
|
178
|
+
peaks, _ = scipy.signal.find_peaks(region, height=region.max() * 0.2)
|
179
|
+
noise_peaks_ratio.append(peaks.size / region.size)
|
180
|
+
|
181
|
+
# compute average with weights equal to the region length
|
182
|
+
noise_peaks_ratio = np.average(
|
183
|
+
noise_peaks_ratio, weights=[region.size for region in noise_data_regions]
|
184
|
+
)
|
185
|
+
|
186
|
+
# filtering!
|
187
|
+
valid_regions_indexes = []
|
188
|
+
for row, region in enumerate(y_data_regions):
|
189
|
+
peaks, _ = scipy.signal.find_peaks(region, height=region.max() * 0.2)
|
190
|
+
if peaks.size != 0 and peaks.size / region.size < noise_peaks_ratio:
|
191
|
+
valid_regions_indexes.append(row)
|
192
|
+
|
193
|
+
# protecting from complete cleaning
|
194
|
+
if not valid_regions_indexes:
|
195
|
+
return peaks_regions
|
196
|
+
|
197
|
+
peaks_regions = peaks_regions[np.array(valid_regions_indexes)]
|
198
|
+
|
199
|
+
return peaks_regions
|
200
|
+
|
201
|
+
|
202
|
+
def merge_regions(x_data, peaks_regions, d_merge, recursively=True):
|
203
|
+
"""Merge peak regions if distance between is less than delta.
|
204
|
+
|
205
|
+
Args:
|
206
|
+
x_data (:obj:np.array): X data points.
|
207
|
+
peaks_regions (:obj:np.array): 2D Nx2 array with peak regions indexes
|
208
|
+
(rows) as left and right borders (columns).
|
209
|
+
d_merge (float): Minimum distance in X data points to merge two or more
|
210
|
+
regions together.
|
211
|
+
recursively (bool, optional): If True - will repeat the procedure until
|
212
|
+
all regions with distance < than d_merge will merge.
|
213
|
+
|
214
|
+
Returns:
|
215
|
+
:obj:np.array: 2D Mx2 array with peak regions indexes (rows) as left and
|
216
|
+
right borders (columns), merged according to predefined minimal
|
217
|
+
distance.
|
218
|
+
|
219
|
+
Example:
|
220
|
+
>>> regions = np.array([
|
221
|
+
[1, 10],
|
222
|
+
[11, 20],
|
223
|
+
[25, 45],
|
224
|
+
[50, 75],
|
225
|
+
[100, 120],
|
226
|
+
[122, 134]
|
227
|
+
])
|
228
|
+
>>> data = np.ones_like(regions) # ones as example
|
229
|
+
>>> merge_regions(data, regions, 1)
|
230
|
+
array([[ 1, 20],
|
231
|
+
[ 25, 45],
|
232
|
+
[ 50, 75],
|
233
|
+
[100, 120],
|
234
|
+
[122, 134]])
|
235
|
+
>>> merge_regions(data, regions, 20, True)
|
236
|
+
array([[ 1, 75],
|
237
|
+
[100, 134]])
|
238
|
+
"""
|
239
|
+
# the code is pretty ugly but works
|
240
|
+
merged_regions = []
|
241
|
+
|
242
|
+
# converting to list to drop the data of the fly
|
243
|
+
regions = peaks_regions.tolist()
|
244
|
+
|
245
|
+
for i, _ in enumerate(regions):
|
246
|
+
try:
|
247
|
+
# check left border of i regions with right of i+1
|
248
|
+
if abs(x_data[regions[i][-1]] - x_data[regions[i + 1][0]]) <= d_merge:
|
249
|
+
# if lower append merge the regions
|
250
|
+
merged_regions.append([regions[i][0], regions[i + 1][-1]])
|
251
|
+
# drop the merged one
|
252
|
+
regions.pop(i + 1)
|
253
|
+
else:
|
254
|
+
# if nothing to merge, just append the current region
|
255
|
+
merged_regions.append(regions[i])
|
256
|
+
except IndexError:
|
257
|
+
# last row
|
258
|
+
merged_regions.append(regions[i])
|
259
|
+
|
260
|
+
merged_regions = np.array(merged_regions)
|
261
|
+
|
262
|
+
if not recursively:
|
263
|
+
return merged_regions
|
264
|
+
|
265
|
+
# if recursively, check for the difference
|
266
|
+
if (merged_regions == regions).all():
|
267
|
+
# done
|
268
|
+
return merged_regions
|
269
|
+
|
270
|
+
return merge_regions(x_data, merged_regions, d_merge, recursively=True)
|
271
|
+
|
272
|
+
|
273
|
+
def expand_regions(x_data, peaks_regions, d_expand):
|
274
|
+
"""Expand the peak regions by the desired value.
|
275
|
+
|
276
|
+
Args:
|
277
|
+
x_data (:obj:np.array): X data points.
|
278
|
+
peaks_regions (:obj:np.array): 2D Nx2 array with peak regions indexes
|
279
|
+
(rows) as left and right borders (columns).
|
280
|
+
d_expand (float): Value to expand borders to (in X data scale).
|
281
|
+
|
282
|
+
Returns:
|
283
|
+
:obj:np.array: 2D Nx2 array with expanded peak regions indexes (rows) as
|
284
|
+
left and right borders (columns).
|
285
|
+
"""
|
286
|
+
|
287
|
+
data_regions = np.copy(x_data[peaks_regions])
|
288
|
+
|
289
|
+
# determine scale orientation, i.e. decreasing (e.g. ppm on NMR spectrum)
|
290
|
+
# or increasing (e.g. wavelength on UV spectrum)
|
291
|
+
if (data_regions[:, 0] - data_regions[:, 1]).mean() > 0:
|
292
|
+
# ppm-like scale
|
293
|
+
data_regions[:, 0] += d_expand
|
294
|
+
data_regions[:, -1] -= d_expand
|
295
|
+
else:
|
296
|
+
# wavelength-like scale
|
297
|
+
data_regions[:, 0] -= d_expand
|
298
|
+
data_regions[:, -1] += d_expand
|
299
|
+
|
300
|
+
# converting new values to new indexes
|
301
|
+
for index_, value in np.ndenumerate(data_regions):
|
302
|
+
data_regions[index_] = find_nearest_value_index(x_data, value)[1]
|
303
|
+
|
304
|
+
return data_regions.astype(int)
|
@@ -1,10 +1,13 @@
|
|
1
1
|
Metadata-Version: 2.4
|
2
2
|
Name: pychemstation
|
3
|
-
Version: 0.
|
4
|
-
Summary: Library to interact with Chemstation software, primarily used in Hein
|
3
|
+
Version: 0.10.0
|
4
|
+
Summary: Library to interact with Chemstation software, primarily used in Hein lagit branch -mb
|
5
|
+
Home-page: https://gitlab.com/heingroup/device-api/pychemstation
|
6
|
+
Author: Lucy Hao
|
5
7
|
Author-email: lucyhao <hao.lucyy@gmail.com>
|
8
|
+
Requires-Python: >=3.10
|
9
|
+
Description-Content-Type: text/markdown
|
6
10
|
License-File: LICENSE
|
7
|
-
Requires-Python: >=3.8
|
8
11
|
Requires-Dist: aghplctools>=4.8.8
|
9
12
|
Requires-Dist: coverage>=7.6.1
|
10
13
|
Requires-Dist: matplotlib>=3.7.5
|
@@ -19,7 +22,9 @@ Requires-Dist: seabreeze>=2.9.2
|
|
19
22
|
Requires-Dist: setuptools>=75.3.2
|
20
23
|
Requires-Dist: twine>=6.1.0
|
21
24
|
Requires-Dist: xsdata>=24.9
|
22
|
-
|
25
|
+
Dynamic: author
|
26
|
+
Dynamic: home-page
|
27
|
+
Dynamic: license-file
|
23
28
|
|
24
29
|
# Agilent HPLC Macro Control
|
25
30
|
|
@@ -27,8 +32,12 @@ Description-Content-Type: text/markdown
|
|
27
32
|
|
28
33
|
[](https://pypi.org/project/pychemstation/)
|
29
34
|
|
35
|
+
> **_NOTE:_** If you are running Python **3.8**, use versions 0.**8**.x. If you are running Python **>=3.10**, use
|
36
|
+
> version 0.**10**.x. You are welcome to use newer pychemstation versions with older Python versions, but functionality
|
37
|
+
> is not guaranteed!
|
38
|
+
|
30
39
|
Unofficial Python package to control Agilent Chemstation; we are not affiliated with Agilent.
|
31
|
-
Check out the [docs](https://
|
40
|
+
Check out the [docs](https://pychemstation-e5a086.gitlab.io/pychemstation.html) for usage instructions. This project is under
|
32
41
|
active development, and breaking changes may occur at any moment.
|
33
42
|
|
34
43
|
## Getting started
|
@@ -110,6 +119,8 @@ Lucy Hao, Maria Politi
|
|
110
119
|
|
111
120
|
- Adapted from [**AnalyticalLabware**](https://github.com/croningp/analyticallabware), created by members in the Cronin
|
112
121
|
Group. Copyright © Cronin Group, used under the [CC-BY-4.0](https://creativecommons.org/licenses/by/4.0/) license.
|
113
|
-
- Adapted from the [MACROS](https://github.com/Bourne-Group/HPLCMethodOptimisationGUI)
|
114
|
-
|
115
|
-
|
122
|
+
- Adapted from the [MACROS](https://github.com/Bourne-Group/HPLCMethodOptimisationGUI) used in [**Operator-free HPLC
|
123
|
+
automated method development guided by Bayesian optimization
|
124
|
+
**](https://pubs.rsc.org/en/content/articlelanding/2024/dd/d4dd00062e),
|
125
|
+
created by members in the Bourne Group. Copyright © Bourne Group, used under
|
126
|
+
the [MIT](https://opensource.org/license/mit) license.
|
@@ -0,0 +1,62 @@
|
|
1
|
+
pychemstation/__init__.py,sha256=SpTl-Tg1B1HTyjNOE-8ue-N2wGnXN_2zl7RFUSxlkiM,33
|
2
|
+
pychemstation/analysis/__init__.py,sha256=Vi31PZ7fgIvyuIhkgCNvEYeV_jtUCa8FCrAGbpks7zc,83
|
3
|
+
pychemstation/analysis/base_spectrum.py,sha256=9WkOLk2qTAYTF1ALNUenVPoosOtBiLRvy2ni8zlGU5w,16540
|
4
|
+
pychemstation/analysis/process_report.py,sha256=ZOgcRUMGXdGMrMFcdzsSwdOk6OBp-PpcA83vSvnmVSg,11871
|
5
|
+
pychemstation/analysis/spec_utils.py,sha256=UOo9hJR3evJfmaohEEsyb7aq6X996ofuUfu-GKjiDi8,10201
|
6
|
+
pychemstation/analysis/utils.py,sha256=ISupAOb_yqA4_DZRK9v18UL-XjUQccAicIJKb1VMnGg,2055
|
7
|
+
pychemstation/control/__init__.py,sha256=Js79QczKZxDNZrzG1-4yl_whCoP2aw-yDAQJungiiic,100
|
8
|
+
pychemstation/control/comm.py,sha256=u44g1hTluQ0yUG93Un-QAshScoDpgYRrZfFTgweP5tY,7386
|
9
|
+
pychemstation/control/hplc.py,sha256=f7NHcCWtc_ApasjU5VMQtEvWQxoIboi_-RU9dkjORrs,13215
|
10
|
+
pychemstation/control/controllers/__init__.py,sha256=r7UU0u5zuJHO_KTqt-4Gy65BMlyXtxrdskiOhtO9Yw4,260
|
11
|
+
pychemstation/control/controllers/comm.py,sha256=AN3A3ThvIsOKWY7Kmb_tnE5pRUqI7O2ID8M54z_w-uE,7831
|
12
|
+
pychemstation/control/controllers/method.py,sha256=XUclB7lQ_SIkquR58MBmmi9drHIPEq9AR8VprTLenvI,15503
|
13
|
+
pychemstation/control/controllers/sequence.py,sha256=kYNxxck2I-q9mZDEZwG8bJ_99FfLmunS13EAHOS65wU,8288
|
14
|
+
pychemstation/control/controllers/table_controller.py,sha256=70ovnIjLKkJborS1ztk445Mv42TtUM9jUniaQmZuyWQ,11031
|
15
|
+
pychemstation/control/controllers/devices/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
16
|
+
pychemstation/control/controllers/devices/column.py,sha256=SCpCnVFZFUM9LM51MbWkVcBRayN3WFxy7lz9gs2PYeY,348
|
17
|
+
pychemstation/control/controllers/devices/dad.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
18
|
+
pychemstation/control/controllers/devices/device.py,sha256=JNBKVRka1I3LA1lElIeUO0j93BTK5IJufTPNq95OhNE,1473
|
19
|
+
pychemstation/control/controllers/devices/injector.py,sha256=s40jFd0B_wJn4ID6SgAk_F8WhnGbbflpiti4uwIhaSs,1950
|
20
|
+
pychemstation/control/controllers/devices/pump.py,sha256=DJQh4lNXEraeC1CWrsKmsITOjuYlRI3tih_XRB3F1hg,1404
|
21
|
+
pychemstation/control/controllers/tables/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
22
|
+
pychemstation/control/controllers/tables/method.py,sha256=LHoNRSTsSrrktghqNnU5KTRXDczcuGgqdqKEs_3sUXI,18609
|
23
|
+
pychemstation/control/controllers/tables/ms.py,sha256=JFD-tOhu8uRyKdl-E3-neRssii8MNqVRIlsrnFhNY_M,682
|
24
|
+
pychemstation/control/controllers/tables/sequence.py,sha256=DwX0wi5GhHmk8wnl89X2MKvqTSojLycV4IEvNjdVdWg,13400
|
25
|
+
pychemstation/control/controllers/tables/table.py,sha256=zMzsQgkLxM3LVe9w-OM8WjLZxTo9zrmBTNH182gAyh8,12750
|
26
|
+
pychemstation/control/table/__init__.py,sha256=RgMN4uIWHdNUHpGRBWdzmzAbk7XEKl6Y-qtqWCxzSZU,124
|
27
|
+
pychemstation/control/table/method.py,sha256=THVoGomSXff_CTU3eAYme0BYwkPzab5UgZKsiZ29QSk,12196
|
28
|
+
pychemstation/control/table/sequence.py,sha256=Eri52AnbE3BGthfrRSvYKYciquUzvHKo0lYUTySYYE8,10542
|
29
|
+
pychemstation/control/table/table_controller.py,sha256=HVNYUXqtyFTAvb67fa3RO5RHgmBTFMsYRHKpiXdYcfs,8313
|
30
|
+
pychemstation/generated/__init__.py,sha256=GAoZFAYbPVEJDkcOw3e1rgOqd7TCW0HyKNPM8OMehMg,1005
|
31
|
+
pychemstation/generated/dad_method.py,sha256=xTUiSCvkXcxBUhjVm1YZKu-tHs16k23pF-0xYrQSwWA,8408
|
32
|
+
pychemstation/generated/pump_method.py,sha256=797RsSDI2-QPf_BX8isZQx0O3aRx84EGIXJXhXw3IS0,12180
|
33
|
+
pychemstation/utils/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
34
|
+
pychemstation/utils/chromatogram.py,sha256=2Los_ix_wAi4yxG_9neGRnNYPre9_uC1mrne3Ygit5c,3242
|
35
|
+
pychemstation/utils/injector_types.py,sha256=PXwJK1uXs8hlQ6dWIEbAGfk2BpQJQmN3SlUbL4ntZz0,822
|
36
|
+
pychemstation/utils/macro.py,sha256=Lh8aGcwo9sC2Sfc19Wgms5d3VgBLV3VXdvspqNHYE18,2931
|
37
|
+
pychemstation/utils/method_types.py,sha256=ZOFMJ7wpqWBRJNIvOux-7Ou4nJVSuyWRHrd37wMnPa0,1638
|
38
|
+
pychemstation/utils/num_utils.py,sha256=rgpTJTrpsiBANbtsfys9xj0sqlTe__3J0OSeoygaQTM,2081
|
39
|
+
pychemstation/utils/parsing.py,sha256=iFdnie-v0u5JI4cctJye_yhWQxHgy72_PWZ7w57Ltvg,9318
|
40
|
+
pychemstation/utils/pump_types.py,sha256=HWQHxscGn19NTrfYBwQRCO2VcYfwyko7YfBO5uDhEm4,93
|
41
|
+
pychemstation/utils/sequence_types.py,sha256=WyJWL18Q86TgoUpYH2_CevoTZuhcui0EnyHYdrp3Nmo,1070
|
42
|
+
pychemstation/utils/spec_utils.py,sha256=MQZPDwCYZRfkEhNJQUt74huPexXBlJ3W4o7_230JWcE,10210
|
43
|
+
pychemstation/utils/table_types.py,sha256=7txqW_oNpkh4venSkGEtreVe6UV9dzNB1DTrIeTkQHA,3217
|
44
|
+
pychemstation/utils/tray_types.py,sha256=eOO-muUjadyvCM8JnYAZVyxJeyYBlENP1zXiFskAFbs,5049
|
45
|
+
pychemstation-0.10.0.dist-info/licenses/LICENSE,sha256=9bdF75gIf1MecZ7oymqWgJREVz7McXPG-mjqrTmzzD8,18658
|
46
|
+
tests/__init__.py,sha256=47DEQpj8HBSa-_TImW-5JCeuQeRkm5NMpJWZG3hSuFU,0
|
47
|
+
tests/constants.py,sha256=4XZkV9pw3PLYy6R-18Pbf5ry2iNmAM-jqXA2MuKKkh4,5422
|
48
|
+
tests/test_comb.py,sha256=TS-CbtiPbntL4u6E1gSZ6xquNp6cQxIFdJqUr2ak7PA,5515
|
49
|
+
tests/test_comm.py,sha256=iwl-Ey-xoytXmlNrjG84pDm82Ry_QUX6wY4gmVh4NDc,2516
|
50
|
+
tests/test_inj.py,sha256=UakPA1Sd1GAbFvFepEredWcWPoW7PMLKotfqVZ1i4hE,1434
|
51
|
+
tests/test_method.py,sha256=KB7yAtVb4gZftnYzh-VfPb9LGVZOHUIW6OljEYRtbhA,4570
|
52
|
+
tests/test_nightly.py,sha256=WpLZfs-n9oPrwz-64gWJB5oxJGYz_ab4sLZ4E-xFBpY,2654
|
53
|
+
tests/test_offline_stable.py,sha256=nUyX-LGiQYMjJ1fvjByFBAUS6eMqaqlq6ufoHb8Ai0E,2911
|
54
|
+
tests/test_online_stable.py,sha256=f--r8QqGJtx3kDQi1j0pM5v1IOT4SC7B636otZRYfhE,11325
|
55
|
+
tests/test_proc_rep.py,sha256=sxRiTBybVm6lyAqmgrri-T2EfZgs27oSgbYXSsN9CwU,1380
|
56
|
+
tests/test_runs_stable.py,sha256=hmsI0ZjJRsjSdiRPqXPqEoIxS2sqZIyybNpQpacRs9Q,10235
|
57
|
+
tests/test_sequence.py,sha256=vs5-dqkItRds_tPM2-N6MNJ37FB0nLRFaDzBV8d42i8,4880
|
58
|
+
tests/test_stable.py,sha256=UFb9rUBnOk7JabcweNIYZLWpBHWGbqKAtsTNfxDhEFg,12208
|
59
|
+
pychemstation-0.10.0.dist-info/METADATA,sha256=8jxjr4cJvOZcxFtKJKwkrriG_prk1tmal1_xPD8ruVM,4998
|
60
|
+
pychemstation-0.10.0.dist-info/WHEEL,sha256=CmyFI0kx5cdEMTLiONQRbGQwjIoR1aIYB7eCAQ4KPJ0,91
|
61
|
+
pychemstation-0.10.0.dist-info/top_level.txt,sha256=zXfKu_4nYWwPHo3OsuhshMNC3SPkcoTGCyODjURaghY,20
|
62
|
+
pychemstation-0.10.0.dist-info/RECORD,,
|
tests/__init__.py
ADDED
File without changes
|
tests/constants.py
ADDED
@@ -0,0 +1,134 @@
|
|
1
|
+
import os
|
2
|
+
import random
|
3
|
+
import shutil
|
4
|
+
|
5
|
+
from pychemstation.control import HPLCController
|
6
|
+
from pychemstation.utils.macro import Command
|
7
|
+
from pychemstation.utils.method_types import (
|
8
|
+
HPLCMethodParams,
|
9
|
+
MethodDetails,
|
10
|
+
TimeTableEntry,
|
11
|
+
)
|
12
|
+
from pychemstation.utils.sequence_types import SampleType, SequenceEntry
|
13
|
+
from pychemstation.utils.tray_types import FiftyFourVialPlate, TenVialColumn
|
14
|
+
|
15
|
+
VIAL_PLATES = [
|
16
|
+
FiftyFourVialPlate.from_str('P1-A7'),
|
17
|
+
FiftyFourVialPlate.from_str('P1-B4'),
|
18
|
+
FiftyFourVialPlate.from_str('P1-C2'),
|
19
|
+
FiftyFourVialPlate.from_str('P1-D8'),
|
20
|
+
FiftyFourVialPlate.from_str('P1-E3'),
|
21
|
+
FiftyFourVialPlate.from_str('P1-F5'),
|
22
|
+
# plate 2
|
23
|
+
FiftyFourVialPlate.from_str('P2-A7'),
|
24
|
+
FiftyFourVialPlate.from_str('P2-B2'),
|
25
|
+
FiftyFourVialPlate.from_str('P2-C1'),
|
26
|
+
FiftyFourVialPlate.from_str('P2-D8'),
|
27
|
+
FiftyFourVialPlate.from_str('P2-E3'),
|
28
|
+
FiftyFourVialPlate.from_str('P2-F6'),
|
29
|
+
]
|
30
|
+
|
31
|
+
DEFAULT_METHOD = "GENERAL-POROSHELL-OPT"
|
32
|
+
DEFAULT_SEQUENCE = "hplc_testing"
|
33
|
+
|
34
|
+
# CONSTANTS: paths only work in Hein group HPLC machine in room 242
|
35
|
+
DEFAULT_COMMAND_PATH = "C:\\Users\\User\\Desktop\\Lucy\\hplc-method-optimization\\tests\\"
|
36
|
+
DEFAULT_METHOD_DIR = "C:\\ChemStation\\1\\Methods\\"
|
37
|
+
DATA_DIR = "C:\\Users\\Public\\Documents\\ChemStation\\2\\Data\\LC-BO\\"
|
38
|
+
SEQUENCE_DIR = "C:\\USERS\\PUBLIC\\DOCUMENTS\\CHEMSTATION\\3\\Sequence"
|
39
|
+
SEQUENCE_DATA_DIR_2 = "C:\\Users\\Public\\Documents\\ChemStation\\2\\Data"
|
40
|
+
SEQUENCE_DATA_DIR = "C:\\Users\\Public\\Documents\\ChemStation\\3\\Data\\"
|
41
|
+
|
42
|
+
HEIN_LAB_CONSTANTS_242 = [DEFAULT_COMMAND_PATH,
|
43
|
+
DEFAULT_METHOD_DIR,
|
44
|
+
DATA_DIR,
|
45
|
+
SEQUENCE_DIR,
|
46
|
+
SEQUENCE_DATA_DIR_2,
|
47
|
+
SEQUENCE_DATA_DIR]
|
48
|
+
|
49
|
+
# these CONSTANTS work in rm 254
|
50
|
+
DEFAULT_COMMAND_PATH_254 = "D:\\\git_repositories\\\hplc_comm\\"
|
51
|
+
DEFAULT_METHOD_DIR_254 = "D:\\Chemstation\\1\\Methods\\"
|
52
|
+
DATA_DIR_254 = "D:\\Chemstation\\1\\Data\\LC BO\\"
|
53
|
+
SEQUENCE_DIR_254 = "C:\\1\\Sequence\\"
|
54
|
+
SEQUENCE_DATA_DIR_254 = "D:\\Chemstation\\1\\Data\\"
|
55
|
+
|
56
|
+
HEIN_LAB_CONSTANTS_254 = [DEFAULT_COMMAND_PATH_254,
|
57
|
+
DEFAULT_METHOD_DIR_254,
|
58
|
+
DATA_DIR_254,
|
59
|
+
SEQUENCE_DIR_254,
|
60
|
+
SEQUENCE_DATA_DIR_254]
|
61
|
+
|
62
|
+
|
63
|
+
def room(num: int):
|
64
|
+
if num == 242:
|
65
|
+
return HEIN_LAB_CONSTANTS_242
|
66
|
+
elif num == 254:
|
67
|
+
return HEIN_LAB_CONSTANTS_254
|
68
|
+
|
69
|
+
|
70
|
+
def gen_rand_method():
|
71
|
+
org_modifier = int(random.random() * 10)
|
72
|
+
max_run_time = int(random.random() * 10)
|
73
|
+
post_run_time = int(random.random() * 10)
|
74
|
+
flow = float(random.random() * 10) / 10
|
75
|
+
flow_1 = float(random.random() * 10) / 10
|
76
|
+
flow_2 = float(random.random() * 10) / 10
|
77
|
+
return MethodDetails(name=DEFAULT_METHOD,
|
78
|
+
timetable=[TimeTableEntry(start_time=0.10,
|
79
|
+
organic_modifer=org_modifier,
|
80
|
+
flow=flow_1),
|
81
|
+
TimeTableEntry(start_time=1,
|
82
|
+
organic_modifer=100 - int(random.random() * 10),
|
83
|
+
flow=flow_2)],
|
84
|
+
stop_time=max_run_time,
|
85
|
+
post_time=post_run_time,
|
86
|
+
params=HPLCMethodParams(organic_modifier=org_modifier, flow=flow))
|
87
|
+
|
88
|
+
|
89
|
+
seq_entry = SequenceEntry(
|
90
|
+
vial_location=TenVialColumn.ONE,
|
91
|
+
method=DEFAULT_METHOD,
|
92
|
+
num_inj=int(random.random() * 10),
|
93
|
+
inj_vol=int(random.random() * 10),
|
94
|
+
sample_name="Test",
|
95
|
+
sample_type=SampleType(int(random.random() * 3)),
|
96
|
+
)
|
97
|
+
|
98
|
+
|
99
|
+
def set_up_utils(num: int, offline: bool = False, runs: bool = False) -> HPLCController:
|
100
|
+
path_constants = room(num)
|
101
|
+
if not offline:
|
102
|
+
for path in path_constants:
|
103
|
+
if not os.path.exists(path):
|
104
|
+
raise FileNotFoundError(
|
105
|
+
f"{path} does not exist on your system. If you would like to run tests, please change this path.")
|
106
|
+
|
107
|
+
controller = HPLCController(offline=offline,
|
108
|
+
comm_dir=path_constants[0],
|
109
|
+
method_dir=path_constants[1],
|
110
|
+
data_dirs=[path_constants[2], path_constants[4], path_constants[5]],
|
111
|
+
sequence_dir=path_constants[3],
|
112
|
+
debug=True)
|
113
|
+
if not offline:
|
114
|
+
controller.send(Command.SAVE_METHOD_CMD.value.format(commit_msg="method saved by pychemstation"))
|
115
|
+
controller.send(Command.SAVE_SEQUENCE_CMD)
|
116
|
+
if runs:
|
117
|
+
controller.instrument_on()
|
118
|
+
controller.preprun()
|
119
|
+
return controller
|
120
|
+
|
121
|
+
|
122
|
+
|
123
|
+
def clean_up(hplc_controller: HPLCController):
|
124
|
+
if hasattr(hplc_controller.method_controller, "data_dirs") and hasattr(hplc_controller.sequence_controller, "data_dirs"):
|
125
|
+
files = hplc_controller.method_controller.data_files + [d.dir for d in hplc_controller.sequence_controller.data_files]
|
126
|
+
data_dirs = hplc_controller.method_controller.data_dirs
|
127
|
+
for folder in files:
|
128
|
+
if os.path.isdir(folder):
|
129
|
+
shutil.rmtree(folder)
|
130
|
+
else:
|
131
|
+
for data_dir in data_dirs:
|
132
|
+
possible_path = os.path.join(data_dir, folder)
|
133
|
+
if os.path.isdir(possible_path):
|
134
|
+
shutil.rmtree(possible_path)
|