|
1 | 1 | # PyAutoGalaxy — Agent Instructions |
2 | 2 |
|
3 | | -**PyAutoGalaxy** is a Bayesian galaxy morphology fitting library. It depends on `autoarray` (data structures) and `autofit` (model-fitting framework). |
| 3 | +Canonical, agent-agnostic instructions for this repo. `CLAUDE.md` imports this |
| 4 | +file; any tool that does not process `@`-imports should read this directly. |
4 | 5 |
|
5 | | -## Setup |
| 6 | +## What this repo is |
6 | 7 |
|
7 | | -```bash |
8 | | -pip install -e ".[dev]" |
9 | | -``` |
| 8 | +**PyAutoGalaxy** (package `autogalaxy`) is a Bayesian galaxy-morphology fitting |
| 9 | +library: light/mass profiles (incl. MGE/linear/operated), `Galaxy`/`Galaxies`, |
| 10 | +per-dataset `Fit*` and `Analysis*` classes (imaging, interferometer, ellipse), |
| 11 | +inversions for linear profiles/pixelizations, and adapt-image multi-stage |
| 12 | +fitting. |
| 13 | + |
| 14 | +Dependency direction: autogalaxy may import **autoarray** (data structures), |
| 15 | +**autofit** (model-fitting), and **autoconf** (config). It must **never** |
| 16 | +import `autolens` — lensing lives one layer up. |
10 | 17 |
|
11 | | -## Running Tests |
| 18 | +## Related repos |
| 19 | + |
| 20 | +- **Source siblings:** PyAutoConf, PyAutoArray, PyAutoFit (upstream); |
| 21 | + PyAutoLens (downstream — builds multi-plane lensing on autogalaxy). |
| 22 | +- **autogalaxy_workspace** — runnable tutorials/examples (`../autogalaxy_workspace`). |
| 23 | +- **autogalaxy_workspace_test** — integration + JAX/likelihood parity scripts. |
| 24 | +- **HowToGalaxy** — the lecture-style tutorial series (`../HowToGalaxy`). |
| 25 | +- **docs/** — Sphinx source; published to ReadTheDocs. |
| 26 | +- **Science context:** the lensing-focused knowledge wiki at |
| 27 | + `autolens_assistant/wiki/literature/` (concepts, entities, sources) covers |
| 28 | + source reconstruction, regularization, bulge/halo decomposition, kinematics, |
| 29 | + and multipoles useful to galaxy modelling. |
| 30 | + |
| 31 | +## Quick commands |
12 | 32 |
|
13 | 33 | ```bash |
14 | | -python -m pytest test_autogalaxy/ |
15 | | -python -m pytest test_autogalaxy/galaxy/test_galaxy.py |
16 | | -python -m pytest test_autogalaxy/galaxy/test_galaxy.py::TestGalaxy::test_name |
| 34 | +pip install -e ".[dev]" # install with dev/test extras |
| 35 | +python -m pytest test_autogalaxy/ # full test suite |
| 36 | +python -m pytest test_autogalaxy/galaxy/test_galaxy.py # one focused test (add -s for output) |
| 37 | +black autogalaxy/ # formatter (advisory — not gated) |
17 | 38 | ``` |
18 | 39 |
|
19 | | -### Sandboxed / Codex runs |
| 40 | +In a sandboxed / restricted environment, point numba and matplotlib at |
| 41 | +writable caches: |
20 | 42 |
|
21 | 43 | ```bash |
22 | 44 | NUMBA_CACHE_DIR=/tmp/numba_cache MPLCONFIGDIR=/tmp/matplotlib python -m pytest test_autogalaxy/ |
23 | 45 | ``` |
24 | 46 |
|
25 | | -## Key Architecture |
| 47 | +## CI / definition of green |
| 48 | + |
| 49 | +PRs must pass `pytest --cov` on the CI matrix (Python 3.12 **and** 3.13). There |
| 50 | +is no black/ruff/flake8 gate — formatting is advisory. (`requires-python` in |
| 51 | +`pyproject.toml` is `>=3.9`.) |
26 | 52 |
|
27 | | -- **Profiles**: `LightProfile` (`lp.*`), `MassProfile` (`mp.*`), `LightProfileLinear` (`lp_linear.*`) |
28 | | -- **Galaxy** (`galaxy/galaxy.py`): holds light/mass profiles, pixelizations |
29 | | -- **Fit classes**: `FitImaging`, `FitInterferometer`, `FitEllipse` |
30 | | -- **Analysis classes**: `AnalysisImaging`, `AnalysisInterferometer` — implement `log_likelihood_function` |
31 | | -- **Decorator system** (from autoarray): `@to_array`, `@to_grid`, `@to_vector_yx`, `@transform` |
32 | | -- **Operate mixins**: `OperateImage`, `OperateDeflections`, `LensCalc` |
| 53 | +## Configuration & defaults |
33 | 54 |
|
34 | | -## Key Rules |
| 55 | +autoconf supplies the packaged defaults under `autogalaxy/config/`. Workspaces |
| 56 | +override them via their own `config/` directory; the test suite pushes a local |
| 57 | +config dir via `conf.instance.push(...)` in `test_autogalaxy/conftest.py`. When |
| 58 | +a change adds a new config key, mirror it into the packaged defaults so |
| 59 | +downstream workspaces inherit it. |
35 | 60 |
|
36 | | -- The `xp` parameter controls NumPy vs JAX: `xp=np` (default) or `xp=jnp` |
37 | | -- Functions inside `jax.jit` must guard autoarray wrapping with `if xp is np:` |
38 | | -- Decorated functions return **raw arrays** — the decorator wraps them |
39 | | -- Use `grid.array[:, 0]` to access grid coordinates (not `grid[:, 0]`) |
40 | | -- All files must use Unix line endings (LF) |
41 | | -- Format with `black autogalaxy/` |
| 61 | +## JAX & `xp` |
42 | 62 |
|
43 | | -## Working on Issues |
| 63 | +NumPy is the default everywhere; JAX is opt-in and never imported at module |
| 64 | +level. `xp=np` (default) selects NumPy; `xp=jnp` selects JAX (imported locally). |
| 65 | +Thread `xp` through **every** nested call — a missed site silently defaults to |
| 66 | +`xp=np` and fails when a tracer hits an `np.*` op. Two patterns cross the |
| 67 | +`jax.jit` boundary: the `if xp is np:` **guard** for raw `jax.Array` returns |
| 68 | +(used by all `LensCalc` hessian methods in `operate/lens_calc.py`), and |
| 69 | +**pytree registration** for functions returning a real wrapper/structured |
| 70 | +object. |
| 71 | + |
| 72 | +**Unit tests are NumPy-only.** A JAX/`xp` change is validated only by the |
| 73 | +parity scripts in `autogalaxy_workspace_test` (`jax.jit` round-trip + |
| 74 | +`fitness._vmap` batch eval) — never by `test_autogalaxy/`. |
| 75 | + |
| 76 | +Full detail lives in PyAutoArray: |
| 77 | +**[`PyAutoArray/docs/agents/jax_and_decorators.md`](../PyAutoArray/docs/agents/jax_and_decorators.md)**. |
| 78 | + |
| 79 | +## Public API |
| 80 | + |
| 81 | +The public surface is defined authoritatively in `autogalaxy/__init__.py` — |
| 82 | +read it rather than trusting a hand-maintained namespace table. Canonical |
| 83 | +import: |
| 84 | + |
| 85 | +```python |
| 86 | +import autogalaxy as ag |
| 87 | +``` |
| 88 | + |
| 89 | +Profiles are namespaced there (`ag.lp.*`, `ag.lp_linear.*`, `ag.mp.*`, |
| 90 | +`ag.lmp.*`, …) alongside `ag.Galaxy`, `ag.FitImaging`, `ag.AnalysisImaging`. |
| 91 | + |
| 92 | +## Key rules / footguns |
| 93 | + |
| 94 | +- Import direction: autoarray / autofit / autoconf only — **never** `autolens`. |
| 95 | +- Operate mixins are `OperateImage` (`operate/image.py`) and `LensCalc` |
| 96 | + (`operate/lens_calc.py`). There is no `OperateDeflections` / `operate/ |
| 97 | + deflections.py`. |
| 98 | +- Grid-decorated profile methods return a **raw array** (the decorator wraps |
| 99 | + it); write `aa.decorators.*` and read coordinates via `grid.array[:, 0]`. |
| 100 | +- All files use Unix line endings (LF, `\n`) — never `\r\n`. |
| 101 | + |
| 102 | +## Working on issues |
44 | 103 |
|
45 | 104 | 1. Read the issue description and any linked plan. |
46 | | -2. Identify affected files and write your changes. |
47 | | -3. Run the full test suite: `python -m pytest test_autogalaxy/` |
48 | | -4. Ensure all tests pass before opening a PR. |
49 | | -5. If changing public API, note the change in your PR description — downstream packages (PyAutoLens) and workspaces may need updates. |
50 | | -## Never rewrite history |
51 | | - |
52 | | -NEVER perform these operations on any repo with a remote: |
53 | | - |
54 | | -- `git init` in a directory already tracked by git |
55 | | -- `rm -rf .git && git init` |
56 | | -- Commit with subject "Initial commit", "Fresh start", "Start fresh", "Reset |
57 | | - for AI workflow", or any equivalent message on a branch with a remote |
58 | | -- `git push --force` to `main` (or any branch tracked as `origin/HEAD`) |
59 | | -- `git filter-repo` / `git filter-branch` on shared branches |
60 | | -- `git rebase -i` rewriting commits already pushed to a shared branch |
61 | | - |
62 | | -If the working tree needs a clean state, the **only** correct sequence is: |
63 | | - |
64 | | - git fetch origin |
65 | | - git reset --hard origin/main |
66 | | - git clean -fd |
67 | | - |
68 | | -This applies equally to humans, local Claude Code, cloud Claude agents, Codex, |
69 | | -and any other agent. The "Initial commit — fresh start for AI workflow" pattern |
70 | | -that appeared independently on origin and local for three workspace repos is |
71 | | -exactly what this rule prevents — it costs ~40 commits of redundant local work |
72 | | -every time it happens. |
| 105 | +2. Identify affected files and make the change. |
| 106 | +3. Run the full suite: `python -m pytest test_autogalaxy/`. |
| 107 | +4. If you changed public API, say so explicitly — PyAutoLens and the workspaces |
| 108 | + may need updates. |
| 109 | +5. Ensure all tests pass before opening a PR. |
| 110 | + |
| 111 | +## Deep dives |
| 112 | + |
| 113 | +- [`PyAutoArray/docs/agents/jax_and_decorators.md`](../PyAutoArray/docs/agents/jax_and_decorators.md) |
| 114 | + — decorator system, `xp` backend pattern, and the `jax.jit` boundary. |
| 115 | + |
| 116 | +## Clean state |
| 117 | + |
| 118 | +Never rewrite history on a repo with a remote (no `git init` over a tracked |
| 119 | +tree, no force-push to `main`, no rebasing pushed shared branches). To reset a |
| 120 | +dirty tree the only correct sequence is: |
| 121 | + |
| 122 | +```bash |
| 123 | +git fetch origin |
| 124 | +git reset --hard origin/main |
| 125 | +git clean -fd |
| 126 | +``` |
0 commit comments