nebius/SWE-rebench-V2-PRs huggingface dataset:
Repository: gammapy/gammapy
Pull request #5368 (2024-07-10 20:58:45)

Backport PR #5366 on branch v1.2.x (Remove use of np.rint in pix_tuple_to_idx)
Backport PR #5366: Remove use of np.rint in pix_tuple_to_idx


Patch:
diff --git a/gammapy/maps/geom.py b/gammapy/maps/geom.py
index 5afe26113..8bb9c565b 100644
--- a/gammapy/maps/geom.py
+++ b/gammapy/maps/geom.py
@@ -47,7 +47,7 @@ def pix_tuple_to_idx(pix):
             idx += [p]
         else:
             with np.errstate(invalid="ignore"):
-                p_idx = np.rint(p).astype(int)
+                p_idx = np.floor(p + 0.5).astype(int)
             p_idx[~np.isfinite(p)] = INVALID_INDEX.int
             idx += [p_idx]
 


Test patch:
diff --git a/gammapy/maps/wcs/tests/test_ndmap.py b/gammapy/maps/wcs/tests/test_ndmap.py
index 022ba4a99..9ed7a09b5 100644
--- a/gammapy/maps/wcs/tests/test_ndmap.py
+++ b/gammapy/maps/wcs/tests/test_ndmap.py
@@ -1045,3 +1045,26 @@ def test_plot_mask():
 
     with mpl_plot_check():
         mask.plot_grid()
+
+
+def test_histogram_center_value():
+    evt_energy = np.arange(100.0, 105, 0.5) * u.GeV
+    N_evt = evt_energy.shape[0]
+    center = SkyCoord(0, 0, unit="deg", frame="icrs")
+    radec = SkyCoord(
+        [center.ra] * N_evt, [center.dec] * N_evt, unit="deg"
+    )  # fake position list
+    energy_axis = MapAxis.from_edges(np.arange(100, 106, 1) * u.GeV, name="energy")
+    map1 = WcsNDMap.create(
+        skydir=center, binsz=0.1 * u.deg, width=0.1 * u.deg, axes=[energy_axis]
+    )
+    map1.fill_by_coord({"skycoord": radec, "energy": evt_energy})
+    assert_allclose(map1.data[0:2], [[[2.0]], [[2.0]]])
+
+    map1 = WcsNDMap.create(
+        skydir=center,
+        binsz=1 * u.deg,
+        width=3 * u.deg,
+    )
+    map1.fill_by_pix([[0.0, 0.5, 1.0, 1.5], [0.0, 0.5, 1.0, 1.5]])
+    assert_allclose(map1.data, [[1.0, 0.0, 0.0], [0.0, 2.0, 0.0], [0.0, 0.0, 1.0]])
Repository: gammapy/gammapy
Pull request #5390 (2024-07-24 18:08:14)

Fix region evaluation without psf convolution
See https://github.com/gammapy/gammapy/pull/5386/files#r1689548126


Patch:
diff --git a/gammapy/datasets/evaluator.py b/gammapy/datasets/evaluator.py
index c246517e6..5347d8001 100644
--- a/gammapy/datasets/evaluator.py
+++ b/gammapy/datasets/evaluator.py
@@ -61,7 +61,6 @@ class MapEvaluator:
         evaluation_mode="local",
         use_cache=True,
     ):
-
         self.model = model
         self.exposure = exposure
         self.psf = psf
@@ -323,9 +322,7 @@ class MapEvaluator:
             if self.psf and self.model.apply_irf["psf"]:
                 values = self._compute_flux_spatial_geom(wcs_geom)
             else:
-                values = self.model.spatial_model.integrate_geom(
-                    wcs_geom, oversampling_factor=1
-                )
+                values = self.model.spatial_model.integrate_geom(wcs_geom)
                 axes = [self.geom.axes["energy_true"].squash()]
                 values = values.to_cube(axes=axes)
 


Test patch:
diff --git a/gammapy/datasets/tests/test_evaluator.py b/gammapy/datasets/tests/test_evaluator.py
index fcdcb803a..1d1f3ac11 100644
--- a/gammapy/datasets/tests/test_evaluator.py
+++ b/gammapy/datasets/tests/test_evaluator.py
@@ -1,6 +1,7 @@
 # Licensed under a 3-clause BSD style license - see LICENSE.rst
 import pytest
 import numpy as np
