beta-parameterization 2.3.4__tar.gz → 3.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.
Files changed (50) hide show
  1. beta_parameterization-3.0.0/CHANGELOG.md +242 -0
  2. {beta_parameterization-2.3.4 → beta_parameterization-3.0.0}/CMakeLists.txt +21 -4
  3. {beta_parameterization-2.3.4 → beta_parameterization-3.0.0}/PKG-INFO +1 -1
  4. beta_parameterization-3.0.0/include/beta_parameterization.h +263 -0
  5. beta_parameterization-3.0.0/include/beta_parameterization.hpp +410 -0
  6. beta_parameterization-3.0.0/python/beta_parameterization/__init__.py +22 -0
  7. beta_parameterization-3.0.0/python/beta_parameterization/_cdefs.py +101 -0
  8. beta_parameterization-3.0.0/python/beta_parameterization/api.py +388 -0
  9. beta_parameterization-3.0.0/python/tests/test_api.py +153 -0
  10. beta_parameterization-3.0.0/src/beta_parameterization_c_api_mod.f08 +511 -0
  11. beta_parameterization-3.0.0/src/beta_parameterization_mod.f08 +1419 -0
  12. {beta_parameterization-2.3.4 → beta_parameterization-3.0.0}/src/beta_parameterization_workers_mod.f08 +82 -40
  13. beta_parameterization-3.0.0/tests/beta_param_bitwise_test.f08 +252 -0
  14. beta_parameterization-3.0.0/tests/beta_param_boundary_test.f08 +148 -0
  15. beta_parameterization-3.0.0/tests/beta_param_golden_test.f08 +152 -0
  16. beta_parameterization-3.0.0/tests/beta_param_interleave_test.f08 +378 -0
  17. beta_parameterization-3.0.0/tests/beta_param_lifecycle_test.f08 +124 -0
  18. beta_parameterization-3.0.0/tests/beta_param_minimality_test.f08 +260 -0
  19. beta_parameterization-3.0.0/tests/beta_param_outputs_test.f08 +132 -0
  20. beta_parameterization-3.0.0/tests/beta_param_property_test.f08 +157 -0
  21. beta_parameterization-3.0.0/tests/beta_param_resolve_test.f08 +53 -0
  22. beta_parameterization-3.0.0/tests/beta_param_standalone_test.f08 +115 -0
  23. beta_parameterization-3.0.0/tests/beta_param_status_test.f08 +32 -0
  24. beta_parameterization-3.0.0/tests/beta_pes_sweep.f08 +231 -0
  25. beta_parameterization-3.0.0/tests/c_api_smoke_test.cpp +213 -0
  26. beta_parameterization-3.0.0/tests/golden_capture.f08 +113 -0
  27. beta_parameterization-3.0.0/tests/thread_stress_test.cpp +168 -0
  28. beta_parameterization-2.3.4/include/beta_parameterization.h +0 -207
  29. beta_parameterization-2.3.4/include/beta_parameterization.hpp +0 -292
  30. beta_parameterization-2.3.4/python/beta_parameterization/__init__.py +0 -23
  31. beta_parameterization-2.3.4/python/beta_parameterization/_cdefs.py +0 -59
  32. beta_parameterization-2.3.4/python/beta_parameterization/api.py +0 -297
  33. beta_parameterization-2.3.4/python/tests/test_api.py +0 -185
  34. beta_parameterization-2.3.4/src/beta_parameterization_c_api_mod.f08 +0 -425
  35. beta_parameterization-2.3.4/src/beta_parameterization_mod.f08 +0 -828
  36. beta_parameterization-2.3.4/tests/beta_param_breakdown_test.f08 +0 -123
  37. beta_parameterization-2.3.4/tests/beta_param_com_test.f08 +0 -97
  38. beta_parameterization-2.3.4/tests/beta_param_core_test.f08 +0 -105
  39. beta_parameterization-2.3.4/tests/beta_param_error_test.f08 +0 -153
  40. beta_parameterization-2.3.4/tests/beta_param_golden_test.f08 +0 -165
  41. beta_parameterization-2.3.4/tests/beta_param_node_set_test.f08 +0 -335
  42. beta_parameterization-2.3.4/tests/c_api_smoke_test.cpp +0 -214
  43. beta_parameterization-2.3.4/tests/golden_capture.f08 +0 -84
  44. beta_parameterization-2.3.4/tests/thread_stress_test.cpp +0 -60
  45. {beta_parameterization-2.3.4 → beta_parameterization-3.0.0}/.gitignore +0 -0
  46. {beta_parameterization-2.3.4 → beta_parameterization-3.0.0}/LICENSE +0 -0
  47. {beta_parameterization-2.3.4 → beta_parameterization-3.0.0}/ci/build-wheel.sh +0 -0
  48. {beta_parameterization-2.3.4 → beta_parameterization-3.0.0}/pyproject.toml +0 -0
  49. {beta_parameterization-2.3.4 → beta_parameterization-3.0.0}/python/beta_parameterization/_libloader.py +0 -0
  50. {beta_parameterization-2.3.4 → beta_parameterization-3.0.0}/tests/test_utils_mod.f08 +0 -0
