Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
18 commits
Select commit Hold shift + click to select a range
498b136
feat: Added sandbox libstempo interface
vhaasteren Oct 10, 2025
b3549a3
Fix linting issues in sandbox implementation
vhaasteren Oct 10, 2025
7f91592
Changed some comments
vhaasteren Oct 10, 2025
506f198
Fix pyproject.toml license format for PEP 621 compliance
vhaasteren Oct 10, 2025
456d83f
Fix pyproject.toml license to use file-based format
vhaasteren Oct 11, 2025
112c340
Fix linting issues: line length and unused imports
vhaasteren Oct 11, 2025
5d24e49
Trigger CI re-run
vhaasteren Oct 11, 2025
179e798
sandbox: stdio routing (FD1β†’FD2), stderr drain thread, logs(tail); te…
vhaasteren Oct 11, 2025
2aa631a
sandbox: stdio routing (FD1β†’FD2), stderr drain thread, logs(tail); te…
vhaasteren Oct 11, 2025
50304f5
sandbox: robust, backward-compatible process isolation for tempopulsar
vhaasteren Oct 12, 2025
9cac16d
Added output of stdout/stderr to screen in real time
vhaasteren Oct 12, 2025
e16b10d
removed: old legacy RPC path
vhaasteren Oct 12, 2025
c1e6755
fix: sandbox did not have state management. Now it restores state aft…
vhaasteren Oct 12, 2025
95a094f
fix: pickling error for unpickleable psr attributes, solved by adding…
vhaasteren Oct 13, 2025
268f0d1
fix: more robust b64 decoding by first checking for encode attribute
vhaasteren Oct 13, 2025
2841a4d
fix: RPC-JSON communication was polluted by warning when astropy is n…
vhaasteren Dec 2, 2025
5420809
Added array operations for _ArrayProxy
vhaasteren Mar 20, 2026
a9debb5
fix: sandbox code review β€” 3 bugs, structural cleanup, new tests
vhaasteren Apr 10, 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
2 changes: 2 additions & 0 deletions MANIFEST.in
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ include libstempo/multinest.py
include libstempo/plot.py
include libstempo/spharmORFbasis.py
include libstempo/toasim.py
include libstempo/sandbox.py
include libstempo/tim_file_analyzer.py
include libstempo/ecc_vs_nharm.txt
include demo/libstempo-demo.ipynb
include demo/libstempo-toasim-demo.ipynb
Expand Down
99 changes: 99 additions & 0 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -64,3 +64,102 @@ pip install libstempo
## Usage

See [Demo Notebook 1](https://github.com/vallis/libstempo/blob/master/demo/libstempo-demo.ipynb) for basic usage and [Demo Notebook 2](https://github.com/vallis/libstempo/blob/master/demo/libstempo-toasim-demo.ipynb) for simulation usage.

## Sandbox Mode (Crash-Protected)

libstempo includes a sandbox mode that provides crash isolation and automatic retry capabilities. This is particularly useful when working with problematic pulsars or long-running analyses where tempo2 crashes are common.

### Basic Usage

The sandbox provides a drop-in replacement for the standard `tempopulsar` class:

```python
from libstempo.sandbox import tempopulsar

# Basic usage - same API as regular tempopulsar
psr = tempopulsar(parfile="J1713.par", timfile="J1713.tim", dofit=False)
residuals = psr.residuals()
design_matrix = psr.designmatrix()
```

### Advanced Configuration

```python
from libstempo.sandbox import tempopulsar, Policy, configure_logging

# Configure logging for debugging
configure_logging(level="DEBUG", log_file="tempo2.log")

# Configure retry and timeout policies
policy = Policy(
ctor_retry=5, # Retry constructor 5 times on failure
call_timeout_s=300.0, # 5-minute timeout per RPC call
max_calls_per_worker=1000, # Recycle worker after 1000 calls
max_age_s=3600, # Recycle worker after 1 hour
rss_soft_limit_mb=2048 # Recycle worker if memory exceeds 2GB
)

psr = tempopulsar(parfile="J1713.par", timfile="J1713.tim", policy=policy)
```

### Environment Support

The sandbox supports different Python environments:

```python
# Use virtual/conda environment
psr = tempopulsar(parfile="J1713.par", timfile="J1713.tim", env_name="tempo2_intel")

# Use system Python with Rosetta (macOS)
psr = tempopulsar(parfile="J1713.par", timfile="J1713.tim", env_name="arch")

# Use explicit Python path
psr = tempopulsar(parfile="J1713.par", timfile="J1713.tim", env_name="python:/path/to/python")
```

### Key Benefits

- **Crash Isolation**: Segfaults in tempo2 only kill the worker process, not your main kernel
- **Automatic Retry**: Built-in retry logic for transient failures
- **Worker Recycling**: Prevents memory leaks and resource accumulation
- **Environment Flexibility**: Support for conda, venv, and Rosetta environments
- **Enhanced Logging**: Comprehensive logging for debugging and monitoring
- **Proactive TOA Handling**: Automatically handles large TOA files to prevent "Too many TOAs" errors

### Performance

The sandbox adds ~9x initialization overhead but only ~1.2x overhead for computational operations like `residuals()` and `designmatrix()`. For heavy computations, the overhead becomes negligible relative to the actual work. Use sandbox when stability is critical, direct libstempo when performance is paramount.

### Bulk Loading

For processing many pulsars:

```python
from libstempo.sandbox import load_many, Policy

pairs = [("J1713.par", "J1713.tim"), ("J1909.par", "J1909.tim"), ...]
policy = Policy(ctor_retry=3, call_timeout_s=120.0)

ok_by_name, retried_by_name, failed_list = load_many(pairs, policy=policy, parallel=8)

print(f"Successfully loaded: {len(ok_by_name)}")
print(f"Required retries: {len(retried_by_name)}")
print(f"Failed: {len(failed_list)}")
```

### Error Handling

The sandbox defines specific exception types:

```python
from libstempo.sandbox import Tempo2Error, Tempo2Crashed, Tempo2Timeout

try:
psr = tempopulsar(parfile="problematic.par", timfile="problematic.tim")
except Tempo2Crashed:
print("Worker process crashed - likely a segfault")
except Tempo2Timeout:
print("Worker timed out")
except Tempo2Error as e:
print(f"Sandbox error: {e}")
```
3 changes: 3 additions & 0 deletions libstempo/__init__.py
Original file line number Diff line number Diff line change
@@ -1,6 +1,9 @@
import os
from ._find_tempo2 import find_tempo2_runtime

# Import sandbox functionality
from .sandbox import tempopulsar as sandbox_tempopulsar, Policy, configure_logging # noqa: F401
from .tim_file_analyzer import TimFileAnalyzer # noqa: F401

# check to see if TEMPO2 environment variable is set
TEMPO2_RUNTIME = os.getenv("TEMPO2")
Expand Down
Loading
Loading