dct-toolkit 0.6.0__tar.gz → 2.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 (42) hide show
  1. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/AGENTS.md +67 -27
  2. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/CHANGELOG.md +109 -0
  3. dct_toolkit-2.0.0/PKG-INFO +425 -0
  4. dct_toolkit-2.0.0/README.md +379 -0
  5. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/dct_toolkit/__init__.py +39 -21
  6. dct_toolkit-2.0.0/dct_toolkit/_gaussian.py +50 -0
  7. dct_toolkit-2.0.0/dct_toolkit/_geometry.py +560 -0
  8. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/dct_toolkit/_kernels.py +1 -1
  9. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/dct_toolkit/cartesian.py +7 -3
  10. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/dct_toolkit/core.py +15 -3
  11. dct_toolkit-2.0.0/dct_toolkit/polar.py +448 -0
  12. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/dct_toolkit/stats.py +309 -107
  13. dct_toolkit-2.0.0/docs/API_REFERENCE.md +499 -0
  14. dct_toolkit-2.0.0/docs/MATHEMATICAL_BASIS.md +406 -0
  15. dct_toolkit-2.0.0/docs/RELEASING.md +127 -0
  16. dct_toolkit-2.0.0/examples/nd_polar.py +96 -0
  17. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/pyproject.toml +2 -2
  18. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/tests/test_core.py +4 -4
  19. dct_toolkit-2.0.0/tests/test_gaussian.py +194 -0
  20. dct_toolkit-2.0.0/tests/test_geometry_precision.py +282 -0
  21. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/tests/test_polar_kernels.py +13 -4
  22. dct_toolkit-2.0.0/tests/test_polar_nd.py +619 -0
  23. dct_toolkit-2.0.0/tests/test_polar_nd_fallback.py +341 -0
  24. dct_toolkit-2.0.0/tests/test_polar_nd_stats.py +552 -0
  25. dct_toolkit-0.6.0/PKG-INFO +0 -199
  26. dct_toolkit-0.6.0/README.md +0 -153
  27. dct_toolkit-0.6.0/dct_toolkit/polar.py +0 -295
  28. dct_toolkit-0.6.0/docs/API_REFERENCE.md +0 -329
  29. dct_toolkit-0.6.0/docs/MATHEMATICAL_BASIS.md +0 -178
  30. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/.gitignore +0 -0
  31. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/LICENSE +0 -0
  32. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/dct_toolkit/_widths.py +0 -0
  33. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/dct_toolkit/gap_filling.py +0 -0
  34. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/examples/basic_polar.py +0 -0
  35. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/examples/comprehensive_demo.py +0 -0
  36. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/tests/test_api.py +0 -0
  37. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/tests/test_cartesian.py +0 -0
  38. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/tests/test_gap_filling.py +0 -0
  39. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/tests/test_polar.py +0 -0
  40. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/tests/test_polar_robustness.py +0 -0
  41. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/tests/test_stats.py +0 -0
  42. {dct_toolkit-0.6.0 → dct_toolkit-2.0.0}/tests/test_stats_nd.py +0 -0
@@ -1,9 +1,11 @@
1
1
  # AGENTS.md - DCT Toolkit Agent Guidelines
2
2
 
3
3
  **Project**: dct-toolkit
4
- **Version**: 0.6.0
5
- **Status**: Preparing v0.6.0 release (PyPI & conda-forge)
6
- **Last Updated**: 2026-09-21
4
+ **Version**: 2.0.0
5
+
6
+ **Status**: Full sampled Gaussian statistics release track
7
+
8
+ **Last Updated**: 2026-11-11
7
9
 
8
10
  ---
9
11
 
@@ -45,7 +47,16 @@ conda activate dct-publish
45
47
  - xarray, matplotlib, cmweather (radar colormaps)
46
48
  - open-radar-data (sample radar datasets)
47
49
  - build, twine (for PyPI publishing)
