Repository: gammapy/gammapy

Issue:
Error in MapDataset.to_image if no safe_mask is set
**Gammapy version**
v0.15 and dev

**Bug description**
`MapDataset.to_image()` fails if `mask_safe` is not set.
This code cannot work `counts = self.counts * self.mask_safe`

**Expected behavior**
It should yield the image dataset correctly. So either test if `mask_safe` exists or create a property that returns a `mask_safe` with the correct geom.

**To Reproduce**
```
counts = Map.read("$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-counts-cube.fits.gz")
background = Map.read(
    "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-background-cube.fits.gz"
)
background = BackgroundModel(background)

exposure = Map.read(
    "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-exposure-cube.fits.gz"
)
exposure = exposure.sum_over_axes(keepdims=True)
dataset = MapDataset(
    counts=counts,
    background_model=background,
    exposure=exposure
)
dataset.to_image()
```



Discussion:
Thanks @registerrier, this is somehow related to the recent question of how we handle "undefined" maps in the `MapDataset`, either by setting it to `None` or keeping it as empty maps. I'll put the point on the agenda for tomorrow's developer call.

Resolving patch:
diff --git a/gammapy/cube/fit.py b/gammapy/cube/fit.py
--- a/gammapy/cube/fit.py
+++ b/gammapy/cube/fit.py
@@ -902,16 +902,22 @@ def to_image(self, spectrum=None, name=None):
             Map dataset containing images.
         """
         name = make_name(name)
-        counts = self.counts * self.mask_safe
-        background = self.background_model.evaluate() * self.mask_safe
+
+        if self.mask_safe is None:
+            mask_safe = 1
+            mask_image = None
+        else:
+            mask_safe = self.mask_safe
+            mask_image = mask_safe.reduce_over_axes(func=np.logical_or, keepdims=True)
+
+        counts = self.counts * mask_safe
+        background = self.background_model.evaluate() * mask_safe
 
         counts = counts.sum_over_axes(keepdims=True)
         exposure = _map_spectrum_weight(self.exposure, spectrum)
         exposure = exposure.sum_over_axes(keepdims=True)
         background = background.sum_over_axes(keepdims=True)
 
-        mask_image = self.mask_safe.reduce_over_axes(func=np.logical_or, keepdims=True)
-
         # TODO: add edisp and psf
         edisp = None
 


Test patch:
diff --git a/gammapy/cube/tests/test_fit.py b/gammapy/cube/tests/test_fit.py
--- a/gammapy/cube/tests/test_fit.py
+++ b/gammapy/cube/tests/test_fit.py
@@ -207,7 +207,25 @@ def test_to_spectrum_dataset(sky_model, geom, geom_etrue):
     )
 
 
+@requires_data()
 def test_to_image(geom):
+
+    counts = Map.read("$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-counts-cube.fits.gz")
+    background = Map.read(
+        "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-background-cube.fits.gz"
+    )
+    background = BackgroundModel(background)
+
+    exposure = Map.read(
+        "$GAMMAPY_DATA/fermi-3fhl-gc/fermi-3fhl-gc-exposure-cube.fits.gz"
+    )
+    exposure = exposure.sum_over_axes(keepdims=True)
+    dataset = MapDataset(counts=counts, background_model=background, exposure=exposure)
+    dataset_im = dataset.to_image()
+    assert dataset_im.mask_safe is None
+    assert dataset_im.counts.data.sum() == dataset.counts.data.sum()
+    assert_allclose(dataset_im.background_model.map.data.sum(), 28548.625, rtol=1e-5)
+
     ebounds = np.logspace(-1.0, 1.0, 3)
     axis = MapAxis.from_edges(ebounds, name="energy", unit=u.TeV, interp="log")
     geom = WcsGeom.create(
@@ -220,7 +238,6 @@ def test_to_image(geom):
     dataset.mask_safe = WcsNDMap.from_geom(geom=geom, data=data)
 
     dataset_im = dataset.to_image()
-
     assert dataset_im.mask_safe.data.dtype == bool
 
     desired = np.array([[False, True], [True, True]])