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/io/gwf/_lalframe.py DELETED
@@ -1,86 +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
- """GWF I/O utilities for LALFrame.
20
-
21
- This module provides the LALFrame implementation of the functions
22
- that make up the `gwpy.io.gwf` module API.
23
- """
24
-
25
- from enum import IntEnum
26
-
27
- import lalframe
28
-
29
- from ...utils.enum import NumpyTypeEnum
30
-
31
-
32
- # -- type mapping -------------------------------------------------------------
33
-
34
- class FrVectType(IntEnum, NumpyTypeEnum):
35
- INT8 = lalframe.FRAMEU_FR_VECT_C
36
- INT16 = lalframe.FRAMEU_FR_VECT_2S
37
- INT32 = lalframe.FRAMEU_FR_VECT_4S
38
- INT64 = lalframe.FRAMEU_FR_VECT_8S
39
- FLOAT32 = lalframe.FRAMEU_FR_VECT_4R
40
- FLOAT64 = lalframe.FRAMEU_FR_VECT_8R
41
- COMPLEX64 = lalframe.FRAMEU_FR_VECT_8C
42
- COMPLEX128 = lalframe.FRAMEU_FR_VECT_16C
43
- BYTES = lalframe.FRAMEU_FR_VECT_STRING
44
- UINT8 = lalframe.FRAMEU_FR_VECT_1U
45
- UINT16 = lalframe.FRAMEU_FR_VECT_2U
46
- UINT32 = lalframe.FRAMEU_FR_VECT_4U
47
- UINT64 = lalframe.FRAMEU_FR_VECT_8U
48
-
49
-
50
- def _lalframe_proctype(type_):
51
- return getattr(lalframe, f"FRAMEU_FR_PROC_TYPE_{type_.upper()}")
52
-
53
-
54
- class FrProcDataType(IntEnum):
55
- UNKNOWN = _lalframe_proctype("UNKNOWN")
56
- TIME_SERIES = _lalframe_proctype("TIME_SERIES")
57
- FREQUENCY_SERIES = _lalframe_proctype("FREQUENCY_SERIES")
58
- OTHER_1D_SERIES_DATA = _lalframe_proctype("OTHER_1D_SERIES_DATA")
59
- TIME_FREQUENCY = _lalframe_proctype("TIME_FREQUENCY")
60
- WAVELETS = _lalframe_proctype("WAVELETS")
61
- MULTI_DIMENSIONAL = _lalframe_proctype("MULTI_DIMENSIONAL")
62
-
63
-
64
- def _lalframe_proc_subtype(type_):
65
- return getattr(lalframe, f"FRAMEU_FR_PROC_SUB_TYPE_{type_.upper()}")
66
-
67
-
68
- class FrProcDataSubType(IntEnum):
69
- UNKNOWN = _lalframe_proc_subtype("UNKNOWN")
70
- DFT = _lalframe_proc_subtype("DFT")
71
- AMPLITUDE_SPECTRAL_DENSITY = _lalframe_proc_subtype("AMPLITUDE_SPECTRAL_DENSITY")
72
- POWER_SPECTRAL_DENSITY = _lalframe_proc_subtype("POWER_SPECTRAL_DENSITY")
73
- CROSS_SPECTRAL_DENSITY = _lalframe_proc_subtype("CROSS_SPECTRAL_DENSITY")
74
- COHERENCE = _lalframe_proc_subtype("COHERENCE")
75
- TRANSFER_FUNCTION = _lalframe_proc_subtype("TRANSFER_FUNCTION")
76
-
77
-
78
- def _iter_channels(framefile):
79
- if not isinstance(framefile, lalframe.FrameUFrFile):
80
- framefile = lalframe.FrameUFrFileOpen(framefile, "r")
81
- toc = lalframe.FrameUFrTOCRead(framefile)
82
- for type_ in ('sim', 'proc', 'adc'):
83
- nchan = getattr(lalframe, f"FrameUFrTOCQuery{type_.title()}N")(toc)
84
- get_name = getattr(lalframe, f"FrameUFrTOCQuery{type_.title()}Name")
85
- for i in range(nchan):
86
- yield get_name(toc, i), type_
@@ -1,582 +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
- """Read data from gravitational-wave frame (GWF) files using
20
- |LDAStools.frameCPP|__.
21
- """
22
-
23
- import re
24
- from math import ceil
25
-
26
- import lalframe
27
-
28
- import numpy
29
-
30
- from ....io.utils import file_list
31
- from ....segments import Segment
32
- from ....time import (LIGOTimeGPS, to_gps)
33
- from ... import TimeSeries
34
- from ...core import _dynamic_scaled
35
-
36
- from . import channel_dict_kwarg
37
-
38
- __author__ = 'Duncan Macleod <duncan.macleod@ligo.org>'
39
-
40
- FRAME_LIBRARY = 'LDAStools.frameCPP'
41
-
42
- # error regexs
43
- FRERR_NO_FRAME_AT_NUM = re.compile(
44
- r'\ARequest for frame (?P<frnum>\d+) exceeds the range of '
45
- r'0 through (?P<nframes>\d+)\Z',
46
- )
47
- FRERR_NO_CHANNEL_OF_TYPE = re.compile(
48
- r'\ANo Fr(Adc|Proc|Sim)Data structures with the name ',
49
- )
50
-
51
-
52
- class _Skip(ValueError):
53
- """Error denoting that the contents of a given structure aren't required
54
- """
55
- pass
56
-
57
-
58
- # -- read ---------------------------------------------------------------------
59
-
60
- def read(source, channels, start=None, end=None, scaled=None, type=None,
61
- series_class=TimeSeries):
62
- # pylint: disable=redefined-builtin
63
- """Read a dict of series from one or more GWF files
64
-
65
- Parameters
66
- ----------
67
- source : `str`, `list`
68
- Source of data, any of the following:
69
-
70
- - `str` path of single data file,
71
- - `str` path of cache file,
72
- - `list` of paths.
73
-
74
- channels : `~gwpy.detector.ChannelList`, `list`
75
- a list of channels to read from the source.
76
-
77
- start : `~gwpy.time.LIGOTimeGPS`, `float`, `str` optional
78
- GPS start time of required data, anything parseable by
79
- :func:`~gwpy.time.to_gps` is fine.
80
-
81
- end : `~gwpy.time.LIGOTimeGPS`, `float`, `str`, optional
82
- GPS end time of required data, anything parseable by
83
- :func:`~gwpy.time.to_gps` is fine.
84
-
85
- scaled : `bool`, optional
86
- apply slope and bias calibration to ADC data.
87
-
88
- type : `dict`, optional
89
- a `dict` of ``(name, channel-type)`` pairs, where ``channel-type``
90
- can be one of ``'adc'``, ``'proc'``, or ``'sim'``.
91
-
92
- series_class : `type`, optional
93
- the `Series` sub-type to return.
94
-
95
- Returns
96
- -------
97
- data : `~gwpy.timeseries.TimeSeriesDict` or similar
98
- a dict of ``(channel, series)`` pairs read from the GWF source(s).
99
- """
100
- # parse input source
101
- source = file_list(source)
102
-
103
- # parse type
104
- ctype = channel_dict_kwarg(type, channels, (str,))
105
-
106
- # read each individually and append
107
- out = series_class.DictClass()
108
- for i, file_ in enumerate(source):
109
- if i == 1: # force data into fresh memory so that append works
110
- for name in out:
111
- out[name] = numpy.require(out[name], requirements=['O'])
112
- # read frame
113
- out.append(read_gwf(file_, channels, start=start, end=end, ctype=ctype,
114
- scaled=scaled, series_class=series_class),
115
- copy=False)
116
- return out
117
-
118
-
119
- def read_gwf(filename, channels, start=None, end=None, scaled=None,
120
- ctype=None, series_class=TimeSeries):
121
- """Read a dict of series data from a single GWF file
122
-
123
- Parameters
124
- ----------
125
- filename : `str`
126
- the GWF path from which to read
127
-
128
- channels : `~gwpy.detector.ChannelList`, `list`
129
- a list of channels to read from the source.
130
-
131
- start : `~gwpy.time.LIGOTimeGPS`, `float`, `str` optional
132
- GPS start time of required data, anything parseable by
133
- :func:`~gwpy.time.to_gps` is fine.
134
-
135
- end : `~gwpy.time.LIGOTimeGPS`, `float`, `str`, optional
136
- GPS end time of required data, anything parseable by
137
- :func:`~gwpy.time.to_gps` is fine.
138
-
139
- scaled : `bool`, optional
140
- apply slope and bias calibration to ADC data.
141
-
142
- type : `dict`, optional
143
- a `dict` of ``(name, channel-type)`` pairs, where ``channel-type``
144
- can be one of ``'adc'``, ``'proc'``, or ``'sim'``.
145
-
146
- series_class : `type`, optional
147
- the `Series` sub-type to return.
148
-
149
- Returns
150
- -------
151
- data : `~gwpy.timeseries.TimeSeriesDict` or similar
152
- a dict of ``(channel, series)`` pairs read from the GWF file.
153
- """
154
- # parse kwargs
155
- if not start:
156
- start = 0
157
- if not end:
158
- end = 0
159
- span = Segment(start, end)
160
-
161
- # open file
162
- file = lalframe.FrameUFrFileOpen(filename, "r")
163
- toc = lalframe.FrameUFrTOCRead(file)
164
- nframes = lalframe.FrameUFrTOCQueryNFrame(toc)
165
-
166
- # find channels
167
- out = series_class.DictClass()
168
-
169
- # loop over frames in GWF
170
- i = 0
171
- while True:
172
- this = i
173
- i += 1
174
-
175
- # read frame
176
- try:
177
- frame = stream.ReadFrameNSubset(this, 0)
178
- except IndexError:
179
- if this >= nframes:
180
- break
181
- raise
182
-
183
- # check whether we need this frame at all
184
- if not _need_frame(frame, start, end):
185
- continue
186
-
187
- # get epoch for this frame
188
- epoch = LIGOTimeGPS(*frame.GetGTime())
189
-
190
- # and read all the channels
191
- for channel in channels:
192
- _scaled = _dynamic_scaled(scaled, channel)
193
- try:
194
- new = _read_channel(stream, this, str(channel),
195
- ctype.get(channel, None),
196
- epoch, start, end, scaled=_scaled,
197
- series_class=series_class)
198
- except _Skip: # don't need this frame for this channel
199
- continue
200
- try:
201
- out[channel].append(new)
202
- except KeyError:
203
- out[channel] = numpy.require(new, requirements=['O'])
204
-
205
- # if we have all of the data we want, stop now
206
- if all(span in out[channel].span for channel in out):
207
- break
208
-
209
- # if any channels weren't read, something went wrong
210
- for channel in channels:
211
- if channel not in out:
212
- msg = "Failed to read {0!r} from {1!r}".format(
213
- str(channel), filename)
214
- if start or end:
215
- msg += ' for {0}'.format(span)
216
- raise ValueError(msg)
217
-
218
- return out
219
-
220
-
221
- def _read_channel(stream, num, name, ctype, epoch, start, end,
222
- scaled=True, series_class=TimeSeries):
223
- """Read a channel from a specific frame in a stream
224
- """
225
- data = _get_frdata(stream, num, name, ctype=ctype)
226
- return read_frdata(data, epoch, start, end,
227
- scaled=scaled, series_class=series_class)
228
-
229
-
230
- def _get_frdata(stream, num, name, ctype=None):
231
- """Brute force-ish method to return the FrData structure for a channel
232
-
233
- This saves on pulling the channel type from the TOC
234
- """
235
- ctypes = (ctype,) if ctype else ('adc', 'proc', 'sim')
236
- for ctype in ctypes:
237
- _reader = getattr(stream, 'ReadFr{0}Data'.format(ctype.title()))
238
- try:
239
- return _reader(num, name)
240
- except IndexError as exc:
241
- if FRERR_NO_CHANNEL_OF_TYPE.match(str(exc)):
242
- continue
243
- raise
244
- raise ValueError("no Fr{{Adc,Proc,Sim}}Data structures with the "
245
- "name {0}".format(name))
246
-
247
-
248
- def _need_frame(frame, start, end):
249
- frstart = LIGOTimeGPS(*frame.GetGTime())
250
- if end and frstart >= end:
251
- return False
252
-
253
- frend = frstart + frame.GetDt()
254
- if start and frend <= start:
255
- return False
256
-
257
- return True
258
-
259
-
260
- def read_frdata(frdata, epoch, start, end, scaled=True,
261
- series_class=TimeSeries):
262
- """Read a series from an `FrData` structure
263
-
264
- Parameters
265
- ----------
266
- frdata : `LDAStools.frameCPP.FrAdcData` or similar
267
- the data structure to read
268
-
269
- epoch : `float`
270
- the GPS start time of the containing frame
271
- (`LDAStools.frameCPP.FrameH.GTime`)
272
-
273
- start : `float`
274
- the GPS start time of the user request
275
-
276
- end : `float`
277
- the GPS end time of the user request
278
-
279
- scaled : `bool`, optional
280
- apply slope and bias calibration to ADC data.
281
-
282
- series_class : `type`, optional
283
- the `Series` sub-type to return.
284
-
285
- Returns
286
- -------
287
- series : `~gwpy.timeseries.TimeSeriesBase`
288
- the formatted data series
289
-
290
- Raises
291
- ------
292
- _Skip
293
- if this data structure doesn't overlap with the requested
294
- ``[start, end)`` interval.
295
- """
296
- datastart = epoch + frdata.GetTimeOffset()
297
-
298
- # check overlap with user-requested span
299
- if end and datastart >= end:
300
- raise _Skip()
301
-
302
- # get scaling
303
- try:
304
- slope = frdata.GetSlope()
305
- bias = frdata.GetBias()
306
- except AttributeError: # not FrAdcData
307
- slope = None
308
- bias = None
309
- else:
310
- # workaround https://git.ligo.org/ldastools/LDAS_Tools/-/issues/114
311
- # by forcing the default slope to 1.
312
- if bias == slope == 0.:
313
- slope = 1.
314
- null_scaling = slope == 1. and bias == 0.
315
-
316
- out = None
317
- for j in range(frdata.data.size()):
318
- # we use range(frdata.data.size()) to avoid segfault
319
- # related to iterating directly over frdata.data
320
- try:
321
- new = read_frvect(frdata.data[j], datastart, start, end,
322
- name=frdata.GetName(),
323
- series_class=series_class)
324
- except _Skip:
325
- continue
326
-
327
- # apply scaling for ADC channels
328
- if scaled and slope is not None:
329
- rtype = numpy.result_type(new, slope, bias)
330
- typechange = not numpy.can_cast(
331
- rtype,
332
- new.dtype,
333
- casting='same_kind',
334
- )
335
- # only apply scaling if interesting _or_ if it would lead to a
336
- # type change, otherwise we are unnecessarily duplicating memory
337
- if typechange:
338
- new = new * slope + bias
339
- elif not null_scaling:
340
- new *= slope
341
- new += bias
342
- elif slope is not None:
343
- # user has deliberately disabled the ADC calibration, so
344
- # the stored engineering unit is not valid, revert to 'counts':
345
- new.override_unit('count')
346
-
347
- if out is None:
348
- out = new
349
- else:
350
- out.append(new)
351
- return out
352
-
353
-
354
- def read_frvect(vect, epoch, start, end, name=None, series_class=TimeSeries):
355
- """Read an array from an `FrVect` structure
356
-
357
- Parameters
358
- ----------
359
- vect : `LDASTools.frameCPP.FrVect`
360
- the frame vector structur to read
361
-
362
- start : `float`
363
- the GPS start time of the request
364
-
365
- end : `float`
366
- the GPS end time of the request
367
-
368
- epoch : `float`
369
- the GPS start time of the containing `FrData` structure
370
-
371
- name : `str`, optional
372
- the name of the output `series_class`; this is also used
373
- to ignore ``FrVect`` structures containing other information
374
-
375
- series_class : `type`, optional
376
- the `Series` sub-type to return.
377
-
378
- Returns
379
- -------
380
- series : `~gwpy.timeseries.TimeSeriesBase`
381
- the formatted data series
382
-
383
- Raises
384
- ------
385
- _Skip
386
- if this vect doesn't overlap with the requested
387
- ``[start, end)`` interval, or the name doesn't match.
388
- """
389
- # only read FrVect with matching name (or no name set)
390
- # frame spec allows for arbitrary other FrVects
391
- # to hold other information
392
- if vect.GetName() and name and vect.GetName() != name:
393
- raise _Skip()
394
-
395
- # get array
396
- arr = vect.GetDataArray()
397
- nsamp = arr.size
398
-
399
- # and dimensions
400
- dim = vect.GetDim(0)
401
- dx = dim.dx
402
- x0 = dim.startX
403
-
404
- # start and end GPS times of this FrVect
405
- dimstart = epoch + x0
406
- dimend = dimstart + nsamp * dx
407
-
408
- # index of first required sample
409
- nxstart = int(max(0., float(start-dimstart)) / dx)
410
-
411
- # requested start time is after this frame, skip
412
- if nxstart >= nsamp:
413
- raise _Skip()
414
-
415
- # index of end sample
416
- if end:
417
- nxend = int(nsamp - ceil(max(0., float(dimend-end)) / dx))
418
- else:
419
- nxend = None
420
-
421
- if nxstart or nxend:
422
- arr = arr[nxstart:nxend]
423
-
424
- # -- cast as a series
425
-
426
- # get unit
427
- unit = vect.GetUnitY() or None
428
-
429
- # create array
430
- series = series_class(arr, t0=dimstart+nxstart*dx, dt=dx, name=name,
431
- channel=name, unit=unit, copy=False)
432
-
433
- # add information to channel
434
- series.channel.sample_rate = series.sample_rate.value
435
- series.channel.unit = unit
436
- series.channel.dtype = series.dtype
437
-
438
- return series
439
-
440
-
441
- # -- write --------------------------------------------------------------------
442
-
443
- def write(tsdict, outfile,
444
- start=None, end=None,
445
- type=None,
446
- name='gwpy', run=0,
447
- compression='GZIP', compression_level=None):
448
- """Write data to a GWF file using the frameCPP API
449
-
450
- Parameters
451
- ----------
452
- tsdict : `TimeSeriesDict`
453
- dict of data to write
454
-
455
- outfile : `str`
456
- the file name of the target output file
457
-
458
- start : `float`, optional
459
- the GPS start time of the file
460
-
461
- end : `float`, optional
462
- the GPS end time of the file
463
-
464
- type : `str`, optional
465
- the type of the channel, one of 'adc', 'proc', 'sim', default
466
- is 'proc' unless stored in the channel structure
467
-
468
- name : `str`, optional
469
- the name of each frame
470
-
471
- run : `int`, optional
472
- the FrameH run number
473
-
474
- compression : `int`, `str`, optional
475
- name of compresion algorithm to use, or its endian-appropriate
476
- ID, choose from
477
-
478
- - ``'RAW'``
479
- - ``'GZIP'``
480
- - ``'DIFF_GZIP'``
481
- - ``'ZERO_SUPPRESS_WORD_2'``
482
- - ``'ZERO_SUPPRESS_WORD_4'``
483
- - ``'ZERO_SUPPRESS_WORD_8'``
484
- - ``'ZERO_SUPPRESS_OTHERWISE_GZIP'``
485
-
486
- compression_level : `int`, optional
487
- compression level for given method, default is ``6`` for GZIP-based
488
- methods, otherwise ``0``
489
- """
490
- # set frame header metadata
491
- if not start or not end:
492
- starts, ends = zip(*(ts.span for ts in tsdict.values()))
493
- start = to_gps(start or min(starts))
494
- end = to_gps(end or max(ends))
495
- duration = end - start
496
- ifos = {
497
- ts.channel.ifo for ts in tsdict.values() if (
498
- ts.channel
499
- and ts.channel.ifo
500
- and ts.channel.ifo in io_framecpp.DetectorLocation.__members__
501
- )
502
- }
503
-
504
- # create frame
505
- frame = io_gwf.create_frame(
506
- time=start,
507
- duration=duration,
508
- name=name,
509
- run=run,
510
- ifos=ifos,
511
- )
512
-
513
- # append channels
514
- for i, key in enumerate(tsdict):
515
- ctype = (
516
- type
517
- or getattr(tsdict[key].channel, "_ctype", "proc").lower()
518
- or "proc"
519
- )
520
- if ctype == 'adc':
521
- kw = {"channelid": i}
522
- else:
523
- kw = {}
524
- _append_to_frame(frame, tsdict[key].crop(start, end), type=ctype, **kw)
525
-
526
- # write frame to file
527
- io_gwf.write_frames(
528
- outfile,
529
- [frame],
530
- compression=compression,
531
- compression_level=compression_level,
532
- )
533
-
534
-
535
- def _append_to_frame(frame, timeseries, type='proc', **kwargs):
536
- # pylint: disable=redefined-builtin
537
- """Append data from a `TimeSeries` to a `~frameCPP.FrameH`
538
-
539
- Parameters
540
- ----------
541
- frame : `~frameCPP.FrameH`
542
- frame object to append to
543
-
544
- timeseries : `TimeSeries`
545
- the timeseries to append
546
-
547
- type : `str`
548
- the type of the channel, one of 'adc', 'proc', 'sim'
549
-
550
- **kwargs
551
- other keyword arguments are passed to the relevant
552
- `create_xxx` function
553
-
554
- See also
555
- --------
556
- gwpy.io.gwf.create_fradcdata
557
- gwpy.io.gwf.create_frprocdata
558
- gwpy.io.gwf_create_frsimdata
559
- for details of the data structure creation, and associated available
560
- arguments
561
- """
562
- epoch = LIGOTimeGPS(*frame.GetGTime())
563
-
564
- # create the data container
565
- if type.lower() == 'adc':
566
- create = io_gwf.create_fradcdata
567
- append = frame.AppendFrAdcData
568
- elif type.lower() == 'proc':
569
- create = io_gwf.create_frprocdata
570
- append = frame.AppendFrProcData
571
- elif type.lower() == 'sim':
572
- create = io_gwf.create_frsimdata
573
- append = frame.AppendFrSimData
574
- else:
575
- raise RuntimeError("Invalid channel type {!r}, please select one of "
576
- "'adc, 'proc', or 'sim'".format(type))
577
- frdata = create(timeseries, frame_epoch=epoch, **kwargs)
578
-
579
- # append an FrVect
580
- frdata.AppendData(io_gwf.create_frvect(timeseries))
581
- append(frdata)
582
- return frdata
File without changes
File without changes