Passed
Pull Request — master (#2111)
by
unknown
02:29
created

SpectrumDatasetOnOff.npred()   A

Complexity

Conditions 2

Size

Total Lines 6
Code Lines 5

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 2
eloc 5
nop 1
dl 0
loc 6
rs 10
c 0
b 0
f 0
1
# Licensed under a 3-clause BSD style license - see LICENSE.rst
2
import numpy as np
3
from .observation import SpectrumObservation
4
from .utils import SpectrumEvaluator
5
from ..utils.fitting import Dataset, Parameters
6
from ..stats import wstat
7
8
__all__ = ["SpectrumDatasetOnOff"]
9
10
11
class SpectrumDatasetOnOff(Dataset):
12
    """Compute spectral model fit statistic on a ON OFF Spectrum.
13
14
15
    Parameters
16
    ----------
17
    model : `~gammapy.spectrum.models.SpectralModel`
18
        Fit model
19
    counts_on : `~gammapy.spectrum.PHACountsSpectrum`
20
        ON Counts spectrum
21
    counts_off : `~gammapy.spectrum.PHACountsSpectrum`
22
        OFF Counts spectrum
23
    livetime : `~astropy.units.Quantity`
24
        Livetime
25
    mask : numpy.array
26
        Mask to apply to the likelihood.
27
    aeff : `~gammapy.irf.EffectiveAreaTable`
28
        Effective area
29
    edisp : `~gammapy.irf.EnergyDispersion`
30
        Energy dispersion
31
    """
32
33
    def __init__(
34
        self,
35
        model=None,
36
        counts_on=None,
37
        counts_off=None,
38
        livetime=None,
39
        mask=None,
40
        aeff=None,
41
        edisp=None,
42
    ):
43
        if mask is not None and mask.dtype != np.dtype("bool"):
44
            raise ValueError("mask data must have dtype bool")
45
46
        self.counts_on = counts_on
47
        self.counts_off = counts_off
48
        self.livetime = livetime
49
        self.mask = mask
50
        self.aeff = aeff
51
        self.edisp = edisp
52
53
        self.model = model
54
55
    @property
56
    def alpha(self):
57
        """Exposure ratio between signal and background regions"""
58
        return self.counts_on.backscal / self.counts_off.backscal
59
60
    @property
61
    def model(self):
62
        return self._model
63
64
    @model.setter
65
    def model(self, model):
66
        self._model = model
67
        if model is not None:
68
            self._parameters = Parameters(self._model.parameters.parameters)
69
            if self.edisp is None:
70
                self._predictor = SpectrumEvaluator(
71
                    model=self.model,
72
                    livetime=self.livetime,
73
                    aeff=self.aeff,
74
                    e_true=self.counts_on.energy.bins,
75
                )
76
            else:
77
                self._predictor = SpectrumEvaluator(
78
                    model=self.model,
79
                    aeff=self.aeff,
80
                    edisp=self.edisp,
81
                    livetime=self.livetime,
82
                )
83
84
        else:
85
            self._parameters = None
86
            self._predictor = None
87
88
    @property
89
    def parameters(self):
90
        if self._parameters is None:
91
            raise AttributeError("No model set for Dataset")
92
        else:
93
            return self._parameters
94
95
    @property
96
    def data_shape(self):
97
        """Shape of the counts data"""
98
        return self.counts_on.data.data.shape
99
100
    def npred(self):
101
        """Returns npred counts vector """
102
        if self._predictor is None:
103
            raise AttributeError("No model set for this Dataset")
104
        model_npred = self._predictor.compute_npred().data.data
105
        return model_npred
106
107
    def likelihood_per_bin(self):
108
        """Likelihood per bin given the current model parameters"""
109
        on_stat_ = wstat(
110
            n_on=self.counts_on.data.data,
111
            n_off=self.counts_off.data.data,
112
            alpha=self.alpha,
113
            mu_sig=self.npred(),
114
        )
115
        return np.nan_to_num(on_stat_)
116
117 View Code Duplication
    def likelihood(self, parameters, mask=None):
0 ignored issues
show
Duplication introduced by
This code seems to be duplicated in your project.
Loading history...
118
        """Total likelihood given the current model parameters.
119
120
        Parameters
121
        ----------
122
        mask : `~numpy.ndarray`
123
            Mask to be combined with the dataset mask.
124
        """
125
        if self.mask is None and mask is None:
126
            stat = self.likelihood_per_bin()
127
        elif self.mask is None:
128
            stat = self.likelihood_per_bin()[mask]
129
        elif mask is None:
130
            stat = self.likelihood_per_bin()[self.mask]
131
        else:
132
            stat = self.likelihood_per_bin()[mask & self.mask]
133
134
        return np.sum(stat, dtype=np.float64)
135
136
    @classmethod
137
    def read(cls, filename):
138
        """Read from file
139
140
        For now, filename is assumed to the name of a PHA file where BKG file, ARF, and RMF names
141
        must be set in the PHA header and be present in the same folder
142
143
        Parameters
144
        ----------
145
        filename : str
146
            OGIP PHA file to read
147
        """
148
        observation = SpectrumObservation.read(filename)
149
        return SpectrumDatasetOnOff._from_spectrum_observation(observation)
150
151
    # TODO: check if SpectrumObservation is needed in the long run
152
    @classmethod
153
    def _from_spectrum_observation(cls, observation):
154
        """Creates a SpectrumDatasetOnOff from a SpectrumObservation object"""
155
156
        # Build mask from quality vector
157
        quality = observation.on_vector.quality
158
        mask = quality == 0
159
160
        return cls(
161
            counts_on=observation.on_vector,
162
            aeff=observation.aeff,
163
            counts_off=observation.off_vector,
164
            edisp=observation.edisp,
165
            livetime=observation.livetime,
166
            mask=mask,
167
        )
168