48
- - dct-toolkit v0.5.0 (editable install)
50
+ - dct-toolkit editable install (verify the runtime and installed-distribution versions)
51
+
52
+ After changing the package version, refresh editable installation metadata:
53
+
54
+ ```bash
55
+ conda run -n dct-publish python -m pip install --no-deps -e .
56
+ conda run -n dct-publish python -c 'from importlib.metadata import version; import dct_toolkit as dct; assert dct.__version__ == version("dct-toolkit")'
57
+ ```
58
+
59
+ An editable source import alone does not update installed distribution metadata.
49
60
 
50
61
  ### PYTHONPATH
51
62
  When running tests or examples from project root:
@@ -158,8 +169,9 @@ dct_toolkit/ # PROJECT ROOT
158
169
  ├── dct_toolkit/ # INSTALLABLE PACKAGE ⚠️ CODE GOES HERE
159
170
  │ ├── __init__.py # Public API exports
160
171
  │ ├── core.py # Transfer functions & 1D primitives
161
- │ ├── cartesian.py # 2D Cartesian separable smoothing
162
- │ ├── polar.py # 2D Polar smoothing (adaptive kernels)
172
+ │ ├── cartesian.py # N-D Cartesian separable smoothing
173
+ │ ├── polar.py # Legacy 2D and explicit geometry-aware N-D smoothing
174
+ │ ├── _geometry.py # Shared axis/coordinate/width validation and support
163
175
  │ ├── stats.py # Statistical ops (Normalized Convolution)
164
176
  │ └── gap_filling.py # Gap-filling methods (deferred for public stats-first release)
165
177
  │
@@ -189,7 +201,7 @@ dct_toolkit/ # PROJECT ROOT
189
201
  ├── docs/ # DOCUMENTATION
190
202
  │ ├── API_REFERENCE.md
191
203
  │ ├── MATHEMATICAL_BASIS.md
192
- │ └── GAP_FILLING_BASIS.md
204
+ │ └── RELEASING.md # Local build, artifact checks, and publication handoff
193
205
  │
194
206
  ├── README.md # Main documentation
195
207
  ├── CHANGELOG.md # Version history
@@ -215,7 +227,8 @@ dct_toolkit/ # PROJECT ROOT
215
227
 
216
228
  3. **Review Documentation**
217
229
  - Check `docs/MATHEMATICAL_BASIS.md` for theory
218
- - Check `docs/GAP_FILLING_BASIS.md` for gap filling theory
230
+ - Gap filling outside the exported statistics API remains research-internal;
231
+ inspect `dct_toolkit/gap_filling.py` only when that scope is requested
219
232
  - Check `docs/API_REFERENCE.md` for existing API
220
233
 
221
234
  ### Making Changes
@@ -245,6 +258,10 @@ python -m pytest /path/to/dct_toolkit/tests/ -v
245
258
 
246
259
  **Expected Output**: all tests passing
247
260
 
261
+ CI additionally runs the installed package outside the checkout, checks runtime
262
+ and distribution versions agree, and exercises the N-D example. Its minimum
263
+ dependency job uses Python 3.8, NumPy 1.20.0, and SciPy 1.8.0.
264
+
248
265
  **If Tests Fail**:
249
266
  - Fix the code, not the tests
250
267
  - Tests represent ground truth requirements
@@ -302,8 +319,19 @@ Before declaring task complete:
302
319
  - [x] Tag `v0.4.0` release
303
320
  - [x] Create `research/gap-filling` branch for long-term research
304
321
 
305
- ### 🔭 Future (v0.5.0 and beyond)
306
- - [ ] 3D support (volumetric data)
322
+ ### v1.0.0 Development Scope
323
+
324
+ - Geometry-aware N-D polar arrays with selectable azimuth, elevation, range,
325
+ time, linear, and batch roles in arbitrary array order.
326
+ - Per-axis kernels, boundaries, grid/physical width units, and filtering selection.
327
+ - Complete propagation through normalized moments, support, prefill, and fallback.
328
+ - Unfiltered axes remain isolated domains, including all-missing batches.
329
+ - Keep existing 2D calls compatible; explicit physical-coordinate mode is opt-in.
330
+ - New public APIs need independent numerical tests and an independent code/docs review.
331
+ - Do not modify manuscripts or review trackers as part of this software task.
332
+
333
+ ### Future Beyond v2.0.0
334
+
307
335
  - [ ] Additional kernels (Savitzky-Golay, Hanning)
