gwpy 3.0.7__py3-none-any.whl → 3.0.9__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.

Files changed (50) hide show
  1. gwpy/_version.py +2 -2
  2. gwpy/astro/range.py +3 -3
  3. gwpy/astro/tests/test_range.py +4 -5
  4. gwpy/cli/qtransform.py +1 -1
  5. gwpy/detector/tests/test_units.py +3 -0
  6. gwpy/detector/units.py +12 -3
  7. gwpy/frequencyseries/frequencyseries.py +13 -4
  8. gwpy/io/cache.py +24 -1
  9. gwpy/io/datafind.py +1 -0
  10. gwpy/io/ffldatafind.py +27 -16
  11. gwpy/io/tests/test_ffldatafind.py +10 -3
  12. gwpy/plot/gps.py +7 -2
  13. gwpy/plot/tests/test_gps.py +1 -0
  14. gwpy/plot/tests/test_tex.py +3 -0
  15. gwpy/plot/tex.py +8 -6
  16. gwpy/segments/flag.py +14 -3
  17. gwpy/segments/tests/test_flag.py +53 -0
  18. gwpy/signal/filter_design.py +4 -3
  19. gwpy/signal/spectral/_lal.py +1 -1
  20. gwpy/signal/tests/test_coherence.py +9 -9
  21. gwpy/signal/tests/test_filter_design.py +3 -3
  22. gwpy/spectrogram/tests/test_spectrogram.py +2 -2
  23. gwpy/testing/fixtures.py +2 -19
  24. gwpy/testing/utils.py +43 -19
  25. gwpy/time/_tconvert.py +19 -33
  26. gwpy/time/tests/test_time.py +4 -45
  27. gwpy/timeseries/core.py +4 -2
  28. gwpy/timeseries/io/cache.py +47 -29
  29. gwpy/timeseries/io/gwf/framecpp.py +11 -2
  30. gwpy/timeseries/io/gwf/lalframe.py +21 -0
  31. gwpy/timeseries/io/losc.py +8 -2
  32. gwpy/timeseries/tests/test_io_cache.py +74 -0
  33. gwpy/timeseries/tests/test_io_gwf_lalframe.py +17 -0
  34. gwpy/timeseries/tests/test_timeseries.py +78 -36
  35. gwpy/types/array.py +16 -3
  36. gwpy/types/index.py +7 -5
  37. gwpy/types/sliceutils.py +5 -1
  38. gwpy/types/tests/test_array2d.py +4 -0
  39. gwpy/types/tests/test_series.py +26 -0
  40. gwpy/utils/shell.py +2 -2
  41. gwpy/utils/sphinx/zenodo.py +118 -61
  42. gwpy/utils/tests/test_shell.py +2 -2
  43. gwpy/utils/tests/test_sphinx_zenodo.py +175 -0
  44. {gwpy-3.0.7.dist-info → gwpy-3.0.9.dist-info}/METADATA +8 -7
  45. {gwpy-3.0.7.dist-info → gwpy-3.0.9.dist-info}/RECORD +49 -48
  46. {gwpy-3.0.7.dist-info → gwpy-3.0.9.dist-info}/WHEEL +1 -1
  47. gwpy/utils/sphinx/epydoc.py +0 -104
  48. {gwpy-3.0.7.dist-info → gwpy-3.0.9.dist-info}/LICENSE +0 -0
  49. {gwpy-3.0.7.dist-info → gwpy-3.0.9.dist-info}/entry_points.txt +0 -0
  50. {gwpy-3.0.7.dist-info → gwpy-3.0.9.dist-info}/top_level.txt +0 -0
gwpy/_version.py CHANGED
@@ -12,5 +12,5 @@ __version__: str
12
12
  __version_tuple__: VERSION_TUPLE
13
13
  version_tuple: VERSION_TUPLE
14
14
 
15
- __version__ = version = '3.0.7'
16
- __version_tuple__ = version_tuple = (3, 0, 7)
15
+ __version__ = version = '3.0.9'
16
+ __version_tuple__ = version_tuple = (3, 0, 9)
gwpy/astro/range.py CHANGED
@@ -25,7 +25,7 @@ import warnings
25
25
  from functools import wraps
26
26
  from math import pi
27
27
 
28
- from scipy.integrate import trapz
28
+ from scipy.integrate import trapezoid
29
29
  from scipy.interpolate import interp1d
30
30
 
