Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
17 changes: 14 additions & 3 deletions .github/workflows/ci.yml
Original file line number Diff line number Diff line change
Expand Up @@ -15,9 +15,9 @@ jobs:
with:
python-version: "3.11"
- run: pip install flake8 black mypy
- run: flake8 engine/
- run: black --check engine/
- run: mypy engine/ --ignore-missing-imports || true
- run: flake8 astrosis/
- run: black --check astrosis/
- run: mypy astrosis/ --ignore-missing-imports || true

test:
runs-on: ubuntu-latest
Expand All @@ -41,3 +41,14 @@ jobs:
run: echo "pybind11_DIR=$(python -c 'import pybind11; print(pybind11.get_cmake_dir())')" >> $GITHUB_ENV
- run: cmake -S cpp -B cpp/build -DUSE_CUDA=OFF -Dpybind11_DIR=${{ env.pybind11_DIR }}
- run: cmake --build cpp/build -- -j$(nproc)

build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install build twine
- run: python -m build
- run: python -m twine check dist/*
19 changes: 19 additions & 0 deletions .github/workflows/publish.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
name: Publish to PyPI

on:
push:
tags:
- 'v*'

jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: '3.11'
- run: python -m pip install --upgrade pip
- run: pip install build twine
- run: python -m build
- run: python -m twine upload dist/* -u __token__ -p ${{ secrets.PYPI_API_TOKEN }}
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@ __pycache__/
.pytest_cache/
*.egg-info/

dist/

# Environment
.env
.env.local
Expand Down
4 changes: 2 additions & 2 deletions .pre-commit-config.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -5,14 +5,14 @@ repos:
- id: black
language_version: python3
args: [--check]
files: ^(engine/|tests/).*\.py$
files: ^(astrosis/|tests/).*\.py$

- repo: https://github.com/astral-sh/ruff-pre-commit
rev: v0.9.0
hooks:
- id: ruff
args: [--fix]
files: ^engine/|^tests/
files: ^astrosis/|^tests/

- repo: https://github.com/pre-commit/mirrors-clang-format
rev: v19.1.0
Expand Down
24 changes: 12 additions & 12 deletions AGENTS.md
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
CLI + TUI orbital mechanics calculator. No frontend, no server.

## Structure
- `engine/` — Python engine (entrypoints: `main.py`, `python -m engine`, or `astrosis` after `pip install -e .`)
- `astrosis/` — Python implementation (entrypoints: `main.py`, `python -m astrosis`, or `astrosis` after `pip install -e .`)
- `cpp/` — C++/CUDA backends (pybind11 module `physics_engine`, built via CMake)
- `tests/` — `test_correctness.py` (17 tests)
- `validation/` — Physics validation plots (run from repo root — scripts use `sys.path.insert(0, ...)`)
Expand All @@ -16,12 +16,12 @@ CLI + TUI orbital mechanics calculator. No frontend, no server.
| Install deps | `pip install -r requirements.txt` |
| Install pybind11 | `pip install pybind11` (needed for C++ build) |
| Build C++/CUDA | `./build-backends.sh` (auto-detects CUDA) |
| Run CLI | `astrosis <command>` or `python -m engine <command>` or `python main.py <command>` |
| Run CLI | `astrosis <command>` or `python -m astrosis` or `python main.py <command>` |
| Run TUI | `astrosis` (no args) |
| Tests | `pytest tests/test_correctness.py -v` (17 tests) |
| Lint | `flake8 engine/` |
| Format check | `black --check engine/` |
| Typecheck | `mypy engine/ --ignore-missing-imports \|\| true` (CI passes with `\|\| true`) |
| Lint | `flake8 astrosis/` |
| Format check | `black --check astrosis/` |
| Typecheck | `mypy astrosis/ --ignore-missing-imports \|\| true` (CI passes with `\|\| true`) |
| Validation | `python validation/validate_physics.py` (outputs PNGs to `validation/plots/`) |
| SGP4 comparison | `python validation/sgp4_vs_rk4.py` |
| TLE refresh | `./scripts/refresh-tle-cache.sh` |
Expand All @@ -34,10 +34,10 @@ CI order (`.github/workflows/ci.yml`): `flake8` → `black --check` → `mypy \|
- State: 6-element list `[x, y, z, vx, vy, vz]`, ECI frame, km and km/s
- FP64 everywhere — FP32 insufficient for 24 h integration
- Fixed-step RK4 only (no adaptive stepping; GPU warp uniformity constraint)
- Constants single-source in `engine/constants.py`
- `julian_date`, `equation_of_equinoxes`, `teme_to_eci` in `engine/geo/frames.py` — do NOT reimplement
- `Severity` (StrEnum) in `engine/core/conjunction.py` — use enum, not string literals
- Auto-backend: `engine/core/accelerator.py` picks CUDA → C++/OpenMP → NumPy → Python fallback
- Constants single-source in `astrosis/constants.py`
- `julian_date`, `equation_of_equinoxes`, `teme_to_eci` in `astrosis/geo/frames.py` — do NOT reimplement
- `Severity` (StrEnum) in `astrosis/core/conjunction.py` — use enum, not string literals
- Auto-backend: `astrosis/core/accelerator.py` picks CUDA → C++/OpenMP → NumPy → Python fallback
- Mock GPU: `ASTROSIS_MOCK_GPU=1` or `python main.py --mock-gpu`

## C++/CUDA specifics
Expand All @@ -48,8 +48,8 @@ CI order (`.github/workflows/ci.yml`): `flake8` → `black --check` → `mypy \|
- Brent minimiser: `brent_minimise<F>` in `conjunction.cpp` — templated, no `std::function`
- CUDA conjunction: 2-phase `k_prepropagate` (SoA per timestep) + `k_scan_pairs` (coalesced reads)
- C++ conjunction: pre-propagates all objects via `batch_propagate_full_history`, then pairwise distance scan + Brent refinement from nearest pre-propagated frame
- `monte_carlo_pc()` in `engine/core/accelerator.py` — CUDA → Python fallback
- `engine/__main__.py` enables `python -m engine`
- `monte_carlo_pc()` in `astrosis/core/accelerator.py` — CUDA → Python fallback
- `astrosis/__main__.py` enables `python -m astrosis`

## TUI gotchas (Textual 8.x)
- **Do NOT name an attribute `_current_mode`** — Textual's `App` uses this internally for its MODES dict. Use `_active_tab` or similar.
Expand All @@ -64,7 +64,7 @@ CI order (`.github/workflows/ci.yml`): `flake8` → `black --check` → `mypy \|
- **Bug to avoid:** The CSV loader always consumes the first row. For 6-col files, it tries to parse it as data (numeric); if that fails, it treats it as a header. For 7-col files, the first row is always treated as a header.

## Pre-commit hooks
black (engine/ + tests/), ruff (engine/ + tests/), clang-format (cpp/), trailing-whitespace, end-of-file-fixer, check-yaml, check-json.
black (astrosis/ + tests/), ruff (astrosis/ + tests/), clang-format (cpp/), trailing-whitespace, end-of-file-fixer, check-yaml, check-json.

## TLE cache
- Location: `~/.cache/astrosis/tle/`
Expand Down
8 changes: 3 additions & 5 deletions MANIFEST.in
Original file line number Diff line number Diff line change
@@ -1,7 +1,5 @@
include README.md
include LICENSE
include requirements.txt
recursive-include engine *.py
recursive-include engine *.pyi
recursive-include data *
recursive-include assets *
recursive-include astrosis *.py
recursive-include astrosis *.pyi
recursive-include astrosis/data *.txt
140 changes: 140 additions & 0 deletions PUBLISH.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
# Publishing Astrosis to PyPI

## Current Status

✅ **Release Branch** (`release`): Production-ready, fully refactored
- ✅ All 17 tests pass
- ✅ Package builds (sdist + wheel)
- ✅ `twine check` passes
- ✅ Clean imports: `astrosis` (no `engine` references)
- ✅ Entry point: `astrosis = "astrosis.cli:main"`
- ✅ README updated with `astrosis` examples
- ✅ CI workflow: lint, test, C++ build, package check

📌 **Main Branch** (`main`): Development
- Current state with development tools
- Can be merged with release changes or kept separate

## Quick Start: Publish to PyPI

### 1. Create PyPI Account & API Token
- Go to https://pypi.org/account/register/
- Create account and verify email
- Go to Account Settings → API tokens → Add API token
- Generate a token with "Entire account" scope
- **Save token securely** (you'll only see it once)

### 2. Set GitHub Secrets (for CI publish)
```bash
# In your GitHub repo: Settings → Secrets and variables → Actions
# Add two secrets:
PYPI_API_TOKEN = pypi-<your-token>
PYPI_USERNAME = __token__
```

### 3. Create Release Workflow (CI/CD Auto-Publish)
Copy this to `.github/workflows/publish.yml`:
```yaml
name: Publish to PyPI

on:
push:
tags:
- 'v*'

jobs:
publish:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-python@v5
with:
python-version: "3.11"
- run: pip install build twine
- run: python -m build
- run: >
python -m twine upload dist/*
-u __token__
-p ${{ secrets.PYPI_API_TOKEN }}
```

### 4. Bump Version (on release branch)
```bash
# On release branch
git checkout release
# Edit pyproject.toml: version = "0.1.1"
git add pyproject.toml
git commit -m "Bump version to 0.1.1"
git tag -a v0.1.1 -m "Release v0.1.1"
git push origin release --tags
```

This triggers the publish workflow automatically. Or manually:

```bash
# Manual publish
git checkout release
python -m build
python -m twine upload dist/* \
-u __token__ \
-p pypi-<your-token>
```

### 5. Verify on PyPI
After publish, visit: https://pypi.org/project/astrosis/

Install and test:
```bash
pip install astrosis
python -c "import astrosis; print(astrosis.__version__)"
```

## Branch Strategy

| Branch | Purpose | Merge Into PyPI |
|--------|---------|-----------------|
| `main` | Development, experiments | ❌ No |
| `release` | Production-ready, clean | ✅ Yes |

## Pre-Publish Checklist

- [ ] Confirm package name `astrosis` is available (not taken by someone else)
- [ ] Bump version in `pyproject.toml` (don't reuse old versions)
- [ ] Run tests: `pytest tests/ -v`
- [ ] Build: `python -m build`
- [ ] Validate: `python -m twine check dist/*`
- [ ] (Optional) Test on TestPyPI first:
```bash
python -m twine upload --repository testpypi dist/* \
-u __token__ -p pypi-<test-token>
```
Then: `pip install -i https://test.pypi.org/simple/ astrosis==0.1.1`

## Important Notes

- **Native backends** (C++/CUDA) are optional. Users can install and use the pure-Python fallback. Prebuilt wheels are not included in this release.
- **Dependencies**: Ensure all required packages (`numpy`, `scipy`, `sgp4`, `rich`, `textual`) are pinned to tested versions.
- **License**: Package uses MIT license (see `LICENSE` file).
- **GitHub**: Point users to https://github.com/UtkarshJoshiNtl/Astrosis for source, issues, docs.

## What Happens When Users Install

```bash
pip install astrosis
```

- Downloads `astrosis-0.1.0-py3-none-any.whl` (or `.tar.gz`)
- Installs `astrosis` package
- Sets up CLI entry point: `astrosis` command available
- Users can `import astrosis` or run `astrosis --help`

## Post-Publish

- [ ] Create GitHub Release: https://github.com/UtkarshJoshiNtl/Astrosis/releases
- [ ] Link PyPI URL and version
- [ ] Add release notes (changelog)
- [ ] Update README badge: [![PyPI - Version](https://img.shields.io/pypi/v/astrosis)](https://pypi.org/project/astrosis/)

---

**Questions?** Refer to [pypa.io](https://packaging.python.org/tutorials/packaging-projects/) or [twine docs](https://twine.readthedocs.io/).
16 changes: 8 additions & 8 deletions README.md
Original file line number Diff line number Diff line change
Expand Up @@ -63,27 +63,27 @@ astrosis info --id 25544
Use Astrosis as a library in your own scripts:

```python
import engine
import astrosis

# Propagate a single satellite 24 hours forward
state = engine.propagate(
state = astrosis.propagate(
[6678, 0, 0, 0, 7.7, 0], # ECI: x, y, z, vx, vy, vz (km, km/s)
dt_seconds=86400
)
print(f"After 24 h: {state}")

# Batch propagate 1,000 satellites — auto-picks fastest backend
states = engine.propagate_batch(
states = astrosis.propagate_batch(
initial_states, dt_seconds=60, steps=1440
)

# Conjunction screening
warnings = engine.detect_conjunctions(
warnings = astrosis.detect_conjunctions(
satellites, debris, lookahead=86400, step_s=60
)

# Check which backend is active
print(engine.backend_info())
print(astrosis.backend_info())
```

## Features
Expand All @@ -105,8 +105,8 @@ graph TB
subgraph UI["User Interface"]
direction LR
CLI["main.py / CLI"]
TUI["engine/tui.py<br/>Textual 8.x"]
API["engine.*<br/>Python API"]
TUI["astrosis/tui.py<br/>Textual 8.x"]
API["astrosis.*<br/>Python API"]
end

subgraph CORE["Physics Core"]
Expand Down Expand Up @@ -143,7 +143,7 @@ graph TB
CITIES --> PASS
```

The router in `engine/core/accelerator.py` probes `cuda_available()`, C++ module
The router in `astrosis/core/accelerator.py` probes `cuda_available()`, C++ module
presence, and falls back through the layers — all transparent to the caller.

## Performance
Expand Down
19 changes: 19 additions & 0 deletions RELEASE_CHECKLIST.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
Release checklist for publishing Astrosis

- [ ] Confirm `pyproject.toml` `name` is the intended PyPI project (astrosis)
- [ ] Bump `version` in `pyproject.toml` (do not reuse published versions)
- [ ] Run test suite: `pytest -q`
- [ ] Build sdist and wheel: `python -m build`
- [ ] Run `python -m twine check dist/*`
- [ ] Upload to TestPyPI and validate installation there
- [ ] Create Git tag and GitHub release notes
- [ ] Publish to PyPI using a PyPI API token stored in GitHub Secrets
- [ ] Verify README renders on PyPI and GitHub
- [ ] Confirm C++/CUDA backend docs explain optional native build steps

Notes:
- This repository contains native backends under `cpp/`. For user-friendly
prebuilt wheels consider adding `cibuildwheel` to CI and producing manylinux
wheels for Linux (and platform-specific CUDA wheels if desired).
- The package exposes functionality via `astrosis` (the main implementation) and is published as
`astrosis` on PyPI.
Loading
Loading