Repository: RadioAstronomySoftwareGroup/pyuvdata
Pull request #679 (2019-08-31 19:48:08)

Add LatLonAlt_from_XYZ check_acceptability
<!--- Provide a general summary of your changes in the Title above -->
Makes `utils.LatLonAlt_from_XYZ` hard-coded acceptability check optional.
## Description
<!--- Describe your changes in detail -->
The hard-coded acceptability check in `utils.LatLonAlt_from_XYZ` means files with non-pyuvdata compliant telescope XYZ coordinates __cannot__ be read-in, even with the `run_check_acceptability=False` kwarg in the read statements. This can be remedied by making the check optional in the `utils` module, and then feeding the `run_acceptability_check` kwarg to it in the higher level class method calls.

## Motivation and Context
<!--- Why is this change required? What problem does it solve? -->
feature addition, or bug fix depending on how you look at it
<!--- If it fixes an open issue, please link to the issue here. If this PR closes an issue, put the word 'closes' before the issue link to auto-close the issue when the PR is merged. -->

## Types of changes
<!--- What types of changes does your code introduce? Put an `x` in all the boxes that apply: -->
- [x] Bug fix (non-breaking change which fixes an issue)
- [x] New feature (non-breaking change which adds functionality)
- [ ] Breaking change (fix or feature that would cause existing functionality to change)
- [ ] Documentation change (documentation changes only)
- [ ] Version change
- [ ] Build or continuous integration change


