Downloading Waveforms from Different Catalogs

This tutorial demonstrates how to download and work with waveforms from various numerical relativity catalogs using PyART. PyART provides a unified interface to access data from multiple catalogs including:

  • SXS (Simulating eXtreme Spacetimes)

  • RIT (Rochester Institute of Technology)

  • CoRe (Computational Relativity)

  • GRA (GR-Athena++)

  • ICCUB (Institute of Cosmos Sciences)

  • SACRA

Setup

First, let’s import the necessary modules:

%matplotlib inline
%config InlineBackend.figure_format = 'retina'

from PyART.catalogs import sxs, rit, core, icc_public
from PyART.catalogs.cataloger import Cataloger

try:
    from PyART.catalogs import gra
except ImportError:
    gra = None
    print('Skipping GRA catalog examples: optional dependencies for PyART.catalogs.gra are not installed.')
/opt/hostedtoolcache/Python/3.12.15/x64/lib/python3.12/site-packages/PyART/analysis/match.py:20: UserWarning: Wswiglal-redir-stdio:

SWIGLAL standard output/error redirection is enabled in IPython.
This may lead to performance penalties. To disable locally, use:

with lal.no_swig_redirect_standard_output_error():
    ...

To disable globally, use:

lal.swig_redirect_standard_output_error(False)

Note however that this will likely lead to error messages from
LAL functions being either misdirected or lost when called from
Jupyter notebooks.

To suppress this warning, use:

import warnings
warnings.filterwarnings("ignore", "Wswiglal-redir-stdio")
import lal

  import lal

Downloading from a Single Catalog

Let’s start by downloading waveforms from the SXS catalog. We specify:

  • The catalog name

  • The simulation ID

  • Whether to download if not locally available

SXS

# Download and load an SXS waveform
# Note: You may need to adjust the path or set download=True
sxs_id = '0180'
wf_sxs = sxs.Waveform_SXS(path='./', ID=sxs_id, download=True, cut_N=300, ignore_deprecation=True)

print(f"SXS Waveform {sxs_id} loaded successfully")
print(f"Mass ratio q = {wf_sxs.metadata['q']:.3f}")
print(f"Total mass M = {wf_sxs.metadata['M']:.3f}")
print(f"Chi1z = {wf_sxs.metadata['chi1z']:.3f}")
print(f"Chi2z = {wf_sxs.metadata['chi2z']:.3f}")
/opt/hostedtoolcache/Python/3.12.15/x64/lib/python3.12/site-packages/tqdm/auto.py:21: TqdmWarning: IProgress not found. Please update jupyter and ipywidgets. See https://ipywidgets.readthedocs.io/en/stable/user_install.html
  from .autonotebook import tqdm as notebook_tqdm
  0%|          | 0/5589954 [00:00<?, ?it/s]
9.62MB [00:00, 98.5MB/s]                   
31.1MB [00:00, 210MB/s] 

  0%|          | 0/1390909 [00:00<?, ?it/s]
  5%|▍         | 64.0k/1.33M [00:00<00:05, 240kB/s]
  9%|▉         | 128k/1.33M [00:00<00:03, 320kB/s] 
 14%|█▍        | 192k/1.33M [00:00<00:03, 385kB/s]
 24%|██▎       | 320k/1.33M [00:00<00:01, 593kB/s]
 28%|██▊       | 384k/1.33M [00:00<00:01, 565kB/s]
 38%|███▊      | 512k/1.33M [00:00<00:01, 706kB/s]
 47%|████▋     | 640k/1.33M [00:01<00:01, 606kB/s]
 57%|█████▋    | 768k/1.33M [00:01<00:00, 708kB/s]
 66%|██████▌   | 896k/1.33M [00:01<00:00, 787kB/s]
 75%|███████▌  | 1.00M/1.33M [00:01<00:00, 662kB/s]
 85%|████████▍ | 1.12M/1.33M [00:01<00:00, 744kB/s]
 94%|█████████▍| 1.25M/1.33M [00:02<00:00, 649kB/s]
100%|██████████| 1.33M/1.33M [00:02<00:00, 655kB/s]

---------------------------------------------------------------------------
KeyboardInterrupt                         Traceback (most recent call last)
Cell In[2], line 4
      1 # Download and load an SXS waveform
      2 # Note: You may need to adjust the path or set download=True
      3 sxs_id = '0180'
