Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Add function to determine pivot energy for any spectral model #4635

Merged
merged 28 commits into from Jul 26, 2023
Merged
Show file tree
Hide file tree
Changes from 12 commits
Commits
Show all changes
28 commits
Select commit Hold shift + click to select a range
2138284
Add function to determine pivot energy for any spectral model
Astro-Kirsty Jul 3, 2023
66b91f9
Update doc strings
Astro-Kirsty Jul 4, 2023
c4505a9
Simplify implementation of minimum
Astro-Kirsty Jul 6, 2023
a7bd5d1
Modify the input energy to be energy bounds
Astro-Kirsty Jul 6, 2023
b9bf6a3
Modify docstring
Astro-Kirsty Jul 6, 2023
ade9551
Implementing fsolve function
Astro-Kirsty Jul 7, 2023
1d8f081
Adjust minimizer function, remove property decorator
Astro-Kirsty Jul 10, 2023
411eb62
Update returns, ensure minimiser works by adapting test functions
Astro-Kirsty Jul 17, 2023
0b96f97
Adding log.warning to provide information on NaN values.
Astro-Kirsty Jul 18, 2023
d9e723c
Final adjustments as per dev call
Astro-Kirsty Jul 21, 2023
eaa9f91
Edit docstrings and log warnings
Astro-Kirsty Jul 24, 2023
bbf5564
Increase tolerance
Astro-Kirsty Jul 25, 2023
7b1ac2f
Add function to determine pivot energy for any spectral model
Astro-Kirsty Jul 3, 2023
72b0baa
Update doc strings
Astro-Kirsty Jul 4, 2023
8cfab6c
Simplify implementation of minimum
Astro-Kirsty Jul 6, 2023
1431300
Modify the input energy to be energy bounds
Astro-Kirsty Jul 6, 2023
3a95956
Modify docstring
Astro-Kirsty Jul 6, 2023
e64a131
Implementing fsolve function
Astro-Kirsty Jul 7, 2023
0ed8e53
Adjust minimizer function, remove property decorator
Astro-Kirsty Jul 10, 2023
dc8a2ef
Update returns, ensure minimiser works by adapting test functions
Astro-Kirsty Jul 17, 2023
1cfc245
Adding log.warning to provide information on NaN values.
Astro-Kirsty Jul 18, 2023
16d4539
Final adjustments as per dev call
Astro-Kirsty Jul 21, 2023
8fec678
Edit docstrings and log warnings
Astro-Kirsty Jul 24, 2023
965db1e
Increase tolerance
Astro-Kirsty Jul 25, 2023
d995411
Adapt test
Astro-Kirsty Jul 25, 2023
9186606
Revert previous change
Astro-Kirsty Jul 25, 2023
a59cbe1
Merge branch 'pivotenergy' of github.com:Astro-Kirsty/gammapy into pi…
Astro-Kirsty Jul 25, 2023
98e9bef
Adapt test to include ecpl
Astro-Kirsty Jul 25, 2023
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
53 changes: 51 additions & 2 deletions gammapy/modeling/models/spectral.py
Expand Up @@ -213,6 +213,45 @@ def evaluate_error(self, energy, epsilon=1e-4):
"""
return self._propagate_error(epsilon=epsilon, fct=self, energy=energy)

@property
def pivot_energy(self):
"""The pivot or decorrelation energy, for a given spectral model calculated numerically.
It is defined as the energy at which the correlation between the spectral parameters is minimized.

