obdeect 0.6.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.
Files changed (98) hide show
  1. obdeect-0.6.0/.clang-format +5 -0
  2. obdeect-0.6.0/.clang-tidy +17 -0
  3. obdeect-0.6.0/.editorconfig +12 -0
  4. obdeect-0.6.0/.gitattributes +7 -0
  5. obdeect-0.6.0/.github/workflows/ci.yml +33 -0
  6. obdeect-0.6.0/.github/workflows/docs.yml +61 -0
  7. obdeect-0.6.0/.github/workflows/pypi.yml +98 -0
  8. obdeect-0.6.0/.github/workflows/tests.yml +54 -0
  9. obdeect-0.6.0/.gitignore +32 -0
  10. obdeect-0.6.0/.pre-commit-config.yaml +64 -0
  11. obdeect-0.6.0/AGENTS.md +83 -0
  12. obdeect-0.6.0/CHANGELOG.md +123 -0
  13. obdeect-0.6.0/CITATION.cff +13 -0
  14. obdeect-0.6.0/CMakeLists.txt +85 -0
  15. obdeect-0.6.0/CMakePresets.json +55 -0
  16. obdeect-0.6.0/LICENSE +29 -0
  17. obdeect-0.6.0/PKG-INFO +132 -0
  18. obdeect-0.6.0/README.md +74 -0
  19. obdeect-0.6.0/cpp/bench/bench_trace.cpp +331 -0
  20. obdeect-0.6.0/cpp/bench/replay.cpp +302 -0
  21. obdeect-0.6.0/cpp/bench/replay_compare.hpp +163 -0
  22. obdeect-0.6.0/cpp/bindings/README.md +21 -0
  23. obdeect-0.6.0/cpp/bindings/core.cpp +522 -0
  24. obdeect-0.6.0/cpp/include/obdeect/bounds.hpp +65 -0
  25. obdeect-0.6.0/cpp/include/obdeect/bunches.hpp +276 -0
  26. obdeect-0.6.0/cpp/include/obdeect/json.hpp +194 -0
  27. obdeect-0.6.0/cpp/include/obdeect/model.hpp +77 -0
  28. obdeect-0.6.0/cpp/include/obdeect/model_json.hpp +488 -0
  29. obdeect-0.6.0/cpp/include/obdeect/obscurers.hpp +763 -0
  30. obdeect-0.6.0/cpp/include/obdeect/random.hpp +47 -0
  31. obdeect-0.6.0/cpp/include/obdeect/source.hpp +177 -0
  32. obdeect-0.6.0/cpp/include/obdeect/surfaces.hpp +931 -0
  33. obdeect-0.6.0/cpp/include/obdeect/table.hpp +74 -0
  34. obdeect-0.6.0/cpp/include/obdeect/trace.hpp +666 -0
  35. obdeect-0.6.0/cpp/include/obdeect/vec.hpp +42 -0
  36. obdeect-0.6.0/cpp/tests/check.hpp +43 -0
  37. obdeect-0.6.0/cpp/tests/data/make_polynomial_reference.py +82 -0
  38. obdeect-0.6.0/cpp/tests/legacy_asphere.hpp +158 -0
  39. obdeect-0.6.0/cpp/tests/test_asphere_steps.cpp +43 -0
  40. obdeect-0.6.0/cpp/tests/test_bounds.cpp +163 -0
  41. obdeect-0.6.0/cpp/tests/test_kernels.cpp +1236 -0
  42. obdeect-0.6.0/cpp/tests/test_model_json.cpp +97 -0
  43. obdeect-0.6.0/cpp/tests/test_replay_compare.cpp +162 -0
  44. obdeect-0.6.0/cpp/tests/test_trace.cpp +650 -0
  45. obdeect-0.6.0/docs/VALIDATION.md +348 -0
  46. obdeect-0.6.0/docs/_static/figures/baffle_area.png +0 -0
  47. obdeect-0.6.0/docs/_static/figures/mst_shadowing.png +0 -0
  48. obdeect-0.6.0/docs/_static/figures/telescope_lst.png +0 -0
  49. obdeect-0.6.0/docs/_static/figures/telescope_mst_flashcam.png +0 -0
  50. obdeect-0.6.0/docs/_static/figures/telescope_mst_nectarcam.png +0 -0
  51. obdeect-0.6.0/docs/_static/figures/telescope_sct.png +0 -0
  52. obdeect-0.6.0/docs/_static/figures/telescope_sst.png +0 -0
  53. obdeect-0.6.0/docs/_static/figures/telescopes-provenance.json +80 -0
  54. obdeect-0.6.0/docs/_static/figures/validation_psf_area.png +0 -0
  55. obdeect-0.6.0/docs/_static/images/obdeect_21ratio_large.jpg +0 -0
  56. obdeect-0.6.0/docs/_static/images/obdeect_21ratio_small.jpg +0 -0
  57. obdeect-0.6.0/docs/_static/images/obdeect_large.jpg +0 -0
  58. obdeect-0.6.0/docs/_static/images/obdeect_logo.jpg +0 -0
  59. obdeect-0.6.0/docs/_static/images/obdeect_small.jpg +0 -0
  60. obdeect-0.6.0/docs/_static/obdeect.css +55 -0
  61. obdeect-0.6.0/docs/api.md +32 -0
  62. obdeect-0.6.0/docs/batch-tracing.md +97 -0
  63. obdeect-0.6.0/docs/build_versions.py +165 -0
  64. obdeect-0.6.0/docs/changelog.md +2 -0
  65. obdeect-0.6.0/docs/changes/.gitkeep +0 -0
  66. obdeect-0.6.0/docs/conf.py +74 -0
  67. obdeect-0.6.0/docs/figures/make_figures.py +121 -0
  68. obdeect-0.6.0/docs/figures/telescopes.yml +68 -0
  69. obdeect-0.6.0/docs/index.md +81 -0
  70. obdeect-0.6.0/docs/installation.md +38 -0
  71. obdeect-0.6.0/docs/light-sources.md +80 -0
  72. obdeect-0.6.0/docs/limitations.md +69 -0
  73. obdeect-0.6.0/docs/optical-elements.md +91 -0
  74. obdeect-0.6.0/docs/optical-models.md +31 -0
  75. obdeect-0.6.0/docs/optics.md +36 -0
  76. obdeect-0.6.0/docs/python-guide.md +54 -0
  77. obdeect-0.6.0/docs/shadowing.md +56 -0
  78. obdeect-0.6.0/docs/telescopes.md +67 -0
  79. obdeect-0.6.0/docs/usage.md +32 -0
  80. obdeect-0.6.0/docs/user-guide.md +15 -0
  81. obdeect-0.6.0/pyproject.toml +66 -0
  82. obdeect-0.6.0/python/obdeect/__init__.py +26 -0
  83. obdeect-0.6.0/python/obdeect/cli.py +168 -0
  84. obdeect-0.6.0/python/obdeect/compiler.py +909 -0
  85. obdeect-0.6.0/python/obdeect/formats.py +393 -0
  86. obdeect-0.6.0/python/obdeect/model.py +524 -0
  87. obdeect-0.6.0/python/obdeect/plot.py +78 -0
  88. obdeect-0.6.0/python/obdeect/propagation.py +49 -0
  89. obdeect-0.6.0/python/obdeect/psf.py +55 -0
  90. obdeect-0.6.0/python/obdeect/repository.py +171 -0
  91. obdeect-0.6.0/python/obdeect/simtel_tables.py +261 -0
  92. obdeect-0.6.0/python/tests/telescopes.py +187 -0
  93. obdeect-0.6.0/python/tests/test_bunches.py +366 -0
  94. obdeect-0.6.0/python/tests/test_compiler.py +213 -0
  95. obdeect-0.6.0/python/tests/test_docs_versions.py +70 -0
  96. obdeect-0.6.0/python/tests/test_formats.py +131 -0
  97. obdeect-0.6.0/python/tests/test_model.py +410 -0
  98. obdeect-0.6.0/python/tests/test_propagation.py +31 -0