+from copy import deepcopy
 from numpy.testing import assert_allclose
 import astropy.units as u
 from astropy.coordinates import SkyCoord
@@ -58,6 +59,28 @@ def test_compute_flux_spatial(evaluator):
 
 def test_compute_flux_spatial_no_psf(evaluator):
     # check that spatial integration is not performed in the absence of a psf
+
+    evaluator_gaussian = deepcopy(evaluator)
+    model = evaluator.model.copy()
+    model.spatial_model = GaussianSpatialModel(
+        lon_0=0 * u.deg, lat_0=0 * u.deg, sigma=0.001 * u.deg, frame="galactic"
+    )
+    evaluator_gaussian.model = model
+
+    evaluator_gaussian.model.apply_irf["psf"] = False
+    flux = evaluator_gaussian.compute_flux_spatial()
+    evaluator_gaussian.model.apply_irf["psf"] = True
+    assert_allclose(flux, 1.0)
+
+    evaluator_gaussian.psf = None
+    flux = evaluator_gaussian.compute_flux_spatial()
+    assert_allclose(flux, 1.0)
+
+    evaluator.model.apply_irf["psf"] = False
+    flux = evaluator.compute_flux_spatial()
+    evaluator.model.apply_irf["psf"] = True
+    assert_allclose(flux, 1.0)
+
     evaluator.psf = None
     flux = evaluator.compute_flux_spatial()
     assert_allclose(flux, 1.0)
Repository: gammapy/gammapy
Pull request #5394 (2024-07-25 14:27:49)

Backport PR #5366: Remove use of np.rint in pix_tuple_to_idx'
Backport PR #5366: Remove use of np.rint in pix_tuple_to_idx'


Patch:
diff --git a/gammapy/maps/geom.py b/gammapy/maps/geom.py
index 55d86111a..552c87605 100644
--- a/gammapy/maps/geom.py
+++ b/gammapy/maps/geom.py
@@ -46,7 +46,7 @@ def pix_tuple_to_idx(pix):
             idx += [p]
         else:
             with np.errstate(invalid="ignore"):
-                p_idx = np.rint(p).astype(int)
+                p_idx = np.floor(p + 0.5).astype(int)
             p_idx[~np.isfinite(p)] = INVALID_INDEX.int
             idx += [p_idx]
 


Test patch:
diff --git a/gammapy/maps/wcs/tests/test_ndmap.py b/gammapy/maps/wcs/tests/test_ndmap.py
index a8f69d77e..8002a5de1 100644
--- a/gammapy/maps/wcs/tests/test_ndmap.py
+++ b/gammapy/maps/wcs/tests/test_ndmap.py
@@ -963,3 +963,42 @@ def test_double_cutout():
     m_new.stack(m_cc)
     m_c_new = m_new.cutout(position=position, width="2 deg")
     np.testing.assert_allclose(m_c_new.data, m_cc.data)
+
+
+def test_plot_mask():
+    axis = MapAxis.from_energy_bounds("0.1 TeV", "10 TeV", nbin=2)
+    geom = WcsGeom.create(
+        binsz=0.02,
+        width=(2, 2),
+        frame="icrs",
+        axes=[axis],
+    )
+
+    mask = Map.from_geom(geom=geom, dtype=bool)
+    mask.data[1] |= True
+
+    with mpl_plot_check():
+        mask.plot_grid()
+
+
+def test_histogram_center_value():
+    evt_energy = np.arange(100.0, 105, 0.5) * u.GeV
+    N_evt = evt_energy.shape[0]
+    center = SkyCoord(0, 0, unit="deg", frame="icrs")
+    radec = SkyCoord(
+        [center.ra] * N_evt, [center.dec] * N_evt, unit="deg"
+    )  # fake position list
+    energy_axis = MapAxis.from_edges(np.arange(100, 106, 1) * u.GeV, name="energy")
+    map1 = WcsNDMap.create(
+        skydir=center, binsz=0.1 * u.deg, width=0.1 * u.deg, axes=[energy_axis]
+    )
+    map1.fill_by_coord({"skycoord": radec, "energy": evt_energy})
+    assert_allclose(map1.data[0:2], [[[2.0]], [[2.0]]])
+
+    map1 = WcsNDMap.create(
+        skydir=center,
+        binsz=1 * u.deg,
+        width=3 * u.deg,
+    )
+    map1.fill_by_pix([[0.0, 0.5, 1.0, 1.5], [0.0, 0.5, 1.0, 1.5]])
+    assert_allclose(map1.data, [[1.0, 0.0, 0.0], [0.0, 2.0, 0.0], [0.0, 0.0, 1.0]])
Repository: gammapy/gammapy
Pull request #5399 (2024-07-26 00:23:50)

