Skip to content

Commit fa7a7e3

Browse files
authored
gh-385: Non square mms (#384)
1 parent e9a3e5a commit fa7a7e3

File tree

2 files changed

+115
-3
lines changed

2 files changed

+115
-3
lines changed

heracles/twopoint.py

Lines changed: 33 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -31,7 +31,7 @@
3131

3232
from .core import TocDict, toc_match, update_metadata
3333
from .progress import NoProgress, Progress
34-
from .result import Result, binned
34+
from .result import Result, binned, get_result_array
3535

3636
try:
3737
from copy import replace
@@ -461,7 +461,25 @@ def invert_mixing_matrix(
461461
else:
462462
_inv_M = np.linalg.pinv(_M, rcond=_rcond)
463463

464-
inv_M[key] = replace(M[key], array=_inv_M)
464+
if _n != _m:
465+
# A pseudo-inverse swaps output/input ell dimensions. Build
466+
# angular arrays from the inverse output size (row dimension).
467+
axis = value.axis[0]
468+
out_size = _inv_M.shape[axis]
469+
ell = np.arange(out_size)
470+
lower = np.arange(out_size)
471+
upper = np.arange(1, out_size + 1)
472+
weight = np.ones(out_size)
473+
inv_M[key] = replace(
474+
M[key],
475+
array=_inv_M,
476+
ell=ell,
477+
lower=lower,
478+
upper=upper,
479+
weight=weight,
480+
)
481+
else:
482+
inv_M[key] = replace(M[key], array=_inv_M)
465483
return inv_M
466484

467485

@@ -480,6 +498,11 @@ def apply_mixing_matrix(d, M):
480498
s1, s2 = d[key].spin
481499
_d = np.atleast_2d(d[key].array)
482500
_M = M[key].array
501+
# Output angular metadata follows the matrix output ell axis.
502+
_ell = get_result_array(M[key], "ell")[0]
503+
_lower = get_result_array(M[key], "lower")[0]
504+
_upper = get_result_array(M[key], "upper")[0]
505+
_weight = get_result_array(M[key], "weight")[0]
483506
if (s1 != 0) and (s2 != 0):
484507
_corr_d_EE = _M[0] @ _d[0, 0] + _M[1] @ _d[1, 1]
485508
_corr_d_BB = _M[1] @ _d[0, 0] + _M[0] @ _d[1, 1]
@@ -492,5 +515,12 @@ def apply_mixing_matrix(d, M):
492515
_corr_d.append(_M @ cl)
493516
_corr_d = np.squeeze(_corr_d)
494517
_corr_d = np.array(list(_corr_d), dtype=dtype)
495-
corr_d[key] = replace(d[key], array=_corr_d)
518+
corr_d[key] = replace(
519+
d[key],
520+
array=_corr_d,
521+
ell=_ell,
522+
lower=_lower,
523+
upper=_upper,
524+
weight=_weight,
525+
)
496526
return corr_d

tests/test_twopoint.py

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -418,3 +418,85 @@ def test_inverting_mixing_matrices():
418418
_mixed_cls = np.sum(mixed_cls[key].array)
419419
print(key, _mixed_cls)
420420
np.testing.assert_allclose(_mixed_cls, (n + 1) * 1.0)
421+
422+
423+
def test_nonsquare_mixing_matrix_metadata_binning_and_io(tmp_path):
424+
import heracles
425+
426+
from heracles.twopoint import Result, apply_mixing_matrix, invert_mixing_matrix
427+
428+
key = ("POS", "POS", 0, 0)
429+
430+
in_ell = np.arange(8)
431+
out_ell = np.array([2.0, 4.0, 6.0, 8.0, 10.0])
432+
out_lower = np.array([1.5, 3.5, 5.5, 7.5, 9.5])
433+
out_upper = np.array([2.5, 4.5, 6.5, 8.5, 10.5])
434+
435+
cls_in = {
436+
key: Result(
437+
np.linspace(1.0, 8.0, in_ell.size),
438+
spin=(0, 0),
439+
axis=(0,),
440+
ell=in_ell,
441+
)
442+
}
443+
444+
mm = {
445+
key: Result(
446+
np.arange(out_ell.size * in_ell.size, dtype=float).reshape(
447+
out_ell.size, in_ell.size
448+
),
449+
spin=(0, 0),
450+
axis=(0,),
451+
ell=out_ell,
452+
lower=out_lower,
453+
upper=out_upper,
454+
)
455+
}
456+
457+
mixed = apply_mixing_matrix(cls_in, mm)
458+
np.testing.assert_array_equal(mixed[key].ell, out_ell)
459+
np.testing.assert_array_equal(mixed[key].lower, out_lower)
460+
np.testing.assert_array_equal(mixed[key].upper, out_upper)
461+
462+
bins = np.array([2.0, 5.0, 11.0])
463+
mixed_binned = heracles.binned(mixed, bins)
464+
assert mixed_binned[key].shape == (2,)
465+
np.testing.assert_array_equal(mixed_binned[key].lower, bins[:-1])
466+
np.testing.assert_array_equal(mixed_binned[key].upper, bins[1:])
467+
468+
mixed_path = tmp_path / "mixed_nonsquare.fits"
469+
heracles.write(mixed_path, mixed_binned)
470+
mixed_read = heracles.read(mixed_path)
471+
np.testing.assert_array_equal(mixed_read[key], mixed_binned[key])
472+
np.testing.assert_array_equal(mixed_read[key].ell, mixed_binned[key].ell)
473+
474+
inv_mm = invert_mixing_matrix(mm, rcond=1e-12)
475+
assert inv_mm[key].shape == (in_ell.size, out_ell.size)
476+
np.testing.assert_array_equal(inv_mm[key].ell, np.arange(in_ell.size))
477+
np.testing.assert_array_equal(inv_mm[key].lower, np.arange(in_ell.size))
478+
np.testing.assert_array_equal(inv_mm[key].upper, np.arange(1, in_ell.size + 1))
479+
480+
cls_out = {
481+
key: Result(
482+
np.linspace(1.0, out_ell.size, out_ell.size),
483+
spin=(0, 0),
484+
axis=(0,),
485+
ell=out_ell,
486+
)
487+
}
488+
489+
unmixed = apply_mixing_matrix(cls_out, inv_mm)
490+
np.testing.assert_array_equal(unmixed[key].ell, np.arange(in_ell.size))
491+
np.testing.assert_array_equal(unmixed[key].lower, np.arange(in_ell.size))
492+
np.testing.assert_array_equal(unmixed[key].upper, np.arange(1, in_ell.size + 1))
493+
494+
inv_bins = np.array([0.0, 4.0, 8.0])
495+
unmixed_binned = heracles.binned(unmixed, inv_bins)
496+
assert unmixed_binned[key].shape == (2,)
497+
498+
unmixed_path = tmp_path / "unmixed_nonsquare.fits"
499+
heracles.write(unmixed_path, unmixed_binned)
500+
unmixed_read = heracles.read(unmixed_path)
501+
np.testing.assert_array_equal(unmixed_read[key], unmixed_binned[key])
502+
np.testing.assert_array_equal(unmixed_read[key].ell, unmixed_binned[key].ell)

0 commit comments

Comments
 (0)