pychmp 0.1.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 (176) hide show
  1. pychmp-0.1.0/.gitattributes +6 -0
  2. pychmp-0.1.0/.github/ISSUE_TEMPLATE/bug_report.yml +24 -0
  3. pychmp-0.1.0/.github/ISSUE_TEMPLATE/feature_request.yml +18 -0
  4. pychmp-0.1.0/.github/pull_request_template.md +14 -0
  5. pychmp-0.1.0/.github/workflows/ci.yml +30 -0
  6. pychmp-0.1.0/.gitignore +25 -0
  7. pychmp-0.1.0/.zenodo.json +44 -0
  8. pychmp-0.1.0/CHANGELOG.md +52 -0
  9. pychmp-0.1.0/CITATION.cff +65 -0
  10. pychmp-0.1.0/CODEOWNERS +1 -0
  11. pychmp-0.1.0/CONTRIBUTING.md +53 -0
  12. pychmp-0.1.0/LICENSE +29 -0
  13. pychmp-0.1.0/PKG-INFO +286 -0
  14. pychmp-0.1.0/README.md +255 -0
  15. pychmp-0.1.0/development-notes/2026-03-27-eovsa-synoptic-download-fix.md +89 -0
  16. pychmp-0.1.0/development-notes/2026-03-27-soft-q0-and-sparse-grid-cli.md +191 -0
  17. pychmp-0.1.0/development-notes/2026-04-13-point-centric-artifact-migration.md +73 -0
  18. pychmp-0.1.0/development-notes/2026-05-24-shared-map-database-search-architecture.md +224 -0
  19. pychmp-0.1.0/development-notes/2026-05-28-chmp-fidelity-observation-shift-plan.md +124 -0
  20. pychmp-0.1.0/docs/artifact_data_contract.rst +424 -0
  21. pychmp-0.1.0/docs/conf.py +4 -0
  22. pychmp-0.1.0/docs/geometry_policy.rst +32 -0
  23. pychmp-0.1.0/docs/index.rst +17 -0
  24. pychmp-0.1.0/docs/provenance.rst +9 -0
  25. pychmp-0.1.0/docs/viewer_refresh_workflow.rst +124 -0
  26. pychmp-0.1.0/docs/workflow_architecture.md +425 -0
  27. pychmp-0.1.0/examples/README.md +404 -0
  28. pychmp-0.1.0/examples/__init__.py +1 -0
  29. pychmp-0.1.0/examples/benchmark_multi_scan_ab.py +168 -0
  30. pychmp-0.1.0/examples/benchmark_scan_ab_obs_map.py +271 -0
  31. pychmp-0.1.0/examples/convert_ab_scan_artifact_to_sparse.py +33 -0
  32. pychmp-0.1.0/examples/demo_gxrender_mw_adapter.py +69 -0
  33. pychmp-0.1.0/examples/download_fix_eovsa_synoptic.py +309 -0
  34. pychmp-0.1.0/examples/estimate_map_noise_cli.py +212 -0
  35. pychmp-0.1.0/examples/fit_q0_obs_map.py +2355 -0
  36. pychmp-0.1.0/examples/notebooks/README.md +13 -0
  37. pychmp-0.1.0/examples/plot_ab_scan_artifacts.py +400 -0
  38. pychmp-0.1.0/examples/pychmp_view.py +18 -0
  39. pychmp-0.1.0/examples/python/adaptive_ab_search_single_observation.py +5580 -0
  40. pychmp-0.1.0/examples/python/validate_q0_recovery_earth_eovsa_psf.py +260 -0
  41. pychmp-0.1.0/examples/q0_artifact_plot.py +10 -0
  42. pychmp-0.1.0/examples/replot_q0_artifacts.py +263 -0
  43. pychmp-0.1.0/examples/scan_ab_obs_map.py +3261 -0
  44. pychmp-0.1.0/examples/scan_synthetic_ab_grid.py +59 -0
  45. pychmp-0.1.0/examples/test_map_noise_manual.py +213 -0
  46. pychmp-0.1.0/examples/validate_q0_recovery.py +1671 -0
  47. pychmp-0.1.0/examples/validate_synthetic_q0_recovery.py +40 -0
  48. pychmp-0.1.0/pyproject.toml +77 -0
  49. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_01_r01.h5 +0 -0
  50. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_01_r01.h5.log +147 -0
  51. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_01_r01.h5.refresh +1 -0
  52. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_02_r01.h5 +0 -0
  53. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_02_r01.h5.log +147 -0
  54. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_02_r01.h5.refresh +1 -0
  55. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_03_r01.h5 +0 -0
  56. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_03_r01.h5.log +147 -0
  57. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_03_r01.h5.refresh +1 -0
  58. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_04_r01.h5 +0 -0
  59. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_04_r01.h5.log +147 -0
  60. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_04_r01.h5.refresh +1 -0
  61. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_05_r01.h5 +0 -0
  62. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_05_r01.h5.log +147 -0
  63. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_05_r01.h5.refresh +1 -0
  64. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_06_r01.h5 +0 -0
  65. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_06_r01.h5.log +147 -0
  66. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_06_r01.h5.refresh +1 -0
  67. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_07_r01.h5 +0 -0
  68. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_07_r01.h5.log +147 -0
  69. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_07_r01.h5.refresh +1 -0
  70. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_08_r01.h5 +0 -0
  71. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_08_r01.h5.log +147 -0
  72. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_08_r01.h5.refresh +1 -0
  73. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_09_r01.h5 +0 -0
  74. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_09_r01.h5.log +147 -0
  75. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_process-pool_09_r01.h5.refresh +1 -0
  76. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_serial_01_r01.h5 +0 -0
  77. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_serial_01_r01.h5.log +147 -0
  78. pychmp-0.1.0/reports/parallel benchmark test/artifacts/scan_ab_obs_map_serial_01_r01.h5.refresh +1 -0
  79. pychmp-0.1.0/reports/parallel benchmark test/generate_scan_ab_obs_map_benchmark_report.py +503 -0
  80. pychmp-0.1.0/reports/parallel benchmark test/scan_ab_obs_map_benchmark_2026-04-09.csv +11 -0
  81. pychmp-0.1.0/reports/parallel benchmark test/scan_ab_obs_map_benchmark_2026-04-09.md +143 -0
  82. pychmp-0.1.0/reports/parallel benchmark test/scan_ab_obs_map_benchmark_2026-04-09.pdf +0 -0
  83. pychmp-0.1.0/reports/parallel benchmark test/scan_ab_obs_map_benchmark_2026-04-09.png +0 -0
  84. pychmp-0.1.0/reports/parallel benchmark test/scan_ab_obs_map_benchmark_2026-04-13.csv +11 -0
  85. pychmp-0.1.0/reports/parallel benchmark test/scan_ab_obs_map_benchmark_2026-04-13.md +143 -0
  86. pychmp-0.1.0/reports/parallel benchmark test/scan_ab_obs_map_benchmark_2026-04-13.pdf +0 -0
  87. pychmp-0.1.0/reports/parallel benchmark test/scan_ab_obs_map_benchmark_2026-04-13.png +0 -0
  88. pychmp-0.1.0/scripts/README.md +827 -0
  89. pychmp-0.1.0/scripts/unix/adaptive_ab_search_single_observation_options_test.sh +568 -0
  90. pychmp-0.1.0/scripts/unix/benchmark_scan_ab_obs_map.sh +242 -0
  91. pychmp-0.1.0/scripts/unix/fit_q0_obs_map_options_test.sh +365 -0
  92. pychmp-0.1.0/scripts/unix/scan_ab_obs_map_options_test.sh +412 -0
  93. pychmp-0.1.0/scripts/unix/validate_q0_recovery_options_test.sh +270 -0
  94. pychmp-0.1.0/scripts/windows/adaptive_ab_search_single_observation_options_test.cmd +469 -0
  95. pychmp-0.1.0/scripts/windows/benchmark_scan_ab_obs_map.cmd +283 -0
  96. pychmp-0.1.0/scripts/windows/fit_q0_obs_map_options_test.cmd +290 -0
  97. pychmp-0.1.0/scripts/windows/scan_ab_obs_map_options_test.cmd +317 -0
  98. pychmp-0.1.0/scripts/windows/validate_q0_recovery_options_test.cmd +234 -0
  99. pychmp-0.1.0/src/pychmp/__init__.py +117 -0
  100. pychmp-0.1.0/src/pychmp/__main__.py +5 -0
  101. pychmp-0.1.0/src/pychmp/ab_scan_artifacts.py +6307 -0
  102. pychmp-0.1.0/src/pychmp/ab_scan_execution.py +160 -0
  103. pychmp-0.1.0/src/pychmp/ab_scan_tasks.py +114 -0
  104. pychmp-0.1.0/src/pychmp/ab_search.py +1856 -0
  105. pychmp-0.1.0/src/pychmp/chmp_evaluation.py +295 -0
  106. pychmp-0.1.0/src/pychmp/cli.py +145 -0
  107. pychmp-0.1.0/src/pychmp/fits_utils.py +136 -0
  108. pychmp-0.1.0/src/pychmp/fitting.py +308 -0
  109. pychmp-0.1.0/src/pychmp/geometry_policy.py +178 -0
  110. pychmp-0.1.0/src/pychmp/grid_points.py +1469 -0
  111. pychmp-0.1.0/src/pychmp/gxrender_adapter.py +1085 -0
  112. pychmp-0.1.0/src/pychmp/map_noise.py +334 -0
  113. pychmp-0.1.0/src/pychmp/metrics.py +396 -0
  114. pychmp-0.1.0/src/pychmp/obs_alignment.py +183 -0
  115. pychmp-0.1.0/src/pychmp/obs_maps.py +995 -0
  116. pychmp-0.1.0/src/pychmp/obs_preprocessing.py +806 -0
  117. pychmp-0.1.0/src/pychmp/obs_time_alignment.py +246 -0
  118. pychmp-0.1.0/src/pychmp/optimize.py +1560 -0
  119. pychmp-0.1.0/src/pychmp/psf.py +523 -0
  120. pychmp-0.1.0/src/pychmp/q0_artifact_panel.py +1586 -0
  121. pychmp-0.1.0/src/pychmp/q0_search.py +130 -0
  122. pychmp-0.1.0/src/pychmp/refresh_signal.py +97 -0
  123. pychmp-0.1.0/src/pychmp/render_obs_fits_dir.py +416 -0
  124. pychmp-0.1.0/src/pychmp/repair_grid_trial_maps.py +364 -0
  125. pychmp-0.1.0/src/pychmp/rescore_search.py +725 -0
  126. pychmp-0.1.0/src/pychmp/search_contract.py +181 -0
  127. pychmp-0.1.0/src/pychmp/search_options.py +141 -0
  128. pychmp-0.1.0/src/pychmp/slice_map_index.py +395 -0
  129. pychmp-0.1.0/src/pychmp/spectral.py +130 -0
  130. pychmp-0.1.0/src/pychmp/viewer.py +6838 -0
  131. pychmp-0.1.0/src/pychmp/viewer_navigation.py +199 -0
  132. pychmp-0.1.0/src/pychmp/viewer_plot_style.py +279 -0
  133. pychmp-0.1.0/src/pychmp/warm_q0.py +435 -0
  134. pychmp-0.1.0/test_eovsa_map_noise.py +99 -0
  135. pychmp-0.1.0/tests/test_ab_scan_artifacts.py +2937 -0
  136. pychmp-0.1.0/tests/test_ab_scan_execution.py +148 -0
  137. pychmp-0.1.0/tests/test_ab_scan_tasks.py +68 -0
  138. pychmp-0.1.0/tests/test_ab_search.py +865 -0
  139. pychmp-0.1.0/tests/test_adaptive_search_lifecycle.py +210 -0
  140. pychmp-0.1.0/tests/test_adaptive_single_observation_cli.py +1930 -0
  141. pychmp-0.1.0/tests/test_build_artifact_payload_hydrate.py +169 -0
  142. pychmp-0.1.0/tests/test_chmp_evaluation.py +80 -0
  143. pychmp-0.1.0/tests/test_cli.py +8 -0
  144. pychmp-0.1.0/tests/test_expand_grid_search.py +62 -0
  145. pychmp-0.1.0/tests/test_fitting.py +113 -0
  146. pychmp-0.1.0/tests/test_geometry_policy.py +86 -0
  147. pychmp-0.1.0/tests/test_grid_points.py +536 -0
  148. pychmp-0.1.0/tests/test_gxrender_adapter.py +891 -0
  149. pychmp-0.1.0/tests/test_import.py +7 -0
  150. pychmp-0.1.0/tests/test_map_noise.py +306 -0
  151. pychmp-0.1.0/tests/test_metrics.py +90 -0
  152. pychmp-0.1.0/tests/test_metrics_mask_display.py +79 -0
  153. pychmp-0.1.0/tests/test_metrics_mask_safeguard.py +46 -0
  154. pychmp-0.1.0/tests/test_obs_alignment.py +66 -0
  155. pychmp-0.1.0/tests/test_obs_maps.py +335 -0
  156. pychmp-0.1.0/tests/test_obs_preprocessing.py +250 -0
  157. pychmp-0.1.0/tests/test_obs_time_alignment.py +45 -0
  158. pychmp-0.1.0/tests/test_observation_cli_shared.py +161 -0
  159. pychmp-0.1.0/tests/test_optimize.py +527 -0
  160. pychmp-0.1.0/tests/test_psf.py +163 -0
  161. pychmp-0.1.0/tests/test_q0_artifact_contract.py +142 -0
  162. pychmp-0.1.0/tests/test_q0_artifact_panel.py +152 -0
  163. pychmp-0.1.0/tests/test_q0_search.py +198 -0
  164. pychmp-0.1.0/tests/test_recompute_search_repair.py +90 -0
  165. pychmp-0.1.0/tests/test_render_obs_fits_dir.py +294 -0
  166. pychmp-0.1.0/tests/test_repair_grid_trial_maps.py +144 -0
  167. pychmp-0.1.0/tests/test_rescore_search.py +233 -0
  168. pychmp-0.1.0/tests/test_scan_ab_obs_map_resume.py +719 -0
  169. pychmp-0.1.0/tests/test_search_contract.py +225 -0
  170. pychmp-0.1.0/tests/test_slice_map_index.py +136 -0
  171. pychmp-0.1.0/tests/test_viewer_navigation.py +70 -0
  172. pychmp-0.1.0/tests/test_viewer_navigation_global_best.py +68 -0
  173. pychmp-0.1.0/tests/test_viewer_plot_style.py +285 -0
  174. pychmp-0.1.0/tests/test_viewer_scan_state.py +3856 -0
  175. pychmp-0.1.0/tests/test_warm_grid_trial_commit.py +142 -0
  176. pychmp-0.1.0/uv.lock +663 -0
