Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
21a1e80
update workflow [reset cache]
AnujKankani Feb 20, 2026
844f891
[reset cache]
AnujKankani Feb 20, 2026
befc260
reduce tolerance
AnujKankani Mar 25, 2026
eb15bbb
reduce tolerance for optimized Omega_0 mismatch
AnujKankani Mar 25, 2026
eb03e97
lower tolerance for Omega_0 as well
AnujKankani Mar 25, 2026
9b6fce1
fix mismatch testing
AnujKankani Mar 25, 2026
16f21f0
fix file prefix
AnujKankani Mar 25, 2026
cb76112
fix offline testing
AnujKankani Mar 25, 2026
2f019de
update env variables in testing
AnujKankani Mar 25, 2026
f79549d
test file prefix
AnujKankani Mar 25, 2026
a3cbc68
reduce tolerance for tests
AnujKankani Mar 25, 2026
1d23450
Call qnm lazy init at start of creation setter (#16)
AnujKankani Mar 25, 2026
c885813
Replace debug print statements with logging in BOB_utils and gen_utils
AnujKankani Mar 25, 2026
1ea0ec2
logging implemented
AnujKankani Mar 26, 2026
5903397
Merge branch 'dev' into dev_split
AnujKankani Apr 25, 2026
3f96ca4
change class design into multiple parts
AnujKankani Apr 25, 2026
d85f7fc
move construct_BOB for finite t0
AnujKankani Apr 25, 2026
bf6a7a7
minf_t0 construction moved
AnujKankani Apr 25, 2026
dc7ebef
attribute refactor
AnujKankani Apr 25, 2026
f1b97ad
inline documentation updated
AnujKankani Apr 25, 2026
643d952
test refactoring [skip ci]
AnujKankani Apr 27, 2026
7b30839
unit tests added
AnujKankani Apr 27, 2026
0ff84a6
unit tests added
AnujKankani Apr 27, 2026
647d7d8
test python 3.11 and 3.12
AnujKankani Apr 27, 2026
1d6e58c
macOS added to testing
AnujKankani Apr 27, 2026
d5255df
reduce tolerance
AnujKankani Apr 27, 2026
0e83b69
download test data instead of storing
AnujKankani Apr 27, 2026
3db4816
fetch data bug fixed
AnujKankani Apr 27, 2026
d7c2a4b
cleanup
AnujKankani Apr 27, 2026
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
214 changes: 204 additions & 10 deletions .github/workflows/pytest.yml
Original file line number Diff line number Diff line change
Expand Up @@ -2,15 +2,44 @@ name: Python package

on: [push, pull_request]

# T6.3 of test refactor: jobs split into three for fast feedback.
#
# - unit (Python 3.10 / 3.11 / 3.12, ~10s each)
# Fast, deterministic, no NR data required. Required to pass on all
# three Python versions to merge.
#
# - integration (Python 3.10 only, ~1m30s)
# SXS / CCE end-to-end workflow tests. Required to pass.
# Runs only after `unit` succeeds on all matrix entries.
#
# - regression-baselines (Python 3.10 only, ~16s, opt-in)
# Byte-for-byte fingerprints from the Stage 2 / Stage 3 refactors.
# Memory-heavy; opt-in via `-m regression_baseline`.
# Runs only after `unit` succeeds.
#
# Both `integration` and `regression-baselines` require `unit` to pass first,
# so a Python-version regression in unit tests fails fast without burning
# CI minutes on the slow suites.

jobs:
build:
# =========================================================================
# 1. Fast unit tests across the Python × OS matrix
# =========================================================================
unit:
name: unit (${{ matrix.os }}, Python ${{ matrix.python-version }})
if: |
github.event_name != 'push' ||
!contains(github.event.head_commit.message, '[skip ci]')
runs-on: ubuntu-latest
runs-on: ${{ matrix.os }}
# All combinations are required to pass — failure on any blocks merges.
# T6.6 added macOS as mandatory (no continue-on-error). ``fail-fast: false``
# means each entry's failures are reported independently rather than
# aborting on the first.
strategy:
fail-fast: false
matrix:
python-version: ["3.10"]
os: [ubuntu-latest, macos-latest]
python-version: ["3.10", "3.11", "3.12"]

steps:
- uses: actions/checkout@v3
Expand All @@ -19,6 +48,76 @@ jobs:
with:
python-version: ${{ matrix.python-version }}

- name: Install system dependencies (Linux)
if: runner.os == 'Linux'
run: |
sudo apt-get update
sudo apt-get install -y libfftw3-dev

- name: Install system dependencies (macOS)
if: runner.os == 'macOS'
run: |
brew update
brew install fftw

- name: Get pip cache directory
id: pip-cache
run: echo "dir=$(pip cache dir)" >> "$GITHUB_OUTPUT"

- name: Cache pip
uses: actions/cache@v3
with:
path: ${{ steps.pip-cache.outputs.dir }}
# Cache key includes OS + Python version so each matrix entry has
# its own pip cache (wheels are per-OS-per-Python).
# If commit message contains [reset cache], the key changes → fresh cache.
key: ${{ runner.os }}-pip-py${{ matrix.python-version }}-${{ hashFiles('**/pyproject.toml') }}-${{ contains(github.event.head_commit.message, '[reset cache]') }}
restore-keys: |
${{ runner.os }}-pip-py${{ matrix.python-version }}-
${{ runner.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[tests]"

# Claude Code: See CLAUDE.md / MEMORY.md / code_review §5 for context.
- name: Verify editable install (no site-packages shadowing)
run: |
python <<'PY'
import sys
import gwBOB
loc = gwBOB.__file__
if "site-packages" in loc:
print("ERROR: gwBOB was loaded from site-packages, not the local source.", file=sys.stderr)
print(f" gwBOB.__file__ = {loc}", file=sys.stderr)
print(" This is the 'stale install shadowing local source' trap that", file=sys.stderr)
print(" silently caused a WSL OOM event on 2026-04-25.", file=sys.stderr)
print(" Fix: run `pip install -e .` from BackwardsOneBody/.", file=sys.stderr)
sys.exit(1)
print(f"OK: gwBOB loaded from local source: {loc}")
PY

- name: Run unit tests
run: pytest tests/unit/ -v

# =========================================================================
# 2. Slow integration tests on canonical Python (3.10) only
# =========================================================================
integration:
name: integration (Python 3.10)
if: |
github.event_name != 'push' ||
!contains(github.event.head_commit.message, '[skip ci]')
runs-on: ubuntu-latest
needs: unit # only run if all unit-test matrix entries pass

steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"

- name: Install system dependencies
run: |
sudo apt-get update
Expand All @@ -27,21 +126,116 @@ jobs:
uses: actions/cache@v3
with:
path: ~/.cache/pip
# By default, cache key is based on pyproject.toml hash.
# If commit message contains [reset cache], the key changes → fresh cache
key: ${{ runner.os }}-pip-${{ hashFiles('**/pyproject.toml') }}-${{ contains(github.event.head_commit.message, '[reset cache]') }}
key: ${{ runner.os }}-pip-py3.10-${{ hashFiles('**/pyproject.toml') }}-${{ contains(github.event.head_commit.message, '[reset cache]') }}
restore-keys: |
${{ runner.os }}-pip-py3.10-
${{ runner.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[tests]"

- name: Test with pytest
- name: Verify editable install (no site-packages shadowing)
run: |
python <<'PY'
import sys
import gwBOB
loc = gwBOB.__file__
if "site-packages" in loc:
print("ERROR: gwBOB was loaded from site-packages, not the local source.", file=sys.stderr)
print(f" gwBOB.__file__ = {loc}", file=sys.stderr)
sys.exit(1)
print(f"OK: gwBOB loaded from local source: {loc}")
PY

# The ~90 MB of SXS + Zenodo waveform data isn't committed to the repo;
# fetch_data.py downloads it. Cache it across runs (key on the script
# so cache busts when fetch logic changes) to keep CI fast.
- name: Cache SXS / CCE test data
id: cache-test-data
uses: actions/cache@v3
with:
path: tests/sxs_cache
key: ${{ runner.os }}-test-data-${{ hashFiles('tests/fetch_data.py') }}

- name: Fetch test data
if: steps.cache-test-data.outputs.cache-hit != 'true'
run: python tests/fetch_data.py

# Default `pytest tests/integration/` excludes the regression-baseline
# marker via ``addopts`` in pyproject.toml, so this job runs the
# workflow regressions but NOT the byte-for-byte fingerprints.
- name: Run integration tests
env:
SXSCACHEDIR: ${{ github.workspace }}/tests/sxs_cache
SXSCONFIGDIR: ${{ github.workspace }}/tests/sxs_cache
run: pytest tests/integration/ -v

# =========================================================================
# 3. Byte-for-byte regression baselines (opt-in via marker)
# =========================================================================
regression-baselines:
name: regression-baselines (Python 3.10)
if: |
github.event_name != 'push' ||
!contains(github.event.head_commit.message, '[skip ci]')
runs-on: ubuntu-latest
needs: unit

steps:
- uses: actions/checkout@v3
- name: Set up Python 3.10
uses: actions/setup-python@v3
with:
python-version: "3.10"

- name: Install system dependencies
run: |
sudo apt-get update
sudo apt-get install -y libfftw3-dev
- name: Cache pip
uses: actions/cache@v3
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-py3.10-${{ hashFiles('**/pyproject.toml') }}-${{ contains(github.event.head_commit.message, '[reset cache]') }}
restore-keys: |
${{ runner.os }}-pip-py3.10-
${{ runner.os }}-pip-
- name: Install dependencies
run: |
python -m pip install --upgrade pip
pip install -e ".[tests]"

- name: Verify editable install (no site-packages shadowing)
run: |
pytest tests/


python <<'PY'
import sys
import gwBOB
loc = gwBOB.__file__
if "site-packages" in loc:
print("ERROR: gwBOB was loaded from site-packages, not the local source.", file=sys.stderr)
print(f" gwBOB.__file__ = {loc}", file=sys.stderr)
sys.exit(1)
print(f"OK: gwBOB loaded from local source: {loc}")
PY

# Same cache + fetch pattern as the integration job; both pull the
# same key, so a cache populated by either job is reusable by the other.
- name: Cache SXS / CCE test data
id: cache-test-data
uses: actions/cache@v3
with:
path: tests/sxs_cache
key: ${{ runner.os }}-test-data-${{ hashFiles('tests/fetch_data.py') }}

- name: Fetch test data
if: steps.cache-test-data.outputs.cache-hit != 'true'
run: python tests/fetch_data.py

# Opt-in via ``-m regression_baseline`` overrides the ``addopts`` filter
# in pyproject.toml that excludes them by default.
- name: Run regression baselines
env:
SXSCACHEDIR: ${{ github.workspace }}/tests/sxs_cache
SXSCONFIGDIR: ${{ github.workspace }}/tests/sxs_cache
run: pytest tests/integration/test_regression_baselines.py -m regression_baseline -v
24 changes: 24 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -4,3 +4,27 @@ docs/build/
build/
gwBOB.egg-info/

# Ignore design notes, agent scratch, and ad-hoc markdown files.
# README.md and joss/paper.md remain tracked.
*.md
!README.md
!joss/paper.md

# Local scratch files
code_review
test_stuff.py

# Local utility scripts (memory profiling, ad-hoc benchmarks, etc.)
scripts/

# Pytest / coverage artifacts
.pytest_cache/
.coverage
tests/coverage_html/

# Test data fetched on-demand by tests/fetch_data.py (~90 MB).
# The SXS catalog data and the Zenodo CCE waveforms are not ours to
# redistribute, and committing them bloats fresh clones. Run
# python tests/fetch_data.py
# once after cloning to populate this directory. Unit tests don't need it.
tests/sxs_cache/
25 changes: 23 additions & 2 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -70,6 +70,24 @@ pip install gwBOB
```


## Running the Tests

If you've cloned the repo and want to run the test suite:

```bash
cd BackwardsOneBody/
pip install -e ".[tests]"

# Unit tests are fast and need no external data:
pytest tests/unit/

# Integration tests need ~90 MB of waveform data from the SXS catalog and
# the Zenodo CCE record. Fetch it once:
python tests/fetch_data.py
pytest tests/
```


## Citing this Code

If you use this code please cite
Expand Down Expand Up @@ -98,9 +116,12 @@ If you use this code please cite
}
```

BOB paper to be added.
JOSS paper to be added. If you have any issues with this code, want any new features, or use this code for your own research, please let me know!


## AI Usage

JOSS paper to be added.
While the original code was written largely manually, this code is now mostly developed through the use of Claude Code. AI usage follows the JOSS policy on AI usage. All design decisions are made by humans. All LLM generated code is verified manually by humans. Throughout the code you will likely see comments starting with "Claude Code:" that refer to specific MD files. These files are not part of the git but Anuj will share them on request.

## Contributing

Expand Down
Loading
Loading