/***************************************************************************
* test_GObservation.cpp - Test observation module *
* ----------------------------------------------------------------------- *
* copyright (C) 2012-2017 by Jean-Baptiste Cayrou *
* ----------------------------------------------------------------------- *
* *
* 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 . *
* *
***************************************************************************/
/**
* @file test_GObservation.cpp
* @brief Test observation module
* @author Jean-Baptiste Cayrou
*/
/* __ Includes ___________________________________________________________ */
#ifdef HAVE_CONFIG_H
#include
#endif
#include "testinst/GTestLib.hpp"
#include "test_GObservation.hpp"
/* __ OpenMP section _____________________________________________________ */
#ifdef _OPENMP
#include
#ifdef HAVE_OPENMP_DARWIN_KLUGE
#include
pthread_attr_t gomp_thread_attr;
#endif
#endif
/* __ Coding definitions _________________________________________________ */
#define RATE 13.0 //!< Events per seconde. For events generation.
#define UN_BINNED 0
#define BINNED 1
/***********************************************************************//**
* @brief Set tests
***************************************************************************/
void TestGObservation::set(void)
{
// Set test name
name("Observation module");
// Append tests
append(static_cast(&TestGObservation::test_time_reference),
"Test GTimeReference class");
append(static_cast(&TestGObservation::test_time),
"Test GTime class");
append(static_cast(&TestGObservation::test_times),
"Test GTimes class");
append(static_cast(&TestGObservation::test_gti),
"Test GGti class");
append(static_cast(&TestGObservation::test_energy),
"Test GEnergy class");
append(static_cast(&TestGObservation::test_energies),
"Test GEnergies class");
append(static_cast(&TestGObservation::test_ebounds),
"Test GEbounds class");
append(static_cast(&TestGObservation::test_phases),
"Test GPhases class");
append(static_cast(&TestGObservation::test_photons),
"Test GPhotons class");
append(static_cast(&TestGObservation::test_observations_optimizer),
"Test GObservations::likelihood class");
// Return
return;
}
/***********************************************************************//**
* @brief Clone test suite
*
* @return Pointer to deep copy of test suite.
***************************************************************************/
TestGObservation* TestGObservation::clone(void) const
{
// Clone test suite
return new TestGObservation(*this);
}
/***********************************************************************//**
* @brief Test GEbounds
***************************************************************************/
void TestGObservation::test_ebounds(void)
{
// Test void constructor
test_try("Void constructor");
try {
GEbounds ebds;
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Manipulate energy boudaries starting from an empty object
GEbounds ebds;
test_value(ebds.size(), 0, "GEbounds should have zero size.");
test_assert(ebds.is_empty(), "GEbounds should be empty.");
test_value(ebds.emin().MeV(), 0.0, 1.0e-10, "Minimum energy should be 0.");
test_value(ebds.emax().MeV(), 0.0, 1.0e-10, "Maximum energy should be 0.");
// Add empty interval
ebds.append(GEnergy(1.0, "MeV"), GEnergy(1.0, "MeV"));
test_value(ebds.size(), 1, "GEbounds should have 1 element.");
test_assert(!ebds.is_empty(), "GEbounds should not be empty.");
test_value(ebds.emin().MeV(), 1.0, 1.0e-10, "Minimum energy should be 1.");
test_value(ebds.emax().MeV(), 1.0, 1.0e-10, "Maximum energy should be 1.");
// Add one interval
ebds.append(GEnergy(1.0, "MeV"), GEnergy(10.0, "MeV"));
test_value(ebds.size(), 2, "GEbounds should have 2 elements.");
test_assert(!ebds.is_empty(), "GEbounds should not be empty.");
test_value(ebds.emin().MeV(), 1.0, 1.0e-10, "Minimum energy should be 1.");
test_value(ebds.emax().MeV(), 10.0, 1.0e-10, "Maximum energy should be 10.");
// Remove intervals
ebds.remove(0);
ebds.remove(0); // Now old intervals 1 is interval 0
test_value(ebds.size(), 0, "GEbounds should have zero size.");
test_assert(ebds.is_empty(), "GEbounds should be empty.");
test_value(ebds.emin().MeV(), 0.0, 1.0e-10, "Minimum energy should be 0.");
test_value(ebds.emax().MeV(), 0.0, 1.0e-10, "Maximum energy should be 0.");
// Append two overlapping intervals
ebds.append(GEnergy(1.0, "MeV"), GEnergy(100.0, "MeV"));
ebds.append(GEnergy(10.0, "MeV"), GEnergy(1000.0, "MeV"));
test_value(ebds.size(), 2, "GEbounds should have 2 elements.");
test_assert(!ebds.is_empty(), "GEbounds should not be empty.");
test_value(ebds.emin().MeV(), 1.0, 1.0e-10, "Minimum energy should be 1.");
test_value(ebds.emax().MeV(), 1000.0, 1.0e-10, "Maximum energy should be 1000.");
// Clear object
ebds.clear();
test_value(ebds.size(), 0, "GEbounds should have zero size.");
test_assert(ebds.is_empty(), "GEbounds should be empty.");
test_value(ebds.emin().MeV(), 0.0, 1.0e-10, "Minimum energy should be 0.");
test_value(ebds.emax().MeV(), 0.0, 1.0e-10, "Maximum energy should be 0.");
// Append two overlapping intervals in inverse order
ebds.clear();
ebds.append(GEnergy(10.0, "MeV"), GEnergy(1000.0, "MeV"));
ebds.append(GEnergy(1.0, "MeV"), GEnergy(100.0, "MeV"));
test_value(ebds.size(), 2, "GEbounds should have 2 elements.");
test_assert(!ebds.is_empty(), "GEbounds should not be empty.");
test_value(ebds.emin().MeV(), 1.0, 1.0e-10, "Minimum energy should be 1.");
test_value(ebds.emax().MeV(), 1000.0, 1.0e-10, "Maximum energy should be 1000.");
// Insert two overlapping intervals
ebds.clear();
ebds.insert(GEnergy(1.0, "MeV"), GEnergy(100.0, "MeV"));
ebds.insert(GEnergy(10.0, "MeV"), GEnergy(1000.0, "MeV"));
test_value(ebds.size(), 2, "GEbounds should have 2 elements.");
test_assert(!ebds.is_empty(), "GEbounds should not be empty.");
test_value(ebds.emin().MeV(), 1.0, 1.0e-10, "Minimum energy should be 1.");
test_value(ebds.emax().MeV(), 1000.0, 1.0e-10, "Maximum energy should be 1000.");
// Insert two overlapping intervals in inverse order
ebds.clear();
ebds.insert(GEnergy(10.0, "MeV"), GEnergy(1000.0, "MeV"));
ebds.insert(GEnergy(1.0, "MeV"), GEnergy(100.0, "MeV"));
test_value(ebds.size(), 2, "GEbounds should have 2 elements.");
test_assert(!ebds.is_empty(), "GEbounds should not be empty.");
test_value(ebds.emin().MeV(), 1.0, 1.0e-10, "Minimum energy should be 1.");
test_value(ebds.emax().MeV(), 1000.0, 1.0e-10, "Maximum energy should be 1000.");
// Merge two overlapping intervals
ebds.clear();
ebds.merge(GEnergy(1.0, "MeV"), GEnergy(100.0, "MeV"));
ebds.merge(GEnergy(10.0, "MeV"), GEnergy(1000.0, "MeV"));
test_value(ebds.size(), 1, "GEbounds should have 1 element.");
test_assert(!ebds.is_empty(), "GEbounds should not be empty.");
test_value(ebds.emin().MeV(), 1.0, 1.0e-10, "Minimum energy should be 1.");
test_value(ebds.emax().MeV(), 1000.0, 1.0e-10, "Maximum energy should be 1000.");
// Merge two overlapping intervals in inverse order
ebds.clear();
ebds.merge(GEnergy(10.0, "MeV"), GEnergy(1000.0, "MeV"));
ebds.merge(GEnergy(1.0, "MeV"), GEnergy(100.0, "MeV"));
test_value(ebds.size(), 1, "GEbounds should have 1 element.");
test_assert(!ebds.is_empty(), "GEbounds should not be empty.");
test_value(ebds.emin().MeV(), 1.0, 1.0e-10, "Minimum energy should be 1.");
test_value(ebds.emax().MeV(), 1000.0, 1.0e-10, "Maximum energy should be 1000.");
// Check linear boundaries
ebds.clear();
ebds.set_lin(2, GEnergy(1.0, "MeV"), GEnergy(3.0, "MeV"));
test_value(ebds.size(), 2, "GEbounds should have 2 elements.");
test_assert(!ebds.is_empty(), "GEbounds should not be empty.");
test_value(ebds.emin(0).MeV(), 1.0, 1.0e-10, "Bin 0 minimum energy should be 1.");
test_value(ebds.emin(1).MeV(), 2.0, 1.0e-10, "Bin 1 minimum energy should be 2.");
test_value(ebds.emax(0).MeV(), 2.0, 1.0e-10, "Bin 0 maximum energy should be 2.");
test_value(ebds.emax(1).MeV(), 3.0, 1.0e-10, "Bin 1 maximum energy should be 3.");
test_value(ebds.emin().MeV(), 1.0, 1.0e-10, "Minimum energy should be 1.");
test_value(ebds.emax().MeV(), 3.0, 1.0e-10, "Maximum energy should be 3.");
// Check logarithmic boundaries
ebds.clear();
ebds.set_log(2, GEnergy(1.0, "MeV"), GEnergy(100.0, "MeV"));
test_value(ebds.size(), 2, "GEbounds should have 2 elements.");
test_assert(!ebds.is_empty(), "GEbounds should not be empty.");
test_value(ebds.emin(0).MeV(), 1.0, 1.0e-10, "Bin 0 minimum energy should be 1.");
test_value(ebds.emin(1).MeV(), 10.0, 1.0e-10, "Bin 1 minimum energy should be 10.");
test_value(ebds.emax(0).MeV(), 10.0, 1.0e-10, "Bin 0 maximum energy should be 10.");
test_value(ebds.emax(1).MeV(), 100.0, 1.0e-10, "Bin 1 maximum energy should be 100.");
test_value(ebds.emin().MeV(), 1.0, 1.0e-10, "Minimum energy should be 1.");
test_value(ebds.emax().MeV(), 100.0, 1.0e-10, "Maximum energy should be 100.");
// Check boundary extension
GEbounds ext(1, GEnergy(100.0, "MeV"), GEnergy(1000.0, "MeV"));
ebds.extend(ext);
test_value(ebds.size(), 3, "GEbounds should have 3 elements.");
test_assert(!ebds.is_empty(), "GEbounds should not be empty.");
test_value(ebds.emin(0).MeV(), 1.0, 1.0e-10, "Bin 0 minimum energy should be 1.");
test_value(ebds.emin(1).MeV(), 10.0, 1.0e-10, "Bin 1 minimum energy should be 10.");
test_value(ebds.emin(2).MeV(), 100.0, 1.0e-10, "Bin 2 minimum energy should be 100.");
test_value(ebds.emax(0).MeV(), 10.0, 1.0e-10, "Bin 0 maximum energy should be 10.");
test_value(ebds.emax(1).MeV(), 100.0, 1.0e-10, "Bin 1 maximum energy should be 100.");
test_value(ebds.emax(2).MeV(), 1000.0, 1.0e-10, "Bin 1 maximum energy should be 1000.");
test_value(ebds.emin().MeV(), 1.0, 1.0e-10, "Minimum energy should be 1.");
test_value(ebds.emax().MeV(), 1000.0, 1.0e-10, "Maximum energy should be 1000.");
// Check emean, elogmean and ewidth methods
ebds.set_log(1, GEnergy(1.0, "MeV"), GEnergy(10.0, "MeV"));
test_value(ebds.emean(0).MeV(), 5.5, 1.0e-10, "Mean energy should be 5.5.");
test_value(ebds.elogmean(0).MeV(), 3.16227766017, 1.0e-10, "Log mean energy should be 3.16227766017.");
test_value(ebds.ewidth(0).MeV(), 9.0, 1.0e-10, "Energy width should be 9.0.");
// Check appending of invalid interval
test_try("Test appending of invalid interval");
try {
ebds.append(GEnergy(100.0, "MeV"), GEnergy(10.0, "MeV"));
test_try_failure("Appending an invalid interval shall throw an exception.");
}
catch (GException::invalid_argument &e) {
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Check constructing of linear invalid energy boundaries
test_try("Test constructing of linear invalid energy boundaries");
try {
GEbounds bad(10, GEnergy(100.0, "MeV"), GEnergy(10.0, "MeV"), false);
test_try_failure("Constructing of linear invalid energy boundaries "
"shall throw an exception.");
}
catch (GException::invalid_argument &e) {
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Check constructing of logarithmic invalid energy boundaries
test_try("Test constructing of logarithmic invalid energy boundaries");
try {
GEbounds bad(10, GEnergy(100.0, "MeV"), GEnergy(10.0, "MeV"), true);
test_try_failure("Constructing of logarithmic invalid energy "
"boundaries shall throw an exception.");
}
catch (GException::invalid_argument &e) {
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Check constructing of logarithmic invalid energy boundaries
test_try("Test constructing of logarithmic invalid energy boundaries");
try {
GEbounds bad(10, GEnergy(0.0, "MeV"), GEnergy(10.0, "MeV"), true);
test_try_failure("Constructing of logarithmic invalid energy "
"boundaries shall throw an exception.");
}
catch (GException::invalid_argument &e) {
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Check constructing of logarithmic invalid energy boundaries
test_try("Test constructing of logarithmic invalid energy boundaries");
try {
GEbounds bad(10, GEnergy(10.0, "MeV"), GEnergy(0.0, "MeV"), true);
test_try_failure("Constructing of logarithmic invalid energy "
"boundaries shall throw an exception.");
}
catch (GException::invalid_argument &e) {
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Check energy containment
GEbounds containment(1, GEnergy(100.0, "MeV"), GEnergy(1000.0, "MeV"));
test_assert(containment.contains(GEnergy(200.0, "MeV")),
"Energy 200 MeV should be contained.");
test_assert(!containment.contains(GEnergy(10.0, "MeV")),
"Energy 10 MeV should not be contained.");
test_assert(!containment.contains(GEnergy(2000.0, "MeV")),
"Energy 2000 MeV should not be contained.");
test_assert(containment.contains(GEnergy(200.0, "MeV"), GEnergy(800.0, "MeV")),
"Energy bin [200,800] MeV should be contained.");
test_assert(!containment.contains(GEnergy(80.0, "MeV"), GEnergy(800.0, "MeV")),
"Energy bin [80,800] MeV should not be contained.");
test_assert(!containment.contains(GEnergy(200.0, "MeV"), GEnergy(2000.0, "MeV")),
"Energy bin [200,2000] MeV should not be contained.");
test_assert(!containment.contains(GEnergy(80.0, "MeV"), GEnergy(2000.0, "MeV")),
"Energy bin [80,2000] MeV should not be contained.");
// Remove test file
GFilename filename("test_ebounds.fits");
filename.remove();
// Check saving
containment.save("test_ebounds.fits");
GEbounds load1("test_ebounds.fits");
test_value(load1.size(), 1, "GEbounds should have 1 element.");
test_value(load1.emin().MeV(), 100.0, 1.0e-10, "Minimum energy should be 100.");
test_value(load1.emax().MeV(), 1000.0, 1.0e-10, "Maximum energy should be 1000.");
// Check saving in a different extnsion
ebds.save("test_ebounds.fits[ENERGY BOUNDARIES 2]", true);
GEbounds load2("test_ebounds.fits[ENERGY BOUNDARIES 2]");
test_value(load2.size(), 1, "GEbounds should have 1 element.");
test_value(load2.emin().MeV(), 1.0, 1.0e-10, "Minimum energy should be 1.");
test_value(load2.emax().MeV(), 10.0, 1.0e-10, "Maximum energy should be 10.");
// Check XML write and read methods
GXmlElement element;
ebds.write(element);
GEbounds xml1(element);
test_value(xml1.size(), 1, "XML write and read methods");
test_value(xml1.emin().MeV(), 1.0, 1.0e-10, "XML write and read methods");
test_value(xml1.emax().MeV(), 10.0, 1.0e-10, "XML write and read methods");
// Check energies constructor method
GEnergies energies1(3, GEnergy(1.0, "MeV"), GEnergy(10.0, "MeV"), false);
GEbounds ebds1(energies1);
test_value(ebds1.size(), 2, "GEnergies constructor (3 elements)");
test_value(ebds1.emin().MeV(), 1.0, 1.0e-10, "GEnergies constructor (3 elements)");
test_value(ebds1.emax(0).MeV(), 5.5, 1.0e-10, "GEnergies constructor (3 elements)");
test_value(ebds1.emax().MeV(), 10.0, 1.0e-10, "GEnergies constructor (3 elements)");
// Check energies constructor method
GEnergies energies2(1, GEnergy(1.0, "MeV"), GEnergy(1.0, "MeV"), false);
GEbounds ebds2(energies2);
test_value(ebds2.size(), 1, "GEnergies constructor (1 element)");
test_value(ebds2.emin().MeV(), 1.0, 1.0e-10, "GEnergies constructor (1 element)");
test_value(ebds2.emax().MeV(), 1.0, 1.0e-10, "GEnergies constructor (1 element)");
// Check energy boundary setter method
ebds2.emin(0, GEnergy(123.0, "MeV"));
ebds2.emax(0, GEnergy(511.0, "MeV"));
test_value(ebds2.size(), 1, "Energy boundary setter");
test_value(ebds2.emin().MeV(), 123.0, 1.0e-10, "Energy boundary setter");
test_value(ebds2.emax().MeV(), 511.0, 1.0e-10, "Energy boundary setter");
// Check equality operator
test_assert(ebds1 == ebds1, "Equality operator");
// Check inequality operator
test_assert(ebds1 != ebds2, "Inequality operator");
// Return
return;
}
/***********************************************************************//**
* @brief Test GGti
***************************************************************************/
void TestGObservation::test_gti(void)
{
// Test void constructor
test_try("Void constructor");
try {
GGti gti;
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Manipulate GTIs starting from an empty object
GGti gti;
test_value(gti.size(), 0, "GGti should have zero size.");
test_assert(gti.is_empty(), "GGti should be empty.");
test_value(gti.tstart().secs(), 0.0, 1.0e-7, "Start time should be 0.");
test_value(gti.tstop().secs(), 0.0, 1.0e-7, "Stop time should be 0.");
// Add empty interval
gti.append(GTime(1.0), GTime(1.0));
test_value(gti.size(), 1, "GGti should have 1 interval.");
test_assert(!gti.is_empty(), "GGti should not be empty.");
test_value(gti.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1.");
test_value(gti.tstop().secs(), 1.0, 1.0e-7, "Stop time should be 1.");
// Add one interval
gti.append(GTime(1.0), GTime(10.0));
test_value(gti.size(), 2, "GGti should have 2 intervals.");
test_assert(!gti.is_empty(), "GGti should not be empty.");
test_value(gti.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1.");
test_value(gti.tstop().secs(), 10.0, 1.0e-7, "Stop time should be 10.");
// Remove interval
gti.remove(0);
gti.remove(0);
test_value(gti.size(), 0, "GGti should have zero size.");
test_assert(gti.is_empty(), "GGti should be empty.");
test_value(gti.tstart().secs(), 0.0, 1.0e-7, "Start time should be 0.");
test_value(gti.tstop().secs(), 0.0, 1.0e-7, "Stop time should be 0.");
// Append two overlapping intervals
gti.append(GTime(1.0), GTime(100.0));
gti.append(GTime(10.0), GTime(1000.0));
test_value(gti.size(), 2, "GGti should have 2 intervals.");
test_assert(!gti.is_empty(), "GGti should not be empty.");
test_value(gti.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1.");
test_value(gti.tstop().secs(), 1000.0, 1.0e-7, "Stop time should be 1000.");
// Clear object
gti.clear();
test_value(gti.size(), 0, "GGti should have zero size.");
test_assert(gti.is_empty(), "GGti should be empty.");
test_value(gti.tstart().secs(), 0.0, 1.0e-7, "Start time should be 0.");
test_value(gti.tstop().secs(), 0.0, 1.0e-7, "Stop time should be 0.");
// Append two overlapping intervals in inverse order
gti.clear();
gti.append(GTime(10.0), GTime(1000.0));
gti.append(GTime(1.0), GTime(100.0));
test_value(gti.size(), 2, "GGti should have 2 intervals.");
test_assert(!gti.is_empty(), "GGti should not be empty.");
test_value(gti.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1.");
test_value(gti.tstop().secs(), 1000.0, 1.0e-7, "Stop time should be 1000.");
// Insert two overlapping intervals
gti.clear();
gti.insert(GTime(1.0), GTime(100.0));
gti.insert(GTime(10.0), GTime(1000.0));
test_value(gti.size(), 2, "GGti should have 2 intervals.");
test_assert(!gti.is_empty(), "GGti should not be empty.");
test_value(gti.tstart().secs(), 1.0, 1.0e-10, "Start time should be 1.");
test_value(gti.tstop().secs(), 1000.0, 1.0e-10, "Stop time should be 1000.");
// Insert two overlapping intervals in inverse order
gti.clear();
gti.insert(GTime(10.0), GTime(1000.0));
gti.insert(GTime(1.0), GTime(100.0));
test_value(gti.size(), 2, "GGti should have 2 intervals.");
test_assert(!gti.is_empty(), "GGti should not be empty.");
test_value(gti.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1.");
test_value(gti.tstop().secs(), 1000.0, 1.0e-7, "Stop time should be 1000.");
// Merge two overlapping intervals
gti.clear();
gti.merge(GTime(1.0), GTime(100.0));
gti.merge(GTime(10.0), GTime(1000.0));
test_value(gti.size(), 1, "GGti should have 1 interval.");
test_assert(!gti.is_empty(), "GGti should not be empty.");
test_value(gti.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1.");
test_value(gti.tstop().secs(), 1000.0, 1.0e-7, "Stop time should be 1000.");
// Merge two overlapping intervals in inverse order
gti.clear();
gti.merge(GTime(10.0), GTime(1000.0));
gti.merge(GTime(1.0), GTime(100.0));
test_value(gti.size(), 1, "GGti should have 1 interval.");
test_assert(!gti.is_empty(), "GGti should not be empty.");
test_value(gti.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1.");
test_value(gti.tstop().secs(), 1000.0, 1.0e-7, "Stop time should be 1000.");
// Check extension
gti.clear();
gti.append(GTime(1.0), GTime(10.0));
gti.append(GTime(10.0), GTime(100.0));
GGti ext;
ext.append(GTime(100.0), GTime(1000.0));
gti.extend(ext);
test_value(gti.size(), 3, "GGti should have 3 intervals.");
test_assert(!gti.is_empty(), "GGti should not be empty.");
test_value(gti.tstart(0).secs(), 1.0, 1.0e-7, "Bin 0 start time should be 1.");
test_value(gti.tstart(1).secs(), 10.0, 1.0e-7, "Bin 1 start time should be 10.");
test_value(gti.tstart(2).secs(), 100.0, 1.0e-7, "Bin 2 start time should be 100.");
test_value(gti.tstop(0).secs(), 10.0, 1.0e-7, "Bin 0 stop time should be 10.");
test_value(gti.tstop(1).secs(), 100.0, 1.0e-7, "Bin 1 stop time should be 100.");
test_value(gti.tstop(2).secs(), 1000.0, 1.0e-7, "Bin 2 stop time should be 1000.");
test_value(gti.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1.");
test_value(gti.tstop().secs(), 1000.0, 1.0e-7, "Stop time should be 1000.");
// Remove test file
GFilename file1("test_gti1.fits");
GFilename file2("test_gti2.fits");
file1.remove();
file2.remove();
// Check saving in and loading from FITS file
gti.save("test_gti1.fits", true);
GGti test1("test_gti1.fits");
test_value(test1.size(), 3, "GGti should have 3 intervals.");
test_value(test1.tstart(0).secs(), 1.0, 1.0e-7, "Bin 0 start time should be 1.");
test_value(test1.tstart(1).secs(), 10.0, 1.0e-7, "Bin 1 start time should be 10.");
test_value(test1.tstart(2).secs(), 100.0, 1.0e-7, "Bin 2 start time should be 100.");
test_value(test1.tstop(0).secs(), 10.0, 1.0e-7, "Bin 0 stop time should be 10.");
test_value(test1.tstop(1).secs(), 100.0, 1.0e-7, "Bin 1 stop time should be 100.");
test_value(test1.tstop(2).secs(), 1000.0, 1.0e-7, "Bin 2 stop time should be 1000.");
test_value(test1.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1.");
test_value(test1.tstop().secs(), 1000.0, 1.0e-7, "Stop time should be 1000.");
// Check saving in and loading from FITS file with specific extension
gti.save("test_gti2.fits[GTI_2]", true);
GGti test2("test_gti2.fits[GTI_2]");
test_value(test2.size(), 3, "GGti should have 3 intervals.");
test_value(test2.tstart(0).secs(), 1.0, 1.0e-7, "Bin 0 start time should be 1.");
test_value(test2.tstart(1).secs(), 10.0, 1.0e-7, "Bin 1 start time should be 10.");
test_value(test2.tstart(2).secs(), 100.0, 1.0e-7, "Bin 2 start time should be 100.");
test_value(test2.tstop(0).secs(), 10.0, 1.0e-7, "Bin 0 stop time should be 10.");
test_value(test2.tstop(1).secs(), 100.0, 1.0e-7, "Bin 1 stop time should be 100.");
test_value(test2.tstop(2).secs(), 1000.0, 1.0e-7, "Bin 2 stop time should be 1000.");
test_value(test2.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1.");
test_value(test2.tstop().secs(), 1000.0, 1.0e-7, "Stop time should be 1000.");
// Check reading from XML element using "tmin" and "tmax" format
GXmlElement element("observation");
element.append(GXmlElement("parameter name=\"GoodTimeIntervals\" tmin=\"0\" tmax=\"100.0\""));
element.append(GXmlElement("parameter name=\"TimeReference\" mjdrefi=\"51544\" mjdreff=\"0.5\" timeunit=\"s\" timesys=\"TT\" timeref=\"LOCAL\""));
GGti test3(element);
test_value(test3.size(), 1, "GGti should have 1 interval.");
test_value(test3.tstart(0).convert(GTimeReference(51544.5, "s")), 0.0, 1.0e-7, "Bin 0 start time should be 0.");
test_value(test3.tstop(0).convert(GTimeReference(51544.5, "s")), 100.0, 1.0e-7, "Bin 0 stop time should be 100.");
test_value(test3.tstart().convert(GTimeReference(51544.5, "s")), 0.0, 1.0e-7, "Start time should be 0.");
test_value(test3.tstop().convert(GTimeReference(51544.5, "s")), 100.0, 1.0e-7, "Stop time should be 100.");
// Check writing of GTI into XML element
element.clear();
test3.write(element);
const GXmlElement* par = gammalib::xml_get_par("test_GObservation", element, "GoodTimeIntervals");
test_value(gammalib::tofloat(par->attribute("tmin")), 0.0, 1.0e-7,
"Attribute tmin should be 0, found "+
par->attribute("tmin")+".");
test_value(gammalib::tofloat(par->attribute("tmax")), 100.0, 1.0e-7,
"Attribute tmax should be 100, found "+
par->attribute("tmax")+".");
par = gammalib::xml_get_par("test_GObservation", element, "TimeReference");
test_value(gammalib::tofloat(par->attribute("mjdrefi")), 51544.0, 1.0e-7,
"Attribute mjdrefi should be 51544, found "+
par->attribute("mjdrefi")+".");
test_value(gammalib::tofloat(par->attribute("mjdreff")), 0.5, 1.0e-7,
"Attribute mjdreff should be 0.5, found "+
par->attribute("mjdreff")+".");
test_assert(par->attribute("timeunit") == "s",
"Attribute timeunit should be \"s\", found "+
par->attribute("timeunit")+".");
test_assert(par->attribute("timesys") == "TT",
"Attribute timesys should be \"TT\", found "+
par->attribute("timesys")+".");
test_assert(par->attribute("timeref") == "LOCAL",
"Attribute timeref should be \"LOCAL\", found "+
par->attribute("timeref")+".");
// Check reading from XML element using "file" format
element = GXmlElement("observation");
element.append(GXmlElement("parameter name=\"GoodTimeIntervals\" file=\"test_gti2.fits[GTI_2]\""));
GGti test4(element);
test_value(test4.size(), 3, "GGti should have 3 intervals.");
test_value(test4.tstart(0).secs(), 1.0, 1.0e-7, "Bin 0 start time should be 1.");
test_value(test4.tstart(1).secs(), 10.0, 1.0e-7, "Bin 1 start time should be 10.");
test_value(test4.tstart(2).secs(), 100.0, 1.0e-7, "Bin 2 start time should be 100.");
test_value(test4.tstop(0).secs(), 10.0, 1.0e-7, "Bin 0 stop time should be 10.");
test_value(test4.tstop(1).secs(), 100.0, 1.0e-7, "Bin 1 stop time should be 100.");
test_value(test4.tstop(2).secs(), 1000.0, 1.0e-7, "Bin 2 stop time should be 1000.");
test_value(test4.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1.");
test_value(test4.tstop().secs(), 1000.0, 1.0e-7, "Stop time should be 1000.");
// Append one time interval to test change of GTI file
test4.append(GTime(1000.0), GTime(10000.0));
// Check writing of GTI into XML element
element.clear();
test4.write(element);
par = gammalib::xml_get_par("test_GObservation", element, "GoodTimeIntervals");
test_assert(par->attribute("file") == "test_gti2.fits[GTI_2]",
"Attribute file should be \"test_gti2.fits[GTI_2]\", found "+
par->attribute("file")+".");
GGti test5(par->attribute("file"));
test_value(test5.size(), 4, "GGti should have 4 intervals.");
test_value(test5.tstart(0).secs(), 1.0, 1.0e-7, "Bin 0 start time should be 1.");
test_value(test5.tstart(1).secs(), 10.0, 1.0e-7, "Bin 1 start time should be 10.");
test_value(test5.tstart(2).secs(), 100.0, 1.0e-7, "Bin 2 start time should be 100.");
test_value(test5.tstart(3).secs(), 1000.0, 1.0e-7, "Bin 3 start time should be 1000.");
test_value(test5.tstop(0).secs(), 10.0, 1.0e-7, "Bin 0 stop time should be 10.");
test_value(test5.tstop(1).secs(), 100.0, 1.0e-7, "Bin 1 stop time should be 100.");
test_value(test5.tstop(2).secs(), 1000.0, 1.0e-7, "Bin 2 stop time should be 1000.");
test_value(test5.tstop(3).secs(), 10000.0, 1.0e-7, "Bin 3 stop time should be 10000.");
test_value(test5.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1.");
test_value(test5.tstop().secs(), 10000.0, 1.0e-7, "Stop time should be 10000.");
// Remove test file
GFilename filename("test_gti.fits");
filename.remove();
// Check saving
test4.save("test_gti.fits");
GGti load1("test_gti.fits");
test_value(load1.size(), 4, "GGti should have 4 intervals.");
test_value(load1.tstart().secs(), 1.0, 1.0e-7, "Start time should be 1.");
test_value(load1.tstop().secs(), 10000.0, 1.0e-7, "Stop time should be 10000.");
// Check saving in a different extension
test3.save("test_gti.fits[GOOD TIME INTERVALS]", true);
GGti load2("test_gti.fits[GOOD TIME INTERVALS]");
test_value(load2.size(), 1, "GGti should have 1 interval.");
test_value(load2.tstart().convert(GTimeReference(51544.5, "s")), 0.0, 1.0e-7, "Start time should be 0.");
test_value(load2.tstop().convert(GTimeReference(51544.5, "s")), 100.0, 1.0e-7, "Stop time should be 100.");
// Check contains() method
GGti test6;
test6.append(GTime(2.0), GTime(3.0));
test6.append(GTime(5.0), GTime(7.0));
test6.append(GTime(10.0), GTime(20.0));
test_value(test6.size(), 3, "Check GGti::contains(): size=3");
test_value(test6.tstart().secs(), 2.0, 1.0e-7, "Check GGti::contains(): start=2");
test_value(test6.tstop().secs(), 20.0, 1.0e-7, "Check GGti::contains(): stop=20");
test_assert(!test6.contains(GTime(1.0)), "Check GGti::contains(): 1 is not contained");
test_assert(test6.contains(GTime(15.0)), "Check GGti::contains(): 15 is contained");
test_assert(test6.contains(GTime(20.0)), "Check GGti::contains(): 20 is contained");
test_assert(test6.contains(GTime(2.5)), "Check GGti::contains(): 2.5 is contained");
test_assert(test6.contains(GTime(20.0)), "Check GGti::contains(): 20 is still contained");
test_assert(test6.contains(GTime(6.0)), "Check GGti::contains(): 6 is contained");
test_assert(!test6.contains(GTime(8.0)), "Check GGti::contains(): 8 is not contained");
test_assert(!test6.contains(GTime(4.0)), "Check GGti::contains(): 4 is not contained");
// Return
return;
}
/***********************************************************************//**
* @brief Test GTimeReference
***************************************************************************/
void TestGObservation::test_time_reference(void)
{
// Test void constructor
test_try("Void constructor");
try {
GTimeReference reference;
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Test copy constructor
test_try("Copy constructor");
try {
GTimeReference reference;
GTimeReference reference2(reference);
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Test reference constructor
test_try("Reference constructor");
try {
GTimeReference reference(55197.0, "s", "TT", "LOCAL");
test_try_success();
test_value(reference.mjdref(), 55197.0);
test_assert(reference.timeunit() == "s",
"Time unit was \""+reference.timeunit()+"\", expected \"s\"");
test_assert(reference.timesys() == "TT",
"Time system was \""+reference.timesys()+"\", expected \"TT\"");
test_assert(reference.timeref() == "LOCAL",
"Time reference was \""+reference.timeref()+"\", expected \"LOCAL\"");
}
catch (std::exception &e) {
test_try_failure(e);
}
// Test reference constructor
test_try("Reference constructor (split reference)");
try {
GTimeReference reference(55197, 0.000766018518519, "s", "TT", "LOCAL");
test_try_success();
test_value(reference.mjdref(), 55197.000766018518519);
test_assert(reference.timeunit() == "s",
"Time unit was \""+reference.timeunit()+"\", expected \"s\"");
test_assert(reference.timesys() == "TT",
"Time system was \""+reference.timesys()+"\", expected \"TT\"");
test_assert(reference.timeref() == "LOCAL",
"Time reference was \""+reference.timeref()+"\", expected \"LOCAL\"");
}
catch (std::exception &e) {
test_try_failure(e);
}
// Test FITS file writing
GTimeReference reference(55197.000766018518519, "s", "TT", "LOCAL");
GFits fits;
GFitsBinTable table;
reference.write(table);
fits.append(table);
fits.saveto("test_time_reference.fits", true);
fits.close();
// Read back from FITS file and check values
fits.open("test_time_reference.fits");
const GFitsTable& hdu = *fits.table(1);
GTimeReference value(hdu);
fits.close();
test_value(value.mjdref(), reference.mjdref());
test_value(value.mjdrefi(), reference.mjdrefi());
test_value(value.mjdreff(), reference.mjdreff());
test_assert(value.timeunit() == reference.timeunit(),
"Time unit was \""+value.timeunit()+"\", expected "+reference.timeunit()+".");
test_assert(value.timesys() == reference.timesys(),
"Time system was \""+value.timesys()+"\", expected "+reference.timesys()+".");
test_assert(value.timeref() == reference.timeref(),
"Time reference was \""+value.timeref()+"\", expected "+reference.timeref()+".");
// Return
return;
}
/***********************************************************************//**
* @brief Test GTime
***************************************************************************/
void TestGObservation::test_time(void)
{
// Test void constructor
test_try("Void constructor");
try {
GTime time;
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Test copy constructor
test_try("Copy constructor");
try {
GTime time;
GTime time2(time);
test_try_success();
test_assert(time == time2, "Time differs after using copy constructor.");
}
catch (std::exception &e) {
test_try_failure(e);
}
// Test time constructor (seconds)
test_try("Time constructor (seconds)");
try {
GTime time(1800.01);
test_try_success();
test_value(time.secs(), 1800.01);
test_value(time.days(), 1800.01/86400.0);
}
catch (std::exception &e) {
test_try_failure(e);
}
// Test time constructor (days)
test_try("Time constructor (days)");
try {
GTime time(41.7, "days");
test_try_success();
test_value(time.days(), 41.7);
test_value(time.secs(), 41.7*86400.0);
}
catch (std::exception &e) {
test_try_failure(e);
}
// Test time constructor (string)
test_try("Time constructor (string)");
try {
GTime time("1800.01");
test_try_success();
test_value(time.secs(), 1800.01);
test_value(time.days(), 1800.01/86400.0);
}
catch (std::exception &e) {
test_try_failure(e);
}
// Test time access methods
// Reference times are from
// - http://heasarc.gsfc.nasa.gov/cgi-bin/Tools/xTime/xTime.pl
GTime time(123456.789);
test_value(time.jd(), 2455198.92966648);
test_value(time.jd("TT"), 2455198.92966648);
test_value(time.jd("TAI"), 2455198.92929398); // TAI=TT-0.0003725
test_value(time.jd("UTC"), 2455198.92890046);
test_value(time.mjd(), 55198.42966648);
test_value(time.mjd("TT"), 55198.42966648);
test_value(time.mjd("TAI"), 55198.42929398); // TAI=TT-0.0003725
test_value(time.mjd("UTC"), 55198.42890046);
test_value(time.secs(), 123456.789);
test_value(time.secs("TT"), 123456.789);
test_value(time.secs("TAI"), 123424.605); // TAI=TT-32.184
test_value(time.secs("UTC"), 123390.60487); // UTC=TT-66.184126
test_value(time.days(), 1.4288979);
test_value(time.days("TT"), 1.4288979);
test_value(time.days("TAI"), 1.4285254); // TAI=TT-0.0003725
test_value(time.days("UTC"), 1.42813188); // UTC=TT-0.00076602
test_assert(time.utc() == "2010-01-02T10:17:37",
"GTime::utc(): 2010-01-02T10:17:37 expected, "+
time.utc()+" found.");
// Test set method. The UTC conversion to MJD (TT) was done using xTime.
// Note that xTime missed a second for the "2006-01-01T00:00:00"
// conversion, hence I added the second by hand to the expected
// result
time.jd(57.9);
test_value(time.jd(), 57.9);
time.mjd(57.9);
test_value(time.mjd(), 57.9);
time.secs(57.9);
test_value(time.secs(), 57.9);
time.days(57.9);
test_value(time.days(), 57.9);
time.utc("1994-01-01T00:00:00");
test_value(time.utc(), "1994-01-01T00:00:00");
test_value(time.mjd(), 49353.00069657, 1.0e-6);
time.utc("1999-12-31T23:59:59");
test_value(time.utc(), "1999-12-31T23:59:59");
test_value(time.mjd(), 51544.00073130, 1.0e-6);
time.utc("2000-01-01T00:00:00");
test_value(time.utc(), "2000-01-01T00:00:00");
test_value(time.mjd(), 51544.00074287, 1.0e-6);
time.utc("2006-01-01T00:00:00");
test_value(time.utc(), "2006-01-01T00:00:00");
test_value(time.mjd(), 53736.0007544, 1.0e-6);
time.utc("2014-10-12T22:08:37");
test_value(time.utc(), "2014-10-12T22:08:37");
test_value(time.mjd(), 56942.92342806, 1.0e-6);
// Test Julian Day set method for various time systems
time.jd(2455198.92966648, "TT");
test_value(time.jd(), 2455198.92966648);
time.jd(2455198.92929398, "TAI");
test_value(time.jd(), 2455198.92966648);
time.jd(2455198.92890046, "UTC");
test_value(time.jd(), 2455198.92966648);
// Test Modified Julian Day set method for various time systems
time.mjd(55198.42966648, "TT");
test_value(time.mjd(), 55198.42966648);
time.mjd(55198.42929398, "TAI");
test_value(time.mjd(), 55198.42966648);
time.mjd(55198.42890046, "UTC");
test_value(time.mjd(), 55198.42966648);
// Test seconds set method for various time systems
time.secs(123456.789, "TT");
test_value(time.secs(), 123456.789);
time.secs(123424.605, "TAI");
test_value(time.secs(), 123456.789);
time.secs(123390.60487, "UTC");
test_value(time.secs(), 123456.789);
// Test days set method for various time systems
time.days(1.4288979, "TT");
test_value(time.days(), 1.4288979);
time.days(1.4285254, "TAI");
test_value(time.days(), 1.4288979);
time.days(1.42813188, "UTC");
test_value(time.days(), 1.4288979);
// Test convert method
double mjd_ref = 55197.000766018518519;
time.secs(123456.789);
test_value(time.convert(GTimeReference(mjd_ref, "days", "TT", "LOCAL")),
1.4288979);
test_value(time.convert(GTimeReference(mjd_ref, "days", "TAI", "LOCAL")),
1.4285254);
test_value(time.convert(GTimeReference(mjd_ref, "days", "UTC", "LOCAL")),
1.42813188);
test_value(time.convert(GTimeReference(0.0, "s", "TT", "LOCAL")),
123456.789 + mjd_ref*86400.0, 1.0e-6); //!< Poor precision on OpenSolaris
// Test set method
time.set(1.4288979, GTimeReference(mjd_ref, "days", "TT", "LOCAL"));
test_value(time.days(), 1.4288979);
time.set(1.4285254, GTimeReference(mjd_ref, "days", "TAI", "LOCAL"));
test_value(time.days(), 1.4288979);
time.set(1.42813188, GTimeReference(mjd_ref, "days", "UTC", "LOCAL"));
test_value(time.days(), 1.4288979);
time.set(12.3, GTimeReference(0.0, "secs", "TT", "LOCAL"));
test_value(time.secs(), 12.3 - mjd_ref*86400.0);
// Test time string set method
time.set("2005-10-08T14:30:25");
test_value(time.utc(), "2005-10-08T14:30:25");
time.set("123456.789");
test_value(time.secs(), 123456.789);
time.set("123456.789 (TT)");
test_value(time.secs(), 123456.789);
time.set("123424.605(TAI)");
test_value(time.secs(), 123456.789);
time.set("123390.60487(UTC)");
test_value(time.secs(), 123456.789);
time.set("MJD55198.42966648");
test_value(time.mjd(), 55198.42966648);
time.set("MJD 55198.42966648(TT)");
test_value(time.mjd(), 55198.42966648);
time.set("MJD 55198.42929398 (TAI)");
test_value(time.mjd(), 55198.42966648);
time.set("MJD 55198.42890046 (UTC)");
test_value(time.mjd(), 55198.42966648);
time.set("JD 2455198.92966648");
test_value(time.jd(), 2455198.92966648);
time.set("JD2455198.92966648(TT)");
test_value(time.jd(), 2455198.92966648);
time.set("JD 2455198.92929398 (TAI)");
test_value(time.jd(), 2455198.92966648);
time.set("JD 2455198.92890046 (UTC)");
test_value(time.jd(), 2455198.92966648);
// Test time string set method using reference system
time.set("123456.789", GTimeReference(mjd_ref, "secs", "TT", "LOCAL"));
test_value(time.days(), 1.4288979);
time.set("1.4288979", GTimeReference(mjd_ref, "days", "TT", "LOCAL"));
test_value(time.days(), 1.4288979);
time.set("1.4288979 (TT)", GTimeReference(mjd_ref, "days", "UTC", "LOCAL"));
test_value(time.days(), 1.4288979);
time.set("1.4285254 (TAI)", GTimeReference(mjd_ref, "days", "TT", "LOCAL"));
test_value(time.days(), 1.4288979);
time.set("1.42813188 (UTC)", GTimeReference(mjd_ref, "days", "TT", "LOCAL"));
test_value(time.days(), 1.4288979);
// Test conversion to different time systems
time.utc("2005-10-08T14:30:25");
test_value(time.convert(GTimeReference(0.0, "days", "TT", "LOCAL")),
53651.60519889, 1.0e-6);
test_value(time.convert(GTimeReference(0.0, "days", "UTC", "LOCAL")),
53651.60445602, 1.0e-6);
// Test setting to different time systems
time.set(53651.60519889, GTimeReference(0.0, "days", "TT", "LOCAL"));
test_value(time.utc(), "2005-10-08T14:30:25");
time.set(53651.60445602, GTimeReference(0.0, "days", "UTC", "LOCAL"));
test_value(time.utc(), "2005-10-08T14:30:25");
// Test now method (just test that it does not core dump; cannot really
// test the value :-)
time.now();
// Test gmst and gast methods. Precision is 1 second since the methods
// use UTC instead of UT1. Therefore use a precision of 2.777e-4 in
// the unit tests. The actual precision is even better (not sure why).
// References from http://dc.zah.uni-heidelberg.de/apfs/times/q/form
time.utc("1994-07-02T09:10:11"); // Largest UTC-UT1 difference
test_value(time.gmst(), 3.8483111, 2.777e-4);
test_value(time.gast(), 3.8485481, 2.777e-4);
test_value(time.lmst(123.456), 19.617911, 2.777e-4);
test_value(time.last(123.456), 19.618148, 2.777e-4);
time.utc("1997-11-11T11:11:11");
test_value(time.gmst(), 14.562163, 2.777e-4);
test_value(time.gast(), 14.562068, 2.777e-4);
test_value(time.lmst(123.456), 6.331763, 2.777e-4);
test_value(time.last(123.456), 6.331668, 2.777e-4);
time.utc("2008-10-04T10:30:23");
test_value(time.gmst(), 11.405402, 2.777e-4);
test_value(time.gast(), 11.405589, 2.777e-4);
test_value(time.lmst(123.456), 3.175002, 2.777e-4);
test_value(time.last(123.456), 3.175189, 2.777e-4);
time.utc("2016-02-29T23:59:59");
test_value(time.gmst(), 10.615045, 2.777e-4);
test_value(time.gast(), 10.615018, 2.777e-4);
test_value(time.lmst(123.456), 2.384645, 2.777e-4);
test_value(time.last(123.456), 2.384618, 2.777e-4);
// Test operators
GTime a(13.72);
GTime b(6.28);
test_value((a+6.28).secs(), 20.00, 1.0e-6, "Seconds right addition operator");
test_value((6.28+a).secs(), 20.00, 1.0e-6, "Seconds left addition operator");
test_value((a-6.28).secs(), 7.44, 1.0e-6, "Seconds substraction operator");
test_value((a-b), 7.44, 1.0e-6, "Time subtraction operator");
GTime c = a;
c += 6.28,
test_value(c.secs(), 20.00, 1.0e-6, "Seconds unary addition operator");
GTime d = a;
d -= 6.28,
test_value(d.secs(), 7.44, 1.0e-6, "Seconds unary subtraction operator");
test_assert(a == a, "Equality operator");
test_assert(a != b, "Non-equality operator");
test_assert(a > b, "Greater than operator");
test_assert(a >= b, "Greater than or equal operator");
test_assert(b < a, "Less than operator");
test_assert(b <= a, "Less than or equal operator");
// Return
return;
}
/***********************************************************************//**
* @brief Test GTimes
***************************************************************************/
void TestGObservation::test_times(void)
{
// Test void constructor
test_try("Void constructor");
try {
GTimes times;
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Manipulate GTimes starting from an empty object
GTimes times;
test_value(times.size(), 0, "GTimes should have zero size.");
test_assert(times.is_empty(), "GTimes should be empty.");
// Add a time
times.append(GTime());
test_value(times.size(), 1, "GTimes should have 1 time.");
test_assert(!times.is_empty(), "GTimes should not be empty.");
// Remove time
times.remove(0);
test_value(times.size(), 0, "GTimes should have zero size.");
test_assert(times.is_empty(), "GTimes should be empty.");
// Append two times
times.append(GTime());
times.append(GTime());
test_value(times.size(), 2, "GTimes should have 2 times.");
test_assert(!times.is_empty(), "GTimes should not be empty.");
// Clear object
times.clear();
test_value(times.size(), 0, "GTimes should have zero size.");
test_assert(times.is_empty(), "GTimes should be empty.");
// Insert two times
times.insert(0, GTime());
times.insert(0, GTime());
test_value(times.size(), 2, "GTimes should have 2 times.");
test_assert(!times.is_empty(), "GTimes should not be empty.");
// Extend times
times.extend(times);
test_value(times.size(), 4, "GTimes should have 4 times.");
test_assert(!times.is_empty(), "GTimes should not be empty.");
// Return
return;
}
/***********************************************************************//**
* @brief Test GEnergy class
***************************************************************************/
void TestGObservation::test_energy(void)
{
// Test void constructor
test_try("Void constructor");
try {
GEnergy energy;
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Test value constructors
GEnergy erg(3.0, "erg");
test_value(erg.erg(), 3.0, 1.0e-6, "GEnergy(erg) constructor");
GEnergy keV(3.0, "keV");
test_value(keV.keV(), 3.0, 1.0e-6, "GEnergy(keV) constructor");
GEnergy MeV(3.0, "MeV");
test_value(MeV.MeV(), 3.0, 1.0e-6, "GEnergy(MeV) constructor");
GEnergy GeV(3.0, "GeV");
test_value(GeV.GeV(), 3.0, 1.0e-6, "GEnergy(GeV) constructor");
GEnergy TeV(3.0, "TeV");
test_value(TeV.TeV(), 3.0, 1.0e-6, "GEnergy(TeV) constructor");
GEnergy Angstrom(3.0, "Angstrom");
test_value(Angstrom.Angstrom(), 3.0, 1.0e-6, "GEnergy(Angstrom) constructor");
// Test energy value access methods
test_value(MeV.erg(), 3.0/gammalib::erg2MeV, 1.0e-6, "erg() get method");
test_value(MeV.keV(), 3.0e+3, 1.0e-6, "keV() get method");
test_value(MeV.GeV(), 3.0e-3, 1.0e-6, "GeV() get method");
test_value(MeV.TeV(), 3.0e-6, 1.0e-6, "TeV() get method");
test_value(MeV.Angstrom(), gammalib::MeV2Angstrom/3.0, 1.0e-6, "Angstrom() get method");
test_value(MeV("erg"), 3.0/gammalib::erg2MeV, 1.0e-6, "(erg) get operator");
test_value(MeV("keV"), 3.0e+3, 1.0e-6, "(keV) get operator");
test_value(MeV("MeV"), 3.0, 1.0e-6, "(MeV) get operator");
test_value(MeV("GeV"), 3.0e-3, 1.0e-6, "(GeV) get operator");
test_value(MeV("TeV"), 3.0e-6, 1.0e-6, "(TeV) get operator");
test_value(MeV("Angstrom"), gammalib::MeV2Angstrom/3.0, 1.0e-6, "(Angstrom) get operator");
test_value(MeV.log10erg(), std::log10(3.0/gammalib::erg2MeV), 1.0e-6, "log10erg() get method");
test_value(MeV.log10keV(), std::log10(3.0e+3), 1.0e-6, "log10keV() get method");
test_value(MeV.log10MeV(), std::log10(3.0), 1.0e-6, "log10MeV() get method");
test_value(MeV.log10GeV(), std::log10(3.0e-3), 1.0e-6, "log10GeV() get method");
test_value(MeV.log10TeV(), std::log10(3.0e-6), 1.0e-6, "log10TeV() get method");
test_value(MeV.log10("erg"), std::log10(3.0/gammalib::erg2MeV), 1.0e-6, "log10(erg) get method");
test_value(MeV.log10("keV"), std::log10(3.0e+3), 1.0e-6, "log10(keV) get method");
test_value(MeV.log10("MeV"), std::log10(3.0), 1.0e-6, "log10(MeV) get method");
test_value(MeV.log10("GeV"), std::log10(3.0e-3), 1.0e-6, "log10(GeV) get method");
test_value(MeV.log10("TeV"), std::log10(3.0e-6), 1.0e-6, "log10(TeV) get method");
// Test value set methods
GEnergy energy;
energy.erg(3.0);
test_value(energy.erg(), 3.0, 1.0e-6, "erg() set method");
energy.keV(3.0);
test_value(energy.keV(), 3.0, 1.0e-6, "keV() set method");
energy.MeV(3.0);
test_value(energy.MeV(), 3.0, 1.0e-6, "MeV() set method");
energy.GeV(3.0);
test_value(energy.GeV(), 3.0, 1.0e-6, "GeV() set method");
energy.TeV(3.0);
test_value(energy.TeV(), 3.0, 1.0e-6, "TeV() set method");
energy.Angstrom(3.0);
test_value(energy.Angstrom(), 3.0, 1.0e-6, "Angstrom() set method");
energy(3.0, "erg");
test_value(energy.erg(), 3.0, 1.0e-6, "(erg) set operator");
energy(3.0, "keV");
test_value(energy.keV(), 3.0, 1.0e-6, "(keV) set method");
energy(3.0, "MeV");
test_value(energy.MeV(), 3.0, 1.0e-6, "(MeV) set method");
energy(3.0, "GeV");
test_value(energy.GeV(), 3.0, 1.0e-6, "(GeV) set method");
energy(3.0, "TeV");
test_value(energy.TeV(), 3.0, 1.0e-6, "(TeV) set method");
energy(3.0, "Angstrom");
test_value(energy.Angstrom(), 3.0, 1.0e-6, "(Angstrom) set method");
energy.log10erg(std::log10(3.0));
test_value(energy.erg(), 3.0, 1.0e-6, "log10erg() set method");
energy.log10keV(std::log10(3.0));
test_value(energy.keV(), 3.0, 1.0e-6, "log10keV() set method");
energy.log10MeV(std::log10(3.0));
test_value(energy.MeV(), 3.0, 1.0e-6, "log10MeV() set method");
energy.log10GeV(std::log10(3.0));
test_value(energy.GeV(), 3.0, 1.0e-6, "log10GeV() set method");
energy.log10TeV(std::log10(3.0));
test_value(energy.TeV(), 3.0, 1.0e-6, "log10TeV() set method");
energy.log10(std::log10(3.0), "erg");
test_value(energy.erg(), 3.0, 1.0e-6, "log10(erg) set method");
energy.log10(std::log10(3.0), "keV");
test_value(energy.keV(), 3.0, 1.0e-6, "log10(keV) set method");
energy.log10(std::log10(3.0), "MeV");
test_value(energy.MeV(), 3.0, 1.0e-6, "log10(MeV) set method");
energy.log10(std::log10(3.0), "GeV");
test_value(energy.GeV(), 3.0, 1.0e-6, "log10(GeV) set method");
energy.log10(std::log10(3.0), "TeV");
test_value(energy.TeV(), 3.0, 1.0e-6, "log10(TeV) set method");
// Test operators
double va = 2.1;
double vb = 3.7;
GEnergy a(va, "MeV");
GEnergy b(vb, "MeV");
GEnergy test = a + b;
test_value(test.MeV(), va+vb, 1.0e-6, "operator+");
test = a - b;
test_value(test.MeV(), va-vb, 1.0e-6, "operator-");
test = a * 2.9;
test_value(test.MeV(), va*2.9, 1.0e-6, "operator*");
test = 2.8 * a;
test_value(test.MeV(), 2.8*va, 1.0e-6, "operator*");
test = a / 3.7;
test_value(test.MeV(), va/3.7, 1.0e-6, "operator*");
test = a;
test += b;
test_value(test.MeV(), va+vb, 1.0e-6, "operator+=");
test = a;
test -= b;
test_value(test.MeV(), va-vb, 1.0e-6, "operator-=");
test_assert((a == a), "operator== (equal values)");
test_assert(!(a == b), "operator== (non equal values)");
test_assert(!(a != a), "operator!= (equal values)");
test_assert((a != b), "operator!= (non equal values)");
test_assert((a < b), "less than operator");
test_assert(!(b < a), "less than operator");
test_assert(!(a > b), "larger than operator");
test_assert((b > a), "larger than operator");
test_assert((a <= a), "less or equal operator");
test_assert((a <= b), "less or equal operator");
test_assert(!(b <= a), "less or equal operator");
test_assert((a >= a), "larger or equal operator");
test_assert(!(a >= b), "larger or equal operator");
test_assert((b >= a), "larger or equal operator");
// Return
return;
}
/***********************************************************************//**
* @brief Test GEnergies
***************************************************************************/
void TestGObservation::test_energies(void)
{
// Test void constructor
test_try("Void constructor");
try {
GEnergies energies;
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Manipulate GEnergies starting from an empty object
GEnergies energies;
test_value(energies.size(), 0, "GEnergies should have zero size.");
test_assert(energies.is_empty(), "GEnergies should be empty.");
// Add an energy
energies.append(GEnergy());
test_value(energies.size(), 1, "GEnergies should have 1 energy.");
test_assert(!energies.is_empty(), "GEnergies should not be empty.");
// Remove energy
energies.remove(0);
test_value(energies.size(), 0, "GEnergies should have zero size.");
test_assert(energies.is_empty(), "GEnergies should be empty.");
// Append two energies
energies.append(GEnergy());
energies.append(GEnergy());
test_value(energies.size(), 2, "GEnergies should have 2 energies.");
test_assert(!energies.is_empty(), "GEnergies should not be empty.");
// Clear object
energies.clear();
test_value(energies.size(), 0, "GEnergies should have zero size.");
test_assert(energies.is_empty(), "GEnergies should be empty.");
// Insert two energies
energies.insert(0, GEnergy());
energies.insert(0, GEnergy());
test_value(energies.size(), 2, "GEnergies should have 2 energies.");
test_assert(!energies.is_empty(), "GEnergies should not be empty.");
// Extend energies
energies.extend(energies);
test_value(energies.size(), 4, "GEnergies should have 4 energies.");
test_assert(!energies.is_empty(), "GEnergies should not be empty.");
// Create 4 energies
energies.clear();
for (int i = 0; i < 4; ++i) {
energies.append(GEnergy(double(i), "MeV"));
}
for (int i = 0; i < 4; ++i) {
test_value(energies[i].MeV(), double(i));
}
// Remove test file
GFilename filename("test_energies.fits");
filename.remove();
// Save and reload energies
test_try("Saving and loading");
try {
energies.save("test_energies.fits", true);
energies.clear();
energies.load("test_energies.fits");
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
for (int i = 0; i < 4; ++i) {
test_value(energies[i].MeV(), double(i));
}
// Test load constructor
test_try("Load constructor");
try {
GEnergies energies2("test_energies.fits");
for (int i = 0; i < 4; ++i) {
test_value(energies[i].MeV(), double(i));
}
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Save and reload energies in another extension
test_try("Saving and loading in another extension");
try {
energies.save("test_energies.fits[NEW ENERGIES]", true);
energies.clear();
energies.load("test_energies.fits[NEW ENERGIES]");
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
for (int i = 0; i < 4; ++i) {
test_value(energies[i].MeV(), double(i));
}
// Check linear energies
energies.clear();
energies.set_lin(3, GEnergy(1.0, "MeV"), GEnergy(3.0, "MeV"));
test_value(energies.size(), 3, "GEnergies should have 3 elements.");
test_assert(!energies.is_empty(), "GEnergies should not be empty.");
test_value(energies[0].MeV(), 1.0, 1.0e-10, "Energy 0 should be 1 MeV.");
test_value(energies[1].MeV(), 2.0, 1.0e-10, "Energy 1 should be 2 MeV.");
test_value(energies[2].MeV(), 3.0, 1.0e-10, "Energy 3 should be 3 MeV.");
// Check logarithmic energies
energies.clear();
energies.set_log(3, GEnergy(1.0, "MeV"), GEnergy(100.0, "MeV"));
test_value(energies.size(), 3, "GEnergies should have 3 elements.");
test_assert(!energies.is_empty(), "GEnergies should not be empty.");
test_value(energies[0].MeV(), 1.0, 1.0e-10, "Energy 0 should be 1 MeV.");
test_value(energies[1].MeV(), 10.0, 1.0e-10, "Energy 1 should be 10 MeV.");
test_value(energies[2].MeV(), 100.0, 1.0e-10, "Energy 2 should be 100 MeV.");
// Check energy boundary set method
GEbounds ebds1(2, GEnergy(1.0, "MeV"), GEnergy(3.0, "MeV"), false);
energies.set(ebds1);
test_value(energies.size(), 3, "GEbounds constructor (3 elements)");
test_value(energies[0].MeV(), 1.0, 1.0e-10, "GEbounds constructor (3 elements)");
test_value(energies[1].MeV(), 2.0, 1.0e-10, "GEbounds constructor (3 elements)");
test_value(energies[2].MeV(), 3.0, 1.0e-10, "GEbounds constructor (3 elements)");
// Check energy boundary set method
GEbounds ebds2(1, GEnergy(1.0, "MeV"), GEnergy(1.0, "MeV"));
energies.set(ebds2);
test_value(energies.size(), 1, "GEbounds constructor (1 element)");
test_value(energies[0].MeV(), 1.0, 1.0e-10, "GEbounds constructor (1 element)");
// Return
return;
}
/***********************************************************************//**
* @brief Test GPhotons
***************************************************************************/
void TestGObservation::test_photons(void)
{
// Test void constructor
test_try("Void constructor");
try {
GPhotons photons;
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Manipulate GPhotons starting from an empty object
GPhotons photons;
test_value(photons.size(), 0, "GPhotons should have zero size.");
test_assert(photons.is_empty(), "GPhotons should be empty.");
// Add one photon
photons.append(GPhoton());
test_value(photons.size(), 1, "GPhotons should have 1 photon.");
test_assert(!photons.is_empty(), "GPhotons should not be empty.");
// Remove photon
photons.remove(0);
test_value(photons.size(), 0, "GPhotons should have zero size.");
test_assert(photons.is_empty(), "GPhotons should be empty.");
// Append two photons
photons.append(GPhoton());
photons.append(GPhoton());
test_value(photons.size(), 2, "GPhotons should have 2 photons.");
test_assert(!photons.is_empty(), "GPhotons should not be empty.");
// Clear object
photons.clear();
test_value(photons.size(), 0, "GPhotons should have zero size.");
test_assert(photons.is_empty(), "GPhotons should be empty.");
// Insert two photons
photons.insert(0, GPhoton());
photons.insert(0, GPhoton());
test_value(photons.size(), 2, "GPhotons should have 2 photons.");
test_assert(!photons.is_empty(), "GPhotons should not be empty.");
// Extend photons
photons.extend(photons);
test_value(photons.size(), 4, "GPhotons should have 4 photons.");
test_assert(!photons.is_empty(), "GPhotons should not be empty.");
// Return
return;
}
/***********************************************************************//**
* @brief Test GPhases
***************************************************************************/
void TestGObservation::test_phases(void)
{
// Test void constructor
test_try("Void constructor");
try {
GPhases phases;
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Manipulate GPhases starting from an empty object
GPhases phases;
test_value(phases.size(), 0);
test_assert(phases.is_empty(), "Test for empty GPhases object");
// Add one phase interval
phases.append(0.3, 0.5);
test_value(phases.size(), 1);
test_value(phases.pmin(0), 0.3);
test_value(phases.pmax(0), 0.5);
test_assert(!phases.is_empty(), "Test for non-empty GPhases object");
// Remove phase interval
phases.remove(0);
test_value(phases.size(), 0);
test_assert(phases.is_empty(), "Test for empty GPhases object");
// Append two phase intervals
phases.append(0.3, 0.5);
phases.append(0.4, 0.7);
test_value(phases.pmin(0), 0.3);
test_value(phases.pmax(0), 0.5);
test_value(phases.pmin(1), 0.4);
test_value(phases.pmax(1), 0.7);
test_value(phases.size(), 2);
test_assert(!phases.is_empty(), "Test for non-empty GPhases object");
// Copy phase intervals
GPhases phases2(phases);
test_value(phases2.pmin(0), 0.3);
test_value(phases2.pmax(0), 0.5);
test_value(phases2.pmin(1), 0.4);
test_value(phases2.pmax(1), 0.7);
test_value(phases2.size(), 2);
test_assert(!phases2.is_empty(), "Test for non-empty GPhases object");
// Clear object
phases.clear();
test_value(phases.size(), 0);
test_assert(phases.is_empty(), "Test for empty GPhases object");
// Extend photons
phases.append(0.3, 0.5);
phases.append(0.4, 0.7);
phases.extend(phases);
test_value(phases.size(), 4);
test_assert(!phases.is_empty(), "Test for non-empty GPhases object");
// Return
return;
}
/***********************************************************************//**
* @brief Test GObservations::likelihood
***************************************************************************/
void TestGObservation::test_observations_optimizer(void)
{
// Create Test Model
GTestModelData model;
// Create Models conteners
GModels models;
models.append(model);
// Time iterval
GTime tmin(0.0);
GTime tmax(1800.0);
// Rate : events/sec
double rate = RATE;
// Create observations
GObservations obs;
// Add observations to container
for (int i = 0; i < 6; ++i) {
// Set random Generator
GRan ran(i);
// Create an event list
GEvents *events = model.generateList(rate, tmin, tmax, ran);
// Create a observation
GTestObservation observation;
observation.id(gammalib::str(i));
// Add events to the observation
observation.events(*events);
observation.ontime(tmax.secs()-tmin.secs());
// Append observation to container
obs.append(observation);
// Free the event list
delete events;
} // endfor: added observations to container
// Add the model to the observation
obs.models(models);
// Create a GLog for show the interations of optimizer.
GLog log;
// Create an optimizer.
GOptimizerLM opt(&log);
// Set number of stalls
opt.max_stalls(50);
// Optimize
obs.optimize(opt);
// Compute errors
obs.errors(opt);
// Get the result
GModelPar result = (*(obs.models()[0]))[0];
// Check if converged
test_value(opt.status(), 0, "Check if converged",
"Optimizer did not converge");
// Check if value is correct
test_value(result.factor_value(), RATE, result.factor_error()*3.0);
// Save covariance matrix as FITS file
obs.function().save("test_observations_optimizer.fits");
// Try loading covariance matrix as FITS file
test_try("Load covariance matrix as FITS file");
try {
GFits file("test_observations_optimizer.fits");
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Save covariance matrix as CSV file
obs.function().save("test_observations_optimizer.csv");
// Try loading covariance matrix as CSV file
test_try("Load covariance matrix as CSV file");
try {
GCsv file("test_observations_optimizer.csv");
test_try_success();
}
catch (std::exception &e) {
test_try_failure(e);
}
// Return
return;
}
#ifdef _OPENMP
/***********************************************************************//**
* @brief Set tests
***************************************************************************/
void TestOpenMP::set(void)
{
// Set test name
name("OpenMP");
// Append unbinned tests
append(static_cast(&TestOpenMP::test_observations_optimizer_unbinned_1), "Test unbinned optimization (1 thread)");
append(static_cast(&TestOpenMP::test_observations_optimizer_unbinned_10), "Test unbinned optimization (10 threads)");
// Append binned tests
append(static_cast(&TestOpenMP::test_observations_optimizer_binned_1), "Test binned optimization (1 thread)");
append(static_cast(&TestOpenMP::test_observations_optimizer_binned_10), "Test binned optimisation (10 threads)");
// Return
return;
}
/***********************************************************************//**
* @brief Clone test suite
*
* @return Pointer to deep copy of test suite.
***************************************************************************/
TestOpenMP* TestOpenMP::clone(void) const
{
// Clone test suite
return new TestOpenMP(*this);
}
/***********************************************************************//**
* @brief Test observations optimizer.
*
* @param[in] mode Testing mode.
*
* This method supports two testing modes: 0 = unbinned and 1 = binned.
***************************************************************************/
void TestOpenMP::test_observations_optimizer(const int& mode)
{
// Create Test Model
GTestModelData model;
// Create Models conteners
GModels models;
models.append(model);
// Time iterval
GTime tmin(0.0);
GTime tmax(1800.0);
// Rate : events/sec
double rate = RATE;
// Create observations
GObservations obs;
// Add some observation
for (int i = 0; i < 6; ++i) {
// Random Generator
GRan ran;
ran.seed(i);
// Allocate events pointer
GEvents *events;
// Create either a event list or an event cube
if (mode == UN_BINNED) {
events = model.generateList(rate,tmin,tmax,ran);
}
else {
events = model.generateCube(rate,tmin,tmax,ran);
}
// Create an observation
GTestObservation ob;
ob.id(gammalib::str(i));
// Add events to the observation
ob.events(*events);
ob.ontime(tmax.secs()-tmin.secs());
obs.append(ob);
// Delete events pointer
delete events;
}
// Add the model to the observation
obs.models(models);
// Create a GLog for show the interations of optimizer.
GLog log;
// Create an optimizer.
GOptimizerLM opt(&log);
// Set number of stalls
opt.max_stalls(50);
// Optimize
obs.optimize(opt);
// Compute errors
obs.errors(opt);
// Get the result
GModelPar result = (*(obs.models()[0]))[0];
// Check if converged
test_assert(opt.status()==0, "Check if converged",
"Optimizer did not converge");
// Check if value is correct
test_value(result.factor_value(),RATE,result.factor_error()*3);
// Return
return;
}
/***********************************************************************//**
* @brief Test optimizer with unbinned events and 1 thread
***************************************************************************/
void TestOpenMP::test_observations_optimizer_unbinned_1(void)
{
// Test with 1 thread
omp_set_num_threads(1);
test_observations_optimizer(UN_BINNED);
// Return
return;
}
/***********************************************************************//**
* @brief Test optimizer with unbinned events and 10 thread
***************************************************************************/
void TestOpenMP::test_observations_optimizer_unbinned_10(void)
{
// Test with 10 threads
omp_set_num_threads(10);
test_observations_optimizer(UN_BINNED);
// Return
return;
}
/***********************************************************************//**
* @brief Test optimizer with binned events and 1 thread
***************************************************************************/
void TestOpenMP::test_observations_optimizer_binned_1(void)
{
// Test with 1 thread
omp_set_num_threads(1);
test_observations_optimizer(BINNED);
// Return
return;
}
/***********************************************************************//**
* @brief Test optimizer with binned events and 10 threads
***************************************************************************/
void TestOpenMP::test_observations_optimizer_binned_10(void)
{
// Test with 10 threads
omp_set_num_threads(10);
test_observations_optimizer(BINNED);
// Return
return;
}
#endif
/***************************************************************************
* @brief Main entry point for test executable
***************************************************************************/
int main(void)
{
// Allocate test suit container
GTestSuites testsuites("Observation module");
// Initially assume that we pass all tests
bool success = true;
// Create and append test suites
TestGObservation obs;
testsuites.append(obs);
// Create and append OpenMP test suite
#ifdef _OPENMP
TestOpenMP openmp;
testsuites.append(openmp);
#endif
// Run the testsuites
success = testsuites.run();
// Save test report
testsuites.save("reports/GObservation.xml");
// Return success status
return (success ? 0 : 1);
}