Backport PR #5390 on branch v1.2.x (Fix region evaluation without psf convolution)
Backport PR #5390: Fix region evaluation without psf convolution


Patch:
diff --git a/gammapy/datasets/evaluator.py b/gammapy/datasets/evaluator.py
index f88981ec3..09a531335 100644
--- a/gammapy/datasets/evaluator.py
+++ b/gammapy/datasets/evaluator.py
@@ -61,7 +61,6 @@ class MapEvaluator:
         evaluation_mode="local",
         use_cache=True,
     ):
-
         self.model = model
         self.exposure = exposure
         self.psf = psf
@@ -327,9 +326,7 @@ class MapEvaluator:
             if self.psf and self.model.apply_irf["psf"]:
                 values = self._compute_flux_spatial_geom(wcs_geom)
             else:
-                values = self.model.spatial_model.integrate_geom(
-                    wcs_geom, oversampling_factor=1
-                )
+                values = self.model.spatial_model.integrate_geom(wcs_geom)
                 axes = [self.geom.axes["energy_true"].squash()]
                 values = values.to_cube(axes=axes)
 


Test patch:
diff --git a/gammapy/datasets/tests/test_evaluator.py b/gammapy/datasets/tests/test_evaluator.py
index fcdcb803a..1d1f3ac11 100644
--- a/gammapy/datasets/tests/test_evaluator.py
+++ b/gammapy/datasets/tests/test_evaluator.py
@@ -1,6 +1,7 @@
 # Licensed under a 3-clause BSD style license - see LICENSE.rst
 import pytest
 import numpy as np
+from copy import deepcopy
 from numpy.testing import assert_allclose
 import astropy.units as u
 from astropy.coordinates import SkyCoord
@@ -58,6 +59,28 @@ def test_compute_flux_spatial(evaluator):
 
 def test_compute_flux_spatial_no_psf(evaluator):
     # check that spatial integration is not performed in the absence of a psf
+
+    evaluator_gaussian = deepcopy(evaluator)
+    model = evaluator.model.copy()
+    model.spatial_model = GaussianSpatialModel(
+        lon_0=0 * u.deg, lat_0=0 * u.deg, sigma=0.001 * u.deg, frame="galactic"
+    )
+    evaluator_gaussian.model = model
+
+    evaluator_gaussian.model.apply_irf["psf"] = False
+    flux = evaluator_gaussian.compute_flux_spatial()
+    evaluator_gaussian.model.apply_irf["psf"] = True
+    assert_allclose(flux, 1.0)
+
+    evaluator_gaussian.psf = None
+    flux = evaluator_gaussian.compute_flux_spatial()
+    assert_allclose(flux, 1.0)
+
+    evaluator.model.apply_irf["psf"] = False
+    flux = evaluator.compute_flux_spatial()
+    evaluator.model.apply_irf["psf"] = True
+    assert_allclose(flux, 1.0)
+
     evaluator.psf = None
     flux = evaluator.compute_flux_spatial()
     assert_allclose(flux, 1.0)
Repository: gammapy/gammapy
Pull request #5400 (2024-07-26 07:47:06)

Backport PR #5389 on branch v1.2.x (Fix `LabelMapAxis` so it doesn't reorder the labels)
Backport PR #5389: Fix `LabelMapAxis` so it doesn't reorder the labels


