pytrms 0.9.2__py3-none-any.whl → 0.9.3__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.
- pytrms/__init__.py +38 -38
- pytrms/_base/__init__.py +24 -24
- pytrms/_base/ioniclient.py +32 -32
- pytrms/_base/mqttclient.py +119 -119
- pytrms/_version.py +26 -26
- pytrms/clients/__init__.py +33 -33
- pytrms/clients/db_api.py +200 -183
- pytrms/clients/ioniclient.py +87 -87
- pytrms/clients/modbus.py +532 -528
- pytrms/clients/mqtt.py +800 -797
- pytrms/clients/ssevent.py +82 -82
- pytrms/compose/__init__.py +2 -2
- pytrms/compose/composition.py +302 -302
- pytrms/data/IoniTofPrefs.ini +112 -112
- pytrms/data/ParaIDs.csv +731 -731
- pytrms/helpers.py +126 -120
- pytrms/instrument.py +119 -119
- pytrms/measurement.py +173 -173
- pytrms/peaktable.py +499 -501
- pytrms/plotting/__init__.py +4 -4
- pytrms/plotting/plotting.py +27 -27
- pytrms/readers/__init__.py +4 -4
- pytrms/readers/ionitof_reader.py +472 -472
- {pytrms-0.9.2.dist-info → pytrms-0.9.3.dist-info}/LICENSE +339 -339
- {pytrms-0.9.2.dist-info → pytrms-0.9.3.dist-info}/METADATA +3 -2
- pytrms-0.9.3.dist-info/RECORD +27 -0
- {pytrms-0.9.2.dist-info → pytrms-0.9.3.dist-info}/WHEEL +1 -1
- pytrms-0.9.2.dist-info/RECORD +0 -27
pytrms/measurement.py
CHANGED
|
@@ -1,173 +1,173 @@
|
|
|
1
|
-
import time
|
|
2
|
-
from operator import attrgetter
|
|
3
|
-
from itertools import chain
|
|
4
|
-
from abc import abstractmethod, ABC
|
|
5
|
-
|
|
6
|
-
import pandas as pd
|
|
7
|
-
|
|
8
|
-
from .readers import IoniTOFReader
|
|
9
|
-
|
|
10
|
-
__all__ = ['Measurement', 'PreparingMeasurement', 'RunningMeasurement', 'FinishedMeasurement']
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
class Measurement(ABC):
|
|
14
|
-
"""Class for PTRMS-measurements and batch processing.
|
|
15
|
-
|
|
16
|
-
The start time of the measurement is given by `.time_of_meas`.
|
|
17
|
-
|
|
18
|
-
A measurement is iterable over the 'rows' of its data.
|
|
19
|
-
In the online case, this would slowly produce the current trace, one
|
|
20
|
-
after another.
|
|
21
|
-
In the offline case, this would quickly iterate over the traces in the given
|
|
22
|
-
measurement file.
|
|
23
|
-
"""
|
|
24
|
-
|
|
25
|
-
def _new_state(self, newstate):
|
|
26
|
-
# Note: we get ourselves a nifty little state-machine :)
|
|
27
|
-
self.__class__ = newstate
|
|
28
|
-
|
|
29
|
-
def start(self, filename=''):
|
|
30
|
-
"""Start a measurement on the PTR server.
|
|
31
|
-
|
|
32
|
-
'filename' is the filename of the datafile to write to.
|
|
33
|
-
If left blank, start a "quick measurement".
|
|
34
|
-
|
|
35
|
-
If pointing to a file and the file exist on the (local) server, this raises an exception.
|
|
36
|
-
To create unique filenames, use placeholders for year (%Y), month (%m), and so on,
|
|
37
|
-
for example `filename=C:/Ionicon/Data/Sauerteig_%Y-%m-%d_%H-%M-%S.h5`.
|
|
38
|
-
|
|
39
|
-
see also:
|
|
40
|
-
"""
|
|
41
|
-
# this method must be implemented by each state
|
|
42
|
-
raise RuntimeError("can't start %s" % self.__class__)
|
|
43
|
-
|
|
44
|
-
# (see also: this docstring)
|
|
45
|
-
start.__doc__ += time.strftime.__doc__
|
|
46
|
-
|
|
47
|
-
def stop(self):
|
|
48
|
-
"""Stop the current measurement on the PTR server."""
|
|
49
|
-
raise RuntimeError("can't stop %s" % self.__class__)
|
|
50
|
-
|
|
51
|
-
@abstractmethod
|
|
52
|
-
def __len__(self):
|
|
53
|
-
pass
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
class PreparingMeasurement(Measurement):
|
|
57
|
-
|
|
58
|
-
@property
|
|
59
|
-
def single_spec_duration_ms(self):
|
|
60
|
-
return self.ptr.get('ACQ_SRV_SpecTime_ms')
|
|
61
|
-
|
|
62
|
-
@single_spec_duration_ms.setter
|
|
63
|
-
def single_spec_duration_ms(self, value):
|
|
64
|
-
self.ptr.set('ACQ_SRV_SpecTime_ms', int(value), unit='ms')
|
|
65
|
-
|
|
66
|
-
@property
|
|
67
|
-
def extraction_time_us(self):
|
|
68
|
-
return self.ptr.get('ACQ_SRV_ExtractTime')
|
|
69
|
-
|
|
70
|
-
@extraction_time_us.setter
|
|
71
|
-
def extraction_time_us(self, value):
|
|
72
|
-
self.ptr.set('ACQ_SRV_ExtractTime', int(value), unit='us')
|
|
73
|
-
|
|
74
|
-
@property
|
|
75
|
-
def max_flight_time_us(self):
|
|
76
|
-
return self.ptr.get('ACQ_SRV_MaxFlighttime')
|
|
77
|
-
|
|
78
|
-
@max_flight_time_us.setter
|
|
79
|
-
def max_flight_time_us(self, value):
|
|
80
|
-
self.ptr.set('ACQ_SRV_MaxFlighttime', int(value), unit='us')
|
|
81
|
-
|
|
82
|
-
@property
|
|
83
|
-
def expected_mass_range_amu(self):
|
|
84
|
-
return self.ptr.get('ACQ_SRV_ExpectMRange')
|
|
85
|
-
|
|
86
|
-
@expected_mass_range_amu.setter
|
|
87
|
-
def expected_mass_range_amu(self, value):
|
|
88
|
-
self.ptr.set('ACQ_SRV_ExpectMRange', int(value), unit='amu')
|
|
89
|
-
|
|
90
|
-
def __init__(self, instrument):
|
|
91
|
-
self.ptr = instrument
|
|
92
|
-
|
|
93
|
-
def start(self, filename=''):
|
|
94
|
-
self.ptr.start_measurement(filename)
|
|
95
|
-
self._new_state(RunningMeasurement)
|
|
96
|
-
|
|
97
|
-
def __len__(self):
|
|
98
|
-
return 0
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
class RunningMeasurement(Measurement):
|
|
102
|
-
|
|
103
|
-
def __init__(self, instrument):
|
|
104
|
-
self.ptr = instrument
|
|
105
|
-
|
|
106
|
-
def stop(self):
|
|
107
|
-
self.ptr.stop_measurement()
|
|
108
|
-
self._new_state(FinishedMeasurement)
|
|
109
|
-
|
|
110
|
-
def __len__(self):
|
|
111
|
-
return -1
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
class FinishedMeasurement(Measurement):
|
|
115
|
-
|
|
116
|
-
@classmethod
|
|
117
|
-
def _check(cls, sourcefiles):
|
|
118
|
-
_assumptions = ("incompatible files! "
|
|
119
|
-
"sourcefiles must have the same number-of-timebins and "
|
|
120
|
-
"the same instrument-type to be collected as a batch")
|
|
121
|
-
|
|
122
|
-
assert 1 == len(set(sf.inst_type for sf in sourcefiles)), _assumptions
|
|
123
|
-
assert 1 == len(set(sf.number_of_timebins for sf in sourcefiles)), _assumptions
|
|
124
|
-
|
|
125
|
-
@property
|
|
126
|
-
def number_of_timebins(self):
|
|
127
|
-
return next(iter(self.sourcefiles)).number_of_timebins
|
|
128
|
-
|
|
129
|
-
@property
|
|
130
|
-
def poisson_deadtime_ns(self):
|
|
131
|
-
return next(iter(self.sourcefiles)).poisson_deadtime_ns
|
|
132
|
-
|
|
133
|
-
@property
|
|
134
|
-
def pulsing_period_ns(self):
|
|
135
|
-
return next(iter(self.sourcefiles)).pulsing_period_ns
|
|
136
|
-
|
|
137
|
-
@property
|
|
138
|
-
def single_spec_duration_ms(self):
|
|
139
|
-
return next(iter(self.sourcefiles)).single_spec_duration_ms
|
|
140
|
-
|
|
141
|
-
@property
|
|
142
|
-
def start_delay_ns(self):
|
|
143
|
-
return next(iter(self.sourcefiles)).start_delay_ns
|
|
144
|
-
|
|
145
|
-
@property
|
|
146
|
-
def timebin_width_ps(self):
|
|
147
|
-
return next(iter(self.sourcefiles)).timebin_width_ps
|
|
148
|
-
|
|
149
|
-
def __init__(self, *filenames, _reader=IoniTOFReader):
|
|
150
|
-
if not len(filenames):
|
|
151
|
-
raise ValueError("no filename given")
|
|
152
|
-
|
|
153
|
-
self.sourcefiles = sorted((_reader(f) for f in filenames), key=attrgetter('time_of_file'))
|
|
154
|
-
self._check(self.sourcefiles)
|
|
155
|
-
|
|
156
|
-
def read_traces(self, kind='conc', index='abs_cycle', force_original=False):
|
|
157
|
-
"""Return the timeseries ("traces") of all masses, compounds and settings.
|
|
158
|
-
|
|
159
|
-
'kind' is the type of traces and must be one of 'raw', 'concentration' or
|
|
160
|
-
'corrected'.
|
|
161
|
-
|
|
162
|
-
'index' specifies the desired index and must be one of 'abs_cycle', 'rel_cycle',
|
|
163
|
-
'abs_time' or 'rel_time'.
|
|
164
|
-
|
|
165
|
-
"""
|
|
166
|
-
return pd.concat(sf.read_all(kind, index, force_original) for sf in self.sourcefiles)
|
|
167
|
-
|
|
168
|
-
def __iter__(self):
|
|
169
|
-
return iter(self.sourcefiles)
|
|
170
|
-
|
|
171
|
-
def __len__(self):
|
|
172
|
-
return len(self.sourcefiles)
|
|
173
|
-
|
|
1
|
+
import time
|
|
2
|
+
from operator import attrgetter
|
|
3
|
+
from itertools import chain
|
|
4
|
+
from abc import abstractmethod, ABC
|
|
5
|
+
|
|
6
|
+
import pandas as pd
|
|
7
|
+
|
|
8
|
+
from .readers import IoniTOFReader
|
|
9
|
+
|
|
10
|
+
__all__ = ['Measurement', 'PreparingMeasurement', 'RunningMeasurement', 'FinishedMeasurement']
|
|
11
|
+
|
|
12
|
+
|
|
13
|
+
class Measurement(ABC):
|
|
14
|
+
"""Class for PTRMS-measurements and batch processing.
|
|
15
|
+
|
|
16
|
+
The start time of the measurement is given by `.time_of_meas`.
|
|
17
|
+
|
|
18
|
+
A measurement is iterable over the 'rows' of its data.
|
|
19
|
+
In the online case, this would slowly produce the current trace, one
|
|
20
|
+
after another.
|
|
21
|
+
In the offline case, this would quickly iterate over the traces in the given
|
|
22
|
+
measurement file.
|
|
23
|
+
"""
|
|
24
|
+
|
|
25
|
+
def _new_state(self, newstate):
|
|
26
|
+
# Note: we get ourselves a nifty little state-machine :)
|
|
27
|
+
self.__class__ = newstate
|
|
28
|
+
|
|
29
|
+
def start(self, filename=''):
|
|
30
|
+
"""Start a measurement on the PTR server.
|
|
31
|
+
|
|
32
|
+
'filename' is the filename of the datafile to write to.
|
|
33
|
+
If left blank, start a "quick measurement".
|
|
34
|
+
|
|
35
|
+
If pointing to a file and the file exist on the (local) server, this raises an exception.
|
|
36
|
+
To create unique filenames, use placeholders for year (%Y), month (%m), and so on,
|
|
37
|
+
for example `filename=C:/Ionicon/Data/Sauerteig_%Y-%m-%d_%H-%M-%S.h5`.
|
|
38
|
+
|
|
39
|
+
see also:
|
|
40
|
+
"""
|
|
41
|
+
# this method must be implemented by each state
|
|
42
|
+
raise RuntimeError("can't start %s" % self.__class__)
|
|
43
|
+
|
|
44
|
+
# (see also: this docstring)
|
|
45
|
+
start.__doc__ += time.strftime.__doc__
|
|
46
|
+
|
|
47
|
+
def stop(self):
|
|
48
|
+
"""Stop the current measurement on the PTR server."""
|
|
49
|
+
raise RuntimeError("can't stop %s" % self.__class__)
|
|
50
|
+
|
|
51
|
+
@abstractmethod
|
|
52
|
+
def __len__(self):
|
|
53
|
+
pass
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class PreparingMeasurement(Measurement):
|
|
57
|
+
|
|
58
|
+
@property
|
|
59
|
+
def single_spec_duration_ms(self):
|
|
60
|
+
return self.ptr.get('ACQ_SRV_SpecTime_ms')
|
|
61
|
+
|
|
62
|
+
@single_spec_duration_ms.setter
|
|
63
|
+
def single_spec_duration_ms(self, value):
|
|
64
|
+
self.ptr.set('ACQ_SRV_SpecTime_ms', int(value), unit='ms')
|
|
65
|
+
|
|
66
|
+
@property
|
|
67
|
+
def extraction_time_us(self):
|
|
68
|
+
return self.ptr.get('ACQ_SRV_ExtractTime')
|
|
69
|
+
|
|
70
|
+
@extraction_time_us.setter
|
|
71
|
+
def extraction_time_us(self, value):
|
|
72
|
+
self.ptr.set('ACQ_SRV_ExtractTime', int(value), unit='us')
|
|
73
|
+
|
|
74
|
+
@property
|
|
75
|
+
def max_flight_time_us(self):
|
|
76
|
+
return self.ptr.get('ACQ_SRV_MaxFlighttime')
|
|
77
|
+
|
|
78
|
+
@max_flight_time_us.setter
|
|
79
|
+
def max_flight_time_us(self, value):
|
|
80
|
+
self.ptr.set('ACQ_SRV_MaxFlighttime', int(value), unit='us')
|
|
81
|
+
|
|
82
|
+
@property
|
|
83
|
+
def expected_mass_range_amu(self):
|
|
84
|
+
return self.ptr.get('ACQ_SRV_ExpectMRange')
|
|
85
|
+
|
|
86
|
+
@expected_mass_range_amu.setter
|
|
87
|
+
def expected_mass_range_amu(self, value):
|
|
88
|
+
self.ptr.set('ACQ_SRV_ExpectMRange', int(value), unit='amu')
|
|
89
|
+
|
|
90
|
+
def __init__(self, instrument):
|
|
91
|
+
self.ptr = instrument
|
|
92
|
+
|
|
93
|
+
def start(self, filename=''):
|
|
94
|
+
self.ptr.start_measurement(filename)
|
|
95
|
+
self._new_state(RunningMeasurement)
|
|
96
|
+
|
|
97
|
+
def __len__(self):
|
|
98
|
+
return 0
|
|
99
|
+
|
|
100
|
+
|
|
101
|
+
class RunningMeasurement(Measurement):
|
|
102
|
+
|
|
103
|
+
def __init__(self, instrument):
|
|
104
|
+
self.ptr = instrument
|
|
105
|
+
|
|
106
|
+
def stop(self):
|
|
107
|
+
self.ptr.stop_measurement()
|
|
108
|
+
self._new_state(FinishedMeasurement)
|
|
109
|
+
|
|
110
|
+
def __len__(self):
|
|
111
|
+
return -1
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class FinishedMeasurement(Measurement):
|
|
115
|
+
|
|
116
|
+
@classmethod
|
|
117
|
+
def _check(cls, sourcefiles):
|
|
118
|
+
_assumptions = ("incompatible files! "
|
|
119
|
+
"sourcefiles must have the same number-of-timebins and "
|
|
120
|
+
"the same instrument-type to be collected as a batch")
|
|
121
|
+
|
|
122
|
+
assert 1 == len(set(sf.inst_type for sf in sourcefiles)), _assumptions
|
|
123
|
+
assert 1 == len(set(sf.number_of_timebins for sf in sourcefiles)), _assumptions
|
|
124
|
+
|
|
125
|
+
@property
|
|
126
|
+
def number_of_timebins(self):
|
|
127
|
+
return next(iter(self.sourcefiles)).number_of_timebins
|
|
128
|
+
|
|
129
|
+
@property
|
|
130
|
+
def poisson_deadtime_ns(self):
|
|
131
|
+
return next(iter(self.sourcefiles)).poisson_deadtime_ns
|
|
132
|
+
|
|
133
|
+
@property
|
|
134
|
+
def pulsing_period_ns(self):
|
|
135
|
+
return next(iter(self.sourcefiles)).pulsing_period_ns
|
|
136
|
+
|
|
137
|
+
@property
|
|
138
|
+
def single_spec_duration_ms(self):
|
|
139
|
+
return next(iter(self.sourcefiles)).single_spec_duration_ms
|
|
140
|
+
|
|
141
|
+
@property
|
|
142
|
+
def start_delay_ns(self):
|
|
143
|
+
return next(iter(self.sourcefiles)).start_delay_ns
|
|
144
|
+
|
|
145
|
+
@property
|
|
146
|
+
def timebin_width_ps(self):
|
|
147
|
+
return next(iter(self.sourcefiles)).timebin_width_ps
|
|
148
|
+
|
|
149
|
+
def __init__(self, *filenames, _reader=IoniTOFReader):
|
|
150
|
+
if not len(filenames):
|
|
151
|
+
raise ValueError("no filename given")
|
|
152
|
+
|
|
153
|
+
self.sourcefiles = sorted((_reader(f) for f in filenames), key=attrgetter('time_of_file'))
|
|
154
|
+
self._check(self.sourcefiles)
|
|
155
|
+
|
|
156
|
+
def read_traces(self, kind='conc', index='abs_cycle', force_original=False):
|
|
157
|
+
"""Return the timeseries ("traces") of all masses, compounds and settings.
|
|
158
|
+
|
|
159
|
+
'kind' is the type of traces and must be one of 'raw', 'concentration' or
|
|
160
|
+
'corrected'.
|
|
161
|
+
|
|
162
|
+
'index' specifies the desired index and must be one of 'abs_cycle', 'rel_cycle',
|
|
163
|
+
'abs_time' or 'rel_time'.
|
|
164
|
+
|
|
165
|
+
"""
|
|
166
|
+
return pd.concat(sf.read_all(kind, index, force_original) for sf in self.sourcefiles)
|
|
167
|
+
|
|
168
|
+
def __iter__(self):
|
|
169
|
+
return iter(self.sourcefiles)
|
|
170
|
+
|
|
171
|
+
def __len__(self):
|
|
172
|
+
return len(self.sourcefiles)
|
|
173
|
+
|