86 lines
3.4 KiB
Markdown
86 lines
3.4 KiB
Markdown
# yksa_orbital
|
|
|
|
Propagation for Django services: a backend registry, and the client to the
|
|
Orekit sidecar.
|
|
|
|
```python
|
|
from yksa_orbital import get_backend
|
|
|
|
state = get_backend().state_at(omm, at)
|
|
weather = get_backend("orekit").space_weather(start, stop)
|
|
```
|
|
|
|
## Why it is its own app
|
|
|
|
ODMS and `track.tmtc.yksa.space` both propagate, both against the same sidecar.
|
|
The alternative to sharing this is two HTTP clients that drift apart on timeouts,
|
|
on 503 handling, and on what they put in a request — and since the sidecar's
|
|
whole purpose is that two services fly the *same* model, two clients that send
|
|
different things quietly defeat it.
|
|
|
|
## Install
|
|
|
|
Add `"yksa_orbital"` to `INSTALLED_APPS` and set:
|
|
|
|
```
|
|
ORBITAL_PROPAGATOR_BACKEND=sgp4 # or "orekit"
|
|
OREKIT_SERVICE_URL=http://orekit:5000
|
|
```
|
|
|
|
It depends on `odm` and on `httpx`. Nothing else — in particular, nothing
|
|
from the host service.
|
|
|
|
## Backends
|
|
|
|
| Name | What it can do |
|
|
|---|---|
|
|
| `sgp4` | Pure Python. TEME plus a GMST Earth-fixed frame. Analytical theory only: **no drag integration**, so it refuses decay, drag fitting and space weather rather than returning a number nobody should trust. |
|
|
| `orekit` | HTTP client to the Orekit sidecar (`tle/services/orekit`). Rigorous frames, numerical and semi-analytical propagation, TLE fitting, drag fitting, decay forecasts, solar-activity ensembles, space weather. |
|
|
|
|
### Name the backend when you need the sidecar
|
|
|
|
`get_backend()` returns the deployment's default, which is `sgp4`. Anything
|
|
needing physics `sgp4` does not have must ask for `"orekit"` explicitly.
|
|
|
|
This is not hypothetical. A view that forgot to, and swallowed the resulting
|
|
`PropagationError`, rendered an empty space-weather chart for weeks with nothing
|
|
logging a complaint. If your call needs the sidecar, say so.
|
|
|
|
## Capacity
|
|
|
|
The sidecar keeps a worker free for the interactive queries a page load waits on,
|
|
and turns heavy work away rather than queueing it. A 503 arrives here as
|
|
`BackendBusy` — a subclass of `PropagationError`, so existing handlers still
|
|
work, but a Celery task should catch it **first** and retry. Nothing about the
|
|
request needs to change for it to succeed later; recording it as a failed
|
|
forecast is wrong.
|
|
|
|
## The model config
|
|
|
|
`yksa_orbital.model_config` reads the sidecar's `GET /config` — the force model,
|
|
propagator, decay altitude, drag-fit thresholds and weather sources it is
|
|
actually flying — with a cache and a vendored fallback.
|
|
|
|
Use it for values a page genuinely needs locally: the ensemble's display floor,
|
|
the decay altitude in a caption. Do **not** use it to build a request. Omitting a
|
|
parameter already gets the sidecar's value; echoing it back only adds a way for
|
|
the two to disagree.
|
|
|
|
```python
|
|
from yksa_orbital.model_config import model_config, setting
|
|
|
|
floor_km = setting("ensemble", "display_floor_km", 150.0)
|
|
```
|
|
|
|
`setting()` applies this deployment's `DECAY_*` override when there is one, so a
|
|
caption describes the run on screen rather than the model in general.
|
|
|
|
## Layout
|
|
|
|
| File | What |
|
|
|---|---|
|
|
| `registry.py` | `get_backend()`, and `register()` for a service with its own propagator. |
|
|
| `backends/sgp4.py` | The pure-Python backend. |
|
|
| `backends/orekit.py` | The sidecar HTTP client. |
|
|
| `wire.py` | Stored OMM dict → the CCSDS message the sidecar consumes. The only place that conversion happens. |
|
|
| `model_config.py` | Cached access to the sidecar's model definition. |
|