Patch:
diff --git a/gammapy/maps/axes.py b/gammapy/maps/axes.py
index 8056fefa8..e3a227a6a 100644
--- a/gammapy/maps/axes.py
+++ b/gammapy/maps/axes.py
@@ -3048,7 +3048,7 @@ class LabelMapAxis:
         if not len(unique_labels) == len(labels):
             raise ValueError("Node labels must be unique")
 
-        self._labels = unique_labels
+        self._labels = np.array(labels)
         self._name = name
 
     @property


Test patch:
diff --git a/gammapy/maps/tests/test_axes.py b/gammapy/maps/tests/test_axes.py
index ba09e23a7..049ec9176 100644
--- a/gammapy/maps/tests/test_axes.py
+++ b/gammapy/maps/tests/test_axes.py
@@ -773,6 +773,21 @@ def test_label_map_axis_basics():
     axis_copy = axis.copy()
     assert axis_copy.name == "label-axis"
 
+    # Ensure order is correct
+    labels = np.array([1, 4, 5])
+    assert_allclose(labels, [1, 4, 5])
+    assert_allclose(LabelMapAxis(labels).center, labels)
+    assert_allclose(LabelMapAxis(labels)._labels, labels)
+
+    # Test case with non unique labels
+    with pytest.raises(ValueError) as exc_info:
+        LabelMapAxis([1, 1, 1])
+    assert str(exc_info.value) == "Node labels must be unique"
+
+    # Ensure non alphabetical ordering
+    labels = np.array(["b", "a", "d", "c"])
+    assert_equal(LabelMapAxis(labels).center, labels)
+
 
 def test_label_map_axis_coord_to_idx():
     axis = LabelMapAxis(labels=["label-1", "label-2", "label-3"], name="label-axis")
Repository: gammapy/gammapy
Pull request #5403 (2024-07-26 14:01:08)

Backport PR #4978 on branch v1.0.x (Support negative offset for Background2d.to_3d)
Backport PR #4978 on branch v1.0.x (Support negative offset for Background2d.to_3d)


Patch:
diff --git a/gammapy/irf/background.py b/gammapy/irf/background.py
index 770a993ab..46db8a6dd 100644
--- a/gammapy/irf/background.py
+++ b/gammapy/irf/background.py
@@ -133,6 +133,7 @@ class Background3D(BackgroundIRF):
         This takes the values at Y = 0 and X >= 0.
         """
         # TODO: this is incorrect as it misses the Jacobian?
+
         idx_lon = self.axes["fov_lon"].coord_to_idx(0 * u.deg)[0]
         idx_lat = self.axes["fov_lat"].coord_to_idx(0 * u.deg)[0]
         data = self.quantity[:, idx_lon:, idx_lat].copy()
@@ -243,14 +244,11 @@ class Background2D(BackgroundIRF):
     default_unit = u.s**-1 * u.MeV**-1 * u.sr**-1
 
     def to_3d(self):
-        """ "Convert to Background3D"""
-
-        edges = np.concatenate(
-            (
-                np.negative(self.axes["offset"].edges)[::-1][:-1],
-                self.axes["offset"].edges,
-            )
-        )
+        """Convert to Background3D."""
+        offsets = self.axes["offset"].edges
+        edges_neg = np.negative(offsets)[::-1]
+        edges_neg = edges_neg[edges_neg <= 0]
+        edges = np.concatenate((edges_neg, offsets[offsets > 0]))
         fov_lat = MapAxis.from_edges(edges=edges, name="fov_lat")
         fov_lon = MapAxis.from_edges(edges=edges, name="fov_lon")
 


Test patch:
diff --git a/gammapy/irf/tests/test_background.py b/gammapy/irf/tests/test_background.py
index 334a262e5..4b8e7b4e0 100644
--- a/gammapy/irf/tests/test_background.py
+++ b/gammapy/irf/tests/test_background.py
@@ -137,7 +137,6 @@ def test_plot_at_energy(bkg_3d):
 
 
 def test_background_3d_missing_values(bkg_3d_interp):