## Checklist:
<!--- You may remove the checklists that don't apply to your change type(s) or just leave them empty -->
<!--- Go over all the following points, and replace the space with an `x` in all the boxes that apply. -->
<!--- If you're unsure about any of these, don't hesitate to ask. We're here to help! -->
- [ ] I have read the [contribution guide](https://github.com/RadioAstronomySoftwareGroup/pyuvdata/blob/master/.github/CONTRIBUTING.md).
- [x] My code follows the code style of this project.

Bug fix checklist:
- [x] My fix includes a new test that breaks as a result of the bug (if possible).
- [x] All new and existing tests pass in both python 2 and python 3.
- [x] I have updated the [CHANGELOG](https://github.com/RadioAstronomySoftwareGroup/pyuvdata/blob/master/CHANGELOG.md).

New feature checklist:
- [ ] I have added or updated the docstrings associated with my feature using the [numpy docstring format](https://numpydoc.readthedocs.io/en/latest/format.html).
- [ ] I have updated the tutorial to highlight my new feature (if appropriate).
- [ ] I have added tests to cover my new feature.
- [ ] All new and existing tests pass in both python 2 and python 3.
- [ ] I have updated the [CHANGELOG](https://github.com/RadioAstronomySoftwareGroup/pyuvdata/blob/master/CHANGELOG.md).

Breaking change checklist:  
- [ ] I have updated the docstrings associated with my change using the [numpy docstring format](https://numpydoc.readthedocs.io/en/latest/format.html).
- [ ] I have updated the tutorial to reflect my changes (if appropriate).
- [ ] My change includes backwards compatibility and deprecation warnings (if possible).
- [ ] I have added tests to cover my changes.
- [ ] All new and existing tests pass in both python 2 and python 3.
- [ ] I have updated the [CHANGELOG](https://github.com/RadioAstronomySoftwareGroup/pyuvdata/blob/master/CHANGELOG.md).

Documentation change checklist:
- [ ] Any updated docstrings use the [numpy docstring format](https://numpydoc.readthedocs.io/en/latest/format.html).
- [ ] If this is a significant change to the readme or other docs, I have checked that they are rendered properly on ReadTheDocs. (you may need help to get this branch to build on RTD, just ask!)

Version change checklist:
- [ ] I have updated the [CHANGELOG](https://github.com/RadioAstronomySoftwareGroup/pyuvdata/blob/master/CHANGELOG.md) to put all the unreleased changes under the new version (leaving the unreleased section empty).
- [ ] I have noted any dependency changes since the last version and will update the conda package build accordingly.

Build or continuous integration change checklist:
- [ ] If required or optional dependencies have changed (including version numbers), I have updated the readme to reflect this.
- [ ] If this is a new CI setup, I have added the associated badge to the readme and to references/make_index.py (if appropriate).


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

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

```diff
@@             Coverage Diff             @@
##           master     #679       +/-   ##
===========================================
- Coverage   98.96%   83.64%   -15.33%     
===========================================
  Files          20       20               
  Lines        8777     8778        +1     
===========================================
- Hits         8686     7342     -1344     
- Misses         91     1436     +1345
```


| [Impacted Files](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/679?src=pr&el=tree) | Coverage Δ | |
|---|---|---|
| [pyuvdata/uvfits.py](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/679/diff?src=pr&el=tree#diff-cHl1dmRhdGEvdXZmaXRzLnB5) | `100% <ø> (ø)` | :arrow_up: |
| [pyuvdata/fhd.py](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/679/diff?src=pr&el=tree#diff-cHl1dmRhdGEvZmhkLnB5) | `100% <100%> (ø)` | :arrow_up: |
| [pyuvdata/utils.py](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/679/diff?src=pr&el=tree#diff-cHl1dmRhdGEvdXRpbHMucHk=) | `99.03% <100%> (-0.97%)` | :arrow_down: |
| [pyuvdata/parameter.py](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/679/diff?src=pr&el=tree#diff-cHl1dmRhdGEvcGFyYW1ldGVyLnB5) | `100% <100%> (ø)` | :arrow_up: |
| [pyuvdata/uvh5.py](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/679/diff?src=pr&el=tree#diff-cHl1dmRhdGEvdXZoNS5weQ==) | `0% <0%> (-100%)` | :arrow_down: |
| [pyuvdata/ms.py](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/679/diff?src=pr&el=tree#diff-cHl1dmRhdGEvbXMucHk=) | `0% <0%> (-89.68%)` | :arrow_down: |
| [pyuvdata/uvbeam.py](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/679/diff?src=pr&el=tree#diff-cHl1dmRhdGEvdXZiZWFtLnB5) | `71.36% <0%> (-27.96%)` | :arrow_down: |
| [pyuvdata/uvflag.py](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/679/diff?src=pr&el=tree#diff-cHl1dmRhdGEvdXZmbGFnLnB5) | `76.09% <0%> (-23.91%)` | :arrow_down: |
| [pyuvdata/beamfits.py](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/679/diff?src=pr&el=tree#diff-cHl1dmRhdGEvYmVhbWZpdHMucHk=) | `91.53% <0%> (-8.47%)` | :arrow_down: |
| [pyuvdata/uvdata.py](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/679/diff?src=pr&el=tree#diff-cHl1dmRhdGEvdXZkYXRhLnB5) | `96.01% <0%> (-3.99%)` | :arrow_down: |
| ... and [5 more](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/679/diff?src=pr&el=tree-more) | |

------

[Continue to review full report at Codecov](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/679?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/679?src=pr&el=footer). Last update [b297ab0...e73646a](https://codecov.io/gh/RadioAstronomySoftwareGroup/pyuvdata/pull/679?src=pr&el=lastupdated). Read the [comment docs](https://docs.codecov.io/docs/pull-request-comments).

bhazelton: @nkern ping on this, I reviewed it last week.
nkern: @bhazelton thanks for the update: i'll get to it this week
bhazelton: I think this change may merit a line in the changelog. Can you add a test that breaks before this change?
bhazelton: @nkern I think this PR is ready as soon as you add a test that errors before this fix.

Patch:
diff --git a/CHANGELOG.md b/CHANGELOG.md
index f6678978..e73e68c8 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -14,6 +14,7 @@ All notable changes to this project will be documented in this file.
 - `UVFlag` information on Read The Docs
 
 ### Changed
+- Added optional acceptability check for `utils.LatLonAlt_from_XYZ`
 - Use `astropy_healpix` rather than `healpy` for HEALPix functionality because `healpy` has a GPL license which is incompatible with ours.
 - `h5py` is now a required package instead of an optional one.
 - Phasing now supports metadata only `UVData` objects
@@ -21,6 +22,8 @@ All notable changes to this project will be documented in this file.
 - UVData.get_antenna_redundancies will no longer automatically conjugate baselines.
 - UVData.get_baseline_redundancies and UVData.get_antenna_redundancies have been combined.
 - `UVFlag` inherits from `UVBase` object.
+- `UVFlag` objects can now convert from antenna type to baseline type
+- `UVFlag` objects can now be initialized without inputs
 
 ### Fixed
 - A bug in get_antenna_redundancies for nearly N-S baselines.
diff --git a/README.md b/README.md
index 8fa22802..5d611ed7 100644
--- a/README.md
+++ b/README.md
@@ -75,8 +75,7 @@ see the [phasing memo](docs/references/phasing.pdf) for more details).
 * UVCal/UVData: method to apply calibration to data.
 * package version detection can cause issues with installation directly from the
 repo for some users (see [issue #590](https://github.com/RadioAstronomySoftwareGroup/pyuvdata/issues/590))
-* UVFlag: cannot convert between "antenna" and "baseline" types. (see [issue #565](https://github.com/RadioAstronomySoftwareGroup/pyuvdata/issues/565))
-* UVFlag: cannot initialize a blank object. (see [issue #652](https://github.com/RadioAstronomySoftwareGroup/pyuvdata/issues/652))
+* UVFlag: Adding requires a high level knowledge of individual objects. (see [issue #653](https://github.com/RadioAstronomySoftwareGroup/pyuvdata/issues/653))
 
 For details see the [issue log](https://github.com/RadioAstronomySoftwareGroup/pyuvdata/issues).
 
diff --git a/pyuvdata/fhd.py b/pyuvdata/fhd.py
index 3e3cc245..d06da853 100644
--- a/pyuvdata/fhd.py
+++ b/pyuvdata/fhd.py
@@ -352,7 +352,8 @@ class FHD(UVData):
             if xyz_telescope_frame == 'itrf':
                 # compare to lat/lon/alt
                 location_latlonalt = uvutils.XYZ_from_LatLonAlt(latitude, longitude, altitude)
-                latlonalt_arr_center = uvutils.LatLonAlt_from_XYZ(arr_center)
+                latlonalt_arr_center = uvutils.LatLonAlt_from_XYZ(arr_center,
+                                                                  check_acceptability=run_check_acceptability)
 
                 # check both lat/lon/alt and xyz because of subtle differences in tolerances
                 if (self._xyz_close(location_latlonalt, arr_center)
diff --git a/pyuvdata/parameter.py b/pyuvdata/parameter.py
index 61cfb008..db247d41 100644
--- a/pyuvdata/parameter.py
+++ b/pyuvdata/parameter.py
@@ -323,7 +323,8 @@ class LocationParameter(UVParameter):
         if self.value is None:
             return None
         else:
-            return utils.LatLonAlt_from_XYZ(self.value)
+            # check defaults to False b/c exposed check kwarg exists in UVData
+            return utils.LatLonAlt_from_XYZ(self.value, check_acceptability=False)
 
     def set_lat_lon_alt(self, lat_lon_alt):
         """
@@ -344,7 +345,7 @@ class LocationParameter(UVParameter):
         if self.value is None:
             return None
         else:
-            latitude, longitude, altitude = utils.LatLonAlt_from_XYZ(self.value)
+            latitude, longitude, altitude = self.lat_lon_alt()
             return latitude * 180. / np.pi, longitude * 180. / np.pi, altitude
 
     def set_lat_lon_alt_degrees(self, lat_lon_alt_degree):
diff --git a/pyuvdata/utils.py b/pyuvdata/utils.py
index 53a90eb5..e2c2e141 100644
--- a/pyuvdata/utils.py
+++ b/pyuvdata/utils.py
@@ -69,12 +69,13 @@ JONES_NUM2STR_DICT = {-1: 'Jrr', -2: 'Jll', -3: 'Jrl', -4: 'Jlr',
                       -5: 'Jxx', -6: 'Jyy', -7: 'Jxy', -8: 'Jyx'}
 
 
-def LatLonAlt_from_XYZ(xyz):
+def LatLonAlt_from_XYZ(xyz, check_acceptability=True):
     """
     Calculate lat/lon/alt from ECEF x,y,z.
 
     Args:
         xyz: numpy array, shape (Npts, 3), with ECEF x,y,z coordinates
+        check_acceptability: bool, check XYZ coordinates are reasonable.
 
     Returns:
         tuple of latitude, longitude, altitude numpy arrays (if Npts > 1) or
@@ -105,10 +106,11 @@ def LatLonAlt_from_XYZ(xyz):
         xyz_use = xyz_use[np.newaxis, :]
 
     # checking for acceptable values
-    if (np.any(np.linalg.norm(xyz_use, axis=1) < 6.35e6)
-            or np.any(np.linalg.norm(xyz_use, axis=1) > 6.39e6)):
-        raise ValueError(
-            'xyz values should be ECEF x, y, z coordinates in meters')
+    if check_acceptability:
+        if (np.any(np.linalg.norm(xyz_use, axis=1) < 6.35e6)
+                or np.any(np.linalg.norm(xyz_use, axis=1) > 6.39e6)):
+            raise ValueError(
+                'xyz values should be ECEF x, y, z coordinates in meters')
 
     # see wikipedia geodetic_datum and Datum transformations of
     # GPS positions PDF in docs/references folder
diff --git a/pyuvdata/uvfits.py b/pyuvdata/uvfits.py
index 3963b3cb..3e6230fd 100644
--- a/pyuvdata/uvfits.py
+++ b/pyuvdata/uvfits.py
@@ -433,7 +433,8 @@ class UVFITS(UVData):
                 # goes through the local meridian.
                 rot_ecef_positions = ant_hdu.data.field('STABXYZ')
                 latitude, longitude, altitude = \
-                    uvutils.LatLonAlt_from_XYZ(np.array([x_telescope, y_telescope, z_telescope]))
+                    uvutils.LatLonAlt_from_XYZ(np.array([x_telescope, y_telescope, z_telescope]),
+                                               check_acceptability=run_check_acceptability)
                 self.antenna_positions = uvutils.ECEF_from_rotECEF(rot_ecef_positions,
                                                                    longitude)
 
diff --git a/pyuvdata/uvflag.py b/pyuvdata/uvflag.py
index 343dfa5e..b48d27b8 100644
--- a/pyuvdata/uvflag.py
+++ b/pyuvdata/uvflag.py
@@ -9,7 +9,7 @@ import os
 import warnings
 import copy
 import six
-from six.moves import map
+from six.moves import map, zip
 import h5py
 
 from .uvbase import UVBase
@@ -67,7 +67,7 @@ class UVFlag(UVBase):
 
     """
 
-    def __init__(self, input, mode='metric', copy_flags=False, waterfall=False,
+    def __init__(self, input=None, mode='metric', copy_flags=False, waterfall=False,
                  history='', label='', run_check=True, check_extra=True,
                  run_check_acceptability=True):
         """Initialize the object."""
@@ -231,24 +231,20 @@ class UVFlag(UVBase):
         # initialize the underlying UVBase properties
         super(UVFlag, self).__init__()
 
-        if mode.lower() == "metric":
-            self._set_mode_metric()
-        elif mode.lower() == "flag":
-            self._set_mode_flag()
-        else:
-            raise ValueError("Input mode must be within acceptable values: "
-                             "{}".format((', ').join(self._mode.acceptable_vals)))
-
         self.history = ''  # Added to at the end
 
         self.label = ''  # Added to at the end
         if isinstance(input, (list, tuple)):
             self.__init__(input[0], mode=mode, copy_flags=copy_flags,
-                          waterfall=waterfall, history=history)
+                          waterfall=waterfall, history=history, label=label,
+                          run_check=run_check, check_extra=check_extra,
+                          run_check_acceptability=run_check_acceptability)
             if len(input) > 1:
                 for i in input[1:]:
                     fobj = UVFlag(i, mode=mode, copy_flags=copy_flags,
-                                  waterfall=waterfall, history=history)
+                                  waterfall=waterfall, history=history,
+                                  run_check=run_check, check_extra=check_extra,
+                                  run_check_acceptability=run_check_acceptability)
                     self.__add__(fobj, run_check=run_check,
                                  inplace=True,
                                  check_extra=check_extra,
@@ -260,124 +256,21 @@ class UVFlag(UVBase):
             self.read(input, history, run_check=run_check,
                       check_extra=check_extra,
                       run_check_acceptability=run_check_acceptability)
-        elif waterfall and issubclass(input.__class__, (UVData, UVCal)):
-            self._set_type_waterfall()
-            self.history += ('Flag object with type "waterfall" created. ')
-            if not uvutils._check_history_version(self.history, self.pyuvdata_version_str):
-                self.history += self.pyuvdata_version_str
-
-            self.time_array, ri = np.unique(input.time_array, return_index=True)
-            self.Ntimes = len(self.time_array)
-            self.freq_array = input.freq_array[0, :]
-            self.Nspws = None
-            self.Nfreqs = len(self.freq_array)
-            self.Nblts = len(self.time_array)
-            if issubclass(input.__class__, UVData):
-                self.polarization_array = input.polarization_array
-                self.Npols = len(self.polarization_array)
-                self.lst_array = input.lst_array[ri]
-            else:
-                self.polarization_array = input.jones_array
-                self.Npols = len(self.polarization_array)
-                self.lst_array = lst_from_uv(input)[ri]
-            if copy_flags:
-                raise NotImplementedError('Cannot copy flags when initializing '
-                                          ' waterfall UVFlag from UVData or UVCal.')
-            else:
-                if self.mode == 'flag':
-                    self.flag_array = np.zeros((len(self.time_array),
-                                                len(self.freq_array),
-                                                len(self.polarization_array)), np.bool)
-                elif self.mode == 'metric':
-                    self.metric_array = np.zeros((len(self.time_array),
-                                                  len(self.freq_array),
-                                                  len(self.polarization_array)))
-
         elif issubclass(input.__class__, UVData):
-            self._set_type_baseline()
-            self.history += ('Flag object with type "baseline" created. ')
-            if not uvutils._check_history_version(self.history, self.pyuvdata_version_str):
-                self.history += self.pyuvdata_version_str
-
-            self.baseline_array = input.baseline_array
-            self.Nbls = np.unique(self.baseline_array).size
-            self.Nblts = len(self.baseline_array)
-            self.ant_1_array = input.ant_1_array
-            self.ant_2_array = input.ant_2_array
-            self.Nants_data = input.Nants_data
-
-            self.time_array = input.time_array
-            self.lst_array = input.lst_array
-            self.Ntimes = np.unique(self.time_array).size
-
-            self.freq_array = input.freq_array
-            self.Nfreqs = np.unique(self.freq_array).size
-            self.Nspws = input.Nspws
-
-            self.polarization_array = input.polarization_array
-            self.Npols = len(self.polarization_array)
-            self.Nants_telescope = input.Nants_telescope
-            if copy_flags:
-                self.flag_array = input.flag_array
-                self.history += ' Flags copied from ' + str(input.__class__) + ' object.'
-                if self.mode == 'metric':
-                    warnings.warn('Copying flags to type=="baseline" results in mode=="flag".')
-                    self._set_mode_flag()
-            else:
-                if self.mode == 'flag':
-                    self.flag_array = np.zeros_like(input.flag_array)
-                elif self.mode == 'metric':
-                    self.metric_array = np.zeros_like(input.flag_array).astype(np.float)
+            self.from_uvdata(input, mode=mode, copy_flags=copy_flags,
+                             waterfall=waterfall, history=history, label=label,
+                             run_check=run_check, check_extra=check_extra,
+                             run_check_acceptability=run_check_acceptability)
 
         elif issubclass(input.__class__, UVCal):
-            self._set_type_antenna()
-            self.history += ('Flag object with type "antenna" created. ')
-            if not uvutils._check_history_version(self.history, self.pyuvdata_version_str):
-                self.history += self.pyuvdata_version_str
-            self.ant_array = input.ant_array
-            self.Nants_data = len(self.ant_array)
-
-            self.time_array = input.time_array
-            self.lst_array = lst_from_uv(input)
-            self.Ntimes = np.unique(self.time_array).size
-            self.Nblts = self.Ntimes
-
-            self.freq_array = input.freq_array
-            self.Nspws = input.Nspws
-            self.Nfreqs = np.unique(self.freq_array).size
-
-            self.polarization_array = input.jones_array
-            self.Npols = len(self.polarization_array)
-            if copy_flags:
-                self.flag_array = input.flag_array
-                self.history += ' Flags copied from ' + str(input.__class__) + ' object.'
-                if self.mode == 'metric':
-                    warnings.warn('Copying flags to type=="antenna" results in mode=="flag".')
-                    self._set_mode_flag()
-            else:
-                if self.mode == 'flag':
-                    self.flag_array = np.zeros_like(input.flag_array)
-                elif self.mode == 'metric':
-                    self.metric_array = np.zeros_like(input.flag_array).astype(np.float)
-        else:
-            raise ValueError('input to UVFlag.__init__ must be one of: list, tuple, '
-                             'string, UVData, or UVCal.')
-
-        if issubclass(input.__class__, (UVData, UVCal)):
-            if self.mode == 'flag':
-                self.weights_array = np.ones(self.flag_array.shape)
-            else:
-                self.weights_array = np.ones(self.metric_array.shape)
-
-        if history not in self.history:
-            self.history += history
-        self.label += label
+            self.from_uvcal(input, mode=mode, copy_flags=copy_flags,
+                            waterfall=waterfall, history=history, label=label,
+                            run_check=run_check, check_extra=check_extra,
+                            run_check_acceptability=run_check_acceptability)
 
-        self.clear_unused_attributes()
-
-        if run_check:
-            self.check(check_extra=check_extra,
-                       run_check_acceptability=run_check_acceptability)
+        elif input is not None:
+            raise ValueError('input to UVFlag.__init__ must be one of: '
+                             'list, tuple, string, UVData, or UVCal.')
 
     @property
     def _data_params(self):
@@ -385,7 +278,7 @@ class UVFlag(UVBase):
         if not hasattr(self, "mode") or self.mode is None:
             return None
         elif self.mode == "flag":
-            return ['flag_array', 'weights_array']
+            return ['flag_array']
         elif self.mode == "metric":
             return ['metric_array', 'weights_array']
         else:
@@ -427,6 +320,7 @@ class UVFlag(UVBase):
         self.mode = 'flag'
         self._flag_array.required = True
         self._metric_array.required = False
+        self._weights_array.required = False
         return
 
     def _set_mode_metric(self):
@@ -434,6 +328,10 @@ class UVFlag(UVBase):
         self.mode = 'metric'
         self._flag_array.required = False
         self._metric_array.required = True
+        self._weights_array.required = True
+
+        if self.weights_array is None and self.metric_array is not None:
+            self.weights_array = np.ones_like(self.metric_array, dtype=float)
         return
 
     def _set_type_antenna(self):
@@ -526,7 +424,6 @@ class UVFlag(UVBase):
         self._Nants_data.required = False
         self._Nbls.required = False
         self._Nspws.required = False
-        self._weights_array.required = True
 
         self.Nblts = self.Ntimes
 
@@ -1240,11 +1137,10 @@ class UVFlag(UVBase):
                 dgrp = f['/Data']
                 if self.mode == 'metric':
                     self.metric_array = dgrp['metric_array'][()]
+                    self.weights_array = dgrp['weights_array'][()]
                 elif self.mode == 'flag':
                     self.flag_array = dgrp['flag_array'][()]
 
-                self.weights_array = dgrp['weights_array'][()]
-
             self.clear_unused_attributes()
 
             if run_check:
@@ -1320,13 +1216,13 @@ class UVFlag(UVBase):
                 header['Nspws'] = self.Nspws
 
             dgrp = f.create_group("Data")
-            wtsdata = dgrp.create_dataset('weights_array', chunks=True,
-                                          data=self.weights_array,
-                                          compression=data_compression)
             if self.mode == 'metric':
                 data = dgrp.create_dataset('metric_array', chunks=True,
                                            data=self.metric_array,
                                            compression=data_compression)
+                wtsdata = dgrp.create_dataset('weights_array', chunks=True,
+                                              data=self.weights_array,
+                                              compression=data_compression)
             elif self.mode == 'flag':
                 data = dgrp.create_dataset('flag_array', chunks=True,
                                            data=self.flag_array,
@@ -1439,8 +1335,8 @@ class UVFlag(UVBase):
         elif this.mode == 'metric':
             this.metric_array = np.concatenate([this.metric_array,
                                                 other.metric_array], axis=ax)
-        this.weights_array = np.concatenate([this.weights_array,
-                                             other.weights_array], axis=ax)
+            this.weights_array = np.concatenate([this.weights_array,
+                                                 other.weights_array], axis=ax)
 
         this.history += 'Data combined along ' + axis + ' axis. '
         if not uvutils._check_history_version(this.history, this.pyuvdata_version_str):
@@ -1565,6 +1461,264 @@ class UVFlag(UVBase):
         """Return a copy of this object."""
         return copy.deepcopy(self)
 
+    def from_uvdata(self, input, mode='metric', copy_flags=False,
+                    waterfall=False, history='', label='',
+                    run_check=True, check_extra=True,
+                    run_check_acceptability=True):
+        """Construct a UVFlag object from a UVData object.
+
+        Parameters
+        ----------
+        input : UVData
+            Input to initialize UVFlag object.
+        mode : {"metric", "flag"}, optional
+            The mode determines whether the object has a floating point metric_array
+            or a boolean flag_array.
+        copy_flags : bool, optional
+            Whether to copy flags from input to new UVFlag object
+        waterfall : bool, optional
+            Whether to immediately initialize as a waterfall object, with flag/metric
+            axes: time, frequency, polarization.
+        history : str, optional
+            History string to attach to object.
+        label: str, optional
+            String used for labeling the object (e.g. 'FM').
+        run_check : bool
+            Option to check for the existence and proper shapes of parameters
+            after creating UVFlag object.
+        check_extra : bool
+            Option to check optional parameters as well as required ones (the
+            default is True, meaning the optional parameters will be checked).
+        run_check_acceptability : bool
+            Option to check acceptable range of the values of parameters after
+            creating UVFlag object.
+
+        """
+        if not issubclass(input.__class__, UVData):
+            raise ValueError("from_uvdata can only initialize a UVFlag object "
+                             "from an input UVData object or a subclass "
+                             " of a UVData object.")
+
+        if mode.lower() == "metric":
+            self._set_mode_metric()
+        elif mode.lower() == "flag":
+            self._set_mode_flag()
+        else:
+            raise ValueError("Input mode must be within acceptable values: "
+                             "{}".format((', ').join(self._mode.acceptable_vals)))
+
+        if waterfall:
+            self._set_type_waterfall()
+            self.history += ('Flag object with type "waterfall" created. ')
+            if not uvutils._check_history_version(self.history,
+                                                  self.pyuvdata_version_str):
+                self.history += self.pyuvdata_version_str
+
+            self.time_array, ri = np.unique(input.time_array,
+                                            return_index=True)
+            self.Ntimes = len(self.time_array)
+            self.freq_array = input.freq_array[0, :]
+            self.Nspws = None
+            self.Nfreqs = len(self.freq_array)
+            self.Nblts = len(self.time_array)
+            self.polarization_array = input.polarization_array
+            self.Npols = len(self.polarization_array)
+            self.lst_array = input.lst_array[ri]
+            if copy_flags:
+                raise NotImplementedError('Cannot copy flags when '
+                                          'initializing waterfall UVFlag '
+                                          'from UVData or UVCal.')
+            else:
+                if self.mode == 'flag':
+                    self.flag_array = np.zeros((len(self.time_array),
+                                                len(self.freq_array),
+                                                len(self.polarization_array)),
+                                               np.bool)
+                elif self.mode == 'metric':
+                    self.metric_array = np.zeros((len(self.time_array),
+                                                  len(self.freq_array),
+                                                  len(self.polarization_array)))
+
+        else:
+            self._set_type_baseline()
+            self.history += ('Flag object with type "baseline" created. ')
+            if not uvutils._check_history_version(self.history,
+                                                  self.pyuvdata_version_str):
+                self.history += self.pyuvdata_version_str
+
+            self.baseline_array = input.baseline_array
+            self.Nbls = np.unique(self.baseline_array).size
+            self.Nblts = len(self.baseline_array)
+            self.ant_1_array = input.ant_1_array
+            self.ant_2_array = input.ant_2_array
+            self.Nants_data = input.Nants_data
+
+            self.time_array = input.time_array
+            self.lst_array = input.lst_array
+            self.Ntimes = np.unique(self.time_array).size
+
+            self.freq_array = input.freq_array
+            self.Nfreqs = np.unique(self.freq_array).size
+            self.Nspws = input.Nspws
+
+            self.polarization_array = input.polarization_array
+            self.Npols = len(self.polarization_array)
+            self.Nants_telescope = input.Nants_telescope
+            if copy_flags:
+                self.flag_array = input.flag_array
+                self.history += (' Flags copied from '
+                                 + str(input.__class__) + ' object.')
+                if self.mode == 'metric':
+                    warnings.warn('Copying flags to type=="baseline" '
+                                  'results in mode=="flag".')
+                    self._set_mode_flag()
+            else:
+                if self.mode == 'flag':
+                    self.flag_array = np.zeros_like(input.flag_array)
+                elif self.mode == 'metric':
+                    self.metric_array = (np.zeros_like(input.flag_array)
+                                         .astype(np.float))
+
+        if self.mode == "metric":
+            self.weights_array = np.ones(self.metric_array.shape)
+
+        if history not in self.history:
+            self.history += history
+        self.label += label
+
+        self.clear_unused_attributes()
+
+        if run_check:
+            self.check(check_extra=check_extra,
+                       run_check_acceptability=run_check_acceptability)
+        return
+
+    def from_uvcal(self, input, mode='metric', copy_flags=False,
+                   waterfall=False, history='', label='',
+                   run_check=True, check_extra=True,
+                   run_check_acceptability=True):
+        """Construct a UVFlag object from a UVCal object.
+
+        Parameters
+        ----------
+        input : UVData
+            Input to initialize UVFlag object.
+        mode : {"metric", "flag"}, optional
+            The mode determines whether the object has a floating point metric_array
+            or a boolean flag_array.
+        copy_flags : bool, optional
+            Whether to copy flags from input to new UVFlag object
+        waterfall : bool, optional
+            Whether to immediately initialize as a waterfall object, with flag/metric
+            axes: time, frequency, polarization.
+        history : str, optional
+            History string to attach to object.
+        label: str, optional
+            String used for labeling the object (e.g. 'FM').
+        run_check : bool
+            Option to check for the existence and proper shapes of parameters
+            after creating UVFlag object.
+        check_extra : bool
+            Option to check optional parameters as well as required ones (the
+            default is True, meaning the optional parameters will be checked).
+        run_check_acceptability : bool
+            Option to check acceptable range of the values of parameters after
+            creating UVFlag object.
+
+        """
+        if not issubclass(input.__class__, UVCal):
+            raise ValueError("from_uvcal can only initialize a UVFlag object "
+                             "from an input UVCal object or a subclass "
+                             "of a UVCal object.")
+
+        if mode.lower() == "metric":
+            self._set_mode_metric()
+        elif mode.lower() == "flag":
+            self._set_mode_flag()
+        else:
+            raise ValueError("Input mode must be within acceptable values: "
+                             "{}".format((', ').join(self._mode.acceptable_vals)))
+
+        if waterfall:
+            self._set_type_waterfall()
+            self.history += ('Flag object with type "waterfall" created. ')
+            if not uvutils._check_history_version(self.history,
+                                                  self.pyuvdata_version_str):
+                self.history += self.pyuvdata_version_str
+
+            self.time_array, ri = np.unique(input.time_array,
+                                            return_index=True)
+            self.Ntimes = len(self.time_array)
+            self.freq_array = input.freq_array[0, :]
+            self.Nspws = None
+            self.Nfreqs = len(self.freq_array)
+            self.Nblts = len(self.time_array)
+            self.polarization_array = input.jones_array
+            self.Npols = len(self.polarization_array)
+            self.lst_array = lst_from_uv(input)[ri]
+            if copy_flags:
+                raise NotImplementedError('Cannot copy flags when '
+                                          'initializing waterfall UVFlag '
+                                          'from UVData or UVCal.')
+            else:
+                if self.mode == 'flag':
+                    self.flag_array = np.zeros((len(self.time_array),
+                                                len(self.freq_array),
+                                                len(self.polarization_array)),
+                                               np.bool)
+                elif self.mode == 'metric':
+                    self.metric_array = np.zeros((len(self.time_array),
+                                                  len(self.freq_array),
+                                                  len(self.polarization_array)))
+
+        else:
+            self._set_type_antenna()
+            self.history += ('Flag object with type "antenna" created. ')
+            if not uvutils._check_history_version(self.history,
+                                                  self.pyuvdata_version_str):
+                self.history += self.pyuvdata_version_str
+            self.ant_array = input.ant_array
+            self.Nants_data = len(self.ant_array)
+
+            self.time_array = input.time_array
+            self.lst_array = lst_from_uv(input)
+            self.Ntimes = np.unique(self.time_array).size
+            self.Nblts = self.Ntimes
+
+            self.freq_array = input.freq_array
+            self.Nspws = input.Nspws
+            self.Nfreqs = np.unique(self.freq_array).size
+
+            self.polarization_array = input.jones_array
+            self.Npols = len(self.polarization_array)
+            if copy_flags:
+                self.flag_array = input.flag_array
+                self.history += (' Flags copied from '
+                                 + str(input.__class__) + ' object.')
+                if self.mode == 'metric':
+                    warnings.warn('Copying flags to type=="antenna" '
+                                  'results in mode=="flag".')
+                    self._set_mode_flag()
+            else:
+                if self.mode == 'flag':
+                    self.flag_array = np.zeros_like(input.flag_array)
+                elif self.mode == 'metric':
+                    self.metric_array = (np.zeros_like(input.flag_array)
+                                         .astype(np.float))
+        if self.mode == "metric":
+            self.weights_array = np.ones(self.metric_array.shape)
+
+        if history not in self.history:
+            self.history += history
+        self.label += label
+
+        self.clear_unused_attributes()
+
+        if run_check:
+            self.check(check_extra=check_extra,
+                       run_check_acceptability=run_check_acceptability)
+        return
+
     def combine_metrics(self, others, method='quadmean', inplace=True,
                         run_check=True, check_extra=True,
                         run_check_acceptability=True):
@@ -1649,11 +1803,19 @@ class UVFlag(UVBase):
         else:
             darr = self.metric_array
         if len(self.polarization_array) > 1:
+            if self.mode == "metric":
+                _weights = self.weights_array
+            else:
+                _weights = np.ones_like(darr)
             # Collapse pol dimension. But note we retain a polarization axis.
-            d, w = uvutils.collapse(darr, method, axis=-1, weights=self.weights_array,
+            d, w = uvutils.collapse(darr, method, axis=-1,
+                                    weights=_weights,
                                     return_weights=True)
             darr = np.expand_dims(d, axis=d.ndim)
-            self.weights_array = np.expand_dims(w, axis=w.ndim)
+
+            if self.mode == "metric":
+                self.weights_array = np.expand_dims(w, axis=w.ndim)
+
             self.polarization_array = np.array([','.join(map(str, self.polarization_array))],
                                                dtype=np.str_)
 
@@ -1717,7 +1879,8 @@ class UVFlag(UVBase):
             d, w = uvutils.collapse(darr, method, axis=(0, 1), weights=self.weights_array,
                                     return_weights=True)
             darr = np.swapaxes(d, 0, 1)
-            self.weights_array = np.swapaxes(w, 0, 1)
+            if self.mode == "metric":
+                self.weights_array = np.swapaxes(w, 0, 1)
         elif self.type == 'baseline':
             Nt = len(np.unique(self.time_array))
             Nf = len(self.freq_array[0, :])
@@ -1726,12 +1889,17 @@ class UVFlag(UVBase):
             w = np.zeros((Nt, Nf, Np))
             for i, t in enumerate(np.unique(self.time_array)):
                 ind = self.time_array == t
+                if self.mode == "metric":
+                    _weights = self.weights_array[ind, :, :]
+                else:
+                    _weights = np.ones_like(darr[ind, :, :], dtype=float)
                 d[i, :, :], w[i, :, :] = uvutils.collapse(darr[ind, :, :], method,
                                                           axis=0,
-                                                          weights=self.weights_array[ind, :, :],
+                                                          weights=_weights,
                                                           return_weights=True)
             darr = d
-            self.weights_array = w
+            if self.mode == "metric":
+                self.weights_array = w
             self.time_array, ri = np.unique(self.time_array, return_index=True)
             self.lst_array = self.lst_array[ri]
         if ((method == 'or') or (method == 'and')) and (self.mode == 'flag'):
@@ -1787,8 +1955,7 @@ class UVFlag(UVBase):
         if not (issubclass(uv.__class__, UVData) or (isinstance(uv, UVFlag) and uv.type == 'baseline')):
             raise ValueError('Must pass in UVData object or UVFlag object of type '
                              '"baseline" to match.')
-        if self.type != 'waterfall':
-            raise ValueError('Cannot convert from type "' + self.type + '" to "baseline".')
+
         # Deal with polarization
         if force_pol and self.polarization_array.size == 1:
             # Use single pol for all pols, regardless
@@ -1798,7 +1965,7 @@ class UVFlag(UVBase):
                 self.flag_array = self.flag_array.repeat(self.polarization_array.size, axis=-1)
             else:
                 self.metric_array = self.metric_array.repeat(self.polarization_array.size, axis=-1)
-            self.weights_array = self.weights_array.repeat(self.polarization_array.size, axis=-1)
+                self.weights_array = self.weights_array.repeat(self.polarization_array.size, axis=-1)
         # Now the pol axes should match regardless of force_pol.
         if not np.array_equal(uv.polarization_array, self.polarization_array):
             if self.polarization_array.size == 1:
@@ -1806,31 +1973,74 @@ class UVFlag(UVBase):
                                  + ' if you wish to broadcast to all polarizations.')
             else:
                 raise ValueError('Polarizations could not be made to match.')
-        # Populate arrays
-        warr = np.zeros_like(uv.flag_array, dtype=np.float)
-        if self.mode == 'flag':
-            arr = np.zeros_like(uv.flag_array)
-            sarr = self.flag_array
-        elif self.mode == 'metric':
-            arr = np.zeros_like(uv.flag_array, dtype=float)
-            sarr = self.metric_array
-        for i, t in enumerate(np.unique(uv.time_array)):
-            ti = np.where(uv.time_array == t)
-            arr[ti, :, :, :] = sarr[i, :, :][np.newaxis, np.newaxis, :, :]
-            warr[ti, :, :, :] = self.weights_array[i, :, :][np.newaxis, np.newaxis, :, :]
-        if self.mode == 'flag':
-            self.flag_array = arr
-        elif self.mode == 'metric':
-            self.metric_array = arr
-        self.weights_array = warr
-
-        self.baseline_array = uv.baseline_array
-        self.Nbls = np.unique(self.baseline_array).size
+        if self.type == "waterfall":
+            # Populate arrays
+            if self.mode == 'flag':
+                arr = np.zeros_like(uv.flag_array)
+                sarr = self.flag_array
+            elif self.mode == 'metric':
+                arr = np.zeros_like(uv.flag_array, dtype=float)
+                warr = np.zeros_like(uv.flag_array, dtype=np.float)
+                sarr = self.metric_array
+            for i, t in enumerate(np.unique(self.time_array)):
+                ti = np.where(uv.time_array == t)
+                arr[ti, :, :, :] = sarr[i, :, :][np.newaxis, np.newaxis, :, :]
+                if self.mode == "metric":
+                    warr[ti, :, :, :] = self.weights_array[i, :, :][np.newaxis, np.newaxis, :, :]
+            if self.mode == 'flag':
+                self.flag_array = arr
+            elif self.mode == 'metric':
+                self.metric_array = arr
+                self.weights_array = warr
+
+        elif self.type == "antenna":
+            if self.mode == "metric":
+                raise NotImplementedError("Cannot currently convert from "
+                                          "antenna type, metric mode to "
+                                          "baseline type UVFlag object.")
+            else:
+                ants_data = np.unique(uv.ant_1_array.tolist()
+                                      + uv.ant_2_array.tolist()
+                                      )
+                new_ants = np.setdiff1d(ants_data, self.ant_array)
+                if new_ants.size > 0:
+                    self.ant_array = np.append(self.ant_array, new_ants).tolist()
+                    # make new flags of the same shape but with first axis the
+                    # size of the new ants
+                    flag_shape = list(self.flag_array.shape)
+                    flag_shape[0] = new_ants.size
+                    new_flags = np.full(flag_shape, True, dtype=bool)
+                    self.flag_array = np.append(self.flag_array,
+                                                new_flags,
+                                                axis=0)
+
+                baseline_flags = np.full((uv.Nblts, self.Nspws,
+                                          self.Nfreqs, self.Npols),
+                                         True, dtype=bool)
+
+                for t_index, bl in enumerate(uv.baseline_array):
+                    uvf_t_index = np.nonzero(uv.time_array[t_index]
+                                             == self.time_array)[0]
+                    if uvf_t_index.size > 0:
+                        # if the time is found in the array
+                        # input the or'ed data from each antenna
+                        ant1, ant2 = uv.baseline_to_antnums(bl)
+                        ant1_index = np.nonzero(np.array(self.ant_array) == ant1)
+                        ant2_index = np.nonzero(np.array(self.ant_array) == ant2)
+                        or_flag = np.logical_or(
+                            self.flag_array[ant1_index, :, :, uvf_t_index, :],
+                            self.flag_array[ant2_index, :, :, uvf_t_index, :])
+
+                        baseline_flags[t_index, :, :, :] = or_flag.copy()
+
+                self.flag_array = baseline_flags
 
         # Check the frequency array for Nspws, otherwise broadcast to 1,Nfreqs
         self.freq_array = np.atleast_2d(self.freq_array)
         self.Nspws = self.freq_array.shape[0]
 
+        self.baseline_array = uv.baseline_array
+        self.Nbls = np.unique(self.baseline_array).size
         self.ant_1_array = uv.ant_1_array
         self.ant_2_array = uv.ant_2_array
         self.Nants_data = int(len(set(self.ant_1_array.tolist()
@@ -1838,9 +2048,11 @@ class UVFlag(UVBase):
 
         self.time_array = uv.time_array
         self.lst_array = uv.lst_array
+        self.Nblts = self.time_array.size
 
         self.Nants_telescope = int(uv.Nants_telescope)
         self._set_type_baseline()
+        self.clear_unused_attributes()
         self.history += 'Broadcast to type "baseline". '
 
         if not uvutils._check_history_version(self.history, self.pyuvdata_version_str):
@@ -1896,7 +2108,7 @@ class UVFlag(UVBase):
                 self.flag_array = self.flag_array.repeat(self.polarization_array.size, axis=-1)
             else:
                 self.metric_array = self.metric_array.repeat(self.polarization_array.size, axis=-1)
-            self.weights_array = self.weights_array.repeat(self.polarization_array.size, axis=-1)
+                self.weights_array = self.weights_array.repeat(self.polarization_array.size, axis=-1)
         # Now the pol axes should match regardless of force_pol.
         if not np.array_equal(polarr, self.polarization_array):
             if self.polarization_array.size == 1:
@@ -1913,9 +2125,9 @@ class UVFlag(UVBase):
             self.metric_array = np.swapaxes(self.metric_array, 0, 1)[np.newaxis, np.newaxis,
                                                                      :, :, :]
             self.metric_array = self.metric_array.repeat(len(uv.ant_array), axis=0)
-        self.weights_array = np.swapaxes(self.weights_array, 0, 1)[np.newaxis, np.newaxis,
-                                                                   :, :, :]
-        self.weights_array = self.weights_array.repeat(len(uv.ant_array), axis=0)
+            self.weights_array = np.swapaxes(self.weights_array, 0, 1)[np.newaxis, np.newaxis,
+                                                                       :, :, :]
+            self.weights_array = self.weights_array.repeat(len(uv.ant_array), axis=0)
         self.ant_array = uv.ant_array
         self.Nants_data = len(uv.ant_array)
         # Check the frequency array for Nspws, otherwise broadcast to 1,Nfreqs
@@ -1960,7 +2172,6 @@ class UVFlag(UVBase):
             self.flag_array = np.where(self.metric_array >= threshold,
                                        True, False)
             self._set_mode_flag()
-            self.weights_array = np.ones_like(self.metric_array, dtype=np.float)
         else:
             raise ValueError('Unknown UVFlag mode: ' + self.mode + '. Cannot convert to flag.')
         self.history += 'Converted to mode "flag". '
@@ -2003,6 +2214,7 @@ class UVFlag(UVBase):
         elif self.mode == 'flag':
             self.metric_array = self.flag_array.astype(np.float)
             self._set_mode_metric()
+
             if convert_wgts:
                 self.weights_array = np.ones_like(self.weights_array)
                 if self.type == 'waterfall':


Test patch:
diff --git a/pyuvdata/tests/test_uvdata.py b/pyuvdata/tests/test_uvdata.py
index 5324e460..6b296de9 100644
--- a/pyuvdata/tests/test_uvdata.py
+++ b/pyuvdata/tests/test_uvdata.py
@@ -2942,6 +2942,23 @@ def test_get_ENU_antpos():
     assert np.isclose(antpos[0, 0], -0.0026981323386223721)
 
 
+@pytest.mark.filterwarnings("ignore:Altitude is not present in Miriad file")
+def test_telescope_loc_XYZ_check():
+    # test that improper telescope locations can still be read
+    miriad_file = os.path.join(DATA_PATH, 'zen.2456865.60537.xy.uvcRREAA')
+    uv = UVData()
+    uv.read(miriad_file)
+    uv.telescope_location = uvutils.XYZ_from_LatLonAlt(*uv.telescope_location)
+    fname = DATA_PATH + "/test/test.uv"
+    uv.write_miriad(fname, run_check=False, check_extra=False, clobber=True)
+
+    # try to read file without checks (passing is implicit)
+    uv.read(fname, run_check=False)
+
+    # try to read without checks: assert it fails
+    pytest.raises(ValueError, uv.read, fname)
+
+
 @pytest.mark.filterwarnings("ignore:Telescope EVLA is not")
 def test_get_pols():
     # Test function to get unique polarizations in string format
diff --git a/pyuvdata/tests/test_uvflag.py b/pyuvdata/tests/test_uvflag.py
index 165340f5..b6269e17 100644
--- a/pyuvdata/tests/test_uvflag.py
+++ b/pyuvdata/tests/test_uvflag.py
@@ -32,7 +32,8 @@ import h5py
 def uvf_from_miriad():
     uv = UVData()
     uv.read_miriad(test_d_file)
-    uvf = UVFlag(uv)
+    uvf = UVFlag()
+    uvf.from_uvdata(uv)
 
     # yield the object for the test
     yield uvf
@@ -45,7 +46,8 @@ def uvf_from_miriad():
 def uvf_from_uvcal():
     uvc = UVCal()
     uvc.read_calfits(test_c_file)
-    uvf = UVFlag(uvc)
+    uvf = UVFlag()
+    uvf.from_uvcal(uvc)
 
     # yield the object for the test
     yield uvf
@@ -58,7 +60,8 @@ def uvf_from_uvcal():
 def uvf_from_waterfall():
     uv = UVData()
     uv.read_miriad(test_d_file)
-    uvf = UVFlag(uv, waterfall=True)
+    uvf = UVFlag()
+    uvf.from_uvdata(uv, waterfall=True)
 
     # yield the object for the test
     yield uvf
@@ -115,6 +118,13 @@ def test_init_bad_mode():
                history='I made a UVFlag object', label='test')
     assert str(cm.value).startswith('Input mode must be within acceptable')
 
+    uv = UVCal()
+    uv.read_calfits(test_c_file)
+    with pytest.raises(ValueError) as cm:
+        UVFlag(uv, mode='bad_mode',
+               history='I made a UVFlag object', label='test')
+    assert str(cm.value).startswith('Input mode must be within acceptable')
+
 
 def test_init_UVData():
     uv = UVData()
@@ -148,8 +158,30 @@ def test_init_UVData_copy_flags():
     assert hasattr(uvf, 'metric_array')
     assert uvf.metric_array is None
     assert np.array_equal(uvf.flag_array, uv.flag_array)
-    assert uvf.weights_array.shape == uv.flag_array.shape
-    assert np.all(uvf.weights_array == 1)
+    assert uvf.weights_array is None
+    assert uvf.type == 'baseline'
+    assert uvf.mode == 'flag'
+    assert np.all(uvf.time_array == uv.time_array)
+    assert np.all(uvf.lst_array == uv.lst_array)
+    assert np.all(uvf.freq_array == uv.freq_array[0])
+    assert np.all(uvf.polarization_array == uv.polarization_array)
+    assert np.all(uvf.baseline_array == uv.baseline_array)
+    assert np.all(uvf.ant_1_array == uv.ant_1_array)
+    assert np.all(uvf.ant_2_array == uv.ant_2_array)
+    assert 'Flag object with type "baseline"' in uvf.history
+    assert pyuvdata_version_str in uvf.history
+
+
+def test_init_UVData_mode_flag():
+    uv = UVData()
+    uv.read_miriad(test_d_file)
+    uvf = UVFlag()
+    uvf.from_uvdata(uv, copy_flags=False, mode="flag")
+    #  with copy flags uvf.metric_array should be none
+    assert hasattr(uvf, 'metric_array')
+    assert uvf.metric_array is None
+    assert np.array_equal(uvf.flag_array, uv.flag_array)
+    assert uvf.weights_array is None
     assert uvf.type == 'baseline'
     assert uvf.mode == 'flag'
     assert np.all(uvf.time_array == uv.time_array)
@@ -183,6 +215,26 @@ def test_init_UVCal():
     assert pyuvdata_version_str in uvf.history
 
 
+def test_init_UVCal_mode_flag():
+    uvc = UVCal()
+    uvc.read_calfits(test_c_file)
+    uvf = UVFlag(uvc, copy_flags=False, mode='flag')
+    assert hasattr(uvf, 'metric_array')
+    assert uvf.metric_array is None
+    assert np.array_equal(uvf.flag_array, uvc.flag_array)
+    assert uvf.weights_array is None
+    assert uvf.type == 'antenna'
+    assert uvf.mode == 'flag'
+    assert np.all(uvf.time_array == uvc.time_array)
+    lst = lst_from_uv(uvc)
+    assert np.all(uvf.lst_array == lst)
+    assert np.all(uvf.freq_array == uvc.freq_array[0])
+    assert np.all(uvf.polarization_array == uvc.jones_array)
+    assert np.all(uvf.ant_array == uvc.ant_array)
+    assert 'Flag object with type "antenna"' in uvf.history
+    assert pyuvdata_version_str in uvf.history
+
+
 def test_init_cal_copy_flags():
     uv = UVCal()
     uv.read_calfits(test_c_file)
@@ -192,7 +244,6 @@ def test_init_cal_copy_flags():
     assert hasattr(uvf, 'metric_array')
     assert uvf.metric_array is None
     assert np.array_equal(uvf.flag_array, uv.flag_array)
-    assert uvf.weights_array.shape == uv.flag_array.shape
     assert uvf.type == 'antenna'
     assert uvf.mode == 'flag'
     assert np.all(uvf.time_array == np.unique(uv.time_array))
@@ -222,7 +273,7 @@ def test_init_waterfall_uvd():
 def test_init_waterfall_uvc():
     uv = UVCal()
     uv.read_calfits(test_c_file)
-    uvf = UVFlag(uv, waterfall=True)
+    uvf = UVFlag(uv, waterfall=True, history='input history check')
     assert uvf.metric_array.shape == (uv.Ntimes, uv.Nfreqs, uv.Njones)
     assert np.all(uvf.metric_array == 0)
     assert uvf.weights_array.shape == (uv.Ntimes, uv.Nfreqs, uv.Njones)
@@ -233,17 +284,17 @@ def test_init_waterfall_uvc():
     assert np.all(uvf.freq_array == uv.freq_array[0])
     assert np.all(uvf.polarization_array == uv.jones_array)
     assert 'Flag object with type "waterfall"' in uvf.history
+    assert 'input history check' in uvf.history
     assert pyuvdata_version_str in uvf.history
 
 
-def test_init_waterfall_flag():
+def test_init_waterfall_flag_uvcal():
     uv = UVCal()
     uv.read_calfits(test_c_file)
     uvf = UVFlag(uv, waterfall=True, mode='flag')
     assert uvf.flag_array.shape == (uv.Ntimes, uv.Nfreqs, uv.Njones)
     assert not np.any(uvf.flag_array)
-    assert uvf.weights_array.shape == (uv.Ntimes, uv.Nfreqs, uv.Njones)
-    assert np.all(uvf.weights_array == 1)
+    assert uvf.weights_array is None
     assert uvf.type == 'waterfall'
     assert uvf.mode == 'flag'
     assert np.all(uvf.time_array == np.unique(uv.time_array))
@@ -253,6 +304,22 @@ def test_init_waterfall_flag():
     assert pyuvdata_version_str in uvf.history
 
 
+def test_init_waterfall_flag_uvdata():
+    uv = UVData()
+    uv.read_miriad(test_d_file)
+    uvf = UVFlag(uv, waterfall=True, mode='flag')
+    assert uvf.flag_array.shape == (uv.Ntimes, uv.Nfreqs, uv.Npols)
+    assert not np.any(uvf.flag_array)
+    assert uvf.weights_array is None
+    assert uvf.type == 'waterfall'
+    assert uvf.mode == 'flag'
+    assert np.all(uvf.time_array == np.unique(uv.time_array))
+    assert np.all(uvf.freq_array == uv.freq_array[0])
+    assert np.all(uvf.polarization_array == uv.polarization_array)
+    assert 'Flag object with type "waterfall"' in uvf.history
+    assert pyuvdata_version_str in uvf.history
+
+
 def test_init_waterfall_copy_flags():
     uv = UVCal()
     uv.read_calfits(test_c_file)
@@ -260,6 +327,12 @@ def test_init_waterfall_copy_flags():
         UVFlag(uv, copy_flags=True, mode='flag', waterfall=True)
     assert str(cm.value).startswith('Cannot copy flags when initializing')
 
+    uv = UVData()
+    uv.read_miriad(test_d_file)
+    with pytest.raises(NotImplementedError) as cm:
+        UVFlag(uv, copy_flags=True, mode='flag', waterfall=True)
+    assert str(cm.value).startswith('Cannot copy flags when initializing')
+
 
 def test_init_invalid_input():
     # input is not UVData, UVCal, path, or list/tuple
@@ -268,6 +341,24 @@ def test_init_invalid_input():
     assert str(cm.value).startswith('input to UVFlag.__init__ must be one of:')
 
 
+def test_from_uvcal_error():
+    uv = UVData()
+    uv.read_miriad(test_d_file)
+    uvf = UVFlag()
+    with pytest.raises(ValueError) as cm:
+        uvf.from_uvcal(uv)
+    assert str(cm.value).startswith("from_uvcal can only initialize a UVFlag object")
+
+
+def test_from_udata_error():
+    uv = UVCal()
+    uv.read_calfits(test_c_file)
+    uvf = UVFlag()
+    with pytest.raises(ValueError) as cm:
+        uvf.from_uvdata(uv)
+    assert str(cm.value).startswith("from_uvdata can only initialize a UVFlag object")
+
+
 def test_init_list_files_weights(tmpdir):
     # Test that weights are preserved when reading list of files
     tmp_path = tmpdir.strpath
@@ -733,8 +824,6 @@ def test_add_flag():
                           uv3.lst_array)
     assert np.array_equal(np.concatenate((uv1.flag_array, uv2.flag_array), axis=0),
                           uv3.flag_array)
-    assert np.array_equal(np.concatenate((uv1.weights_array, uv2.weights_array), axis=0),
-                          uv3.weights_array)
     assert np.array_equal(uv1.freq_array, uv3.freq_array)
     assert uv3.type == 'baseline'
     assert uv3.mode == 'flag'
@@ -927,7 +1016,7 @@ def test_collapse_pol_add_pol_axis():
 def test_collapse_pol_or():
     uvf = UVFlag(test_f_file)
     uvf.to_flag()
-    uvf.weights_array = np.ones_like(uvf.weights_array)
+    assert uvf.weights_array is None
     uvf2 = uvf.copy()
     uvf2.polarization_array[0] = -4
     uvf.__add__(uvf2, inplace=True, axis='pol')  # Concatenate to form multi-pol object
@@ -944,7 +1033,6 @@ def test_collapse_pol_or():
 def test_collapse_pol_add_version_str():
     uvf = UVFlag(test_f_file)
     uvf.to_flag()
-    uvf.weights_array = np.ones_like(uvf.weights_array)
 
     uvf2 = uvf.copy()
     uvf2.polarization_array[0] = -4
@@ -971,7 +1059,7 @@ def test_collapse_single_pol():
 def test_collapse_pol_flag():
     uvf = UVFlag(test_f_file)
     uvf.to_flag()
-    uvf.weights_array = np.ones_like(uvf.weights_array)
+    assert uvf.weights_array is None
     uvf2 = uvf.copy()
     uvf2.polarization_array[0] = -4
     uvf.__add__(uvf2, inplace=True, axis='pol')  # Concatenate to form multi-pol object
@@ -988,7 +1076,6 @@ def test_collapse_pol_flag():
 def test_to_waterfall_bl_flags():
     uvf = UVFlag(test_f_file)
     uvf.to_flag()
-    uvf.weights_array = np.ones_like(uvf.weights_array)
     uvf.to_waterfall()
     assert uvf.type == 'waterfall'
     assert uvf.mode == 'metric'
@@ -1001,25 +1088,20 @@ def test_to_waterfall_bl_flags():
 def test_to_waterfall_bl_flags_or():
     uvf = UVFlag(test_f_file)
     uvf.to_flag()
-    uvf.weights_array = np.ones_like(uvf.weights_array)
+    assert uvf.weights_array is None
     uvf.to_waterfall(method='or')
     assert uvf.type == 'waterfall'
     assert uvf.mode == 'flag'
     assert uvf.flag_array.shape == (len(uvf.time_array), len(uvf.freq_array),
                                     len(uvf.polarization_array))
-    assert np.array_equal(uvf.weights_array, np.ones_like(uvf.flag_array, np.float))
     assert len(uvf.lst_array) == len(uvf.time_array)
     uvf = UVFlag(test_f_file)
     uvf.to_flag()
-    uvf.weights_array = np.ones_like(uvf.weights_array)
-    uvf.weights_array[0, 0, 0, 0] = 0.2
-    uvtest.checkWarnings(uvf.to_waterfall, [], {'method': 'or'}, nwarnings=1,
-                         message='Currently weights are')
+    uvf.to_waterfall(method='or')
     assert uvf.type == 'waterfall'
     assert uvf.mode == 'flag'
     assert uvf.flag_array.shape == (len(uvf.time_array), len(uvf.freq_array),
                                     len(uvf.polarization_array))
-    assert np.array_equal(uvf.weights_array, np.ones_like(uvf.flag_array, np.float))
     assert len(uvf.lst_array) == len(uvf.time_array)
 
 
@@ -1112,6 +1194,63 @@ def test_baseline_to_baseline():
     assert uvf == uvf2
 
 
+def test_to_baseline_metric_error(uvf_from_uvcal):
+    uvf = uvf_from_uvcal
+    uvf.select(polarizations=uvf.polarization_array[0])
+    uv = UVData()
+    uv.read_miriad(test_d_file)
+    with pytest.raises(NotImplementedError) as cm:
+        uvf.to_baseline(uv, force_pol=True)
+    assert str(cm.value).startswith("Cannot currently convert from "
+                                    "antenna type, metric mode")
+
+
+def test_to_baseline_from_antenna(uvf_from_uvcal):
+    uvf = uvf_from_uvcal
+    uvf.select(polarizations=uvf.polarization_array[0])
+    uvf.to_flag()
+    uv = UVData()
+    uv.read_miriad(test_d_file)
+
+    ants_data = np.unique(uv.ant_1_array.tolist() + uv.ant_2_array.tolist())
+    new_ants = np.setdiff1d(ants_data, uvf.ant_array)
+
+    old_baseline = (uvf.ant_array[0], uvf.ant_array[1])
+    old_times = np.unique(uvf.time_array)
+    or_flags = np.logical_or(uvf.flag_array[0], uvf.flag_array[1])
+    or_flags = np.transpose(or_flags, [2, 0, 1, 3])
+
+    uv2 = copy.deepcopy(uv)
+    uvf2 = uvf.copy()
+
+    # hack in the exact times so we can compare some values later
+    uv2.select(bls=old_baseline)
+    uv2.time_array[:uvf2.time_array.size] = uvf.time_array
+
+    uvf.to_baseline(uv, force_pol=True)
+    uvf2.to_baseline(uv2, force_pol=True)
+    assert uvf.check()
+
+    uvf2.select(bls=old_baseline, times=old_times)
+    assert np.allclose(or_flags, uvf2.flag_array)
+
+    # all new antenna should be completely flagged
+    # checks auto correlations
+    uvf_new = uvf.select(antenna_nums=new_ants, inplace=False)
+    for bl in np.unique(uvf_new.baseline_array):
+        uvf2 = uvf_new.select(bls=uv.baseline_to_antnums(bl), inplace=False)
+        assert np.all(uvf2.flag_array)
+
+    # check for baselines with one new antenna
+    bls = [uvf.baseline_to_antnums(bl)
+           for bl in uvf.baseline_array
+           if np.intersect1d(new_ants, uvf.baseline_to_antnums(bl)).size > 0]
+    uvf_new = uvf.select(bls=bls, inplace=False)
+    for bl in np.unique(uvf_new.baseline_array):
+        uvf2 = uvf_new.select(bls=uv.baseline_to_antnums(bl), inplace=False)
+        assert np.all(uvf2.flag_array)
+
+
 def test_to_baseline_errors():
     uvc = UVCal()
     uvc.read_calfits(test_c_file)
@@ -1123,11 +1262,6 @@ def test_to_baseline_errors():
         uvf.to_baseline(7.3)  # invalid matching object
     assert str(cm.value).startswith('Must pass in UVData object or UVFlag object')
 
-    uvf = UVFlag(uvc)
-    with pytest.raises(ValueError) as cm:
-        uvf.to_baseline(uv)  # Cannot pass in antenna type
-    assert str(cm.value).startswith('Cannot convert from type "'
-                                    + uvf.type + '" to "baseline"')
     uvf = UVFlag(test_f_file)
     uvf.to_waterfall()
     uvf2 = uvf.copy()