Release 3.2.0: structure-function API rename, kernel lengths, field and noise realizations - #41
Merged
Merged
Conversation
The accumulated structure-function work that had been sitting in the
working tree. Committed as one base so later changes are reviewable
against a known state rather than against an unversioned checkout.
- Rename to the calculate_/fit_/plot_ convention; StructureFunction2D*
drop the 2D suffix. Old spellings alias through a PEP 562 module
__getattr__ with a DeprecationWarning, removal in 4.0.
- calculate_heuristics defaults to length_scale='kernel', so heuristic
and fit_GRF lengths are finally in one convention.
- Declare grid= ('polar'/'cartesian') on every bare-array entry point;
radius/azimuth analyses refuse a Cartesian grid, and S2_i is None on
a polar grid rather than mixing arcsec with degrees.
- plateau() and half_power_lag() exclude unpopulated lag bins.
- Field realizations: draw_polar_field, make_polar_grid, and
StructureFunction.draw_realization (spectral synthesis from a
measured S_2, defaulting sigma2 to plateau()/2 and warning when the
PSD clip is large).
- Module-level calculate_structure_function[_stack] entry points.
Completes the {analytic, empirical} x {S_2 prediction, field
realization} set: gaussian_beam_s2 had no realization counterpart, and
draw_realization had no cube-level wrapper, so downstream projects were
carrying their own copies of both. The structure-function papers'
paper2/notebooks/noise.py was one such fork, and it had drifted -- it
took the injected variance from max(S2)/2 where draw_realization uses
plateau()/2, over-dispersing every empirical noise draw by 6-10% in
realized variance on four production ALMA cubes.
- gaussian_beam_realization(shape, dpix, bmaj, bmin, bpa, sigma, ...):
white noise convolved with a unit-power Gaussian beam kernel, in the
same beam frame as gaussian_beam_s2 (FITS PA east of north, axis 0 =
+DEC / axis 1 = -RA). Unit power means the output sits at the
requested per-pixel sigma whatever the beam size, matching the
2*sigma2 plateau gaussian_beam_s2 predicts.
- imagecube.noise_realization(method, ...): fills shape, dpix and beam
from the object and dispatches to gaussian_beam_realization or
StructureFunction.draw_realization, mirroring how
linecube.gaussian_beam_s2 already wraps the module-level function.
On imagecube so momentmap and rotationmap get it too. The analytic
sigma defaults to estimate_cube_RMS() on a linecube and is required
elsewhere rather than invented.
Verified bit-identical to the fork it replaces on the analytic path,
and on the empirical path once the old sigma2 is passed explicitly, so
the only behaviour change is the normalization above.
Tested: the measured S_2 of the draws matches gaussian_beam_s2 to 0.8%
RMS of the plateau while missing a 90-degree-rotated beam by 16%, so an
axis swap or sign error in the beam frame cannot pass.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Bump the version to 3.2.0 and date the CHANGELOG section that had been accumulating under [Unreleased] since 3.1.1: the structure-function API rename, the `grid=` declaration on the bare-array entry points, the kernel-length convention, and the field/noise realization additions. Also document the two realization entry points that had been left out of docs/user/structurefunction.rst -- `gaussian_beam_realization` and the cube-level `imagecube.noise_realization` -- and say in prose how the parametric and empirical noise nulls relate. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was no written release flow, and the history shows it: 3.0.1 and 3.1.0 were never tagged, and 3.1.0 never reached PyPI at all despite having a CHANGELOG entry. Write down the six steps -- dual version bump, local checks, annotated tag, scoped twine upload, GitHub release, confirm -- so the easy-to-skip ones are on a list. Notes the two gotchas hit while cutting 3.2.0: the docs build needs pandoc on PATH (a system package) for nbsphinx, and `twine upload` must be scoped to the new version's artifacts because a bare `dist/*` re-submits every previous release. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Cuts 3.2.0. Three commits: the structure-function API rename and kernel-length
convention, the beam-convolved noise realizations, and the release prep
(version bump, dated CHANGELOG, two missing doc entries).
Changed
calculate_/fit_/plot_convention, and the result classes dropped their
2Dsuffix —StructureFunctionandStructureFunctionStack. Every old spelling stillworks but emits a
DeprecationWarningand goes away in 4.0. The classaliases are served through a module-level
__getattr__(PEP 562) ratherthan as subclasses, so
isinstancechecks against the old names areunaffected, and a plain
import eddydoes not warn.calculate_heuristicsnow returns kernel correlation lengths, nothalf-power lags. The two differ by
sqrt(2 ln 2) = 1.1774, so before thischange
calculate_heuristicsandfit_GRFreturned numbers that differedby that factor on identical data and nothing in the test suite noticed. The
old behavior is available as
length_scale='halfpower'.grid=on every bare-array entry point, defaulting to'polar'. Thekernel is a generic regular-grid lag estimator and cannot infer the
geometry, so it is now declared rather than assumed; the radius/azimuth
analyses raise on a Cartesian result instead of reading its second axis as
degrees.
Added
draw_polar_field(exact Paciorek–Schervishfactorization, or a spatially-varying process convolution that targets the
same covariance without forming an
N x Nmatrix),make_polar_grid,polar_covariance, andStructureFunction.draw_realizationforWiener–Khinchin synthesis from a measured
S_2.gaussian_beam_realization(the realizationcounterpart of
gaussian_beam_s2, and the naive-PSF null todraw_realization's empirical one) andimagecube.noise_realizationasthe cube-level entry point to both backends.
calculate_structure_function/calculate_structure_function_stack,so the bare-array and sky-map routes share one verb.
Fixed
S2_iis no longer returned in mixed units from the bare-array polar path.See
CHANGELOG.mdfor the full list.Checks
pytest: 93 passed (58 at 3.1.0). Newtests/test_length_convention.pypins the kernel-length convention end to end, including the slice-mode
stack
fit_GRFpath that had no coverage before.ruff check .: clean.docs/user/structurefunction.rstbuilds with every new cross-referenceresolving.
Known gaps, not blocking
fit_GRF(method='mcmc')is still untested; thelsqpath is well covered.fit_GRF/calculate_heuristicssee the axis-alignedchords of a pitched correlation ellipse, so
ell0phiand the anisotropyare biased low when
pitch != 0. Only the global-surfacefit_GRF(pitch=True, r_axis=...)recovers the truth. The docs say pitch isonly measurable in global mode but do not yet warn that the slice values
are biased.
clean restart-and-run-all.
🤖 Generated with Claude Code