-
     res = bkg_3d_interp.evaluate(
         fov_lon=0.5 * u.deg,
         fov_lat=0.5 * u.deg,
@@ -423,3 +422,21 @@ def test_write_bkg_3d():
     bg = Background3D.read("background.fits", hdu="BACKGROUND")
 
     assert bg.fov_alignment.value == "ALTAZ"
+
+
+def test_to2d_to3d():
+    # Test for issue 4950
+    energy = [0.1, 10, 1000] * u.TeV
+    energy_axis = MapAxis.from_energy_edges(energy)
+    nbin = 21
+    fov_lon_axis = MapAxis.from_bounds(-2 * u.deg, 2 * u.deg, nbin=nbin, name="fov_lon")
+    fov_lat_axis = MapAxis.from_bounds(-2 * u.deg, 2 * u.deg, nbin=nbin, name="fov_lat")
+    data = np.ones((2, nbin, nbin)) * 1.5
+    bkg = Background3D(
+        axes=[energy_axis, fov_lon_axis, fov_lat_axis], data=data, unit="s-1 GeV-1 sr-1"
+    )
+    bkg2d = bkg.to_2d()
+    assert_allclose(bkg2d.axes["offset"].center[0].value, 0.0, atol=1e-5)
+    bkg3d = bkg2d.to_3d()
+    assert bkg3d.axes["fov_lon"].is_allclose(fov_lon_axis)
+    assert_allclose(bkg3d.data[0][10], bkg.data[0][10], rtol=1e-5)
Repository: gammapy/gammapy
Pull request #5441 (2024-09-18 13:23:58)

Add a warning in TemplateSpatialModel for presence of nan values
Presence of any nan value in a Template map silently creates all nan values in the normalised template as reported in #5379 This becomes very difficult to debug.

This PR adds a warning similar to some other invalid inputs.
It remains the users responsibiltity to understand how to interpret and fix the nans


Patch:
diff --git a/gammapy/modeling/models/spatial.py b/gammapy/modeling/models/spatial.py
index 5a061b503..11cd1fe93 100644
--- a/gammapy/modeling/models/spatial.py
+++ b/gammapy/modeling/models/spatial.py
@@ -1,5 +1,6 @@
 # Licensed under a 3-clause BSD style license - see LICENSE.rst
 """Spatial models."""
+
 import logging
 import os
 import numpy as np
@@ -1305,6 +1306,8 @@ class TemplateSpatialModel(SpatialModel):
             log.warning("Map has negative values. Check and fix this!")
         if (map.data == 0.0).all():
             log.warning("Map values are all zeros. Check and fix this!")
+        if np.isnan(map.data).any():
+            log.warning("Map has NaN values. Check and fix this!")
         if not map.geom.is_image and (map.data.sum(axis=(1, 2)) == 0).any():
             log.warning(
                 "Map values are all zeros in at least one energy bin. Check and fix this!"


Test patch:
diff --git a/gammapy/modeling/models/tests/test_spatial.py b/gammapy/modeling/models/tests/test_spatial.py
index d3a96e1d1..bbef5b49b 100644
--- a/gammapy/modeling/models/tests/test_spatial.py
+++ b/gammapy/modeling/models/tests/test_spatial.py
@@ -487,6 +487,14 @@ def test_sky_diffuse_map_empty(caplog):
         )
         assert np.all(np.isfinite(model.map.data))
 
+    # model with nan
+    model_map.data[0, 0, 0] = np.nan
+    with caplog.at_level(logging.WARNING):
+        TemplateSpatialModel(model_map, normalize=True)
+        assert "Map has NaN values. Check and fix this!" in [
+            _.message for _ in caplog.records
+        ]
+
 
 @pytest.mark.parametrize("model_cls", SPATIAL_MODEL_REGISTRY)
 def test_model_from_dict(tmpdir, model_cls):
Repository: gammapy/gammapy
Pull request #5445 (2024-09-24 12:22:01)

Add a to_table() method to TimeMapAxis
This simple PR adds a `to_table` method for TimeMapAxis that produces the same table as the one produced by the equivalent GTIs.
Mentioned by @AtreyeeS as a simple possibility to spare a couple of function calls in PR #5443 

Probably needs to be completed with some format and validity checks.


Patch:
diff --git a/gammapy/maps/axes.py b/gammapy/maps/axes.py
index e359d94ba..a1057e319 100644
--- a/gammapy/maps/axes.py
+++ b/gammapy/maps/axes.py
@@ -3030,6 +3030,18 @@ class TimeMapAxis:
             self.edges_min, self.edges_max, reference_time=self.reference_time
         )
 
