makewfs 1.0.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.
- makewfs-1.0.0/.gitignore +231 -0
- makewfs-1.0.0/AGENTS.md +223 -0
- makewfs-1.0.0/CHANGELOG.md +130 -0
- makewfs-1.0.0/CITATION.cff +12 -0
- makewfs-1.0.0/CONTRIBUTING.md +44 -0
- makewfs-1.0.0/LICENSE +21 -0
- makewfs-1.0.0/PKG-INFO +133 -0
- makewfs-1.0.0/README.md +84 -0
- makewfs-1.0.0/ROADMAP.md +994 -0
- makewfs-1.0.0/benchmarks/__init__.py +1 -0
- makewfs-1.0.0/benchmarks/check_regression.py +118 -0
- makewfs-1.0.0/benchmarks/configs/pyramid_40_float32.toml +37 -0
- makewfs-1.0.0/benchmarks/configs/pyramid_60_mod8_float32.toml +37 -0
- makewfs-1.0.0/benchmarks/configs/pyramid_80_mod32_float64.toml +37 -0
- makewfs-1.0.0/benchmarks/configs/shack_hartmann_20x20_float32.toml +37 -0
- makewfs-1.0.0/benchmarks/configs/shack_hartmann_60x60_float64.toml +37 -0
- makewfs-1.0.0/benchmarks/configs/shack_hartmann_broadband_lgs.toml +42 -0
- makewfs-1.0.0/benchmarks/device-results.json +357 -0
- makewfs-1.0.0/benchmarks/device-results.md +18 -0
- makewfs-1.0.0/benchmarks/profile_warm.py +58 -0
- makewfs-1.0.0/benchmarks/reference-results.json +205 -0
- makewfs-1.0.0/benchmarks/reference-table.md +18 -0
- makewfs-1.0.0/benchmarks/render_device_table.py +80 -0
- makewfs-1.0.0/benchmarks/render_table.py +96 -0
- makewfs-1.0.0/benchmarks/run.py +237 -0
- makewfs-1.0.0/docs/adr/0001-units-coordinates.md +12 -0
- makewfs-1.0.0/docs/adr/0002-flux-normalization.md +11 -0
- makewfs-1.0.0/docs/adr/0003-public-api.md +10 -0
- makewfs-1.0.0/docs/adr/0004-backend-boundary.md +21 -0
- makewfs-1.0.0/docs/adr/index.md +10 -0
- makewfs-1.0.0/docs/api.md +11 -0
- makewfs-1.0.0/docs/concepts.md +38 -0
- makewfs-1.0.0/docs/configuration.md +263 -0
- makewfs-1.0.0/docs/contributing.md +6 -0
- makewfs-1.0.0/docs/detectors.md +25 -0
- makewfs-1.0.0/docs/examples.md +39 -0
- makewfs-1.0.0/docs/gallery/makewfs-gallery.json +23 -0
- makewfs-1.0.0/docs/gallery/makewfs-gallery.svg +4071 -0
- makewfs-1.0.0/docs/gallery.md +18 -0
- makewfs-1.0.0/docs/guide-stars.md +62 -0
- makewfs-1.0.0/docs/index.md +29 -0
- makewfs-1.0.0/docs/interop.md +66 -0
- makewfs-1.0.0/docs/performance.md +133 -0
- makewfs-1.0.0/docs/pyramid.md +38 -0
- makewfs-1.0.0/docs/quickstart.md +50 -0
- makewfs-1.0.0/docs/release.md +28 -0
- makewfs-1.0.0/docs/shack-hartmann.md +52 -0
- makewfs-1.0.0/docs/stability.md +26 -0
- makewfs-1.0.0/docs/troubleshooting.md +26 -0
- makewfs-1.0.0/docs/units-and-coordinates.md +14 -0
- makewfs-1.0.0/docs/validation.md +81 -0
- makewfs-1.0.0/examples/README.md +49 -0
- makewfs-1.0.0/examples/closed_loop_injection.py +114 -0
- makewfs-1.0.0/examples/compare_sensors.py +58 -0
- makewfs-1.0.0/examples/configs/angular_kernel.txt +4 -0
- makewfs-1.0.0/examples/configs/lgs_thin_beacon.toml +42 -0
- makewfs-1.0.0/examples/configs/precision_throughput.toml +37 -0
- makewfs-1.0.0/examples/configs/pyramid_minimal.toml +43 -0
- makewfs-1.0.0/examples/configs/qe_curve.txt +4 -0
- makewfs-1.0.0/examples/configs/shack_hartmann_extended_source.toml +43 -0
- makewfs-1.0.0/examples/configs/shack_hartmann_minimal.toml +41 -0
- makewfs-1.0.0/examples/configs/shack_hartmann_spectral_qe.toml +40 -0
- makewfs-1.0.0/examples/detector_choices.py +84 -0
- makewfs-1.0.0/examples/gallery.py +160 -0
- makewfs-1.0.0/examples/keck_haka/README.md +361 -0
- makewfs-1.0.0/examples/keck_haka/analyze_lut.py +1018 -0
- makewfs-1.0.0/examples/keck_haka/benchmark.py +553 -0
- makewfs-1.0.0/examples/keck_haka/camera_modes.csv +21 -0
- makewfs-1.0.0/examples/keck_haka/camera_modes_empirical_floor_continuous.csv +202 -0
- makewfs-1.0.0/examples/keck_haka/compare_real.py +744 -0
- makewfs-1.0.0/examples/keck_haka/fit_secondary.py +213 -0
- makewfs-1.0.0/examples/keck_haka/haka_cpu_gpu_benchmark.json +2223 -0
- makewfs-1.0.0/examples/keck_haka/haka_lut_snr.json +7020 -0
- makewfs-1.0.0/examples/keck_haka/keck_haka.json +581 -0
- makewfs-1.0.0/examples/keck_haka/keck_haka.toml +65 -0
- makewfs-1.0.0/examples/keck_haka/mauna_kea_extinction.csv +19 -0
- makewfs-1.0.0/examples/keck_haka/ocam_20260720/extract_ocam_images.py +194 -0
- makewfs-1.0.0/examples/keck_haka/ocam_20260720/make_ocam_video.py +145 -0
- makewfs-1.0.0/examples/keck_haka/real_vs_simulation.json +596 -0
- makewfs-1.0.0/examples/keck_haka/secondary_fit.json +31 -0
- makewfs-1.0.0/examples/keck_haka/simulate.py +905 -0
- makewfs-1.0.0/examples/lgs_elongation.py +92 -0
- makewfs-1.0.0/examples/lgs_thin_beacon.py +96 -0
- makewfs-1.0.0/examples/magnitude_series.py +75 -0
- makewfs-1.0.0/examples/moving_atmosphere.py +100 -0
- makewfs-1.0.0/examples/precision_throughput.py +117 -0
- makewfs-1.0.0/examples/pyramid_modulation.py +61 -0
- makewfs-1.0.0/examples/quickstart.py +58 -0
- makewfs-1.0.0/examples/realistic_broadband.py +114 -0
- makewfs-1.0.0/examples/sh_design_trade.py +49 -0
- makewfs-1.0.0/examples/spectral_qe.py +179 -0
- makewfs-1.0.0/pyproject.toml +125 -0
- makewfs-1.0.0/src/makewfs/__about__.py +3 -0
- makewfs-1.0.0/src/makewfs/__init__.py +15 -0
- makewfs-1.0.0/src/makewfs/api.py +210 -0
- makewfs-1.0.0/src/makewfs/backend.py +396 -0
- makewfs-1.0.0/src/makewfs/cli.py +99 -0
- makewfs-1.0.0/src/makewfs/config.py +830 -0
- makewfs-1.0.0/src/makewfs/detector.py +116 -0
- makewfs-1.0.0/src/makewfs/provenance.py +109 -0
- makewfs-1.0.0/src/makewfs/pupil.py +112 -0
- makewfs-1.0.0/src/makewfs/py.typed +0 -0
- makewfs-1.0.0/src/makewfs/radiometry.py +34 -0
- makewfs-1.0.0/src/makewfs/sampling.py +164 -0
- makewfs-1.0.0/src/makewfs/sensors/__init__.py +7 -0
- makewfs-1.0.0/src/makewfs/sensors/base.py +46 -0
- makewfs-1.0.0/src/makewfs/sensors/pyramid.py +215 -0
- makewfs-1.0.0/src/makewfs/sensors/shack_hartmann.py +315 -0
- makewfs-1.0.0/src/makewfs/source.py +169 -0
- makewfs-1.0.0/src/makewfs/wavefront.py +204 -0
- makewfs-1.0.0/tests/test_backend_audit.py +98 -0
- makewfs-1.0.0/tests/test_benchmarks.py +60 -0
- makewfs-1.0.0/tests/test_cli.py +67 -0
- makewfs-1.0.0/tests/test_config.py +371 -0
- makewfs-1.0.0/tests/test_gpu_backend.py +110 -0
- makewfs-1.0.0/tests/test_hcipy_validation.py +248 -0
- makewfs-1.0.0/tests/test_interop.py +25 -0
- makewfs-1.0.0/tests/test_keck_haka_example.py +368 -0
- makewfs-1.0.0/tests/test_numerics.py +195 -0
- makewfs-1.0.0/tests/test_oopao_validation.py +193 -0
- makewfs-1.0.0/tests/test_optics_validation.py +381 -0
- makewfs-1.0.0/tests/test_provenance.py +50 -0
- makewfs-1.0.0/tests/test_public_api.py +18 -0
- makewfs-1.0.0/tests/test_pyramid.py +93 -0
- makewfs-1.0.0/tests/test_shack_hartmann.py +153 -0
- makewfs-1.0.0/tests/test_source.py +185 -0
- makewfs-1.0.0/tests/test_validation_report.py +28 -0
- makewfs-1.0.0/tests/test_wavefront.py +149 -0
- makewfs-1.0.0/validation/__init__.py +1 -0
- makewfs-1.0.0/validation/run.py +193 -0
makewfs-1.0.0/.gitignore
ADDED
|
@@ -0,0 +1,231 @@
|
|
|
1
|
+
# Byte-compiled / optimized / DLL files
|
|
2
|
+
__pycache__/
|
|
3
|
+
*.py[codz]
|
|
4
|
+
*$py.class
|
|
5
|
+
|
|
6
|
+
# C extensions
|
|
7
|
+
*.so
|
|
8
|
+
|
|
9
|
+
# Distribution / packaging
|
|
10
|
+
.Python
|
|
11
|
+
build/
|
|
12
|
+
develop-eggs/
|
|
13
|
+
dist/
|
|
14
|
+
downloads/
|
|
15
|
+
eggs/
|
|
16
|
+
.eggs/
|
|
17
|
+
lib/
|
|
18
|
+
lib64/
|
|
19
|
+
parts/
|
|
20
|
+
sdist/
|
|
21
|
+
var/
|
|
22
|
+
wheels/
|
|
23
|
+
share/python-wheels/
|
|
24
|
+
*.egg-info/
|
|
25
|
+
.installed.cfg
|
|
26
|
+
*.egg
|
|
27
|
+
MANIFEST
|
|
28
|
+
|
|
29
|
+
# PyInstaller
|
|
30
|
+
# Usually these files are written by a python script from a template
|
|
31
|
+
# before PyInstaller builds the exe, so as to inject date/other infos into it.
|
|
32
|
+
*.manifest
|
|
33
|
+
*.spec
|
|
34
|
+
|
|
35
|
+
# Installer logs
|
|
36
|
+
pip-log.txt
|
|
37
|
+
pip-delete-this-directory.txt
|
|
38
|
+
|
|
39
|
+
# Unit test / coverage reports
|
|
40
|
+
htmlcov/
|
|
41
|
+
.tox/
|
|
42
|
+
.nox/
|
|
43
|
+
.coverage
|
|
44
|
+
.coverage.*
|
|
45
|
+
.cache
|
|
46
|
+
nosetests.xml
|
|
47
|
+
coverage.xml
|
|
48
|
+
*.cover
|
|
49
|
+
*.py.cover
|
|
50
|
+
.hypothesis/
|
|
51
|
+
.pytest_cache/
|
|
52
|
+
cover/
|
|
53
|
+
|
|
54
|
+
# Translations
|
|
55
|
+
*.mo
|
|
56
|
+
*.pot
|
|
57
|
+
|
|
58
|
+
# Django stuff:
|
|
59
|
+
*.log
|
|
60
|
+
local_settings.py
|
|
61
|
+
db.sqlite3
|
|
62
|
+
db.sqlite3-journal
|
|
63
|
+
|
|
64
|
+
# Flask stuff:
|
|
65
|
+
instance/
|
|
66
|
+
.webassets-cache
|
|
67
|
+
|
|
68
|
+
# Scrapy stuff:
|
|
69
|
+
.scrapy
|
|
70
|
+
|
|
71
|
+
# Sphinx documentation
|
|
72
|
+
docs/_build/
|
|
73
|
+
|
|
74
|
+
# PyBuilder
|
|
75
|
+
.pybuilder/
|
|
76
|
+
target/
|
|
77
|
+
|
|
78
|
+
# Jupyter Notebook
|
|
79
|
+
.ipynb_checkpoints
|
|
80
|
+
|
|
81
|
+
# IPython
|
|
82
|
+
profile_default/
|
|
83
|
+
ipython_config.py
|
|
84
|
+
|
|
85
|
+
# pyenv
|
|
86
|
+
# For a library or package, you might want to ignore these files since the code is
|
|
87
|
+
# intended to run in multiple environments; otherwise, check them in:
|
|
88
|
+
# .python-version
|
|
89
|
+
|
|
90
|
+
# pipenv
|
|
91
|
+
# According to pypa/pipenv#598, it is recommended to include Pipfile.lock in version control.
|
|
92
|
+
# However, in case of collaboration, if having platform-specific dependencies or dependencies
|
|
93
|
+
# having no cross-platform support, pipenv may install dependencies that don't work, or not
|
|
94
|
+
# install all needed dependencies.
|
|
95
|
+
# Pipfile.lock
|
|
96
|
+
|
|
97
|
+
# UV
|
|
98
|
+
# Similar to Pipfile.lock, it is generally recommended to include uv.lock in version control.
|
|
99
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
100
|
+
# commonly ignored for libraries.
|
|
101
|
+
# uv.lock
|
|
102
|
+
|
|
103
|
+
# poetry
|
|
104
|
+
# Similar to Pipfile.lock, it is generally recommended to include poetry.lock in version control.
|
|
105
|
+
# This is especially recommended for binary packages to ensure reproducibility, and is more
|
|
106
|
+
# commonly ignored for libraries.
|
|
107
|
+
# https://python-poetry.org/docs/basic-usage/#commit-your-poetrylock-file-to-version-control
|
|
108
|
+
# poetry.lock
|
|
109
|
+
# poetry.toml
|
|
110
|
+
|
|
111
|
+
# pdm
|
|
112
|
+
# Similar to Pipfile.lock, it is generally recommended to include pdm.lock in version control.
|
|
113
|
+
# pdm recommends including project-wide configuration in pdm.toml, but excluding .pdm-python.
|
|
114
|
+
# https://pdm-project.org/en/latest/usage/project/#working-with-version-control
|
|
115
|
+
# pdm.lock
|
|
116
|
+
# pdm.toml
|
|
117
|
+
.pdm-python
|
|
118
|
+
.pdm-build/
|
|
119
|
+
|
|
120
|
+
# pixi
|
|
121
|
+
# Similar to Pipfile.lock, it is generally recommended to include pixi.lock in version control.
|
|
122
|
+
# pixi.lock
|
|
123
|
+
# Pixi creates a virtual environment in the .pixi directory, just like venv module creates one
|
|
124
|
+
# in the .venv directory. It is recommended not to include this directory in version control.
|
|
125
|
+
.pixi
|
|
126
|
+
|
|
127
|
+
# PEP 582; used by e.g. github.com/David-OConnor/pyflow and github.com/pdm-project/pdm
|
|
128
|
+
__pypackages__/
|
|
129
|
+
|
|
130
|
+
# Celery stuff
|
|
131
|
+
celerybeat-schedule
|
|
132
|
+
celerybeat.pid
|
|
133
|
+
|
|
134
|
+
# Redis
|
|
135
|
+
*.rdb
|
|
136
|
+
*.aof
|
|
137
|
+
*.pid
|
|
138
|
+
|
|
139
|
+
# RabbitMQ
|
|
140
|
+
mnesia/
|
|
141
|
+
rabbitmq/
|
|
142
|
+
rabbitmq-data/
|
|
143
|
+
|
|
144
|
+
# ActiveMQ
|
|
145
|
+
activemq-data/
|
|
146
|
+
|
|
147
|
+
# SageMath parsed files
|
|
148
|
+
*.sage.py
|
|
149
|
+
|
|
150
|
+
# Environments
|
|
151
|
+
.env
|
|
152
|
+
.envrc
|
|
153
|
+
.venv
|
|
154
|
+
env/
|
|
155
|
+
venv/
|
|
156
|
+
ENV/
|
|
157
|
+
env.bak/
|
|
158
|
+
venv.bak/
|
|
159
|
+
|
|
160
|
+
# Spyder project settings
|
|
161
|
+
.spyderproject
|
|
162
|
+
.spyproject
|
|
163
|
+
|
|
164
|
+
# Rope project settings
|
|
165
|
+
.ropeproject
|
|
166
|
+
|
|
167
|
+
# mkdocs documentation
|
|
168
|
+
/site
|
|
169
|
+
|
|
170
|
+
# mypy
|
|
171
|
+
.mypy_cache/
|
|
172
|
+
.dmypy.json
|
|
173
|
+
dmypy.json
|
|
174
|
+
|
|
175
|
+
# Pyre type checker
|
|
176
|
+
.pyre/
|
|
177
|
+
|
|
178
|
+
# pytype static type analyzer
|
|
179
|
+
.pytype/
|
|
180
|
+
|
|
181
|
+
# Cython debug symbols
|
|
182
|
+
cython_debug/
|
|
183
|
+
|
|
184
|
+
# PyCharm
|
|
185
|
+
# JetBrains specific template is maintained in a separate JetBrains.gitignore that can
|
|
186
|
+
# be found at https://github.com/github/gitignore/blob/main/Global/JetBrains.gitignore
|
|
187
|
+
# and can be added to the global gitignore or merged into this file. For a more nuclear
|
|
188
|
+
# option (not recommended) you can uncomment the following to ignore the entire idea folder.
|
|
189
|
+
# .idea/
|
|
190
|
+
|
|
191
|
+
# Abstra
|
|
192
|
+
# Abstra is an AI-powered process automation framework.
|
|
193
|
+
# Ignore directories containing user credentials, local state, and settings.
|
|
194
|
+
# Learn more at https://abstra.io/docs
|
|
195
|
+
.abstra/
|
|
196
|
+
|
|
197
|
+
# Visual Studio Code
|
|
198
|
+
# Visual Studio Code specific template is maintained in a separate VisualStudioCode.gitignore
|
|
199
|
+
# that can be found at https://github.com/github/gitignore/blob/main/Global/VisualStudioCode.gitignore
|
|
200
|
+
# and can be added to the global gitignore or merged into this file. However, if you prefer,
|
|
201
|
+
# you could uncomment the following to ignore the entire vscode folder
|
|
202
|
+
# .vscode/
|
|
203
|
+
# Temporary file for partial code execution
|
|
204
|
+
tempCodeRunnerFile.py
|
|
205
|
+
|
|
206
|
+
# Ruff stuff:
|
|
207
|
+
.ruff_cache/
|
|
208
|
+
|
|
209
|
+
# PyPI configuration file
|
|
210
|
+
.pypirc
|
|
211
|
+
|
|
212
|
+
# Marimo
|
|
213
|
+
marimo/_static/
|
|
214
|
+
marimo/_lsp/
|
|
215
|
+
__marimo__/
|
|
216
|
+
|
|
217
|
+
# Streamlit
|
|
218
|
+
.streamlit/secrets.toml
|
|
219
|
+
|
|
220
|
+
# makewfs generated artifacts
|
|
221
|
+
*.coverage
|
|
222
|
+
.coverage
|
|
223
|
+
*.npy
|
|
224
|
+
*.npz
|
|
225
|
+
*.fits
|
|
226
|
+
*.fit
|
|
227
|
+
*.png
|
|
228
|
+
validation-metrics.json
|
|
229
|
+
benchmark-results.json
|
|
230
|
+
*.gif
|
|
231
|
+
.vscode
|
makewfs-1.0.0/AGENTS.md
ADDED
|
@@ -0,0 +1,223 @@
|
|
|
1
|
+
# AGENTS.md
|
|
2
|
+
|
|
3
|
+
This file is the operating guide for AI agents working in `makewfs`. It applies
|
|
4
|
+
to the entire repository.
|
|
5
|
+
|
|
6
|
+
## Start here
|
|
7
|
+
|
|
8
|
+
Before changing anything:
|
|
9
|
+
|
|
10
|
+
1. Read `README.md` and the complete `ROADMAP.md`.
|
|
11
|
+
2. Read `pyproject.toml` when present, the relevant source/tests/docs, and any
|
|
12
|
+
linked ADR once those files exist.
|
|
13
|
+
3. Run `git status --short --branch`. Preserve all user changes and unrelated
|
|
14
|
+
work; never reset or overwrite them.
|
|
15
|
+
4. Identify the smallest unchecked roadmap item that contains the requested work
|
|
16
|
+
and state its acceptance criteria.
|
|
17
|
+
5. Inspect the public sibling API before proposing cross-repository work:
|
|
18
|
+
`/home/donkeykong/pyturb` for atmosphere and
|
|
19
|
+
`/home/donkeykong/getframes` for detector/radiometry.
|
|
20
|
+
|
|
21
|
+
The repository is currently in the Shack-Hartmann and fixed-mask four-face
|
|
22
|
+
pyramid stage, with deterministic source spectral/angular quadrature, measured
|
|
23
|
+
source curves and user-supplied angular kernels, physical SH sampling controls,
|
|
24
|
+
analytic segmented/rotated pupils, and a documented SH sodium-range geometry
|
|
25
|
+
model. It also includes a versioned labelled documentation gallery, benchmark
|
|
26
|
+
reference snapshot, non-editable-wheel clean-room smoke evidence, released
|
|
27
|
+
wavelength-resolved detector QE through `getframes>=2.1.1`, and public
|
|
28
|
+
end-to-end CuPy execution with CPU parity tests. The GPU path uses
|
|
29
|
+
`numerics.device = "gpu"` and the sibling `getframes` CuPy detector. Do not
|
|
30
|
+
present range-resolved turbulent LGS OPD or broad independent-reference parity
|
|
31
|
+
as implemented until their gates pass.
|
|
32
|
+
|
|
33
|
+
## Product boundary
|
|
34
|
+
|
|
35
|
+
`makewfs` owns wavefront-sensor image formation:
|
|
36
|
+
|
|
37
|
+
```text
|
|
38
|
+
pupil OPD/phase + static config
|
|
39
|
+
|
|
|
40
|
+
v
|
|
41
|
+
makewfs optics
|
|
42
|
+
|
|
|
43
|
+
v
|
|
44
|
+
photon rate [photons/s/native detector pixel]
|
|
45
|
+
|
|
|
46
|
+
v
|
|
47
|
+
getframes.Camera.expose[_spectral]
|
|
48
|
+
|
|
|
49
|
+
v
|
|
50
|
+
Frame data [ADU]
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
- Atmosphere, frozen flow, Cn2 profiles, off-axis footprints, and LGS cone-effect
|
|
54
|
+
phase belong to `pyturb`.
|
|
55
|
+
- QE, shot/read/dark noise, gain, detector artifacts, digitization, calibration,
|
|
56
|
+
and detector presets belong to `getframes`.
|
|
57
|
+
- Reconstruction, centroid/slopes, DMs, and controllers belong to downstream AO
|
|
58
|
+
software.
|
|
59
|
+
- `makewfs` may model finite guide-source and sodium-layer image morphology
|
|
60
|
+
because it is part of WFS image formation, but it never predicts LGS return
|
|
61
|
+
flux or evolves the sodium layer.
|
|
62
|
+
|
|
63
|
+
Do not copy sibling physics for convenience. If their public API is insufficient,
|
|
64
|
+
write a failing integration test/design note, use the conditional gates in
|
|
65
|
+
`ROADMAP.md`, and make the smallest change in the owning repository.
|
|
66
|
+
|
|
67
|
+
## Stable contracts to protect
|
|
68
|
+
|
|
69
|
+
- The per-frame runtime inputs are the wavefront and an optional noise seed. All
|
|
70
|
+
instrument/source/detector choices live in versioned config.
|
|
71
|
+
- OPD metres are the canonical internal wavefront quantity. Phase-radian input
|
|
72
|
+
must declare its reference wavelength; units are never inferred.
|
|
73
|
+
- Arrays use `(y, x)` order and documented centered pixel coordinates. Never fix
|
|
74
|
+
a sign or transpose mismatch by visual trial and error—add an analytic ramp test.
|
|
75
|
+
- Ideal output is a non-negative photon-rate map in photons/s/native detector
|
|
76
|
+
pixel. Only `getframes` turns it into electrons or ADU.
|
|
77
|
+
- Intensities, not fields, are summed over incoherent wavelengths, modulation
|
|
78
|
+
points, finite-source samples, and sodium slices.
|
|
79
|
+
- Cropping reports lost flux; it does not renormalize it away.
|
|
80
|
+
- The intended top-level API is `load_config`, `WavefrontSensor`, and `simulate`.
|
|
81
|
+
Keep other implementation objects out of `makewfs.__init__` unless an API review
|
|
82
|
+
explicitly accepts them.
|
|
83
|
+
- The optical core must not import `pyturb`. Only the detector adapter imports
|
|
84
|
+
`getframes.Camera`; radiometry may import documented `getframes` radiometry APIs.
|
|
85
|
+
|
|
86
|
+
## Numerical and physics standards
|
|
87
|
+
|
|
88
|
+
- Start from a derivation, primary paper, or maintained independent reference.
|
|
89
|
+
Cite it in the module and user guide.
|
|
90
|
+
- Every physics feature needs a quantitative assertion against theory or an
|
|
91
|
+
independent calculation. “The plot looks right” is not validation.
|
|
92
|
+
- Required invariants include piston invariance, non-negative intensity, explicit
|
|
93
|
+
flux accounting, photon-rate linearity, stable axis/sign conventions, and
|
|
94
|
+
convergence with numerical sampling.
|
|
95
|
+
- Use explicit centered FFT helpers and normalization. Do not scatter `fftshift`
|
|
96
|
+
conventions through sensor implementations.
|
|
97
|
+
- Use flux-conserving pixel-area integration/rebinning; interpolation is not a
|
|
98
|
+
substitute for integrating detector pixels.
|
|
99
|
+
- Preserve `float32/complex64` and `float64/complex128` pairs. Test both; do not
|
|
100
|
+
allow silent promotion in a hot path.
|
|
101
|
+
- Randomness uses passed `numpy.random.Generator` instances or reproducibly
|
|
102
|
+
derived named seeds. Never use global `np.random` state.
|
|
103
|
+
- Static grids, masks, ramps, normalization constants, and detector construction
|
|
104
|
+
are cached on the persistent sensor. Benchmark construction separately from
|
|
105
|
+
warm per-frame operation.
|
|
106
|
+
- Write array operations behind `ArrayBackend`. Sensor engines must not call
|
|
107
|
+
NumPy allocation, FFT, or reduction functions directly. File readers and
|
|
108
|
+
source/config parsing are explicit host operations; the detector boundary
|
|
109
|
+
preserves the selected backend. Use `ArrayBackend.scalar` or `to_host` only at
|
|
110
|
+
named metadata/file crossings.
|
|
111
|
+
The backend-audit AST test and injected-CPU parity tests must remain green.
|
|
112
|
+
- CPU correctness comes first. The private `_backend=cupy_backend()` hook remains
|
|
113
|
+
an implementation/testing escape hatch. The supported GPU contract is the
|
|
114
|
+
serializable `numerics.device = "gpu"` field and requires device-resident
|
|
115
|
+
`getframes`; never reimplement detector behavior in this repository.
|
|
116
|
+
|
|
117
|
+
## Configuration rules
|
|
118
|
+
|
|
119
|
+
- TOML is canonical. All physical keys include units in their names.
|
|
120
|
+
- Config models are immutable and contain only serializable intent, never runtime
|
|
121
|
+
arrays, FFT plans, RNG state, or camera state.
|
|
122
|
+
- Reject unknown keys, incompatible alternatives, non-finite values, invalid
|
|
123
|
+
ranges, mismatched detector geometry, and unsupported schema versions with
|
|
124
|
+
path-specific actionable messages.
|
|
125
|
+
- Resolve file references relative to the config file. Hash referenced masks,
|
|
126
|
+
curves, and static OPD for provenance.
|
|
127
|
+
- A new user-facing field requires validation tests, serialization/digest tests,
|
|
128
|
+
config-reference documentation, and at least one example where appropriate.
|
|
129
|
+
- Backward-incompatible schema changes require a schema-version change and a
|
|
130
|
+
migration/stability note.
|
|
131
|
+
|
|
132
|
+
## Code organization
|
|
133
|
+
|
|
134
|
+
Follow the target layout in `ROADMAP.md`:
|
|
135
|
+
|
|
136
|
+
- `config.py` parses and validates; it does not propagate optics.
|
|
137
|
+
- `wavefront.py`, `pupil.py`, and `sampling.py` hold shared numerical rules.
|
|
138
|
+
- `sensors/` contains deterministic ideal optical engines and no camera noise.
|
|
139
|
+
- `radiometry.py` produces source photon budgets using public `getframes` tools.
|
|
140
|
+
- `detector.py` is a narrow adapter to `getframes.Camera.expose` and the
|
|
141
|
+
optional public `expose_spectral` cube API.
|
|
142
|
+
- `api.py` owns the user facade and caching lifecycle.
|
|
143
|
+
- `validation/` produces theory/reference evidence; `benchmarks/` measures speed;
|
|
144
|
+
neither is imported by the runtime package.
|
|
145
|
+
|
|
146
|
+
Keep functions small enough that their units and normalization can be tested in
|
|
147
|
+
isolation. Prefer immutable dataclasses and pure numerical kernels. Public APIs
|
|
148
|
+
have type hints and NumPy-style docstrings. Internal names start with `_` unless
|
|
149
|
+
another module has a deliberate need for them.
|
|
150
|
+
|
|
151
|
+
## Tests and quality gate
|
|
152
|
+
|
|
153
|
+
Once Phase 0 creates the tooling, the normal pre-handoff gate is:
|
|
154
|
+
|
|
155
|
+
```bash
|
|
156
|
+
ruff check .
|
|
157
|
+
ruff format --check .
|
|
158
|
+
python -m mypy
|
|
159
|
+
pytest --cov=makewfs --cov-branch --cov-report=term-missing
|
|
160
|
+
mkdocs build --strict
|
|
161
|
+
python -m build
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
Run `python -m mypy` from a clean Python 3.10 environment, as the CI lint job
|
|
165
|
+
does. The configured mypy target is the minimum supported Python version, so the
|
|
166
|
+
type-check environment must also resolve the Python 3.10 dependency markers
|
|
167
|
+
(including `tomli`) and a NumPy release whose stubs support Python 3.10. Running
|
|
168
|
+
the Python 3.10-targeted check from a newer environment can instead install
|
|
169
|
+
newer-only NumPy stubs and omit the conditional `tomli` dependency.
|
|
170
|
+
|
|
171
|
+
Also run the narrowest relevant tests while iterating. Mark slow statistical,
|
|
172
|
+
validation, GPU, and example tests explicitly; ordinary tests must stay quick.
|
|
173
|
+
When sibling packages are installed, run `python -m pytest -m interop` as a
|
|
174
|
+
separate compatibility check.
|
|
175
|
+
|
|
176
|
+
Test public behavior, units, signs, shapes, failure modes, precision, and seeded
|
|
177
|
+
reproducibility. Statistical tests use ensemble uncertainty and non-flaky
|
|
178
|
+
tolerances. Independent reference packages such as HCIPy are optional validation
|
|
179
|
+
dependencies, never core dependencies.
|
|
180
|
+
|
|
181
|
+
When CUDA 12 CuPy and a device are available, also run `python -m pytest -q -m
|
|
182
|
+
gpu`. GPU tests are optional and must verify CPU optical parity, device-resident
|
|
183
|
+
detector/truth arrays, direct `pyturb` interoperability, and seeded detector
|
|
184
|
+
behavior; they must not make ordinary CI depend on CUDA.
|
|
185
|
+
|
|
186
|
+
For performance changes, run the affected warm and cold benchmarks and report the
|
|
187
|
+
hardware/dependency context. Do not claim a speedup from one timing sample or
|
|
188
|
+
weaken physics accuracy to win a benchmark without an explicit documented mode.
|
|
189
|
+
The representative CI guard is reproducible locally with:
|
|
190
|
+
|
|
191
|
+
```bash
|
|
192
|
+
python benchmarks/run.py --representative --frames 1 --output /tmp/makewfs-benchmark.json
|
|
193
|
+
python benchmarks/check_regression.py /tmp/makewfs-benchmark.json
|
|
194
|
+
MPLBACKEND=Agg python examples/gallery.py
|
|
195
|
+
```
|
|
196
|
+
|
|
197
|
+
## Documentation and examples
|
|
198
|
+
|
|
199
|
+
- Every public feature lands with its API docstring and the relevant user guide.
|
|
200
|
+
- Every configuration field appears in the configuration reference with units,
|
|
201
|
+
default, allowed range, interactions, and an example.
|
|
202
|
+
- Examples are scripts plus TOML, deterministic by default, headless, and able to
|
|
203
|
+
save plots. Give them a reduced CI mode; never rely on an interactive notebook
|
|
204
|
+
as the only executable form.
|
|
205
|
+
- Plot labels include units and state whether an image is ideal photon rate,
|
|
206
|
+
expected electrons, or noisy ADU.
|
|
207
|
+
- Be explicit about approximations, especially partial sampling, chromatic
|
|
208
|
+
pyramid behavior, LGS mean-altitude OPD, and detector cropping.
|
|
209
|
+
- Update `CHANGELOG.md` under Unreleased for user-visible changes.
|
|
210
|
+
|
|
211
|
+
## Roadmap and handoff discipline
|
|
212
|
+
|
|
213
|
+
- Work in dependency order. Shared contracts/ADRs precede parallel sensor work.
|
|
214
|
+
- Take bounded vertical slices; avoid sweeping “implement a whole phase” changes.
|
|
215
|
+
- Check a roadmap box only when implementation, tests, docs, and required
|
|
216
|
+
validation/benchmark are all complete and passing.
|
|
217
|
+
- Do not mark conditional sibling work as required until its gate is demonstrated.
|
|
218
|
+
- At handoff, summarize files changed, assumptions, physics/reference basis,
|
|
219
|
+
commands run and results, benchmark impact, and remaining roadmap items.
|
|
220
|
+
- Maintain this file: update it when the repository layout, quality-gate commands,
|
|
221
|
+
stable contracts, or current implementation stage changes.
|
|
222
|
+
- If blocked, document the exact failing contract and evidence. Do not work around
|
|
223
|
+
it by absorbing atmosphere or detector behavior into this repository.
|
|
@@ -0,0 +1,130 @@
|
|
|
1
|
+
# Changelog
|
|
2
|
+
|
|
3
|
+
All notable changes to `makewfs` are documented here.
|
|
4
|
+
|
|
5
|
+
## [Unreleased]
|
|
6
|
+
|
|
7
|
+
## [1.0.0] - 2026-07-26
|
|
8
|
+
|
|
9
|
+
- Prepared the first stable public release with versioned package metadata,
|
|
10
|
+
PyPI/CI badges, citation and release documentation, and a trusted-publishing
|
|
11
|
+
GitHub Actions workflow using the `pypi` environment.
|
|
12
|
+
- Fixed the benchmark runner on Python 3.10 by using the portable
|
|
13
|
+
`datetime.timezone.utc` API.
|
|
14
|
+
- Raised the detector dependency to released `getframes>=2.1.1`, made
|
|
15
|
+
wavelength-resolved detector QE and full spectral truth part of the supported
|
|
16
|
+
contract, and removed the pre-release integrated-signal compatibility path.
|
|
17
|
+
- Added an R-band HAKA camera-LUT analysis using representative A0 V through M3
|
|
18
|
+
V continua and generated open-loop Maunakea states. It reports mean active
|
|
19
|
+
4x4-lenslet intensity SNR with OCAM2K photon, EM-excess, dark, CIC, read, and
|
|
20
|
+
quantization noise, fits a smooth ceiling-aware broken-power-law cadence floor
|
|
21
|
+
only to the R>=10 fine-adjustment tail, asymptotes to the true 2067 Hz OCAM2K
|
|
22
|
+
limit, and emits a smooth saturation-constrained policy that never slows below
|
|
23
|
+
that empirical model merely to recover per-frame SNR.
|
|
24
|
+
- Generalized the HAKA broadband photon-budget helper from fixed Johnson V
|
|
25
|
+
normalization to an explicit Johnson normalization band, retaining V as the
|
|
26
|
+
showcase and eng519 default.
|
|
27
|
+
- Fixed temporal integration to average and forward wavelength-resolved photon
|
|
28
|
+
cubes to the detector, preserving configured spectral QE instead of silently
|
|
29
|
+
falling back to scalar QE.
|
|
30
|
+
- Fixed even-sized Shack-Hartmann focal-plane registration: zero slope now lies
|
|
31
|
+
at the intersection of the central four detector pixels, using half-integer
|
|
32
|
+
Fourier samples rather than an asymmetric integer-grid crop.
|
|
33
|
+
- Added a Keck II HAKA open-loop worked example with a generated 36-segment
|
|
34
|
+
Keck pupil including a live-data-fitted circle-plus-hexagon secondary shadow
|
|
35
|
+
and six 26 mm support arms, exact
|
|
36
|
+
57x57-by-4x4 (228x228) Shack-Hartmann/OCAM2K geometry,
|
|
37
|
+
magnitude-dependent EM gain and frame rate, temporally integrated `pyturb`
|
|
38
|
+
Maunakea OPD, exposure-matched master-dark subtraction, GIF/MP4 output, and a
|
|
39
|
+
reproducibility manifest with per-frame photon/electron/count flux auditing.
|
|
40
|
+
The supplied real eng519 V=10.16 RTC cube constrains the roughly 54-lenslet pupil
|
|
41
|
+
diameter, compact quadcell sampling, and the eight-output 4x2 OCAM geometry,
|
|
42
|
+
outside-pupil dark/bias levels, and relative conversion gains. With no matched
|
|
43
|
+
dark cube, the RTC comparison subtracts a per-output/repeated-4x4 template and
|
|
44
|
+
per-frame output drift inferred outside the pupil, then reports real and
|
|
45
|
+
simulated lenslet signal/morphology without global rescaling. The
|
|
46
|
+
eng519 comparison now simulates V=10.16 at 750 fps, retains every tenth
|
|
47
|
+
generated phase-screen exposure like the telemetry, and writes a side-by-side
|
|
48
|
+
GIF. The magnitude showcase advances frozen flow by a visible minimum cadence
|
|
49
|
+
at every magnitude without changing the physical detector exposure. HAKA NGS
|
|
50
|
+
photon formation now integrates a V-normalized 6600 K spectrum over the full
|
|
51
|
+
400--950 nm band, applies measured Mauna Kea extinction at the observed
|
|
52
|
+
airmass, applies 0.88 reflectivity to the aluminum primary, secondary, and
|
|
53
|
+
tertiary, uses the sampled clear-pupil collecting area, and passes the
|
|
54
|
+
resolved spectral cube through OCAM2K's wavelength-dependent QE. The reference
|
|
55
|
+
renders now use the Keck-characterized approximately 28 output e-/ADU OCAM2K
|
|
56
|
+
conversion. Team-confirmed independent bench measurements now establish the
|
|
57
|
+
downstream HAKA throughput as 28.7%; it is applied as physical radiometry after
|
|
58
|
+
the telescope mirrors rather than inferred or fitted by the RTC comparison.
|
|
59
|
+
The regenerated eng519 comparison has a real/simulation signal ratio of
|
|
60
|
+
1.00029.
|
|
61
|
+
- Added a reproducible warm HAKA CPU/GPU benchmark. It times non-periodic Mauna
|
|
62
|
+
Kea atmosphere evolution, the full eight-wavelength 57x57 Shack--Hartmann
|
|
63
|
+
propagation, and noisy OCAM2K exposure while excluding static setup and
|
|
64
|
+
synchronizing CUDA batches. Its local GIF shows CPU/GPU detector streams over
|
|
65
|
+
equal wall-clock playback with measured FPS, real-time factor, frame counter,
|
|
66
|
+
and atmosphere time overlays.
|
|
67
|
+
- Removed generated PNG/GIF artifacts from version control and ignore them
|
|
68
|
+
globally; example scripts continue to create them locally on demand.
|
|
69
|
+
- Added public end-to-end GPU execution through `numerics.device = "gpu"`.
|
|
70
|
+
CuPy OPD, SH/PWFS optics, wavelength-resolved photon maps, the `getframes`
|
|
71
|
+
detector chain, truth, and ADU remain device-resident. The runtime reports an
|
|
72
|
+
actionable error when the installed `getframes` lacks its GPU camera contract.
|
|
73
|
+
- Added direct `pyturb` GPU OPD → Shack–Hartmann → GPU ADU integration coverage,
|
|
74
|
+
updated SH/PWFS CUDA parity tests, synchronized GPU benchmark mode, and measured
|
|
75
|
+
detector-only timing.
|
|
76
|
+
- Added a paired CPU/GPU bulk-throughput artifact and rendered comparison for
|
|
77
|
+
representative SH, broadband LGS, and modulated pyramid workflows, with
|
|
78
|
+
README and performance-guide results plus exact reproduction commands.
|
|
79
|
+
- Optimized persistent SH/PWFS execution by caching source/range geometry,
|
|
80
|
+
modulation phasors, resampling grids, flux normalization, and monochromatic
|
|
81
|
+
spectral views; using native orthonormal FFT scaling and an intensity-only SH
|
|
82
|
+
transform; removing redundant validations/resampling; and batching GPU
|
|
83
|
+
metadata scalar transfers. On the RTX 5090 reference matrix this improves CPU
|
|
84
|
+
throughput by 1.19x–1.73x and GPU throughput by 1.42x–2.58x over the initial
|
|
85
|
+
end-to-end implementation while retaining the physics/parity gates.
|
|
86
|
+
|
|
87
|
+
- Expanded optical verification with a direct-DFT pyramid reference,
|
|
88
|
+
multi-amplitude HCIPy SH response curves, HCIPy low-order pyramid response
|
|
89
|
+
maps, supplementary local OOPAO comparisons, and quantitative SH/pyramid
|
|
90
|
+
metrics in the deterministic validation report.
|
|
91
|
+
- Fixed the pyramid propagation grid to honor `numerics.fft_oversampling`, so
|
|
92
|
+
the diffraction halo no longer wraps onto the pupil rims; cropped flux is
|
|
93
|
+
reported as captured rate and independent HCIPy parity improved.
|
|
94
|
+
- Reconfigured the shipped example TOMLs to be representative demonstrations:
|
|
95
|
+
pyramid pupils are now separated (`pupil_separation_pixels` larger than
|
|
96
|
+
`pixels_across_pupil`) and source photon rates correspond to a bright guide
|
|
97
|
+
star so detector frames show spots above read noise.
|
|
98
|
+
- Added deterministic broadband/finite-source quadrature, measured SED and
|
|
99
|
+
transmission curves, physical SH sampling, field stops, optical blur,
|
|
100
|
+
detector margins, and sodium-range SH elongation examples.
|
|
101
|
+
- Added strict configuration-reference documentation for every v1 table and
|
|
102
|
+
key, plus validation and benchmark smoke reports in CI.
|
|
103
|
+
- Added headless worked-example CI smoke tests, deterministic plotting backend
|
|
104
|
+
selection, and a 90% enforced branch-coverage gate.
|
|
105
|
+
- Added configuration-relative three-column angular source kernels for measured
|
|
106
|
+
or resolved guide-star morphologies, with normalized state provenance.
|
|
107
|
+
- Added rotated analytic segment-gap pupils and a cached physical-coordinate
|
|
108
|
+
lenslet-grid rotation/offset path with aligned-grid parity tests.
|
|
109
|
+
- Added an optional HCIPy ideal-pyramid cross-check and a dedicated validation
|
|
110
|
+
CI job; HCIPy remains outside runtime dependencies.
|
|
111
|
+
- Added configuration-relative measured SH optical blur kernels with unit-sum
|
|
112
|
+
validation, cached convolution, and provenance hashes.
|
|
113
|
+
- Added a public API/configuration stability audit and same-run benchmark
|
|
114
|
+
regression envelopes for representative CPU kernels.
|
|
115
|
+
- Added versioned benchmark snapshots and isolated non-editable-wheel
|
|
116
|
+
interoperability verification for `pyturb` 1.0 and `getframes`.
|
|
117
|
+
- Added a versioned labelled SVG capability gallery with units, color bars,
|
|
118
|
+
seeds, configuration digests, and modeling notes.
|
|
119
|
+
- Added wavelength-resolved detector QE through the public `getframes` spectral
|
|
120
|
+
cube contract, with truth preservation and a shipped comparison example.
|
|
121
|
+
- Formalized the private optical `ArrayBackend` boundary and added static
|
|
122
|
+
leakage/parity checks so a future device backend does not require sensor
|
|
123
|
+
mathematics to be rewritten.
|
|
124
|
+
- Added the original private CUDA 12 CuPy optical path with SH/pyramid parity
|
|
125
|
+
tests; it is retained as a compatibility hook underneath the public
|
|
126
|
+
configuration-driven GPU path.
|
|
127
|
+
- Added the monochromatic CPU four-face pyramid engine, modulation support, a
|
|
128
|
+
complete pyramid example configuration, and symmetry/flux/detector tests.
|
|
129
|
+
- Added the implementation roadmap and agent guide.
|
|
130
|
+
- Added the initial configuration and numerical implementation foundation.
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
cff-version: 1.2.0
|
|
2
|
+
message: "If you use makewfs in your research, please cite this software."
|
|
3
|
+
title: "makewfs: configuration-driven adaptive-optics wavefront-sensor image simulation"
|
|
4
|
+
type: software
|
|
5
|
+
authors:
|
|
6
|
+
- family-names: Taylor
|
|
7
|
+
given-names: Jacob
|
|
8
|
+
version: 1.0.0
|
|
9
|
+
date-released: 2026-07-26
|
|
10
|
+
license: MIT
|
|
11
|
+
repository-code: "https://github.com/jacotay7/makewfs"
|
|
12
|
+
url: "https://jacotay7.github.io/makewfs/"
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
# Contributing to makewfs
|
|
2
|
+
|
|
3
|
+
`makewfs` is a numerical optics package. A contribution is complete only when
|
|
4
|
+
its behavior, units, tests, documentation, and performance implications are
|
|
5
|
+
clear.
|
|
6
|
+
|
|
7
|
+
Read [AGENTS.md](AGENTS.md) and the relevant section of [ROADMAP.md](ROADMAP.md)
|
|
8
|
+
before starting. Keep atmosphere physics in `pyturb` and detector physics in
|
|
9
|
+
`getframes`.
|
|
10
|
+
|
|
11
|
+
## Development setup
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
python -m venv .venv
|
|
15
|
+
source .venv/bin/activate
|
|
16
|
+
python -m pip install -e ".[dev,examples]"
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
For local sibling development, install the checked-out packages separately:
|
|
20
|
+
|
|
21
|
+
```bash
|
|
22
|
+
python -m pip install -e ../getframes
|
|
23
|
+
python -m pip install -e ../pyturb
|
|
24
|
+
```
|
|
25
|
+
|
|
26
|
+
## Quality gate
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
ruff check .
|
|
30
|
+
ruff format --check .
|
|
31
|
+
mypy
|
|
32
|
+
python -m pytest -q --cov=makewfs --cov-branch --cov-report=term-missing
|
|
33
|
+
mkdocs build --strict
|
|
34
|
+
python -m build
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
Physics changes require an analytic or independent-reference assertion. Keep
|
|
38
|
+
randomness on explicit seeded generators, state all array units, and update the
|
|
39
|
+
configuration reference and changelog for public changes.
|
|
40
|
+
|
|
41
|
+
## Pull requests
|
|
42
|
+
|
|
43
|
+
Keep changes focused. Describe the numerical model, source/reference used for
|
|
44
|
+
validation, tests run, benchmark impact, and any conditional upstream work.
|
makewfs-1.0.0/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Jacob Taylor
|
|
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.
|