308
336
  - [ ] Performance optimizations (numba?)
309
337
  - [ ] Jupyter notebook examples
@@ -317,17 +345,31 @@ Before declaring task complete:
317
345
  ### Transfer Functions
318
346
  - **Boxcar (Analytical)**: `H[k] = sin(W·θ)/(W·sin(θ))`, θ = πk/(2n)
319
347
  - **Boxcar (Discrete)**: Sum of cosines for discrete kernels
320
- - **Gaussian**: `H[k] = exp(-0.5·(ω·σ)²)`, σ = width/√12
348
+ - **Gaussian (default)**: full normalized sampled Gaussian, σ = width/√12;
349
+ evaluate its cosine sum or equivalent frequency-alias sum to float64 precision.
350
+ No fixed spatial cutoff; nonnegative spatial weights support statistical moments.
351
+ - **Gaussian (spectral compatibility)**: `gaussian_spectral` retains
352
+ `H[k] = exp(-0.5·(ω·σ)²)`, σ = width/√12; spatial weights can be signed.
321
353
 
322
354
  ### Normalized Convolution
323
355
  Formula for robust mean with gaps:
324
356
  ```
325
- μ = smooth(data * mask) / (smooth(mask) + ε)
357
+ μ = smooth(zero_filled_valid_data) / smooth(valid_mask)
326
358
  ```
359
+ Apply the complete smoothing operator to each input before normalizing once.
360
+ The denominator must be strictly greater than the floor (default `1e-3`);
361
+ unsupported locations use the documented selective prefill fallback. This is
362
+ not additive-epsilon regularization. `dct_count` reports nominal weighted
363
+ support, not statistical effective sample size.
327
364
 
328
365
  ### Polar Coordinates
329
- - **Data Layout**: (n_azimuth, n_range)
330
- - **Adaptive Width**: w_az(r) = width / (r · dθ)
366
+ - **Legacy Data Layout**: (n_azimuth, n_range), retaining index-based width units.
367
+ - **Explicit N-D Mode**: axis roles, coordinates, and units define the geometry.
368
+ - **Physical Angular Widths**: azimuth scales with `1 / (r * cos(elevation) * dθ)`;
369
+ elevation scales with `1 / (r * dφ)`. Use actual coordinates, not gate indices.
370
+ - **Filter Order**: azimuth, elevation, range, then independent time/linear axes;
371
+ this is an ordered nonstationary operator, not one global separable transform.
372
+ - **Fallback Domains**: never borrow support across unfiltered/batch axes.
331
373
  - **Boundary Conditions**:
332
374
  - Reflective: DCT-II (even symmetry)
333
375
  - Periodic: Real FFT (circular convolution)