@@ -0,0 +1,242 @@
1
+ # Changelog
2
+
3
+ All notable changes to this project are documented here. Versions follow
4
+ semantic versioning; the format follows [Keep a Changelog](https://keepachangelog.com).
5
+
6
+ ## 3.0.0
7
+
8
+ Adoption of the three-tier shape parameterization contract against
9
+ `shape_core_mod` (fortran-foundations 2.4.0). Every public surface — Fortran,
10
+ C, C++, Python — changes. Read the breaking-change list before upgrading;
11
+ nothing in 2.x compiles against 3.0.0 unchanged.
12
+
13
+ ### BREAKING: thread-safety promise withdrawn
14
+
15
+ **The 2.x guarantee that one cache serves concurrent computes from many threads
16
+ is gone.** It was never true once the cache started tracking recompute state.
17
+
18
+ | object | 3.0.0 rule |
19
+ |---|---|
20
+ | `tables_t` / `beta_param_tables_t*` / `Tables` | immutable after creation; share across threads for concurrent reads |
21
+ | `node_set_t` / `beta_param_node_set_t*` / `NodeSet` | immutable after build; share across threads for concurrent reads |
22
+ | `cache_t` / `beta_param_cache_t*` / `Cache` / Python `Cache` | **THREAD-CONFINED**; every compute mutates it; concurrent use from more than one thread is undefined |
23
+
24
+ The supported pattern is one shared `tables_t` plus one cache per thread, built
25
+ with `cache_init_shared_s` / `beta_param_cache_create_shared()` /
26
+ `Tables`-taking `Cache` constructor. Callers that fanned out one 2.x cache
27
+ across an OpenMP region **must** hoist a per-thread cache; the old code will
28
+ race silently. C++ `Cache` compute methods are no longer `const` — the compiler
29
+ catches most of these at the call site.
30
+
31
+ **Fortran callers of `cache_init_shared_s` MUST declare their `tables_t` with
32
+ the `target` attribute.** The cache stores a pointer to it, and a pointer
33
+ associated with a non-target dummy becomes undefined when that procedure
34
+ returns (F2018 8.5.17). Without `target` the code compiles, links and usually
35
+ appears to work — then reads freed memory. Declare
36
+ `type(tables_t), target :: tables`.
37
+
38
+ ### Added
39
+
40
+ - **In-library volume conservation.** `conserve_volume` is a cache/standalone
41
+ creation flag. The factor `c = (2 / Σᵢ wᵢ Rᵢ³)^(1/3)` is computed on the
42
+ internal GL-512 set over the COM-corrected, unscaled shape, after validation,
43
+ and applied to radii, dR/dθ and the polar radii — never to β-space values.
44
+ Consumers that rescaled shapes themselves (wmmm's
45
+ `compute_volume_factor_from_dense_f`) should drop their copy.
46
+ - `apply_com` as a creation flag, replacing the separate
47
+ `*_with_com_shift` entry points.
48
+ - `tables_t` — a shared, immutable tables level (normalization constants,
49
+ Gauss-Legendre set, Legendre tables at the primary thetas) with
50
+ `tables_init_s` / `tables_free_s` / `tables_max_l_f` / `tables_n_thetas_f`.
51
+ - `status_message_f(status)` (C: `beta_param_status_message`) — one pure lookup
52
+ returning a fixed string per code.
53
+ - `cache_radius_grid_unchecked_s` — the rendering/diagnostic path: no validity
54
+ gate, no volume scaling, usage errors only, so a rejected shape still yields
55
+ its outline. Its radii are UNSCALED even on a `conserve_volume` cache; mixing
56
+ it with the checked path draws two outlines of different size for one shape.
57
+ - `cache_recompute_count_f` plus the public intermediate indices
58
+ `BETA_PARAM_I_RESOLVED`, `_I_MIN_RADIUS`, `_I_VOLUME`, `_I_RADII`, `_I_DERIV`
59
+ — always-on recompute counters for cache-minimality testing.
60
+ - `BETA_PARAM_ERROR_NODE_SET_MISMATCH` (106) for an unbuilt node set or one
61
+ whose `max_l` is below the cache's `n_params`.
62
+ - Public constants for the two tier caps, so callers can check before creating
63
+ anything: `SHAPE_CACHE_MAX_PARAMS` (8) and `SHAPE_STANDALONE_MAX_PARAMS` (64)
64
+ re-exported from Fortran, `BETA_PARAM_CACHE_MAX_PARAMS` (8) and
65
+ `BETA_PARAM_MAX_PARAMS_LIMIT` (64) in the C header,
66
+ `beta_param::cache_max_params` / `beta_param::max_params_limit` in the C++
67
+ header, and `CACHE_MAX_PARAMS` (8) / `MAX_BETA_PARAMS_LIMIT` (64) in Python.
68
+ - The documented dependency map lives in the module header of
69
+ `src/beta_parameterization_mod.f08`: five intermediates, every mask = all
70
+ `n_params` bits.
71
+
72
+ ### Changed
73
+
74
+ - **BREAKING: the cached tier now caps `n_params` at 8, down from 64.** A cache
75
+ carries the recompute engine, whose per-intermediate dependency masks are
76
+ fixed-width, so `shape_core`'s `SHAPE_CACHE_MAX_PARAMS` = 8 is the hard limit.
77
+ `cache_init_s` / `cache_init_shared_s` reject `n_params > 8` with
78
+ `SHAPE_ERROR_TOO_MANY_PARAMS` (1) and `n_params < 1` with
79
+ `SHAPE_ERROR_INVALID_INIT` (5) — the engine check runs before any table is
80
+ built, so nothing is allocated. **The standalone tier is unaffected and still
81
+ accepts up to 64** (`SHAPE_STANDALONE_MAX_PARAMS`): it constructs no engine.
82
+ 2.x accepted `max_beta_params` up to 64 for the cache, so any consumer that
83
+ created a cache with more than 8 parameters — wmmm's
84
+ `number_of_deformation_parameters = 20` is the known case — fails at cache
85
+ creation and must either reduce its parameter count or move to the standalone
86
+ tier. Beta PES calculations realistically stay within 8 dimensions; wmmm's
87
+ 20 existed for fos→beta conversion, which is obsolete now that fos works on
88
+ the radius grid directly.
89
+ - **BREAKING: the internal uniform grid is gone.** 2.x caches took `n_grid` and
90
+ generated their own uniform theta grid. 3.0.0 takes an explicit **primary
91
+ theta set** — `tables_init_s(tables, max_l, thetas, status)`,
92
+ `cache_init_s(cache, n_params, thetas, ...)`. The caller owns the grid.
93
+ Pole values (θ = 0, π) are rejected as cache input; get them analytically
94
+ from `cache_resolve_shape_s`'s `r_north` / `r_south`.
95
+ - **BREAKING: all `message` arguments removed** from every entry point in
96
+ Fortran, C, C++ and Python. Diagnostics are the integer status plus
97
+ `status_message_f`. No per-call message formatting exists anywhere.
98
+ - **BREAKING (bitwise): the COM correction is now Newton's method** on the
99
+ numerator of the COM integral (`N(β10) = Σᵢ wᵢ xᵢ Rᵢ⁴`,
100
+ `N'(β10) = 4·C₁·Σᵢ wᵢ xᵢ² Rᵢ³`), replacing 2.x fixed-point iteration. The
101
+ tolerance (`|z_cm| < 1e-5`) and iteration cap (50) are unchanged, so the same
102
+ shapes converge — but **corrected β₁₀ and every downstream radius differ in
103
+ the last bits from 2.x**. Goldens were re-baselined; consumers pinning exact
104
+ values must re-baseline too.
105
+ - **BREAKING: `beta_con` is off the public surface.** 2.x
106
+ `cache_resolve_shape` returned the resolved coefficient array and
107
+ `compute_radius_and_derivative` took it back as an argument. 3.0.0 keeps
108
+ resolved coefficients inside the cache as intermediate 1;
109
+ `cache_resolve_shape_s` returns only `corrected_beta10`, `r_north`, `r_south`
110
+ and `volume_factor`, and node evaluation takes `(cache, node_set, params)`.
111
+ - Type-bound methods (`cache%init`, `cache%compute_radius_grid`, …) replaced by
112
+ free subroutines (`cache_init_s`, `cache_radius_grid_s`, …), matching the
113
+ contract's naming.
114
+ - Standalone tier: `compute_radius_grid_standalone_s(params, thetas,
115
+ conserve_volume, apply_com, radii, status)` and
116
+ `compute_radius_and_derivative_standalone_s(...)`. `n_params = size(params)`,
117
+ accepted up to the **standalone** cap of 64
118
+ (`SHAPE_STANDALONE_MAX_PARAMS` = `MAX_BETA_PARAMS_LIMIT`); above →
119
+ `SHAPE_ERROR_TOO_MANY_PARAMS`, never silent truncation. The
120
+ `max_beta_params` padding argument is removed. Tier 1 never constructs an
121
+ engine, which is why it keeps the higher cap.
122
+ - Failure semantics are now uniform: on ANY nonzero status inside a checked
123
+ cached compute the library zero-fills every output and invalidates the whole
124
+ engine, so the next call runs cold. Usage errors follow the contract's
125
+ normative order — a buffer-size mismatch (104) is reported before a node-set
126
+ mismatch (106).
127
+ - Minimum fortran-foundations is **2.4.0** (`shape_core_mod`); gcc-opts stays at
128
+ **2.0.0**.
129
+
130
+ ### Changed: status codes
131
+
132
+ Shared contract codes (0–99) come from `shape_core_mod`: `SHAPE_VALID` 0,
133
+ `SHAPE_ERROR_TOO_MANY_PARAMS` 1, `SHAPE_ERROR_CACHE_NOT_INITIALIZED` 2,
134
+ `SHAPE_ERROR_INVALID_GRID` 3 (theta floor: `size(thetas) >= 2`),
135
+ `SHAPE_ERROR_WRONG_PARAM_COUNT` 4, `SHAPE_ERROR_INVALID_INIT` 5,
136
+ `SHAPE_ERROR_TABLES_NOT_INITIALIZED` 6.
137
+
138
+ Library codes are renamed `LEGENDRE_*` → `BETA_PARAM_ERROR_*` and renumbered
139
+ ≥ 100. This range is **append-only** from 3.0.0 on:
140
+
141
+ | old (2.x) | new (3.0.0) |
142
+ |---|---|
143
+ | `LEGENDRE_ERROR_NORTH_POLE` 1 | `BETA_PARAM_ERROR_NORTH_POLE` 100 |
144
+ | `LEGENDRE_ERROR_SOUTH_POLE` 2 | `BETA_PARAM_ERROR_SOUTH_POLE` 101 |
145
+ | `LEGENDRE_ERROR_INTERIOR_NEGATIVE` 4 | `BETA_PARAM_ERROR_INTERIOR_NEGATIVE` 102 |
146
+ | `LEGENDRE_ERROR_COM_NOT_CONVERGED` 7 | `BETA_PARAM_ERROR_COM_NOT_CONVERGED` 103 |
147
+ | `LEGENDRE_ERROR_INVALID_BUFFER_SIZE` 8 | `BETA_PARAM_ERROR_INVALID_BUFFER_SIZE` 104 |
148
+ | `LEGENDRE_ERROR_POLE_NODE` 9 | `BETA_PARAM_ERROR_POLE_NODE` 105 |
149
+ | — (new) | `BETA_PARAM_ERROR_NODE_SET_MISMATCH` 106 |
150
+ | `LEGENDRE_ERROR_EMPTY_PARAMS` 3 | → shared 4 (compute) / 5 (init) |
151
+ | `LEGENDRE_ERROR_INVALID_MAX_PARAMS` 5 | → shared 5 / 3 / 2 by cause |
152
+ | `LEGENDRE_ERROR_TOO_MANY_PARAMS` 6 | → shared 1 |
153
+ | `LEGENDRE_ERROR_NO_UNIFORM_GRID` 10 | removed (no uniform grid) |
154
+
155
+ Note that the old and new numbering overlap: 2.x code 1 meant "north pole",
156
+ 3.0.0 code 1 means "too many params". Callers comparing raw integers must be
157
+ updated, not merely recompiled.
158
+
159
+ ### Changed: C API
160
+
161
+ Handle-based, with statuses reported through out-parameters instead of
162
+ in-band returns:
163
+
164
+ - `beta_param_tables_create(max_l, thetas, n_thetas, int* status)` /
165
+ `beta_param_tables_destroy` — new handle type `beta_param_tables_t*`.
166
+ - `beta_param_cache_create(n_params, thetas, n_thetas, conserve_volume,
167
+ apply_com, int* status)` and
168
+ `beta_param_cache_create_shared(tables, n_params, conserve_volume, apply_com,
169
+ int* status)` — both return `NULL` on failure and write the rejecting code to
170
+ the nullable `status` out-param. The 2.x `n_grid` + `message` arguments are
171
+ gone.
172
+ - Computes drop the `compute_` infix and the `_with_com_shift` variants:
173
+ `beta_param_cache_radius_grid`, `_radius_and_derivative`,
174
+ `_radius_grid_unchecked`, `_resolve_shape`, `_node_radius_and_derivative`,
175
+ `beta_param_radius_grid_standalone`, `_radius_and_derivative_standalone`.
176
+ Each returns the status code directly.
177
+ - `beta_param_status_message(int)` returns a static string; no caller-supplied
178
+ message buffers anywhere.
179
+ - Lifetime rule: a tables handle passed to `beta_param_cache_create_shared()`
180
+ or `beta_param_node_set_create()` must outlive everything built from it;
181
+ `beta_param_cache_destroy()` never frees shared tables.
182
+
183
+ ### Changed: C++ header
184
+
185
+ `beta_parameterization.hpp` (C++20, header-only) exposes `Tables`, `Cache` and
186
+ `NodeSet` RAII wrappers. `Cache` is move-only and thread-confined; its compute
187
+ methods are non-`const`. Status strings come from `beta_param_status_message`.
188
+ The 2.x concurrent-compute documentation is replaced, not amended.
189
+
190
+ ### Changed: Python wheel
191
+
192
+ - **BREAKING: `NodeSet` is removed.** BetaRender's single-set usage maps onto
193
+ the primary theta set. Node sets return to Python only when a consumer needs
194
+ a genuine second set — the same principle that keeps `tables_t` out of
195
+ Python.
196
+ - **BREAKING: `theta_grid(n)` is now the OPEN uniform grid**
197
+ `theta_i = i·π/(n+1), i = 1..n`. The 2.x closed `linspace(0, π, n)` includes
198
+ both poles, which the pole guard now rejects as cache input. Close plotted
199
+ curves with the analytic `r_north` / `r_south` from `resolve_shape`.
200
+ - Module-level tier 1: `radius_grid(params, thetas, conserve_volume=False,
201
+ apply_com=False)`, `radius_and_derivative(...)`.
202
+ - `Cache(n_params, thetas, conserve_volume=False, apply_com=False)` with
203
+ `.radius_grid`, `.radius_and_derivative`, `.radius_grid_unchecked`,
204
+ `.resolve_shape`. Thread-confined.
205
+ - **Returns are result objects, not exceptions**: `RadiusGridResult`,
206
+ `RadiusDerivativeResult`, `ResolvedShape`, each with `.ok`, `.status` and a
207
+ `.message` property. Shape-validation failures come back as a status-carrying
208
+ result; `BetaParamError` is raised only for usage errors (closed handle,
209
+ non-1-D params, create failure).
210
+ - The `Status` enum is renumbered per the table above.
211
+
212
+ ### Removed
213
+
214
+ - Concurrent-compute-on-one-cache support (see the breaking section above).
215
+ - The internally generated uniform theta grid and
216
+ `LEGENDRE_ERROR_NO_UNIFORM_GRID`.
217
+ - All `message` output arguments and the message-formatting code behind them.
218
+ - `*_with_com_shift` entry points (Fortran, C), superseded by the `apply_com`
219
+ creation flag.
220
+ - `beta_con` from every public signature.
221
+ - The `max_beta_params` padding argument on the standalone entry points.
222
+ - Python `NodeSet`.
223
+
224
+ ### Migration sketch
225
+
226
+ ```fortran
227
+ ! 2.x
228
+ call cache%init(max_beta_params = 4_ik, n_grid = 80_ik, error_code = ec, message = msg)
229
+ call cache%compute_radius_grid_with_com_shift(params, radii, ec, msg)
230
+ call cache%destroy()
231
+
232
+ ! 3.0.0 — the caller owns the theta set; flags are set once, at creation
233
+ thetas = [(i * PI / 81.0_rk, i = 1, 80)] ! open grid: no poles
234
+ call cache_init_s(cache, n_params = 4_ik, thetas = thetas, &
235
+ conserve_volume = .false., apply_com = .true., status = status)
236
+ call cache_radius_grid_s(cache, params, radii, status)
237
+ call cache_free_s(cache)
238
+ ```
239
+
240
+ ## 2.3.4 and earlier
241
+
242
+ No changelog was kept before 3.0.0. See the git history.
@@ -3,7 +3,7 @@ cmake_minimum_required(VERSION 3.20)
3
3
  include(FetchContent)
4
4
 
5
5
  project(beta-parameterization
6
- VERSION 2.3.4
6
+ VERSION 3.0.0
7
7
  LANGUAGES Fortran CXX
8
8
  DESCRIPTION "Beta parameterization for nuclear physics applications"
9
9
  )
@@ -24,7 +24,7 @@ FetchContent_MakeAvailable(GCC-Compiler-Options)
24
24
  FetchContent_Declare(
25
25
  Fortran-Foundations
26
26
  GIT_REPOSITORY https://github.com/AleksanderAugustyn/Fortran-Foundations.git
27
- GIT_TAG 2.3.2
27
+ GIT_TAG 2.4.0
28
28
  )
29
29
  FetchContent_MakeAvailable(Fortran-Foundations)
30
30
 
@@ -118,7 +118,8 @@ set_target_properties(beta_param_test_utils PROPERTIES
118
118
  target_include_directories(beta_param_test_utils PUBLIC
119
119
  $<BUILD_INTERFACE:${CMAKE_CURRENT_BINARY_DIR}/mod_files_tests>)
120
120
 
121
- set(BETA_PARAM_TEST_SUITES core com error breakdown golden node_set)
121
+ set(BETA_PARAM_TEST_SUITES status lifecycle resolve outputs standalone bitwise minimality
122
+ interleave boundary property golden)
122
123
  foreach (suite IN LISTS BETA_PARAM_TEST_SUITES)
123
124
  add_executable(beta_param_${suite}_test tests/beta_param_${suite}_test.f08)
124
125
  target_link_libraries(beta_param_${suite}_test PRIVATE
@@ -134,19 +135,35 @@ endforeach ()
134
135
  set_source_files_properties(tests/beta_param_golden_test.f08 PROPERTIES
135
136
  COMPILE_OPTIONS "-Wno-conversion-extra;-Wno-error=conversion-extra")
136
137
 
138
+ # Capture tool for the golden baseline: an executable, never a test.
137
139
  add_executable(golden_capture tests/golden_capture.f08)
138
140
  target_link_libraries(golden_capture PRIVATE
139
141
  beta_parameterization beta_param_test_utils beta_parameterization_flags)
140
142
  set_target_properties(golden_capture PROPERTIES
141
143
  Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod_files_tests/capture)
142
144
 
145
+ # PES-range sweep: 1.55M shapes, far too slow for ctest. An executable driven
146
+ # by an explicit custom target, never registered with add_test.
147
+ add_executable(beta_pes_sweep tests/beta_pes_sweep.f08)
148
+ target_link_libraries(beta_pes_sweep PRIVATE
149
+ beta_parameterization beta_param_test_utils beta_parameterization_flags)
150
+ set_target_properties(beta_pes_sweep PROPERTIES
151
+ Fortran_MODULE_DIRECTORY ${CMAKE_CURRENT_BINARY_DIR}/mod_files_tests/sweep)
152
+ add_custom_target(test_beta_pes_sweep
153
+ COMMAND beta_pes_sweep
154
+ DEPENDS beta_pes_sweep
155
+ COMMENT "Running the PES-range sweep (1.55M + 172.8k shapes)")
156
+
157
+ # C API smoke test: links the SHARED library, the binary the bindings load.
143
158
  add_executable(c_api_smoke_test tests/c_api_smoke_test.cpp)
144
159
  target_link_libraries(c_api_smoke_test PRIVATE beta_parameterization_cxx)
145
160
  add_test(NAME c_api_smoke COMMAND c_api_smoke_test)
146
161
 
162
+ # Thread model of 3.0.0: shared tables, per-thread caches, via the C++ wrapper.
147
163
  find_package(Threads REQUIRED)
148
164
  add_executable(thread_stress_test tests/thread_stress_test.cpp)
149
- target_link_libraries(thread_stress_test PRIVATE beta_parameterization_cxx Threads::Threads)
165
+ target_link_libraries(thread_stress_test PRIVATE
166
+ beta_parameterization_cxx Threads::Threads)
150
167
  add_test(NAME thread_stress COMMAND thread_stress_test)
151
168
 
152
169
  endif ()
@@ -1,6 +1,6 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: beta-parameterization
3
- Version: 2.3.4
3
+ Version: 3.0.0
4
4
  Summary: Python bindings for the beta (Legendre) nuclear-shape parameterization library
5
5
  License-Expression: MIT
6
6
  License-File: LICENSE
@@ -0,0 +1,263 @@
1
+ /**
2
+ * @file beta_parameterization.h
3
+ * @brief C API for the Fortran beta parameterization library (v3.0.0).
4
+ *
5
+ * Three handle types, from shared to per-shape:
6
+ * - `beta_param_tables_t` — everything determined by `max_l` and the
7
+ * primary theta set (normalization constants, Gauss-Legendre tables,
8
+ * Legendre tables at the primary thetas). Built once, shared read-only.
9
+ * - `beta_param_node_set_t` — an extra set of evaluation thetas with its own
10
+ * Legendre tables, sized to one tables handle. Immutable after creation.
11
+ * - `beta_param_cache_t` — per-shape working state: the recompute engine
12
+ * and every per-shape buffer. Mutated by every compute call.
13
+ *
14
+ * Two tiers of computation:
15
+ * - Cached: create a cache once, call the `beta_param_cache_*` functions for
16
+ * many shapes. Only the intermediates invalidated by the changed
17
+ * parameters are recomputed.
18
+ * - Standalone: one-off calls that build, use and discard their own tables.
19
+ *
20
+ * Thread safety (BREAKING CHANGE at 3.0.0 — the 2.x promise is withdrawn):
21
+ * A `beta_param_cache_t*` is THREAD-CONFINED. It is mutated by every compute
22
+ * call; concurrent use of one cache from more than one thread is undefined.
23
+ * Give every thread its own cache. `beta_param_tables_t*` and
24
+ * `beta_param_node_set_t*` are immutable after creation and may be shared
25
+ * across threads for concurrent reads, including as the backing tables of
26
+ * per-thread caches created with beta_param_cache_create_shared().
27
+ *
28
+ * Lifetime:
29
+ * A tables handle passed to beta_param_cache_create_shared() or
30
+ * beta_param_node_set_create() MUST outlive every cache and node set built
31
+ * from it — the cache/node set holds a reference, not a copy. Destroy order:
32
+ * node sets and caches first, their tables last.
33
+ *
34
+ * Diagnostics:
35
+ * There are no message buffers. `_create` functions return NULL on failure
36
+ * and write the reason to the nullable `int* status` out-parameter (pass
37
+ * NULL to ignore it). Every other function returns the status code directly;
38
+ * BETA_PARAM_VALID (0) means success. beta_param_status_message() maps a code
39
+ * to a fixed, static, null-terminated string; the returned pointer is owned
40
+ * by the library, never freed by the caller, and is safe to read from any
41
+ * thread.
42
+ *
43
+ * Failure behavior:
44
+ * On any nonzero status from a compute function, every output buffer is
45
+ * zero-filled and the cache is returned to a cold state — the next call
46
+ * recomputes from scratch. No partially updated results are ever visible.
47
+ * A NULL handle passed into a compute function returns
48
+ * BETA_PARAM_ERROR_CACHE_NOT_INITIALIZED (2).
49
+ *
50
+ * Precondition — finite input:
51
+ * `params` and `thetas` must be finite. Non-finite input is undefined
52
+ * behavior: the library cannot detect NaN under fast-math, so validation
53
+ * comparisons silently pass and the call returns BETA_PARAM_VALID (0) with
54
+ * NaN outputs. Screen inputs before calling.
55
+ */
56
+
57
+ #ifndef BETA_PARAMETERIZATION_H
58
+ #define BETA_PARAMETERIZATION_H
59
+
60
+ #ifdef __cplusplus
61
+ extern "C" {
62
+ #endif
63
+
64
+ /* --- Limits --- */
65
+ /** Highest Legendre order a tables handle may be built for. */
66
+ #define BETA_PARAM_MAX_PARAMS_LIMIT 64
67
+ /** Highest n_params a cache (cached tier) accepts. */
68
+ #define BETA_PARAM_CACHE_MAX_PARAMS 8
69
+
70
+ /* --- Shared contract status codes (0-99, identical numbers in every
71
+ * shape-parameterization library) --- */
72
+ #define BETA_PARAM_VALID 0
73
+ #define BETA_PARAM_ERROR_TOO_MANY_PARAMS 1
74
+ #define BETA_PARAM_ERROR_CACHE_NOT_INITIALIZED 2
75
+ #define BETA_PARAM_ERROR_INVALID_GRID 3
76
+ #define BETA_PARAM_ERROR_WRONG_PARAM_COUNT 4
77
+ #define BETA_PARAM_ERROR_INVALID_INIT 5
78
+ #define BETA_PARAM_ERROR_TABLES_NOT_INITIALIZED 6
79
+
80
+ /* --- Library status codes (>= 100, append-only after 3.0.0) --- */
81
+ #define BETA_PARAM_ERROR_NORTH_POLE 100
82
+ #define BETA_PARAM_ERROR_SOUTH_POLE 101
83
+ #define BETA_PARAM_ERROR_INTERIOR_NEGATIVE 102
84
+ #define BETA_PARAM_ERROR_COM_NOT_CONVERGED 103
85
+ #define BETA_PARAM_ERROR_INVALID_BUFFER_SIZE 104
86
+ #define BETA_PARAM_ERROR_POLE_NODE 105
87
+ #define BETA_PARAM_ERROR_NODE_SET_MISMATCH 106
88
+
89
+ /* --- Opaque handles --- */
90
+ typedef struct beta_param_tables beta_param_tables_t;
91
+ typedef struct beta_param_cache beta_param_cache_t;
92
+ typedef struct beta_param_node_set beta_param_node_set_t;
93
+
94
+ /* --- Diagnostics --- */
95
+
96
+ /**
97
+ * Fixed description of a status code. Never NULL; unknown codes map to an
98
+ * "unknown status code" string. The pointer is to static storage: do not free
99
+ * it, and it stays valid for the life of the process.
100
+ */
101
+ const char* beta_param_status_message(int status);
102
+
103
+ /* --- Tables lifecycle --- */
104
+
105
+ /**
106
+ * Build the shared immutable level. Returns NULL on failure.
107
+ *
108
+ * @param max_l 1 .. BETA_PARAM_MAX_PARAMS_LIMIT
109
+ * @param thetas Primary theta set in radians; at least 2 entries, none at
110
+ * or beyond a pole (cos(theta)^2 == 1 in double precision)
111
+ * @param n_thetas Number of entries in thetas
112
+ * @param status Nullable; receives BETA_PARAM_VALID or the rejecting code
113
+ */
114
+ beta_param_tables_t* beta_param_tables_create(
115
+ int max_l, const double* thetas, int n_thetas, int* status);
116
+
117
+ /** Destroy a tables handle. NULL-safe. Every cache and node set built from it
118
+ * must already be destroyed. */
119
+ void beta_param_tables_destroy(beta_param_tables_t* tables);
120
+
121
+ /* --- Cache lifecycle --- */
122
+
123
+ /**
124
+ * Create a cache that owns private tables built with max_l = n_params.
125
+ * Returns NULL on failure.
126
+ *
127
+ * @param n_params 1 .. BETA_PARAM_CACHE_MAX_PARAMS; the exact length
128
+ * every later params array must have
129
+ * @param thetas Primary theta set in radians (see tables_create)
130
+ * @param n_thetas Number of entries in thetas
131
+ * @param conserve_volume Nonzero: rescale radii to fixed volume
132
+ * @param apply_com Nonzero: apply the centre-of-mass correction
133
+ * @param status Nullable; receives the rejecting code on failure
134
+ */
135
+ beta_param_cache_t* beta_param_cache_create(
136
+ int n_params, const double* thetas, int n_thetas,
137
+ int conserve_volume, int apply_com, int* status);
138
+
139
+ /**
140
+ * Create a cache over caller-owned shared tables. Returns NULL on failure.
141
+ * The tables handle MUST outlive the cache; it is referenced, not copied, and
142
+ * beta_param_cache_destroy() never frees it.
143
+ *
144
+ * @param tables Tables handle; n_params must not exceed its max_l
145
+ * @param n_params 1 .. BETA_PARAM_CACHE_MAX_PARAMS
146
+ * @param conserve_volume Nonzero: rescale radii to fixed volume
147
+ * @param apply_com Nonzero: apply the centre-of-mass correction
148
+ * @param status Nullable; receives the rejecting code on failure
149
+ */
150
+ beta_param_cache_t* beta_param_cache_create_shared(
151
+ const beta_param_tables_t* tables, int n_params,
152
+ int conserve_volume, int apply_com, int* status);
153
+
154
+ /** Destroy a cache. NULL-safe. Shared tables are left untouched. */
155
+ void beta_param_cache_destroy(beta_param_cache_t* cache);
156
+
157
+ /* --- Node-set lifecycle --- */
158
+
159
+ /**
160
+ * Build an extra evaluation set (thetas plus Legendre P_k and P_k' tables)
161
+ * sized to `tables`. Returns NULL on failure — including a pole node, which is
162
+ * rejected with BETA_PARAM_ERROR_POLE_NODE; use the resolve_shape polar radii
163
+ * for the poles instead.
164
+ *
165
+ * @param tables Tables handle; must outlive the node set
166
+ * @param thetas Node angles in radians; any order, need not be uniform
167
+ * @param n_thetas Number of nodes (at least 2)
168
+ * @param status Nullable; receives the rejecting code on failure
169
+ */
170
+ beta_param_node_set_t* beta_param_node_set_create(
171
+ const beta_param_tables_t* tables, const double* thetas, int n_thetas,
172
+ int* status);
173
+
174
+ /** Destroy a node set. NULL-safe. */
175
+ void beta_param_node_set_destroy(beta_param_node_set_t* node_set);
176
+
177
+ /* --- Cached computes ---
178
+ *
179
+ * Every one of these mutates the cache (thread-confined, see above). `params`
180
+ * must hold exactly the cache's n_params entries, else
181
+ * BETA_PARAM_ERROR_WRONG_PARAM_COUNT. Output buffer lengths must equal the
182
+ * cache's theta count (or the node set's node count), else
183
+ * BETA_PARAM_ERROR_INVALID_BUFFER_SIZE. Radii and derivatives are
184
+ * COM-corrected and volume-scaled per the cache's flags.
185
+ */
186
+
187
+ /** R(theta) at the cache's primary thetas. `n_radii` must equal that count. */
188
+ int beta_param_cache_radius_grid(
189
+ beta_param_cache_t* cache, const double* params, int n_params,
190
+ double* radii, int n_radii);
191
+
192
+ /** R(theta) and dR/dtheta at the cache's primary thetas. */
193
+ int beta_param_cache_radius_and_derivative(
194
+ beta_param_cache_t* cache, const double* params, int n_params,
195
+ double* radii, double* dr_dthetas, int n_radii);
196
+
197
+ /**
198
+ * R(theta) at the primary thetas with NO validation gates and NO volume
199
+ * scaling — the rendering/diagnostic path. It reports usage errors only (not
200
+ * initialized, wrong parameter count, buffer size, COM non-convergence), so a
201
+ * shape rejected by the checked path still yields its (partly negative)
202
+ * outline instead of a zero-filled buffer.
203
+ *
204
+ * CAUTION: the radii are UNSCALED even on a cache created with
205
+ * conserve_volume = 1 — this path never computes the volume factor. Mixing it
206
+ * with beta_param_cache_radius_grid() on such a cache draws two outlines of
207
+ * different size for one shape; scale by beta_param_cache_resolve_shape()'s
208
+ * volume_factor if the sizes must agree.
209
+ */
210
+ int beta_param_cache_radius_grid_unchecked(
211
+ beta_param_cache_t* cache, const double* params, int n_params,
212
+ double* radii, int n_radii);
213
+
214
+ /**
215
+ * Resolve a shape without evaluating a grid: the COM-corrected beta10, the
216
+ * analytic polar radii, and the applied volume factor.
217
+ *
218
+ * `corrected_beta10` is a beta-space value and is never volume-scaled;
219
+ * `r_north` and `r_south` are scaled. `volume_factor` is exactly 1.0 when the
220
+ * cache was created with conserve_volume = 0.
221
+ */
222
+ int beta_param_cache_resolve_shape(
223
+ beta_param_cache_t* cache, const double* params, int n_params,
224
+ double* corrected_beta10, double* r_north, double* r_south,
225
+ double* volume_factor);
226
+
227
+ /**
228
+ * R(theta) and dR/dtheta at a node set's thetas. The node set must be built
229
+ * from tables whose max_l is at least the cache's n_params, else
230
+ * BETA_PARAM_ERROR_NODE_SET_MISMATCH. `n_nodes` must equal the node set's node
231
+ * count. This evaluation is not cached; the resolve/validation/volume
232
+ * intermediates behind it are.
233
+ */
234
+ int beta_param_cache_node_radius_and_derivative(
235
+ beta_param_cache_t* cache, const beta_param_node_set_t* node_set,
236
+ const double* params, int n_params,
237
+ double* radii, double* dr_dthetas, int n_nodes);
238
+
239
+ /* --- Standalone computes (tier 1) ---
240
+ *
241
+ * One-off: tables are built, used and discarded per call — no handle, nothing
242
+ * to free, no engine. `n_params` may be 1 .. BETA_PARAM_MAX_PARAMS_LIMIT (the
243
+ * cached-tier cap does not apply); above that,
244
+ * BETA_PARAM_ERROR_TOO_MANY_PARAMS, never silent truncation. Output buffers
245
+ * hold n_thetas doubles. Outputs are zero-filled on failure.
246
+ */
247
+
248
+ int beta_param_radius_grid_standalone(
249
+ const double* params, int n_params,
250
+ const double* thetas, int n_thetas,
251
+ int conserve_volume, int apply_com, double* radii);
252
+
253
+ int beta_param_radius_and_derivative_standalone(
254
+ const double* params, int n_params,
255
+ const double* thetas, int n_thetas,
256
+ int conserve_volume, int apply_com,
257
+ double* radii, double* dr_dthetas);
258
+
259
+ #ifdef __cplusplus
260
+ }
261
+ #endif
262
+
263
+ #endif /* BETA_PARAMETERIZATION_H */