sodetlib 0.6.1rc1__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.
sodetlib/stream.py ADDED
@@ -0,0 +1,291 @@
1
+ from sotodlib.io import load_smurf
2
+ from sodetlib.util import Registers
3
+ from sodetlib.operations import uxm_setup
4
+ import os
5
+ import time
6
+
7
+ try:
8
+ from pysmurf.client.util.pub import set_action
9
+ except:
10
+ set_action = lambda : (lambda f : f)
11
+
12
+
13
+ def get_session_files(stream_id, session_id, idx=None,
14
+ base_dir='/data/so/timestreams'):
15
+ """
16
+ Gets a list of all files on the system corresponding to a given streaming
17
+ session.
18
+
19
+ Args
20
+ ----
21
+ stream_id : str
22
+ stream_id for the stream you wish to load. Often this will be in
23
+ cfg.stream_id
24
+ session_id : int
25
+ Session id corresonding with the stream session you wish to load.
26
+ This is what is returned by the stream-taking functions.
27
+ idx : int, list(int), optional
28
+ Index of file you wish to load. Long streams are chunked into 10-minute
29
+ files, and this parameter can used to isolate a smaller part of a long
30
+ stream.
31
+ base_dir : str
32
+ Base directory where timestreams are stored. Defaults to
33
+ /data/so/timestreams.
34
+ """
35
+ subdir = os.path.join(base_dir, str(session_id)[:5], stream_id)
36
+ files = sorted([
37
+ os.path.join(subdir, f) for f in os.listdir(subdir)
38
+ if str(session_id) in f
39
+ ])
40
+
41
+ if idx is None:
42
+ return files
43
+ elif isinstance(idx, int):
44
+ return files[idx]
45
+ else: # list of indexes
46
+ return [files[i] for i in idx]
47
+
48
+ def load_session_status(stream_id, session_id, base_dir='/data/so/timestreams'):
49
+ """
50
+ Gets SmurfStatus object for a given stream.
51
+
52
+ Args
53
+ ----
54
+ stream_id : str
55
+ stream_id for the stream you wish to load. Often this will be in
56
+ cfg.stream_id
57
+ session_id : int
58
+ Session id corresonding with the stream session you wish to load.
59
+ This is what is returned by the stream-taking functions.
60
+ base_dir : str
61
+ Base directory where timestreams are stored. Defaults to
62
+ /data/so/timestreams.
63
+ """
64
+ files = get_session_files(stream_id, session_id, base_dir=base_dir)
65
+ if len(files) == 0:
66
+ raise FileNotFoundError(
67
+ f"Could not find files for {(stream_id, session_id)}"
68
+ )
69
+ return load_smurf.SmurfStatus.from_file(files[0])
70
+
71
+
72
+ def load_session(stream_id, session_id, idx=None,
73
+ base_dir='/data/so/timestreams', show_pb=False, **kwargs):
74
+ """
75
+ Loads a stream-session into an axis manager. Any additional keyword
76
+ arguments will be passed to the ``load_smurf.load_file`` function.
77
+
78
+ Args
79
+ ----
80
+ stream_id : str
81
+ stream_id for the stream you wish to load. Often this will be in
82
+ cfg.stream_id
83
+ session_id : int
84
+ Session id corresonding with the stream session you wish to load.
85
+ This is what is returned by the stream-taking functions.
86
+ idx : int, list(int), optional
87
+ Index of file you wish to load. Long streams are chunked into 10-minute
88
+ files, and this parameter can used to isolate a smaller part of a long
89
+ stream.
90
+ base_dir : str
91
+ Base directory where timestreams are stored. Defaults to
92
+ /data/so/timestreams.
93
+ """
94
+ files = get_session_files(stream_id, session_id, idx=idx,
95
+ base_dir=base_dir)
96
+ if len(files) == 0:
97
+ raise FileNotFoundError(
98
+ f"Could not find files for {(stream_id, session_id)}"
99
+ )
100
+ am = load_smurf.load_file(files, show_pb=show_pb, **kwargs)
101
+
102
+ if 'ch_info' not in am._fields:
103
+ am.wrap('ch_info', am.det_info.smurf)
104
+
105
+ return am
106
+
107
+
108
+ @set_action()
109
+ def take_g3_data(S, dur, **stream_kw):
110
+ """
111
+ Takes data for some duration
112
+
113
+ Args
114
+ ----
115
+ S : SmurfControl
116
+ Pysmurf control object
117
+ dur : float
118
+ Duration to take data over
119
+
120
+ Returns
121
+ -------
122
+ session_id : int
123
+ Id used to read back stream data
124
+ """
125
+ stream_g3_on(S, **stream_kw)
126
+ time.sleep(dur)
127
+ return stream_g3_off(S, emulator=stream_kw.get('emulator', False))
128
+
129
+
130
+ @set_action()
131
+ def stream_g3_on(S, make_freq_mask=False, emulator=False, tag=None,
132
+ channel_mask=None, filter_wait_time=2, make_datfile=False,
133
+ downsample_factor=None, downsample_mode=None,
134
+ filter_disable=False, filter_order=None, filter_cutoff=None,
135
+ stream_type=None, subtype='stream', enable_compression=None):
136
+ """
137
+ Starts the G3 data-stream. Returns the session-id corresponding with the
138
+ data stream.
139
+
140
+ Args
141
+ ----
142
+ S : S
143
+ Pysmurf control object
144
+ make_freq_mask : bool, optional
145
+ Tell pysmurf to write and register the current freq mask
146
+ emulator : bool
147
+ If True, will enable the emulator source data-generator. Defaults to
148
+ False.
149
+ tag : optional(string)
150
+ If set, this will attach the tag to the g3 stream
151
+ channel_mask : optional(list)
152
+ List of channels to stream. If None, this will stream all channels with
153
+ a probe tone
154
+ filter_wait_time : float
155
+ Seconds to wait after resetting the filter before writing data to disk
156
+ make_datfile bool
157
+ If True, will create a datfile
158
+ downsample_factor : optional(int)
159
+ Downsample factor. If None, this will be pulled from the device
160
+ cfg.
161
+ downsample_mode : optional(string)
162
+ Downsample mode, can either be 'internal' or 'external'. If not set,
163
+ this will be pulled from the device cfg.
164
+ filter_disable : bool
165
+ If true, will disable the downsample filter before streaming.
166
+ filter_order : int
167
+ Order of the downsample filter. Read from device config by default.
168
+ filter_cutoff : float
169
+ The cutoff frequency in Hz for the downsample filter.
170
+ Read from device config by default.
171
+ stream_type : optional(string)
172
+ Type of stream. This should either be "obs" or "oper". If None,
173
+ it will be determined based off of the subtype. ('stream', 'cmb', and
174
+ 'cal', will automatically be set to 'obs' type)
175
+ subtype : optional(string)
176
+ Stream subtype. This defaults to 'stream'.
177
+ enable_compression : optional(bool)
178
+ If true, will tell the smurf-streamer to compress data.
179
+
180
+ Return
181
+ -------
182
+ session_id : int
183
+ Id used to read back streamed data
184
+ """
185
+ cfg = S._sodetlib_cfg
186
+ if stream_type is None:
187
+ if subtype in ['stream', 'cmb', 'cal']:
188
+ stream_type = 'obs'
189
+ else:
190
+ stream_type = 'oper'
191
+
192
+ if enable_compression is None:
193
+ enable_compression = cfg.dev.exp.get('enable_compression', True)
194
+
195
+ tags = f'{stream_type},{subtype}'
196
+ if tag is not None:
197
+ tags += ',' + tag
198
+
199
+ reg = Registers(S)
200
+
201
+ reg.pysmurf_action.set(S.pub._action)
202
+ reg.pysmurf_action_timestamp.set(S.pub._action_ts)
203
+ reg.stream_tag.set(tags)
204
+
205
+ reg.enable_compression.set(enable_compression)
206
+
207
+ if downsample_mode is None:
208
+ downsample_mode = cfg.dev.exp['downsample_mode']
209
+ if downsample_factor is None:
210
+ downsample_factor = cfg.dev.exp['downsample_factor']
211
+ if filter_order is None:
212
+ filter_order = cfg.dev.exp["downsample_filter"]["order"]
213
+ if filter_cutoff is None:
214
+ filter_cutoff = cfg.dev.exp["downsample_filter"]["cutoff_freq"]
215
+
216
+ S.set_downsample_mode(downsample_mode)
217
+ S.set_downsample_factor(downsample_factor)
218
+ S.set_downsample_filter(filter_order, filter_cutoff)
219
+ S.set_filter_disable(int(filter_disable))
220
+
221
+ # ensure fixed tones are on
222
+ uxm_setup.turn_on_fixed_tones(S, cfg)
223
+
224
+ S.stream_data_on(make_freq_mask=make_freq_mask, channel_mask=channel_mask,
225
+ filter_wait_time=filter_wait_time, make_datafile=make_datfile)
226
+
227
+ if emulator:
228
+ reg.source_enable.set(1)
229
+ S.set_stream_enable(1)
230
+
231
+ reg.open_g3stream.set(1)
232
+
233
+ # Sometimes it takes a bit for data to propogate through to the
234
+ # streamer
235
+ for _ in range(10):
236
+ sess_id = reg.g3_session_id.get()
237
+ if sess_id != 0:
238
+ break
239
+ time.sleep(0.5)
240
+ S.log(f"Session id: {sess_id}")
241
+ return sess_id
242
+
243
+
244
+ @set_action()
245
+ def stream_g3_off(S, emulator=False):
246
+ """
247
+ Stops the G3 data-stream. Returns the session-id corresponding with the
248
+ data stream.
249
+
250
+ Args
251
+ ----
252
+ S : S
253
+ Pysmurf control object
254
+ emulator : bool
255
+ If True, will enable the emulator source data-generator. Defaults to
256
+ False.
257
+
258
+ Return
259
+ -------
260
+ session_id : int
261
+ Id used to read back streamed data
262
+ """
263
+ reg = Registers(S)
264
+ sess_id = reg.g3_session_id.get()
265
+ if sess_id == 0:
266
+ S.log("Session-id returned 0! Will try to obtain from file path")
267
+ fpath = reg.g3_filepath.get()
268
+ try:
269
+ sess_id = int(os.path.basename(fpath).split('_')[0])
270
+ except Exception:
271
+ S.log("Could not extract session id from filepath! Setting to 0")
272
+ sess_id = 0
273
+
274
+ if emulator:
275
+ reg.source_enable.set(0)
276
+
277
+ S.set_stream_enable(0)
278
+ S.stream_data_off()
279
+
280
+ reg.open_g3stream.set(0)
281
+ reg.pysmurf_action.set('')
282
+ reg.pysmurf_action_timestamp.set(0)
283
+ reg.stream_tag.set('')
284
+
285
+ # Waits until file is closed out before returning
286
+ S.log("Waiting for g3 file to close out")
287
+ while reg.g3_session_id.get() != 0:
288
+ time.sleep(0.5)
289
+
290
+ return sess_id
291
+