/***********************************************************************//** * @brief Print response information * * @param[in] chatter Chattiness (defaults to NORMAL). * @return String containing response information. ***************************************************************************/ std::string GCTAResponseCube::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("=== GCTAResponseCube ==="); // Append response information result.append("\n"+gammalib::parformat("Energy dispersion")); if (use_edisp()) { result.append("Used"); } else { if (apply_edisp()) { result.append("Not available"); } else { result.append("Not used"); } } // Append exposure cube information result.append("\n"+m_exposure.print(chatter)); // Append point spread function information result.append("\n"+m_psf.print(chatter)); // Append background information result.append("\n"+m_background.print(chatter)); } // endif: chatter was not silent // Return result return result; }
/***********************************************************************//** * @brief Convolve sky model with the instrument response * * @param[in] model Sky model. * @param[in] event Event. * @param[in] obs Observation. * @param[in] grad Should model gradients be computed? (default: true) * @return Event probability. * * Computes the event probability * * \f[ * P(p',E',t') = \int \int \int * S(p,E,t) \times R(p',E',t'|p,E,t) \, dp \, dE \, dt * \f] * * without taking into account any time dispersion. Energy dispersion is * correctly handled by this method. If time dispersion is indeed needed, * an instrument specific method needs to be provided. ***************************************************************************/ double GResponse::convolve(const GModelSky& model, const GEvent& event, const GObservation& obs, const bool& grad) const { // Set number of iterations for Romberg integration. static const int iter = 6; // Initialise result double prob = 0.0; // Continue only if the model has a spatial component if (model.spatial() != NULL) { // Get source time (no dispersion) GTime srcTime = event.time(); // Case A: Integration if (use_edisp()) { // Retrieve true energy boundaries GEbounds ebounds = this->ebounds(event.energy()); // Loop over all boundaries for (int i = 0; i < ebounds.size(); ++i) { // Get boundaries in MeV double emin = ebounds.emin(i).MeV(); double emax = ebounds.emax(i).MeV(); // Continue only if valid if (emax > emin) { // Setup integration function edisp_kern integrand(this, &obs, &model, &event, srcTime, grad); GIntegral integral(&integrand); // Set number of iterations integral.fixed_iter(iter); // Do Romberg integration emin = std::log(emin); emax = std::log(emax); prob += integral.romberg(emin, emax); } // endif: interval was valid } // endfor: looped over intervals } // Case B: No integration (assume no energy dispersion) else { // Get source energy (no dispersion) GEnergy srcEng = event.energy(); // Evaluate probability prob = eval_prob(model, event, srcEng, srcTime, obs, grad); } // Compile option: Check for NaN/Inf #if defined(G_NAN_CHECK) if (gammalib::is_notanumber(prob) || gammalib::is_infinite(prob)) { std::cout << "*** ERROR: GResponse::convolve:"; std::cout << " NaN/Inf encountered"; std::cout << " (prob=" << prob; std::cout << ", event=" << event; std::cout << ", srcTime=" << srcTime; std::cout << ")" << std::endl; } #endif } // endif: spatial component valid // Return probability return prob; }