/***********************************************************************//** * @brief Get response cube spectrum * * @return Response cube spectrum. * * Returns the response cube spectrum. ***************************************************************************/ inline const GModelSpectralNodes& GCTABackgroundPerfTable::spectrum(void) const { if (m_mc_spectrum.nodes() == 0) { init_mc_cache(); } return (m_mc_spectrum); }
/***********************************************************************//** * @brief Determine sky model flux * * @param[in] model Sky model. * @param[in] emin Minimum energy. * @param[in] emax Maximum energy. * @param[in] centre Centre of region for photon rate determination. * @param[in] radius Radius of region for photon rate determination. * @return Model flux (photons/cm2/sec). ***************************************************************************/ double ctobssim::get_model_flux(const GModelSky* model, const GEnergy& emin, const GEnergy& emax, const GSkyDir& centre, const double& radius) { // Initialise de-allocation flag bool free_spectral = false; // Get pointer to spectral model const GModelSpectral* spectral = model->spectral(); // If the spatial model is a diffuse cube then create a node function // spectral model that is the product of the diffuse cube node function // and the spectral model evaluated at the energies of the node function GModelSpatialDiffuseCube* cube = dynamic_cast<GModelSpatialDiffuseCube*>(model->spatial()); if (cube != NULL) { // Set MC cone cube->set_mc_cone(centre, radius); // Allocate node function to replace the spectral component GModelSpectralNodes* nodes = new GModelSpectralNodes(cube->spectrum()); for (int i = 0; i < nodes->nodes(); ++i) { GEnergy energy = nodes->energy(i); GTime time; // Dummy time double intensity = nodes->intensity(i); double norm = spectral->eval(energy, time); nodes->intensity(i, norm*intensity); } // Signal that node function needs to be de-allocated later free_spectral = true; // Set the spectral model pointer to the node function spectral = nodes; } // endif: spatial model was a diffuse cube // Compute flux within [emin, emax] in model from spectral // component (units: ph/cm2/s) double flux = spectral->flux(emin, emax); // Free spectral model if required if (free_spectral) delete spectral; // Return model flux return flux; }
/***********************************************************************//** * @brief Return simulated list of events * * @param[in] obs Observation. * @param[in] ran Random number generator. * @return Pointer to list of simulated events (needs to be de-allocated by * client) * * @exception GException::invalid_argument * No CTA event list found in observation. * * Draws a sample of events from the background model using a Monte * Carlo simulation. The pointing information, the energy boundaries and the * good time interval for the sampling will be extracted from the observation * argument that is passed to the method. The method also requires a random * number generator of type GRan which is passed by reference, hence the * state of the random number generator will be changed by the method. * * The method also applies a deadtime correction using a Monte Carlo process, * taking into account temporal deadtime variations. For this purpose, the * method makes use of the time dependent GObservation::deadc method. ***************************************************************************/ GCTAEventList* GCTAModelBackground::mc(const GObservation& obs, GRan& ran) const { // Initialise new event list GCTAEventList* list = new GCTAEventList; // Continue only if model is valid) if (valid_model()) { // Extract event list to access the ROI, energy boundaries and GTIs 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_MC, msg); } // Get simulation region const GCTARoi& roi = events->roi(); const GEbounds& ebounds = events->ebounds(); const GGti& gti = events->gti(); // Set simulation region for result event list list->roi(roi); list->ebounds(ebounds); list->gti(gti); // Loop over all energy boundaries for (int ieng = 0; ieng < ebounds.size(); ++ieng) { // Initialise de-allocation flag bool free_spectral = false; // Set pointer to spectral model GModelSpectral* spectral = m_spectral; // If the spectral model is a diffuse cube then create a node // function spectral model that is the product of the diffuse // cube node function and the spectral model evaluated at the // energies of the node function GModelSpatialDiffuseCube* cube = dynamic_cast<GModelSpatialDiffuseCube*>(m_spatial); if (cube != NULL) { // Set MC simulation cone based on ROI cube->set_mc_cone(roi.centre().dir(), roi.radius()); // Allocate node function to replace the spectral component GModelSpectralNodes* nodes = new GModelSpectralNodes(cube->spectrum()); for (int i = 0; i < nodes->nodes(); ++i) { GEnergy energy = nodes->energy(i); double intensity = nodes->intensity(i); double norm = m_spectral->eval(energy, events->tstart()); nodes->intensity(i, norm*intensity); } // Signal that node function needs to be de-allocated later free_spectral = true; // Set the spectral model pointer to the node function spectral = nodes; } // endif: spatial model was a diffuse cube // Compute the background rate in model within the energy boundaries // from spectral component (units: cts/s). // Note that the time here is ontime. Deadtime correction will be done // later. double rate = spectral->flux(ebounds.emin(ieng), ebounds.emax(ieng)); // Debug option: dump rate #if defined(G_DUMP_MC) std::cout << "GCTAModelBackground::mc(\"" << name() << "\": "; std::cout << "rate=" << rate << " cts/s)" << std::endl; #endif // Loop over all good time intervals for (int itime = 0; itime < gti.size(); ++itime) { // Get Monte Carlo event arrival times from temporal model GTimes times = m_temporal->mc(rate, gti.tstart(itime), gti.tstop(itime), ran); // Get number of events int n_events = times.size(); // Reserve space for events if (n_events > 0) { list->reserve(n_events); } // Loop over events for (int i = 0; i < n_events; ++i) { // Apply deadtime correction double deadc = obs.deadc(times[i]); if (deadc < 1.0) { if (ran.uniform() > deadc) { continue; } } // Get Monte Carlo event energy from spectral model GEnergy energy = spectral->mc(ebounds.emin(ieng), ebounds.emax(ieng), times[i], ran); // Get Monte Carlo event direction from spatial model GSkyDir dir = spatial()->mc(energy, times[i], ran); // Allocate event GCTAEventAtom event; // Set event attributes event.dir(GCTAInstDir(dir)); event.energy(energy); event.time(times[i]); // Append event to list if it falls in ROI if (events->roi().contains(event)) { list->append(event); } } // endfor: looped over all events } // endfor: looped over all GTIs // Free spectral model if required if (free_spectral) delete spectral; } // endfor: looped over all energy boundaries } // endif: model was valid // Return return list; }