Skip to content

Commit 4489dd4

Browse files
cailmdaleyclaude
andcommitted
Simplify sacc_io writers/readers and test builders
- Factor the theta-tagged insertion loop into _add_theta_series (add_rho, add_tau, add_pure_eb); add_pure_eb zips PURE_TYPES.values() against its signature order, and PURE_KEYS is derived from PURE_TYPES instead of restating it. - Factor the (theta, plus, minus) read pattern into _get_pm (get_xi, get_rho, get_tau). - add_xi hoists the optional-tag None-filtering out of the point loop; extract and merge lose their throwaway mutable dicts; get_cosebis builds its scale-cut tags in one expression. - Tests: shared _add_xi default-ξ builder and _xi_block/_cl_block/ _cosebi_block canonical index-block helpers replace ~60 lines of copy-pasted setup; test_readers_on_mixed_file builds on _multi_statistic_sacc. Behaviour unchanged; 41/41 tests green in the container. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01QWF72ofwJh6ekgnCt9Xx6C
1 parent 87b3598 commit 4489dd4

2 files changed

Lines changed: 89 additions & 152 deletions

File tree

src/sp_validation/sacc_io.py

Lines changed: 42 additions & 61 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,11 @@
7474
"xip_amb": "galaxy_shear_xiPureAmb_plus",
7575
"xim_amb": "galaxy_shear_xiPureAmb_minus",
7676
}
77-
# Insertion order of the six pure-EB blocks — matches b_modes._EB_KEYS, whose
78-
# order is the [xip_E; xim_E; xip_B; xim_B; xip_amb; xim_amb] layout of the
79-
# treecorr/MC pure-EB covariance (b_modes.calculate_eb_statistics, ~L392).
80-
PURE_KEYS = ("xip_E", "xim_E", "xip_B", "xim_B", "xip_amb", "xim_amb")
77+
# PURE_TYPES key order is the insertion order of the six pure-EB blocks —
78+
# matches b_modes._EB_KEYS, whose order is the [xip_E; xim_E; xip_B; xim_B;
79+
# xip_amb; xim_amb] layout of the treecorr/MC pure-EB covariance
80+
# (b_modes.calculate_eb_statistics, ~L392).
81+
PURE_KEYS = tuple(PURE_TYPES)
8182

8283
RHO_PLUS = "psf_rho{k}_xi_plus"
8384
RHO_MINUS = "psf_rho{k}_xi_minus"
@@ -155,6 +156,12 @@ def _check_ascending(name, values):
155156
)
156157

157158