@@ -0,0 +1,6 @@
1
+ * text=auto
2
+
3
+ *.py text eol=lf
4
+ *.sh text eol=lf
5
+ *.cmd text eol=crlf
6
+ *.bat text eol=crlf
@@ -0,0 +1,24 @@
1
+ name: Bug report
2
+ description: Report a reproducible problem
3
+ labels: [bug]
4
+ body:
5
+ - type: textarea
6
+ id: description
7
+ attributes:
8
+ label: Description
9
+ description: What happened?
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: steps
14
+ attributes:
15
+ label: Steps to reproduce
16
+ description: Minimal reproducible steps
17
+ validations:
18
+ required: true
19
+ - type: textarea
20
+ id: expected
21
+ attributes:
22
+ label: Expected behavior
23
+ validations:
24
+ required: true
@@ -0,0 +1,18 @@
1
+ name: Feature request
2
+ description: Propose an enhancement
3
+ labels: [enhancement]
4
+ body:
5
+ - type: textarea
6
+ id: problem
7
+ attributes:
8
+ label: Problem statement
9
+ description: What need does this solve?
10
+ validations:
11
+ required: true
12
+ - type: textarea
13
+ id: proposal
14
+ attributes:
15
+ label: Proposed solution
16
+ description: Describe the desired behavior
17
+ validations:
18
+ required: true
@@ -0,0 +1,14 @@
1
+ ## Summary
2
+
3
+ Describe the problem and the change.
4
+
5
+ ## Provenance Notes
6
+
7
+ If this PR ports or mirrors logic from IDL gxmodelfitting,
8
+ add concise references to source routines and rationale.
9
+
10
+ ## Validation
11
+
12
+ - [ ] Tests pass locally
13
+ - [ ] CI passes
14
+ - [ ] Documentation updated (if needed)
@@ -0,0 +1,30 @@
1
+ name: CI
2
+
3
+ on:
4
+ push:
5
+ branches: ["main"]
6
+ pull_request:
7
+ branches: ["main"]
8
+
9
+ jobs:
10
+ tests:
11
+ runs-on: ubuntu-latest
12
+ strategy:
13
+ matrix:
14
+ python-version: ["3.10", "3.12"]
15
+ steps:
16
+ - name: Checkout
17
+ uses: actions/checkout@v4
18
+
19
+ - name: Set up Python
20
+ uses: actions/setup-python@v5
21
+ with:
22
+ python-version: ${{ matrix.python-version }}
23
+
24
+ - name: Install package
25
+ run: |
26
+ python -m pip install --upgrade pip
27
+ pip install -e .[dev]
28
+
29
+ - name: Run tests
30
+ run: pytest -q
@@ -0,0 +1,25 @@
1
+ # Python
2
+ __pycache__/
3
+ *.py[cod]
4
+ *.so
5
+
6
+ # Packaging
7
+ *.egg-info/
8
+ dist/
9
+ build/
10
+
11
+ # Testing
12
+ .pytest_cache/
13
+ .coverage
14
+
15
+ # Virtual environments
16
+ .venv/
17
+ venv/
18
+ .conda/
19
+
20
+ # IDE
21
+ .vscode/
22
+ .idea/
23
+
24
+ # macOS
25
+ .DS_Store
@@ -0,0 +1,44 @@
1
+ {
2
+ "title": "pyCHMP",
3
+ "description": "Python Coronal Heating Modeling Pipeline for data-constrained fitting of GX Simulator active-region models.",
4
+ "license": "BSD-3-Clause",
5
+ "creators": [
6
+ {
7
+ "name": "Nita, Gelu",
8
+ "affiliation": "SUNCAST-ORG"
9
+ },
10
+ {
11
+ "name": "Kuznetsov, Alexey"
12
+ }
13
+ ],
14
+ "keywords": [
15
+ "solar physics",
16
+ "GX Simulator",
17
+ "EBTEL",
18
+ "model fitting",
19
+ "microwave",
20
+ "EUV"
21
+ ],
22
+ "related_identifiers": [
23
+ {
24
+ "identifier": "https://github.com/kuznetsov-radio/gxmodelfitting",
25
+ "relation": "isDerivedFrom",
26
+ "scheme": "url"
27
+ },
28
+ {
29
+ "identifier": "10.5281/zenodo.19057091",
30
+ "relation": "isSupplementTo",
31
+ "scheme": "doi"
32
+ },
33
+ {
34
+ "identifier": "10.5281/zenodo.15660387",
35
+ "relation": "isSupplementTo",
36
+ "scheme": "doi"
37
+ },
38
+ {
39
+ "identifier": "10.3847/1538-4365/acd343",
40
+ "relation": "isDerivedFrom",
41
+ "scheme": "doi"
42
+ }
43
+ ]
44
+ }
@@ -0,0 +1,52 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented in this file.
4
+
5
+ The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
6
+ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
+
8
+ ## [0.1.0] - 2026-06-04
9
+
10
+ First public release of the unified artifact and adaptive-search infrastructure,
11
+ intended for observational fitting workflows together with [pyAMPP](https://pypi.org/project/pyampp/)
12
+ and [pyGXrender](https://pypi.org/project/pyGXrender/).
13
+
14
+ ### Added
15
+
16
+ - Unified HDF5 layout: slice-level `common`, per-search `grid_points`, shared `map_store`.
17
+ - Adaptive runner: `examples/python/adaptive_ab_search_single_observation.py` with live
18
+ `pychmp-view` refresh, warm Q₀ start from `map_store`, and HDF5 grid-point events.
19
+ - CLI utilities: `pychmp-rescore`, `pychmp-repair-grid-trial-maps`.
20
+ - Targeted search modes: `--recompute-search-id` (repair incomplete/contract-broken cells),
21
+ `--expand-grid-search-id` (widen `a`/`b` with prior-footprint wall seed on resume).
22
+ - Library modules: `grid_points`, `slice_map_index`, `warm_q0`, `search_contract`,
23
+ `refresh_signal`, expand/resume helpers in `ab_search`.
24
+ - Viewer: heatmap log scale, improved runner liveness vs terminal search status,
25
+ HDF5 read retries, dedicated heatmap colorbar axes.
26
+
27
+ ### Changed
28
+
29
+ - Version `0.1.0a2` → `0.1.0` (drops alpha pre-release label for this artifact generation).
30
+ - Consolidated sparse/fixed/adaptive point metadata under one schema for `pychmp-view`.
31
+ - Documentation: `README.md`, `docs/workflow_architecture.md`, `docs/artifact_data_contract.rst`.
32
+
33
+ ### Removed
34
+
35
+ - `examples/python/adaptive_ab_search_single_frequency.py` and its dedicated CLI tests
36
+ (use `adaptive_ab_search_single_observation.py`).
37
+
38
+ ### Migration from 0.1.0a2
39
+
40
+ - Artifacts produced with `0.1.0a2` may not resume cleanly; prefer a new search identity
41
+ or `--recompute-search-id` / `--expand-grid-search-id` after validating compatibility.
42
+ - Pin versions in publications: `pychmp==0.1.0`, `pyampp>=1.0.2`, and your chosen `pyGXrender`
43
+ release; record model/observation provenance in the artifact.
44
+
45
+ ### Known limitations
46
+
47
+ - Cherry-picked refit of individual grid points under an existing `search_id` is planned
48
+ but not shipped in 0.1.0 (see project implementation notes).
49
+ - Full observational runs still require external model H5, EBTEL, and observation inputs
50
+ (for example the `pyGXrender-test-data` checkout referenced in `README.md`).
51
+
52
+ [0.1.0]: https://github.com/suncast-org/pyCHMP/releases/tag/v0.1.0
@@ -0,0 +1,65 @@
1
+ cff-version: 1.2.0
2
+ title: "pyCHMP"
3
+ version: 0.1.0
4
+ date-released: 2026-06-04
5
+ message: "If you use this software, please cite it using the metadata below."
6
+ type: software
7
+ authors:
8
+ - family-names: "Nita"
9
+ given-names: "Gelu"
10
+ - family-names: "Kuznetsov"
11
+ given-names: "Alexey"
12
+ repository-code: "https://github.com/suncast-org/pyCHMP"
13
+ url: "https://github.com/suncast-org/pyCHMP"
14
+ license: "BSD-3-Clause"
15
+ keywords:
16
+ - solar physics
17
+ - GX Simulator
18
+ - EBTEL
19
+ - model fitting
20
+ - microwave
21
+ - EUV
22
+ abstract: >-
23
+ pyCHMP is a Python coronal heating model fitting pipeline for data-constrained
24
+ exploration of EBTEL parameter space using pyAMPP models and pyGXrender
25
+ synthetic observables.
26
+ references:
27
+ - type: software
28
+ title: "gxmodelfitting"
29
+ url: "https://github.com/kuznetsov-radio/gxmodelfitting"
30
+ - type: software
31
+ title: "gximagecomputing"
32
+ url: "https://github.com/kuznetsov-radio/gximagecomputing"
33
+ - type: software
34
+ title: "pyAMPP"
35
+ url: "https://github.com/suncast-org/pyAMPP"
36
+ doi: "10.5281/zenodo.19057091"
37
+ - type: software
38
+ title: "pyAMPP (all versions)"
39
+ doi: "10.5281/zenodo.15660387"
40
+ - type: article
41
+ title: "Data-constrained Solar Modeling with GX Simulator"
42
+ authors:
43
+ - family-names: "Nita"
44
+ given-names: "Gelu M."
45
+ - family-names: "Fleishman"
46
+ given-names: "Gregory D."
47
+ - family-names: "Kuznetsov"
48
+ given-names: "Alexey A."
49
+ - family-names: "Anfinogentov"
50
+ given-names: "Sergey A."
51
+ - family-names: "Stupishin"
52
+ given-names: "Alexey G."
53
+ - family-names: "Kontar"
54
+ given-names: "Eduard P."
55
+ - family-names: "Schonfeld"
56
+ given-names: "Samuel J."
57
+ - family-names: "Klimchuk"
58
+ given-names: "James A."
59
+ - family-names: "Gary"
60
+ given-names: "Dale E."
61
+ journal: "The Astrophysical Journal Supplement Series"
62
+ year: 2023
63
+ volume: 267
64
+ issue: 1
65
+ doi: "10.3847/1538-4365/acd343"
@@ -0,0 +1 @@
1
+ * @Gelu-Nita
@@ -0,0 +1,53 @@
1
+ # Contributing to pyCHMP
2
+
3
+ ## Workflow
4
+
5
+ - Create a feature branch from `main`.
6
+ - Open a pull request into `main`.
7
+ - Keep changes scoped and documented.
8
+ - Ensure CI passes before merge.
9
+
10
+ ## Architecture
11
+
12
+ Keep the package layering clear:
13
+
14
+ - `src/pychmp/` contains package-level primitives and reusable workflow logic.
15
+ - `examples/` contains runnable real-data and validation workflows.
16
+ - `scripts/` contains tracked shell launchers that wrap those Python workflows.
17
+
18
+ For the current observational fitting/search stack:
19
+
20
+ - `fit_q0_to_observation(...)` is the core single-point numerical primitive.
21
+ - `examples/fit_q0_obs_map.py` is the single-point real observational workflow.
22
+ - `examples/scan_ab_obs_map.py` is the fixed-grid / sparse-grid orchestration layer.
23
+ - `search_local_minimum_ab(...)` is the adaptive `(a, b)` search core.
24
+ - `examples/python/adaptive_ab_search_single_observation.py` is the real observational wrapper around the adaptive search core.
25
+
26
+ For observational-map ingestion, prefer reusing:
27
+
28
+ - `load_obs_map(...)`
29
+ - `validate_obs_map_identity(...)`
30
+ - `estimate_obs_map_noise(...)`
31
+
32
+ Do not introduce new script-local FITS/refmap loaders unless there is a clear reason they cannot fit the shared `obs_maps.py` contract.
33
+
34
+ For artifact work, align new storage and viewer changes with the tracked
35
+ contract in [docs/artifact_data_contract.rst](docs/artifact_data_contract.rst).
36
+ Do not introduce new file families or MW-only metadata assumptions if the same
37
+ goal can be expressed through the canonical slice / trial / solution model.
38
+
39
+ ## Commit style
40
+
41
+ Use clear, action-oriented commit messages.
42
+
43
+ ## Scientific provenance
44
+
45
+ When implementing logic ported from IDL CHMP/gxmodelfitting, include concise provenance notes in code docstrings and PR descriptions.
46
+
47
+ ## Testing
48
+
49
+ Run locally before opening PR:
50
+
51
+ ```bash
52
+ pytest -q
53
+ ```
pychmp-0.1.0/LICENSE ADDED
@@ -0,0 +1,29 @@
1
+ BSD 3-Clause License
2
+
3
+ Copyright (c) 2026, SUNCAST-ORG
4
+ All rights reserved.
5
+
6
+ Redistribution and use in source and binary forms, with or without
7
+ modification, are permitted provided that the following conditions are met:
8
+
9
+ 1. Redistributions of source code must retain the above copyright notice, this
10
+ list of conditions and the following disclaimer.
11
+
12
+ 2. Redistributions in binary form must reproduce the above copyright notice,
13
+ this list of conditions and the following disclaimer in the documentation
14
+ and/or other materials provided with the distribution.
15
+
16
+ 3. Neither the name of the copyright holder nor the names of its
17
+ contributors may be used to endorse or promote products derived from
18
+ this software without specific prior written permission.
19
+
20
+ THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
21
+ AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
22
+ IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
23
+ DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
24
+ FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
25
+ DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
26
+ SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
27
+ CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
28
+ OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
29
+ OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
pychmp-0.1.0/PKG-INFO ADDED
@@ -0,0 +1,286 @@
1
+ Metadata-Version: 2.4
2
+ Name: pychmp
3
+ Version: 0.1.0
4
+ Summary: Python Coronal Heating Modeling Pipeline for data-constrained fitting of GX models
5
+ Project-URL: Homepage, https://github.com/suncast-org/pyCHMP
6
+ Project-URL: Repository, https://github.com/suncast-org/pyCHMP
7
+ Project-URL: Algorithmic Provenance, https://github.com/kuznetsov-radio/gxmodelfitting
8
+ Author: Gelu Nita, Alexey Kuznetsov
9
+ License-Expression: BSD-3-Clause
10
+ License-File: LICENSE
11
+ Keywords: ebtel,euv,gx-simulator,model-fitting,radio,solar-physics
12
+ Classifier: Development Status :: 3 - Alpha
13
+ Classifier: Intended Audience :: Science/Research
14
+ Classifier: License :: OSI Approved :: BSD License
15
+ Classifier: Programming Language :: Python :: 3
16
+ Classifier: Programming Language :: Python :: 3 :: Only
17
+ Classifier: Programming Language :: Python :: 3.10
18
+ Classifier: Programming Language :: Python :: 3.11
19
+ Classifier: Programming Language :: Python :: 3.12
20
+ Classifier: Topic :: Scientific/Engineering :: Astronomy
21
+ Requires-Python: >=3.10
22
+ Requires-Dist: astropy>=5
23
+ Requires-Dist: h5py>=3.8
24
+ Requires-Dist: matplotlib>=3.8
25
+ Requires-Dist: numpy>=1.25
26
+ Requires-Dist: scipy>=1.11
27
+ Provides-Extra: dev
28
+ Requires-Dist: bumpver>=2024.1130; extra == 'dev'
29
+ Requires-Dist: pytest>=8.0; extra == 'dev'
30
+ Description-Content-Type: text/markdown
31
+
32
+ # pyCHMP
33
+
34
+ Python Coronal Heating Modeling Pipeline for data-constrained fitting of GX Simulator active-region models.
35
+
36
+ ## Overview
37
+
38
+ pyCHMP is a Python application for parameter-space exploration of EBTEL-based magneto-thermal models in search of best agreement between synthetic and observational maps.
39
+
40
+ Initial scope:
41
+ - Replicate the validated CHMP search strategy used in the IDL GX Simulator ecosystem.
42
+ - Use pyAMPP-produced models and pyGXrender synthetic maps.
43
+ - Support microwave fitting first, then extend the same workflow to EUV constraints.
44
+
45
+ ## Provenance and Acknowledgement
46
+
47
+ This project is algorithmically grounded in the model-fitting approach developed and maintained by Alexey Kuznetsov in gxmodelfitting:
48
+
49
+ - https://github.com/kuznetsov-radio/gxmodelfitting
50
+
51
+ pyCHMP is an independent Python implementation under SUNCAST-ORG. The intent is scientific reproducibility and extensibility, while preserving explicit provenance and credit.
52
+
53
+ ## Installation
54
+
55
+ ### pyCHMP only
56
+
57
+ ```bash
58
+ pip install pychmp
59
+ ```
60
+
61
+ For development:
62
+
63
+ ```bash
64
+ pip install -e ".[dev]"
65
+ ```
66
+
67
+ ### SUNCAST fitting stack (pyAMPP → pyGXrender → pyCHMP)
68
+
69
+ Observational fitting uses three installable packages. Pin versions in publications
70
+ (for example `pyampp==1.0.2`, your chosen `pyGXrender` release, and `pychmp==0.1.0`).
71
+
72
+ ```bash
73
+ pip install -U pip setuptools wheel
74
+ pip install "pyampp>=1.0.2" pyGXrender pychmp
75
+ ```
76
+
77
+ `pyGXrender` currently requires **Python 3.12+** on PyPI; `pychmp` supports **3.10+**.
78
+ Use a 3.12 environment when installing the full stack.
79
+
80
+ Packages alone do not include model cubes, EBTEL tables, or observation FITS. For
81
+ runnable examples, clone [pyGXrender-test-data](https://github.com/suncast-org/pyGXrender-test-data)
82
+ next to this repository (or set explicit `--model-h5`, `--ebtel-path`, and
83
+ `--obs-fits-path` / `--obs-map-id` on the workflow scripts). See `examples/python/`
84
+ and `scripts/README.md`.
85
+
86
+ Console entry points after install:
87
+
88
+ | Command | Role |
89
+ |---------|------|
90
+ | `pychmp` | Package CLI |
91
+ | `pychmp-view` | Artifact viewer |
92
+ | `pychmp-rescore` | Rescore `map_store` into a parallel search identity |
93
+ | `pychmp-repair-grid-trial-maps` | Repair invalid trial HDF5 groups |
94
+
95
+ Release history: [CHANGELOG.md](CHANGELOG.md).
96
+
97
+ ## Quick Start
98
+
99
+ ```bash
100
+ pychmp --help
101
+ ```
102
+
103
+ User-facing runnable workflows live under `examples/`, and tracked shell
104
+ launchers for the heavier manual validation and observational fitting runs live
105
+ under `scripts/`.
106
+
107
+ If you use the tracked launcher scripts, install `pyGXrender-test-data` as a
108
+ sibling checkout next to `pyCHMP` so they can resolve shared models, EOVSA
109
+ maps, and EBTEL inputs without machine-specific absolute paths.
110
+
111
+ For EUV/UV model-refmap workflows, `--euv-response-sav` is now an explicit
112
+ compatibility override rather than the default path. When omitted,
113
+ gximagecomputing resolves supported instrument responses through its
114
+ pyEUVTools-backed provider and surfaces the chosen `response.source` /
115
+ `response.mode` metadata in the downstream render result.
116
+
117
+ ## User Manual
118
+
119
+ ### Artifact Reuse Policy
120
+
121
+ pyCHMP artifacts are meant to represent meaningful scientific products, not to
122
+ act as an audit log of failed or abandoned attempts.
123
+
124
+ - A new slice should appear only when the scientific target changes in a way
125
+ that changes slice identity, such as a different EUV channel, MW frequency,
126
+ geometry/WCS, observer contract, or other incompatibility that makes the
127
+ stored maps physically non-reusable.
128
+ - If the current run is compatible with the existing artifact and no grid-reset
129
+ flag is set, pyCHMP resumes implicitly from the existing search state.
130
+ Changing only search boundaries does not create a new slice or a new search
131
+ lineage.
132
+ - `--recompute-search-id SEARCH_ID` (with `--artifact-h5`): **repair** mode —
133
+ restores the stored scoring recipe, preserves valid map-linked trials, resets
134
+ only contract-broken points, and resumes the adaptive walk to complete incomplete
135
+ cells. Allowed flags: `--artifact-h5`, `--recompute-search-id`, optional
136
+ `--no-viewer` / `--dry-run`.
137
+ - `--expand-grid-search-id SEARCH_ID` (with `--artifact-h5`): widen `a`/`b` on the
138
+ same search id and stored recipe; hydrates completed cells; explores only new or
139
+ outstanding cells in the enlarged domain (Phase‑1 seeds from the prior footprint
140
+ wall toward the widened bound).
141
+ - `pychmp-repair-grid-trial-maps`: purge invalid trial HDF5 groups and rebuild
142
+ headers; does not refit or clear `map_store`.
143
+ - `pychmp-rescore build|commit`: rescore existing `map_store` maps into a new
144
+ `{root}_rN` search via a sidecar file (no gxrender, no viewer). Commit when no
145
+ adaptive run is active.
146
+ - `--recompute-existing` clears the grid for the matching search identity and
147
+ refits every point, reusing `map_store` maps for warm q0 start (no gxrender
148
+ for compatible stored q0 values).
149
+ - `--new-search-identity` does the same refit under a parallel search identity
150
+ for debugging (e.g. algorithm changes with the same target contract). Prior
151
+ searches remain in the artifact; `map_store` warm start still applies.
152
+ - Changes that alter the scientific meaning of the stored results, such as
153
+ different masks, thresholds, or beams, must not silently reuse incompatible
154
+ results. They should branch only when the metadata signature requires it.
155
+
156
+ Practical interpretation:
157
+
158
+ - same target + same compatible signature + default (no flags): resume
159
+ - same target + same compatible signature + `--recompute-existing`: same search
160
+ id, fresh grid, map_store warm start
161
+ - same target + same compatible signature + `--new-search-identity`: parallel
162
+ search id, fresh grid, prior searches kept, map_store warm start
163
+ - changed slice identity: create a new slice
164
+
165
+ ## Development
166
+
167
+ ```bash
168
+ pytest -q
169
+ ```
170
+
171
+ User-facing runnable workflows are available in `examples/`.
172
+
173
+ Consolidated scan artifacts now use one normalized point schema across
174
+ fixed-grid and adaptive search workflows. Each artifact keeps common
175
+ slice-level metadata plus per-search point records under a unified slice/search
176
+ layout, with reusable rendered arrays promoted into the shared `map_store`
177
+ when applicable. Each stored point carries the final best-fit maps plus
178
+ per-trial `q0`, `chi2`, `rho2`, and `eta2` histories when available, so
179
+ `pychmp-view` can plot the selected metric history directly from the artifact.
180
+
181
+ Real-data gxrender validation workflows live under `examples/python/` rather
182
+ than in the default automated test suite.
183
+
184
+ The `examples/` area is now structured to allow parallel workflow formats:
185
+ standalone Python validation scripts live under `examples/python/`, while
186
+ future developer and collaborator notebook examples can live under
187
+ `examples/notebooks/`.
188
+
189
+ The `scripts/` directory remains reserved for tracked shell launchers (`.sh`
190
+ and `.cmd`) that wrap those Python workflows; it is not the home of the Python
191
+ entry-point files themselves.
192
+
193
+ ## Workflow Call Graph
194
+
195
+ The package has a layered structure. The most important distinction is between:
196
+
197
+ - package-level fitting/search primitives under `src/pychmp/`
198
+ - real-data runnable workflows under `examples/`
199
+ - shell launchers under `scripts/`
200
+
201
+ The current call hierarchy for the observational workflows is:
202
+
203
+ ```text
204
+ shell launchers (.sh / .cmd)
205
+ -> examples/fit_q0_obs_map.py
206
+ -> pychmp.load_obs_map(...)
207
+ -> pychmp.estimate_obs_map_noise(...)
208
+ -> pychmp.resolve_geometry_policy(...)
209
+ -> pychmp.fit_q0_to_observation(...)
210
+
211
+ shell launchers (.sh / .cmd)
212
+ -> examples/scan_ab_obs_map.py
213
+ -> pychmp.load_obs_map(...)
214
+ -> pychmp.estimate_obs_map_noise(...)
215
+ -> pychmp.resolve_geometry_policy(...)
216
+ -> per-point fit workflow
217
+ -> examples/fit_q0_obs_map.py
218
+ -> pychmp.fit_q0_to_observation(...)
219
+
220
+ shell launchers (.sh / .cmd)
221
+ -> examples/python/adaptive_ab_search_single_observation.py
222
+ -> pychmp.load_obs_map(...)
223
+ -> pychmp.validate_obs_map_identity(...)
224
+ -> pychmp.resolve_render_geometry_via_gxrender(...)
225
+ -> pychmp.validate_scan_artifact_reuse_preflight(...) [when reusing an existing target slice]
226
+ -> pychmp.estimate_obs_map_noise(...)
227
+ -> pychmp.resolve_geometry_policy(...)
228
+ -> pychmp.search_local_minimum_ab(...)
229
+ -> pychmp.evaluate_ab_point(...)
230
+ -> pychmp.fit_q0_to_observation(...)
231
+ ```
232
+
233
+ Contributor notes:
234
+
235
+ - `fit_q0_to_observation(...)` is the core single-point numerical primitive.
236
+ - `fit_q0_obs_map.py` is the single-point real observational workflow wrapper around that primitive.
237
+ - `scan_ab_obs_map.py` is the fixed-grid / sparse-grid orchestration layer.
238
+ - `search_local_minimum_ab(...)` is the adaptive `(a, b)` search core.
239
+ - `adaptive_ab_search_single_observation.py` is the real observational wrapper around the adaptive search core.
240
+ - `src/pychmp/obs_maps.py` is the shared observation-ingestion layer used by the real observational workflows.
241
+ - `src/pychmp/geometry_policy.py` resolves observation LOS compatibility before workflows reuse model-saved observer/FOV metadata.
242
+ - `src/pychmp/ab_scan_artifacts.py` owns the unified slice/search artifact contract, compatibility validation, and reusable map-store plumbing shared by fixed-grid and adaptive workflows.
243
+
244
+ When adding new observational workflows, prefer reusing:
245
+
246
+ - `load_obs_map(...)`
247
+ - `validate_obs_map_identity(...)`
248
+ - `estimate_obs_map_noise(...)`
249
+ - `resolve_geometry_policy(...)`
250
+
251
+ instead of introducing new script-local FITS/refmap loaders.
252
+
253
+ The user-facing `fit_q0_obs_map.py`, `scan_ab_obs_map.py`, and
254
+ `adaptive_ab_search_single_observation.py` workflows all expose the bounded
255
+ Q0 minimizer controls `--xatol` and `--maxiter`. These tune the final bounded
256
+ minimization accuracy and iteration budget; adaptive-search
257
+ `--max-bracket-steps` only limits additional bracket expansion attempts before
258
+ that minimization stage.
259
+
260
+ ### Version Bumping
261
+
262
+ This repository uses `bumpver` to keep package versions in sync between
263
+ `pyproject.toml` and `src/pychmp/__init__.py`.
264
+
265
+ ```bash
266
+ pip install -e .[dev]
267
+ bumpver show
268
+ ```
269
+
270
+ For normal stable-version increments you can use the usual `bumpver update`
271
+ subcommands. For explicit pre-release bumps like `0.1.0a0 -> 0.1.0a1`, update
272
+ the version fields directly or use an explicit `bumpver` target rather than
273
+ assuming `--patch` is the right semantic move.
274
+
275
+ ```bash
276
+ python -m bumpver show
277
+ ```
278
+
279
+ ## Citation
280
+
281
+ Please cite using [CITATION.cff](CITATION.cff) (version **0.1.0**) and the Zenodo record
282
+ created from the matching GitHub release tag. See also `.zenodo.json` for archive metadata.
283
+
284
+ ## License
285
+
286
+ BSD-3-Clause