----> 4 wf_sxs = sxs.Waveform_SXS(path='./', ID=sxs_id, download=True, cut_N=300, ignore_deprecation=True)
      5 
      6 print(f"SXS Waveform {sxs_id} loaded successfully")
      7 print(f"Mass ratio q = {wf_sxs.metadata['q']:.3f}")

File /opt/hostedtoolcache/Python/3.12.15/x64/lib/python3.12/site-packages/PyART/catalogs/sxs.py:157, in Waveform_SXS.__init__(self, path, ID, order, level, cut_N, cut_U, ellmax, load, download, downloads, load_m0, nu_rescale, src, ignore_deprecation, basename)
    152     logger.info(
    153         f"The path {self.sxs_data_path} does not exist, contains no 'Lev*'"
    154         + "directory, or does not contain the requested order."
    155     )
    156     logger.info("Downloading the simulation from the SXS catalog.")
--> 157     self.download_simulation(
    158         ID=self.ID,
    159         path=path,
    160         downloads=downloads,
    161         level=self.level,
    162         ignore_deprecation=ignore_deprecation,
    163         extrapolation_order=order,
    164     )
    165 else:
    166     logger.warning(
    167         "Use download=True to download the simulation from the SXS catalog."
    168     )

File /opt/hostedtoolcache/Python/3.12.15/x64/lib/python3.12/site-packages/PyART/catalogs/sxs.py:343, in Waveform_SXS.download_simulation(self, ID, path, downloads, level, ignore_deprecation, extrapolation_order)
    341 # Save hlm data if requested
    342 if "hlm" in downloads:
--> 343     wav = sxs_sim.h
    344     extp = f"Extrapolated_N{extrapolation_order}.dir"
    345     to_h5file = {extp: {}}

File /opt/hostedtoolcache/Python/3.12.15/x64/lib/python3.12/site-packages/sxs/simulations/simulation.py:555, in SimulationBase.strain(self)
    552 @property
    553 def strain(self):
    554     if not hasattr(self, "_strain"):
--> 555         self._strain = self.load_waveform(*self.strain_path)
    556     return self._strain

File /opt/hostedtoolcache/Python/3.12.15/x64/lib/python3.12/site-packages/sxs/simulations/simulation.py:935, in Simulation_v2.load_waveform(self, file_name, group, transform_to_inertial, drop_times_before)
    933         raise ValueError(f"{json_truepath} not found and download is disabled")
    934     download_file(json_location, json_truepath)
--> 935 return load(
    936     h5_location, truepath=h5_truepath, group=group, metadata=self.metadata,
    937     transform_to_inertial=transform_to_inertial, drop_times_before=drop_times_before,
    938 )

File /opt/hostedtoolcache/Python/3.12.15/x64/lib/python3.12/site-packages/sxs/handlers.py:385, in load(location, download, cache, progress, truepath, **kwargs)
    381             return loaded
    383 loader = sxs_loader(path, kwargs.get("group", None))
--> 385 loaded = loader(path, **kwargs)
    386 try:
    387     loaded.__file__ = str(path)

File /opt/hostedtoolcache/Python/3.12.15/x64/lib/python3.12/site-packages/sxs/waveforms/format_handlers/rotating_paired_diff_multishuffle_bzip2.py:636, in load(file_name, ignore_validation, check_md5, transform_to_inertial, convert_from_conjugate_pairs, compression, diff, formats, metadata, **kwargs)
    633     w.convert_from_conjugate_pairs()
    635 if transform_to_inertial:
--> 636     w = w.to_inertial_frame()
    638 if metadata is None:
    639     try:

File /opt/hostedtoolcache/Python/3.12.15/x64/lib/python3.12/site-packages/sxs/waveforms/waveform_modes.py:1226, in WaveformModes.to_inertial_frame(self)
   1224 if self.frame.shape != (self.n_times, 4):
   1225     raise ValueError(f"Frame shape {self.frame.shape} not understood; expected {(self.n_times, 4)}")
-> 1226 w = self.rotate(~self.frame)
   1227 w._metadata["frame_type"] = "inertial"
   1228 return w

File /opt/hostedtoolcache/Python/3.12.15/x64/lib/python3.12/site-packages/sxs/waveforms/waveform_modes.py:1202, in WaveformModes.rotate(self, quat)
   1200         m = m.reshape(-1, m.shape[-1])
   1201         r = r.reshape(-1, r.shape[-1])
