gwpy 3.0.6__py3-none-any.whl → 3.0.7__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 gwpy might be problematic. Click here for more details.
- gwpy/_version.py +2 -2
- {gwpy-3.0.6.dist-info → gwpy-3.0.7.dist-info}/METADATA +1 -1
- {gwpy-3.0.6.dist-info → gwpy-3.0.7.dist-info}/RECORD +7 -11
- gwpy/io/gwf/__init__.py +0 -768
- gwpy/io/gwf/_framecpp.py +0 -739
- gwpy/io/gwf/_lalframe.py +0 -86
- gwpy/timeseries/io/gwf/lalframe2.py +0 -582
- {gwpy-3.0.6.dist-info → gwpy-3.0.7.dist-info}/LICENSE +0 -0
- {gwpy-3.0.6.dist-info → gwpy-3.0.7.dist-info}/WHEEL +0 -0
- {gwpy-3.0.6.dist-info → gwpy-3.0.7.dist-info}/entry_points.txt +0 -0
- {gwpy-3.0.6.dist-info → gwpy-3.0.7.dist-info}/top_level.txt +0 -0
gwpy/io/gwf/__init__.py
DELETED
|
@@ -1,768 +0,0 @@
|
|
|
1
|
-
# -*- coding: utf-8 -*-
|
|
2
|
-
# Copyright (C) Duncan Macleod (2014-2020)
|
|
3
|
-
#
|
|
4
|
-
# This file is part of GWpy.
|
|
5
|
-
#
|
|
6
|
-
# GWpy is free software: you can redistribute it and/or modify
|
|
7
|
-
# it under the terms of the GNU General Public License as published by
|
|
8
|
-
# the Free Software Foundation, either version 3 of the License, or
|
|
9
|
-
# (at your option) any later version.
|
|
10
|
-
#
|
|
11
|
-
# GWpy is distributed in the hope that it will be useful,
|
|
12
|
-
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
13
|
-
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
|
14
|
-
# GNU General Public License for more details.
|
|
15
|
-
#
|
|
16
|
-
# You should have received a copy of the GNU General Public License
|
|
17
|
-
# along with GWpy. If not, see <http://www.gnu.org/licenses/>.
|
|
18
|
-
|
|
19
|
-
"""I/O utilities for GWF files.
|
|
20
|
-
"""
|
|
21
|
-
|
|
22
|
-
import importlib
|
|
23
|
-
import warnings
|
|
24
|
-
from functools import wraps
|
|
25
|
-
|
|
26
|
-
import numpy
|
|
27
|
-
|
|
28
|
-
from ...segments import (Segment, SegmentList)
|
|
29
|
-
from ...time import (to_gps, LIGOTimeGPS)
|
|
30
|
-
from ..cache import read_cache
|
|
31
|
-
from ..utils import file_path
|
|
32
|
-
|
|
33
|
-
__author__ = 'Duncan Macleod <duncan.macleod@ligo.org>'
|
|
34
|
-
|
|
35
|
-
APIS = [
|
|
36
|
-
"frameCPP",
|
|
37
|
-
"LALFrame",
|
|
38
|
-
"FrameL",
|
|
39
|
-
]
|
|
40
|
-
|
|
41
|
-
# first 4 bytes of any valid GWF file (see LIGO-T970130 §4.3.1)
|
|
42
|
-
GWF_SIGNATURE = b'IGWD'
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
# -- library finding ----------------------------------------------------------
|
|
46
|
-
|
|
47
|
-
def _import_gwf_library(library, package=__package__, prefix=""):
|
|
48
|
-
"""Utility method to import the relevant gwpy.io.gwf frame API.
|
|
49
|
-
|
|
50
|
-
This is just a wrapper around :meth:`importlib.import_module` with
|
|
51
|
-
a slightly nicer error message.
|
|
52
|
-
"""
|
|
53
|
-
# import the frame library here to have any ImportErrors occur early
|
|
54
|
-
try:
|
|
55
|
-
return importlib.import_module(f".{prefix}{library}", package=package)
|
|
56
|
-
except ImportError as exc:
|
|
57
|
-
exc.args = (f"Cannot import {library} frame API: {exc}",)
|
|
58
|
-
raise
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
def get_default_gwf_api():
|
|
62
|
-
"""Return the preferred GWF API library.
|
|
63
|
-
|
|
64
|
-
Examples
|
|
65
|
-
--------
|
|
66
|
-
If you have |LDAStools.frameCPP|_ installed:
|
|
67
|
-
|
|
68
|
-
>>> from gwpy.io.gwf import get_default_gwf_api
|
|
69
|
-
>>> get_default_gwf_api()
|
|
70
|
-
'frameCPP'
|
|
71
|
-
|
|
72
|
-
Or, if you have |lalframe|_:
|
|
73
|
-
|
|
74
|
-
>>> get_default_gwf_api()
|
|
75
|
-
'LALFrame'
|
|
76
|
-
|
|
77
|
-
Or, if you have |FrameL|_:
|
|
78
|
-
|
|
79
|
-
>>> get_default_gwf_api()
|
|
80
|
-
'FrameL'
|
|
81
|
-
|
|
82
|
-
Otherwise:
|
|
83
|
-
|
|
84
|
-
>>> get_default_gwf_api()
|
|
85
|
-
ImportError: no GWF API available, please install a supported third-party
|
|
86
|
-
GWF library and try again
|
|
87
|
-
"""
|
|
88
|
-
for lib in APIS:
|
|
89
|
-
try:
|
|
90
|
-
_import_gwf_library(lib.lower())
|
|
91
|
-
except ImportError:
|
|
92
|
-
continue
|
|
93
|
-
else:
|
|
94
|
-
return lib
|
|
95
|
-
raise ImportError(
|
|
96
|
-
"no GWF API available, please install a supported third-party GWF "
|
|
97
|
-
"library and try again",
|
|
98
|
-
)
|
|
99
|
-
|
|
100
|
-
try:
|
|
101
|
-
DEFAULT_GWF_API = get_default_gwf_api()
|
|
102
|
-
except ImportError:
|
|
103
|
-
DEFAULT_GWF_API = None
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
def _gwf_library_function(func):
|
|
107
|
-
name = func.__name__
|
|
108
|
-
|
|
109
|
-
@wraps(func)
|
|
110
|
-
def wrapper(*args, **kwargs):
|
|
111
|
-
api = DEFAULT_GWF_API or get_default_gwf_api()
|
|
112
|
-
lib = _import_gwf_library(api.lower(), prefix="_")
|
|
113
|
-
return getattr(lib, name)(*args, **kwargs)
|
|
114
|
-
|
|
115
|
-
return wrapper
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
# -- i/o ----------------------------------------------------------------------
|
|
119
|
-
|
|
120
|
-
def identify_gwf(origin, filepath, fileobj, *args, **kwargs):
|
|
121
|
-
"""Identify a filename or file object as GWF
|
|
122
|
-
|
|
123
|
-
This function is overloaded in that it will also identify a cache file
|
|
124
|
-
as 'gwf' if the first entry in the cache contains a GWF file extension
|
|
125
|
-
"""
|
|
126
|
-
# pylint: disable=unused-argument
|
|
127
|
-
|
|
128
|
-
# try and read file descriptor
|
|
129
|
-
if fileobj is not None:
|
|
130
|
-
loc = fileobj.tell()
|
|
131
|
-
fileobj.seek(0)
|
|
132
|
-
try:
|
|
133
|
-
if fileobj.read(4) == GWF_SIGNATURE:
|
|
134
|
-
return True
|
|
135
|
-
finally:
|
|
136
|
-
fileobj.seek(loc)
|
|
137
|
-
if filepath is not None:
|
|
138
|
-
if filepath.endswith('.gwf'):
|
|
139
|
-
return True
|
|
140
|
-
if filepath.endswith(('.lcf', '.cache')):
|
|
141
|
-
try:
|
|
142
|
-
cache = read_cache(filepath)
|
|
143
|
-
except IOError:
|
|
144
|
-
return False
|
|
145
|
-
else:
|
|
146
|
-
if cache[0].path.endswith('.gwf'):
|
|
147
|
-
return True
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
def open_gwf(filename, mode='r'):
|
|
151
|
-
"""Open a filename for reading or writing GWF format data
|
|
152
|
-
|
|
153
|
-
Parameters
|
|
154
|
-
----------
|
|
155
|
-
filename : `str`
|
|
156
|
-
the path to read from, or write to
|
|
157
|
-
|
|
158
|
-
mode : `str`, optional
|
|
159
|
-
either ``'r'`` (read) or ``'w'`` (write)
|
|
160
|
-
|
|
161
|
-
Returns
|
|
162
|
-
-------
|
|
163
|
-
`LDAStools.frameCPP.IFrameFStream`
|
|
164
|
-
the input frame stream (if `mode='r'`), or
|
|
165
|
-
`LDAStools.frameCPP.IFrameFStream`
|
|
166
|
-
the output frame stream (if `mode='w'`)
|
|
167
|
-
"""
|
|
168
|
-
if mode not in ('r', 'w'):
|
|
169
|
-
raise ValueError("mode must be either 'r' or 'w'")
|
|
170
|
-
from LDAStools import frameCPP
|
|
171
|
-
filename = file_path(filename)
|
|
172
|
-
if mode == 'r':
|
|
173
|
-
return frameCPP.IFrameFStream(str(filename))
|
|
174
|
-
return frameCPP.OFrameFStream(str(filename))
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
def write_frames(filename, frames, compression='GZIP', compression_level=None):
|
|
178
|
-
"""Write a list of frame objects to a file
|
|
179
|
-
|
|
180
|
-
**Requires:** |LDAStools.frameCPP|_
|
|
181
|
-
|
|
182
|
-
Parameters
|
|
183
|
-
----------
|
|
184
|
-
filename : `str`
|
|
185
|
-
path to write into
|
|
186
|
-
|
|
187
|
-
frames : `list` of `LDAStools.frameCPP.FrameH`
|
|
188
|
-
list of frames to write into file
|
|
189
|
-
|
|
190
|
-
compression : `int`, `str`, optional
|
|
191
|
-
name of compresion algorithm to use, or its endian-appropriate
|
|
192
|
-
ID, choose from
|
|
193
|
-
|
|
194
|
-
- ``'RAW'``
|
|
195
|
-
- ``'GZIP'``
|
|
196
|
-
- ``'DIFF_GZIP'``
|
|
197
|
-
- ``'ZERO_SUPPRESS'``
|
|
198
|
-
- ``'ZERO_SUPPRESS_OTHERWISE_GZIP'``
|
|
199
|
-
|
|
200
|
-
compression_level : `int`, optional
|
|
201
|
-
compression level for given method, default is ``6`` for GZIP-based
|
|
202
|
-
methods, otherwise ``0``
|
|
203
|
-
"""
|
|
204
|
-
from LDAStools import frameCPP
|
|
205
|
-
from ._framecpp import (Compression, DefaultCompressionLevel)
|
|
206
|
-
|
|
207
|
-
# handle compression arguments
|
|
208
|
-
if not isinstance(compression, int):
|
|
209
|
-
compression = Compression[compression]
|
|
210
|
-
if compression_level is None:
|
|
211
|
-
compression_level = DefaultCompressionLevel[compression.name]
|
|
212
|
-
|
|
213
|
-
# open stream
|
|
214
|
-
stream = open_gwf(filename, 'w')
|
|
215
|
-
|
|
216
|
-
# write frames one-by-one
|
|
217
|
-
if isinstance(frames, frameCPP.FrameH):
|
|
218
|
-
frames = [frames]
|
|
219
|
-
for frame in frames:
|
|
220
|
-
stream.WriteFrame(frame, int(compression), int(compression_level))
|
|
221
|
-
# stream auto-closes (apparently)
|
|
222
|
-
|
|
223
|
-
|
|
224
|
-
def create_frame(time=0, duration=None, name='gwpy', run=-1, ifos=None):
|
|
225
|
-
"""Create a new :class:`~LDAStools.frameCPP.FrameH`
|
|
226
|
-
|
|
227
|
-
**Requires:** |LDAStools.frameCPP|_
|
|
228
|
-
|
|
229
|
-
Parameters
|
|
230
|
-
----------
|
|
231
|
-
time : `float`, optional
|
|
232
|
-
frame start time in GPS seconds
|
|
233
|
-
|
|
234
|
-
duration : `float`, optional
|
|
235
|
-
frame length in seconds
|
|
236
|
-
|
|
237
|
-
name : `str`, optional
|
|
238
|
-
name of project or other experiment description
|
|
239
|
-
|
|
240
|
-
run : `int`, optional
|
|
241
|
-
run number (number < 0 reserved for simulated data); monotonic for
|
|
242
|
-
experimental runs
|
|
243
|
-
|
|
244
|
-
ifos : `list`, optional
|
|
245
|
-
list of interferometer prefices (e.g. ``'L1'``) associated with this
|
|
246
|
-
frame
|
|
247
|
-
|
|
248
|
-
Returns
|
|
249
|
-
-------
|
|
250
|
-
frame : :class:`~LDAStools.frameCPP.FrameH`
|
|
251
|
-
the newly created frame header
|
|
252
|
-
"""
|
|
253
|
-
from LDAStools import frameCPP
|
|
254
|
-
from ._framecpp import DetectorLocation
|
|
255
|
-
|
|
256
|
-
# create frame
|
|
257
|
-
frame = frameCPP.FrameH()
|
|
258
|
-
|
|
259
|
-
# add timing
|
|
260
|
-
gps = to_gps(time)
|
|
261
|
-
gps = frameCPP.GPSTime(gps.gpsSeconds, gps.gpsNanoSeconds)
|
|
262
|
-
frame.SetGTime(gps)
|
|
263
|
-
if duration is not None:
|
|
264
|
-
frame.SetDt(float(duration))
|
|
265
|
-
|
|
266
|
-
# add FrDetectors
|
|
267
|
-
for prefix in ifos or []:
|
|
268
|
-
frame.AppendFrDetector(
|
|
269
|
-
frameCPP.GetDetector(DetectorLocation[prefix], gps),
|
|
270
|
-
)
|
|
271
|
-
|
|
272
|
-
# add descriptions
|
|
273
|
-
frame.SetName(name)
|
|
274
|
-
frame.SetRun(run)
|
|
275
|
-
|
|
276
|
-
return frame
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
def create_fradcdata(series, frame_epoch=0,
|
|
280
|
-
channelgroup=0, channelid=0, nbits=16):
|
|
281
|
-
"""Create a `~frameCPP.FrAdcData` from a `~gwpy.types.Series`
|
|
282
|
-
|
|
283
|
-
.. note::
|
|
284
|
-
|
|
285
|
-
Currently this method is restricted to 1-dimensional arrays.
|
|
286
|
-
|
|
287
|
-
Parameters
|
|
288
|
-
----------
|
|
289
|
-
series : `~gwpy.types.Series`
|
|
290
|
-
the input data array to store
|
|
291
|
-
|
|
292
|
-
frame_epoch : `float`, `int`, optional
|
|
293
|
-
the GPS start epoch of the `Frame` that will contain this
|
|
294
|
-
data structure
|
|
295
|
-
|
|
296
|
-
Returns
|
|
297
|
-
-------
|
|
298
|
-
frdata : `~frameCPP.FrAdcData`
|
|
299
|
-
the newly created data structure
|
|
300
|
-
|
|
301
|
-
Notes
|
|
302
|
-
-----
|
|
303
|
-
See Table 10 (§4.3.2.4) of LIGO-T970130 for more details
|
|
304
|
-
"""
|
|
305
|
-
from LDAStools import frameCPP
|
|
306
|
-
|
|
307
|
-
# assert correct type
|
|
308
|
-
if not series.xunit.is_equivalent('s') or series.ndim != 1:
|
|
309
|
-
raise TypeError("only 1-dimensional timeseries data can be "
|
|
310
|
-
"written as FrAdcData")
|
|
311
|
-
|
|
312
|
-
frdata = frameCPP.FrAdcData(
|
|
313
|
-
_series_name(series),
|
|
314
|
-
channelgroup,
|
|
315
|
-
channelid,
|
|
316
|
-
nbits,
|
|
317
|
-
(1 / series.dx.to('s')).value
|
|
318
|
-
)
|
|
319
|
-
frdata.SetTimeOffset(
|
|
320
|
-
float(to_gps(series.x0.value) - to_gps(frame_epoch)),
|
|
321
|
-
)
|
|
322
|
-
return frdata
|
|
323
|
-
|
|
324
|
-
|
|
325
|
-
def _get_series_trange(series):
|
|
326
|
-
if series.xunit.is_equivalent('s'):
|
|
327
|
-
return abs(series.xspan)
|
|
328
|
-
return 0
|
|
329
|
-
|
|
330
|
-
|
|
331
|
-
def _get_series_frange(series):
|
|
332
|
-
if series.xunit.is_equivalent('Hz'): # FrequencySeries
|
|
333
|
-
return abs(series.xspan)
|
|
334
|
-
elif series.ndim == 2 and series.yunit.is_equivalent('Hz'): # Spectrogram
|
|
335
|
-
return abs(series.yspan)
|
|
336
|
-
return 0
|
|
337
|
-
|
|
338
|
-
|
|
339
|
-
def create_frprocdata(series, frame_epoch=0, comment=None,
|
|
340
|
-
type=None, subtype=None, trange=None,
|
|
341
|
-
fshift=0, phase=0, frange=None, bandwidth=0):
|
|
342
|
-
"""Create a `~frameCPP.FrAdcData` from a `~gwpy.types.Series`
|
|
343
|
-
|
|
344
|
-
.. note::
|
|
345
|
-
|
|
346
|
-
Currently this method is restricted to 1-dimensional arrays.
|
|
347
|
-
|
|
348
|
-
Parameters
|
|
349
|
-
----------
|
|
350
|
-
series : `~gwpy.types.Series`
|
|
351
|
-
the input data array to store
|
|
352
|
-
|
|
353
|
-
frame_epoch : `float`, `int`, optional
|
|
354
|
-
the GPS start epoch of the `Frame` that will contain this
|
|
355
|
-
data structure
|
|
356
|
-
|
|
357
|
-
comment : `str`, optional
|
|
358
|
-
comment
|
|
359
|
-
|
|
360
|
-
type : `int`, `str`, optional
|
|
361
|
-
type of data object
|
|
362
|
-
|
|
363
|
-
subtype : `int`, `str`, optional
|
|
364
|
-
subtype for f-Series
|
|
365
|
-
|
|
366
|
-
trange : `float`, optional
|
|
367
|
-
duration of sampled data
|
|
368
|
-
|
|
369
|
-
fshift : `float`, optional
|
|
370
|
-
frequency in the original data that corresponds to 0 Hz in the
|
|
371
|
-
heterodyned series
|
|
372
|
-
|
|
373
|
-
phase : `float`, optional
|
|
374
|
-
phase of the heterodyning signal at start of dataset
|
|
375
|
-
|
|
376
|
-
frange : `float`, optional
|
|
377
|
-
frequency range
|
|
378
|
-
|
|
379
|
-
bandwidth : `float, optional
|
|
380
|
-
reoslution bandwidth
|
|
381
|
-
|
|
382
|
-
Returns
|
|
383
|
-
-------
|
|
384
|
-
frdata : `~frameCPP.FrAdcData`
|
|
385
|
-
the newly created data structure
|
|
386
|
-
|
|
387
|
-
Notes
|
|
388
|
-
-----
|
|
389
|
-
See Table 17 (§4.3.2.11) of LIGO-T970130 for more details
|
|
390
|
-
"""
|
|
391
|
-
from LDAStools import frameCPP
|
|
392
|
-
|
|
393
|
-
# format auxiliary data
|
|
394
|
-
if trange is None:
|
|
395
|
-
trange = _get_series_trange(series)
|
|
396
|
-
if frange is None:
|
|
397
|
-
frange = _get_series_frange(series)
|
|
398
|
-
|
|
399
|
-
return frameCPP.FrProcData(
|
|
400
|
-
_series_name(series),
|
|
401
|
-
str(comment or series.name),
|
|
402
|
-
_get_frprocdata_type(series, type),
|
|
403
|
-
_get_frprocdata_subtype(series, subtype),
|
|
404
|
-
float(to_gps(series.x0.value) - to_gps(frame_epoch)),
|
|
405
|
-
trange,
|
|
406
|
-
fshift,
|
|
407
|
-
phase,
|
|
408
|
-
frange,
|
|
409
|
-
bandwidth,
|
|
410
|
-
)
|
|
411
|
-
|
|
412
|
-
|
|
413
|
-
def create_frsimdata(series, frame_epoch=0, comment=None, fshift=0, phase=0):
|
|
414
|
-
"""Create a `~frameCPP.FrAdcData` from a `~gwpy.types.Series`
|
|
415
|
-
|
|
416
|
-
.. note::
|
|
417
|
-
|
|
418
|
-
Currently this method is restricted to 1-dimensional arrays.
|
|
419
|
-
|
|
420
|
-
Parameters
|
|
421
|
-
----------
|
|
422
|
-
series : `~gwpy.types.Series`
|
|
423
|
-
the input data array to store
|
|
424
|
-
|
|
425
|
-
frame_epoch : `float`, `int`, optional
|
|
426
|
-
the GPS start epoch of the `Frame` that will contain this
|
|
427
|
-
data structure
|
|
428
|
-
|
|
429
|
-
fshift : `float`, optional
|
|
430
|
-
frequency in the original data that corresponds to 0 Hz in the
|
|
431
|
-
heterodyned series
|
|
432
|
-
|
|
433
|
-
phase : `float`, optional
|
|
434
|
-
phase of the heterodyning signal at start of dataset
|
|
435
|
-
|
|
436
|
-
Returns
|
|
437
|
-
-------
|
|
438
|
-
frdata : `~frameCPP.FrSimData`
|
|
439
|
-
the newly created data structure
|
|
440
|
-
|
|
441
|
-
Notes
|
|
442
|
-
-----
|
|
443
|
-
See Table 20 (§4.3.2.14) of LIGO-T970130 for more details
|
|
444
|
-
"""
|
|
445
|
-
from LDAStools import frameCPP
|
|
446
|
-
|
|
447
|
-
# assert correct type
|
|
448
|
-
if not series.xunit.is_equivalent('s'):
|
|
449
|
-
raise TypeError("only timeseries data can be written as FrSimData")
|
|
450
|
-
|
|
451
|
-
return frameCPP.FrSimData(
|
|
452
|
-
_series_name(series),
|
|
453
|
-
str(comment or series.name),
|
|
454
|
-
(1 / series.dx.to('s')).value,
|
|
455
|
-
float(to_gps(series.x0.value) - to_gps(frame_epoch)),
|
|
456
|
-
fshift,
|
|
457
|
-
phase,
|
|
458
|
-
)
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
def create_frvect(series):
|
|
462
|
-
"""Create a `~frameCPP.FrVect` from a `~gwpy.types.Series`
|
|
463
|
-
|
|
464
|
-
.. note::
|
|
465
|
-
|
|
466
|
-
Currently this method is restricted to 1-dimensional arrays.
|
|
467
|
-
|
|
468
|
-
Parameters
|
|
469
|
-
----------
|
|
470
|
-
series : `~gwpy.types.Series`
|
|
471
|
-
the input data array to store
|
|
472
|
-
|
|
473
|
-
Returns
|
|
474
|
-
-------
|
|
475
|
-
frvect : `~frameCPP.FrVect`
|
|
476
|
-
the newly created data vector
|
|
477
|
-
"""
|
|
478
|
-
from LDAStools import frameCPP
|
|
479
|
-
from ._framecpp import FrVectType
|
|
480
|
-
|
|
481
|
-
# create dimensions
|
|
482
|
-
dims = frameCPP.Dimension(
|
|
483
|
-
series.shape[0], # num elements
|
|
484
|
-
series.dx.value, # step size
|
|
485
|
-
str(series.dx.unit), # unit
|
|
486
|
-
0, # starting value
|
|
487
|
-
)
|
|
488
|
-
|
|
489
|
-
# create FrVect
|
|
490
|
-
vect = frameCPP.FrVect(
|
|
491
|
-
_series_name(series), # name
|
|
492
|
-
int(FrVectType.find(series.dtype)), # data type enum
|
|
493
|
-
series.ndim, # num dimensions
|
|
494
|
-
dims, # dimension object
|
|
495
|
-
str(series.unit), # unit
|
|
496
|
-
)
|
|
497
|
-
|
|
498
|
-
# populate FrVect
|
|
499
|
-
vect.GetDataArray()[:] = numpy.require(series.value, requirements=['C'])
|
|
500
|
-
|
|
501
|
-
return vect
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
# -- utilities ----------------------------------------------------------------
|
|
505
|
-
|
|
506
|
-
def num_channels(framefile):
|
|
507
|
-
"""Find the total number of channels in this framefile
|
|
508
|
-
|
|
509
|
-
**Requires:** |LDAStools.frameCPP|_
|
|
510
|
-
|
|
511
|
-
Parameters
|
|
512
|
-
----------
|
|
513
|
-
framefile : `str`
|
|
514
|
-
path to GWF-format file on disk
|
|
515
|
-
|
|
516
|
-
Returns
|
|
517
|
-
-------
|
|
518
|
-
n : `int`
|
|
519
|
-
the total number of channels found in the table of contents for this
|
|
520
|
-
file
|
|
521
|
-
"""
|
|
522
|
-
return len(get_channel_names(framefile))
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
def get_channel_type(channel, framefile):
|
|
526
|
-
"""Find the channel type in a given GWF file
|
|
527
|
-
|
|
528
|
-
**Requires:** |LDAStools.frameCPP|_
|
|
529
|
-
|
|
530
|
-
Parameters
|
|
531
|
-
----------
|
|
532
|
-
channel : `str`, `~gwpy.detector.Channel`
|
|
533
|
-
name of data channel to find
|
|
534
|
-
|
|
535
|
-
framefile : `str`
|
|
536
|
-
path of GWF file in which to search
|
|
537
|
-
|
|
538
|
-
Returns
|
|
539
|
-
-------
|
|
540
|
-
ctype : `str`
|
|
541
|
-
the type of the channel ('adc', 'sim', or 'proc')
|
|
542
|
-
|
|
543
|
-
Raises
|
|
544
|
-
------
|
|
545
|
-
ValueError
|
|
546
|
-
if the channel is not found in the table-of-contents
|
|
547
|
-
"""
|
|
548
|
-
channel = str(channel)
|
|
549
|
-
for name, type_ in _iter_channels(framefile):
|
|
550
|
-
if channel == name:
|
|
551
|
-
return type_
|
|
552
|
-
raise ValueError(
|
|
553
|
-
f"'{channel}' not found in table-of-contents for {framefile}",
|
|
554
|
-
)
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
def channel_in_frame(channel, framefile):
|
|
558
|
-
"""Determine whether a channel is stored in this framefile
|
|
559
|
-
|
|
560
|
-
**Requires:** |LDAStools.frameCPP|_
|
|
561
|
-
|
|
562
|
-
Parameters
|
|
563
|
-
----------
|
|
564
|
-
channel : `str`
|
|
565
|
-
name of channel to find
|
|
566
|
-
|
|
567
|
-
framefile : `str`
|
|
568
|
-
path of GWF file to test
|
|
569
|
-
|
|
570
|
-
Returns
|
|
571
|
-
-------
|
|
572
|
-
inframe : `bool`
|
|
573
|
-
whether this channel is included in the table of contents for
|
|
574
|
-
the given framefile
|
|
575
|
-
"""
|
|
576
|
-
return str(channel) in iter_channel_names(framefile)
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
def iter_channel_names(framefile):
|
|
580
|
-
"""Iterate over the names of channels found in a GWF file.
|
|
581
|
-
|
|
582
|
-
Parameters
|
|
583
|
-
----------
|
|
584
|
-
framefile : `str`
|
|
585
|
-
path of GWF file to read
|
|
586
|
-
|
|
587
|
-
Returns
|
|
588
|
-
-------
|
|
589
|
-
channels : `generator`
|
|
590
|
-
an iterator that will loop over the names of channels as read from
|
|
591
|
-
the table of contents of the given GWF file
|
|
592
|
-
"""
|
|
593
|
-
for name, _ in _iter_channels(framefile):
|
|
594
|
-
yield name
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
def get_channel_names(framefile):
|
|
598
|
-
"""Return a list of all channel names found in a GWF file
|
|
599
|
-
|
|
600
|
-
This method just returns
|
|
601
|
-
|
|
602
|
-
>>> list(iter_channel_names(framefile))
|
|
603
|
-
|
|
604
|
-
Parameters
|
|
605
|
-
----------
|
|
606
|
-
framefile : `str`
|
|
607
|
-
path of GWF file to read
|
|
608
|
-
|
|
609
|
-
Returns
|
|
610
|
-
-------
|
|
611
|
-
channels : `list` of `str`
|
|
612
|
-
a `list` of channel names as read from the table of contents of
|
|
613
|
-
the given GWF file
|
|
614
|
-
"""
|
|
615
|
-
return list(iter_channel_names(framefile))
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
@_gwf_library_function
|
|
619
|
-
def iter_channels(framefile):
|
|
620
|
-
"""Yields the name and type of each channel in a GWF file.
|
|
621
|
-
|
|
622
|
-
Parameters
|
|
623
|
-
----------
|
|
624
|
-
framefile : `str`
|
|
625
|
-
path of GWF file, or open file stream, to read
|
|
626
|
-
"""
|
|
627
|
-
pass # decorator does the work
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
def data_segments(paths, channel, warn=True):
|
|
631
|
-
"""Returns the segments containing data for a channel
|
|
632
|
-
|
|
633
|
-
A frame is considered to contain data if a valid FrData structure
|
|
634
|
-
(of any type) exists for the channel in that frame. No checks
|
|
635
|
-
are directly made against the underlying FrVect structures.
|
|
636
|
-
|
|
637
|
-
Parameters
|
|
638
|
-
----------
|
|
639
|
-
paths : `list` of `str`
|
|
640
|
-
a list of GWF file paths
|
|
641
|
-
|
|
642
|
-
channel : `str`
|
|
643
|
-
the name to check in each frame
|
|
644
|
-
|
|
645
|
-
warn : `bool`, optional
|
|
646
|
-
emit a `UserWarning` when a channel is not found in a frame
|
|
647
|
-
|
|
648
|
-
Returns
|
|
649
|
-
-------
|
|
650
|
-
segments : `~gwpy.segments.SegmentList`
|
|
651
|
-
the list of segments containing data
|
|
652
|
-
"""
|
|
653
|
-
segments = SegmentList()
|
|
654
|
-
for path in paths:
|
|
655
|
-
segments.extend(_gwf_channel_segments(path, channel, warn=warn))
|
|
656
|
-
return segments.coalesce()
|
|
657
|
-
|
|
658
|
-
|
|
659
|
-
def _gwf_channel_segments(path, channel, warn=True):
|
|
660
|
-
"""Yields the segments containing data for ``channel`` in this GWF path
|
|
661
|
-
"""
|
|
662
|
-
stream = open_gwf(path)
|
|
663
|
-
# get segments for frames
|
|
664
|
-
toc = stream.GetTOC()
|
|
665
|
-
secs = toc.GetGTimeS()
|
|
666
|
-
nano = toc.GetGTimeN()
|
|
667
|
-
dur = toc.GetDt()
|
|
668
|
-
|
|
669
|
-
readers = [getattr(stream, f"ReadFr{type_.title()}Data") for
|
|
670
|
-
type_ in ("proc", "sim", "adc")]
|
|
671
|
-
|
|
672
|
-
# for each segment, try and read the data for this channel
|
|
673
|
-
for i, (s, ns, dt) in enumerate(zip(secs, nano, dur)):
|
|
674
|
-
for read in readers:
|
|
675
|
-
try:
|
|
676
|
-
read(i, channel)
|
|
677
|
-
except (IndexError, ValueError):
|
|
678
|
-
continue
|
|
679
|
-
readers = [read] # use this one from now on
|
|
680
|
-
epoch = LIGOTimeGPS(s, ns)
|
|
681
|
-
yield Segment(epoch, epoch + dt)
|
|
682
|
-
break
|
|
683
|
-
else: # none of the readers worked for this channel, warn
|
|
684
|
-
if warn:
|
|
685
|
-
warnings.warn(
|
|
686
|
-
f"'{channel}' not found in frame {i} of {path}",
|
|
687
|
-
)
|
|
688
|
-
|
|
689
|
-
|
|
690
|
-
def _get_type(type_, enum):
|
|
691
|
-
"""Handle a type string, or just return an `int`
|
|
692
|
-
|
|
693
|
-
Only to be called in relation to FrProcDataType and FrProcDataSubType
|
|
694
|
-
"""
|
|
695
|
-
if isinstance(type_, int):
|
|
696
|
-
return type_
|
|
697
|
-
return enum[str(type_).upper()]
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
def _get_frprocdata_type(series, type_):
|
|
701
|
-
"""Determine the appropriate `FrProcDataType` for this series
|
|
702
|
-
|
|
703
|
-
Notes
|
|
704
|
-
-----
|
|
705
|
-
See Table 17 (§4.3.2.11) of LIGO-T970130 for more details
|
|
706
|
-
"""
|
|
707
|
-
from ._framecpp import FrProcDataType
|
|
708
|
-
|
|
709
|
-
if type_ is not None: # format user value
|
|
710
|
-
return _get_type(type_, FrProcDataType)
|
|
711
|
-
|
|
712
|
-
if series.ndim == 1 and series.xunit.is_equivalent("s"):
|
|
713
|
-
type_ = FrProcDataType.TIME_SERIES
|
|
714
|
-
elif series.ndim == 1 and series.xunit.is_equivalent("Hz"):
|
|
715
|
-
type_ = FrProcDataType.FREQUENCY_SERIES
|
|
716
|
-
elif series.ndim == 1:
|
|
717
|
-
type_ = FrProcDataType.OTHER_1D_SERIES_DATA
|
|
718
|
-
elif (
|
|
719
|
-
series.ndim == 2
|
|
720
|
-
and series.xunit.is_equivalent("s")
|
|
721
|
-
and series.yunit.is_equivalent("Hz")
|
|
722
|
-
):
|
|
723
|
-
type_ = FrProcDataType.TIME_FREQUENCY
|
|
724
|
-
elif series.ndim > 2:
|
|
725
|
-
type_ = FrProcDataType.MULTI_DIMENSIONAL
|
|
726
|
-
else:
|
|
727
|
-
type_ = FrProcDataType.UNKNOWN
|
|
728
|
-
|
|
729
|
-
return type_
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
def _get_frprocdata_subtype(series, subtype):
|
|
733
|
-
"""Determine the appropriate `FrProcDataSubType` for this series
|
|
734
|
-
|
|
735
|
-
Notes
|
|
736
|
-
-----
|
|
737
|
-
See Table 17 (§4.3.2.11) of LIGO-T970130 for more details
|
|
738
|
-
"""
|
|
739
|
-
from ._framecpp import FrProcDataSubType
|
|
740
|
-
|
|
741
|
-
if subtype is not None: # format user value
|
|
742
|
-
return _get_type(subtype, FrProcDataSubType)
|
|
743
|
-
|
|
744
|
-
if series.unit == 'coherence':
|
|
745
|
-
return FrProcDataSubType.COHERENCE
|
|
746
|
-
return FrProcDataSubType.UNKNOWN
|
|
747
|
-
|
|
748
|
-
|
|
749
|
-
def _series_name(series):
|
|
750
|
-
"""Returns the 'name' of a `Series` that should be written to GWF
|
|
751
|
-
|
|
752
|
-
This is basically `series.name or str(series.channel) or ""`
|
|
753
|
-
|
|
754
|
-
Parameters
|
|
755
|
-
----------
|
|
756
|
-
series : `gwpy.types.Series`
|
|
757
|
-
the input series that will be written
|
|
758
|
-
|
|
759
|
-
Returns
|
|
760
|
-
-------
|
|
761
|
-
name : `str`
|
|
762
|
-
the name to use when storing this series
|
|
763
|
-
"""
|
|
764
|
-
return (
|
|
765
|
-
series.name
|
|
766
|
-
or str(series.channel or "")
|
|
767
|
-
or None
|
|
768
|
-
)
|