sxs 2025.0.22__py3-none-any.whl → 2025.0.23__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.
sxs/__version__.py CHANGED
@@ -1 +1 @@
1
- __version__ = "2025.0.22"
1
+ __version__ = "2025.0.23"
sxs/waveforms/__init__.py CHANGED
@@ -16,6 +16,7 @@ from .format_handlers import (
16
16
  rotating_paired_xor_multishuffle_bzip2,
17
17
  spectre_cce_v1,
18
18
  grathena,
19
+ lvcnr,
19
20
  )
20
21
  from .format_handlers.lvc import to_lvc_conventions
21
22
  from . import memory, transformations, alignment, norms
@@ -25,6 +26,7 @@ formats = {
25
26
  None: nrar,
26
27
  "": nrar,
27
28
  "nrar": nrar,
29
+ "lvcnr": lvcnr,
28
30
  "rotating_paired_xor_multishuffle_bzip2": rotating_paired_xor_multishuffle_bzip2,
29
31
  "rpxm": rotating_paired_xor_multishuffle_bzip2,
30
32
  "rpxmb": rotating_paired_xor_multishuffle_bzip2,
@@ -0,0 +1,111 @@
1
+ import re
2
+ import numpy as np
3
+ import h5py
4
+ from scipy.interpolate import InterpolatedUnivariateSpline as Spline
5
+ import spherical as sf
6
+ from ... import waveforms
7
+
8
+ def load(file_name, data_type="h"):
9
+ """Load a waveform from an HDF5 file in the LVCNR format.
10
+
11
+ This function reads data from HDF5 files in the LVCNR format. It
12
+ extracts amplitude and phase information for spherical harmonic
13
+ modes and reconstructs the complex-valued data. This function can
14
+ be extended to further data types.
15
+
16
+ Parameters
17
+ ----------
18
+ file_name : str
19
+ Path to the HDF5 file to be loaded.
20
+
21
+ data_type : str, optional
22
+ The type of data to be loaded. Default is "h" for strain.
23
+
24
+ Returns
25
+ -------
26
+ waveforms.WaveformModes
27
+ The loaded waveform data in WaveformModes format with spin
28
+ weight -2 and data type "h" (strain). The waveform includes
29
+ mode decomposition information with ell_min and ell_max
30
+ determined from the file contents. The data type can be
31
+ overridden if necessary, to accommodate other types of data
32
+ stored in LVCNR format.
33
+ """
34
+
35
+ phase_re = re.compile("phase_l(?P<ell>.*)_m(?P<m>.*)")
36
+
37
+ with h5py.File(file_name, "r") as f:
38
+
39
+ # Find the NRTimes array. RIT and MAYA have different
40
+ # capitalizations.
41
+ nrtimes_matches = [
42
+ key for key in f if key.lower() == "nrtimes"
43
+ ]
44
+ if not (len(nrtimes_matches) == 1 and
45
+ isinstance(f[nrtimes_matches[0]], h5py.Dataset)):
46
+ raise KeyError(
47
+ f"File {file_name} must contain exactly 1 Dataset "
48
+ "named NRTimes (case insensitive)"
49
+ )
50
+
51
+ t = f[nrtimes_matches[0]]
52
+
53
+ # Extract l and m values from the dataset keys
54
+ ell_m = np.array(
55
+ [
56
+ [int(match["ell"]), int(match["m"])]
57
+ for key in f
58
+ for match in [phase_re.match(key)]
59
+ if match
60
+ ]
61
+ )
62
+ ell_min = np.min(ell_m[:, 0])
63
+ ell_max = np.max(ell_m[:, 0])
64
+ data = np.empty(
65
+ (t.size, sf.LM_total_size(ell_min, ell_max)),
66
+ dtype=complex
67
+ )
68
+
69
+ # Compose the data array using amplitude and phase datasets
70
+ for ell in range(ell_min, ell_max + 1):
71
+ for m in range(-ell, ell + 1):
72
+ amp = Spline(
73
+ f[f"amp_l{ell}_m{m}/X"][:],
74
+ f[f"amp_l{ell}_m{m}/Y"][:],
75
+ k=int(f[f"amp_l{ell}_m{m}/deg"][()])
76
+ )(t)
77
+ phase = Spline(
78
+ f[f"phase_l{ell}_m{m}/X"][:],
79
+ f[f"phase_l{ell}_m{m}/Y"][:],
80
+ k=int(f[f"phase_l{ell}_m{m}/deg"][()])
81
+ )(t)
82
+ idx = sf.LM_index(ell, m, ell_min)
83
+ data[:, idx] = amp * np.exp(1j * phase)
84
+
85
+ if "auxiliary-info" in f and \
86
+ "history.txt" in f["auxiliary-info"]:
87
+ history_txt = f["auxiliary-info/history.txt"][()].decode()
88
+ history = (
89
+ "### " + history_txt.replace("\n", "\n### ")
90
+ ).split("\n")
91
+ else:
92
+ history = [""]
93
+
94
+ kwargs = dict(
95
+ time=t,
96
+ time_axis=0,
97
+ modes_axis=1,
98
+ spin_weight=-2,
99
+ data_type=data_type,
100
+ frame_type="inertial",
101
+ history=history,
102
+ version_hist=[],
103
+ r_is_scaled_out=True,
104
+ m_is_scaled_out=True,
105
+ ell_min=ell_min,
106
+ ell_max=ell_max,
107
+ )
108
+
109
+ w = waveforms.WaveformModes(data, **kwargs)
110
+
111
+ return w
sxs/waveforms/memory.py CHANGED
@@ -2,14 +2,15 @@
2
2
 
3
3
  This code is based on the paper "Adding Gravitational Memory to Waveform
4
4
  Catalogs using BMS Balance Laws" by Mitman et al. The main result of that
5
- paper is encapsulated in the `add_memory` function. Basic usage looks like
6
- this:
5
+ paper is encapsulated in the `add_memory` function. All waveforms in
6
+ versions > 1 contain memory, added via this function. If desired,
7
+ memory can be removed via the function 'remove_memory', e.g.,
7
8
 
8
9
  ```python
9
- h = sxs.load("SXS:BBH:0123/Lev/rhOverM", extrapolation_order=3)
10
- h_with_memory = sxs.waveforms.memory.add_memory(h, integration_start_time=1000.0)
10
+ sim = sxs.load("SXS:BBH:0123")
11
+ h = sim.h
12
+ h_without_memory = sxs.waveforms.memory.remove_memory(h, integration_start_time=sim.metadata.relaxation_time)
11
13
  ```
12
-
13
14
  """
14
15
 
15
16
  import numpy as np
@@ -209,7 +210,7 @@ def J_J(h):
209
210
 
210
211
 
211
212
  def add_memory(h, integration_start_time=None, psi4=None):
212
- """Add electric component of null memory to strain and optionally psi4
213
+ """Add electric component of null memory to strain and optionally psi4.
213
214
 
214
215
  This adds the contribution from the energy flux to the strain, and
215
216
  optionally adds minus the 2nd derivative of this contribution to psi4.
@@ -242,3 +243,38 @@ def add_memory(h, integration_start_time=None, psi4=None):
242
243
  psi4_with_memory = WaveformModes(waveform_mts.MTS(psi4) - waveform_mts.MTS(h_memory_correction).ddot)
243
244
  psi4_with_memory.register_modification(add_memory, integration_start_time=integration_start_time)
244
245
  return (h_with_memory, psi4_with_memory)
246
+
247
+ def remove_memory(h, integration_start_time=None, psi4=None):
248
+ """Remove electric component of null memory to strain and optionally psi4.
249
+
250
+ This removes the contribution from the energy flux to the strain, and
251
+ optionally removes minus the 2nd derivative of this contribution to psi4.
252
+
253
+ Parameters
254
+ ----------
255
+ h : WaveformModes
256
+ WaveformModes object corresponding to the strain
257
+ integration_start_time : float, optional
258
+ Time at which the energy flux integral should begin. The default is
259
+ `h.t[0]`.
260
+ psi4 : WaveformModes, optional
261
+ WaveformModes object corresponding to psi4
262
+
263
+ Returns
264
+ -------
265
+ h_without_memory : WaveformModes
266
+ WaveformModes object corresponding to the strain with electric memory
267
+ psi4_without_memory : WaveformModes, optional
268
+ WaveformModes object corresponding to `psi4` with electric memory. If
269
+ `psi4` is `None`, then this is absent.
270
+
271
+ """
272
+ h_memory_correction = J_E(h, integration_start_time=integration_start_time)
273
+ h_without_memory = WaveformModes(waveform_mts.MTS(h) - h_memory_correction)
274
+ h_without_memory.register_modification(remove_memory, integration_start_time=integration_start_time)
275
+ if psi4 is None:
276
+ return h_without_memory
277
+ else:
278
+ psi4_without_memory = WaveformModes(waveform_mts.MTS(psi4) + waveform_mts.MTS(h_memory_correction).ddot)
279
+ psi4_without_memory.register_modification(remove_memory, integration_start_time=integration_start_time)
280
+ return (h_without_memory, psi4_without_memory)
@@ -1358,8 +1358,32 @@ class WaveformModes(WaveformMixin, TimeSeries):
1358
1358
  h_tilde = h_tilde[h_tilde.t.size//2:]
1359
1359
 
1360
1360
  return h_tilde
1361
+
1362
+ def remove_memory(self, integration_start_time):
1363
+ """Remove memory from a waveform.
1364
+
1365
+ This uses sxs.waveforms.memory.remove_memory to remove
1366
+ memory from the waveform. Note that to return the
1367
+ waveform to a state as close as possible to before the
1368
+ memory correction was applied, one should use the
1369
+ simulation's relaxation time as the `integration_start_time`.
1370
+ Even with this, however, the waveform will still be slightly
1371
+ altered as this process is not invertible.
1372
+
1373
+ Parameters
1374
+ ----------
1375
+ integration_start_time : float
1376
+ The time at which to start the integration for the
1377
+ memory calculation. If this is not the relaxation time,
1378
+ then the memory removal may be worse.
1379
+ """
1380
+ from .memory import remove_memory as raw_remove_memory
1361
1381
 
1382
+ h_without_memory = raw_remove_memory(self, integration_start_time=integration_start_time)
1362
1383
 
1384
+ return h_without_memory
1385
+
1386
+
1363
1387
  class WaveformModesDict(MutableMapping, WaveformModes):
1364
1388
  """A dictionary-like class for storing waveform modes
1365
1389
 
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: sxs
3
- Version: 2025.0.22
3
+ Version: 2025.0.23
4
4
  Summary: Interface to data produced by the Simulating eXtreme Spacetimes collaboration
5
5
  Project-URL: Homepage, https://github.com/sxs-collaboration/sxs
6
6
  Project-URL: Documentation, https://sxs.readthedocs.io/
@@ -66,8 +66,14 @@ Description-Content-Type: text/markdown
66
66
  > As described in our [latest paper](https://arxiv.org/abs/2505.13378), our
67
67
  > waveforms now include memory effects. Specifically, when using any
68
68
  > simulation with version 3 or greater, you should expect to see memory effects,
69
- > most visible in the $(\ell, 0)$ modes, and generally resulting in ringdowns
70
- > that do not approach 0 at late times.
69
+ > resulting in ringdowns that do not approach 0 at late times.
70
+ > These effects are most prominent in the $(\ell, 0)$ modes for $\ell \\% 2 = 0$,
71
+ > but they can also appear in other modes if the system is asymmetric.
72
+ > If desired, these effects can be approximately removed by running, e.g.,
73
+ > ```
74
+ > sim = sxs.load("SXS:BBH:0123")
75
+ > h_without_memory = sim.h.remove_memory(sim.metadata.relaxation_time)
76
+ > ```
71
77
 
72
78
 
73
79
  The `sxs` python package provides a high-level interface for using data
@@ -1,5 +1,5 @@
1
1
  sxs/__init__.py,sha256=C8VhmrUPAa70Y-C2KfZv9BhS6ef-eB7uaNtwm18IRhk,2637
2
- sxs/__version__.py,sha256=xAQjE2CoEjOWGwE89i4Wgv0T4Vi5sk-1P7dji-IB02M,26
2
+ sxs/__version__.py,sha256=ZhjwmHWExLtJzl0aDHq5XnI29vsUdrS_-VLalAgSJM0,26
3
3
  sxs/citation.py,sha256=QAiRnasTXpufZCaoxTKR5ESSJQ2ww7FgWyxoaaAQifw,7167
4
4
  sxs/handlers.py,sha256=fhqDkLAdZPWHLB5ezZd4ynBUoBp2VZKePgcJnPp5Y20,18949
5
5
  sxs/juliapkg.json,sha256=j-T3x1iSsGEw7mttbjaUvo0GPXB5611bp9Cob_XLDBo,178
@@ -56,20 +56,21 @@ sxs/utilities/references/fairchild_report.py,sha256=MUnYQD7zJcz202Vt3-j9ueXglthG
56
56
  sxs/utilities/references/inspire.py,sha256=kDjY-UFJT-VTS3yJOT8fT6LJG-pRrX9TK8nv3RZqrbo,8431
57
57
  sxs/utilities/references/journal_abbreviations.py,sha256=SuRXcr4rv9YPbXD4mzujSvE7M6KS1lwELimuyn7mfCE,31018
58
58
  sxs/utilities/references/references.py,sha256=29rPUZKw3dztXQLRDEt1hGYjZaONFd0qX--xQxzOmUU,418
59
- sxs/waveforms/__init__.py,sha256=yfPzExhZZqNrPOe784f8BC8mHUiwb85urKM_4_pzUFo,1157
59
+ sxs/waveforms/__init__.py,sha256=Xggh2YM9--z3-fTq6jcj4HDYcro2Vp7SLZa_nZnAO3w,1188
60
60
  sxs/waveforms/alignment.py,sha256=vFa58ZgdMTFam-LFQ47xo0iBjfiiFaGIaN1kE5kpjSk,32718
61
- sxs/waveforms/memory.py,sha256=UR2NLMyS0TLJ-2ntdKdzQ00Ot4OvBDrlX6lhFM_uPtI,7300
61
+ sxs/waveforms/memory.py,sha256=oEHTf9C40R1giN3H7tZaGCKTp4-OhGNKC6O7LDyF4jc,8988
62
62
  sxs/waveforms/mode_utilities.py,sha256=gxsW-hunCoIReBVv9IrkGLdshr0rmztbH-JRgD6D9z0,5253
63
63
  sxs/waveforms/norms.py,sha256=zemgJsWNhng3QAi3ixHAZ8P5SSIUcHysSQIcqRGDeyI,8944
64
64
  sxs/waveforms/transformations.py,sha256=S5C-xnCk2umZlVsYgciyp7VMGZA8NI6md7OZp72upJU,9124
65
65
  sxs/waveforms/waveform_grid.py,sha256=aBlcsudj1XozZD7n42sh6-nzysKNalAdHJkVQ7M6fE4,180
66
66
  sxs/waveforms/waveform_mixin.py,sha256=S0RNe2HkwnqdCyGEarGYmoXD_DkTWGorsiGGIBWOam8,1179
67
- sxs/waveforms/waveform_modes.py,sha256=BpjjB42COmr9A3Li5MjhPs_jr9FOfOWRGN_tykQyEYA,60177
67
+ sxs/waveforms/waveform_modes.py,sha256=lQ9MVljTdkARFO4-qVh8-otlZRSqKLkHkMhiosL-fSc,61188
68
68
  sxs/waveforms/waveform_mts.py,sha256=rdEDlAK4TA4F6hFCVi0DrdYucJIGneqmWkEHaScDh0I,660
69
69
  sxs/waveforms/waveform_signal.py,sha256=Ojrt6DSDdleB0qmu6UwjjPnYdaWsrjnpBA_8dhnM_q4,182
70
70
  sxs/waveforms/format_handlers/__init__.py,sha256=0wsnuBYCYsCkN19L2ipga7BtigvPyBcqiy_4qrzmLpE,50
71
71
  sxs/waveforms/format_handlers/grathena.py,sha256=5NrHL3K0mRHApnFx5YsMUufDKUD1A_dZu8mGQqOdBeE,3622
72
72
  sxs/waveforms/format_handlers/lvc.py,sha256=bGAB2k1vXIloA25dUKu4ZUJde5Y4CHrjkPXtQ93aw7w,8006
73
+ sxs/waveforms/format_handlers/lvcnr.py,sha256=QhCjQmS5JTJGT2o0kTyvybw-gloxAdpoQzgT02OU3FQ,3651
73
74
  sxs/waveforms/format_handlers/nrar.py,sha256=3ycVoqQcWAAixV3mKp58_wUhYBHt6QeLv2YGSvy-EGM,21538
74
75
  sxs/waveforms/format_handlers/rotating_paired_diff_multishuffle_bzip2.py,sha256=jTUn487h32wUdXmKFIzUoU5yPj-fxSdzR9OV5f52zRc,27702
75
76
  sxs/waveforms/format_handlers/rotating_paired_xor_multishuffle_bzip2.py,sha256=pFEJIlb6OQQNhv6r48ALFnZMKNZjuQY55ydWBADCDgU,2348
@@ -83,8 +84,8 @@ sxs/zenodo/api/__init__.py,sha256=EM_eh4Q8R5E0vIfMhyIR1IYFfOBu6vA0UTasgX9gHys,21
83
84
  sxs/zenodo/api/deposit.py,sha256=J4RGvGjh0cEOrN4bBZWEDcPAhNscqB2fzLlvRZ5HTHM,36948
84
85
  sxs/zenodo/api/login.py,sha256=hXyxLrx1PALaEEH76XrBvlO5Wwz-qa-MCjkI8UyB3t0,18005
85
86
  sxs/zenodo/api/records.py,sha256=nKkhoHZ95CTztHF9Zzaug5p7IiUCJG4Em1i-l-WqH6U,3689
86
- sxs-2025.0.22.dist-info/METADATA,sha256=7-3W2KRg5N5LOf45gVjeDyZwhBLaTmiHXs3LFaTe7lY,11941
87
- sxs-2025.0.22.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
88
- sxs-2025.0.22.dist-info/entry_points.txt,sha256=51VqSnJT5UOMI4RilR9giG9DNrIDgnsSkuNuYldEnTs,89
89
- sxs-2025.0.22.dist-info/licenses/LICENSE,sha256=ptVOd5m7LDM5ZF0x32cxb8c2Nd5NDmAhy6DX7xt_7VA,1080
90
- sxs-2025.0.22.dist-info/RECORD,,
87
+ sxs-2025.0.23.dist-info/METADATA,sha256=vzTKgKY66TLYO5WZl9X0EuLwef6l5uinLB20JGCBggw,12230
88
+ sxs-2025.0.23.dist-info/WHEEL,sha256=WLgqFyCfm_KASv4WHyYy0P3pM_m7J5L9k2skdKLirC8,87
89
+ sxs-2025.0.23.dist-info/entry_points.txt,sha256=51VqSnJT5UOMI4RilR9giG9DNrIDgnsSkuNuYldEnTs,89
90
+ sxs-2025.0.23.dist-info/licenses/LICENSE,sha256=ptVOd5m7LDM5ZF0x32cxb8c2Nd5NDmAhy6DX7xt_7VA,1080
91
+ sxs-2025.0.23.dist-info/RECORD,,