test_file_function.py 7.76 KB
#! /usr/bin/env python
# ==========================================================================
# This script tests the GModelSpectralFunc file function spectral model.
#
# Copyright (C) 2011-2015 Jurgen Knodlseder
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
#
# ==========================================================================
import math
import gammalib

# ================================= #
# Generate file function from model #
# ================================= #
def make_file_function(model, emin=0.1e6, emax=100.0e6, nodes=10):
    """
    Generate file function from model.
    """
    # Set filename
    filename = "file_function.dat"

    # Generate file function CSV file
    dloge = (math.log10(emax) - math.log10(emin)) / (nodes - 1)
    file = open(filename, "w")
    for i in range(nodes):
        energy = math.pow(10.0, math.log10(emin) + i * dloge)
        eng    = gammalib.GEnergy()
        eng.MeV(energy)
        value = model.eval(eng)
        file.write(str(energy) + " " + str(value) + "\n")
    file.close()

    # Generate file function
    file_function = gammalib.GModelSpectralFunc(filename)

    # Return
    return file_function


# ========================== #
# Compare photon flux values #
# ========================== #
def compare_photon_flux(model, file_function, emin=8.7, emax=1123.0, steps=13):
    """
    Compare photon fluxes
    """
    # Set accuracy
    eps = 1.0e-8
    n_violate = 0

    # Allocate boundaries
    e_min = gammalib.GEnergy()
    e_max = gammalib.GEnergy()

    # Ramp up emax from below first node
    e_min.MeV(emin)
    dloge = (math.log10(emax) - math.log10(emin)) / (steps - 1)
    for i in range(steps):
        energy = math.pow(10.0, math.log10(emin) + i * dloge)
        e_max.MeV(energy)
        flux_model = model.flux(e_min, e_max)
        flux_ff    = file_function.flux(e_min, e_max)
        if (abs(flux_model - flux_ff) > eps):
            print(e_min, e_max, flux_model, flux_ff, flux_model - flux_ff)
            n_violate += 1

    # Ramp up emax from above first node
    emin = 13.0
    e_min.MeV(emin)
    dloge = (math.log10(emax) - math.log10(emin)) / (steps - 1)
    for i in range(steps):
        energy = math.pow(10.0, math.log10(emin) + i * dloge)
        e_max.MeV(energy)
        flux_model = model.flux(e_min, e_max)
        flux_ff = file_function.flux(e_min, e_max)
        if (abs(flux_model - flux_ff) > eps):
            print(e_min, e_max, flux_model, flux_ff, flux_model - flux_ff)
            n_violate += 1

    # Ramp down emin from above last node
    e_max.MeV(emax)
    dloge = (math.log10(emax) - math.log10(emin)) / (steps - 1)
    for i in range(steps):
        energy = math.pow(10.0, math.log10(emax) - i * dloge)
        e_min.MeV(energy)
        flux_model = model.flux(e_min, e_max)
        flux_ff = file_function.flux(e_min, e_max)
        if (abs(flux_model - flux_ff) > eps):
            print(e_min, e_max, flux_model, flux_ff, flux_model - flux_ff)
            n_violate += 1

    # Ramp down emin from below last node
    emax = 873.0
    e_max.MeV(emax)
    dloge = (math.log10(emax) - math.log10(emin)) / (steps - 1)
    for i in range(steps):
        energy = math.pow(10.0, math.log10(emax) - i * dloge)
        e_min.MeV(energy)
        flux_model = model.flux(e_min, e_max)
        flux_ff = file_function.flux(e_min, e_max)
        if (abs(flux_model - flux_ff) > eps):
            print(e_min, e_max, flux_model, flux_ff, flux_model - flux_ff)
            n_violate += 1

    # Print summary
    if n_violate == 0:
        print("compare_photon_flux: All tests satisfied accuracy.")
    else:
        print("compare_photon_flux: " + str(n_violate) + " tests exceeded accuracy.")

    # Return
    return


