Skip to content

Commit e37348d

Browse files
CopilotRoxGamba
andauthored
Add tutorial notebooks for waveform analysis workflows (Issue #42) (#43)
Add new tutorial notebooks based on examples, one small bugfix in `interpolate_hlm` method --------- Co-authored-by: copilot-swe-agent[bot] <198982749+Copilot@users.noreply.github.com> Co-authored-by: RoxGamba <72128273+RoxGamba@users.noreply.github.com> Co-authored-by: RoxGamba <rgamba@berkeley.edu>
1 parent 1814e70 commit e37348d

10 files changed

Lines changed: 1884 additions & 204 deletions

PyART/waveform.py

Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -201,7 +201,7 @@ def compute_dothlm(self, factor=1.0, only_warn=False):
201201
dothlm[k] = wf_ut.get_multipole_dict(dhlm)
202202
self._dothlm = dothlm
203203
pass
204-
204+
205205
def compute_psi4lm(self, factor=1.0, only_warn=False):
206206
"""
207207
Compute psi4lm from self.dothlm using
@@ -221,16 +221,16 @@ def compute_psi4lm(self, factor=1.0, only_warn=False):
221221
dictionary with psi4 multipoles
222222
"""
223223
if not self.dothlm:
224-
msg = 'psi4lm cannot be computed if dothlm is not computed'
224+
msg = "psi4lm cannot be computed if dothlm is not computed"
225225
if only_warn:
226226
logging.warning(msg)
227227
else:
228228
raise RuntimeError(msg)
229229

230230
psi4lm = {}
231231
for k in self.dothlm:
232-
dothlm = self.dothlm[k]['z']
233-
ddothlm = ut.D1(dothlm, self.u, 4)
232+
dothlm = self.dothlm[k]["z"]
233+
ddothlm = ut.D1(dothlm, self.u, 4)
234234
ddothlm *= factor
235235
psi4lm[k] = wf_ut.get_multipole_dict(ddothlm)
236236
self._psi4lm = psi4lm
@@ -379,7 +379,7 @@ def interpolate_hlm(self, dT):
379379
iA = np.interp(new_u, self.u, np.abs(h))
380380
ip = np.interp(new_u, self.u, -np.unwrap(np.angle(h)))
381381
ih = iA * np.exp(-1j * ip)
382-
hlm_i[k] = {"A": iA, "p": ip, "h": ih, "real": ih.real, "imag": ih.imag}
382+
hlm_i[k] = {"A": iA, "p": ip, "z": ih, "real": ih.real, "imag": ih.imag}
383383

384384
return new_u, hlm_i
385385

docs/source/conf.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,7 @@
2828
autoapi_dirs = ['../../PyART']
2929
templates_path = ['_templates']
3030
exclude_patterns = []
31-
jupyter_execute_notebooks = "force" # or "auto" / "off"
31+
nb_execution_mode = "force" # or "auto" / "off"
3232

3333
# -- Options for HTML output -------------------------------------------------
3434
# https://www.sphinx-doc.org/en/master/usage/configuration.html#options-for-html-output

docs/source/index.md

Lines changed: 7 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,8 +31,12 @@ We promise to make available on PyPI in near future.
3131
```{toctree}
3232
:caption: 'Contents:'
3333
:maxdepth: 2
34-
:tutorials:
34+
3535
tutorials/intro_to_waveforms.ipynb
36+
tutorials/catalog_downloads.ipynb
3637
tutorials/phase_alignment.ipynb
37-
tutorials/mismatch.ipynb
38-
```
38+
tutorials/nr_eob_mismatch.ipynb
39+
tutorials/optimizing_initial_conditions.ipynb
40+
tutorials/iccub_waveform_integration.ipynb
41+
tutorials/scattering_angles.ipynb
42+
```
Lines changed: 259 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,259 @@
1+
{
2+
"cells": [
3+
{
4+
"cell_type": "markdown",
5+
"id": "a1b2c3d4",
6+
"metadata": {},
7+
"source": [
8+
"# Downloading Waveforms from Different Catalogs\n",
9+
"\n",
10+
"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:\n",
11+
"\n",
12+
"- **SXS** (Simulating eXtreme Spacetimes)\n",
13+
"- **RIT** (Rochester Institute of Technology)\n",
14+
"- **CoRe** (Computational Relativity)\n",
15+
"- **GRA** (GR-Athena++)\n",
16+
"- **ICCUB** (Institute of Cosmos Sciences)\n",
17+
"- **SACRA**\n",
18+
"\n",
19+
"## Setup\n",
20+
"\n",
21+
"First, let's import the necessary modules:"
22+
]
23+
},
24+
{
25+
"cell_type": "code",
26+
"execution_count": null,
27+
"id": "e5f6g7h8",
28+
"metadata": {},
29+
"outputs": [],
30+
"source": [
31+
"%matplotlib inline\n",
32+
"%config InlineBackend.figure_format = 'retina'\n",
33+
"\n",
34+
"from PyART.catalogs import sxs, rit, core, icc_public\n",
35+
"from PyART.catalogs.cataloger import Cataloger"
36+
]
37+
},
38+
{
39+
"cell_type": "markdown",
40+
"id": "i9j0k1l2",
41+
"metadata": {},
42+
"source": [
43+
"## Downloading from a Single Catalog\n",
44+
"\n",
45+
"Let's start by downloading waveforms from the SXS catalog. We specify:\n",
46+
"- The catalog name\n",
47+
"- The simulation ID\n",
48+
"- Whether to download if not locally available"
49+
]
50+
},
51+
{
52+
"cell_type": "markdown",
53+
"id": "67211c4a",
54+
"metadata": {},
55+
"source": [
56+
"### SXS"
57+
]
58+
},
59+
{
60+
"cell_type": "code",
61+
"execution_count": null,
62+
"id": "m3n4o5p6",
63+
"metadata": {},
64+
"outputs": [],
65+
"source": [
66+
"# Download and load an SXS waveform\n",
67+
"# Note: You may need to adjust the path or set download=True\n",
68+
"sxs_id = '0180'\n",
69+
"wf_sxs = sxs.Waveform_SXS(path='./', ID=sxs_id, download=True, cut_N=300, ignore_deprecation=True)\n",
70+
"\n",
71+
"print(f\"SXS Waveform {sxs_id} loaded successfully\")\n",
72+
"print(f\"Mass ratio q = {wf_sxs.metadata['q']:.3f}\")\n",
73+
"print(f\"Total mass M = {wf_sxs.metadata['M']:.3f}\")\n",
74+
"print(f\"Chi1z = {wf_sxs.metadata['chi1z']:.3f}\")\n",
75+
"print(f\"Chi2z = {wf_sxs.metadata['chi2z']:.3f}\")"
76+
]
77+
},
78+
{
79+
"cell_type": "markdown",
80+
"id": "3a8caa94",
81+
"metadata": {},
82+
"source": [
83+
"### RIT\n",
84+
"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."
85+
]
86+
},
87+
{
88+
"cell_type": "code",
89+
"execution_count": null,
90+
"id": "c9d0e1f2",
91+
"metadata": {},
92+
"outputs": [],
93+
"source": [
94+
"# Note: This requires having a RIT data path set up\n",
95+
"# or will download the data if download=True\n",
96+
"# For this example, we'll show the structure without executing\n",
97+
"\n",
98+
"rit_id = 1096\n",
99+
"wf_rit = rit.Waveform_RIT(path='./', ID=rit_id, \n",
100+
" download=True, nu_rescale=True)\n",
101+
"print(f\"RIT Waveform {rit_id} loaded\")\n",
102+
"print(f\"Mass ratio q = {wf_rit.metadata['q']:.3f}\")\n",
103+
"print(f\"Total mass M = {wf_rit.metadata['M']:.3f}\")\n",
104+
"print(f\"Chi1z = {wf_rit.metadata['chi1z']:.3f}\")\n",
105+
"print(f\"Chi2z = {wf_rit.metadata['chi2z']:.3f}\")"
106+
]
107+
},
108+
{
109+
"cell_type": "markdown",
110+
"id": "777cc4f0",
111+
"metadata": {},
112+
"source": [
113+
"### CoRe database\n",
114+
"\n",
115+
"CoRe database waveforms are downloaded from the gitlab public repository, using git-lfs.\n",
116+
"\n",
117+
"For the download of THC waveforms, modify the `code` argument accordingly."
118+
]
119+
},
120+
{
121+
"cell_type": "code",
122+
"execution_count": null,
123+
"id": "37473c05",
124+
"metadata": {},
125+
"outputs": [],
126+
"source": [
127+
"core_id = '0001'\n",
128+
"wf_core = core.Waveform_CoRe(path='./', ID=core_id, download=True, code='BAM')\n",
129+
"\n",
130+
"print(f\"CoRe Waveform {core_id} loaded\")\n",
131+
"print(f\"Mass ratio q = {wf_core.metadata['q']:.3f}\")\n",
132+
"print(f\"Total mass M = {wf_core.metadata['M']:.3f}\")\n",
133+
"print(f\"Chi1z = {wf_core.metadata['chi1z']:.3f}\")\n",
134+
"print(f\"Chi2z = {wf_core.metadata['chi2z']:.3f}\")"
135+
]
136+
},
137+
{
138+
"cell_type": "markdown",
139+
"id": "fd4e0b04",
140+
"metadata": {},
141+
"source": [
142+
"### ICCUB (public repository)"
143+
]
144+
},
145+
{
146+
"cell_type": "code",
147+
"execution_count": null,
148+
"id": "8374183a",
149+
"metadata": {},
150+
"outputs": [],
151+
"source": [
152+
"wf_icc = icc_public.Waveform_ICC(path='./', ID='0001', download=True, ellmax=4)\n",
153+
"\n",
154+
"print(f\"ICCUB Waveform 0001 loaded\")\n",
155+
"print(f\"Mass ratio q = {wf_icc.metadata['q']:.3f}\")\n",
156+
"print(f\"Total mass M = {wf_icc.metadata['M']:.3f}\")\n",
157+
"print(f\"Chi1z = {wf_icc.metadata['chi1z']:.3f}\")\n",
158+
"print(f\"Chi2z = {wf_icc.metadata['chi2z']:.3f}\")"
159+
]
160+
},
161+
{
162+
"cell_type": "markdown",
163+
"id": "ccbca6fe",
164+
"metadata": {},
165+
"source": [
166+
"### GR-Athena++\n",
167+
"\n",
168+
"TODO: implement and demonstrate"
169+
]
170+
},
171+
{
172+
"cell_type": "markdown",
173+
"id": "g3h4i5j6",
174+
"metadata": {},
175+
"source": [
176+
"## Using the Cataloger for Bulk Operations\n",
177+
"\n",
178+
"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.\n",
179+
"\n",
180+
"Here's an example structure:"
181+
]
182+
},
183+
{
184+
"cell_type": "code",
185+
"execution_count": null,
186+
"id": "k7l8m9n0",
187+
"metadata": {},
188+
"outputs": [],
189+
"source": [
190+
"# Example: Working with multiple RIT simulations\n",
191+
"sim_list = list(range(1096, 1100)) # List of simulation IDs\n",
192+
"\n",
193+
"cat = Cataloger(\n",
194+
" path='./local_data/rit/', \n",
195+
" catalog='rit', \n",
196+
" sim_list=sim_list,\n",
197+
" add_opts={'download': True, 'nu_rescale': True}\n",
198+
")\n",
199+
"\n",
200+
"# Plot all waveforms in the catalog\n",
201+
"cat.plot_waves()"
202+
]
203+
},
204+
{
205+
"cell_type": "markdown",
206+
"id": "o1p2q3r4",
207+
"metadata": {},
208+
"source": [
209+
"## Comparing Waveforms Between Catalogs\n",
210+
"\n",
211+
"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.\n",
212+
"\n",
213+
"For detailed mismatch calculations between catalogs, see the [Mode-by-mode Mismatch tutorial](mismatch.ipynb)."
214+
]
215+
},
216+
{
217+
"cell_type": "markdown",
218+
"id": "s5t6u7v8",
219+
"metadata": {},
220+
"source": [
221+
"## Summary\n",
222+
"\n",
223+
"This tutorial covered:\n",
224+
"- How to download waveforms from the SXS catalog\n",
225+
"- How to access waveform metadata\n",
226+
"- How to compute and plot waveform modes\n",
227+
"- The structure for working with other catalogs (RIT, CoRe, etc.)\n",
228+
"- Using the `Cataloger` class for bulk operations\n",
229+
"\n",
230+
"### Next Steps\n",
231+
"\n",
232+
"- Explore the [Intro to Waveforms](intro_to_waveforms.ipynb) tutorial for more details on waveform manipulation\n",
233+
"- Learn about [Phase Alignment](phase_alignment.ipynb) techniques\n",
234+
"- Calculate [Mode-by-mode Mismatches](mismatch.ipynb) between waveforms"
235+
]
236+
}
237+
],
238+
"metadata": {
239+
"kernelspec": {
240+
"display_name": "pyart-dev-3.11",
241+
"language": "python",
242+
"name": "python3"
243+
},
244+
"language_info": {
245+
"codemirror_mode": {
246+
"name": "ipython",
247+
"version": 3
248+
},
249+
"file_extension": ".py",
250+
"mimetype": "text/x-python",
251+
"name": "python",
252+
"nbconvert_exporter": "python",
253+
"pygments_lexer": "ipython3",
254+
"version": "3.11.11"
255+
}
256+
},
257+
"nbformat": 4,
258+
"nbformat_minor": 5
259+
}

0 commit comments

Comments
 (0)