Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix a SSINS test for future pyuvdata compatibility #125

Merged
merged 4 commits into from
May 14, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
52 changes: 46 additions & 6 deletions .github/workflows/testsuite.yml
Original file line number Diff line number Diff line change
Expand Up @@ -19,15 +19,17 @@ jobs:
os: [ubuntu-latest, macos-latest, windows-latest]
python-version: [3.9, "3.10", "3.11", "3.12"]
steps:
- uses: actions/checkout@master
- uses: actions/checkout@main
with:
fetch-depth: 1

- name: Setup Miniconda
- name: Setup Minimamba
uses: conda-incubator/setup-miniconda@v2
with:
auto-update-conda: true
miniconda-version: "latest"
miniforge-variant: Mambaforge
use-mamba: true
python-version: ${{ env.PYTHON }}
environment-file: ci/${{ env.ENV_NAME }}.yml
activate-environment: ${{ env.ENV_NAME }}
Expand All @@ -42,16 +44,54 @@ jobs:
fi
- name: Install
run: |
pip install .
pip install --no-deps .
- name: Run Tests
run: |
python -m pytest --cov=SSINS --cov-config=.coveragerc --cov-report xml:./coverage.xml --junitxml=test-reports/xunit.xml
- name: Doc Tests
run: |
python -m pytest docs/tutorial.rst
- name: Upload Coverage
uses: codecov/codecov-action@v1
with:
token: ${{ secrets.CODECOV_TOKEN }} # not required for public repos
files: ./coverage.xml
verbose: true

docs_test:
env:
ENV_NAME: SSINS_tests
PYTHON: "3.11"
name: Doc Testing
runs-on: ubuntu-latest
defaults:
run:
# Adding -l {0} helps ensure conda can be found properly.
shell: bash -l {0}
strategy:
fail-fast: false
steps:
- uses: actions/checkout@main
with:
fetch-depth: 1

- name: Setup Minimamba
uses: conda-incubator/setup-miniconda@v2
with:
auto-update-conda: true
miniconda-version: "latest"
miniforge-variant: Mambaforge
use-mamba: true
python-version: ${{ env.PYTHON }}
environment-file: ci/${{ env.ENV_NAME }}.yml
activate-environment: ${{ env.ENV_NAME }}

