# Buggy code
def mask_source_lonlats(source_def, mask):
    """Mask source longitudes and latitudes to match data mask"""
    source_geo_def = source_def

    # the data may have additional masked pixels
    # let's compare them to see if we can use the same area
    # assume lons and lats mask are the same
    if np.any(mask) and isinstance(source_geo_def, SwathDefinition):
        # copy the source area and use it for the rest of the calculations
        LOG.debug("Copying source area to mask invalid dataset points")
        source_geo_def = deepcopy(source_geo_def)
        lons, lats = source_geo_def.get_lonlats()
        if np.ndim(mask) == 3:
            # FIXME: we should treat 3d arrays (composites) layer by layer!
            mask = np.sum(mask, axis=2)
            # FIXME: pyresample doesn't seem to like this
            # lons = np.tile(lons, (1, 1, mask.shape[2]))
            # lats = np.tile(lats, (1, 1, mask.shape[2]))

        # use the same data, but make a new mask (i.e. don't affect the original masked array)
        # the ma.array function combines the undelying mask with the new
        # one (OR)
        source_geo_def.lons = np.ma.array(lons, mask=mask)
        source_geo_def.lats = np.ma.array(lats, mask=mask)

    return source_geo_def


# Traceback (AttributeError)
[INFO: 2017-12-12 08:14:04 : satpy.writers.cf_writer] Saving datasets to NetCDF4/CF.
[INFO: 2017-12-12 08:14:04 : satpy.writers.cf_writer] No longitude and latitude data to save.
[INFO: 2017-12-12 08:14:04 : satpy.writers.cf_writer] No grid mapping to save.
---------------------------------------------------------------------------
AttributeError                            Traceback (most recent call last)
<ipython-input-24-58ece08c15f3> in <module>()
----> 1 lcl.save_datasets(writer='cf', filename='/tmp/foo.nc')

/home/lahtinep/Software/pytroll/packages/satpy/satpy/scene.pyc in save_datasets(self, writer, datasets, **kwargs)
632             datasets = self.datasets.values()
633         writer = self.get_writer(writer, **kwargs)
--> 634         writer.save_datasets(datasets, **kwargs)
635
636     def get_writer(self, writer="geotiff", **kwargs):

/home/lahtinep/Software/pytroll/packages/satpy/satpy/writers/cf_writer.pyc in save_datasets(self, datasets, filename, **kwargs)
176                     coords = [line_coord, pixel_coord]
177
--> 178                 domain = cf.Domain(dim=coords,
179                                    aux=aux,
180                                    ref=grid_mapping)

AttributeError: 'module' object has no attribute 'Domain'

# Fixed code
def mask_source_lonlats(source_def, mask):
    """Mask source longitudes and latitudes to match data mask"""
    source_geo_def = source_def

    # the data may have additional masked pixels
    # let's compare them to see if we can use the same area
    # assume lons and lats mask are the same
    if isinstance(source_geo_def, SwathDefinition):
        if np.issubsctype(mask.dtype, np.bool):
            # copy the source area and use it for the rest of the calculations
            LOG.debug("Copying source area to mask invalid dataset points")
            # source_geo_def = deepcopy(source_geo_def)
            # lons, lats = source_geo_def.get_lonlats()
            if np.ndim(mask) == 3:
                # FIXME: we should treat 3d arrays (composites) layer by layer!
                mask = np.sum(mask, axis=2)
                # FIXME: pyresample doesn't seem to like this
                # lons = np.tile(lons, (1, 1, mask.shape[2]))
                # lats = np.tile(lats, (1, 1, mask.shape[2]))

            # use the same data, but make a new mask (i.e. don't affect the original masked array)
            # the ma.array function combines the undelying mask with the new
            # one (OR)
            source_geo_def.lons = source_geo_def.lons.where(~mask)
            source_geo_def.lats = source_geo_def.lats.where(~mask)
            # source_geo_def.lons = np.ma.array(lons, mask=mask)
            # source_geo_def.lats = np.ma.array(lats, mask=mask)
        else:
            import xarray.ufuncs as xu

            return SwathDefinition(
                source_geo_def.lons.where(~xu.isnan(mask)),
                source_geo_def.lats.where(~xu.isnan(mask)),
            )
            # This was evil
            # source_geo_def.lons = source_geo_def.lons.where(~xu.isnan(mask))
            # source_geo_def.lats = source_geo_def.lats.where(~xu.isnan(mask))

    return source_geo_def