@@ -0,0 +1,5 @@
1
+ ---
2
+ BasedOnStyle: LLVM
3
+ ColumnLimit: 100
4
+ IndentWidth: 2
5
+ SortIncludes: CaseSensitive
@@ -0,0 +1,17 @@
1
+ ---
2
+ Checks: >
3
+ -*,
4
+ bugprone-argument-comment,
5
+ bugprone-branch-clone,
6
+ bugprone-empty-catch,
7
+ bugprone-exception-escape,
8
+ bugprone-infinite-loop,
9
+ bugprone-macro-parentheses,
10
+ bugprone-suspicious-memset-usage,
11
+ bugprone-undefined-memory-manipulation,
12
+ performance-for-range-copy
13
+ WarningsAsErrors: '*'
14
+ HeaderFilterRegex: 'cpp/include/obdeect/.*'
15
+ CheckOptions:
16
+ - key: readability-identifier-length.MinimumVariableNameLength
17
+ value: '2'
@@ -0,0 +1,12 @@
1
+ root = true
2
+
3
+ [*]
4
+ charset = utf-8
5
+ end_of_line = lf
6
+ insert_final_newline = true
7
+ indent_style = space
8
+ indent_size = 2
9
+ trim_trailing_whitespace = true
10
+
11
+ [*.py]
12
+ indent_size = 4
@@ -0,0 +1,7 @@
1
+ * text=auto eol=lf
2
+
3
+ *.cpp text diff=cpp
4
+ *.hpp text diff=cpp
5
+ *.py text diff=python
6
+ *.yml text
7
+ *.yaml text
@@ -0,0 +1,33 @@
1
+ ---
2
+ name: CI-linter
3
+
4
+ on:
5
+ push:
6
+ branches:
7
+ - main
8
+ pull_request:
9
+
10
+ concurrency:
11
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
12
+ cancel-in-progress: true
13
+
14
+ jobs:
15
+ lint:
16
+ runs-on: ubuntu-24.04
17
+ steps:
18
+ - uses: actions/checkout@v7
19
+ with:
20
+ fetch-depth: 0
21
+ - uses: actions/setup-python@v7
22
+ with:
23
+ python-version: '3.14'
24
+ - name: Install linters
25
+ run: python -m pip install --upgrade pip pre-commit ruff clang-format
26
+ - name: Run repository hooks
27
+ run: pre-commit run --all-files
28
+ - name: Check Python formatting and lint
29
+ run: ruff format --check python && ruff check python
30
+ - name: Check C++ formatting
31
+ run: >-
32
+ find cpp -type f \( -name '*.cpp' -o -name '*.hpp' \) -print0
33
+ | xargs -0 clang-format --dry-run --Werror
@@ -0,0 +1,61 @@
1
+ ---
2
+ name: CI-docs
3
+ # Publish dev and release documentation together, preserving root URLs.
4
+
5
+ on:
6
+ pull_request:
7
+ push:
8
+ branches:
9
+ - main
10
+ tags:
11
+ - "v*"
12
+ workflow_dispatch:
13
+
14
+ concurrency:
15
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || 'pages' }}
16
+ cancel-in-progress: true
17
+
18
+ jobs:
19
+ build:
20
+ runs-on: ubuntu-24.04
21
+ permissions:
22
+ contents: read
23
+ steps:
24
+ - uses: actions/checkout@v7
25
+ with:
26
+ fetch-depth: 0
27
+ - uses: actions/setup-python@v7
28
+ with:
29
+ python-version: "3.14"
30
+ - name: Install obdeect with the documentation tools
31
+ run: python -m pip install --upgrade pip && python -m pip install ".[docs]"
32
+ - name: Test documentation publishing
33
+ run: |
34
+ python -m pip install pytest
35
+ python -m pytest -q python/tests/test_docs_versions.py
36
+ - name: Build versioned site
37
+ env:
38
+ DOCS_BASE_URL: https://${{ github.repository_owner }}.github.io/${{ github.event.repository.name }}
39
+ run: |
40
+ args=(--output docs/_build/site --base-url "$DOCS_BASE_URL")
41
+ if [[ "$GITHUB_REF" == refs/tags/* ]]; then
42
+ args+=(--dev-ref origin/main)
43
+ fi
44
+ python docs/build_versions.py "${args[@]}"
45
+ - uses: actions/upload-pages-artifact@v5
46
+ with:
47
+ path: docs/_build/site
48
+
49
+ deploy:
50
+ if: github.event_name != 'pull_request' && (github.ref == 'refs/heads/main' || startsWith(github.ref, 'refs/tags/v'))
51
+ needs: build
52
+ runs-on: ubuntu-24.04
53
+ permissions:
54
+ pages: write
55
+ id-token: write
56
+ environment:
57
+ name: github-pages
58
+ url: ${{ steps.deployment.outputs.page_url }}
59
+ steps:
60
+ - id: deployment
61
+ uses: actions/deploy-pages@v5
@@ -0,0 +1,98 @@
1
+ ---
2
+ name: Build and publish obdeect
3
+
4
+ on:
5
+ pull_request:
6
+ push:
7
+ tags:
8
+ - "v*"
9
+ workflow_dispatch:
10
+ inputs:
11
+ publish_testpypi:
12
+ description: Publish the built distributions to TestPyPI
13
+ required: false
14
+ type: boolean
15
+ default: false
16
+
17
+ permissions:
18
+ contents: read
19
+
20
+ jobs:
21
+ wheels:
22
+ strategy:
23
+ fail-fast: false
24
+ matrix:
25
+ os: [ubuntu-24.04, ubuntu-24.04-arm, macos-15]
26
+ runs-on: ${{ matrix.os }}
27
+ steps:
28
+ - uses: actions/checkout@v7
29
+ with:
30
+ ref: ${{ github.ref }}
31
+ - uses: actions/setup-python@v7
32
+ with:
33
+ python-version: "3.14"
34
+ - name: Install wheel tooling
35
+ run: python -m pip install --upgrade cibuildwheel
36
+ - name: Build and smoke-test wheels
37
+ env:
38
+ CIBW_BUILD: "cp314-*"
39
+ CIBW_TEST_REQUIRES: "pytest scipy"
40
+ CIBW_TEST_COMMAND: python -m pytest {project}/python/tests -q
41
+ run: python -m cibuildwheel --output-dir wheelhouse
42
+ - uses: actions/upload-artifact@v7
43
+ with:
44
+ name: wheels-${{ matrix.os }}
45
+ path: wheelhouse/*.whl
46
+
47
+ sdist:
48
+ runs-on: ubuntu-24.04
49
+ steps:
50
+ - uses: actions/checkout@v7
51
+ with:
52
+ ref: ${{ github.ref }}
53
+ - uses: actions/setup-python@v7
54
+ with:
55
+ python-version: "3.14"
56
+ - name: Build source distribution
57
+ run: |
58
+ python -m pip install --upgrade build
59
+ python -m build --sdist --outdir dist
60
+ - uses: actions/upload-artifact@v7
61
+ with:
62
+ name: sdist
63
+ path: dist/*.tar.gz
64
+
65
+ publish:
66
+ if: github.event_name == 'push' && startsWith(github.ref, 'refs/tags/v')
67
+ needs: [wheels, sdist]
68
+ runs-on: ubuntu-24.04
69
+ environment: pypi
70
+ permissions:
71
+ id-token: write
72
+ steps:
73
+ - uses: actions/download-artifact@v8
74
+ with:
75
+ path: dist
76
+ merge-multiple: true
77
+ - name: Publish distributions to PyPI
78
+ uses: pypa/gh-action-pypi-publish@release/v1
79
+
80
+ publish-testpypi:
81
+ if: >-
82
+ ${{
83
+ github.event_name == 'workflow_dispatch' && inputs.publish_testpypi
84
+ }}
85
+ needs: [wheels, sdist]
86
+ runs-on: ubuntu-24.04
87
+ environment: testpypi
88
+ permissions:
89
+ id-token: write
90
+ steps:
91
+ - uses: actions/download-artifact@v8
92
+ with:
93
+ path: dist
94
+ merge-multiple: true
95
+ - name: Publish distributions to TestPyPI
96
+ uses: pypa/gh-action-pypi-publish@release/v1
97
+ with:
98
+ repository-url: https://test.pypi.org/legacy/
@@ -0,0 +1,54 @@
1
+ ---
2
+ name: CI-tests
3
+
4
+ on:
5
+ push:
6
+ branches:
7
+ - main
8
+ pull_request:
9
+
10
+ concurrency:
11
+ group: ${{ github.workflow }}-${{ github.event.pull_request.number || github.ref }}
12
+ cancel-in-progress: true
13
+
14
+ permissions:
15
+ contents: read
16
+
17
+ jobs:
18
+ build-and-test:
19
+ strategy:
20
+ fail-fast: false
21
+ matrix:
22
+ runner: [ubuntu-24.04, macos-15]
23
+ runs-on: ${{ matrix.runner }}
24
+ steps:
25
+ - uses: actions/checkout@v7
26
+ - uses: actions/setup-python@v7
27
+ with:
28
+ python-version: '3.14'
29
+ - name: Install Python package and test dependencies
30
+ run: python -m pip install --upgrade pip && python -m pip install . pytest scipy
31
+ - name: Configure and build
32
+ run: cmake -S . -B build -DCMAKE_BUILD_TYPE=Release && cmake --build build --parallel
33
+ - name: Run native and Python tests
34
+ run: ctest --test-dir build --output-on-failure && pytest python/tests
35
+ fma:
36
+ runs-on: ubuntu-24.04
37
+ steps:
38
+ - uses: actions/checkout@v7
39
+ - name: Configure, build, and test with OBDEECT_USE_FMA
40
+ run: >-
41
+ cmake -S . -B build-fma -DCMAKE_BUILD_TYPE=Release -DOBDEECT_USE_FMA=ON
42
+ && cmake --build build-fma --parallel
43
+ && ctest --test-dir build-fma --output-on-failure
44
+ sanitizers:
45
+ runs-on: ubuntu-24.04
46
+ steps:
47
+ - uses: actions/checkout@v7
48
+ - name: Configure, build, and test with sanitizers
49
+ run: >-
50
+ cmake -S . -B build-sanitize -DCMAKE_BUILD_TYPE=Debug
51
+ -DCMAKE_CXX_FLAGS="-fsanitize=address,undefined -fno-omit-frame-pointer"
52
+ -DCMAKE_EXE_LINKER_FLAGS="-fsanitize=address,undefined"
53
+ && cmake --build build-sanitize --parallel
54
+ && ctest --test-dir build-sanitize --output-on-failure
@@ -0,0 +1,32 @@
1
+ # CMake and native build products
2
+ /build/
3
+ /out/
4
+ /compile_commands.json
5
+ /tmp_planning/
6
+ *.o
7
+ *.obj
8
+ *.a
9
+ *.so
10
+ *.dylib
11
+ *.dll
12
+
13
+ # Generated trace and visualisation products
14
+ *.npz
15
+ *.html
16
+
17
+ # Python
18
+ __pycache__/
19
+ *.py[cod]
20
+ .pytest_cache/
21
+ .ruff_cache/
22
+ .venv/
23
+ *.egg-info/
24
+ /dist/
25
+
26
+ # IDE and operating-system files
27
+ .DS_Store
28
+ .vscode/
29
+ .idea/
30
+
31
+ # Documentation build
32
+ /docs/_build/
@@ -0,0 +1,64 @@
1
+ ---
2
+ default_language_version:
3
+ python: python3.14
4
+
5
+ repos:
6
+ - repo: https://github.com/pre-commit/pre-commit-hooks
7
+ rev: v5.0.0
8
+ hooks:
9
+ - id: check-yaml
10
+ - id: check-json
11
+ - id: end-of-file-fixer
12
+ - id: trailing-whitespace
13
+ - repo: https://github.com/astral-sh/ruff-pre-commit
14
+ rev: v0.12.7
15
+ hooks:
16
+ - id: ruff-check
17
+ args: [--fix]
18
+ - id: ruff-format
19
+ # Github action
20
+ - repo: https://github.com/rhysd/actionlint
21
+ rev: v1.7.12
22
+ hooks:
23
+ - id: actionlint
24
+ # https://pyproject-fmt.readthedocs.io/en/latest/
25
+ - repo: https://github.com/tox-dev/pyproject-fmt
26
+ rev: "v2.29.2"
27
+ hooks:
28
+ - id: pyproject-fmt
29
+ # codespell
30
+ - repo: https://github.com/codespell-project/codespell
31
+ rev: v2.4.3
32
+ hooks:
33
+ - id: codespell
34
+ args: [
35
+ "--ignore-words-list=als,hel",
36
+ ]
37
+ # markdownlint
38
+ - repo: https://github.com/igorshubovych/markdownlint-cli
39
+ rev: v0.49.1
40
+ hooks:
41
+ - id: markdownlint
42
+ args: ["--disable", "MD041"]
43
+ # yamllint
44
+ - repo: https://github.com/adrienverge/yamllint.git
45
+ rev: v1.38.0
46
+ hooks:
47
+ - id: yamllint
48
+ args:
49
+ [
50
+ "--strict",
51
+ "-d",
52
+ '{extends: default, rules: {line-length: {max: 300}, indentation: {spaces: 2, indent-sequences: consistent}, truthy: {allowed-values: ["true", "false", "on", "off"]}}}'
53
+ ]
54
+ # towncrier
55
+ - repo: https://github.com/twisted/towncrier
56
+ rev: 25.8.0
57
+ hooks:
58
+ - id: towncrier-check
59
+ files: ^docs/changes/
60
+ # shellcheck
61
+ - repo: https://github.com/shellcheck-py/shellcheck-py
62
+ rev: v0.11.0.1-1
63
+ hooks:
64
+ - id: shellcheck
@@ -0,0 +1,83 @@
1
+ # obdeect Agent Guide
2
+
3
+ ## Scope
4
+
5
+ `obdeect` is a portable C++20 optical ray tracer with a thin Python interface.
6
+ It traces photons from a defined entrance surface to a focal/sensor surface.
7
+ Air-shower generation, electronics, triggers, and event writing are out of
8
+ scope. Read the relevant code and tests first; use the workspace plans and
9
+ validation matrix for architectural or scientific changes.
10
+
11
+ ## Design rules
12
+
13
+ - Never ever modify the main README.md. Suggest instead changes, don't apply them.
14
+ - Terminology: this project is for gamma-ray astronomy. Always call the
15
+ compiled telescope geometry and optical-response artifact an "optical model".
16
+ - Keep it simple, efficient, deterministic, and portable. Prefer small,
17
+ explicit data structures and testable physical kernels over frameworks,
18
+ global state, hidden defaults, or abstraction in the hot path.
19
+ - Keep the core C++ standard-library-only. Python, plotting, file import, and
20
+ external-simulator dependencies belong at the boundary, never in a trace
21
+ kernel.
22
+ - Use immutable compiled optical models and contiguous SoA photon buffers. After
23
+ output buffers are sized, the per-photon path must not allocate, perform I/O,
24
+ call Python, or dispatch virtually.
25
+ - Make units, frames, random seeds, statuses, and loss accounting explicit.
26
+ Reject invalid or unsupported input; never silently discard fields.
27
+
28
+ ## Data, not telescope-specific code
29
+
30
+ - Do not hardwire CTAO names, telescope geometry, model versions, file paths,
31
+ or optical/physics parameters into the core, public API, or defaults.
32
+ - Geometry, response tables, trace modes, and conventions are validated input
33
+ data. Model import produces a generic, provenance-recorded IR.
34
+ - CTAO support is an explicit importer/adapter or versioned fixture only. It
35
+ must not be required to build, test, or run the generic engine, and it must
36
+ never be an implicit fallback.
37
+ - Use python >3.14. Do not fall back to earlier versions.
38
+
39
+ ## Changes and validation
40
+
41
+ - Make the narrowest complete change and preserve unrelated work.
42
+ - Do not add anything under `docs/changes/` for current work. Leave that
43
+ directory untouched unless the user explicitly asks for a changelog or
44
+ release-note change.
45
+ - Add or update a focused test for every behavioural change. Establish analytic
46
+ kernel and primitive tests before optical-model, cross-tool, or performance tests.
47
+ - Preserve results across photon ordering, blocks, and thread counts. Record
48
+ provenance for fixtures and cross-tool comparisons.
49
+ - Do not weaken tolerances or replace golden data to hide a discrepancy. Keep
50
+ examples and fixtures clearly labelled and configuration-driven.
51
+ - When renaming a public concept, update implementation symbols, imports,
52
+ exception types, serialized keys, fixture variables, and test call sites
53
+ together. Do not leave obsolete geometry terminology in optical-model tests.
54
+
55
+ ## Build, test, and lint
56
+
57
+ Run from this directory. Configure before static analysis so the compilation
58
+ database is current.
59
+
60
+ ```bash
61
+ cmake --preset debug
62
+ cmake --build --preset debug
63
+ ctest --test-dir build/debug --output-on-failure
64
+ python -m pytest python/tests
65
+ ruff format --check python
66
+ ruff check python
67
+ find cpp -type f \( -name '*.cpp' -o -name '*.hpp' \) -print0 | \
68
+ xargs -0 clang-format --dry-run --Werror
69
+ ```
70
+
71
+ Ruff is configured with a 100-character line limit. Run `ruff format` before
72
+ `ruff check`, and manually wrap long strings or boolean expressions that the
73
+ formatter leaves unchanged.
74
+
75
+ After renames, search the affected Python files for removed symbols and run
76
+ the focused tests before the full suite. A clean handoff requires both
77
+ `ruff format --check python` and `ruff check python`; do not rely on a passing
78
+ test run alone because stale test references can fail collection or linting.
79
+
80
+ Run `clang-tidy -p build/debug cpp/src/<changed-file>.cpp` for changed C++
81
+ translation units when available, and `pre-commit run --all-files` before
82
+ handoff. Start with the smallest relevant test; run the full checks for shared
83
+ kernels, interfaces, configuration, or tooling changes.
@@ -0,0 +1,123 @@
1
+ # Changelog
2
+
3
+ This project follows [Keep a Changelog](https://keepachangelog.com/en/1.1.0/)
4
+ and uses semantic versioning after the first stable release.
5
+
6
+ ## [0.6.0]
7
+
8
+ ### Changed
9
+
10
+ - The PyPI distribution is named `obdeect`. Install with `pip install obdeect`.
11
+ The repository is hosted in the `gammasim` organisation.
12
+
13
+ ## [0.5.0]
14
+
15
+ Maintenance release: CI workflows and changelog. No change to the code or the Python API.
16
+
17
+ ### Changed
18
+
19
+ - The documentation workflow uses `actions/deploy-pages` v5 (Node.js 24).
20
+ - The publishing workflow uses `actions/download-artifact` v8. A download whose hash does not
21
+ match the expected hash now fails the workflow.
22
+ - The changelog is rebuilt from the git history for all releases from 0.1.0 on.
23
+
24
+ ## [0.4.0]
25
+
26
+ Performance release for the optical ray tracer, with additions to the Python API and the
27
+ command line. The optical-model format is unchanged (`obdeect.optical-model.v2`).
28
+
29
+ ### Added
30
+
31
+ - `OpticalModel.trace` keyword arguments `outputs`, `detected_only`, `classify_losses` and `pool`.
32
+ - `ThreadPool` (persistent worker pool) and `trace_many` (several telescopes in one call).
33
+ - `trace_bunches`, tracing of CORSIKA-style photon bunches.
34
+ - `OpticalModel.obscurer_hits` and the command `obdeect obscurers`: the obscurers on the path
35
+ of each photon, counted as `crossed`, `first` and `sole`.
36
+ - Optional fused multiply-add build, `-DOBDEECT_USE_FMA=ON` (x86-64, `-mfma`; off by default).
37
+ - CI job that builds and tests with `OBDEECT_USE_FMA=ON`.
38
+ - Documentation site (Sphinx, MyST Markdown) with the user guide, shadowing, telescope and optical
39
+ element descriptions, light sources, batch tracing, physics limitations and the Python API.
40
+ Figures show the telescope structure and the deviations from sim_telarray.
41
+ - Versioned documentation: development and tagged versions are published together to GitHub Pages,
42
+ with a version switcher.
43
+
44
+ ### Changed
45
+
46
+ - Obscurers are indexed per optical leg: a bounding-box hierarchy for every leg, and a uniform
47
+ x-y grid for the incoming leg and for the legs after the primary, walked cell by cell along the
48
+ ray.
49
+ - Aspheric mirrors stop at the single root of the ray when the slope bound guarantees one root.
50
+ A root in a segment gap is a miss, without scanning the aperture. Hits are unchanged.
51
+ - Segment membership on aspheric mirrors uses a cell grid with cached verdicts.
52
+ - Asphere sag and slope are evaluated as polynomials in r² (rounding-level change).
53
+ - `telescope_transmission` is checked by `response_bound`, which raises `ModelError` for an
54
+ unsupported transmission instead of accepting it.
55
+ - Replay comparison has tiers, used to check results across builds.
56
+ - Source comments and docstrings describe obdeect's own conventions instead of sim_telarray's.
57
+ No change in behaviour.
58
+
59
+ ### Fixed
60
+
61
+ - Secondary baffle: a fourth value not below R1 is read as the outer radius, as in sim_telarray,
62
+ instead of as the wall thickness. No current model uses this value.
63
+ - Bunch acceptance rejects axes that are not finite or not increasing; wavelength density nodes
64
+ must start above 0 nm.
65
+ - A failure while starting the thread pool no longer leaves joinable threads behind; an
66
+ exception in a task is rethrown to the caller and the remaining chunks are skipped.
67
+
68
+ ## [0.3.0]
69
+
70
+ Phase 2: calibration light.
71
+
72
+ ### Added
73
+
74
+ - Point emitters: `emitter_photons` makes weighted photons towards a target disk, with Poisson
75
+ statistics.
76
+ - `trace_emitter` and `trace_emitter_blocks`, which trace emitter light in blocks of 250,000
77
+ photons, so memory stays bounded.
78
+ - Direct tracing of photons that start inside the telescope (flashers), with `trace(direct=True)`.
79
+ - Documentation of the hand-off of photon bunches to sim_telarray for dual-mirror telescopes.
80
+
81
+ ### Changed
82
+
83
+ - Segment footprint frames are computed once per optical model. Results are bit-identical; SST
84
+ tracing is about 1.7 times faster.
85
+
86
+ ## [0.2.1]
87
+
88
+ ### Added
89
+
90
+ - Linux arm64 wheels.
91
+
92
+ ## [0.2.0]
93
+
94
+ Phase 1: optical models for in-process use by simtools, with sim_telarray equivalence.
95
+
96
+ ### Added
97
+
98
+ - Python API and `obdeect` command line with `compile`, `trace` and `plot`.
99
+ - Compilation of CTAO optical models from simulation-models: mirror lists, telescope structure
100
+ (one table with explicit shapes), telescope transmission, camera transport, patch productions.
101
+ - Photon diagnostics and CTAO validation scripts.
102
+ - Deterministic optical transport.
103
+
104
+ ### Changed
105
+
106
+ - Detector and ray-tracing seeds are separate.
107
+ - Legacy optical-model seeds are read compatibly.
108
+
109
+ ### Fixed
110
+
111
+ - Optical input validation and deterministic boundary selection.
112
+ - GCC header portability and the macOS wheel deployment target.
113
+
114
+ ## [0.1.0]
115
+
116
+ First version: a C++20 ray tracer with a Python package.
117
+
118
+ ### Added
119
+
120
+ - C++20 artificial 400-nm source, spherical primary and focal-screen tracer.
121
+ - Simple MST-inspired camera and four-mast pre-primary shadow model.
122
+ - CSV trace-path output and optional Matplotlib diagnostic plot.
123
+ - CMake, Python packaging, tests, linting CI, BSD-3-Clause license and citation metadata.
@@ -0,0 +1,13 @@
1
+ cff-version: 1.2.0
2
+ message: "If you use obdeect, please cite it using the metadata below."
3
+ title: "obdeect: Ray tracing for imaging atmospheric Cherenkov telescopes"
4
+ version: 0.1.0
5
+ date-released: 2026-09-18
6
+ license: BSD-3-Clause
7
+ type: software
8
+ authors:
9
+ - given-names: Gernot
10
+ family-names: Maier
11
+ affiliation: DESY
12
+ orcid: 'https://orcid.org/0000-0001-9868-4700'
13
+ abstract: "A C++20 IACT-only prototype for tracing photons through telescope optics and structure."