taoistmc 0.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.
- taoistmc-0.3.0/.gitignore +38 -0
- taoistmc-0.3.0/LICENSE +24 -0
- taoistmc-0.3.0/PKG-INFO +226 -0
- taoistmc-0.3.0/README.md +197 -0
- taoistmc-0.3.0/pyproject.toml +64 -0
- taoistmc-0.3.0/src/taoistmc/__init__.py +18 -0
- taoistmc-0.3.0/src/taoistmc/config/__init__.py +7 -0
- taoistmc-0.3.0/src/taoistmc/config/config.py +77 -0
- taoistmc-0.3.0/src/taoistmc/core/__init__.py +8 -0
- taoistmc-0.3.0/src/taoistmc/core/gpu_kernels.py +68 -0
- taoistmc-0.3.0/src/taoistmc/core/optical_depth.py +160 -0
- taoistmc-0.3.0/src/taoistmc/core/sightline.py +102 -0
- taoistmc-0.3.0/src/taoistmc/data/lyman_series.dat +32 -0
- taoistmc-0.3.0/src/taoistmc/data/starter_config.yaml +33 -0
- taoistmc-0.3.0/src/taoistmc/main.py +102 -0
- taoistmc-0.3.0/src/taoistmc/taoist.py +214 -0
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[cod]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# Environments
|
|
7
|
+
.venv/
|
|
8
|
+
venv/
|
|
9
|
+
ENV/
|
|
10
|
+
env/
|
|
11
|
+
*.env
|
|
12
|
+
*.venv
|
|
13
|
+
|
|
14
|
+
# Distribution / packaging
|
|
15
|
+
dist/
|
|
16
|
+
build/
|
|
17
|
+
*.egg-info/
|
|
18
|
+
*.egg
|
|
19
|
+
|
|
20
|
+
# Unit test / coverage reports
|
|
21
|
+
htmlcov/
|
|
22
|
+
.tox/
|
|
23
|
+
.coverage
|
|
24
|
+
.cache
|
|
25
|
+
nosetests.xml
|
|
26
|
+
coverage.xml
|
|
27
|
+
*.cover
|
|
28
|
+
.pytest_cache/
|
|
29
|
+
|
|
30
|
+
# Jupyter Notebook checkpoints
|
|
31
|
+
.ipynb_checkpoints
|
|
32
|
+
|
|
33
|
+
# IDE-specific (Optional)
|
|
34
|
+
.vscode/
|
|
35
|
+
.idea/
|
|
36
|
+
local/
|
|
37
|
+
_build/
|
|
38
|
+
htmlcov/
|
taoistmc-0.3.0/LICENSE
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
This is free and unencumbered software released into the public domain.
|
|
2
|
+
|
|
3
|
+
Anyone is free to copy, modify, publish, use, compile, sell, or
|
|
4
|
+
distribute this software, either in source code form or as a compiled
|
|
5
|
+
binary, for any purpose, commercial or non-commercial, and by any
|
|
6
|
+
means.
|
|
7
|
+
|
|
8
|
+
In jurisdictions that recognize copyright laws, the author or authors
|
|
9
|
+
of this software dedicate any and all copyright interest in the
|
|
10
|
+
software to the public domain. We make this dedication for the benefit
|
|
11
|
+
of the public at large and to the detriment of our heirs and
|
|
12
|
+
successors. We intend this dedication to be an overt act of
|
|
13
|
+
relinquishment in perpetuity of all present and future rights to this
|
|
14
|
+
software under copyright law.
|
|
15
|
+
|
|
16
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
|
17
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
|
18
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
|
19
|
+
IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
|
|
20
|
+
OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
|
|
21
|
+
ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
|
|
22
|
+
OTHER DEALINGS IN THE SOFTWARE.
|
|
23
|
+
|
|
24
|
+
For more information, please refer to <https://unlicense.org>
|
taoistmc-0.3.0/PKG-INFO
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: taoistmc
|
|
3
|
+
Version: 0.3.0
|
|
4
|
+
Summary: Simulator for generating IGM sightlines for LyC studies
|
|
5
|
+
Project-URL: Homepage, https://github.com
|
|
6
|
+
Project-URL: Documentation, https://github.com#readme
|
|
7
|
+
Author-email: Robert Bassett <rbassett.astro@gmail.com>
|
|
8
|
+
License: MIT
|
|
9
|
+
License-File: LICENSE
|
|
10
|
+
Requires-Python: >=3.10
|
|
11
|
+
Requires-Dist: joblib>=1.5.3
|
|
12
|
+
Requires-Dist: numba>=0.65.1
|
|
13
|
+
Requires-Dist: numpy>=1.26.4
|
|
14
|
+
Requires-Dist: pandas>=2.3.0
|
|
15
|
+
Requires-Dist: pydantic>=2.11.7
|
|
16
|
+
Requires-Dist: pyyaml>=6.0.3
|
|
17
|
+
Requires-Dist: requests>=2.28.0
|
|
18
|
+
Requires-Dist: scipy>=1.15.3
|
|
19
|
+
Requires-Dist: typer>=0.25.1
|
|
20
|
+
Provides-Extra: dev
|
|
21
|
+
Requires-Dist: black; extra == 'dev'
|
|
22
|
+
Requires-Dist: pytest-cov>=4.0; extra == 'dev'
|
|
23
|
+
Requires-Dist: pytest>=7.0; extra == 'dev'
|
|
24
|
+
Provides-Extra: docs
|
|
25
|
+
Requires-Dist: furo>=2024.1; extra == 'docs'
|
|
26
|
+
Requires-Dist: sphinx-rtd-theme>=2.0; extra == 'docs'
|
|
27
|
+
Requires-Dist: sphinx>=7.0; extra == 'docs'
|
|
28
|
+
Description-Content-Type: text/markdown
|
|
29
|
+
|
|
30
|
+