# ========================== #
# Compare energy flux values #
# ========================== #
def compare_energy_flux(model, file_function, emin=8.7, emax=1123.0, steps=13):
    """
    Compare energy fluxes
    """
    # Set accuracy
    eps = 1.0e-5
    n_violate = 0

    # Allocate boundaries
    e_min = gammalib.GEnergy()
    e_max = gammalib.GEnergy()

    # Ramp up emax from below first node
    e_min.MeV(emin)
    dloge = (math.log10(emax) - math.log10(emin)) / (steps - 1)
    for i in range(steps):
        energy = math.pow(10.0, math.log10(emin) + i * dloge)
        e_max.MeV(energy)
        flux_model = model.eflux(e_min, e_max)
        flux_ff = file_function.eflux(e_min, e_max)
        if (abs(flux_model - flux_ff) > eps):
            print(e_min, e_max, flux_model, flux_ff, flux_model - flux_ff)
            n_violate += 1

    # Ramp up emax from above first node
    emin = 13.0
    e_min.MeV(emin)
    dloge = (math.log10(emax) - math.log10(emin)) / (steps - 1)
    for i in range(steps):
        energy = math.pow(10.0, math.log10(emin) + i * dloge)
        e_max.MeV(energy)
        flux_model = model.eflux(e_min, e_max)
        flux_ff = file_function.eflux(e_min, e_max)
        if (abs(flux_model - flux_ff) > eps):
            print(e_min, e_max, flux_model, flux_ff, flux_model - flux_ff)
            n_violate += 1

    # Ramp down emin from above last node
    e_max.MeV(emax)
    dloge = (math.log10(emax) - math.log10(emin)) / (steps - 1)
    for i in range(steps):
        energy = math.pow(10.0, math.log10(emax) - i * dloge)
        e_min.MeV(energy)
        flux_model = model.eflux(e_min, e_max)
        flux_ff = file_function.eflux(e_min, e_max)
        if (abs(flux_model - flux_ff) > eps):
            print(e_min, e_max, flux_model, flux_ff, flux_model - flux_ff)
            n_violate += 1

    # Ramp down emin from below last node
    emax = 873.0
    e_max.MeV(emax)
    dloge = (math.log10(emax) - math.log10(emin)) / (steps - 1)
    for i in range(steps):
        energy = math.pow(10.0, math.log10(emax) - i * dloge)
        e_min.MeV(energy)
        flux_model = model.eflux(e_min, e_max)
        flux_ff = file_function.eflux(e_min, e_max)
        if (abs(flux_model - flux_ff) > eps):
            print(e_min, e_max, flux_model, flux_ff, flux_model - flux_ff)
            n_violate += 1

    # Print summary
    if n_violate == 0:
        print("compare_energy_flux: All tests satisfied accuracy.")
    else:
        print("compare_energy_flux: " + str(n_violate) + " tests exceeded accuracy.")

    # Return
    return


# ======= #
# Test MC #
# ======= #
def test_mc(file_function, trials=10):
    """
    Print a bunch of Monte Carlo energies.
    """
    # Allocate boundaries
    e_min = gammalib.GEnergy()
    e_max = gammalib.GEnergy()
    ran   = GRan()

    # Set energy range
    e_min.TeV(0.1)
    e_max.TeV(100.0)

    # Loop over trials
    for i in range(trials):
        print(file_function.mc(e_min, e_max, ran))

    # Return
    return


# ================ #
# Main entry point #
# ================ #
if __name__ == '__main__':
    """
    Main entry point
    """
    # Allocate power law
    model = gammalib.GModelSpectralPlaw(5.7, -2.48)
    model["Prefactor"].scale(1.0e-16)
    model["PivotEnergy"].value(0.3)
    model["PivotEnergy"].scale(1.0e6)

    # Make file function
    file_function = make_file_function(model)

    # Compare photon fluxes
    compare_photon_flux(model, file_function)

    # Compare energy fluxes
    compare_energy_flux(model, file_function)

    # Test MC
    test_mc(file_function)