/***********************************************************************//** * @brief Evaluate function * * @param[in] event Observed event. * @param[in] obs Observation. * @return Function value. * * @exception GException::invalid_argument * Specified observation is not of the expected type. * * @todo Make sure that DETX and DETY are always set in GCTAInstDir. ***************************************************************************/ double GCTAModelIrfBackground::eval(const GEvent& event, const GObservation& obs) const { // Get pointer on CTA observation const GCTAObservation* cta = dynamic_cast<const GCTAObservation*>(&obs); if (cta == NULL) { std::string msg = "Specified observation is not a CTA observation.\n" + obs.print(); throw GException::invalid_argument(G_EVAL, msg); } // Get pointer on CTA IRF response const GCTAResponseIrf* rsp = dynamic_cast<const GCTAResponseIrf*>(cta->response()); if (rsp == NULL) { std::string msg = "Specified observation does not contain an IRF response.\n" + obs.print(); throw GException::invalid_argument(G_EVAL, msg); } // Retrieve pointer to CTA background const GCTABackground* bgd = rsp->background(); if (bgd == NULL) { std::string msg = "Specified observation contains no background" " information.\n" + obs.print(); throw GException::invalid_argument(G_EVAL, msg); } // Extract CTA instrument direction from event const GCTAInstDir* dir = dynamic_cast<const GCTAInstDir*>(&(event.dir())); if (dir == NULL) { std::string msg = "No CTA instrument direction found in event."; throw GException::invalid_argument(G_EVAL, msg); } // Set DETX and DETY in instrument direction GCTAInstDir inst_dir = cta->pointing().instdir(dir->dir()); // Evaluate function double logE = event.energy().log10TeV(); double spat = (*bgd)(logE, inst_dir.detx(), inst_dir.dety()); double spec = (spectral() != NULL) ? spectral()->eval(event.energy(), event.time()) : 1.0; double temp = (temporal() != NULL) ? temporal()->eval(event.time()) : 1.0; // Compute value double value = spat * spec * temp; // Apply deadtime correction value *= obs.deadc(event.time()); // Return value return value; }
/***********************************************************************//** * @brief Evaluate function * * @param[in] event Observed event. * @param[in] obs Observation. * @return Function value. * * @exception GException::invalid_argument * No CTA instrument direction found in event. * * Evaluates tha CTA background model which is a factorization of a * spatial, spectral and temporal model component. This method also applies * a deadtime correction factor, so that the normalization of the model is * a real rate (counts/exposure time). * * @todo Add bookkeeping of last value and evaluate only if argument * changed ***************************************************************************/ double GCTAModelBackground::eval(const GEvent& event, const GObservation& obs) const { // Get pointer on CTA observation const GCTAObservation* ctaobs = dynamic_cast<const GCTAObservation*>(&obs); if (ctaobs == NULL) { std::string msg = "Specified observation is not a CTA observation.\n" + obs.print(); throw GException::invalid_argument(G_EVAL, msg); } // Extract CTA instrument direction const GCTAInstDir* dir = dynamic_cast<const GCTAInstDir*>(&(event.dir())); if (dir == NULL) { std::string msg = "No CTA instrument direction found in event."; throw GException::invalid_argument(G_EVAL, msg); } // Create a Photon from the event. // We need the GPhoton to evaluate the spatial model. // For the background, GEvent and GPhoton are identical // since the IRFs are not folded in GPhoton photon(dir->dir(), event.energy(), event.time()); // Evaluate function and gradients double spat = (spatial() != NULL) ? spatial()->eval(photon) : 1.0; double spec = (spectral() != NULL) ? spectral()->eval(event.energy(), event.time()) : 1.0; double temp = (temporal() != NULL) ? temporal()->eval(event.time()) : 1.0; // Compute value double value = spat * spec * temp; // Apply deadtime correction value *= obs.deadc(event.time()); // Return return value; }
/***********************************************************************//** * @brief Return spatially integrated background model * * @param[in] obsEng Measured event energy. * @param[in] obsTime Measured event time. * @param[in] obs Observation. * @return Spatially integrated model. * * @exception GException::invalid_argument * The specified observation is not a CTA observation. * * Spatially integrates the cube background model for a given measured event * energy and event time. This method also applies a deadtime correction * factor, so that the normalization of the model is a real rate * (counts/MeV/s). ***************************************************************************/ double GCTAModelCubeBackground::npred(const GEnergy& obsEng, const GTime& obsTime, const GObservation& obs) const { // Initialise result double npred = 0.0; bool has_npred = false; // Build unique identifier std::string id = obs.instrument() + "::" + obs.id(); // Check if Npred value is already in cache #if defined(G_USE_NPRED_CACHE) if (!m_npred_names.empty()) { // Search for unique identifier, and if found, recover Npred value // and break for (int i = 0; i < m_npred_names.size(); ++i) { if (m_npred_names[i] == id && m_npred_energies[i] == obsEng) { npred = m_npred_values[i]; has_npred = true; #if defined(G_DEBUG_NPRED) std::cout << "GCTAModelCubeBackground::npred:"; std::cout << " cache=" << i; std::cout << " npred=" << npred << std::endl; #endif break; } } } // endif: there were values in the Npred cache #endif // Continue only if no Npred cache value has been found if (!has_npred) { // Evaluate only if model is valid if (valid_model()) { // Get pointer on CTA observation const GCTAObservation* cta = dynamic_cast<const GCTAObservation*>(&obs); if (cta == NULL) { std::string msg = "Specified observation is not a CTA" " observation.\n" + obs.print(); throw GException::invalid_argument(G_NPRED, msg); } // Get pointer on CTA cube response const GCTAResponseCube* rsp = dynamic_cast<const GCTAResponseCube*>(cta->response()); if (rsp == NULL) { std::string msg = "Specified observation does not contain" " a cube response.\n" + obs.print(); throw GException::invalid_argument(G_NPRED, msg); } // Get log10 of energy in TeV double logE = obsEng.log10TeV(); // Retrieve CTA background const GCTACubeBackground bgd = rsp->background(); // Integrate the background map at a certain energy npred = bgd.integral(logE); // Store result in Npred cache #if defined(G_USE_NPRED_CACHE) m_npred_names.push_back(id); m_npred_energies.push_back(obsEng); m_npred_times.push_back(obsTime); m_npred_values.push_back(npred); #endif // Debug: Check for NaN #if defined(G_NAN_CHECK) if (gammalib::is_notanumber(npred) || gammalib::is_infinite(npred)) { std::string origin = "GCTAModelCubeBackground::npred"; std::string message = " NaN/Inf encountered (npred=" + gammalib::str(npred) + ")"; gammalib::warning(origin, message); } #endif } // endif: model was valid } // endif: Npred computation required // Multiply in spectral and temporal components npred *= spectral()->eval(obsEng, obsTime); npred *= temporal()->eval(obsTime); // Apply deadtime correction npred *= obs.deadc(obsTime); // Return Npred return npred; }
/***********************************************************************//** * @brief Evaluate function and gradients * * @param[in] event Observed event. * @param[in] obs Observation. * @return Function value. * * @exception GException::invalid_argument * Specified observation is not of the expected type. ***************************************************************************/ double GCTAModelCubeBackground::eval_gradients(const GEvent& event, const GObservation& obs) const { // Get pointer on CTA observation const GCTAObservation* cta = dynamic_cast<const GCTAObservation*>(&obs); if (cta == NULL) { std::string msg = "Specified observation is not a CTA observation.\n" + obs.print(); throw GException::invalid_argument(G_EVAL_GRADIENTS, msg); } // Get pointer on CTA IRF response const GCTAResponseCube* rsp = dynamic_cast<const GCTAResponseCube*>(cta->response()); if (rsp == NULL) { std::string msg = "Specified observation does not contain a" " cube response.\n" + obs.print(); throw GException::invalid_argument(G_EVAL_GRADIENTS, msg); } // Extract CTA instrument direction from event const GCTAInstDir* dir = dynamic_cast<const GCTAInstDir*>(&(event.dir())); if (dir == NULL) { std::string msg = "No CTA instrument direction found in event."; throw GException::invalid_argument(G_EVAL_GRADIENTS, msg); } // Retrieve reference to CTA cube background const GCTACubeBackground& bgd = rsp->background(); // Evaluate function //double logE = event.energy().log10TeV(); double spat = bgd((*dir), event.energy()); double spec = (spectral() != NULL) ? spectral()->eval_gradients(event.energy(), event.time()) : 1.0; double temp = (temporal() != NULL) ? temporal()->eval_gradients(event.time()) : 1.0; // Compute value. Note that background rates are already per // livetime, hence no deadtime correction is needed here. double value = spat * spec * temp; // Multiply factors to spectral gradients if (spectral() != NULL) { double fact = spat * temp; if (fact != 1.0) { for (int i = 0; i < spectral()->size(); ++i) (*spectral())[i].factor_gradient( (*spectral())[i].factor_gradient() * fact ); } } // Multiply factors to temporal gradients if (temporal() != NULL) { double fact = spat * spec; if (fact != 1.0) { for (int i = 0; i < temporal()->size(); ++i) (*temporal())[i].factor_gradient( (*temporal())[i].factor_gradient() * fact ); } } // Return value return value; }
/***********************************************************************//** * @brief Return spatially integrated data model * * @param[in] obsEng Measured event energy. * @param[in] obsTime Measured event time. * @param[in] obs Observation. * @return Spatially integrated model. * * @exception GException::invalid_argument * No CTA event list found in observation. * No CTA pointing found in observation. * * Spatially integrates the data model for a given measured event energy and * event time. This method also applies a deadtime correction factor, so that * the normalization of the model is a real rate (counts/exposure time). ***************************************************************************/ double GCTAModelBackground::npred(const GEnergy& obsEng, const GTime& obsTime, const GObservation& obs) const { // Initialise result double npred = 0.0; bool has_npred = false; // Build unique identifier std::string id = obs.instrument() + "::" + obs.id(); // Check if Npred value is already in cache #if defined(G_USE_NPRED_CACHE) if (!m_npred_names.empty()) { // Search for unique identifier, and if found, recover Npred value // and break for (int i = 0; i < m_npred_names.size(); ++i) { if (m_npred_names[i] == id && m_npred_energies[i] == obsEng) { npred = m_npred_values[i]; has_npred = true; #if defined(G_DEBUG_NPRED) std::cout << "GCTAModelBackground::npred:"; std::cout << " cache=" << i; std::cout << " npred=" << npred << std::endl; #endif break; } } } // endif: there were values in the Npred cache #endif // Continue only if no Npred cache value was found if (!has_npred) { // Evaluate only if model is valid if (valid_model()) { // Get CTA event list const GCTAEventList* events = dynamic_cast<const GCTAEventList*>(obs.events()); if (events == NULL) { std::string msg = "No CTA event list found in observation.\n" + obs.print(); throw GException::invalid_argument(G_NPRED, msg); } #if !defined(G_NPRED_AROUND_ROI) // Get CTA pointing direction GCTAPointing* pnt = dynamic_cast<GCTAPointing*>(obs.pointing()); if (pnt == NULL) { std::string msg = "No CTA pointing found in observation.\n" + obs.print(); throw GException::invalid_argument(G_NPRED, msg); } #endif // Get reference to ROI centre const GSkyDir& roi_centre = events->roi().centre().dir(); // Get ROI radius in radians double roi_radius = events->roi().radius() * gammalib::deg2rad; // Get distance from ROI centre in radians #if defined(G_NPRED_AROUND_ROI) double roi_distance = 0.0; #else double roi_distance = roi_centre.dist(pnt->dir()); #endif // Initialise rotation matrix to transform from ROI system to // celestial coordinate system GMatrix ry; GMatrix rz; ry.eulery(roi_centre.dec_deg() - 90.0); rz.eulerz(-roi_centre.ra_deg()); GMatrix rot = (ry * rz).transpose(); // Compute position angle of ROI centre with respect to model // centre (radians) #if defined(G_NPRED_AROUND_ROI) double omega0 = 0.0; #else double omega0 = pnt->dir().posang(events->roi().centre().dir()); #endif // Setup integration function GCTAModelBackground::npred_roi_kern_theta integrand(spatial(), obsEng, obsTime, rot, roi_radius, roi_distance, omega0); // Setup integrator GIntegral integral(&integrand); integral.eps(1e-3); // Setup integration boundaries #if defined(G_NPRED_AROUND_ROI) double rmin = 0.0; double rmax = roi_radius; #else double rmin = (roi_distance > roi_radius) ? roi_distance-roi_radius : 0.0; double rmax = roi_radius + roi_distance; #endif // Spatially integrate radial component npred = integral.romb(rmin, rmax); // Store result in Npred cache #if defined(G_USE_NPRED_CACHE) m_npred_names.push_back(id); m_npred_energies.push_back(obsEng); m_npred_times.push_back(obsTime); m_npred_values.push_back(npred); #endif // Debug: Check for NaN #if defined(G_NAN_CHECK) if (gammalib::is_notanumber(npred) || gammalib::is_infinite(npred)) { std::cout << "*** ERROR: GCTAModelBackground::npred:"; std::cout << " NaN/Inf encountered"; std::cout << " (npred=" << npred; std::cout << ", roi_radius=" << roi_radius; std::cout << ")" << std::endl; } #endif } // endif: model was valid } // endif: Npred computation required // Multiply in spectral and temporal components npred *= spectral()->eval(obsEng, obsTime); npred *= temporal()->eval(obsTime); // Apply deadtime correction npred *= obs.deadc(obsTime); // Return Npred return npred; }
/***********************************************************************//** * @brief Evaluate function and gradients * * @param[in] event Observed event. * @param[in] obs Observation. * @return Function value. * * @exception GException::invalid_argument * No CTA instrument direction found in event. * * Evaluates tha CTA background model and parameter gradients. The CTA * background model is a factorization of a spatial, spectral and * temporal model component. This method also applies a deadtime correction * factor, so that the normalization of the model is a real rate * (counts/exposure time). * * @todo Add bookkeeping of last value and evaluate only if argument * changed ***************************************************************************/ double GCTAModelBackground::eval_gradients(const GEvent& event, const GObservation& obs) const { // Get pointer on CTA observation const GCTAObservation* ctaobs = dynamic_cast<const GCTAObservation*>(&obs); if (ctaobs == NULL) { std::string msg = "Specified observation is not a CTA observation.\n" + obs.print(); throw GException::invalid_argument(G_EVAL_GRADIENTS, msg); } // Extract CTA instrument direction const GCTAInstDir* dir = dynamic_cast<const GCTAInstDir*>(&(event.dir())); if (dir == NULL) { std::string msg = "No CTA instrument direction found in event."; throw GException::invalid_argument(G_EVAL_GRADIENTS, msg); } // Create a Photon from the event // We need the photon to evaluate the spatial model // For the background, GEvent and GPhoton are identical // since the IRFs are not folded in GPhoton photon = GPhoton(dir->dir(), event.energy(),event.time()); // Evaluate function and gradients double spat = (spatial() != NULL) ? spatial()->eval_gradients(photon) : 1.0; double spec = (spectral() != NULL) ? spectral()->eval_gradients(event.energy(), event.time()) : 1.0; double temp = (temporal() != NULL) ? temporal()->eval_gradients(event.time()) : 1.0; // Compute value double value = spat * spec * temp; // Apply deadtime correction double deadc = obs.deadc(event.time()); value *= deadc; // Multiply factors to spatial gradients if (spatial() != NULL) { double fact = spec * temp * deadc; if (fact != 1.0) { for (int i = 0; i < spatial()->size(); ++i) (*spatial())[i].factor_gradient( (*spatial())[i].factor_gradient() * fact ); } } // Multiply factors to spectral gradients if (spectral() != NULL) { double fact = spat * temp * deadc; if (fact != 1.0) { for (int i = 0; i < spectral()->size(); ++i) (*spectral())[i].factor_gradient( (*spectral())[i].factor_gradient() * fact ); } } // Multiply factors to temporal gradients if (temporal() != NULL) { double fact = spat * spec * deadc; if (fact != 1.0) { for (int i = 0; i < temporal()->size(); ++i) (*temporal())[i].factor_gradient( (*temporal())[i].factor_gradient() * fact ); } } // Return value return value; }
/***********************************************************************//** * @brief Evaluate function * * @param[in] event Observed event. * @param[in] obs Observation. * @param[in] gradients Compute gradients? * @return Function value. * * @exception GException::invalid_argument * Specified observation is not of the expected type. * * If the @p gradients flag is true the method will also set the parameter * gradients of the model parameters. * * @todo Make sure that DETX and DETY are always set in GCTAInstDir. ***************************************************************************/ double GCTAModelAeffBackground::eval(const GEvent& event, const GObservation& obs, const bool& gradients) const { // Get pointer on CTA observation const GCTAObservation* cta = dynamic_cast<const GCTAObservation*>(&obs); if (cta == NULL) { std::string msg = "Specified observation is not a CTA observation.\n" + obs.print(); throw GException::invalid_argument(G_EVAL, msg); } // Get pointer on CTA IRF response const GCTAResponseIrf* rsp = dynamic_cast<const GCTAResponseIrf*>(cta->response()); if (rsp == NULL) { std::string msg = "Specified observation does not contain an IRF response.\n" + obs.print(); throw GException::invalid_argument(G_EVAL, msg); } // Retrieve pointer to CTA Effective Area const GCTAAeff* aeff = rsp->aeff(); if (aeff == NULL) { std::string msg = "Specified observation contains no effective area" " information.\n" + obs.print(); throw GException::invalid_argument(G_EVAL, msg); } // Extract CTA instrument direction from event const GCTAInstDir* dir = dynamic_cast<const GCTAInstDir*>(&(event.dir())); if (dir == NULL) { std::string msg = "No CTA instrument direction found in event."; throw GException::invalid_argument(G_EVAL, msg); } // Set DETX and DETY in instrument direction GCTAInstDir inst_dir = cta->pointing().instdir(dir->dir()); // Set theta and phi from instrument coordinates double theta = std::sqrt(inst_dir.detx() * inst_dir.detx() + inst_dir.dety() * inst_dir.dety()); double phi = gammalib::atan2d(inst_dir.dety(), inst_dir.detx()) * gammalib::deg2rad; // Evaluate function double logE = event.energy().log10TeV(); double spat = (*aeff)(logE, theta, phi, cta->pointing().zenith(), cta->pointing().azimuth(), false); double spec = (spectral() != NULL) ? spectral()->eval(event.energy(), event.time(), gradients) : 1.0; double temp = (temporal() != NULL) ? temporal()->eval(event.time(), gradients) : 1.0; // Compute value double value = spat * spec * temp; // Apply deadtime correction double deadc = obs.deadc(event.time()); value *= deadc; // Optionally compute partial derivatives if (gradients) { // Multiply factors to spectral gradients if (spectral() != NULL) { double fact = spat * temp * deadc; if (fact != 1.0) { for (int i = 0; i < spectral()->size(); ++i) (*spectral())[i].factor_gradient((*spectral())[i].factor_gradient() * fact ); } } // Multiply factors to temporal gradients if (temporal() != NULL) { double fact = spat * spec * deadc; if (fact != 1.0) { for (int i = 0; i < temporal()->size(); ++i) (*temporal())[i].factor_gradient((*temporal())[i].factor_gradient() * fact ); } } } // endif: computed partial derivatives // Return value return value; }
/***********************************************************************//** * @brief Spatially integrate effective area for given energy * * @param[in] obs Observation. * @param[in] logE Log10 of reference energy in TeV. * @return Spatially integrated effective area for given energy. * * @exception GException::invalid_argument * Invalid observation encountered. * * Spatially integrates the effective area for a given reference energy * over the region of interest. ***************************************************************************/ double GCTAModelAeffBackground::aeff_integral(const GObservation& obs, const double& logE) const { // Initialise result double value = 0.0; // Set number of iterations for Romberg integration. static const int iter_theta = 6; static const int iter_phi = 6; // Get pointer on CTA observation const GCTAObservation* cta = dynamic_cast<const GCTAObservation*>(&obs); if (cta == NULL) { std::string msg = "Specified observation is not a CTA" " observation.\n" + obs.print(); throw GException::invalid_argument(G_NPRED, msg); } // Get pointer on CTA IRF response const GCTAResponseIrf* rsp = dynamic_cast<const GCTAResponseIrf*>(cta->response()); if (rsp == NULL) { std::string msg = "Specified observation does not contain" " an IRF response.\n" + obs.print(); throw GException::invalid_argument(G_NPRED, msg); } // Retrieve pointer to CTA effective area const GCTAAeff* aeff = rsp->aeff(); if (aeff == NULL) { std::string msg = "Specified observation contains no effective area" " information.\n" + obs.print(); throw GException::invalid_argument(G_NPRED, msg); } // Get CTA event list const GCTAEventList* events = dynamic_cast<const GCTAEventList*>(obs.events()); if (events == NULL) { std::string msg = "No CTA event list found in observation.\n" + obs.print(); throw GException::invalid_argument(G_NPRED, msg); } // Get ROI radius in radians double roi_radius = events->roi().radius() * gammalib::deg2rad; // Setup integration function GCTAModelAeffBackground::npred_roi_kern_theta integrand(aeff, logE, iter_phi); // Setup integration GIntegral integral(&integrand); // Set fixed number of iterations integral.fixed_iter(iter_theta); // Spatially integrate radial component value = integral.romberg(0.0, roi_radius); // Debug: Check for NaN #if defined(G_NAN_CHECK) if (gammalib::is_notanumber(value) || gammalib::is_infinite(value)) { std::string origin = "GCTAModelAeffBackground::aeff_integral"; std::string message = " NaN/Inf encountered (value=" + gammalib::str(value) + ", roi_radius=" + gammalib::str(roi_radius) + ")"; gammalib::warning(origin, message); } #endif // Return return value; }
/***********************************************************************//** * @brief Return spatially integrated background model * * @param[in] obsEng Measured event energy. * @param[in] obsTime Measured event time. * @param[in] obs Observation. * @return Spatially integrated model. * * @exception GException::invalid_argument * The specified observation is not a CTA observation. * * Spatially integrates the instrumental background model for a given * measured event energy and event time. This method also applies a deadtime * correction factor, so that the normalization of the model is a real rate * (counts/MeV/s). ***************************************************************************/ double GCTAModelIrfBackground::npred(const GEnergy& obsEng, const GTime& obsTime, const GObservation& obs) const { // Initialise result double npred = 0.0; bool has_npred = false; // Build unique identifier std::string id = obs.instrument() + "::" + obs.id(); // Check if Npred value is already in cache #if defined(G_USE_NPRED_CACHE) if (!m_npred_names.empty()) { // Search for unique identifier, and if found, recover Npred value // and break for (int i = 0; i < m_npred_names.size(); ++i) { if (m_npred_names[i] == id && m_npred_energies[i] == obsEng) { npred = m_npred_values[i]; has_npred = true; #if defined(G_DEBUG_NPRED) std::cout << "GCTAModelIrfBackground::npred:"; std::cout << " cache=" << i; std::cout << " npred=" << npred << std::endl; #endif break; } } } // endif: there were values in the Npred cache #endif // Continue only if no Npred cache value has been found if (!has_npred) { // Evaluate only if model is valid if (valid_model()) { // Get pointer on CTA observation const GCTAObservation* cta = dynamic_cast<const GCTAObservation*>(&obs); if (cta == NULL) { std::string msg = "Specified observation is not a CTA" " observation.\n" + obs.print(); throw GException::invalid_argument(G_NPRED, msg); } // Get pointer on CTA IRF response const GCTAResponseIrf* rsp = dynamic_cast<const GCTAResponseIrf*>(cta->response()); if (rsp == NULL) { std::string msg = "Specified observation does not contain" " an IRF response.\n" + obs.print(); throw GException::invalid_argument(G_NPRED, msg); } // Retrieve pointer to CTA background const GCTABackground* bgd = rsp->background(); if (bgd == NULL) { std::string msg = "Specified observation contains no background" " information.\n" + obs.print(); throw GException::invalid_argument(G_NPRED, msg); } // Get CTA event list const GCTAEventList* events = dynamic_cast<const GCTAEventList*>(obs.events()); if (events == NULL) { std::string msg = "No CTA event list found in observation.\n" + obs.print(); throw GException::invalid_argument(G_NPRED, msg); } // Get reference to ROI centre const GSkyDir& roi_centre = events->roi().centre().dir(); // Get ROI radius in radians double roi_radius = events->roi().radius() * gammalib::deg2rad; // Get log10 of energy in TeV double logE = obsEng.log10TeV(); // Setup integration function GCTAModelIrfBackground::npred_roi_kern_theta integrand(bgd, logE); // Setup integrator GIntegral integral(&integrand); integral.eps(g_cta_inst_background_npred_theta_eps); // Spatially integrate radial component npred = integral.romberg(0.0, roi_radius); // Store result in Npred cache #if defined(G_USE_NPRED_CACHE) m_npred_names.push_back(id); m_npred_energies.push_back(obsEng); m_npred_times.push_back(obsTime); m_npred_values.push_back(npred); #endif // Debug: Check for NaN #if defined(G_NAN_CHECK) if (gammalib::is_notanumber(npred) || gammalib::is_infinite(npred)) { std::string origin = "GCTAModelIrfBackground::npred"; std::string message = " NaN/Inf encountered (npred=" + gammalib::str(npred) + ", roi_radius=" + gammalib::str(roi_radius) + ")"; gammalib::warning(origin, message); } #endif } // endif: model was valid } // endif: Npred computation required // Multiply in spectral and temporal components npred *= spectral()->eval(obsEng, obsTime); npred *= temporal()->eval(obsTime); // Apply deadtime correction npred *= obs.deadc(obsTime); // Return Npred return npred; }