- name: Conda Info
run: |
conda info -a
conda list
PYVER=`python -c "import sys; print('{:d}.{:d}'.format(sys.version_info.major, sys.version_info.minor))"`
if [[ $PYVER != ${{ env.PYTHON }} ]]; then
exit 1;
fi
- name: Install
run: pip install --no-deps .
- name: Doc Tests
run: python -m pytest docs/tutorial.rst
25 changes: 10 additions & 15 deletions SSINS/incoherent_noise_spectrum.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,7 +19,7 @@ class INS(UVFlag):
the UVFlag class, a member of the pyuvdata software package.
"""

def __init__(self, indata=None, history="", label="", use_future_array_shapes=False, run_check=True,
def __init__(self, indata=None, history="", label="", run_check=True,
check_extra=True, run_check_acceptability=True, order=0, mask_file=None,
match_events_file=None, spectrum_type="cross",
use_integration_weights=False, nsample_default=1, **kwargs):
Expand All @@ -32,8 +32,6 @@ def __init__(self, indata=None, history="", label="", use_future_array_shapes=Fa
saved INS object. If None, initializes an empty object.
history (str): History to append to object's history string.
label (str): String used for labeling the object (e.g. 'MWA Highband').
use_future_array_shapes (bool): Option to convert to the future planned array shapes before the changes go
into effect by removing the spectral window axis (potentially necessary for initializing from SS).
run_check (bool): Whether to check that the object's parameters have the right shape (default True).
check_extra (bool): Whether to also check optional parameters (default True)
run_check_acceptability (bool): Whether to check that the object's parameters take appropriate values
Expand All @@ -58,13 +56,12 @@ def __init__(self, indata=None, history="", label="", use_future_array_shapes=Fa

self.set_extra_params(order=order, spectrum_type=spectrum_type, use_integration_weights=use_integration_weights,
nsample_default=nsample_default, mask_file=mask_file, match_events_file=match_events_file)

super().__init__(indata=indata, mode='metric', copy_flags=False, waterfall=False, history=history, label=label,
use_future_array_shapes=use_future_array_shapes, run_check=run_check, check_extra=check_extra,
use_future_array_shapes=True, run_check=run_check, check_extra=check_extra,
run_check_acceptability=run_check_acceptability, **kwargs)


def read(self, filename, history="", use_future_array_shapes=False, run_check=True, check_extra=True,
def read(self, filename, history="", run_check=True, check_extra=True,
run_check_acceptability=True, **kwargs):
"""
Populate the object by reading a file. This is called during instantiation, but due to inheritance issues, is not
Expand All @@ -74,8 +71,6 @@ def read(self, filename, history="", use_future_array_shapes=False, run_check=Tr
Args:
filename (str): Path to the file to be read.
history (str): History to be appended to the object's history string.
use_future_array_shapes (bool): Whether to assume a spectral index axis -- should do nothing since all INS
objects should be written out in waterfall mode.
run_check (bool): Whether to check that the object's parameters have the right shape (default True).
check_extra (bool): Whether to also check optional parameters (default True)
run_check_acceptability (bool): Whether to check that the object's parameters take appropriate values
Expand All @@ -92,7 +87,8 @@ def read(self, filename, history="", use_future_array_shapes=False, run_check=Tr
attrs = ("order", "use_integration_weights", "nsample_default", "mask_file", "match_events_file", "spectrum_type", "spec_type_str")
attr_dict = {attr: deepcopy(getattr(self, attr)) for attr in attrs}

super().read(filename, history=history, use_future_array_shapes=use_future_array_shapes, run_check=run_check,
kwargs.pop("use_future_array_shapes", None)
super().read(filename, history=history, use_future_array_shapes=True, run_check=run_check,
check_extra=check_extra, run_check_acceptability=run_check_acceptability, **kwargs)

self._pol_check()
Expand All @@ -118,7 +114,7 @@ def read(self, filename, history="", use_future_array_shapes=False, run_check=Tr
self.metric_array.mask = self.weights_array == 0
else:
# Read in the flag array
flag_uvf = UVFlag(self.mask_file)
flag_uvf = UVFlag(self.mask_file, use_future_array_shapes=True)
self.metric_array.mask = np.copy(flag_uvf.flag_array)
del flag_uvf

Expand Down Expand Up @@ -210,7 +206,7 @@ def _pol_check(self):
" currently support pseudo-Stokes spectra.")

def from_uvdata(self, indata, mode="metric", copy_flags=False, waterfall=False, history="",
label="", use_future_array_shapes=False, run_check=True, check_extra=True,
label="", run_check=True, check_extra=True,
run_check_acceptability=True, **kwargs):
"""
Construct an INS object from a UVData (SS) object. This is called during instantiation, but due to inheritance
Expand All @@ -223,8 +219,6 @@ def from_uvdata(self, indata, mode="metric", copy_flags=False, waterfall=False,
copy_flags (bool): Does nothing -- for compatibility with base class.
waterfall (bool): Does nothing -- for compatibility with base class.
history (str): History to be appended to history string of object.
use_future_array_shapes (bool): Option to convert to the future planned array shapes before the changes go
into effect by removing the spectral window axis (potentially necessary for initializing from SS).
run_check (bool): Whether to check that the object's parameters have the right shape (default True).
check_extra (bool): Whether to also check optional parameters (default True)
run_check_acceptability (bool): Whether to check that the object's parameters take appropriate values
Expand All @@ -235,8 +229,9 @@ def from_uvdata(self, indata, mode="metric", copy_flags=False, waterfall=False,
self._has_data_params_check()
# Must be in metric mode, do not copy flags -- have own flag handling
# will turn to waterfall later. These are just here to match signature.
kwargs.pop("use_future_array_shapes", None)
super().from_uvdata(indata, mode="metric", copy_flags=False, waterfall=False,
history=history, label=label, use_future_array_shapes=use_future_array_shapes,
history=history, label=label, use_future_array_shapes=True,
run_check=run_check, check_extra=check_extra, run_check_acceptability=run_check_acceptability,
**kwargs)

Expand All @@ -255,7 +250,7 @@ def from_uvdata(self, indata, mode="metric", copy_flags=False, waterfall=False,
# Set nsample default if some are zero
indata.nsample_array[indata.nsample_array == 0] = self.nsample_default
# broadcast problems with single pol
self.weights_array *= (indata.integration_time[:, np.newaxis, np.newaxis, np.newaxis] * indata.nsample_array)
self.weights_array *= (indata.integration_time[:, np.newaxis, np.newaxis] * indata.nsample_array)

cross_bool = self.ant_1_array != self.ant_2_array
auto_bool = self.ant_1_array == self.ant_2_array
Expand Down
19 changes: 11 additions & 8 deletions SSINS/sky_subtract.py
Original file line number Diff line number Diff line change
Expand Up @@ -45,7 +45,8 @@ def read(self, filename, diff=False, flag_choice=None, INS=None, custom=None,
warnings.warn("SS.read will be renamed to SS.read_data soon to avoid"
" conflicts with UVData.read.", category=PendingDeprecationWarning)

super().read(filename, **kwargs)
kwargs.pop("use_future_array_shapes", None)
super().read(filename, use_future_array_shapes=True, **kwargs)
if self.Nphase > 1:
raise NotImplementedError("SSINS cannot handle files with more than one phase center.")

Expand Down Expand Up @@ -92,7 +93,7 @@ def apply_flags(self, flag_choice=None, INS=None, custom=None):
# Skip if nothing to flag
if len(freq_inds) > 0:
blt_inds = np.where(self.time_array == time)
self.data_array.mask[blt_inds, :, freq_inds, pol_inds] = True
self.data_array.mask[blt_inds, freq_inds, pol_inds] = True
elif flag_choice == 'custom':
self.data_array.mask[:] = False
if custom is not None:
Expand Down Expand Up @@ -181,14 +182,14 @@ def diff(self, flag_choice=None, INS=None, custom=None):
blend = bltaxisboundaries2[bl_num + 1] # index in baseline-time axis to end

blt_slice = slice(blstart, blstart + len_diff)
self.data_array[blt_slice, :, :, :] = diff_dat
self.data_array[blt_slice] = diff_dat
"""The differenced visibilities. Complex array of shape (Nblts, Nspws, Nfreqs, Npols)."""
self.flag_array[blt_slice, :, :, :] = diff_flags
self.flag_array[blt_slice] = diff_flags
"""The flag array, which results from boolean OR of the flags corresponding to visibilities that are differenced from one another."""

self.time_array[blt_slice] = diff_times
"""The center time of the differenced visibilities. Length Nblts."""
self.nsample_array[blt_slice, :, :, :] = diff_nsamples
self.nsample_array[blt_slice] = diff_nsamples
"""See pyuvdata documentation. Here we average the nsample_array of the visibilities that are differenced"""

where_bl = np.where(self.baseline_array == bl)
Expand Down Expand Up @@ -245,7 +246,7 @@ def MLE_calc(self):
frequency. Used for developing a mixture fit.
"""

self.MLE = np.sqrt(0.5 * np.mean(np.absolute(self.data_array)**2, axis=(0, 1, -1)))
self.MLE = np.sqrt(0.5 * np.mean(np.absolute(self.data_array)**2, axis=(0, -1)))

def mixture_prob(self, bins):
"""
Expand All @@ -265,7 +266,7 @@ def mixture_prob(self, bins):
if type(bins) == str:
_, bins = np.histogram(np.abs(self.data_array[np.logical_not(self.data_array.mask)]))

N_spec = np.sum(np.logical_not(self.data_array.mask), axis=(0, 1, -1))
N_spec = np.sum(np.logical_not(self.data_array.mask), axis=(0, -1))
N_total = np.sum(N_spec)

# Calculate the fraction belonging to each frequency
Expand Down Expand Up @@ -345,7 +346,9 @@ def write(self, filename_out, file_type_out, UV=None, filename_in=None,
self.reorder_blts(order='baseline')
if UV is None:
UV = UVData()
UV.read(filename_in, **read_kwargs)
UV.read(filename_in, use_future_array_shapes=True, **read_kwargs)
else:
UV.use_future_array_shapes()

# Option to keep old flags
if not combine:
Expand Down
27 changes: 19 additions & 8 deletions SSINS/tests/test_INS.py
Original file line number Diff line number Diff line change
Expand Up @@ -137,22 +137,22 @@ def test_mask_to_flags(tmp_path, tv_obs, tv_testfile):
ss.read(tv_testfile, diff=True)

uvd = UVData()
uvd.read(tv_testfile)
uvd.read(tv_testfile, use_future_array_shapes=True)

uvf = UVFlag(uvd, mode='flag', waterfall=True)
uvf = UVFlag(uvd, mode='flag', waterfall=True, use_future_array_shapes=True)
# start with some flags so that we can test the intended OR operation
uvf.flag_array[6, :] = True
ins = INS(ss)

# Check error handling
with pytest.raises(ValueError):
bad_uvf = UVFlag(uvd, mode='metric', waterfall=True)
bad_uvf = UVFlag(uvd, mode='metric', waterfall=True, use_future_array_shapes=True)
err_uvf = ins.flag_uvf(uvf=bad_uvf)
with pytest.raises(ValueError):
bad_uvf = UVFlag(uvd, mode='flag', waterfall=False)
bad_uvf = UVFlag(uvd, mode='flag', waterfall=False, use_future_array_shapes=True)
err_uvf = ins.flag_uvf(uvf=bad_uvf)
with pytest.raises(ValueError):
bad_uvf = UVFlag(uvd, mode='flag', waterfall=True)
bad_uvf = UVFlag(uvd, mode='flag', waterfall=True, use_future_array_shapes=True)
# Pretend the data is off by 1 day
bad_uvf.time_array += 1
err_uvf = ins.flag_uvf(uvf=bad_uvf)
Expand Down Expand Up @@ -191,7 +191,7 @@ def test_mask_to_flags(tmp_path, tv_obs, tv_testfile):

# Test write/read
ins.write(prefix, output_type='flags', uvf=uvf)
read_uvf = UVFlag(flags_outfile, mode='flag', waterfall=True)
read_uvf = UVFlag(flags_outfile, mode='flag', waterfall=True, use_future_array_shapes=True)
# Check equality
assert read_uvf == uvf, "UVFlag object differs after read"

Expand Down Expand Up @@ -338,8 +338,19 @@ def test_spectrum_type_file_init(cross_testfile, tv_ins_testfile):

def test_old_file():
old_ins_file = os.path.join(DATA_PATH, "1061313128_99bl_1pol_half_time_old_SSINS.h5")
with pytest.raises(ValueError, match="Required UVParameter _antenna_names has not been set."):
ins = INS(old_ins_file)
try:
# this works with pyuvdata>=3.0
with pytest.raises(
ValueError, match="Required UVParameter _Nants has not been set."
):
ins = INS(old_ins_file)
except AssertionError:
# this works with pyuvdata<3.0
with pytest.raises(
ValueError, match="Required UVParameter _antenna_names has not been set."
):
ins = INS(old_ins_file)


with pytest.raises(ValueError,
match="spectrum_type is set to auto, but file input is a cross spectrum from an old file."):
Expand Down
Loading
Loading