@@ -412,25 +454,23 @@ git merge feature/hanning-window
412
454
  ```
413
455
 
414
456
  ### Repository Status
415
- - GitHub: Private (core team access only)
416
- - PyPI: **Public** — `pip install dct-toolkit` works
417
- - conda-forge: **Submitted** — PR #32930 in review at `conda-forge/staged-recipes`
418
-
419
- **Check conda-forge PR Status**:
420
- ```bash
421
- gh pr view 32930 --repo conda-forge/staged-recipes
422
- # Or visit: https://github.com/conda-forge/staged-recipes/pull/32930
423
- ```
457
+ - GitHub: **Public** — `JValdivia23/dct-toolkit`
458
+ - PyPI: **Public** distribution channel; local version changes do not publish a release
459
+ - conda-forge: **Approved & Merged** — Feedstock live at `conda-forge/dct-toolkit-feedstock`
424
460
 
425
461
  ### Current Version
426
- - `v0.6.0` — Support for anisotropic smoothing widths, per-axis Cartesian kernels,
427
- mixed polar kernels, periodic polar prefill, and effective density gating.
428
- - Tag: `git checkout v0.6.0`
462
+
463
+ - Version: `2.0.0`, using the full sampled Gaussian by default across smoothing
464
+ and statistics. Use `gaussian_spectral` to reproduce pre-2.0 Gaussian results.
465
+ - Preserve the historical `v1.0.0`, `v0.6.0`, and older release records.
466
+ - Do not tag, push, upload to PyPI/conda-forge, or create a public archival record
467
+ without approval.
468
+ - See `docs/RELEASING.md` for local artifact verification and release handoff.
429
469
 
430
470
  ### Gap-Filling Status
431
471
  - Code exists in `dct_toolkit/gap_filling.py` (available for import directly)
432
472
  - **Not exported** in public API (`__init__.py`) — research-internal
433
- - Full gap-filling to be released in future v1.x after research matures
473
+ - Full gap-filling to be released in a future version after research matures
434
474
 
435
475
  ---
436
476
 
@@ -5,6 +5,115 @@ All notable changes to this project will be documented in this file.
5
5
  The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/),
6
6
  and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html).
7
7
 
8
+ ## [Unreleased]
9
+
10
+ ## [2.0.0] - 2026-11-11
11
+
12
+ Major release changing the default Gaussian's numerical definition. Existing
13
+ calls remain accepted, but Gaussian outputs change. For reproducible pre-2.0
14
+ results, explicitly select `'gaussian_spectral'` wherever Gaussian filtering was
15
+ previously used, including each Gaussian entry in hybrid kernel sequences.
16
+ Widths, coordinate conventions, and the public function signatures are unchanged.
17
+
18
+ ### Breaking Changes
19
+ - Redefine `'gaussian'`, the default kernel, as the full normalized sampled
20
+ Gaussian rather than the exponential spectral response used in v1.0.0.
21
+ This affects existing smoothing/statistics calls even when `kernel_type`
22
+ is omitted. Use `'gaussian_spectral'` to retain the previous response.
23
+
24
+ ### Changed
25
+ - Make the default `'gaussian'` kernel the full normalized sampled Gaussian,
26
+ evaluated to floating-point precision without a fixed spatial truncation.
27
+ Cartesian, legacy polar, explicit N-D polar, both boundaries, normalized
28
+ moments, prefill, and fallback now share this nonnegative spatial kernel.
29
+ Numerical results change, particularly for widths near or below one grid cell.
30
+ - Preserve the previous exponential response as `'gaussian_spectral'` for
31
+ reproducing v1.0.0 Gaussian results, including per-axis hybrid selections.
32
+ Its spatial weights can be signed; it is not the default for statistics.
33
+
34
+ ### Fixed
35
+ - Remove substantive negative raw variances caused by Gaussian spatial ringing.
36
+ The final variance clamp remains for floating-point cancellation. Positivity
37
+ requires nonnegative kernels on every selected axis; fractional analytical
38
+ boxcars and `'gaussian_spectral'` do not provide that guarantee.
39
+ - Evaluate broad sampled Gaussians with an equivalent frequency-alias sum,
40
+ avoiding allocations proportional to potentially enormous effective widths.
41
+
42
+ ### Documentation
43
+ - Document sampled Gaussian normalization, numerical evaluation, narrow-width
44
+ behavior, statistical guarantees, and migration to `'gaussian_spectral'`.
45
+ - Clarify required N-D polar metadata, the default physical width units, and
46
+ coordinate dependencies; add a runnable coordinate-free grid-width example.
47
+ - Compare Cartesian and explicit polar N-D processing, including boundaries,
48
+ axis selection, and the conditions for equivalent finite-data smoothing.
49
+ - Explain input-NaN restoration and the low-level polar width argument in the README.
50
+
51
+ ## [1.0.0] - 2026-10-26
52
+
53
+ Geometry-aware N-D polar release, preserving the v0.6.0 legacy 2D interface.
54
+
55
+ ### Added
56
+ - Explicit N-D polar geometry through keyword-only `axis_types`, `axis_coords`,
57
+ `boundary`, `width_units`, `angle_units`, and `filter_axes` in `smooth_polar`,
58
+ forwarded by the smoothing wrapper and statistics with `coordinates='polar'`.
59
+ - Named azimuth/elevation/range axes in arbitrary array order, plus time, linear
60
+ (`cartesian` alias), and independent batch axes; per-axis widths, kernels,
61
+ boundaries, and physical/grid units follow array order.
62
+ - Physical angular widths use actual range and elevation geometry:
63
+ `L_az / (R*cos(elevation)*delta_az)` and `L_el / (R*delta_el)` in grid cells.
64
+ Regular coordinate validation rejects singular origins/poles and incomplete
65
+ non-singleton physical periodic azimuth grids rather than capping widths.
66
+ - Synthetic, plotting-free `examples/nd_polar.py` demonstrates a
67
+ `(time, elevation, azimuth, range)` field, missing data, mixed kernels/boundaries,
68
+ axis permutation, and isolation of unfiltered time slices.
69
+
70
+ ### Changed
71
+ - Explicit geometry uses canonical azimuth/elevation/range/time/linear filter
72
+ order independently of array storage order. The generally nonseparable,
73
+ noncommuting operator is not an exact isotropic or cell-volume convolution.
74
+ - Batch and unfiltered dimensions remain independent through smoothing,
75
+ normalized statistics, iterative filling, and every fallback. They do not
76
+ contribute nominal support area; wholly missing independent domains stay NaN.
77
+ - Documented `dct_count` as nominal weighted support, distinct from literal
78
+ neighbor counts and squared-weight statistical ESS, including repeated samples
79
+ at reflective/periodic boundaries.
80
+
81
+ ### Documentation corrections
82
+ - Removed the additive-epsilon description: the normal public mean ratio uses
83
+ the full operator once on data and mask and requires a denominator strictly
84
+ greater than `1e-3`. Variance estimates both moments independently, including
85
+ separate fallback prefills of `x` and `x**2`, then clamps negative results.
86
+ - Qualified nonnegative-weight statistical guarantees: arbitrary fractional
87
+ spectral kernels need not have nonnegative spatial weights.
88
+ - Replaced the broken mathematical-guide link to the removed gap-filling basis
89
+ with research-internal module documentation, without adding a public export.
90
+
91
+ ### Fixed
92
+ - Validate integer coordinate spacing before floating-point conversion, including
93
+ large time origins and overflow-safe signed/unsigned integer differences.
94
+ - Promote low-precision floating coordinates before spacing validation, avoiding
95
+ subtraction overflow and concealed irregular grids without downcasting wider types.
96
+ - Compute nominal support lazily with exponent scaling. An unrepresentable count
97
+ factor no longer prevents valid smoothing or normalized-moment computations;
98
+ individual effective widths remain validated.
99
+ - Remove array-layout bias from repeated time/linear-role fallback through joint
100
+ mixed-boundary nearest completion and symmetric averaging of exact global ties.
101
+ Legacy 2D axis-wise tie rules remain unchanged.
102
+ - Preserve zero-dimensional array outputs during count, variance, and standard
103
+ deviation mask restoration, consistently with smoothing and mean operations.
104
+ - Check installed runtime/distribution version alignment and run the suite against
105
+ the installed package in CI, including Python 3.8 with NumPy 1.20.0/SciPy 1.8.0.
106
+ - Document editable metadata refresh and the coordinated PyPI/conda-forge release
107
+ process, including checksums of the exact published source archive.
108
+
109
+ ### Compatibility
110
+ - Existing `smooth_polar` positional arguments, the `width_pixels` name, and
111
+ positional `width` in high-level functions are unchanged.
112
+ - `axis_types=None` preserves the legacy 2D `(azimuth, range)` path, index-based
113
+ range convention, scalar/pair widths and kernels, and existing boundary rules.
114
+ Nondefault new geometry options require explicit `axis_types`; old widths are
115
+ not silently reinterpreted as physical distances.
116
+
8
117
  ## [0.6.0] - 2026-09-21
9
118
 
10
119
  ### Changed