ChessAnalysisPipeline 0.0.2__py3-none-any.whl → 0.0.4__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.
Potentially problematic release.
This version of ChessAnalysisPipeline might be problematic. Click here for more details.
- CHAP/__init__.py +3 -0
- CHAP/common/__init__.py +19 -0
- CHAP/common/models/__init__.py +2 -0
- CHAP/common/models/integration.py +515 -0
- CHAP/common/models/map.py +535 -0
- CHAP/common/processor.py +644 -0
- CHAP/common/reader.py +119 -0
- CHAP/common/utils/__init__.py +37 -0
- CHAP/common/utils/fit.py +2613 -0
- CHAP/common/utils/general.py +1225 -0
- CHAP/common/utils/material.py +231 -0
- CHAP/common/utils/scanparsers.py +785 -0
- CHAP/common/writer.py +96 -0
- CHAP/edd/__init__.py +7 -0
- CHAP/edd/models.py +215 -0
- CHAP/edd/processor.py +321 -0
- CHAP/edd/reader.py +5 -0
- CHAP/edd/writer.py +5 -0
- CHAP/inference/__init__.py +3 -0
- CHAP/inference/processor.py +68 -0
- CHAP/inference/reader.py +5 -0
- CHAP/inference/writer.py +5 -0
- CHAP/pipeline.py +1 -1
- CHAP/processor.py +11 -818
- CHAP/reader.py +18 -113
- CHAP/saxswaxs/__init__.py +6 -0
- CHAP/saxswaxs/processor.py +5 -0
- CHAP/saxswaxs/reader.py +5 -0
- CHAP/saxswaxs/writer.py +5 -0
- CHAP/sin2psi/__init__.py +7 -0
- CHAP/sin2psi/processor.py +5 -0
- CHAP/sin2psi/reader.py +5 -0
- CHAP/sin2psi/writer.py +5 -0
- CHAP/tomo/__init__.py +5 -0
- CHAP/tomo/models.py +125 -0
- CHAP/tomo/processor.py +2009 -0
- CHAP/tomo/reader.py +5 -0
- CHAP/tomo/writer.py +5 -0
- CHAP/writer.py +17 -167
- {ChessAnalysisPipeline-0.0.2.dist-info → ChessAnalysisPipeline-0.0.4.dist-info}/METADATA +1 -1
- ChessAnalysisPipeline-0.0.4.dist-info/RECORD +50 -0
- CHAP/async.py +0 -56
- ChessAnalysisPipeline-0.0.2.dist-info/RECORD +0 -17
- {ChessAnalysisPipeline-0.0.2.dist-info → ChessAnalysisPipeline-0.0.4.dist-info}/LICENSE +0 -0
- {ChessAnalysisPipeline-0.0.2.dist-info → ChessAnalysisPipeline-0.0.4.dist-info}/WHEEL +0 -0
- {ChessAnalysisPipeline-0.0.2.dist-info → ChessAnalysisPipeline-0.0.4.dist-info}/entry_points.txt +0 -0
- {ChessAnalysisPipeline-0.0.2.dist-info → ChessAnalysisPipeline-0.0.4.dist-info}/top_level.txt +0 -0
|
@@ -0,0 +1,785 @@
|
|
|
1
|
+
#!/usr/bin/env python3
|
|
2
|
+
|
|
3
|
+
# -*- coding: utf-8 -*-
|
|
4
|
+
|
|
5
|
+
# system modules
|
|
6
|
+
import csv
|
|
7
|
+
import fnmatch
|
|
8
|
+
from functools import cache
|
|
9
|
+
import json
|
|
10
|
+
import os
|
|
11
|
+
import re
|
|
12
|
+
|
|
13
|
+
# necessary for the base class, ScanParser:
|
|
14
|
+
import numpy as np
|
|
15
|
+
from pyspec.file.spec import FileSpec
|
|
16
|
+
|
|
17
|
+
class ScanParser(object):
|
|
18
|
+
def __init__(self,
|
|
19
|
+
spec_file_name:str,
|
|
20
|
+
scan_number:int):
|
|
21
|
+
|
|
22
|
+
self.spec_file_name = spec_file_name
|
|
23
|
+
self.scan_number = scan_number
|
|
24
|
+
|
|
25
|
+
self._scan_path = None
|
|
26
|
+
self._scan_name = None
|
|
27
|
+
self._scan_title = None
|
|
28
|
+
|
|
29
|
+
self._spec_scan = None
|
|
30
|
+
self._spec_command = None
|
|
31
|
+
self._spec_macro = None
|
|
32
|
+
self._spec_args = None
|
|
33
|
+
self._spec_scan_npts = None
|
|
34
|
+
self._spec_scan_data = None
|
|
35
|
+
self._spec_positioner_values = None
|
|
36
|
+
|
|
37
|
+
self._detector_data_path = None
|
|
38
|
+
|
|
39
|
+
def __repr__(self):
|
|
40
|
+
return(f'{self.__class__.__name__}({self.spec_file_name}, {self.scan_number}) -- {self.spec_command}')
|
|
41
|
+
|
|
42
|
+
@property
|
|
43
|
+
def spec_file(self):
|
|
44
|
+
# NB This FileSpec instance is not stored as a private attribute because
|
|
45
|
+
# it cannot be pickled (and therefore could cause problems for
|
|
46
|
+
# parallel code that uses ScanParsers).
|
|
47
|
+
return(FileSpec(self.spec_file_name))
|
|
48
|
+
@property
|
|
49
|
+
def scan_path(self):
|
|
50
|
+
if self._scan_path is None:
|
|
51
|
+
self._scan_path = self.get_scan_path()
|
|
52
|
+
return self._scan_path
|
|
53
|
+
@property
|
|
54
|
+
def scan_name(self):
|
|
55
|
+
if self._scan_name is None:
|
|
56
|
+
self._scan_name = self.get_scan_name()
|
|
57
|
+
return self._scan_name
|
|
58
|
+
@property
|
|
59
|
+
def scan_title(self):
|
|
60
|
+
if self._scan_title is None:
|
|
61
|
+
self._scan_title = self.get_scan_title()
|
|
62
|
+
return self._scan_title
|
|
63
|
+
@property
|
|
64
|
+
def spec_scan(self):
|
|
65
|
+
if self._spec_scan is None:
|
|
66
|
+
self._spec_scan = self.get_spec_scan()
|
|
67
|
+
return self._spec_scan
|
|
68
|
+
@property
|
|
69
|
+
def spec_command(self):
|
|
70
|
+
if self._spec_command is None:
|
|
71
|
+
self._spec_command = self.get_spec_command()
|
|
72
|
+
return self._spec_command
|
|
73
|
+
@property
|
|
74
|
+
def spec_macro(self):
|
|
75
|
+
if self._spec_macro is None:
|
|
76
|
+
self._spec_macro = self.get_spec_macro()
|
|
77
|
+
return self._spec_macro
|
|
78
|
+
@property
|
|
79
|
+
def spec_args(self):
|
|
80
|
+
if self._spec_args is None:
|
|
81
|
+
self._spec_args = self.get_spec_args()
|
|
82
|
+
return self._spec_args
|
|
83
|
+
@property
|
|
84
|
+
def spec_scan_npts(self):
|
|
85
|
+
if self._spec_scan_npts is None:
|
|
86
|
+
self._spec_scan_npts = self.get_spec_scan_npts()
|
|
87
|
+
return self._spec_scan_npts
|
|
88
|
+
@property
|
|
89
|
+
def spec_scan_data(self):
|
|
90
|
+
if self._spec_scan_data is None:
|
|
91
|
+
self._spec_scan_data = self.get_spec_scan_data()
|
|
92
|
+
return self._spec_scan_data
|
|
93
|
+
@property
|
|
94
|
+
def spec_positioner_values(self):
|
|
95
|
+
if self._spec_positioner_values is None:
|
|
96
|
+
self._spec_positioner_values = self.get_spec_positioner_values()
|
|
97
|
+
return self._spec_positioner_values
|
|
98
|
+
@property
|
|
99
|
+
def detector_data_path(self):
|
|
100
|
+
if self._detector_data_path is None:
|
|
101
|
+
self._detector_data_path = self.get_detector_data_path()
|
|
102
|
+
return self._detector_data_path
|
|
103
|
+
|
|
104
|
+
def get_scan_path(self):
|
|
105
|
+
return(os.path.dirname(self.spec_file_name))
|
|
106
|
+
def get_scan_name(self):
|
|
107
|
+
return(None)
|
|
108
|
+
def get_scan_title(self):
|
|
109
|
+
return(None)
|
|
110
|
+
def get_spec_scan(self):
|
|
111
|
+
return(self.spec_file.getScanByNumber(self.scan_number))
|
|
112
|
+
def get_spec_command(self):
|
|
113
|
+
return(self.spec_scan.command)
|
|
114
|
+
def get_spec_macro(self):
|
|
115
|
+
return(self.spec_command.split()[0])
|
|
116
|
+
def get_spec_args(self):
|
|
117
|
+
return(self.spec_command.split()[1:])
|
|
118
|
+
def get_spec_scan_npts(self):
|
|
119
|
+
raise(NotImplementedError)
|
|
120
|
+
def get_spec_scan_data(self):
|
|
121
|
+
return(dict(zip(self.spec_scan.labels, self.spec_scan.data.T)))
|
|
122
|
+
def get_spec_positioner_values(self):
|
|
123
|
+
positioner_values = dict(self.spec_scan.motor_positions)
|
|
124
|
+
names = list(positioner_values.keys())
|
|
125
|
+
mnemonics = self.spec_scan.motors
|
|
126
|
+
if mnemonics is not None:
|
|
127
|
+
for name,mnemonic in zip(names,mnemonics):
|
|
128
|
+
if name != mnemonic:
|
|
129
|
+
positioner_values[mnemonic] = positioner_values[name]
|
|
130
|
+
return(positioner_values)
|
|
131
|
+
def get_detector_data_path(self):
|
|
132
|
+
raise(NotImplementedError)
|
|
133
|
+
|
|
134
|
+
def get_detector_data_file(self, detector_prefix, scan_step_index:int):
|
|
135
|
+
raise(NotImplementedError)
|
|
136
|
+
def get_detector_data(self, detector_prefix, scan_step_index:int):
|
|
137
|
+
'''
|
|
138
|
+
Return a np.ndarray of detector data.
|
|
139
|
+
|
|
140
|
+
:param detector_prefix: The detector's name in any data files, often
|
|
141
|
+
the EPICS macro $(P).
|
|
142
|
+
:type detector_substring: str
|
|
143
|
+
|
|
144
|
+
:param scan_step_index: The index of the scan step for which detector
|
|
145
|
+
data will be returned.
|
|
146
|
+
:type scan_step_index: int
|
|
147
|
+
|
|
148
|
+
:return: The detector data
|
|
149
|
+
:rtype: np.ndarray
|
|
150
|
+
'''
|
|
151
|
+
raise(NotImplementedError)
|
|
152
|
+
|
|
153
|
+
def get_spec_positioner_value(self, positioner_name):
|
|
154
|
+
try:
|
|
155
|
+
positioner_value = self.spec_positioner_values[positioner_name]
|
|
156
|
+
positioner_value = float(positioner_value)
|
|
157
|
+
return(positioner_value)
|
|
158
|
+
except KeyError:
|
|
159
|
+
raise(KeyError(f'{self.scan_title}: motor {positioner_name} not found for this scan'))
|
|
160
|
+
except ValueError:
|
|
161
|
+
raise(ValueError(f'{self.scan_title}: ccould not convert value of {positioner_name} to float: {positioner_value}'))
|
|
162
|
+
|
|
163
|
+
|
|
164
|
+
class FMBScanParser(ScanParser):
|
|
165
|
+
def __init__(self, spec_file_name, scan_number):
|
|
166
|
+
super().__init__(spec_file_name, scan_number)
|
|
167
|
+
def get_scan_name(self):
|
|
168
|
+
return(os.path.basename(self.spec_file.abspath))
|
|
169
|
+
def get_scan_title(self):
|
|
170
|
+
return(f'{self.scan_name}_{self.scan_number:03d}')
|
|
171
|
+
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
class SMBScanParser(ScanParser):
|
|
175
|
+
def __init__(self, spec_file_name, scan_number):
|
|
176
|
+
super().__init__(spec_file_name, scan_number)
|
|
177
|
+
|
|
178
|
+
self._pars = None # purpose: store values found in the .par file as a dictionary
|
|
179
|
+
self.par_file_pattern = f'*-*-{self.scan_name}'
|
|
180
|
+
|
|
181
|
+
def get_scan_name(self):
|
|
182
|
+
return(os.path.basename(self.scan_path))
|
|
183
|
+
def get_scan_title(self):
|
|
184
|
+
return(f'{self.scan_name}_{self.scan_number}')
|
|
185
|
+
|
|
186
|
+
@property
|
|
187
|
+
def pars(self):
|
|
188
|
+
if self._pars is None:
|
|
189
|
+
self._pars = self.get_pars()
|
|
190
|
+
return(self._pars)
|
|
191
|
+
|
|
192
|
+
def get_pars(self):
|
|
193
|
+
# JSON file holds titles for columns in the par file
|
|
194
|
+
json_files = fnmatch.filter(os.listdir(self.scan_path), f'{self.par_file_pattern}.json')
|
|
195
|
+
if not len(json_files) == 1:
|
|
196
|
+
raise(RuntimeError(f'{self.scan_title}: cannot find the .json file to decode the .par file'))
|
|
197
|
+
with open(os.path.join(self.scan_path, json_files[0])) as json_file:
|
|
198
|
+
par_file_cols = json.load(json_file)
|
|
199
|
+
try:
|
|
200
|
+
par_col_names = list(par_file_cols.values())
|
|
201
|
+
scann_val_idx = par_col_names.index('SCAN_N')
|
|
202
|
+
scann_col_idx = int(list(par_file_cols.keys())[scann_val_idx])
|
|
203
|
+
except:
|
|
204
|
+
raise(RuntimeError(f'{self.scan_title}: cannot find scan pars without a "SCAN_N" column in the par file'))
|
|
205
|
+
|
|
206
|
+
par_files = fnmatch.filter(os.listdir(self.scan_path), f'{self.par_file_pattern}.par')
|
|
207
|
+
if not len(par_files) == 1:
|
|
208
|
+
raise(RuntimeError(f'{self.scan_title}: cannot find the .par file for this scan directory'))
|
|
209
|
+
with open(os.path.join(self.scan_path, par_files[0])) as par_file:
|
|
210
|
+
par_reader = csv.reader(par_file, delimiter=' ')
|
|
211
|
+
for row in par_reader:
|
|
212
|
+
if len(row) == len(par_col_names):
|
|
213
|
+
row_scann = int(row[scann_col_idx])
|
|
214
|
+
if row_scann == self.scan_number:
|
|
215
|
+
par_dict = {}
|
|
216
|
+
for par_col_idx,par_col_name in par_file_cols.items():
|
|
217
|
+
# Convert the string par value from the file to an int or float, if possible.
|
|
218
|
+
par_value = row[int(par_col_idx)]
|
|
219
|
+
try:
|
|
220
|
+
par_value = int(par_value)
|
|
221
|
+
except ValueError:
|
|
222
|
+
try:
|
|
223
|
+
par_value = float(par_value)
|
|
224
|
+
except:
|
|
225
|
+
pass
|
|
226
|
+
par_dict[par_col_name] = par_value
|
|
227
|
+
return(par_dict)
|
|
228
|
+
raise(RuntimeError(f'{self.scan_title}: could not find scan pars for scan number {self.scan_number}'))
|
|
229
|
+
|
|
230
|
+
def get_counter_gain(self, counter_name):
|
|
231
|
+
for comment in self.spec_scan.comments:
|
|
232
|
+
match = re.search(f'{counter_name} gain: (?P<gain_value>\d+) (?P<unit_prefix>[m|u|n])A/V', comment)
|
|
233
|
+
if match:
|
|
234
|
+
unit_prefix = match['unit_prefix']
|
|
235
|
+
gain_scalar = 1 if unit_prefix == 'n' else 1e3 if unit_prefix == 'u' else 1e6
|
|
236
|
+
counter_gain = f'{float(match["gain_value"])*gain_scalar} nA/V'
|
|
237
|
+
return(counter_gain)
|
|
238
|
+
raise(RuntimeError(f'{self.scan_title}: could not get gain for counter {counter_name}'))
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
class LinearScanParser(ScanParser):
|
|
242
|
+
def __init__(self, spec_file_name, scan_number):
|
|
243
|
+
super().__init__(spec_file_name, scan_number)
|
|
244
|
+
|
|
245
|
+
self._spec_scan_motor_mnes = None
|
|
246
|
+
self._spec_scan_motor_vals = None
|
|
247
|
+
self._spec_scan_shape = None
|
|
248
|
+
self._spec_scan_dwell = None
|
|
249
|
+
|
|
250
|
+
@property
|
|
251
|
+
def spec_scan_motor_mnes(self):
|
|
252
|
+
if self._spec_scan_motor_mnes is None:
|
|
253
|
+
self._spec_scan_motor_mnes = self.get_spec_scan_motor_mnes()
|
|
254
|
+
return self._spec_scan_motor_mnes
|
|
255
|
+
@property
|
|
256
|
+
def spec_scan_motor_vals(self):
|
|
257
|
+
if self._spec_scan_motor_vals is None:
|
|
258
|
+
self._spec_scan_motor_vals = self.get_spec_scan_motor_vals()
|
|
259
|
+
return self._spec_scan_motor_vals
|
|
260
|
+
@property
|
|
261
|
+
def spec_scan_shape(self):
|
|
262
|
+
if self._spec_scan_shape is None:
|
|
263
|
+
self._spec_scan_shape = self.get_spec_scan_shape()
|
|
264
|
+
return self._spec_scan_shape
|
|
265
|
+
@property
|
|
266
|
+
def spec_scan_dwell(self):
|
|
267
|
+
if self._spec_scan_dwell is None:
|
|
268
|
+
self._spec_scan_dwell = self.get_spec_scan_dwell()
|
|
269
|
+
return(self._spec_scan_dwell)
|
|
270
|
+
|
|
271
|
+
def get_spec_scan_motor_names(self):
|
|
272
|
+
raise(NotImplementedError)
|
|
273
|
+
def get_spec_scan_motor_vals(self):
|
|
274
|
+
raise(NotImplementedError)
|
|
275
|
+
def get_spec_scan_shape(self):
|
|
276
|
+
raise(NotImplementedError)
|
|
277
|
+
def get_spec_scan_npts(self):
|
|
278
|
+
return(np.prod(self.spec_scan_shape))
|
|
279
|
+
def get_scan_step(self, scan_step_index:int):
|
|
280
|
+
scan_steps = np.ndindex(self.spec_scan_shape[::-1])
|
|
281
|
+
i = 0
|
|
282
|
+
while i <= scan_step_index:
|
|
283
|
+
scan_step = next(scan_steps)
|
|
284
|
+
i += 1
|
|
285
|
+
return(scan_step)
|
|
286
|
+
def get_scan_step_index(self, scan_step:tuple):
|
|
287
|
+
scan_steps = np.ndindex(self.spec_scan_shape[::-1])
|
|
288
|
+
scan_step_found = False
|
|
289
|
+
scan_step_index = -1
|
|
290
|
+
while not scan_step_found:
|
|
291
|
+
next_scan_step = next(scan_steps)
|
|
292
|
+
scan_step_index += 1
|
|
293
|
+
if next_scan_step == scan_step:
|
|
294
|
+
scan_step_found = True
|
|
295
|
+
break
|
|
296
|
+
return(scan_step_index)
|
|
297
|
+
|
|
298
|
+
|
|
299
|
+
class FMBLinearScanParser(LinearScanParser, FMBScanParser):
|
|
300
|
+
def __init__(self, spec_file_name, scan_number):
|
|
301
|
+
super().__init__(spec_file_name, scan_number)
|
|
302
|
+
|
|
303
|
+
def get_spec_scan_motor_mnes(self):
|
|
304
|
+
if self.spec_macro == 'flymesh':
|
|
305
|
+
return((self.spec_args[0], self.spec_args[5]))
|
|
306
|
+
elif self.spec_macro == 'flyscan':
|
|
307
|
+
return((self.spec_args[0],))
|
|
308
|
+
elif self.spec_macro in ('tseries', 'loopscan'):
|
|
309
|
+
return(('Time',))
|
|
310
|
+
else:
|
|
311
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine scan motors for scans of type {self.spec_macro}'))
|
|
312
|
+
def get_spec_scan_motor_vals(self):
|
|
313
|
+
if self.spec_macro == 'flymesh':
|
|
314
|
+
fast_mot_vals = np.linspace(float(self.spec_args[1]), float(self.spec_args[2]), int(self.spec_args[3])+1)
|
|
315
|
+
slow_mot_vals = np.linspace(float(self.spec_args[6]), float(self.spec_args[7]), int(self.spec_args[8])+1)
|
|
316
|
+
return((fast_mot_vals, slow_mot_vals))
|
|
317
|
+
elif self.spec_macro == 'flyscan':
|
|
318
|
+
mot_vals = np.linspace(float(self.spec_args[1]), float(self.spec_args[2]), int(self.spec_args[3])+1)
|
|
319
|
+
return((mot_vals,))
|
|
320
|
+
elif self.spec_macro in ('tseries', 'loopscan'):
|
|
321
|
+
return(self.spec_scan.data[:,0])
|
|
322
|
+
else:
|
|
323
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine scan motors for scans of type {self.spec_macro}'))
|
|
324
|
+
def get_spec_scan_shape(self):
|
|
325
|
+
if self.spec_macro == 'flymesh':
|
|
326
|
+
fast_mot_npts = int(self.spec_args[3])+1
|
|
327
|
+
slow_mot_npts = int(self.spec_args[8])+1
|
|
328
|
+
return((fast_mot_npts, slow_mot_npts))
|
|
329
|
+
elif self.spec_macro == 'flyscan':
|
|
330
|
+
mot_npts = int(self.spec_args[3])+1
|
|
331
|
+
return((mot_npts,))
|
|
332
|
+
elif self.spec_macro in ('tseries', 'loopscan'):
|
|
333
|
+
return(len(np.array(self.spec_scan.data[:,0])))
|
|
334
|
+
else:
|
|
335
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine scan shape for scans of type {self.spec_macro}'))
|
|
336
|
+
def get_spec_scan_dwell(self):
|
|
337
|
+
if self.spec_macro in ('flymesh', 'flyscan'):
|
|
338
|
+
return(float(self.spec_args[4]))
|
|
339
|
+
elif self.spec_macro in ('tseries', 'loopscan'):
|
|
340
|
+
return(float(self.spec_args[1]))
|
|
341
|
+
else:
|
|
342
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine dwell for scans of type {self.spec_macro}'))
|
|
343
|
+
def get_detector_data_path(self):
|
|
344
|
+
return(os.path.join(self.scan_path, self.scan_title))
|
|
345
|
+
|
|
346
|
+
|
|
347
|
+
class FMBSAXSWAXSScanParser(FMBLinearScanParser):
|
|
348
|
+
def __init__(self, spec_file_name, scan_number):
|
|
349
|
+
super().__init__(spec_file_name, scan_number)
|
|
350
|
+
|
|
351
|
+
def get_scan_title(self):
|
|
352
|
+
return(f'{self.scan_name}_{self.scan_number:03d}')
|
|
353
|
+
def get_detector_data_file(self, detector_prefix, scan_step_index:int):
|
|
354
|
+
scan_step = self.get_scan_step(scan_step_index)
|
|
355
|
+
file_indices = [f'{scan_step[i]:03d}' for i in range(len(self.spec_scan_shape)) if self.spec_scan_shape[i] != 1]
|
|
356
|
+
file_name = f'{self.scan_name}_{detector_prefix}_{self.scan_number:03d}_{"_".join(file_indices)}.tiff'
|
|
357
|
+
file_name_full = os.path.join(self.detector_data_path, file_name)
|
|
358
|
+
if os.path.isfile(file_name_full):
|
|
359
|
+
return(file_name_full)
|
|
360
|
+
else:
|
|
361
|
+
raise(RuntimeError(f'{self.scan_title}: could not find detector image file for detector {detector_prefix} scan step ({scan_step})'))
|
|
362
|
+
def get_detector_data(self, detector_prefix, scan_step_index:int):
|
|
363
|
+
from pyspec.file.tiff import TiffFile
|
|
364
|
+
image_file = self.get_detector_data_file(detector_prefix, scan_step_index)
|
|
365
|
+
with TiffFile(image_file) as tiff_file:
|
|
366
|
+
image_data = tiff_file.asarray()
|
|
367
|
+
return(image_data)
|
|
368
|
+
|
|
369
|
+
|
|
370
|
+
class FMBXRFScanParser(FMBLinearScanParser):
|
|
371
|
+
def __init__(self, spec_file_name, scan_number):
|
|
372
|
+
super().__init__(spec_file_name, scan_number)
|
|
373
|
+
def get_scan_title(self):
|
|
374
|
+
return(f'{self.scan_name}_scan{self.scan_number}')
|
|
375
|
+
def get_detector_data_file(self, detector_prefix, scan_step_index:int):
|
|
376
|
+
scan_step = self.get_scan_step(scan_step_index)
|
|
377
|
+
file_name = f'scan{self.scan_number}_{scan_step[1]:03d}.hdf5'
|
|
378
|
+
file_name_full = os.path.join(self.detector_data_path, file_name)
|
|
379
|
+
if os.path.isfile(file_name_full):
|
|
380
|
+
return(file_name_full)
|
|
381
|
+
else:
|
|
382
|
+
raise(RuntimeError(f'{self.scan_title}: could not find detector image file for detector {detector_prefix} scan step ({scan_step_index})'))
|
|
383
|
+
def get_detector_data(self, detector_prefix, scan_step_index:int):
|
|
384
|
+
import h5py
|
|
385
|
+
detector_file = self.get_detector_data_file(detector_prefix, scan_step_index)
|
|
386
|
+
scan_step = self.get_scan_step(scan_step_index)
|
|
387
|
+
with h5py.File(detector_file) as h5_file:
|
|
388
|
+
detector_data = h5_file['/entry/instrument/detector/data'][scan_step[0]]
|
|
389
|
+
return(detector_data)
|
|
390
|
+
|
|
391
|
+
|
|
392
|
+
class SMBLinearScanParser(LinearScanParser, SMBScanParser):
|
|
393
|
+
def __init__(self, spec_file_name, scan_number):
|
|
394
|
+
super().__init__(spec_file_name, scan_number)
|
|
395
|
+
def get_spec_scan_motor_mnes(self):
|
|
396
|
+
if self.spec_macro == 'flymesh':
|
|
397
|
+
return((self.spec_args[0], self.spec_args[5]))
|
|
398
|
+
elif self.spec_macro == 'flyscan':
|
|
399
|
+
return((self.spec_args[0],))
|
|
400
|
+
elif self.spec_macro in ('tseries', 'loopscan'):
|
|
401
|
+
return(('Time',))
|
|
402
|
+
else:
|
|
403
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine scan motors for scans of type {self.spec_macro}'))
|
|
404
|
+
def get_spec_scan_motor_vals(self):
|
|
405
|
+
if self.spec_macro == 'flymesh':
|
|
406
|
+
fast_mot_vals = np.linspace(float(self.spec_args[1]), float(self.spec_args[2]), int(self.spec_args[3])+1)
|
|
407
|
+
slow_mot_vals = np.linspace(float(self.spec_args[6]), float(self.spec_args[7]), int(self.spec_args[8])+1)
|
|
408
|
+
return((fast_mot_vals, slow_mot_vals))
|
|
409
|
+
elif self.spec_macro == 'flyscan':
|
|
410
|
+
mot_vals = np.linspace(float(self.spec_args[1]), float(self.spec_args[2]), int(self.spec_args[3])+1)
|
|
411
|
+
return((mot_vals,))
|
|
412
|
+
elif self.spec_macro in ('tseries', 'loopscan'):
|
|
413
|
+
return(self.spec_scan.data[:,0])
|
|
414
|
+
else:
|
|
415
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine scan motors for scans of type {self.spec_macro}'))
|
|
416
|
+
def get_spec_scan_shape(self):
|
|
417
|
+
if self.spec_macro == 'flymesh':
|
|
418
|
+
fast_mot_npts = int(self.spec_args[3])+1
|
|
419
|
+
slow_mot_npts = int(self.spec_args[8])+1
|
|
420
|
+
return((fast_mot_npts, slow_mot_npts))
|
|
421
|
+
elif self.spec_macro == 'flyscan':
|
|
422
|
+
mot_npts = int(self.spec_args[3])+1
|
|
423
|
+
return((mot_npts,))
|
|
424
|
+
elif self.spec_macro in ('tseries', 'loopscan'):
|
|
425
|
+
return(len(np.array(self.spec_scan.data[:,0])))
|
|
426
|
+
else:
|
|
427
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine scan shape for scans of type {self.spec_macro}'))
|
|
428
|
+
def get_spec_scan_dwell(self):
|
|
429
|
+
if self.spec_macro == 'flymesh':
|
|
430
|
+
return(float(self.spec_args[4]))
|
|
431
|
+
elif self.spec_macro == 'flyscan':
|
|
432
|
+
return(float(self.spec_args[-1]))
|
|
433
|
+
else:
|
|
434
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine dwell time for scans of type {self.spec_macro}'))
|
|
435
|
+
def get_detector_data_path(self):
|
|
436
|
+
return(os.path.join(self.scan_path, str(self.scan_number)))
|
|
437
|
+
def get_detector_data_file(self, detector_prefix, scan_step_index:int):
|
|
438
|
+
scan_step = self.get_scan_step(scan_step_index)
|
|
439
|
+
if len(scan_step) == 1:
|
|
440
|
+
scan_step = (0, *scan_step)
|
|
441
|
+
file_name_pattern = f'{detector_prefix}_{self.scan_name}_*_{scan_step[0]}_data_{(scan_step[1]+1):06d}.h5'
|
|
442
|
+
file_name_matches = fnmatch.filter(os.listdir(self.detector_data_path), file_name_pattern)
|
|
443
|
+
if len(file_name_matches) == 1:
|
|
444
|
+
return(os.path.join(self.detector_data_path, file_name_matches[0]))
|
|
445
|
+
else:
|
|
446
|
+
raise(RuntimeError(f'{self.scan_title}: could not find detector image file for detector {detector_prefix} scan step ({scan_step_index})'))
|
|
447
|
+
def get_detector_data(self, detector_prefix, scan_step_index:int):
|
|
448
|
+
import h5py
|
|
449
|
+
image_file = self.get_detector_data_file(detector_prefix, scan_step_index)
|
|
450
|
+
with h5py.File(image_file) as h5_file:
|
|
451
|
+
image_data = h5_file['/entry/data/data'][0]
|
|
452
|
+
return(image_data)
|
|
453
|
+
|
|
454
|
+
|
|
455
|
+
class RotationScanParser(ScanParser):
|
|
456
|
+
def __init__(self, spec_file_name, scan_number):
|
|
457
|
+
super().__init__(spec_file_name, scan_number)
|
|
458
|
+
|
|
459
|
+
self._scan_type = None
|
|
460
|
+
self._theta_vals = None
|
|
461
|
+
self._horizontal_shift = None
|
|
462
|
+
self._vertical_shift = None
|
|
463
|
+
self._starting_image_index = None
|
|
464
|
+
self._starting_image_offset = None
|
|
465
|
+
|
|
466
|
+
@property
|
|
467
|
+
def scan_type(self):
|
|
468
|
+
if self._scan_type is None:
|
|
469
|
+
self._scan_type = self.get_scan_type()
|
|
470
|
+
return(self._scan_type)
|
|
471
|
+
@property
|
|
472
|
+
def theta_vals(self):
|
|
473
|
+
if self._theta_vals is None:
|
|
474
|
+
self._theta_vals = self.get_theta_vals()
|
|
475
|
+
return(self._theta_vals)
|
|
476
|
+
@property
|
|
477
|
+
def horizontal_shift(self):
|
|
478
|
+
if self._horizontal_shift is None:
|
|
479
|
+
self._horizontal_shift = self.get_horizontal_shift()
|
|
480
|
+
return(self._horizontal_shift)
|
|
481
|
+
@property
|
|
482
|
+
def vertical_shift(self):
|
|
483
|
+
if self._vertical_shift is None:
|
|
484
|
+
self._vertical_shift = self.get_vertical_shift()
|
|
485
|
+
return(self._vertical_shift)
|
|
486
|
+
@property
|
|
487
|
+
def starting_image_index(self):
|
|
488
|
+
if self._starting_image_index is None:
|
|
489
|
+
self._starting_image_index = self.get_starting_image_index()
|
|
490
|
+
return(self._starting_image_index)
|
|
491
|
+
@property
|
|
492
|
+
def starting_image_offset(self):
|
|
493
|
+
if self._starting_image_offset is None:
|
|
494
|
+
self._starting_image_offset = self.get_starting_image_offset()
|
|
495
|
+
return(self._starting_image_offset)
|
|
496
|
+
|
|
497
|
+
def get_scan_type(self):
|
|
498
|
+
return(None)
|
|
499
|
+
def get_theta_vals(self):
|
|
500
|
+
raise(NotImplementedError)
|
|
501
|
+
def get_horizontal_shift(self):
|
|
502
|
+
raise(NotImplementedError)
|
|
503
|
+
def get_vertical_shift(self):
|
|
504
|
+
raise(NotImplementedError)
|
|
505
|
+
def get_starting_image_index(self):
|
|
506
|
+
raise(NotImplementedError)
|
|
507
|
+
def get_starting_image_offset(self):
|
|
508
|
+
raise(NotImplementedError)
|
|
509
|
+
def get_num_image(self, detector_prefix):
|
|
510
|
+
raise(NotImplementedError)
|
|
511
|
+
|
|
512
|
+
|
|
513
|
+
class FMBRotationScanParser(RotationScanParser, FMBScanParser):
|
|
514
|
+
def __init__(self, spec_file_name, scan_number):
|
|
515
|
+
super().__init__(spec_file_name, scan_number)
|
|
516
|
+
def get_spec_scan_npts(self):
|
|
517
|
+
if self.spec_macro == 'flyscan':
|
|
518
|
+
if len(self.spec_args) == 2:
|
|
519
|
+
# Flat field (dark or bright)
|
|
520
|
+
return(int(self.spec_args[0])+1)
|
|
521
|
+
elif len(self.spec_args) == 5:
|
|
522
|
+
return(int(self.spec_args[3])+1)
|
|
523
|
+
else:
|
|
524
|
+
raise(RuntimeError(f'{self.scan_title}: cannot obtain number of points from '+
|
|
525
|
+
f'{self.spec_macro} with arguments {self.spec_args}'))
|
|
526
|
+
else:
|
|
527
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine number of points for scans '+
|
|
528
|
+
f'of type {self.spec_macro}'))
|
|
529
|
+
def get_theta_vals(self):
|
|
530
|
+
if self.spec_macro == 'flyscan':
|
|
531
|
+
if len(self.spec_args) == 2:
|
|
532
|
+
# Flat field (dark or bright)
|
|
533
|
+
return({'num': int(self.spec_args[0])})
|
|
534
|
+
elif len(self.spec_args) == 5:
|
|
535
|
+
return({'start': float(self.spec_args[1]), 'end': float(self.spec_args[2]),
|
|
536
|
+
'num': int(self.spec_args[3])+1})
|
|
537
|
+
else:
|
|
538
|
+
raise(RuntimeError(f'{self.scan_title}: cannot obtain theta values from '+
|
|
539
|
+
f'{self.spec_macro} with arguments {self.spec_args}'))
|
|
540
|
+
else:
|
|
541
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine theta values for scans '+
|
|
542
|
+
f'of type {self.spec_macro}'))
|
|
543
|
+
def get_horizontal_shift(self):
|
|
544
|
+
return(0.0)
|
|
545
|
+
def get_vertical_shift(self):
|
|
546
|
+
return(float(self.get_spec_positioner_value('4C_samz')))
|
|
547
|
+
def get_starting_image_index(self):
|
|
548
|
+
return(0)
|
|
549
|
+
def get_starting_image_offset(self):
|
|
550
|
+
return(1)
|
|
551
|
+
def get_num_image(self, detector_prefix):
|
|
552
|
+
import h5py
|
|
553
|
+
detector_file = self.get_detector_data_file(detector_prefix)
|
|
554
|
+
with h5py.File(detector_file) as h5_file:
|
|
555
|
+
num_image = h5_file['/entry/instrument/detector/data'].shape[0]
|
|
556
|
+
return(num_image-self.starting_image_offset)
|
|
557
|
+
def get_detector_data_path(self):
|
|
558
|
+
return(self.scan_path)
|
|
559
|
+
def get_detector_data_file(self, detector_prefix):
|
|
560
|
+
prefix = detector_prefix.upper()
|
|
561
|
+
file_name = f'{self.scan_name}_{prefix}_{self.scan_number:03d}.h5'
|
|
562
|
+
file_name_full = os.path.join(self.detector_data_path, file_name)
|
|
563
|
+
if os.path.isfile(file_name_full):
|
|
564
|
+
return(file_name_full)
|
|
565
|
+
else:
|
|
566
|
+
raise(RuntimeError(f'{self.scan_title}: could not find detector image file for '+
|
|
567
|
+
f'detector {detector_prefix}'))
|
|
568
|
+
#@cache
|
|
569
|
+
def get_all_detector_data_in_file(self, detector_prefix, scan_step_index=None):
|
|
570
|
+
import h5py
|
|
571
|
+
detector_file = self.get_detector_data_file(detector_prefix)
|
|
572
|
+
with h5py.File(detector_file) as h5_file:
|
|
573
|
+
if scan_step_index is None:
|
|
574
|
+
detector_data = h5_file['/entry/instrument/detector/data'][
|
|
575
|
+
self.starting_image_index:]
|
|
576
|
+
elif isinstance(scan_step_index, int):
|
|
577
|
+
detector_data = h5_file['/entry/instrument/detector/data'][
|
|
578
|
+
self.starting_image_index+scan_step_index]
|
|
579
|
+
elif isinstance(scan_step_index, (list, tuple)) and len(scan_step_index) == 2:
|
|
580
|
+
detector_data = h5_file['/entry/instrument/detector/data'][
|
|
581
|
+
self.starting_image_index+scan_step_index[0]:
|
|
582
|
+
self.starting_image_index+scan_step_index[1]]
|
|
583
|
+
else:
|
|
584
|
+
raise(ValueError(f'Invalid parameter scan_step_index ({scan_step_index})'))
|
|
585
|
+
return(detector_data)
|
|
586
|
+
def get_detector_data(self, detector_prefix, scan_step_index=None):
|
|
587
|
+
return(self.get_all_detector_data_in_file(detector_prefix, scan_step_index))
|
|
588
|
+
|
|
589
|
+
|
|
590
|
+
class SMBRotationScanParser(RotationScanParser, SMBScanParser):
|
|
591
|
+
def __init__(self, spec_file_name, scan_number):
|
|
592
|
+
super().__init__(spec_file_name, scan_number)
|
|
593
|
+
self.par_file_pattern = f'id*-*tomo*-{self.scan_name}'
|
|
594
|
+
def get_spec_scan_npts(self):
|
|
595
|
+
if self.spec_macro == 'slew_ome' or self.spec_macro == 'rams4_slew_ome':
|
|
596
|
+
return(int(self.pars['nframes_real']))
|
|
597
|
+
else:
|
|
598
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine number of points for scans of type {self.spec_macro}'))
|
|
599
|
+
def get_scan_type(self):
|
|
600
|
+
try:
|
|
601
|
+
return(self.pars['tomo_type'])
|
|
602
|
+
except:
|
|
603
|
+
try:
|
|
604
|
+
return(self.pars['tomotype'])
|
|
605
|
+
except:
|
|
606
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine the scan_type'))
|
|
607
|
+
def get_theta_vals(self):
|
|
608
|
+
return({'start': float(self.pars['ome_start_real']),
|
|
609
|
+
'end': float(self.pars['ome_end_real']), 'num': int(self.pars['nframes_real'])})
|
|
610
|
+
def get_horizontal_shift(self):
|
|
611
|
+
try:
|
|
612
|
+
return(float(self.pars['rams4x']))
|
|
613
|
+
except:
|
|
614
|
+
try:
|
|
615
|
+
return(float(self.pars['ramsx']))
|
|
616
|
+
except:
|
|
617
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine the horizontal shift'))
|
|
618
|
+
def get_vertical_shift(self):
|
|
619
|
+
try:
|
|
620
|
+
return(float(self.pars['rams4z']))
|
|
621
|
+
except:
|
|
622
|
+
try:
|
|
623
|
+
return(float(self.pars['ramsz']))
|
|
624
|
+
except:
|
|
625
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine the vertical shift'))
|
|
626
|
+
def get_starting_image_index(self):
|
|
627
|
+
try:
|
|
628
|
+
return(int(self.pars['junkstart']))
|
|
629
|
+
except:
|
|
630
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine first detector image index'))
|
|
631
|
+
def get_starting_image_offset(self):
|
|
632
|
+
try:
|
|
633
|
+
return(int(self.pars['goodstart'])-self.get_starting_image_index())
|
|
634
|
+
except:
|
|
635
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine index offset of first good '+
|
|
636
|
+
'detector image'))
|
|
637
|
+
def get_num_image(self, detector_prefix=None):
|
|
638
|
+
try:
|
|
639
|
+
return(int(self.pars['nframes_real']))
|
|
640
|
+
# indexRegex = re.compile(r'\d+')
|
|
641
|
+
# # At this point only tiffs
|
|
642
|
+
# path = self.get_detector_data_path()
|
|
643
|
+
# files = sorted([f for f in os.listdir(path) if os.path.isfile(os.path.join(path, f)) and
|
|
644
|
+
# f.endswith('.tif') and indexRegex.search(f)])
|
|
645
|
+
# return(len(files)-self.starting_image_offset)
|
|
646
|
+
except:
|
|
647
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine the number of good '+
|
|
648
|
+
'detector images'))
|
|
649
|
+
def get_detector_data_path(self):
|
|
650
|
+
return(os.path.join(self.scan_path, str(self.scan_number), 'nf'))
|
|
651
|
+
def get_detector_data_file(self, scan_step_index:int):
|
|
652
|
+
file_name = f'nf_{self.starting_image_index+scan_step_index:06d}.tif'
|
|
653
|
+
file_name_full = os.path.join(self.detector_data_path, file_name)
|
|
654
|
+
if os.path.isfile(file_name_full):
|
|
655
|
+
return(file_name_full)
|
|
656
|
+
else:
|
|
657
|
+
raise(RuntimeError(f'{self.scan_title}: could not find detector image file for '+
|
|
658
|
+
f'scan step ({scan_step_index})'))
|
|
659
|
+
def get_detector_data(self, detector_prefix, scan_step_index=None):
|
|
660
|
+
if scan_step_index is None:
|
|
661
|
+
detector_data = []
|
|
662
|
+
for index in range(len(self.get_num_image(detector_prefix))):
|
|
663
|
+
detector_data.append(self.get_detector_data(detector_prefix, index))
|
|
664
|
+
detector_data = np.asarray(detector_data)
|
|
665
|
+
elif isinstance(scan_step_index, int):
|
|
666
|
+
image_file = self.get_detector_data_file(scan_step_index)
|
|
667
|
+
from pyspec.file.tiff import TiffFile
|
|
668
|
+
with TiffFile(image_file) as tiff_file:
|
|
669
|
+
detector_data = tiff_file.asarray()
|
|
670
|
+
elif isinstance(scan_step_index, (list, tuple)) and len(scan_step_index) == 2:
|
|
671
|
+
detector_data = []
|
|
672
|
+
for index in range(scan_step_index[0], scan_step_index[1]):
|
|
673
|
+
detector_data.append(self.get_detector_data(detector_prefix, index))
|
|
674
|
+
detector_data = np.asarray(detector_data)
|
|
675
|
+
else:
|
|
676
|
+
raise(ValueError(f'Invalid parameter scan_step_index ({scan_step_index})'))
|
|
677
|
+
return(detector_data)
|
|
678
|
+
|
|
679
|
+
|
|
680
|
+
class MCAScanParser(ScanParser):
|
|
681
|
+
def __init__(self, spec_file_name, scan_number):
|
|
682
|
+
super().__init__(spec_file_name, scan_number)
|
|
683
|
+
|
|
684
|
+
self._dwell_time = None
|
|
685
|
+
self._detector_num_bins = None
|
|
686
|
+
|
|
687
|
+
@property
|
|
688
|
+
def dwell_time(self):
|
|
689
|
+
if self._dwell_time is None:
|
|
690
|
+
self._dwell_time = self.get_dwell_time()
|
|
691
|
+
return(self._dwell_time)
|
|
692
|
+
|
|
693
|
+
def get_dwell_time(self):
|
|
694
|
+
raise(NotImplementedError)
|
|
695
|
+
@cache
|
|
696
|
+
def get_detector_num_bins(self, detector_prefix):
|
|
697
|
+
raise(NotImplementedError)
|
|
698
|
+
|
|
699
|
+
class SMBMCAScanParser(MCAScanParser, SMBScanParser):
|
|
700
|
+
def __init__(self, spec_file_name, scan_number):
|
|
701
|
+
super().__init__(spec_file_name, scan_number)
|
|
702
|
+
|
|
703
|
+
def get_spec_scan_npts(self):
|
|
704
|
+
if self.spec_macro == 'tseries':
|
|
705
|
+
return(1)
|
|
706
|
+
elif self.spec_macro == 'ascan':
|
|
707
|
+
return(int(self.spec_args[3]))
|
|
708
|
+
elif self.spec_scan == 'wbslew_scan':
|
|
709
|
+
return(1)
|
|
710
|
+
else:
|
|
711
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine number of points for scans of type {self.spec_macro}'))
|
|
712
|
+
|
|
713
|
+
def get_dwell_time(self):
|
|
714
|
+
if self.spec_macro == 'tseries':
|
|
715
|
+
return(float(self.spec_args[1]))
|
|
716
|
+
elif self.spec_macro == 'ascan':
|
|
717
|
+
return(float(self.spec_args[4]))
|
|
718
|
+
elif self.spec_macro == 'wbslew_scan':
|
|
719
|
+
return(float(self.spec_args[3]))
|
|
720
|
+
else:
|
|
721
|
+
raise(RuntimeError(f'{self.scan_title}: cannot determine dwell time for scans of type {self.spec_macro}'))
|
|
722
|
+
|
|
723
|
+
def get_detector_num_bins(self, detector_prefix):
|
|
724
|
+
with open(self.get_detector_file(detector_prefix)) as detector_file:
|
|
725
|
+
lines = detector_file.readlines()
|
|
726
|
+
for line in lines:
|
|
727
|
+
if line.startswith('#@CHANN'):
|
|
728
|
+
try:
|
|
729
|
+
line_prefix, number_saved, first_saved, last_saved, reduction_coef = line.split()
|
|
730
|
+
return(int(number_saved))
|
|
731
|
+
except:
|
|
732
|
+
continue
|
|
733
|
+
raise(RuntimeError(f'{self.scan_title}: could not find num_bins for detector {detector_prefix}'))
|
|
734
|
+
|
|
735
|
+
def get_detector_data_path(self):
|
|
736
|
+
return(self.scan_path)
|
|
737
|
+
|
|
738
|
+
def get_detector_file(self, detector_prefix, scan_step_index:int=0):
|
|
739
|
+
file_name = f'spec.log.scan{self.scan_number}.mca1.mca'
|
|
740
|
+
file_name_full = os.path.join(self.detector_data_path, file_name)
|
|
741
|
+
if os.path.isfile(file_name_full):
|
|
742
|
+
return(file_name_full)
|
|
743
|
+
else:
|
|
744
|
+
raise(RuntimeError(f'{self.scan_title}: could not find detector image file'))
|
|
745
|
+
|
|
746
|
+
@cache
|
|
747
|
+
def get_all_detector_data(self, detector_prefix):
|
|
748
|
+
# This should be easy with pyspec, but there are bugs in pyspec for MCA data.....
|
|
749
|
+
# or is the 'bug' from a nonstandard implementation of some macro on our end?
|
|
750
|
+
# According to spec manual and pyspec code, mca data should always begin w/ '@A'
|
|
751
|
+
# In example scans, it begins with '@mca1' instead
|
|
752
|
+
data = []
|
|
753
|
+
|
|
754
|
+
with open(self.get_detector_file(detector_prefix)) as detector_file:
|
|
755
|
+
lines = [line.strip("\\\n") for line in detector_file.readlines()]
|
|
756
|
+
|
|
757
|
+
num_bins = self.get_detector_num_bins(detector_prefix)
|
|
758
|
+
|
|
759
|
+
counter = 0
|
|
760
|
+
for line in lines:
|
|
761
|
+
a = line.split()
|
|
762
|
+
|
|
763
|
+
if len(a) > 0:
|
|
764
|
+
if a[0] == ("@"+detector_prefix):
|
|
765
|
+
counter = 1
|
|
766
|
+
spectrum = np.zeros(num_bins)
|
|
767
|
+
if counter == 1:
|
|
768
|
+
b = np.array(a[1:]).astype('uint16')
|
|
769
|
+
spectrum[(counter-1)*25:((counter-1)*25+25)] = b
|
|
770
|
+
counter = counter + 1
|
|
771
|
+
elif counter > 1 and counter <= (np.floor(num_bins/25.)):
|
|
772
|
+
b = np.array(a).astype('uint16')
|
|
773
|
+
spectrum[(counter-1)*25:((counter-1)*25+25)] = b
|
|
774
|
+
counter = counter+1
|
|
775
|
+
elif counter == (np.ceil(num_bins/25.)):
|
|
776
|
+
b = np.array(a).astype('uint16')
|
|
777
|
+
spectrum[(counter-1)*25:((counter-1)*25+(np.mod(num_bins,25)))] = b
|
|
778
|
+
data.append(spectrum)
|
|
779
|
+
counter = 0
|
|
780
|
+
|
|
781
|
+
return(data)
|
|
782
|
+
|
|
783
|
+
def get_detector_data(self, detector_prefix, scan_step_index:int):
|
|
784
|
+
detector_data = self.get_all_detector_data(detector_prefix)
|
|
785
|
+
return(detector_data[scan_step_index])
|