159+
def _add_theta_series(s, dtype, tracers, theta, values):
160+
"""Insert one theta-tagged series, one point per (theta, value) pair."""
161+
for th, value in zip(theta, values):
162+
s.add_data_point(dtype, tracers, float(value), theta=float(th))
163+
164+
158165
def add_xi(
159166
s,
160167
bins,
@@ -191,15 +198,15 @@ def add_xi(
191198
"""
192199
_check_ascending("theta", theta)
193200
tracers = _pair(bins)
201+
optional = {"theta_nom": theta_nom, "npairs": npairs, "weight": weight}
202+
extras = {key: arr for key, arr in optional.items() if arr is not None}
194203
for dtype, xi in ((XI_PLUS, xip), (XI_MINUS, xim)):
195204
for n, th in enumerate(theta):
196-
tags = {"theta": float(th), "grid": grid}
197-
if theta_nom is not None:
198-
tags["theta_nom"] = float(theta_nom[n])
199-
if npairs is not None:
200-
tags["npairs"] = float(npairs[n])
201-
if weight is not None:
202-
tags["weight"] = float(weight[n])
205+
tags = {
206+
"theta": float(th),
207+
"grid": grid,
208+
**{key: float(arr[n]) for key, arr in extras.items()},
209+
}
203210
s.add_data_point(dtype, tracers, float(xi[n]), **tags)
204211

205212

@@ -293,18 +300,9 @@ def add_pure_eb(s, bins, theta, xip_E, xim_E, xip_B, xim_B, xip_amb, xim_amb):
293300
"""
294301
_check_ascending("theta", theta)
295302
tracers = _pair(bins)
296-
values = {
297-
"xip_E": xip_E,
298-
"xim_E": xim_E,
299-
"xip_B": xip_B,
300-
"xim_B": xim_B,
301-
"xip_amb": xip_amb,
302-
"xim_amb": xim_amb,
303-
}
304-
for key in PURE_KEYS:
305-
dtype, arr = PURE_TYPES[key], values[key]
306-
for n, th in enumerate(theta):
307-
s.add_data_point(dtype, tracers, float(arr[n]), theta=float(th))
303+
arrays = (xip_E, xim_E, xip_B, xim_B, xip_amb, xim_amb)
304+
for dtype, arr in zip(PURE_TYPES.values(), arrays):
305+
_add_theta_series(s, dtype, tracers, theta, arr)
308306

309307

310308
def add_rho(s, k, theta, rho_p, rho_m):
@@ -323,9 +321,8 @@ def add_rho(s, k, theta, rho_p, rho_m):
323321
"""
324322
_check_ascending("theta", theta)
325323
tracers = (PSF_TRACER, PSF_TRACER)
326-
for dtype, arr in ((RHO_PLUS.format(k=k), rho_p), (RHO_MINUS.format(k=k), rho_m)):
327-
for n, th in enumerate(theta):
328-
s.add_data_point(dtype, tracers, float(arr[n]), theta=float(th))
324+
_add_theta_series(s, RHO_PLUS.format(k=k), tracers, theta, rho_p)
325+
_add_theta_series(s, RHO_MINUS.format(k=k), tracers, theta, rho_m)
329326

330327

331328
def add_tau(s, bins, k, theta, tau_p, tau_m):
@@ -347,9 +344,8 @@ def add_tau(s, bins, k, theta, tau_p, tau_m):
347344
"""
348345
_check_ascending("theta", theta)
349346
tracers = (source_name(bins[0]), PSF_TRACER)
350-
for dtype, arr in ((TAU_PLUS.format(k=k), tau_p), (TAU_MINUS.format(k=k), tau_m)):
351-
for n, th in enumerate(theta):
352-
s.add_data_point(dtype, tracers, float(arr[n]), theta=float(th))
347+
_add_theta_series(s, TAU_PLUS.format(k=k), tracers, theta, tau_p)
348+
_add_theta_series(s, TAU_MINUS.format(k=k), tracers, theta, tau_m)
353349

354350

355351
def assemble_covariance(s, blocks):
@@ -453,16 +449,20 @@ def get_nz(s, i):
453449
return tracer.z, tracer.nz
454450

455451

456-
def get_xi(s, bins, *, grid):
457-
"""Return ``(theta, xip, xim)`` for one tracer pair and grid."""
458-
tracers = _pair(bins)
452+
def _get_pm(s, dtype_p, dtype_m, tracers, **tags):
453+
"""Return ``(theta, plus, minus)`` for a +/− data-type pair."""
459454
return (
460-
_tag(s, XI_PLUS, tracers, "theta", grid=grid),
461-
_mean(s, XI_PLUS, tracers, grid=grid),
462-
_mean(s, XI_MINUS, tracers, grid=grid),
455+
_tag(s, dtype_p, tracers, "theta", **tags),
456+
_mean(s, dtype_p, tracers, **tags),
457+
_mean(s, dtype_m, tracers, **tags),
463458
)
464459

465460

461+
def get_xi(s, bins, *, grid):
462+
"""Return ``(theta, xip, xim)`` for one tracer pair and grid."""
463+
return _get_pm(s, XI_PLUS, XI_MINUS, _pair(bins), grid=grid)
464+
465+
466466
def get_pseudo_cl(s, bins):
467467
"""Return ``(ell_eff, cl_ee, cl_bb, cl_eb, window)`` for one tracer pair.
468468
@@ -491,11 +491,7 @@ def get_cosebis(s, bins, scale_cut=None):
491491
``(theta_min, theta_max)`` to select when several cuts share the file.
492492
"""
493493
tracers = _pair(bins)
494-
tags = (
495-
{"theta_min": float(scale_cut[0]), "theta_max": float(scale_cut[1])}
496-
if scale_cut is not None
497-
else {}
498-
)
494+
tags = dict(zip(("theta_min", "theta_max"), map(float, scale_cut or ())))
499495
modes = _tag(s, COSEBI_EE, tracers, "n", **tags)
500496
return (
501497
modes.astype(int),
@@ -518,23 +514,13 @@ def get_pure_eb(s, bins):
518514
def get_rho(s, k):
519515
"""Return ``(theta, rho_p, rho_m)`` for ρ index ``k``."""
520516
tracers = (PSF_TRACER, PSF_TRACER)
521-
dt_p, dt_m = RHO_PLUS.format(k=k), RHO_MINUS.format(k=k)
522-
return (
523-
_tag(s, dt_p, tracers, "theta"),
524-
_mean(s, dt_p, tracers),
525-
_mean(s, dt_m, tracers),
526-
)
517+
return _get_pm(s, RHO_PLUS.format(k=k), RHO_MINUS.format(k=k), tracers)
527518

528519

529520
def get_tau(s, bins, k):
530521
"""Return ``(theta, tau_p, tau_m)`` for τ index ``k`` and source bin."""
531522
tracers = (source_name(bins[0]), PSF_TRACER)
532-
dt_p, dt_m = TAU_PLUS.format(k=k), TAU_MINUS.format(k=k)
533-
return (
534-
_tag(s, dt_p, tracers, "theta"),
535-
_mean(s, dt_p, tracers),
536-
_mean(s, dt_m, tracers),
537-
)
523+
return _get_pm(s, TAU_PLUS.format(k=k), TAU_MINUS.format(k=k), tracers)
538524

539525

540526
def _mean(s, data_type, tracers, **tag_filters):
@@ -583,11 +569,8 @@ def extract(s, data_type=None, tracers=None, **tag_filters):
583569
New Sacc holding only the selected points.
584570
"""
585571
sub = s.copy()
586-
selection = {}
587-
if tracers is not None:
588-
selection["tracers"] = tuple(tracers)
589-
selection.update(tag_filters)
590-
sub.keep_selection(data_type, **selection)
572+
tracer_filter = {"tracers": tuple(tracers)} if tracers is not None else {}
573+
sub.keep_selection(data_type, **tracer_filter, **tag_filters)
591574
return sub
592575

593576

@@ -631,11 +614,9 @@ def merge(saccs):
631614
metadata[key] = value
632615
# Strip metadata before concatenating (the library "resolves" clashing
633616
# keys by renaming them), then restore the validated union.
634-
stripped = []
635-
for s in saccs:
636-
s = s.copy()
617+
stripped = [s.copy() for s in saccs]
618+
for s in stripped:
637619
s.metadata.clear()
638-
stripped.append(s)
639620
seen, shared = set(), set() # tracers appearing in more than one input
640621
for s in saccs:
641622
shared |= seen & set(s.tracers)

0 commit comments

Comments
 (0)