Repository: gammapy/gammapy

Issue:
Dataset model fitting has a unit issue with PowerLaw2 
When jointly fitting CTA DC-1 spectrum observations with a PowerLaw2, the interpreter will eventually reach the method **integrate_model** of the class **SpectrumEvaluator** in **gammapy.spectrum.utils**. In the loop of **line 79**, the code iterates over the bases of "amplitude" to get the **ref_unit**:
```
for unit in self.model.parameters["amplitude"].quantity.unit.bases:
	if unit.is_equivalent("eV"):
		ref_unit = unit
```
However, this doesn't work for PowerLaw2 since its energy unit is not inside "amplitude". Shouldn't the code, alternatively, evaluate the model to get its output energy unit when this is not inside the "amplitude"?
Dataset model fitting has a unit issue with PowerLaw2 
When jointly fitting CTA DC-1 spectrum observations with a PowerLaw2, the interpreter will eventually reach the method **integrate_model** of the class **SpectrumEvaluator** in **gammapy.spectrum.utils**. In the loop of **line 79**, the code iterates over the bases of "amplitude" to get the **ref_unit**:
```
for unit in self.model.parameters["amplitude"].quantity.unit.bases:
	if unit.is_equivalent("eV"):
		ref_unit = unit
```
However, this doesn't work for PowerLaw2 since its energy unit is not inside "amplitude". Shouldn't the code, alternatively, evaluate the model to get its output energy unit when this is not inside the "amplitude"?


Discussion:
Thanks @alexiscoutinho, I can confirm this bug. The solution here is just to refactor / simplify the `SpectrumEvaluator` code. The special unit handling in the part of the code that you quoted, seems to be there for no good reasons (not anymore probably...).
Thanks @alexiscoutinho, I can confirm this bug. The solution here is just to refactor / simplify the `SpectrumEvaluator` code. The special unit handling in the part of the code that you quoted, seems to be there for no good reasons (not anymore probably...).

Resolving patch:
diff --git a/gammapy/spectrum/utils.py b/gammapy/spectrum/utils.py
--- a/gammapy/spectrum/utils.py
+++ b/gammapy/spectrum/utils.py
@@ -62,33 +62,21 @@ def __init__(self, model, aeff=None, edisp=None, livetime=None, e_true=None):
         self.aeff = aeff
         self.edisp = edisp
         self.livetime = livetime
+
+        if aeff is not None:
+            e_true = self.aeff.energy.edges
+
         self.e_true = e_true
         self.e_reco = None
 
     def compute_npred(self):
-        integral_flux = self.integrate_model()
+        integral_flux = self.model.integral(
+            emin=self.e_true[:-1], emax=self.e_true[1:], intervals=True
+        )
+
         true_counts = self.apply_aeff(integral_flux)
         return self.apply_edisp(true_counts)
 
-    def integrate_model(self):
-        """Integrate model in true energy space."""
-        if self.aeff is not None:
-            # TODO: True energy is converted to model amplitude unit. See issue 869
-            ref_unit = None
-            try:
-                for unit in self.model.parameters["amplitude"].quantity.unit.bases:
-                    if unit.is_equivalent("eV"):
-                        ref_unit = unit
-            except IndexError:
-                ref_unit = "TeV"
-            self.e_true = self.aeff.energy.edges.to(ref_unit)
-        else:
-            if self.e_true is None:
-                raise ValueError("No true energy binning given")
-
-        return self.model.integral(
-            emin=self.e_true[:-1], emax=self.e_true[1:], intervals=True
-        )
 
     def apply_aeff(self, integral_flux):
         if self.aeff is not None:


Test patch:
diff --git a/gammapy/spectrum/tests/test_utils.py b/gammapy/spectrum/tests/test_utils.py
--- a/gammapy/spectrum/tests/test_utils.py
+++ b/gammapy/spectrum/tests/test_utils.py
@@ -9,7 +9,7 @@
 from ...irf import EffectiveAreaTable, EnergyDispersion
 from ...spectrum import integrate_spectrum, SpectrumEvaluator
 from ..powerlaw import power_law_energy_flux, power_law_evaluate, power_law_flux
-from ..models import ExponentialCutoffPowerLaw, PowerLaw, TableModel
+from ..models import ExponentialCutoffPowerLaw, PowerLaw, TableModel, PowerLaw2
 
 
 def test_integrate_spectrum():
@@ -85,6 +85,7 @@ def get_test_cases():
     e_reco = Quantity(np.logspace(-1, 2, 100), "TeV")
     return [
         dict(model=PowerLaw(amplitude="1e2 TeV-1"), e_true=e_true, npred=999),
+        dict(model=PowerLaw2(amplitude="1", emin="0.1 TeV", emax="100 TeV"), e_true=e_true, npred=1),
         dict(
             model=PowerLaw(amplitude="1e-11 TeV-1 cm-2 s-1"),
             aeff=EffectiveAreaTable.from_parametrization(e_true),