limTOD 1.3.0__tar.gz
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- limtod-1.3.0/CHANGELOG.md +215 -0
- limtod-1.3.0/LICENSE +21 -0
- limtod-1.3.0/MANIFEST.in +7 -0
- limtod-1.3.0/PKG-INFO +201 -0
- limtod-1.3.0/README.md +135 -0
- limtod-1.3.0/docs/README.md +12 -0
- limtod-1.3.0/docs/api-reference.md +126 -0
- limtod-1.3.0/docs/limtod-jax.md +140 -0
- limtod-1.3.0/docs/mapmaking.md +93 -0
- limtod-1.3.0/docs/theory.md +89 -0
- limtod-1.3.0/docs/tod-simulation.md +143 -0
- limtod-1.3.0/limTOD/HPW_filter.py +785 -0
- limtod-1.3.0/limTOD/__init__.py +60 -0
- limtod-1.3.0/limTOD/flicker_model.py +75 -0
- limtod-1.3.0/limTOD/mpiutil.py +281 -0
- limtod-1.3.0/limTOD/simulator.py +1204 -0
- limtod-1.3.0/limTOD/sky_model.py +153 -0
- limtod-1.3.0/limTOD/visual.py +101 -0
- limtod-1.3.0/limTOD.egg-info/PKG-INFO +201 -0
- limtod-1.3.0/limTOD.egg-info/SOURCES.txt +30 -0
- limtod-1.3.0/limTOD.egg-info/dependency_links.txt +1 -0
- limtod-1.3.0/limTOD.egg-info/requires.txt +44 -0
- limtod-1.3.0/limTOD.egg-info/top_level.txt +2 -0
- limtod-1.3.0/limtod_jax/__init__.py +78 -0
- limtod-1.3.0/limtod_jax/alm.py +122 -0
- limtod-1.3.0/limtod_jax/angles.py +123 -0
- limtod-1.3.0/limtod_jax/core.py +198 -0
- limtod-1.3.0/limtod_jax/hpx.py +63 -0
- limtod-1.3.0/limtod_jax/projection.py +78 -0
- limtod-1.3.0/limtod_jax/wigner.py +111 -0
- limtod-1.3.0/pyproject.toml +111 -0
- limtod-1.3.0/setup.cfg +4 -0
|
@@ -0,0 +1,215 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to this project will be documented in this file.
|
|
4
|
+
|
|
5
|
+
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
|
|
6
|
+
and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
|
|
7
|
+
|
|
8
|
+
## [Unreleased]
|
|
9
|
+
|
|
10
|
+
## [1.3.0] - 2026-07-25
|
|
11
|
+
|
|
12
|
+
### Added
|
|
13
|
+
|
|
14
|
+
- 🚀 **`limtod_jax` package**: pure-JAX, differentiable port of the sky→TOD
|
|
15
|
+
chain (pointing → ZYZ Euler angles → Wigner rotation of beam alms →
|
|
16
|
+
beam-weighted harmonic dot), implementing the e-RHINO
|
|
17
|
+
`docs/limtod-port-contract.md`. Ships `zyz_of_pointing`, `rotate_alm`,
|
|
18
|
+
`beam_weighted_sum`, `generate_tod_sky` (+ exact adjoint),
|
|
19
|
+
`generate_projection_rows`, and JAX-side HEALPix map↔alm wrappers.
|
|
20
|
+
Matches `limTOD.simulator.generate_TOD_sky(..., truncate_frac_thres=0.0)`
|
|
21
|
+
to ~1e-12 relative in float64 (oracle-tested at extreme pointing corners);
|
|
22
|
+
jit/vmap/grad-safe. Install with `pip install -e ".[jax]"` (Python ≥ 3.11).
|
|
23
|
+
- 📦 **Dependency extras**: `[mpi]` (mpi4py), `[gdsm]` (pygdsm), `[jax]`
|
|
24
|
+
(jax + s2fft), and `[full]` (all of the above).
|
|
25
|
+
- 🛡️ **MPI launcher guard**: importing limTOD under `mpirun`/`srun`
|
|
26
|
+
*without* mpi4py now raises a clear `RuntimeError` instead of silently
|
|
27
|
+
running N duplicated serial copies (each process believing it is rank 0).
|
|
28
|
+
Escape hatch for intentionally independent serial copies:
|
|
29
|
+
`LIMTOD_FORCE_SERIAL=1`.
|
|
30
|
+
- 🚢 **First PyPI release**: `pip install limTOD`.
|
|
31
|
+
|
|
32
|
+
### Code quality (post-review polish)
|
|
33
|
+
|
|
34
|
+
- ✅ **New test suites**: full-Stokes physical invariants (spin structure,
|
|
35
|
+
1D/3-row/4-row consistency, linearity, normalization) pin the polarized
|
|
36
|
+
chain the Stokes-I oracle never covered; a flicker-noise boundary sweep
|
|
37
|
+
over (alpha, fc, tau) corners; and an independent end-to-end
|
|
38
|
+
`HPW_mapmaking` oracle that rebuilds the regularized normal equations in
|
|
39
|
+
the test (unfiltered, priors, per-TOD noise variance, high-pass
|
|
40
|
+
consistency, gain/injection calibration).
|
|
41
|
+
- 🧾 **Type annotations** across the numpy package (`mypy
|
|
42
|
+
--disallow-untyped-defs` clean); the previously dead ArrayLike aliases
|
|
43
|
+
are now used.
|
|
44
|
+
- 🪵 **Logging**: all library `print()` calls migrated to module loggers
|
|
45
|
+
(`logging.getLogger`); informational output is now opt-in via standard
|
|
46
|
+
logging configuration instead of unconditional stdout, and MPI ranks no
|
|
47
|
+
longer duplicate messages.
|
|
48
|
+
- 🧩 **`HPW_mapmaking.__call__` decomposed** into `_filter_and_stack`,
|
|
49
|
+
`_build_priors`, and `_normalize_noise_variance` (behavior pinned
|
|
50
|
+
bit-exact by the new oracle tests before refactoring).
|
|
51
|
+
- 📓 Notebooks that require external, non-shipped data
|
|
52
|
+
(`demonstration.ipynb`, `RotatingBeam/baseSim*.ipynb`) now carry a
|
|
53
|
+
warning cell up top instead of failing with a bare `FileNotFoundError`.
|
|
54
|
+
|
|
55
|
+
### Documentation
|
|
56
|
+
|
|
57
|
+
- 📚 **Restructured**: README is now a concise landing page (install,
|
|
58
|
+
quick starts, citation); detailed guides moved to `docs/`
|
|
59
|
+
(tod-simulation, mapmaking, theory & conventions, api-reference,
|
|
60
|
+
limtod-jax). Fixed duplicated/garbled parameter listings, broken
|
|
61
|
+
fences, and case-mismatched notebook links from the old monolithic
|
|
62
|
+
README.
|
|
63
|
+
|
|
64
|
+
### Packaging
|
|
65
|
+
|
|
66
|
+
- Version is single-sourced from `pyproject.toml`: both
|
|
67
|
+
`limTOD.__version__` and `limtod_jax.__version__` read the installed
|
|
68
|
+
distribution metadata (the hardcoded copies had drifted once).
|
|
69
|
+
- Modernized metadata (SPDX license expression + `license-files`,
|
|
70
|
+
Python 3.12/3.13 classifiers, Documentation/Changelog URLs) and a lean
|
|
71
|
+
sdist (packages + docs + CHANGELOG; notebooks/data stay on GitHub).
|
|
72
|
+
|
|
73
|
+
### Changed
|
|
74
|
+
|
|
75
|
+
- **Fresh-install default changed**: `mpi4py` and `pygdsm` are no longer
|
|
76
|
+
required dependencies — a plain `pip install -e .` now installs a lighter,
|
|
77
|
+
wheel-only stack (numpy, healpy, astropy, scipy, tqdm, mpmath). Rationale:
|
|
78
|
+
mpi4py needs a system MPI toolchain and pygdsm downloads sky-model data,
|
|
79
|
+
both an unnecessary burden for downstream users (e.g. e-RHINO) who only
|
|
80
|
+
consume the JAX port. **Existing environments are unaffected** (already-
|
|
81
|
+
installed packages stay); for a fresh full setup use
|
|
82
|
+
`pip install -e ".[full]"`, for MPI runs `.[mpi]`, for GDSM skies `.[gdsm]`.
|
|
83
|
+
- `limTOD.mpiutil` falls back to serial mode (`rank=0, size=1, world=None`)
|
|
84
|
+
when mpi4py is absent — restoring the graceful-degradation behavior of the
|
|
85
|
+
upstream caput `mpiutil` it is adapted from. With mpi4py installed,
|
|
86
|
+
behavior is unchanged.
|
|
87
|
+
- `GDSM_sky_model` imports pygdsm lazily and raises a clear `ImportError`
|
|
88
|
+
pointing at `pip install "limTOD[gdsm]"` when it is missing. All other
|
|
89
|
+
functionality works without pygdsm.
|
|
90
|
+
|
|
91
|
+
### Fixed
|
|
92
|
+
|
|
93
|
+
Pre-release full-code review (independent numpy-side and JAX-side passes)
|
|
94
|
+
caught and fixed, with regression tests for each:
|
|
95
|
+
|
|
96
|
+
- 🐛 **`horizontal_mask` orientation**: the horizontal-frame mask was
|
|
97
|
+
rotated with `elevation=0` instead of the zenith pointing
|
|
98
|
+
(`elevation=90`), tipping it 90° onto the horizon — every masked
|
|
99
|
+
simulation placed the mask at the wrong sky location. Fixed; a
|
|
100
|
+
regression test pins the mask cap to (RA = LST, Dec = latitude).
|
|
101
|
+
- 🐛 **Silent NaN from zero-sum beams**: `normalize_beam`/`normalize=True`
|
|
102
|
+
divided by the beam's pixel sum unguarded; a fully-truncated or
|
|
103
|
+
fully-masked pointing silently poisoned the TOD with NaN. Now raises a
|
|
104
|
+
clear `ValueError` naming the pointing conditions; negative beam sums
|
|
105
|
+
scale all Stokes rows consistently (previously Q/U/V were left
|
|
106
|
+
unscaled).
|
|
107
|
+
- 🐛 **Flicker-noise error handling**: `aux_int` no longer swallows
|
|
108
|
+
mpmath errors into a printed message plus a fabricated `inf`
|
|
109
|
+
(it raises with context); `flicker_corr`/`sim_noise` explicitly reject
|
|
110
|
+
the singular `alpha=1` exponent instead of failing type-dependently.
|
|
111
|
+
- 🐛 **`wiener_filter_map` short TODs**: the default rolling-variance
|
|
112
|
+
estimator crashed with an opaque matmul error for TODs shorter than its
|
|
113
|
+
100-sample window; the window now caps at the TOD length and mismatched
|
|
114
|
+
`noise_variance` lengths raise a clear error.
|
|
115
|
+
- 🐛 **`HPW_mapmaking` prior routing**: mixed 1D/2D
|
|
116
|
+
`Tsys_other_prior_inv_cov_group` elements were all routed by the FIRST
|
|
117
|
+
element's dimensionality, silently discarding off-diagonal covariance
|
|
118
|
+
entries; each element now routes by its own shape.
|
|
119
|
+
- 🐛 **`generate_gaussian_field(seed=None)`** no longer reseeds the global
|
|
120
|
+
NumPy RNG from OS entropy (which clobbered callers' reproducibility
|
|
121
|
+
seeding); it only seeds when a seed is given.
|
|
122
|
+
- 🐛 **Bugs surfaced by the typing pass** (all regression-tested):
|
|
123
|
+
`HPW_mapmaking(return_full_cov=True)` crashed unpacking
|
|
124
|
+
`wiener_filter_map`'s 3-tuple — the posterior covariance is now returned
|
|
125
|
+
as the final element; `wiener_filter_map` no longer hits a `NameError`
|
|
126
|
+
when the covariance is uncomputable (clear `LinAlgError` instead);
|
|
127
|
+
`Tsys_others_operator_group` accepts the documented bare-2D-array form
|
|
128
|
+
(and validates its length against the number of TODs);
|
|
129
|
+
`sim_noise` accepts a plain Python list `time_list` as documented.
|
|
130
|
+
- Pointing-array length mismatches now raise upfront (zip previously
|
|
131
|
+
truncated silently); MPI-unsafe unconditional prints are rank-0-gated;
|
|
132
|
+
`HPW_mapmaking` argument validation raises `ValueError` instead of
|
|
133
|
+
`assert` (which `python -O` strips); example scripts' obfuscated
|
|
134
|
+
serializer imports (written to dodge a security hook) were replaced with
|
|
135
|
+
plain, warning-commented imports.
|
|
136
|
+
- Aligned `pyproject.toml`/`limTOD.__version__` (stuck at 1.1.0) with the
|
|
137
|
+
changelog version history.
|
|
138
|
+
|
|
139
|
+
## [1.2.0] - 2025-10-06
|
|
140
|
+
|
|
141
|
+
### Added
|
|
142
|
+
|
|
143
|
+
- Add `CHANGELOG.md`
|
|
144
|
+
|
|
145
|
+
### Changed
|
|
146
|
+
|
|
147
|
+
- **BREAKING**: Renamed `TODsim` class to `TODSim` for better Python naming conventions
|
|
148
|
+
- Renamed old `limTODsim` class references to `TODSim` throughout codebase
|
|
149
|
+
- Updated all import statements and class instantiations to use `TODSim`
|
|
150
|
+
- Updated `__init__.py` and `__all__` exports to reflect new class name
|
|
151
|
+
|
|
152
|
+
### Improved
|
|
153
|
+
|
|
154
|
+
- 📝 **Documentation**:
|
|
155
|
+
- **Structure**: Moved "Latest Updates" section from README.md to dedicated CHANGELOG.md file
|
|
156
|
+
- 📋 **Table of Contents**: Updated README.md Table of Contents to accurately reflect document structure
|
|
157
|
+
- **Examples**: Removed in flavour of example notebooks to simplify maintainace
|
|
158
|
+
- 🔧 **Code Organization**:
|
|
159
|
+
- Move example notebooks to `examples/`
|
|
160
|
+
- Improved consistency in class naming across all files including:
|
|
161
|
+
- Source code (`simulator.py`)
|
|
162
|
+
- Package exports (`__init__.py`)
|
|
163
|
+
- Documentation (`README.md`)
|
|
164
|
+
- Example notebooks (`examples.ipynb`, `mm_example.ipynb`)
|
|
165
|
+
- Change Log (`CHANGELOG.md`)
|
|
166
|
+
|
|
167
|
+
### Fixed
|
|
168
|
+
|
|
169
|
+
- Corrected all references to use consistent `TODSim` class name
|
|
170
|
+
- Fixed import statements in example notebooks and documentation
|
|
171
|
+
|
|
172
|
+
## [1.1.0] - 2025-10-05
|
|
173
|
+
|
|
174
|
+
### Added
|
|
175
|
+
|
|
176
|
+
- 🎯 **Full Stokes Support**: Added complete polarization handling (I, Q, U, V) for both TOD simulation and map-making
|
|
177
|
+
- 🗺️ **Map-Making Pipeline**: Implemented `HPW_mapmaking` class combining high-pass filtering and Wiener filtering for sky reconstruction from TOD
|
|
178
|
+
- 🎲 **Gaussian Random Field Generator**: Added generator for correlated sky realizations from frequency-frequency angular power spectra C_ℓ(ν,ν'), enabling realistic simulation of line intensity mapping signals with spectral correlations (credit: Katrine Alice Glasscock, Philip Bull)
|
|
179
|
+
- 📓 **Example Notebooks**: Added comprehensive Jupyter notebook demonstrating the full map-making workflow ([examples/mm_example.ipynb](examples/mm_example.ipynb))
|
|
180
|
+
|
|
181
|
+
### Changed
|
|
182
|
+
|
|
183
|
+
- **BREAKING**: `beam_func` and `sky_func` now require keyword-only arguments, two of which must be `freq` and `nside`:
|
|
184
|
+
|
|
185
|
+
```python
|
|
186
|
+
# Old: beam_func(freq, nside) and sky_func(freq, nside)
|
|
187
|
+
# New: beam_func(freq=xx, nside=xx) and sky_func(freq=xx, nside=xx)
|
|
188
|
+
```
|
|
189
|
+
|
|
190
|
+
- **BREAKING**: Function outputs must be HEALPix maps with specific shapes:
|
|
191
|
+
- 1D array of length npix for unpolarized (**I**) beam/sky
|
|
192
|
+
- 2D array of shape (3, npix) for polarized (**I, Q, U**) beam/sky
|
|
193
|
+
- 2D array of shape (4, npix) for polarized (**I, Q, U, V**) beam/sky
|
|
194
|
+
|
|
195
|
+
### Fixed
|
|
196
|
+
|
|
197
|
+
- 🐛 **Bug Fix**: Corrected a critical sign error in coordinate rotation transformations
|
|
198
|
+
|
|
199
|
+
## [1.0.0] - 2025-09-01
|
|
200
|
+
|
|
201
|
+
### Initial Release
|
|
202
|
+
|
|
203
|
+
- Initial release of limTOD: Time-Ordered Data simulation for single-dish radio telescopes
|
|
204
|
+
|
|
205
|
+
### Key Features
|
|
206
|
+
|
|
207
|
+
- TOD simulation with realistic noise models (1/f noise, white noise, gain variations)
|
|
208
|
+
- Support for asymmetric beam patterns
|
|
209
|
+
- Direct beam convolution using HEALPix spherical harmonics rotation and sum to calculate Tsky
|
|
210
|
+
- Flexible beam and sky model functions
|
|
211
|
+
- Global Sky Model (GDSM) integration
|
|
212
|
+
- MPI parallelization support
|
|
213
|
+
- Example scanning patterns and beam models
|
|
214
|
+
- Example notebooks for getting started
|
|
215
|
+
- Documentation and examples
|
limtod-1.3.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Zheng Zhang
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
limtod-1.3.0/MANIFEST.in
ADDED
limtod-1.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,201 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: limTOD
|
|
3
|
+
Version: 1.3.0
|
|
4
|
+
Summary: Time-Ordered Data simulator for single-dish radio intensity mapping, with a differentiable JAX port (limtod_jax)
|
|
5
|
+
Author-email: Zheng Zhang <zheng.zhang@manchester.ac.uk>
|
|
6
|
+
License-Expression: MIT
|
|
7
|
+
Project-URL: Homepage, https://github.com/zzhang0123/limTOD
|
|
8
|
+
Project-URL: Documentation, https://github.com/zzhang0123/limTOD/tree/main/docs
|
|
9
|
+
Project-URL: Changelog, https://github.com/zzhang0123/limTOD/blob/main/CHANGELOG.md
|
|
10
|
+
Project-URL: Bug Reports, https://github.com/zzhang0123/limTOD/issues
|
|
11
|
+
Project-URL: Source Code, https://github.com/zzhang0123/limTOD
|
|
12
|
+
Keywords: time-ordered data,simulation,MeerKAT,HEALPix,beam patterns,sky models,noise modeling,map making
|
|
13
|
+
Classifier: Development Status :: 4 - Beta
|
|
14
|
+
Classifier: Intended Audience :: Science/Research
|
|
15
|
+
Classifier: Operating System :: OS Independent
|
|
16
|
+
Classifier: Programming Language :: Python :: 3
|
|
17
|
+
Classifier: Programming Language :: Python :: 3.8
|
|
18
|
+
Classifier: Programming Language :: Python :: 3.9
|
|
19
|
+
Classifier: Programming Language :: Python :: 3.10
|
|
20
|
+
Classifier: Programming Language :: Python :: 3.11
|
|
21
|
+
Classifier: Programming Language :: Python :: 3.12
|
|
22
|
+
Classifier: Programming Language :: Python :: 3.13
|
|
23
|
+
Classifier: Topic :: Scientific/Engineering :: Astronomy
|
|
24
|
+
Classifier: Topic :: Scientific/Engineering :: Physics
|
|
25
|
+
Requires-Python: >=3.8
|
|
26
|
+
Description-Content-Type: text/markdown
|
|
27
|
+
License-File: LICENSE
|
|
28
|
+
Requires-Dist: numpy>=1.19.0
|
|
29
|
+
Requires-Dist: healpy>=1.14.0
|
|
30
|
+
Requires-Dist: astropy>=4.0.0
|
|
31
|
+
Requires-Dist: scipy>=1.5.0
|
|
32
|
+
Requires-Dist: tqdm>=4.60.0
|
|
33
|
+
Requires-Dist: mpmath>=1.2.0
|
|
34
|
+
Provides-Extra: mpi
|
|
35
|
+
Requires-Dist: mpi4py>=3.0.0; extra == "mpi"
|
|
36
|
+
Provides-Extra: gdsm
|
|
37
|
+
Requires-Dist: pygdsm>=1.2.0; extra == "gdsm"
|
|
38
|
+
Provides-Extra: full
|
|
39
|
+
Requires-Dist: mpi4py>=3.0.0; extra == "full"
|
|
40
|
+
Requires-Dist: pygdsm>=1.2.0; extra == "full"
|
|
41
|
+
Requires-Dist: jax>=0.5; extra == "full"
|
|
42
|
+
Requires-Dist: s2fft>=1.4.0; extra == "full"
|
|
43
|
+
Provides-Extra: dev
|
|
44
|
+
Requires-Dist: pytest>=6.0; extra == "dev"
|
|
45
|
+
Requires-Dist: pytest-cov>=2.0; extra == "dev"
|
|
46
|
+
Requires-Dist: black>=21.0; extra == "dev"
|
|
47
|
+
Requires-Dist: flake8>=3.8; extra == "dev"
|
|
48
|
+
Requires-Dist: mypy>=0.800; extra == "dev"
|
|
49
|
+
Requires-Dist: sphinx>=4.0; extra == "dev"
|
|
50
|
+
Requires-Dist: sphinx-rtd-theme>=1.0; extra == "dev"
|
|
51
|
+
Requires-Dist: jupyter>=1.0; extra == "dev"
|
|
52
|
+
Requires-Dist: matplotlib>=3.3.0; extra == "dev"
|
|
53
|
+
Provides-Extra: docs
|
|
54
|
+
Requires-Dist: sphinx>=4.0; extra == "docs"
|
|
55
|
+
Requires-Dist: sphinx-rtd-theme>=1.0; extra == "docs"
|
|
56
|
+
Requires-Dist: jupyter>=1.0; extra == "docs"
|
|
57
|
+
Requires-Dist: matplotlib>=3.3.0; extra == "docs"
|
|
58
|
+
Provides-Extra: notebooks
|
|
59
|
+
Requires-Dist: jupyter>=1.0; extra == "notebooks"
|
|
60
|
+
Requires-Dist: matplotlib>=3.3.0; extra == "notebooks"
|
|
61
|
+
Requires-Dist: seaborn>=0.11.0; extra == "notebooks"
|
|
62
|
+
Provides-Extra: jax
|
|
63
|
+
Requires-Dist: jax>=0.5; extra == "jax"
|
|
64
|
+
Requires-Dist: s2fft>=1.4.0; extra == "jax"
|
|
65
|
+
Dynamic: license-file
|
|
66
|
+
|
|
67
|
+
# limTOD
|
|
68
|
+
|
|
69
|
+
**Time-Ordered Data simulator for single-dish (autocorrelation) radio
|
|
70
|
+
intensity mapping — with a differentiable pure-JAX port.**
|
|
71
|
+
|
|
72
|
+
limTOD simulates the time-ordered data (TOD) of a single-dish telescope
|
|
73
|
+
scanning a HEALPix sky with an arbitrary (asymmetric) beam: the beam is
|
|
74
|
+
rotated to each pointing in spherical-harmonic space and dotted with the
|
|
75
|
+
sky, then combined with 1/f gain noise and white noise. The package also
|
|
76
|
+
ships:
|
|
77
|
+
|
|
78
|
+
- **`HPW_mapmaking`** — high-pass + Wiener-filter map-making from TOD back
|
|
79
|
+
to sky maps;
|
|
80
|
+
- **`limtod_jax`** — a pure-JAX, jit/vmap/grad-safe port of the sky→TOD
|
|
81
|
+
chain, verified against the numpy implementation to ~1e-12 in float64.
|
|
82
|
+
It powers the differentiable pipeline of
|
|
83
|
+
[e-RHINO](https://github.com/zzhang0123/e-RHINO).
|
|
84
|
+
|
|
85
|
+
Latest changes:
|
|
86
|
+
[CHANGELOG](https://github.com/zzhang0123/limTOD/blob/main/CHANGELOG.md).
|
|
87
|
+
|
|
88
|
+
## Installation
|
|
89
|
+
|
|
90
|
+
```bash
|
|
91
|
+
pip install limTOD
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
The base install is deliberately lightweight (wheel-only: numpy, healpy,
|
|
95
|
+
astropy, scipy, tqdm, mpmath — no compiler needed). Heavier dependencies
|
|
96
|
+
are opt-in extras:
|
|
97
|
+
|
|
98
|
+
| Extra | Installs | When you need it |
|
|
99
|
+
|-------|----------|------------------|
|
|
100
|
+
| `[mpi]` | mpi4py | MPI-parallel simulation (`mpirun -n N ...`). Without it limTOD runs serially; launching under `mpirun` *without* mpi4py fails loudly instead of silently duplicating work. |
|
|
101
|
+
| `[gdsm]` | pygdsm | The `GDSM_sky_model` sky function (Global Sky Model). Everything else works without it. |
|
|
102
|
+
| `[jax]` | jax, s2fft | The `limtod_jax` package (Python ≥ 3.11). |
|
|
103
|
+
| `[full]` | all of the above | The complete setup. |
|
|
104
|
+
|
|
105
|
+
```bash
|
|
106
|
+
pip install "limTOD[full]"
|
|
107
|
+
```
|
|
108
|
+
|
|
109
|
+
From source: clone the
|
|
110
|
+
[repository](https://github.com/zzhang0123/limTOD) and
|
|
111
|
+
`pip install -e ".[dev,full]"` (runs the test suite over both the
|
|
112
|
+
MPI-present and serial-fallback paths).
|
|
113
|
+
|
|
114
|
+
## Quick start
|
|
115
|
+
|
|
116
|
+
Simulate multi-frequency TOD for a MeerKAT-like scan
|
|
117
|
+
(sky model here needs `[gdsm]`; pass your own `sky_func` to go without):
|
|
118
|
+
|
|
119
|
+
```python
|
|
120
|
+
from limTOD import TODSim, example_scan
|
|
121
|
+
|
|
122
|
+
simulator = TODSim(
|
|
123
|
+
ant_latitude_deg=-30.7130, ant_longitude_deg=21.4430, ant_height_m=1054,
|
|
124
|
+
beam_nside=256, sky_nside=256,
|
|
125
|
+
)
|
|
126
|
+
time_list, azimuth_list = example_scan()
|
|
127
|
+
tod, sky_tod, gain_noise = simulator.generate_TOD(
|
|
128
|
+
freq_list=[950, 1000, 1050], # MHz
|
|
129
|
+
time_list=time_list,
|
|
130
|
+
azimuth_deg_list=azimuth_list,
|
|
131
|
+
elevation_deg=41.5,
|
|
132
|
+
) # each (n_freq, n_time)
|
|
133
|
+
```
|
|
134
|
+
|
|
135
|
+
The same sky→TOD chain, differentiable in JAX (`[jax]` extra):
|
|
136
|
+
|
|
137
|
+
```python
|
|
138
|
+
import jax; jax.config.update("jax_enable_x64", True)
|
|
139
|
+
import jax.numpy as jnp
|
|
140
|
+
import limtod_jax as ltj
|
|
141
|
+
|
|
142
|
+
sky_alm = ltj.map2alm_quad(sky_map, nside=nside, lmax=lmax)
|
|
143
|
+
psi, theta, phi = ltj.zyz_of_pointing(lst_deg, lat_deg, az_deg, el_deg, 0.0)
|
|
144
|
+
tod = ltj.generate_tod_sky(
|
|
145
|
+
beam_alm, sky_alm, jnp.stack([psi, theta, phi], axis=-1), lmax=lmax,
|
|
146
|
+
)
|
|
147
|
+
grad = jax.grad(lambda b: ltj.generate_tod_sky(
|
|
148
|
+
b, sky_alm, jnp.stack([psi, theta, phi], axis=-1), lmax=lmax).sum().real
|
|
149
|
+
)(beam_alm) # d(TOD sum)/d(beam alms)
|
|
150
|
+
```
|
|
151
|
+
|
|
152
|
+
## Documentation
|
|
153
|
+
|
|
154
|
+
| Page | Contents |
|
|
155
|
+
|------|----------|
|
|
156
|
+
| [TOD simulation](https://github.com/zzhang0123/limTOD/blob/main/docs/tod-simulation.md) | `TODSim` guide: inputs, outputs, noise model, MPI, troubleshooting |
|
|
157
|
+
| [Map-making](https://github.com/zzhang0123/limTOD/blob/main/docs/mapmaking.md) | `HPW_mapmaking`: high-pass + Wiener filtering |
|
|
158
|
+
| [Theory & conventions](https://github.com/zzhang0123/limTOD/blob/main/docs/theory.md) | Signal model, coordinate chain, Euler-angle conventions |
|
|
159
|
+
| [API reference](https://github.com/zzhang0123/limTOD/blob/main/docs/api-reference.md) | Public numpy API signatures |
|
|
160
|
+
| [limtod_jax](https://github.com/zzhang0123/limTOD/blob/main/docs/limtod-jax.md) | The JAX port: usage, exactness contract, precision requirements |
|
|
161
|
+
|
|
162
|
+
Worked notebooks:
|
|
163
|
+
[TOD simulation](https://github.com/zzhang0123/limTOD/blob/main/examples/TODsim_examples.ipynb)
|
|
164
|
+
and
|
|
165
|
+
[map-making](https://github.com/zzhang0123/limTOD/blob/main/examples/mm_example.ipynb).
|
|
166
|
+
Mathematical derivations:
|
|
167
|
+
[conventions.pdf](https://github.com/zzhang0123/limTOD/blob/main/conventions.pdf).
|
|
168
|
+
|
|
169
|
+
## Citation
|
|
170
|
+
|
|
171
|
+
If you use limTOD in your research, please cite:
|
|
172
|
+
|
|
173
|
+
```bibtex
|
|
174
|
+
@ARTICLE{2026RASTI...5ag024Z,
|
|
175
|
+
author = {{Zhang}, Zheng and {Bull}, Philip and {Santos}, Mario G. and {Nasirudin}, Ainulnabilah},
|
|
176
|
+
title = "{Joint Bayesian calibration and map-making for intensity mapping experiments}",
|
|
177
|
+
journal = {RAS Techniques and Instruments},
|
|
178
|
+
keywords = {Data Methods, methods: data analysis, techniques: spectroscopic, radio lines: general, Instrumentation and Methods for Astrophysics},
|
|
179
|
+
year = 2026,
|
|
180
|
+
month = jan,
|
|
181
|
+
volume = {5},
|
|
182
|
+
eid = {rzag024},
|
|
183
|
+
pages = {rzag024},
|
|
184
|
+
doi = {10.1093/rasti/rzag024},
|
|
185
|
+
archivePrefix = {arXiv},
|
|
186
|
+
eprint = {2509.10992},
|
|
187
|
+
primaryClass = {astro-ph.IM},
|
|
188
|
+
adsurl = {https://ui.adsabs.harvard.edu/abs/2026RASTI...5ag024Z},
|
|
189
|
+
adsnote = {Provided by the SAO/NASA Astrophysics Data System}
|
|
190
|
+
}
|
|
191
|
+
```
|
|
192
|
+
|
|
193
|
+
## License and authorship
|
|
194
|
+
|
|
195
|
+
MIT License — see
|
|
196
|
+
[LICENSE](https://github.com/zzhang0123/limTOD/blob/main/LICENSE).
|
|
197
|
+
|
|
198
|
+
limTOD is developed and maintained by Zheng Zhang (University of
|
|
199
|
+
Manchester), with help and advice from members of the MeerKLASS
|
|
200
|
+
and RHINO collaborations — including Phil Bull, Piyanat Kittiwisit,
|
|
201
|
+
Geoff Murphy, and Mario Santos.
|
limtod-1.3.0/README.md
ADDED
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
# limTOD
|
|
2
|
+
|
|
3
|
+
**Time-Ordered Data simulator for single-dish (autocorrelation) radio
|
|
4
|
+
intensity mapping — with a differentiable pure-JAX port.**
|
|
5
|
+
|
|
6
|
+
limTOD simulates the time-ordered data (TOD) of a single-dish telescope
|
|
7
|
+
scanning a HEALPix sky with an arbitrary (asymmetric) beam: the beam is
|
|
8
|
+
rotated to each pointing in spherical-harmonic space and dotted with the
|
|
9
|
+
sky, then combined with 1/f gain noise and white noise. The package also
|
|
10
|
+
ships:
|
|
11
|
+
|
|
12
|
+
- **`HPW_mapmaking`** — high-pass + Wiener-filter map-making from TOD back
|
|
13
|
+
to sky maps;
|
|
14
|
+
- **`limtod_jax`** — a pure-JAX, jit/vmap/grad-safe port of the sky→TOD
|
|
15
|
+
chain, verified against the numpy implementation to ~1e-12 in float64.
|
|
16
|
+
It powers the differentiable pipeline of
|
|
17
|
+
[e-RHINO](https://github.com/zzhang0123/e-RHINO).
|
|
18
|
+
|
|
19
|
+
Latest changes:
|
|
20
|
+
[CHANGELOG](https://github.com/zzhang0123/limTOD/blob/main/CHANGELOG.md).
|
|
21
|
+
|
|
22
|
+
## Installation
|
|
23
|
+
|
|
24
|
+
```bash
|
|
25
|
+
pip install limTOD
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
The base install is deliberately lightweight (wheel-only: numpy, healpy,
|
|
29
|
+
astropy, scipy, tqdm, mpmath — no compiler needed). Heavier dependencies
|
|
30
|
+
are opt-in extras:
|
|
31
|
+
|
|
32
|
+
| Extra | Installs | When you need it |
|
|
33
|
+
|-------|----------|------------------|
|
|
34
|
+
| `[mpi]` | mpi4py | MPI-parallel simulation (`mpirun -n N ...`). Without it limTOD runs serially; launching under `mpirun` *without* mpi4py fails loudly instead of silently duplicating work. |
|
|
35
|
+
| `[gdsm]` | pygdsm | The `GDSM_sky_model` sky function (Global Sky Model). Everything else works without it. |
|
|
36
|
+
| `[jax]` | jax, s2fft | The `limtod_jax` package (Python ≥ 3.11). |
|
|
37
|
+
| `[full]` | all of the above | The complete setup. |
|
|
38
|
+
|
|
39
|
+
```bash
|
|
40
|
+
pip install "limTOD[full]"
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
From source: clone the
|
|
44
|
+
[repository](https://github.com/zzhang0123/limTOD) and
|
|
45
|
+
`pip install -e ".[dev,full]"` (runs the test suite over both the
|
|
46
|
+
MPI-present and serial-fallback paths).
|
|
47
|
+
|
|
48
|
+
## Quick start
|
|
49
|
+
|
|
50
|
+
Simulate multi-frequency TOD for a MeerKAT-like scan
|
|
51
|
+
(sky model here needs `[gdsm]`; pass your own `sky_func` to go without):
|
|
52
|
+
|
|
53
|
+
```python
|
|
54
|
+
from limTOD import TODSim, example_scan
|
|
55
|
+
|
|
56
|
+
simulator = TODSim(
|
|
57
|
+
ant_latitude_deg=-30.7130, ant_longitude_deg=21.4430, ant_height_m=1054,
|
|
58
|
+
beam_nside=256, sky_nside=256,
|
|
59
|
+
)
|
|
60
|
+
time_list, azimuth_list = example_scan()
|
|
61
|
+
tod, sky_tod, gain_noise = simulator.generate_TOD(
|
|
62
|
+
freq_list=[950, 1000, 1050], # MHz
|
|
63
|
+
time_list=time_list,
|
|
64
|
+
azimuth_deg_list=azimuth_list,
|
|
65
|
+
elevation_deg=41.5,
|
|
66
|
+
) # each (n_freq, n_time)
|
|
67
|
+
```
|
|
68
|
+
|
|
69
|
+
The same sky→TOD chain, differentiable in JAX (`[jax]` extra):
|
|
70
|
+
|
|
71
|
+
```python
|
|
72
|
+
import jax; jax.config.update("jax_enable_x64", True)
|
|
73
|
+
import jax.numpy as jnp
|
|
74
|
+
import limtod_jax as ltj
|
|
75
|
+
|
|
76
|
+
sky_alm = ltj.map2alm_quad(sky_map, nside=nside, lmax=lmax)
|
|
77
|
+
psi, theta, phi = ltj.zyz_of_pointing(lst_deg, lat_deg, az_deg, el_deg, 0.0)
|
|
78
|
+
tod = ltj.generate_tod_sky(
|
|
79
|
+
beam_alm, sky_alm, jnp.stack([psi, theta, phi], axis=-1), lmax=lmax,
|
|
80
|
+
)
|
|
81
|
+
grad = jax.grad(lambda b: ltj.generate_tod_sky(
|
|
82
|
+
b, sky_alm, jnp.stack([psi, theta, phi], axis=-1), lmax=lmax).sum().real
|
|
83
|
+
)(beam_alm) # d(TOD sum)/d(beam alms)
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
## Documentation
|
|
87
|
+
|
|
88
|
+
| Page | Contents |
|
|
89
|
+
|------|----------|
|
|
90
|
+
| [TOD simulation](https://github.com/zzhang0123/limTOD/blob/main/docs/tod-simulation.md) | `TODSim` guide: inputs, outputs, noise model, MPI, troubleshooting |
|
|
91
|
+
| [Map-making](https://github.com/zzhang0123/limTOD/blob/main/docs/mapmaking.md) | `HPW_mapmaking`: high-pass + Wiener filtering |
|
|
92
|
+
| [Theory & conventions](https://github.com/zzhang0123/limTOD/blob/main/docs/theory.md) | Signal model, coordinate chain, Euler-angle conventions |
|
|
93
|
+
| [API reference](https://github.com/zzhang0123/limTOD/blob/main/docs/api-reference.md) | Public numpy API signatures |
|
|
94
|
+
| [limtod_jax](https://github.com/zzhang0123/limTOD/blob/main/docs/limtod-jax.md) | The JAX port: usage, exactness contract, precision requirements |
|
|
95
|
+
|
|
96
|
+
Worked notebooks:
|
|
97
|
+
[TOD simulation](https://github.com/zzhang0123/limTOD/blob/main/examples/TODsim_examples.ipynb)
|
|
98
|
+
and
|
|
99
|
+
[map-making](https://github.com/zzhang0123/limTOD/blob/main/examples/mm_example.ipynb).
|
|
100
|
+
Mathematical derivations:
|
|
101
|
+
[conventions.pdf](https://github.com/zzhang0123/limTOD/blob/main/conventions.pdf).
|
|
102
|
+
|
|
103
|
+
## Citation
|
|
104
|
+
|
|
105
|
+
If you use limTOD in your research, please cite:
|
|
106
|
+
|
|
107
|
+
```bibtex
|
|
108
|
+
@ARTICLE{2026RASTI...5ag024Z,
|
|
109
|
+
author = {{Zhang}, Zheng and {Bull}, Philip and {Santos}, Mario G. and {Nasirudin}, Ainulnabilah},
|
|
110
|
+
title = "{Joint Bayesian calibration and map-making for intensity mapping experiments}",
|
|
111
|
+
journal = {RAS Techniques and Instruments},
|
|
112
|
+
keywords = {Data Methods, methods: data analysis, techniques: spectroscopic, radio lines: general, Instrumentation and Methods for Astrophysics},
|
|
113
|
+
year = 2026,
|
|
114
|
+
month = jan,
|
|
115
|
+
volume = {5},
|
|
116
|
+
eid = {rzag024},
|
|
117
|
+
pages = {rzag024},
|
|
118
|
+
doi = {10.1093/rasti/rzag024},
|
|
119
|
+
archivePrefix = {arXiv},
|
|
120
|
+
eprint = {2509.10992},
|
|
121
|
+
primaryClass = {astro-ph.IM},
|
|
122
|
+
adsurl = {https://ui.adsabs.harvard.edu/abs/2026RASTI...5ag024Z},
|
|
123
|
+
adsnote = {Provided by the SAO/NASA Astrophysics Data System}
|
|
124
|
+
}
|
|
125
|
+
```
|
|
126
|
+
|
|
127
|
+
## License and authorship
|
|
128
|
+
|
|
129
|
+
MIT License — see
|
|
130
|
+
[LICENSE](https://github.com/zzhang0123/limTOD/blob/main/LICENSE).
|
|
131
|
+
|
|
132
|
+
limTOD is developed and maintained by Zheng Zhang (University of
|
|
133
|
+
Manchester), with help and advice from members of the MeerKLASS
|
|
134
|
+
and RHINO collaborations — including Phil Bull, Piyanat Kittiwisit,
|
|
135
|
+
Geoff Murphy, and Mario Santos.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
# limTOD documentation
|
|
2
|
+
|
|
3
|
+
| Page | Contents |
|
|
4
|
+
|------|----------|
|
|
5
|
+
| [TOD simulation](tod-simulation.md) | `TODSim` user guide: inputs, outputs, noise model, examples, troubleshooting |
|
|
6
|
+
| [Map-making](mapmaking.md) | `HPW_mapmaking`: high-pass + Wiener filtering from TOD to sky maps |
|
|
7
|
+
| [Theory & conventions](theory.md) | Signal model, coordinate transformations, Euler-angle conventions, workflow |
|
|
8
|
+
| [API reference](api-reference.md) | Signatures and parameters of the public numpy API |
|
|
9
|
+
| [limtod_jax](limtod-jax.md) | The pure-JAX differentiable port: usage, conventions, exactness contract, precision |
|
|
10
|
+
|
|
11
|
+
Release notes live in [CHANGELOG.md](../CHANGELOG.md); mathematical
|
|
12
|
+
derivations in [conventions.pdf](../conventions.pdf).
|