+    def to_table(self):
+        """Create table.
+
+        Returns
+        -------
+        table : `~astropy.table.Table`
+            Table with axis data.
+        """
+        t = self.to_gti().table
+
+        return t
+
     def to_header(self, format="gadf", idx=0):
         """Create FITS header.
 


Test patch:
diff --git a/gammapy/maps/tests/test_axes.py b/gammapy/maps/tests/test_axes.py
index 223879786..71d290109 100644
--- a/gammapy/maps/tests/test_axes.py
+++ b/gammapy/maps/tests/test_axes.py
@@ -260,6 +260,25 @@ def test_one_bin_nodes():
     assert_allclose(axis.pix_to_coord(0), 1 * u.deg)
 
 
+def test_table():
+    axis = MapAxis(
+        nodes=[0, 1, 2, 3, 4, 5, 6, 7, 8],
+        unit="TeV",
+        name="energy",
+        node_type="edges",
+        interp="lin",
+    )
+
+    table = axis.to_table()
+    assert table.colnames == ["CHANNEL", "E_MIN", "E_MAX"]
+    assert len(table["CHANNEL"]) == axis.nbin
+    assert table["E_MIN"].unit == table["E_MAX"].unit == u.TeV
+    assert (table["E_MIN"].data == axis.edges_min.value).all()
+
+    table_kev = axis.to_table("ogip-sherpa")
+    assert table_kev["E_MIN"].unit == table_kev["E_MAX"].unit == u.keV
+
+
 def test_group_table_basic(energy_axis_ref):
     energy_edges = [1, 2, 10] * u.TeV
 
@@ -606,6 +625,19 @@ def test_coord_to_idx_time_axis(time_intervals):
     assert_allclose(pixels[1::2], [np.nan, 1, 3, 5, 7, 9, 11, 13, 15, 17, 19])
 
 
+def test_timeaxis_table(time_intervals):
+    tmin = time_intervals["t_min"]
+    tmax = time_intervals["t_max"]
+    tref = time_intervals["t_ref"]
+    axis = TimeMapAxis(tmin, tmax, tref, name="time")
+
+    table = axis.to_table()
+
+    assert table.colnames == ["START", "STOP"]
+    assert len(table["START"]) == axis.nbin
+    assert (table["START"] == axis.time_min).all()
+
+
 def test_pix_to_coord_time_axis(time_intervals):
     tmin = time_intervals["t_min"]
     tmax = time_intervals["t_max"]
Repository: gammapy/gammapy
Pull request #5449 (2024-09-26 15:14:04)

combine_flux_maps  supports for different energy axes
Minor change such as `combine_flux_maps` can support maps  with different energy axes.
Works only if the first map energy range encompass the one of the other maps.


Patch:
diff --git a/gammapy/estimators/utils.py b/gammapy/estimators/utils.py
index 61b476160..b5d1d8807 100644
--- a/gammapy/estimators/utils.py
+++ b/gammapy/estimators/utils.py
@@ -959,7 +959,7 @@ def combine_flux_maps(
             if k == 0:
                 stat_scan = map_stat_scan
             else:
-                stat_scan += map_stat_scan
+                stat_scan.data += map_stat_scan.data
 
         return get_flux_map_from_profile(
             {"stat_scan": stat_scan},


Test patch:
diff --git a/gammapy/estimators/map/tests/test_ts.py b/gammapy/estimators/map/tests/test_ts.py
index 674cabf6e..16235b23f 100644
--- a/gammapy/estimators/map/tests/test_ts.py
+++ b/gammapy/estimators/map/tests/test_ts.py
@@ -440,6 +440,32 @@ def test_ts_map_stat_scan(fake_dataset):
         combine_flux_maps([maps, maps1], method="test")
 
 
+def test_ts_map_stat_scan_different_energy(fake_dataset):
+    model = fake_dataset.models["source"]
+
+    dataset = fake_dataset.downsample(25)
+
+    estimator = TSMapEstimator(
+        model,
+        kernel_width="0.3 deg",
+        energy_edges=[200, 3500] * u.GeV,
+        selection_optional=["stat_scan"],
+    )
+
+    estimator_1 = TSMapEstimator(
+        model,
+        kernel_width="0.3 deg",
+        selection_optional=["stat_scan"],
+        energy_edges=[0.2, 10] * u.TeV,
+    )
+
+    maps = estimator.run(dataset)
+    maps_1 = estimator_1.run(dataset)
+
+    combined_map = combine_flux_maps([maps_1, maps], method="profile")
+    assert combined_map.ts.data.shape == (1, 2, 2)
+
+
 def test_ts_map_with_model(fake_dataset):
     model = fake_dataset.models["source"]
     fake_dataset = fake_dataset.copy()
Repository: gammapy/gammapy
Pull request #5548 (2024-11-07 11:22:21)

Remove is_norm in parameter.from_dict for backward compatibility
Remove is_norm in parameter.from_dict for backward compatibility


Patch:
diff --git a/gammapy/modeling/parameter.py b/gammapy/modeling/parameter.py
index 189c99dd1..4b4be5490 100644
--- a/gammapy/modeling/parameter.py
+++ b/gammapy/modeling/parameter.py
@@ -692,6 +692,7 @@ class Parameters(collections.abc.Sequence):
 
         for par in data:
             link_label = par.pop("link", None)
+            par.pop("is_norm", None)
             parameter = Parameter(**par)
             parameter._link_label_io = link_label
             parameters.append(parameter)


Test patch:
diff --git a/gammapy/modeling/tests/test_parameter.py b/gammapy/modeling/tests/test_parameter.py
index dd5ee6ad2..9bf1189de 100644
--- a/gammapy/modeling/tests/test_parameter.py
+++ b/gammapy/modeling/tests/test_parameter.py
@@ -245,6 +245,11 @@ def test_parameters_s():
     assert_allclose(pars[1].factor, 20)
     assert_allclose(pars[1].scale, 1)
 
+    # test for backward compatibilty
+    pars_dict[0]["is_norm"] = True
+    pars = Parameters.from_dict(pars_dict)
+    assert not hasattr(pars[0], "is_norm")
+
 
 def test_parameter_scan_values():
     p = Parameter(name="test", value=0, error=1)
Repository: gammapy/gammapy
Pull request #5644 (2024-12-14 16:42:28)

Add ts in combine_significance_maps output
As discussed in dev call add ts in combine_significance_maps output
so if the significance is inf due to precision error it can be recomputed a posteriori (for example with the method of #5641)


Patch:
diff --git a/gammapy/estimators/utils.py b/gammapy/estimators/utils.py
index 6ace63159..036348dde 100644
--- a/gammapy/estimators/utils.py
+++ b/gammapy/estimators/utils.py
@@ -834,6 +834,7 @@ def combine_significance_maps(maps):
     return dict(
         significance=significance,
         df=df,
+        ts=ts_sum,
         npred_excess=npred_excess_sum,
         estimator_results=maps,
     )


Test patch:
diff --git a/gammapy/estimators/map/tests/test_excess.py b/gammapy/estimators/map/tests/test_excess.py
index 1630e83ca..cc0e804ac 100644
--- a/gammapy/estimators/map/tests/test_excess.py
+++ b/gammapy/estimators/map/tests/test_excess.py
@@ -440,6 +440,7 @@ def test_joint_excess_map(simple_dataset):
 
     assert_allclose(result["npred_excess"].data.sum(), 2 * 19733.602, rtol=1e-3)
     assert_allclose(result["significance"].data[10, 10], 5.618187, rtol=1e-3)
+    assert_allclose(result["ts"].data[10, 10], 35.526888, rtol=1e-3)
     assert_allclose(
         result["df"].data, 2 * (~np.isnan(result["significance"].data)), rtol=1e-3
     )