|
|
31
|
+
|
|
32
|
+
# TAOIST-MC: TrAnsmission Of IoniSing lightT - Monte Carlo
|
|
33
|
+
|
|
34
|
+
[](https://github.com/robbassett/TAOIST_MC/actions/workflows/tests.yml)
|
|
35
|
+
[](https://codecov.io/gh/robbassett/TAOIST_MC)
|
|
36
|
+
|
|
37
|
+
**Simulated IGM UV Transmission for Lyman Continuum Studies**
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Overview
|
|
42
|
+
|
|
43
|
+
TAOIST-MC generates realistic intergalactic medium (IGM) transmission curves for studies of Lyman continuum (LyC) emission from distant galaxies. Using hydrogen absorption system statistics from the literature (redshift and column density distribution functions), it simulates the transmission of ionizing radiation through neutral hydrogen in the IGM for sources at specified redshifts.
|
|
44
|
+
|
|
45
|
+
The primary outputs are ensembles of IGM transmission functions T(λ) at UV wavelengths. These can be coupled with model spectra from population synthesis codes (e.g., BPASS) to predict the observed ionizing flux from high-redshift sources.
|
|
46
|
+
|
|
47
|
+
### Key Improvements (v0.3+)
|
|
48
|
+
|
|
49
|
+
- **Modular OOP Design** — Clean separation of sightline sampling, optical depth calculation, and configuration
|
|
50
|
+
- **Parallel Processing** — Multi-core CPU acceleration via `joblib`
|
|
51
|
+
- **GPU Support** — CUDA-accelerated optical depth kernels via Numba (10×+ speedup)
|
|
52
|
+
- **YAML Configuration** — Physics parameters defined via validated Pydantic models
|
|
53
|
+
- **Automatic Caching** — Sightlines are saved and reused across runs with matching physics configurations
|
|
54
|
+
- **CLI Interface** — `taoistmc init` and `taoistmc run` commands for streamlined workflows
|
|
55
|
+
|
|
56
|
+
---
|
|
57
|
+
|
|
58
|
+
## Installation
|
|
59
|
+
|
|
60
|
+
```bash
|
|
61
|
+
pip install .
|
|
62
|
+
```
|
|
63
|
+
|
|
64
|
+
**Requirements:** Python ≥ 3.10, NumPy, SciPy, Numba, Pydantic, Typer, PyYAML, joblib.
|
|
65
|
+
|
|
66
|
+
> **GPU Support:** GPU acceleration requires a CUDA-capable NVIDIA GPU and the appropriate CUDA toolkit. If unavailable, the package gracefully falls back to CPU execution.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
## Quick Start (Python API)
|
|
71
|
+
|
|
72
|
+
```python
|
|
73
|
+
import taoistmc as tmc
|
|
74
|
+
import numpy as np
|
|
75
|
+
import matplotlib.pyplot as plt
|
|
76
|
+
|
|
77
|
+
from taoistmc.config import PowerLawSegment, SightlineConfig, TaoistConfig
|
|
78
|
+
|
|
79
|
+
if __name__ == "__main__":
|
|
80
|
+
|
|
81
|
+
igm_low = PowerLawSegment(log_N_min=12.0, log_N_max=15.2, beta=1.635, log_A=9.305, gamma=2.5)
|
|
82
|
+
igm_high = PowerLawSegment(log_N_min=15.2, log_N_max=21.0, beta=1.463, log_A=7.542, gamma=1.0)
|
|
83
|
+
cgm_seg = PowerLawSegment(log_N_min=13.0, log_N_max=21.0, beta=1.381, log_A=6.716, gamma=1.0)
|
|
84
|
+
|
|
85
|
+
config = SightlineConfig(
|
|
86
|
+
igm_segments=[igm_low, igm_high],
|
|
87
|
+
cgm_segments=[cgm_seg]
|
|
88
|
+
)
|
|
89
|
+
|
|
90
|
+
full_config = TaoistConfig(
|
|
91
|
+
sightline_config=config,
|
|
92
|
+
delta_wav=0.25
|
|
93
|
+
)
|
|
94
|
+
|
|
95
|
+
F = plt.figure()
|
|
96
|
+
ax = F.add_subplot(111)
|
|
97
|
+
for z in (1.5, 2.5, 3.5):
|
|
98
|
+
tao = tmc.TaoistMc(full_config)
|
|
99
|
+
output = tao.run(z, 200)
|
|
100
|
+
|
|
101
|
+
taum = np.mean(np.exp(-output), axis=0)
|
|
102
|
+
ax.plot(tao.wav / (1. + z), taum, lw=1)
|
|
103
|
+
[ax.axvline(x=_x, c='r', ls='--', lw=.3) for _x in [911.75, 1216.]]
|
|
104
|
+
ax.set_ylim(-.1, 1.1)
|
|
105
|
+
ax.set_xlim(799, 1249)
|
|
106
|
+
ax.set_xlabel(r'$\lambda_{rest}$', fontsize=18)
|
|
107
|
+
ax.set_ylabel(r'$T_{IGM}$', fontsize=18)
|
|
108
|
+
plt.show()
|
|
109
|
+
```
|
|
110
|
+
|
|
111
|
+
---
|
|
112
|
+
|
|
113
|
+
## Command-Line Interface
|
|
114
|
+
|
|
115
|
+
TAOIST-MC provides a Typer-based CLI:
|
|
116
|
+
|
|
117
|
+
```bash
|
|
118
|
+
# Generate a starter config (Steidel et al. 2018 parameters)
|
|
119
|
+
taoistmc init
|
|
120
|
+
|
|
121
|
+
# Run 50 sightlines at z=2.4
|
|
122
|
+
taoistmc run -n 50 2.4
|
|
123
|
+
|
|
124
|
+
# Verbose output, custom config path
|
|
125
|
+
taoistmc run --verbose --config my_config.yaml 3.1
|
|
126
|
+
```
|
|
127
|
+
|
|
128
|
+
- `taoistmc init` — Copies `starter_config.yaml` to the current directory
|
|
129
|
+
- `taoistmc run` — Executes a simulation, automatically reusing cached sightlines when physics parameters match
|
|
130
|
+
|
|
131
|
+
---
|
|
132
|
+
|
|
133
|
+
## Configuration
|
|
134
|
+
|
|
135
|
+
### PowerLawSegment
|
|
136
|
+
|
|
137
|
+
Defines a piecewise segment of the column density distribution function f(N_HI, X) following the form used in Steidel et al. (2018), eq. B3:
|
|
138
|
+
|
|
139
|
+
```python
|
|
140
|
+
PowerLawSegment(
|
|
141
|
+
log_N_min=12.0, # Minimum log column density
|
|
142
|
+
log_N_max=15.2, # Maximum log column density
|
|
143
|
+
beta=1.635, # Power-law slope (negative exponent)
|
|
144
|
+
log_A=9.305, # Normalization
|
|
145
|
+
gamma=2.5 # Redshift evolution: (1+z)^gamma
|
|
146
|
+
)
|
|
147
|
+
```
|
|
148
|
+
|
|
149
|
+
Multiple segments can be combined for a continuous, piecewise f(N) model. Segments must be contiguous (no gaps in log N).
|
|
150
|
+
|
|
151
|
+
### SightlineConfig
|
|
152
|
+
|
|
153
|
+
Controls absorber sampling:
|
|
154
|
+
|
|
155
|
+
| Parameter | Default | Description |
|
|
156
|
+
|-----------|---------|-------------|
|
|
157
|
+
| `dz` | 5e-5 | Redshift bin size for integration |
|
|
158
|
+
| `dhi` | 0.25 | log N_HI bin size |
|
|
159
|
+
| `use_cgm` | True | Enable separate CGM absorber population |
|
|
160
|
+
| `cgm_influence_km_s` | 700.0 | Velocity window (km/s) around source considered "CGM" |
|
|
161
|
+
| `igm_segments` | (required) | List of PowerLawSegments for IGM |
|
|
162
|
+
| `cgm_segments` | (required if use_cgm) | List of PowerLawSegments for CGM |
|
|
163
|
+
|
|
164
|
+
### TaoistConfig
|
|
165
|
+
|
|
166
|
+
Top-level simulation settings:
|
|
167
|
+
|
|
168
|
+
| Parameter | Default | Description |
|
|
169
|
+
|-----------|---------|-------------|
|
|
170
|
+
| `n_jobs` | -1 | Parallel jobs (-1 = all cores) |
|
|
171
|
+
| `use_gpu` | False | Enable CUDA acceleration |
|
|
172
|
+
| `rest_wav_min` | 600 | Minimum rest-frame wavelength (Å) |
|
|
173
|
+
| `rest_wav_max` | 1500 | Maximum rest-frame wavelength (Å) |
|
|
174
|
+
| `delta_wav` | 1.25 | Wavelength sampling resolution (Å) |
|
|
175
|
+
| `sightline_config` | (required) | Nested SightlineConfig |
|
|
176
|
+
| `verbose` | False | Print progress messages |
|
|
177
|
+
| `save` | True | Save results to disk |
|
|
178
|
+
| `output_dir` | "taoist_runs" | Base directory for saved runs |
|
|
179
|
+
|
|
180
|
+
---
|
|
181
|
+
|
|
182
|
+
## Performance & Acceleration
|
|
183
|
+
|
|
184
|
+
- **CPU Parallelism:** Sightlines are generated in parallel using `joblib`. Set `n_jobs` to control worker count.
|
|
185
|
+
- **GPU Acceleration:** When `use_gpu=True` and a CUDA device is available, the optical depth calculation runs on the GPU via Numba CUDA kernels. This can yield >10× speedup for large sightline counts.
|
|
186
|
+
- **Caching:** Results are saved as compressed `.npz` files under `taoist_runs/zXpX/`. Subsequent runs with identical physics parameters automatically load and append to existing sightlines.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Scientific Background
|
|
191
|
+
|
|
192
|
+
This code implements the methodology described in:
|
|
193
|
+
|
|
194
|
+
> **Bassett et al. 2021**, "The Detection of Ionizing Radiation from Star-Forming Galaxies at z ~ 3–4", *MNRAS* (arXiv:2101.00727)
|
|
195
|
+
|
|
196
|
+
The transmission curves account for both Lyman-series absorption and Lyman-continuum opacity from the Lyman-α forest (LAF) and CGM absorbers. Future versions may include helium ionization physics.
|
|
197
|
+
|
|
198
|
+
For more details, see Section 2 of the paper and the legacy documentation in `legacy/README.md`.
|
|
199
|
+
|
|
200
|
+
---
|
|
201
|
+
|
|
202
|
+
## Output Format
|
|
203
|
+
|
|
204
|
+
When `save=True`, each run creates files like:
|
|
205
|
+
|
|
206
|
+
```
|
|
207
|
+
taoist_runs/z2p400/taoist_zem2.400_n50_20260527_221530.npz
|
|
208
|
+
```
|
|
209
|
+
|
|
210
|
+
These archives contain:
|
|
211
|
+
- `z_em`: Source redshift
|
|
212
|
+
- `config_json`: Serialized TaoistConfig for reproducibility checks
|
|
213
|
+
- `sl_i`, `tau_i`: Sightline absorber arrays and optical depth vectors
|
|
214
|
+
|
|
215
|
+
The `TaoistMc.load_results()` and `load_redshift()` methods can reconstruct a simulation state from these files.
|
|
216
|
+
|
|
217
|
+
---
|
|
218
|
+
|
|
219
|
+
## Contact & Citation
|
|
220
|
+
|
|
221
|
+
**Author:** Robert Bassett
|
|
222
|
+
**Email:** rbassett.astro@gmail.com
|
|
223
|
+
|
|
224
|
+
If you use TAOIST-MC in your research, please cite Bassett et al. 2021 and link to this repository.
|
|
225
|
+
|
|
226
|
+
---
|
taoistmc-0.3.0/README.md
ADDED
|
@@ -0,0 +1,197 @@
|
|
|
1
|
+

|
|
2
|
+
|
|
3
|
+
# TAOIST-MC: TrAnsmission Of IoniSing lightT - Monte Carlo
|
|
4
|
+
|
|
5
|
+
[](https://github.com/robbassett/TAOIST_MC/actions/workflows/tests.yml)
|
|
6
|
+
[](https://codecov.io/gh/robbassett/TAOIST_MC)
|
|
7
|
+
|
|
8
|
+
**Simulated IGM UV Transmission for Lyman Continuum Studies**
|
|
9
|
+
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
## Overview
|
|
13
|
+
|
|
14
|
+
TAOIST-MC generates realistic intergalactic medium (IGM) transmission curves for studies of Lyman continuum (LyC) emission from distant galaxies. Using hydrogen absorption system statistics from the literature (redshift and column density distribution functions), it simulates the transmission of ionizing radiation through neutral hydrogen in the IGM for sources at specified redshifts.
|
|
15
|
+
|
|
16
|
+
The primary outputs are ensembles of IGM transmission functions T(λ) at UV wavelengths. These can be coupled with model spectra from population synthesis codes (e.g., BPASS) to predict the observed ionizing flux from high-redshift sources.
|
|
17
|
+
|
|
18
|
+
### Key Improvements (v0.3+)
|
|
19
|
+
|
|
20
|
+
- **Modular OOP Design** — Clean separation of sightline sampling, optical depth calculation, and configuration
|
|
21
|
+
- **Parallel Processing** — Multi-core CPU acceleration via `joblib`
|
|
22
|
+
- **GPU Support** — CUDA-accelerated optical depth kernels via Numba (10×+ speedup)
|
|
23
|
+
- **YAML Configuration** — Physics parameters defined via validated Pydantic models
|
|
24
|
+
- **Automatic Caching** — Sightlines are saved and reused across runs with matching physics configurations
|
|
25
|
+
- **CLI Interface** — `taoistmc init` and `taoistmc run` commands for streamlined workflows
|
|
26
|
+
|
|
27
|
+
---
|
|
28
|
+
|
|
29
|
+
## Installation
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
pip install .
|
|
33
|
+
```
|
|
34
|
+
|
|
35
|
+
**Requirements:** Python ≥ 3.10, NumPy, SciPy, Numba, Pydantic, Typer, PyYAML, joblib.
|
|
36
|
+
|
|
37
|
+
> **GPU Support:** GPU acceleration requires a CUDA-capable NVIDIA GPU and the appropriate CUDA toolkit. If unavailable, the package gracefully falls back to CPU execution.
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Quick Start (Python API)
|
|
42
|
+
|
|
43
|
+
```python
|
|
44
|
+
import taoistmc as tmc
|
|
45
|
+
import numpy as np
|
|
46
|
+
import matplotlib.pyplot as plt
|
|
47
|
+
|
|
48
|
+
from taoistmc.config import PowerLawSegment, SightlineConfig, TaoistConfig
|
|
49
|
+
|
|
50
|
+
if __name__ == "__main__":
|
|
51
|
+
|
|
52
|
+
igm_low = PowerLawSegment(log_N_min=12.0, log_N_max=15.2, beta=1.635, log_A=9.305, gamma=2.5)
|
|
53
|
+
igm_high = PowerLawSegment(log_N_min=15.2, log_N_max=21.0, beta=1.463, log_A=7.542, gamma=1.0)
|
|
54
|
+
cgm_seg = PowerLawSegment(log_N_min=13.0, log_N_max=21.0, beta=1.381, log_A=6.716, gamma=1.0)
|
|
55
|
+
|
|
56
|
+
config = SightlineConfig(
|
|
57
|
+
igm_segments=[igm_low, igm_high],
|
|
58
|
+
cgm_segments=[cgm_seg]
|
|
59
|
+
)
|
|
60
|
+
|
|
61
|
+
full_config = TaoistConfig(
|
|
62
|
+
sightline_config=config,
|
|
63
|
+
delta_wav=0.25
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
F = plt.figure()
|
|
67
|
+
ax = F.add_subplot(111)
|
|
68
|
+
for z in (1.5, 2.5, 3.5):
|
|
69
|
+
tao = tmc.TaoistMc(full_config)
|
|
70
|
+
output = tao.run(z, 200)
|
|
71
|
+
|
|
72
|
+
taum = np.mean(np.exp(-output), axis=0)
|
|
73
|
+
ax.plot(tao.wav / (1. + z), taum, lw=1)
|
|
74
|
+
[ax.axvline(x=_x, c='r', ls='--', lw=.3) for _x in [911.75, 1216.]]
|
|
75
|
+
ax.set_ylim(-.1, 1.1)
|
|
76
|
+
ax.set_xlim(799, 1249)
|
|
77
|
+
ax.set_xlabel(r'$\lambda_{rest}$', fontsize=18)
|
|
78
|
+
ax.set_ylabel(r'$T_{IGM}$', fontsize=18)
|
|
79
|
+
plt.show()
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
---
|
|
83
|
+
|
|
84
|
+
## Command-Line Interface
|
|
85
|
+
|
|
86
|
+
TAOIST-MC provides a Typer-based CLI:
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# Generate a starter config (Steidel et al. 2018 parameters)
|
|
90
|
+
taoistmc init
|
|
91
|
+
|
|
92
|
+
# Run 50 sightlines at z=2.4
|
|
93
|
+
taoistmc run -n 50 2.4
|
|
94
|
+
|
|
95
|
+
# Verbose output, custom config path
|
|
96
|
+
taoistmc run --verbose --config my_config.yaml 3.1
|
|
97
|
+
```
|
|
98
|
+
|
|
99
|
+
- `taoistmc init` — Copies `starter_config.yaml` to the current directory
|
|
100
|
+
- `taoistmc run` — Executes a simulation, automatically reusing cached sightlines when physics parameters match
|
|
101
|
+
|
|
102
|
+
---
|
|
103
|
+
|
|
104
|
+
## Configuration
|
|
105
|
+
|
|
106
|
+
### PowerLawSegment
|
|
107
|
+
|
|
108
|
+
Defines a piecewise segment of the column density distribution function f(N_HI, X) following the form used in Steidel et al. (2018), eq. B3:
|
|
109
|
+
|
|
110
|
+
```python
|
|
111
|
+
PowerLawSegment(
|
|
112
|
+
log_N_min=12.0, # Minimum log column density
|
|
113
|
+
log_N_max=15.2, # Maximum log column density
|
|
114
|
+
beta=1.635, # Power-law slope (negative exponent)
|
|
115
|
+
log_A=9.305, # Normalization
|
|
116
|
+
gamma=2.5 # Redshift evolution: (1+z)^gamma
|
|
117
|
+
)
|
|
118
|
+
```
|
|
119
|
+
|
|
120
|
+
Multiple segments can be combined for a continuous, piecewise f(N) model. Segments must be contiguous (no gaps in log N).
|
|
121
|
+
|
|
122
|
+
### SightlineConfig
|
|
123
|
+
|
|
124
|
+
Controls absorber sampling:
|
|
125
|
+
|
|
126
|
+
| Parameter | Default | Description |
|
|
127
|
+
|-----------|---------|-------------|
|
|
128
|
+
| `dz` | 5e-5 | Redshift bin size for integration |
|
|
129
|
+
| `dhi` | 0.25 | log N_HI bin size |
|
|
130
|
+
| `use_cgm` | True | Enable separate CGM absorber population |
|
|
131
|
+
| `cgm_influence_km_s` | 700.0 | Velocity window (km/s) around source considered "CGM" |
|
|
132
|
+
| `igm_segments` | (required) | List of PowerLawSegments for IGM |
|
|
133
|
+
| `cgm_segments` | (required if use_cgm) | List of PowerLawSegments for CGM |
|
|
134
|
+
|
|
135
|
+
### TaoistConfig
|
|
136
|
+
|
|
137
|
+
Top-level simulation settings:
|
|
138
|
+
|
|
139
|
+
| Parameter | Default | Description |
|
|
140
|
+
|-----------|---------|-------------|
|
|
141
|
+
| `n_jobs` | -1 | Parallel jobs (-1 = all cores) |
|
|
142
|
+
| `use_gpu` | False | Enable CUDA acceleration |
|
|
143
|
+
| `rest_wav_min` | 600 | Minimum rest-frame wavelength (Å) |
|
|
144
|
+
| `rest_wav_max` | 1500 | Maximum rest-frame wavelength (Å) |
|
|
145
|
+
| `delta_wav` | 1.25 | Wavelength sampling resolution (Å) |
|
|
146
|
+
| `sightline_config` | (required) | Nested SightlineConfig |
|
|
147
|
+
| `verbose` | False | Print progress messages |
|
|
148
|
+
| `save` | True | Save results to disk |
|
|
149
|
+
| `output_dir` | "taoist_runs" | Base directory for saved runs |
|
|
150
|
+
|
|
151
|
+
---
|
|
152
|
+
|
|
153
|
+
## Performance & Acceleration
|
|
154
|
+
|
|
155
|
+
- **CPU Parallelism:** Sightlines are generated in parallel using `joblib`. Set `n_jobs` to control worker count.
|
|
156
|
+
- **GPU Acceleration:** When `use_gpu=True` and a CUDA device is available, the optical depth calculation runs on the GPU via Numba CUDA kernels. This can yield >10× speedup for large sightline counts.
|
|
157
|
+
- **Caching:** Results are saved as compressed `.npz` files under `taoist_runs/zXpX/`. Subsequent runs with identical physics parameters automatically load and append to existing sightlines.
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Scientific Background
|
|
162
|
+
|
|
163
|
+
This code implements the methodology described in:
|
|
164
|
+
|
|
165
|
+
> **Bassett et al. 2021**, "The Detection of Ionizing Radiation from Star-Forming Galaxies at z ~ 3–4", *MNRAS* (arXiv:2101.00727)
|
|
166
|
+
|
|
167
|
+
The transmission curves account for both Lyman-series absorption and Lyman-continuum opacity from the Lyman-α forest (LAF) and CGM absorbers. Future versions may include helium ionization physics.
|
|
168
|
+
|
|
169
|
+
For more details, see Section 2 of the paper and the legacy documentation in `legacy/README.md`.
|
|
170
|
+
|
|
171
|
+
---
|
|
172
|
+
|
|
173
|
+
## Output Format
|
|
174
|
+
|
|
175
|
+
When `save=True`, each run creates files like:
|
|
176
|
+
|
|
177
|
+
```
|
|
178
|
+
taoist_runs/z2p400/taoist_zem2.400_n50_20260527_221530.npz
|
|
179
|
+
```
|
|
180
|
+
|
|
181
|
+
These archives contain:
|
|
182
|
+
- `z_em`: Source redshift
|
|
183
|
+
- `config_json`: Serialized TaoistConfig for reproducibility checks
|
|
184
|
+
- `sl_i`, `tau_i`: Sightline absorber arrays and optical depth vectors
|
|
185
|
+
|
|
186
|
+
The `TaoistMc.load_results()` and `load_redshift()` methods can reconstruct a simulation state from these files.
|
|
187
|
+
|
|
188
|
+
---
|
|
189
|
+
|
|
190
|
+
## Contact & Citation
|
|
191
|
+
|
|
192
|
+
**Author:** Robert Bassett
|
|
193
|
+
**Email:** rbassett.astro@gmail.com
|
|
194
|
+
|
|
195
|
+
If you use TAOIST-MC in your research, please cite Bassett et al. 2021 and link to this repository.
|
|
196
|
+
|
|
197
|
+
---
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
[build-system]
|
|
2
|
+
# Modern backends include "hatchling.build", "setuptools.build_meta", or "flit_core.buildapi"
|
|
3
|
+
requires = ["hatchling"]
|
|
4
|
+
build-backend = "hatchling.build"
|
|
5
|
+
|
|
6
|
+
[project]
|
|
7
|
+
name = "taoistmc"
|
|
8
|
+
version = "0.3.0"
|
|
9
|
+
description = "Simulator for generating IGM sightlines for LyC studies"
|
|
10
|
+
readme = "README.md"
|
|
11
|
+
requires-python = ">=3.10"
|
|
12
|
+
license = {text = "MIT"}
|
|
13
|
+
authors = [
|
|
14
|
+
{name = "Robert Bassett", email = "rbassett.astro@gmail.com"}
|
|
15
|
+
]
|
|
16
|
+
dependencies = [
|
|
17
|
+
"requests>=2.28.0",
|
|
18
|
+
"numpy>=1.26.4",
|
|
19
|
+
"pandas>=2.3.0",
|
|
20
|
+
"pydantic>=2.11.7",
|
|
21
|
+
"scipy>=1.15.3",
|
|
22
|
+
"numba>=0.65.1",
|
|
23
|
+
"joblib>=1.5.3",
|
|
24
|
+
"typer>=0.25.1",
|
|
25
|
+
"PyYAML>=6.0.3"
|
|
26
|
+
]
|
|
27
|
+
|
|
28
|
+
[project.optional-dependencies]
|
|
29
|
+
dev = [
|
|
30
|
+
"pytest>=7.0",
|
|
31
|
+
"black",
|
|
32
|
+
"pytest-cov>=4.0",
|
|
33
|
+
]
|
|
34
|
+
docs = [
|
|
35
|
+
"sphinx>=7.0",
|
|
36
|
+
"sphinx-rtd-theme>=2.0",
|
|
37
|
+
"furo>=2024.1",
|
|
38
|
+
]
|
|
39
|
+
|
|
40
|
+
[project.urls]
|
|
41
|
+
Homepage = "https://github.com"
|
|
42
|
+
Documentation = "https://github.com#readme"
|
|
43
|
+
|
|
44
|
+
[tool.hatch.build.targets.wheel]
|
|
45
|
+
packages = ["src/taoistmc"]
|
|
46
|
+
|
|
47
|
+
# Hatchling uses artifacts/inclusion patterns
|
|
48
|
+
[tool.hatch.build.targets.sdist]
|
|
49
|
+
include = [
|
|
50
|
+
"/src/taoistmc",
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
[tool.hatch.build.targets.wheel.shared-data]
|
|
54
|
+
"src/taoistmc/data" = "taoistmc/data"
|
|
55
|
+
|
|
56
|
+
[project.scripts]
|
|
57
|
+
taoistmc = "taoistmc.main:app"
|
|
58
|
+
|
|
59
|
+
[tool.pytest.ini_options]
|
|
60
|
+
testpaths = ["tests"]
|
|
61
|
+
python_files = ["test_*.py"]
|
|
62
|
+
python_classes = ["Test*"]
|
|
63
|
+
python_functions = ["test_*"]
|
|
64
|
+
addopts = "-v --tb=short"
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
from importlib.metadata import version, PackageNotFoundError
|
|
2
|
+
|
|
3
|
+
try:
|
|
4
|
+
__version__ = version("taoistmc")
|
|
5
|
+
except PackageNotFoundError:
|
|
6
|
+
# package is not installed
|
|
7
|
+
__version__ = "unknown"
|
|
8
|
+
|
|
9
|
+
from taoistmc.core import SightlineSampler, OpticalDepthCalculator
|
|
10
|
+
from taoistmc.taoist import TaoistMc
|
|
11
|
+
from taoistmc import config
|
|
12
|
+
|
|
13
|
+
__all__ = [
|
|
14
|
+
"TaoistMc",
|
|
15
|
+
"SightlineSampler",
|
|
16
|
+
"OpticalDepthCalculator",
|
|
17
|
+
"config"
|
|
18
|
+
]
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
from pydantic import BaseModel, Field, model_validator
|
|
2
|
+
from typing import List, Optional
|
|
3
|
+
|
|
4
|
+
class PowerLawSegment(BaseModel):
|
|
5
|
+
"""
|
|
6
|
+
Represents a single segment of f(N_HI, X) as defined by
|
|
7
|
+
Carswell et al. (1984) using the f(N_HI, z) equation for
|
|
8
|
+
N_abs found in Steidel et al (2018), eq B3. The full range
|
|
9
|
+
of HI column densities considered in your taoistmc run can
|
|
10
|
+
be made up of any number of segments in a piecewise manner.
|
|
11
|
+
"""
|
|
12
|
+
log_N_min: float = Field(..., description="log of the minimum HI column density for this segment")
|
|
13
|
+
log_N_max: float = Field(..., description="log of the maximum HI column density for this segment")
|
|
14
|
+
beta: float = Field(..., description="Exponent associated with N_HI - negative powerlaw slope")
|
|
15
|
+
log_A: float = Field(..., description="The normalisation factor")
|
|
16
|
+
gamma: float = Field(..., description="The redshift evolution term - (1+z)^gamma")
|
|
17
|
+
|
|
18
|
+
@model_validator(mode='after')
|
|
19
|
+
def check_log_N(self):
|
|
20
|
+
"""Ensure log_N_min is less than log_N_max"""
|
|
21
|
+
if self.log_N_min >= self.log_N_max:
|
|
22
|
+
raise ValueError("log_N_min must be less than log_N_max")
|
|
23
|
+
return self
|
|
24
|
+
|
|
25
|
+
class SightlineConfig(BaseModel):
|
|
26
|
+
"""
|
|
27
|
+
Configuration for the sightline sampling module
|
|
28
|
+
"""
|
|
29
|
+
dz: float = Field(5e-5, description="The size of redshift bins to be used")
|
|
30
|
+
dhi: float = Field(0.25, description="The size of the logNHI bins to be used")
|
|
31
|
+
use_cgm: bool = Field(True, description="Whether or not a different set of PowerLawSegment should be used for CGM")
|
|
32
|
+
cgm_influence_km_s: float = Field(700.0, description="The velocity range to be considered 'CGM' when CGM models are in use")
|
|
33
|
+
|
|
34
|
+
# Distribution Segments
|
|
35
|
+
igm_segments: List[PowerLawSegment] = Field(..., description="Set of PowerLawSegments to use for Poisson sampling of HI absorbers - note this must be a single segment or a continuous piecewise segment.")
|
|
36
|
+
cgm_segments: Optional[List[PowerLawSegment]] = Field(None, description="Set of PowerLawSegments to use for Poisson sampling of HI absorbers in CGM regions - note this must be a single segment or a continuous piecewise segment.")
|
|
37
|
+
|
|
38
|
+
@staticmethod
|
|
39
|
+
def _check_segments(segments: List[PowerLawSegment]) -> bool:
|
|
40
|
+
if len(segments) == 1:
|
|
41
|
+
return True
|
|
42
|
+
for seg1, seg2 in zip(segments[:-1],segments[1:]):
|
|
43
|
+
if seg1.log_N_max != seg2.log_N_min:
|
|
44
|
+
return False
|
|
45
|
+
return True
|
|
46
|
+
|
|
47
|
+
@model_validator(mode='after')
|
|
48
|
+
def check_segments_continuous(self):
|
|
49
|
+
"""Ensure igm_segments and cgm_segments are continuous"""
|
|
50
|
+
if not self._check_segments(self.igm_segments):
|
|
51
|
+
raise ValueError("igm_segments must be continous, no gaps")
|
|
52
|
+
if self.use_cgm:
|
|
53
|
+
if self.cgm_segments is None:
|
|
54
|
+
raise ValueError("cgm_segments must be specified when use_cgm is True")
|
|
55
|
+
if not self._check_segments(self.cgm_segments):
|
|
56
|
+
raise ValueError("cgm_segments must be continous, no gaps")
|
|
57
|
+
return self
|
|
58
|
+
|
|
59
|
+
@model_validator(mode='after')
|
|
60
|
+
def check_cgm_segments(self):
|
|
61
|
+
"""Ensure CGM segments are defined if use_cgm is True"""
|
|
62
|
+
if self.use_cgm and self.cgm_segments is None:
|
|
63
|
+
raise ValueError("If use_cgm is True, you must specify CGM segments")
|
|
64
|
+
return self
|
|
65
|
+
|
|
66
|
+
class TaoistConfig(BaseModel):
|
|
67
|
+
n_jobs: int = Field(-1, description="Number of parallel jobs to run, -1 will run maximum permitted on your system")
|
|
68
|
+
use_gpu: bool = Field(False, description="Use a GPU or not")
|
|
69
|
+
rest_wav_min: int = Field(600, description="Minimum rest wavelength for output transimission curves")
|
|
70
|
+
rest_wav_max: int = Field(1500, description="Maximum rest wavelength for output transmission curves")
|
|
71
|
+
delta_wav: float = Field(1.25, description="Rest wavelength resolution for output transmission curve")
|
|
72
|
+
|
|
73
|
+
sightline_config: SightlineConfig
|
|
74
|
+
|
|
75
|
+
verbose: bool = False
|
|
76
|
+
save: bool = True
|
|
77
|
+
output_dir: str = Field("taoist_runs", description="Output directory for runs")
|