Repository: RadioAstronomySoftwareGroup/pyuvdata

Issue:
Make sure find redundancy methods only put each baseline in one redundant group
Should be asserts to enforce that if it's already the case.

Discussion:
codecov[bot]: # [Codecov](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/732?src=pr&el=h1) Report
> Merging [#732](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/732?src=pr&el=desc) into [master](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/commit/5406e7fd30526b124d9755f0b14e8c9d1af88c01?src=pr&el=desc) will **decrease** coverage by `<.01%`.
> The diff coverage is `100%`.

[![Impacted file tree graph](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/732/graphs/tree.svg?width=650&token=4QykcCeB1H&height=150&src=pr)](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/732?src=pr&el=tree)

```diff
@@            Coverage Diff             @@
##           master     #732      +/-   ##
==========================================
- Coverage   99.03%   99.02%   -0.01%     
==========================================
  Files          21       21              
  Lines        9410     9374      -36     
==========================================
- Hits         9319     9283      -36     
  Misses         91       91
```


| [Impacted Files](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/732?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pyuvdata/utils.py](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/732/diff?src=pr&el=tree#diff-cHl1dmRhdGEvdXRpbHMucHk=) | `100% <100%> (ø)` | :arrow_up: |
| [pyuvdata/uvdata.py](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/732/diff?src=pr&el=tree#diff-cHl1dmRhdGEvdXZkYXRhLnB5) | `100% <0%> (ø)` | :arrow_up: |
| [pyuvdata/uvflag.py](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/732/diff?src=pr&el=tree#diff-cHl1dmRhdGEvdXZmbGFnLnB5) | `100% <0%> (ø)` | :arrow_up: |

------

[Continue to review full report at Codecov](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/732?src=pr&el=continue).
> **Legend** - [Click here to learn more](https://docs.codecov.io/docs/codecov-delta)
> `Δ = absolute <relative> (impact)`, `ø = not affected`, `? = missing data`
> Powered by [Codecov](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/732?src=pr&el=footer). Last update [5406e7f...c606f2c](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/732?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

bhazelton: can you rebase this? The coverage report is crazy and I think it's because it's not based off the current master.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index 342f2bd4..aa6baeda 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -10,6 +10,7 @@ All notable changes to this project will be documented in this file.
 - `utils.apply_uvflag` for applying UVFlag objects to UVData objects
 
 ### Fixed
+- Redundancy finder will now error if any baselines appear in multiple groups.
 - A bug in `UVCal` objects that prevented them from properly getting data with `ee`/`nn`-style polarizations.
 - a bug in `UVFlag` where `x_orientation` was not set during initialization.
 - A bug in `UVCal.read_fhd_cal` that caused calibration solutions to be approximately doubled.
diff --git a/pyuvdata/utils.py b/pyuvdata/utils.py
index ef9e2795..1cebc572 100644
--- a/pyuvdata/utils.py
+++ b/pyuvdata/utils.py
@@ -1389,6 +1389,9 @@ def get_baseline_redundancies(baselines, baseline_vecs, tol=1.0, with_conjugates
         vec_bin_centers[gi] = np.mean(baseline_vecs[inds, :], axis=0)
 
     lens = np.sqrt(np.sum(vec_bin_centers**2, axis=1))
+    if np.sum([len(bg) for bg in bl_gps]) > Nbls:
+        raise ValueError("Some baselines are falling into multiple"
+                         " redundant groups. Lower the tolerance to resolve ambiguity.")
 
     return bl_gps, vec_bin_centers, lens
 


Test patch:
diff --git a/pyuvdata/tests/test_utils.py b/pyuvdata/tests/test_utils.py
index 337bfa8a..eae93e5f 100644
--- a/pyuvdata/tests/test_utils.py
+++ b/pyuvdata/tests/test_utils.py
@@ -570,6 +570,27 @@ def test_redundancy_finder():
                               lens[gi], atol=tol)
 
 
+def test_high_tolerance_redundancy_error():
+    """
+    Confirm that an error is raised if the redundancy tolerance is set too high,
+    such that baselines end up in multiple
+    """
+    uvd = pyuvdata.UVData()
+    uvd.read_uvfits(os.path.join(DATA_PATH, 'fewant_randsrc_airybeam_Nsrc100_10MHz.uvfits'))
+
+    uvd.select(times=uvd.time_array[0])
+    uvd.unphase_to_drift(use_ant_pos=True)   # uvw_array is now equivalent to baseline positions
+    uvd.conjugate_bls(convention='ant1<ant2', use_enu=True)
+    bl_positions = uvd.uvw_array
+
+    tol = 20.05  # meters
+
+    with pytest.raises(ValueError) as cm:
+        baseline_groups, vec_bin_centers, lens, conjugates = uvutils.get_baseline_redundancies(
+            uvd.baseline_array, bl_positions, tol=tol, with_conjugates=True)
+    assert "Some baselines are falling into" in str(cm.value)
+
+
 def test_redundancy_conjugates():
     # Check that the correct baselines are flipped when returning redundancies with conjugates.
 
diff --git a/pyuvdata/tests/test_uvdata.py b/pyuvdata/tests/test_uvdata.py
index 67e686db..ae710852 100644
--- a/pyuvdata/tests/test_uvdata.py
+++ b/pyuvdata/tests/test_uvdata.py
@@ -3858,7 +3858,7 @@ def test_redundancy_contract_expand_nblts_not_nbls_times_ntimes():
 def test_compress_redundancy_metadata_only():
     uv0 = UVData()
     uv0.read_uvfits(os.path.join(DATA_PATH, 'fewant_randsrc_airybeam_Nsrc100_10MHz.uvfits'))
-    tol = 0.01
+    tol = 0.05
 
     # Assign identical data to each redundant group:
     red_gps, centers, lengths = uv0.get_redundancies(tol=tol, use_antpos=True, conjugate_bls=True)