diff --git a/pymaster/covariance.py b/pymaster/covariance.py index 91195b5..49e9f9c 100644 --- a/pymaster/covariance.py +++ b/pymaster/covariance.py @@ -207,6 +207,11 @@ def compute_coupling_coefficients(self, fla1, fla2, if flb2 is None: flb2 = fla2 + if np.any([fla1.anisotropic_mask, fla2.anisotropic_mask, + flb1.anisotropic_mask, flb2.anisotropic_mask]): + raise NotImplementedError("Covariance matrix estimation not " + "implemented for anisotropic weights.") + if (not (fla1.is_compatible(fla2) and fla1.is_compatible(flb1) and fla1.is_compatible(flb2))): diff --git a/pymaster/field.py b/pymaster/field.py index c65e16e..9bc6398 100644 --- a/pymaster/field.py +++ b/pymaster/field.py @@ -98,6 +98,15 @@ class NmtField(object): deprojection and purification, but you don't care about deprojection bias. This will significantly reduce the memory taken up by the resulting object. + mask_22 (`array`): Array containing the mask corresponding to the + ``22`` component of an anisotropic weight matrix. If not ``None`` + the ``mask`` argument will be interpreted as the ``11`` component + of the same matrix. The off-diagonal component of the weight + matrix must then be passed as ``mask_12`` (below). If ``mask_22`` + and ``mask_12`` are ``None``, isotropic weighting is assumed, + described by ``mask``. + mask_12 (`array`): Array containing the off-diagonal component of the + anisotropic weight matrix. See ``mask_22`` above. """ def __init__(self, mask, maps, *, spin=None, templates=None, beam=None, purify_e=False, purify_b=False, n_iter=None, n_iter_mask=None, @@ -233,11 +242,11 @@ def __init__(self, mask, maps, *, spin=None, templates=None, beam=None, raise ValueError("Anisotropic masks can't be used with " "scalar fields.") if pure_any: - raise ValueError("Purification not implemented for " - "anisotropic masks") + raise NotImplementedError("Purification not implemented for " + "anisotropic masks") if templates is not None: - raise ValueError("Contaminant deprojection not supported " - "for anisotropic masks.") + raise NotImplementedError("Contaminant deprojection not " + "supported for anisotropic masks.") # 3. Check templates if isinstance(templates, (list, tuple, np.ndarray)): diff --git a/pymaster/tests/test_master_anisotropic.py b/pymaster/tests/test_master_anisotropic.py index c23abd9..09acaf4 100644 --- a/pymaster/tests/test_master_anisotropic.py +++ b/pymaster/tests/test_master_anisotropic.py @@ -1,6 +1,66 @@ import numpy as np import healpy as hp import pymaster as nmt +import pytest + + +def test_anisotropic_weighting_smoke(): + nside = 64 + npix = hp.nside2npix(nside) + m = np.ones(npix) + + f = nmt.NmtField(m, [m, m], + mask_12=0.5*m, + mask_22=2.0*m) + msk_a = f.get_anisotropic_mask() + + assert np.allclose(msk_a[1], 0.5*m) + assert np.allclose(msk_a[0], -0.5*m) + + +def test_anisotropic_weighting_errors(): + nside = 64 + npix = hp.nside2npix(nside) + m = np.ones(npix) + + # Field-level errors + # Must pass full weight matrix + with pytest.raises(ValueError): + nmt.NmtField(m, [m, m], mask_12=m) + + # Non-positive-definite weight matrix + with pytest.raises(ValueError): + nmt.NmtField(m, [m, m], mask_22=0*m, mask_12=m) + + # No anisotropic matrix for scalar fields + with pytest.raises(ValueError): + nmt.NmtField(m, None, spin=0, mask_22=m, mask_12=m*0) + + # No anisotropic matrix for scalar fields (second check) + with pytest.raises(ValueError): + nmt.NmtField(m, [m], mask_22=m, mask_12=m*0) + + # No purification with anisotropic weights + with pytest.raises(NotImplementedError): + nmt.NmtField(m, [m, m], mask_12=0*m, mask_22=m, + purify_b=True) + + # No contaminant deprojection with anisotropic weights + with pytest.raises(NotImplementedError): + nmt.NmtField(m, [m, m], mask_12=0*m, mask_22=m, + templates=[[m, m]]) + + # Workspace-level errors + f = nmt.NmtField(m, [m, m], + mask_12=0.5*m, + mask_22=2.0*m) + b = nmt.NmtBin.from_nside_linear(nside, nlb=4) + with pytest.raises(NotImplementedError): + nmt.NmtWorkspace.from_fields(f, f, b, l_toeplitz=3) + + # Covariance-level errors + with pytest.raises(NotImplementedError): + nmt.NmtCovarianceWorkspace.from_fields(f, f, f, f) def test_anisotropic_weighting(): diff --git a/pymaster/tests/test_utils.py b/pymaster/tests/test_utils.py index f1fc2df..45009ef 100644 --- a/pymaster/tests/test_utils.py +++ b/pymaster/tests/test_utils.py @@ -62,12 +62,9 @@ def test_moore_penrose_pinv(): # Pick up largest eigval e = e[:, w > 0.1].squeeze() # Should only have two non-zero eigvals - print(w) assert np.sum(np.fabs(w) < 1E-15) == 2 # Check e is parallel to v - print(np.dot(e, v)) - print(np.dot(e, e)) - assert np.isclose(np.dot(e, v), + assert np.isclose(np.fabs(np.dot(e, v)), np.sqrt(np.dot(e, e))) # For invertible matrix, we just get @@ -76,8 +73,6 @@ def test_moore_penrose_pinv(): m = np.diag(w) im = nmt.utils.moore_penrose_pinvh(m, None) imb = np.diag(1/w) - print(im) - print(imb) assert np.allclose(im, imb) diff --git a/pymaster/workspaces.py b/pymaster/workspaces.py index 4946bae..447feed 100644 --- a/pymaster/workspaces.py +++ b/pymaster/workspaces.py @@ -248,8 +248,8 @@ def compute_coupling_matrix(self, fl1, fl2, bins, is_teb=False, anisotropic_mask_any = fl1.anisotropic_mask or fl2.anisotropic_mask if anisotropic_mask_any and (l_toeplitz >= 0): - raise ValueError("Toeplitz approximation not implemented for " - "anisotropic masks.") + raise NotImplementedError("Toeplitz approximation not " + "implemented for anisotropic masks.") ut._toeplitz_sanity(l_toeplitz, l_exact, dl_band, bins.bin.ell_max, fl1, fl2)