31
31
  from astropy import (
@@ -238,7 +238,7 @@ def sensemon_range(psd, snr=8, mass1=1.4, mass2=1.4, fmin=None, fmax=None,
238
238
  integrand = sensemon_range_psd(psd[frange], snr=snr, mass1=mass1,
239
239
  mass2=mass2, horizon=horizon)
240
240
  return (units.Quantity(
241
- trapz(integrand.value, f.value[frange]),
241
+ trapezoid(integrand.value, f.value[frange]),
242
242
  unit=integrand.unit * units.Hertz,
243
243
  ) ** (1/2.)).to('Mpc')
244
244
 
@@ -528,7 +528,7 @@ def burst_range(psd, snr=8, energy=1e-2, fmin=100, fmax=500):
528
528
  # calculate integrand and integrate
529
529
  integrand = burst_range_spectrum(
530
530
  psd[frange], snr=snr, energy=energy) ** 3
531
- out = trapz(integrand.value, f[frange])
531
+ out = trapezoid(integrand.value, f[frange])
532
532
  # normalize and return
533
533
  return (units.Quantity(
534
534
  out / (fmax - fmin),
@@ -24,7 +24,7 @@ from unittest import mock
24
24
  import pytest
25
25
 
26
26
  from astropy import units
27
- from scipy.integrate import trapz
27
+ from scipy.integrate import trapezoid
28
28
 
29
29
  from ... import astro
30
30
  from ...testing import utils
@@ -71,7 +71,7 @@ def test_sensemon_range_psd(psd):
71
71
  r = astro.sensemon_range_psd(psd[frange])
72
72
  assert isinstance(r, FrequencySeries)
73
73
  utils.assert_quantity_almost_equal(
74
- trapz(r, r.frequencies) ** (1/2.),
74
+ trapezoid(r, r.frequencies) ** (1/2.),
75
75
  TEST_RESULTS['sensemon_range'],
76
76
  )
77
77
  assert r.f0.value > 0
@@ -103,9 +103,8 @@ def test_inspiral_range_psd(psd):
103
103
  frange = (psd.frequencies.value < 4096)
104
104
  r = astro.inspiral_range_psd(psd[frange])
105
105
  assert isinstance(r, FrequencySeries)
106
- print(trapz(r, r.frequencies) ** (1/2.))
107
106
  utils.assert_quantity_almost_equal(
108
- trapz(r, r.frequencies) ** (1/2.),
107
+ trapezoid(r, r.frequencies) ** (1/2.),
109
108
  TEST_RESULTS['inspiral_range'],
110
109
  )
111
110
  assert r.f0.value > 0
@@ -129,7 +128,7 @@ def test_burst_range_spectrum(psd):
129
128
  r = astro.burst_range_spectrum(psd[frange])
130
129
  assert isinstance(r, FrequencySeries)
131
130
  utils.assert_quantity_almost_equal(
132
- (trapz(r**3, f[frange]) / (400 * units.Hz)) ** (1/3.),
131
+ (trapezoid(r**3, f[frange]) / (400 * units.Hz)) ** (1/3.),
133
132
  TEST_RESULTS['burst_range'],
134
133
  )
135
134
  assert r.f0.value > 0
gwpy/cli/qtransform.py CHANGED
@@ -215,7 +215,7 @@ class Qtransform(Spectrogram):
215
215
  outseg = Segment(gps, gps).protract(args.plot[self.plot_num])
216
216
 
217
217
  # use the precomputed ASD as the whitener if needed
218
- if self.qxfrm_args.get("whiten"):
218
+ if self.qxfrm_args.get("whiten") is True:
219
219
  self.qxfrm_args["whiten"] = asd
220
220
 
221
221
  # This section tries to optimize the amount of data that is
@@ -39,6 +39,9 @@ __author__ = 'Duncan Macleod <duncan.macleod@ligo.org>'
39
39
  ('degrees_C', units.Unit('Celsius')),
40
40
  ('DegC', units.Unit('Celsius')),
41
41
  ('degrees_F', units.Unit('Fahrenheit')),
42
+ ('time', units.second), # LIGO default time 'unit'
43
+ ('Time (sec)', units.second), # Virgo default time 'unit'
44
+ ('Seconds', units.second), # GWOSC default time 'unit'
42
45
  ])
43
46
  def test_parse_unit(arg, unit):
44
47
  assert parse_unit(arg, parse_strict='silent') == unit
gwpy/detector/units.py CHANGED
@@ -161,9 +161,18 @@ units.add_enabled_units(units_imperial)
161
161
  # 1) alternative names
162
162
  registry = units.get_current_unit_registry().registry
163
163
  for unit, aliases in [
164
- (units.Unit('ct'), ('counts',)),
165
- (units.Unit('Celsius'), ('Degrees_C', 'DegC')),
166
- (units.Unit('Fahrenheit'), ('Degrees_F', 'DegF')),
164
+ (units.Unit('ct'), ('counts',)),
165
+ (units.Unit('Celsius'), ('Degrees_C', 'DegC')),
166
+ (units.Unit('Fahrenheit'), ('Degrees_F', 'DegF')),
167
+ # GW observatories like to record 'time' as the unit
168
+ (units.Unit('second'), (
169
+ 'time',
170
+ 'time (s)',
171
+ 'time [s]',
172
+ 'Time [sec]',
173
+ 'Time (sec)',
174
+ 'Seconds', # GWOSC
175
+ )),
167
176
  ]:
168
177
  unit.names.extend(aliases)
169
178
  for alias in aliases:
@@ -227,10 +227,19 @@ class FrequencySeries(Series):
227
227
  # Undo normalization from TimeSeries.fft
228
228
  # The DC component does not have the factor of two applied
229
229
  # so we account for it here
230
- dift = npfft.irfft(self.value * nout) / 2
231
- new = TimeSeries(dift, epoch=self.epoch, channel=self.channel,
232
- unit=self.unit, dx=1/self.dx/nout)
233
- return new
230
+ array = self.value.copy()
231
+ array[1:] /= 2.0
232
+ dift = npfft.irfft(
233
+ array * nout,
234
+ n=nout,
235
+ )
236
+ return TimeSeries(
237
+ dift,
238
+ epoch=self.epoch,
239
+ channel=self.channel,
240
+ unit=self.unit,
241
+ dx=(1/self.dx/nout).to(TimeSeries._default_xunit),
242
+ )
234
243
 
235
244
  def zpk(self, zeros, poles, gain, analog=True):
236
245
  """Filter this `FrequencySeries` by applying a zero-pole-gain filter
gwpy/io/cache.py CHANGED
@@ -23,6 +23,7 @@ and associated metadata for those files, designed to make identifying
23
23
  relevant data, and sieving large file lists, easier for the user.
24
24
  """
25
25
 
26
+ import contextlib
26
27
  import os
27
28
  import warnings
28
29
  from collections import (namedtuple, OrderedDict)
@@ -51,6 +52,27 @@ else:
51
52
  __author__ = 'Duncan Macleod <duncan.macleod@ligo.org>'
52
53
 
53
54
 
55
+ @contextlib.contextmanager
56
+ def _silence_lal_debug_warnings():
57
+ """Temporarily silence debug warnings from LAL.
58
+ """
59
+ try:
60
+ import lal
61
+ except ImportError:
62
+ yield
63
+ return
64
+
65
+ debuglevel = lal.GetDebugLevel()
66
+ # silence LAL debug warnings
67
+ lal.ClobberDebugLevel(0)
68
+
69
+ try:
70
+ yield
71
+ finally:
72
+ # reset
73
+ lal.ClobberDebugLevel(debuglevel)
74
+
75
+
54
76
  def _preformat_entry(entry):
55
77
  path = file_path(entry)
56
78
  obs, tag, seg = filename_metadata(path)
@@ -83,7 +105,8 @@ def _format_entry_ffl(entry):
83
105
  def _parse_entry_ffl(line, gpstype=LIGOTimeGPS):
84
106
  from ..segments import Segment
85
107
  path, start, dur, _, _ = line
86
- start = gpstype(start)
108
+ with _silence_lal_debug_warnings():
109
+ start = gpstype(start)
87
110
  end = start + float(dur)
88
111
  try:
89
112
  observatory, description = os.path.basename(path).split('-', 2)[:2]
gwpy/io/datafind.py CHANGED
@@ -65,6 +65,7 @@ GRB_TYPE = re.compile(r'^(?!.*_GRB\d{6}([A-Z])?$)') # *_GRBYYMMDD{A}
65
65
  HIGH_PRIORITY_TYPE = re.compile("({})".format("|".join((
66
66
  r'\A[A-Z]\d_HOFT_C\d\d(_T\d{7}_v\d)?\Z', # X1_HOFT_CXY
67
67
  r'\AV1Online\Z',
68
+ r'\AHoftOnline\Z',
68
69
  r'\AV1O[0-9]+([A-Z]+)?Repro[0-9]+[A-Z]+\Z', # V1OXReproXY
69
70
  ))))
70
71
  LOW_PRIORITY_TYPE = re.compile("({})".format("|".join((
gwpy/io/ffldatafind.py CHANGED
@@ -28,8 +28,9 @@ __author__ = "Duncan Macleod <duncan.macleod@ligo.org>"
28
28
 
29
29
  import os
30
30
  import re
31
- from warnings import warn
31
+ from collections import defaultdict
32
32
  from functools import lru_cache
33
+ from warnings import warn
33
34
 
34
35
  from ligo.segments import (
35
36
  segment,
@@ -37,8 +38,10 @@ from ligo.segments import (
37
38
  )
38
39
 
39
40
  from .cache import (
41
+ _CacheEntry,
40
42
  _iter_cache,
41
43
  cache_segments,
44
+ file_segment,
42
45
  read_cache_entry,
43
46
  )
44
47
 
@@ -123,10 +126,10 @@ def _find_ffl_files(basedir=None):
123
126
  def _find_ffls(basedir=None):
124
127
  """Find all readable FFL files.
125
128
  """
126
- ffls = {}
129
+ ffls = defaultdict(list)
127
130
  for path in _find_ffl_files(basedir=basedir):
128
131
  try:
129
- ffls[_get_site_tag(path)] = path
132
+ ffls[_get_site_tag(path)].append(path)
130
133
  except (
131
134
  OSError, # file is empty (or cannot be read at all)
132
135
  AttributeError, # last entry didn't match _SITE_REGEX
@@ -135,8 +138,8 @@ def _find_ffls(basedir=None):
135
138
  return ffls
136
139
 
137
140
 
138
- def _ffl_path(site, tag, basedir=None):
139
- """Return the path of the FFL file for a given site and tag.
141
+ def _ffl_paths(site, tag, basedir=None):
142
+ """Return the paths of all FFL files for a given site and tag.
140
143
  """
141
144
  try:
142
145
  return _find_ffls(basedir=basedir)[(site, tag)]
@@ -147,15 +150,18 @@ def _ffl_path(site, tag, basedir=None):
147
150
 
148
151
 
149
152
  @lru_cache()
150
- def _read_ffl(site, tag, basedir=None):
151
- """Read an FFL file as a list of `CacheEntry` objects
153
+ def _read_ffls(site, tag, basedir=None):
154
+ """Read all FFL files for a given site and tag
155
+ as a list of `CacheEntry` objects.
152
156
  """
153
- ffl = _ffl_path(site, tag, basedir=basedir)
154
- with open(ffl, "r") as fobj:
155
- return [
156
- type(entry)(site, tag, entry.segment, entry.path)
157
- for entry in _iter_cache(fobj, gpstype=float)
158
- ]
157
+ entries = []
158
+ for ffl in _ffl_paths(site, tag, basedir=basedir):
159
+ with open(ffl, "r") as fobj:
160
+ entries.extend(
161
+ _CacheEntry(site, tag, entry.segment, entry.path)
162
+ for entry in _iter_cache(fobj, gpstype=float)
163
+ )
164
+ return entries
159
165
 
160
166
 
161
167
  def _handle_error(action, message):
@@ -261,7 +267,7 @@ def find_urls(
261
267
  span = segment(gpsstart, gpsend)
262
268
 
263
269
  cache = [
264
- e for e in _read_ffl(site, tag) if (
270
+ e for e in _read_ffls(site, tag) if (
265
271
  e.observatory == site
266
272
  and e.description == tag
267
273
  and e.segment.intersects(span)
@@ -305,11 +311,16 @@ def find_latest(site, tag, on_missing="warn"):
305
311
  for a specific site and tag.
306
312
  """
307
313
  try:
308
- fflfile = _ffl_path(site, tag)
314
+ fflfiles = _ffl_paths(site, tag)
309
315
  except ValueError: # no readable FFL file
310
316
  urls = []
311
317
  else:
312
- urls = [read_cache_entry(_read_last_line(fflfile), gpstype=float)]
318
+ urls = [
319
+ read_cache_entry(_read_last_line(fflfile), gpstype=float)
320
+ for fflfile in fflfiles
321
+ ]
322
+ if urls: # if multiple, find the latest one
323
+ urls = sorted(urls, key=file_segment)[-1:]
313
324
 
314
325
  if not urls:
315
326
  _handle_error(on_missing, "No files found")
@@ -96,9 +96,11 @@ def test_is_ffl_file(path, result):
96
96
  # -- test ffl UI ------------
97
97
 
98
98
  FFLS = {
99
- "test.ffl": [
99
+ "a/test.ffl": [
100
100
  "/tmp/X-test-0-1.gwf 0 1 0 0",
101
101
  "/tmp/X-test-1-1.gwf 1 1 0 0",
102
+ ],
103
+ "b/test.ffl": [
102
104
  "/tmp/X-test-2-1.gwf 2 1 0 0",
103
105
  ],
104
106
  "test2.ffl": [
@@ -114,7 +116,11 @@ FFLS = {
114
116
  "test-empty.ffl": [],
115
117
  "test-bad.ffl": ["badness"],
116
118
  }
117
- TEST_URLS = [x.split()[0] for x in FFLS["test.ffl"]]
119
+ TEST_URLS = [
120
+ x.split()[0]
121
+ for key in ("a/test.ffl", "b/test.ffl")
122
+ for x in FFLS[key]
123
+ ]
118
124
 
119
125
 
120
126
  @pytest.fixture(autouse=True)
@@ -124,6 +130,7 @@ def mock_ffl(tmp_path):
124
130
  """
125
131
  for path, lines in FFLS.items():
126
132
  ffl = tmp_path / path
133
+ ffl.parent.mkdir(parents=True, exist_ok=True)
127
134
  ffl.write_text("\n".join(lines))
128
135
  with mock.patch.dict(
129
136
  "os.environ",
@@ -190,7 +197,7 @@ def test_find_latest():
190
197
  assert ffldatafind.find_latest(
191
198
  "X",
192
199
  "test",
193
- ) == sorted(x.split()[0] for x in FFLS["test.ffl"])[-1:]
200
+ ) == sorted(x.split()[0] for x in FFLS["b/test.ffl"])[-1:]
194
201
 
195
202
 
196
203
  @pytest.mark.parametrize(("on_missing", "ctx"), (
gwpy/plot/gps.py CHANGED
@@ -164,8 +164,13 @@ class GPSMixin(object):
164
164
  """
165
165
  if not self.unit:
166
166
  return None
167
- name = sorted(self.unit.names, key=len)[-1]
168
- return name + "s" # pluralise
167
+ try:
168
+ name = self.unit.long_names[0]
169
+ except IndexError:
170
+ name = self.unit.name
171
+ if len(name) > 1:
172
+ return name + "s" # pluralise for humans
173
+ return name
169
174
 
170
175
  def get_scale(self):
171
176
  """The scale (in seconds) of the current GPS unit.
@@ -79,6 +79,7 @@ class TestGPSMixin(object):
79
79
  @pytest.mark.parametrize('unit, name', [
80
80
  (None, None),
81
81
  ('second', 'seconds'),
82
+ (Unit('sday'), 'sdays'), # no long_name
82
83
  ])
83
84
  def test_get_unit_name(self, unit, name):
84
85
  mix = self.TYPE(unit=unit)
@@ -39,6 +39,7 @@ def test_has_tex_missing_exe():
39
39
  """Test that `gwpy.plot.tex.has_tex` returns `False` when
40
40
  any one of the necessary executables is missing.
41
41
  """
42
+ plot_tex.has_tex.cache_clear()
42
43
  assert not plot_tex.has_tex()
43
44
 
44
45
 
@@ -47,6 +48,7 @@ def test_has_tex_bad_latex(_):
47
48
  """Test that `gwpy.plot.tex.has_tex` returns `False` when
48
49
  the LaTeX figure fails to render.
49
50
  """
51
+ plot_tex.has_tex.cache_clear()
50
52
  assert not plot_tex.has_tex()
51
53
 
52
54
 
@@ -57,6 +59,7 @@ def test_has_tex_true(_which_, _test_usetex):
57
59
  all of the necessary executables are found, and the LaTeX figure
58
60
  doesn't raise an exception.
59
61
  """
62
+ plot_tex.has_tex.cache_clear()
60
63
  assert plot_tex.has_tex()
61
64
 
62
65
 
gwpy/plot/tex.py CHANGED
@@ -21,6 +21,7 @@
21
21
  """
22
22
 
23
23
  import re
24
+ from functools import lru_cache
24
25
  from shutil import which
25
26
 
26
27
  __author__ = "Duncan Macleod <duncan.macleod@ligo.org>"
@@ -38,12 +39,15 @@ def _test_usetex():
38
39
  from matplotlib import (pyplot, rc_context)
39
40
  with rc_context({"text.usetex": True}):
40
41
  fig = pyplot.figure()
41
- ax = fig.gca()
42
- ax.set_xlabel(r"\LaTeX")
43
- fig.canvas.draw()
44
- pyplot.close(fig)
42
+ try:
43
+ ax = fig.gca()
44
+ ax.set_xlabel(r"\LaTeX")
45
+ fig.canvas.draw()
46
+ finally:
47
+ pyplot.close(fig)
45
48
 
46
49
 
50
+ @lru_cache(maxsize=None)
47
51
  def has_tex():
48
52
  """Returns whether tex is installed on this system
49
53
 
@@ -69,8 +73,6 @@ def has_tex():
69
73
  return True
70
74
 
71
75
 
72
- HAS_TEX = has_tex()
73
-
74
76
  # -- tex formatting -----------------------------------------------------------
75
77
 
76
78
  LATEX_CONTROL_CHARS = ["%", "\\", "_", "~", "&", "#"]
gwpy/segments/flag.py CHANGED
@@ -1,6 +1,6 @@
1
1
  # -*- coding: utf-8 -*-
2
2
  # Copyright (C) Louisiana State University (2014-2017)
3
- # Cardiff University (2017-2021)
3
+ # Cardiff University (2017-2023)
4
4
  #
5
5
  # This file is part of GWpy.
6
6
  #
@@ -1263,12 +1263,19 @@ class DataQualityDict(OrderedDict):
1263
1263
 
1264
1264
  # parse a table into the target DataQualityDict
1265
1265
  def _parse_segments(table, listattr):
1266
+ # handle missing *_ns columns in LIGO_LW XML
1267
+ # (LIGO DMT doesn't/didn't write them)
1268
+ if 'start_time_ns' in table.columnnames:
1269
+ row_segment = operator.attrgetter("segment")
1270
+ else:
1271
+ row_segment = operator.attrgetter("start_time", "end_time")
1272
+
1266
1273
  for row in table:
1267
1274
  for flag in out:
1268
1275
  # match row ID to list of IDs found for this flag
1269
1276
  if int(row.segment_def_id) in id_[flag]:
1270
1277
  getattr(out[flag], listattr).append(
1271
- Segment(*map(gpstype, row.segment)),
1278
+ Segment(*map(gpstype, row_segment(row))),
1272
1279
  )
1273
1280
  break
1274
1281
 
@@ -1442,7 +1449,11 @@ class DataQualityDict(OrderedDict):
1442
1449
  if segments is None and source.netloc:
1443
1450
  try:
1444
1451
  tmp = {key: self[key].query(
1445
- self[key].name, self[key].known, **kwargs)}
1452
+ self[key].name,
1453
+ self[key].known,
1454
+ url=source.geturl(),
1455
+ **kwargs,
1456
+ )}
1446
1457
  except URLError as exc:
1447
1458
  if on_error == 'ignore':
1448
1459
  pass
@@ -76,6 +76,52 @@ def veto_definer(tmp_path):
76
76
  return tmp
77
77
 
78
78
 
79
+ # -- XML without _ns columns --------------------------------------------------
80
+
81
+ LIGOLW_NO_NS = """
82
+ <?xml version="1.0"?>
83
+ <!DOCTYPE LIGO_LW SYSTEM "http://ldas-sw.ligo.caltech.edu/doc/ligolwAPI/html/ligolw_dtd.txt">
84
+ <LIGO_LW>
85
+ <Table Name="segment_definergroup:segment_definer:table">
86
+ <Column Name="segment_def_id" Type="int_8s"/>
87
+ <Column Name="ifos" Type="lstring"/>
88
+ <Column Name="name" Type="lstring"/>
89
+ <Column Name="version" Type="int_4s"/>
90
+ <Column Name="comment" Type="lstring"/>
91
+ <Stream Name="segment_definergroup:segment_definer:table" Type="Local" Delimiter=",">
92
+ 0,"X1","TEST_FLAG",1,"Test flag",
93
+ </Stream>
94
+ </Table>
95
+ <Table Name="segment_summarygroup:segment_summary:table">
96
+ <Column Name="segment_sum_id" Type="int_8s"/>
97
+ <Column Name="start_time" Type="int_4s"/>
98
+ <Column Name="end_time" Type="int_4s"/>
99
+ <Column Name="comment" Type="lstring"/>
100
+ <Column Name="segment_definer:segment_def_id" Type="int_8s"/>
101
+ <Stream Name="segment_summarygroup:segment_summary:table" Type="Local" Delimiter=",">
102
+ 0,1366644592,1366644608,"",0,
103
+ </Stream>
104
+ </Table>
105
+ <Table Name="segmentgroup:segment:table">
106
+ <Column Name="segment_id" Type="int_8s"/>
107
+ <Column Name="start_time" Type="int_4s"/>
108
+ <Column Name="end_time" Type="int_4s"/>
109
+ <Column Name="segment_definer:segment_def_id" Type="int_8s"/>
110
+ <Stream Name="segmentgroup:segment:table" Type="Local" Delimiter=",">
111
+ 0,1366644592,1366644593,0,
112
+ </Stream>
113
+ </Table>
114
+ </LIGO_LW>
115
+ """.strip() # noqa: E501
116
+
117
+
118
+ @pytest.fixture
119
+ def ligolw_no_ns(tmp_path):
120
+ tmp = tmp_path / "test.xml"
121
+ tmp.write_text(LIGOLW_NO_NS)
122
+ return tmp
123
+
124
+
79
125
  # -- test data ----------------------------------------------------------------
80
126
 
81
127
  def _as_segmentlist(*segments):
@@ -489,6 +535,13 @@ class TestDataQualityFlag(object):
489
535
  segdeftab = read_table(tmp, 'segment_definer')
490
536
  assert int(segdeftab[0].process_id) == 100
491
537
 
538
+ @pytest.mark.requires("ligo.lw.lsctables")
539
+ def test_read_ligolw_no_ns(self, ligolw_no_ns):
540
+ flag = self.TEST_CLASS.read(ligolw_no_ns, format="ligolw")
541
+ assert flag.name == "X1:TEST_FLAG:1"
542
+ assert flag.known == [(1366644592, 1366644608)]
543
+ assert flag.active == [(1366644592, 1366644593)]
544
+
492
545
  # -- test queries ---------------------------
493
546
 
494
547
  @mock.patch("gwpy.segments.flag.query_segments", mock_query_segments)
@@ -30,6 +30,7 @@ from scipy import signal
30
30
 
31
31
  from astropy.units import (Unit, Quantity)
32
32
 
33
+ from ..types.array import COPY_IF_NEEDED
33
34
  from .window import (get_window, planck)
34
35
 
35
36
  __author__ = "Duncan Macleod <duncan.macleod@ligo.org>"
@@ -89,7 +90,7 @@ def _design_fir(wp, ws, sample_rate, gpass, gstop, window='hamming', **kwargs):
89
90
  kwargs.setdefault('pass_zero', False)
90
91
  if ws.shape == (1,):
91
92
  kwargs.setdefault('width', ws - wp)
92
- kwargs.setdefault('nyq', sample_rate/2.)
93
+ kwargs.setdefault('fs', sample_rate)
93
94
  return signal.firwin(nt, wp, window=window, **kwargs)
94
95
 
95
96
 
@@ -281,9 +282,9 @@ def bilinear_zpk(zeros, poles, gain, fs=1.0, unit='Hz'):
281
282
  zpk : `tuple`
282
283
  digital version of input zpk
283
284
  """
284
- zeros = numpy.array(zeros, dtype=float, copy=False)
285
+ zeros = numpy.array(zeros, dtype=float, copy=COPY_IF_NEEDED)
285
286
  zeros = zeros[numpy.isfinite(zeros)]
286
- poles = numpy.array(poles, dtype=float, copy=False)
287
+ poles = numpy.array(poles, dtype=float, copy=COPY_IF_NEEDED)
287
288
  gain = gain
288
289
 
289
290
  # convert from Hz to rad/s if needed
@@ -19,7 +19,7 @@
19
19
  """GWpy API to the LAL FFT routines
20
20
 
21
21
  See the `LAL TimeFreqFFT.h documentation
22
- <http://software.ligo.org/docs/lalsuite/lal/group___time_freq_f_f_t__h.html>`_
22
+ <https://lscsoft.docs.ligo.org/lalsuite/lal/group___time_freq_f_f_t__h.html>`_
23
23
  for more details
24
24
 
25
25
  This module is deprecated and will be removed in a future release.
@@ -33,7 +33,8 @@ from ...timeseries import TimeSeries
33
33
  def series_data():
34
34
  """Create some fake data with equal sampling frequencies.
35
35
 
36
- Returns:
36
+ Returns
37
+ -------
37
38
  firstarr: an array of data, simple mixture of waves
38
39
  secondarr: a second array of data from different mixture
39
40
  seglen: segment length param to reuse for ffts
@@ -49,7 +50,7 @@ def series_data():
49
50
  firstarr += np.random.normal(5.8, 2, n_t)
50
51
 
51
52
  secondarr = 0.5 * np.cos(ts + 0.1) + 0.1 * np.sin(5 * ts + 10)
52
- firstarr += np.random.normal(5.8, 2, n_t)
53
+ secondarr += np.random.normal(5.8, 2, n_t)
53
54
 
54
55
  return firstarr, secondarr, seglen
55
56
 
@@ -58,7 +59,8 @@ def series_data():
58
59
  def unequal_fs_series_data():
59
60
  """Create some fake data with unequal sampling frequencies.
60
61
 
61
- Returns:
62
+ Returns
63
+ -------
62
64
  ts1: array of time points for first data array
63
65
  ts2: array of time points for second data array
64
66
  firstarr: an array of data, simple mixture of waves
@@ -67,7 +69,6 @@ def unequal_fs_series_data():
67
69
  fs_1: sampling frequency 1
68
70
  fs_2: sampling frequency 2
69
71
  """
70
-
71
72
  seglen = 512
72
73
  n_segs1 = 10
73
74
  n_segs2 = 20
@@ -92,7 +93,6 @@ def test_coherence_happy(series_data):
92
93
 
93
94
  For other tests see timeseries/tests/timeseries.py
94
95
  """
95
-
96
96
  firstarr, secondarr, seglen = series_data
97
97
  f_s = 0.001
98
98
 
@@ -108,8 +108,8 @@ def test_coherence_happy(series_data):
108
108
 
109
109
 
110
110
  def test_coherence_resample(unequal_fs_series_data):
111
- """Ensure warning is raised by unequal sampling frequencies"""
112
-
111
+ """Ensure warning is raised by unequal sampling frequencies.
112
+ """
113
113
  ts1, ts2, firstarr, secondarr, seglen, fs_1, fs_2 = unequal_fs_series_data
114
114
 
115
115
  # first and second arrays are different, secondarr should have
@@ -137,8 +137,8 @@ def test_coherence_resample(unequal_fs_series_data):
137
137
 
138
138
 
139
139
  def test_coherence_resample_arg(series_data):
140
- """Ensure warning is raised by unequal sampling frequencies"""
141
-
140
+ """Ensure warning is raised by unequal sampling frequencies.
141
+ """
142
142
  firstarr, secondarr, seglen = series_data
143
143
  f_s = 0.001
144
144
 
@@ -50,7 +50,7 @@ LOWPASS_IIR_100HZ = signal.iirdesign(
50
50
  analog=False, ftype='cheby1', output='zpk',
51
51
  )
52
52
  LOWPASS_FIR_100HZ = signal.firwin(
53
- 30, 100, window='hamming', width=50., nyq=512.,
53
+ 30, 100, window='hamming', width=50., fs=1024.,
54
54
  )
55
55
 
56
56
  HIGHPASS_IIR_100HZ = signal.iirdesign(
@@ -60,7 +60,7 @@ HIGHPASS_IIR_100HZ = signal.iirdesign(
60
60
  analog=False, ftype='cheby1', output='zpk',
61
61
  )
62
62
  HIGHPASS_FIR_100HZ = signal.firwin(
63
- 45, 100, window='hamming', pass_zero=False, width=-100/3., nyq=512.,
63
+ 45, 100, window='hamming', pass_zero=False, width=-100/3., fs=1024.,
64
64
  )
65
65
 
66
66
  BANDPASS_IIR_100HZ_200HZ = signal.iirdesign(
@@ -70,7 +70,7 @@ BANDPASS_IIR_100HZ_200HZ = signal.iirdesign(
70
70
  analog=False, ftype='cheby1', output='zpk',
71
71
  )
72
72
  BANDPASS_FIR_100HZ_200HZ = signal.firwin(
73
- 45, (100, 200.), window='hamming', pass_zero=False, nyq=512.,
73
+ 45, (100, 200.), window='hamming', pass_zero=False, fs=1024.,
74
74
  )
75
75
 
76
76