/***************************************************************************
* GCTACubeSourceDiffuse.cpp - CTA cube analysis diffuse source class *
* ----------------------------------------------------------------------- *
* copyright (C) 2014-2015 by Juergen Knoedlseder *
* ----------------------------------------------------------------------- *
* *
* 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 GCTACubeSourceDiffuse.cpp
* @brief CTA cube analysis diffuse source class implementation
* @author Juergen Knoedlseder
*/
/* __ Includes ___________________________________________________________ */
#ifdef HAVE_CONFIG_H
#include
#endif
#include "GTools.hpp"
#include "GCTACubeSourceDiffuse.hpp"
#include "GModelSpatialDiffuse.hpp"
#include "GObservation.hpp"
#include "GSkyDir.hpp"
#include "GEnergy.hpp"
#include "GTime.hpp"
#include "GIntegral.hpp"
#include "GCTAEventCube.hpp"
#include "GCTAResponseCube.hpp"
#include "GCTAResponse_helpers.hpp"
/* __ OpenMP section _____________________________________________________ */
#ifdef _OPENMP
#include
#endif
/* __ Method name definitions ____________________________________________ */
#define G_SET "GCTACubeSourceDiffuse::set(GModelSpatial&, GObservation&)"
/* __ Macros _____________________________________________________________ */
/* __ Coding definitions _________________________________________________ */
#define G_PSF_INTEGRATE //!< Integrate map over PSF (default)
/* __ Debug definitions __________________________________________________ */
//#define G_DEBUG_SET
/* __ Constants __________________________________________________________ */
/*==========================================================================
= =
= Constructors/destructors =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Void constructor
***************************************************************************/
GCTACubeSourceDiffuse::GCTACubeSourceDiffuse(void) : GCTACubeSource()
{
// Initialise class members
init_members();
// Return
return;
}
/***********************************************************************//**
* @brief Copy constructor
*
* @param[in] source Diffuse source cube.
***************************************************************************/
GCTACubeSourceDiffuse::GCTACubeSourceDiffuse(const GCTACubeSourceDiffuse& source) :
GCTACubeSource(source)
{
// Initialise class members
init_members();
// Copy members
copy_members(source);
// Return
return;
}
/***********************************************************************//**
* @brief Destructor
***************************************************************************/
GCTACubeSourceDiffuse::~GCTACubeSourceDiffuse(void)
{
// Free members
free_members();
// Return
return;
}
/*==========================================================================
= =
= Operators =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Assignment operator
*
* @param[in] source Diffuse source cube.
* @return Diffuse source cube.
***************************************************************************/
GCTACubeSourceDiffuse& GCTACubeSourceDiffuse::operator=(const GCTACubeSourceDiffuse& source)
{
// Execute only if object is not identical
if (this != &source) {
// Copy base class members
this->GCTACubeSource::operator=(source);
// Free members
free_members();
// Initialise private members
init_members();
// Copy members
copy_members(source);
} // endif: object was not identical
// Return this object
return *this;
}
/*==========================================================================
= =
= Public methods =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Clear instance
*
* This method properly resets the object to an initial state.
***************************************************************************/
void GCTACubeSourceDiffuse::clear(void)
{
// Free class members
free_members();
this->GCTACubeSource::free_members();
// Initialise members
this->GCTACubeSource::init_members();
init_members();
// Return
return;
}
/***********************************************************************//**
* @brief Clone instance
*
* @return Deep copy of diffuse source cube.
***************************************************************************/
GCTACubeSourceDiffuse* GCTACubeSourceDiffuse::clone(void) const
{
// Return deep copy
return new GCTACubeSourceDiffuse(*this);
}
/***********************************************************************//**
* @brief Set diffuse source cube for a given observation
*
* @param[in] name Model name.
* @param[in] model Spatial model.
* @param[in] obs Observation.
*
* Sets the diffuse source cube assuming no energy dispersion and assuming
* a negligible variation of the effective area over the size of the
* point spread function.
***************************************************************************/
void GCTACubeSourceDiffuse::set(const std::string& name,
const GModelSpatial& model,
const GObservation& obs)
{
// Debug option: initialise statistics
#if defined(G_DEBUG_SET)
int n_pixels_computed = 0;
std::cout << "GCTACubeSourceDiffuse::set entred." << std::endl;
#ifdef _OPENMP
double t_start = omp_get_wtime();
#else
clock_t t_start = clock();
#endif
#endif
// Get pointer on CTA event cube
const GCTAEventCube* cube = dynamic_cast(obs.events());
if (cube == NULL) {
std::string msg = "Observation does not contain a CTA event cube.";
throw GException::invalid_value(G_SET, msg);
}
// Get pointer on CTA response cube
const GCTAResponseCube* rsp = dynamic_cast(obs.response());
if (rsp == NULL) {
std::string msg = "Observation does not contain a CTA response cube.";
throw GException::invalid_value(G_SET, msg);
}
// Get diffuse source attributes
m_name = name;
GTime obsTime = cube->time();
// Setup empty skymap
m_cube = cube->map();
m_cube = 0.0;
// Loop over all spatial bins
for (int pixel = 0; pixel < cube->npix(); ++pixel) {
// Get cube pixel sky direction
GSkyDir obsDir = cube->map().inx2dir(pixel);
// Loop over all energy layers
for (int iebin = 0; iebin < cube->ebins(); ++iebin) {
// Get cube layer energy
const GEnergy& obsEng = cube->energy(iebin);
// Determine exposure. We assume here that the exposure does
// not vary significantly over the PSF and just compute it at
// the pixel centre. We furthermore assume no energy dispersion,
// and thus compute exposure using the observed energy.
double aeff = rsp->exposure()(obsDir, obsEng);
// Continue only if effective area is positive
if (aeff > 0.0) {
// Revover effective area from exposure
aeff /= obs.livetime();
// Compute product of PSF and diffuse map, integrated
// over the relevant PSF area. We assume no energy
// dispersion and thus compute the product using the
// observed energy.
#if defined(G_PSF_INTEGRATE)
double psf = this->psf(rsp, &model, obsDir, obsEng, obsTime);
#else
double psf = model.eval(GPhoton(obsDir, obsEng, obsTime));
#endif
// Set cube value
m_cube(pixel, iebin) = aeff * psf * obs.deadc(obsTime);
} // endif: effective area was positive
} // endfor: looped over all energy layers
// Debug option: update statistics
#if defined(G_DEBUG_SET)
n_pixels_computed++;
#endif
} // endfor: looped over all spatial pixels
// Debug option: show statistics
#if defined(G_DEBUG_SET)
#ifdef _OPENMP
double t_elapse = omp_get_wtime()-t_start;
#else
double t_elapse = (double)(clock() - t_start) / (double)CLOCKS_PER_SEC;
#endif
std::cout << " Maximum theta ................: " << theta_max << " radians" << std::endl;
std::cout << " Number of spatial pixels used : " << n_pixels_computed << std::endl;
std::cout << " CPU usage ....................: " << t_elapse << " sec" << std::endl;
std::cout << "GCTACubeSourceDiffuse::set exit." << std::endl;
#endif
// Return
return;
}
/***********************************************************************//**
* @brief Integrate PSF over diffuse model
*
* @param[in] rsp Response function.
* @param[in] model Diffuse spatial model.
* @param[in] obsDir Observed event direction.
* @param[in] srcEng True photon energy.
* @param[in] srcTime True photon arrival time.
*
* Computes the integral
*
* \f[
* \int_0^{\delta_{\rm max}}
* {\rm PSF}(\delta) \times
* \int_0^{2\pi} {\rm Map}(\delta, \phi) \sin \delta
* {\rm d}\phi {\rm d}\delta
* \f]
*
* where \f${\rm Map}(\delta, \phi)\f$ is the diffuse map in the coordinate
* system of the point spread function, defined by the angle \f$\delta\f$
* between the true and the measured photon direction and the azimuth angle
* \f$\phi\f$ around the measured photon direction.
* \f${\rm PSF}(\delta)\f$ is the azimuthally symmetric point spread
* function.
***************************************************************************/
double GCTACubeSourceDiffuse::psf(const GCTAResponseCube* rsp,
const GModelSpatial* model,
const GSkyDir& obsDir,
const GEnergy& srcEng,
const GTime& srcTime) const
{
// Set integration precision and Romberg order. These values have been
// determined after careful testing, see
// https://cta-redmine.irap.omp.eu/issues/1291
const double eps_delta = 1.0e-2;
const int order_delta = 5;
const double eps_phi = 1.0e-2;
const int order_phi = 5;
// Initialise PSF
double psf = 0.0;
// Compute rotation matrix to convert from PSF centred coordinate system
// spanned by delta and phi into the reference frame of the observed
// arrival direction given in Right Ascension and Declination.
GMatrix ry;
GMatrix rz;
ry.eulery(obsDir.dec_deg() - 90.0);
rz.eulerz(-obsDir.ra_deg());
GMatrix rot = (ry * rz).transpose();
// Get offset angle integration interval in radians
double delta_min = 0.0;
double delta_max = 1.1 * rsp->psf().delta_max();
// Setup integration kernel. We take here the observed photon arrival
// direction as the true photon arrival direction because the PSF does
// not vary significantly over a small region.
cta_psf_diffuse_kern_delta integrand(rsp, model, obsDir, srcEng, srcTime,
rot, eps_phi, order_phi);
// Integrate over PSF delta angle
GIntegral integral(&integrand);
integral.eps(eps_delta);
psf = integral.romberg(delta_min, delta_max, order_delta);
// Return PSF
return psf;
}
/***********************************************************************//**
* @brief Print diffuse source cube information
*
* @param[in] chatter Chattiness (defaults to NORMAL).
* @return String containing diffuse source cube information.
***************************************************************************/
std::string GCTACubeSourceDiffuse::print(const GChatter& chatter) const
{
// Initialise result string
std::string result;
// Continue only if chatter is not silent
if (chatter != SILENT) {
// Append header
result.append("=== GCTACubeSourceDiffuse ===");
result.append("\n"+gammalib::parformat("Source name") + name());
} // endif: chatter was not silent
// Return result
return result;
}
/*==========================================================================
= =
= Private methods =
= =
==========================================================================*/
/***********************************************************************//**
* @brief Initialise class members
***************************************************************************/
void GCTACubeSourceDiffuse::init_members(void)
{
// Initialise members
m_cube.clear();
// Return
return;
}
/***********************************************************************//**
* @brief Copy class members
*
* @param[in] source Point diffuse cube.
***************************************************************************/
void GCTACubeSourceDiffuse::copy_members(const GCTACubeSourceDiffuse& source)
{
// Copy members
m_cube = source.m_cube;
// Return
return;
}
/***********************************************************************//**
* @brief Delete class members
***************************************************************************/
void GCTACubeSourceDiffuse::free_members(void)
{
// Return
return;
}