Astro-Kirsty marked this conversation as resolved.
Show resolved Hide resolved
Returns
-------
pivot energy : `~astropy.units.Quantity`
The energy at which the statistical error in the computed flux is smallest.
If no minimum is found, NaN will be returned.
"""

x_unit = self.reference.unit

def min_func(x):
"""Function to minimize"""
x = np.exp(x)
dnde, dnde_error = self.evaluate_error(x * x_unit)
return dnde_error / dnde

bounds = [np.log(self.reference.value) - 3, np.log(self.reference.value) + 3]

std = np.std(min_func(x=np.linspace(bounds[0], bounds[1], 100)))
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

does the choice of the number of steps in linespace can affect the precision ?
If yes it should be configurable.

Copy link
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It does not

if std < 1e-5:
log.warning(
"The relative error on the flux does not depend on energy. No pivot energy found."
)
return np.nan * x_unit
AtreyeeS marked this conversation as resolved.
Show resolved Hide resolved

minimizer = scipy.optimize.minimize_scalar(min_func, bounds=bounds)

if not minimizer.success:
log.warning(
"No minima found in the relative error on the flux. Pivot energy computation failed."
)
return np.nan * x_unit
else:
return np.exp(minimizer.x) * x_unit

def integral(self, energy_min, energy_max, **kwargs):
r"""Integrate spectral model numerically if no analytical solution defined.

Expand Down Expand Up @@ -815,13 +854,18 @@ def inverse(self, value, *args):

@property
def pivot_energy(self):
r"""The decorrelation energy is defined as:
r"""The pivot or decorrelation energy is defined as:

.. math::

E_D = E_0 * \exp{cov(\phi_0, \Gamma) / (\phi_0 \Delta \Gamma^2)}

Formula (1) in https://arxiv.org/pdf/0910.4881.pdf

Returns
-------
pivot energy : `~astropy.units.Quantity`
If no minimum is found, NaN will be returned.
AtreyeeS marked this conversation as resolved.
Show resolved Hide resolved
"""
index_err = self.index.error
reference = self.reference.quantity
Expand Down Expand Up @@ -908,13 +952,18 @@ def inverse(self, value, *args):

@property
def pivot_energy(self):
r"""The decorrelation energy is defined as:
r"""The pivot or decorrelation energy is defined as:

.. math::

E_D = E_0 * \exp{cov(\phi_0, \Gamma) / (\phi_0 \Delta \Gamma^2)}

Formula (1) in https://arxiv.org/pdf/0910.4881.pdf

Returns
-------
pivot energy : `~astropy.units.Quantity`
If no minimum is found, NaN will be returned.
AtreyeeS marked this conversation as resolved.
Show resolved Hide resolved
"""
tilt_err = self.tilt.error
reference = self.reference.quantity
Expand Down
17 changes: 16 additions & 1 deletion gammapy/modeling/models/tests/test_spectral.py
Expand Up @@ -614,14 +614,29 @@ def test_ecpl_integrate():

def test_pwl_pivot_energy():
pwl = PowerLawSpectralModel(amplitude="5.35510540e-11 cm-2 s-1 TeV-1")
assert_quantity_allclose(pwl.pivot_energy, np.nan * u.TeV, rtol=1e-5)

pwl.covariance = [
[0.0318377**2, 6.56889442e-14, 0],
[6.56889442e-14, 0, 0],
[0, 0, 0],
]
assert_quantity_allclose(pwl.pivot_energy, 3.3540034 * u.TeV, rtol=1e-5)

assert_quantity_allclose(pwl.pivot_energy, 3.3540034240210987 * u.TeV)

def test_num_pivot_energy():
AtreyeeS marked this conversation as resolved.
Show resolved Hide resolved
lp = LogParabolaSpectralModel(
amplitude="5.82442e-11 cm-2 s-1 GeV-1",
reference="17.337 GeV",
alpha="1.9134",
beta="0.2217",
)
lp.amplitude.error = "2.8804e-12 cm-2 s-1 GeV-1"
Astro-Kirsty marked this conversation as resolved.
Show resolved Hide resolved
assert_quantity_allclose(lp.pivot_energy, np.nan * u.GeV, rtol=1e-5)

lp.alpha.error = "0.1126"
lp.beta.error = "0.0670"
assert_quantity_allclose(lp.pivot_energy, 17.337042 * u.GeV, rtol=1e-5)


def test_template_spectral_model_evaluate_tiny():
Expand Down