-> 1202         _rotate(
   1203             m, r,
   1204             wigner.ell_min, wigner.ell_max, wigner.mp_max,
   1205             self.ell_min, self.ell_max, self.spin_weight,
   1206             D
   1207         )
   1208 else:
   1209     raise ValueError(
   1210         f"Quaternionic array shape {R.shape} not understood; expected {(4,)}, {(1, 4)}, or {(self.n_times, 4)}"
   1211     )

KeyboardInterrupt: 

RIT

The RIT catalog waveforms are downloaded via wget from the RIT website, rather than from a dedicated API. Horizon data is not available for RIT waveforms.

# Note: This requires having a RIT data path set up
# or will download the data if download=True
# For this example, we'll show the structure without executing

rit_id = 1096
wf_rit = rit.Waveform_RIT(path='./', ID=rit_id, 
                           download=True, nu_rescale=True)
print(f"RIT Waveform {rit_id} loaded")
print(f"Mass ratio q = {wf_rit.metadata['q']:.3f}")
print(f"Total mass M = {wf_rit.metadata['M']:.3f}")
print(f"Chi1z = {wf_rit.metadata['chi1z']:.3f}")
print(f"Chi2z = {wf_rit.metadata['chi2z']:.3f}")

CoRe database

CoRe database waveforms are downloaded from the gitlab public repository, using git-lfs.

For the download of THC waveforms, modify the code argument accordingly.

core_id = '0001'
wf_core = core.Waveform_CoRe(path='./', ID=core_id, download=True, code='BAM')

print(f"CoRe Waveform {core_id} loaded")
print(f"Mass ratio q = {wf_core.metadata['q']:.3f}")
print(f"Total mass M = {wf_core.metadata['M']:.3f}")
print(f"Chi1z = {wf_core.metadata['chi1z']:.3f}")
print(f"Chi2z = {wf_core.metadata['chi2z']:.3f}")

ICCUB (public repository)

wf_icc = icc_public.Waveform_ICC(path='./', ID='0001', download=True, ellmax=4)

print(f"ICCUB Waveform 0001 loaded")
print(f"Mass ratio q = {wf_icc.metadata['q']:.3f}")
print(f"Total mass M = {wf_icc.metadata['M']:.3f}")
print(f"Chi1z = {wf_icc.metadata['chi1z']:.3f}")
print(f"Chi2z = {wf_icc.metadata['chi2z']:.3f}")

GR-Athena++

The GR-Athena++ catalog waveforms are downloaded from ScholarSphere, see: https://scholarsphere.psu.edu/resources/610744ac-80b9-4689-8119-320dfd2e2b9a

wf_gra = gra.Waveform_GRA(path='./', ID='0001', download=True, downloads=['hlm', 'metadata'])

print(f"GRA Waveform 0001 loaded")
print(f"Mass ratio q = {wf_gra.metadata['q']:.3f}")
print(f"Total mass M = {wf_gra.metadata['M']:.3f}")
print(f"Chi1z = {wf_gra.metadata['chi1z']:.3f}")
print(f"Chi2z = {wf_gra.metadata['chi2z']:.3f}")

Using the Cataloger for Bulk Operations

The Cataloger class provides a convenient way to work with multiple simulations from a catalog at once. This is particularly useful for computing mismatches or other comparative analyses across a set of simulations.

Here’s an example structure:

# Example: Working with multiple RIT simulations
sim_list = list(range(1096, 1100))  # List of simulation IDs

cat = Cataloger(
    path='./local_data/rit/', 
    catalog='rit', 
    sim_list=sim_list,
    add_opts={'download': True, 'nu_rescale': True}
)

# Plot all waveforms in the catalog
cat.plot_waves()

Comparing Waveforms Between Catalogs

One of PyART’s strengths is the ability to easily compare waveforms from different catalogs. Since all catalogs use the same interface, you can load waveforms from different sources and compare them directly.

For detailed mismatch calculations between catalogs, see the Mode-by-mode Mismatch tutorial.

Summary

This tutorial covered:

  • How to download waveforms from the SXS catalog

  • How to access waveform metadata

  • How to compute and plot waveform modes

  • The structure for working with other catalogs (RIT, CoRe, etc.)

  • Using the Cataloger class for bulk operations

Next Steps