/***********************************************************************//** * @brief Returns vector of random event times * * @param[in] rate Mean event rate (events per second). * @param[in] tmin Minimum event time. * @param[in] tmax Maximum event time. * @param[in,out] ran Random number generator. * * This method returns a vector of random event times assuming a constant * event rate that is specified by the rate parameter. ***************************************************************************/ GTimes GModelTemporalConst::mc(const double& rate, const GTime& tmin, const GTime& tmax, GRan& ran) const { // Allocates empty vector of times GTimes times; // Compute event rate (in events per seconds) double lambda = rate * norm(); // Initialise start and stop times in seconds double time = tmin.secs(); double tstop = tmax.secs(); // Generate events until maximum event time is exceeded while (time <= tstop) { // Simulate next event time time += ran.exp(lambda); // Add time if it is not beyod the stop time if (time <= tstop) { GTime event; event.secs(time); times.append(event); } } // endwhile: loop until stop time is reached // Return vector of times return times; }
/***********************************************************************//** * @brief Integration kernel for npred_temp() method * * @param[in] x Function value. ***************************************************************************/ double GObservation::npred_temp_kern::eval(double x) { // Convert argument in native reference in seconds GTime time; time.secs(x); // Return value return (m_parent->npred_spec(*m_model, time)); }
/***********************************************************************//** * @brief Insert Good Time Interval * * @param[in] index Index after which interval is inserted. * @param[in] tstart Start time of interval. * @param[in] tstop Stop time of interval. * * @exception GException::invalid_argument * Start time later than stop time * * Inserts a Good Time Interval after the specified @p index in the Good * Time Intervals. The method does not reorder the intervals by time, * instead the client needs to determine the approriate @p index. * * Invalid parameters do not produce any exception, but are handled * transparently. If the interval is invalid (i.e. @p tstart > @p tstop) * an exception is thrown. If the @p index is out of the valid range, the * index will be adjusted to either the first or the last element. ***************************************************************************/ void GGti::insert_gti(const int& index, const GTime& tstart, const GTime& tstop) { // Throw an exception if time interval is invalid if (tstart > tstop) { std::string msg = "Invalid time interval specified. Start time "+ tstart.print(NORMAL)+" can not be later than " "stop time "+tstop.print(NORMAL)+"."; throw GException::invalid_argument(G_INSERT_GTI, msg); } // Set index int inx = index; // If inx is out of range then adjust it if (inx < 0) inx = 0; if (inx > m_num) inx = m_num; // Allocate new intervals int num = m_num+1; GTime* start = new GTime[num]; GTime* stop = new GTime[num]; // Copy intervals before GTI to be inserted for (int i = 0; i < inx; ++i) { start[i] = m_start[i]; stop[i] = m_stop[i]; } // Insert GTI start[inx] = tstart; stop[inx] = tstop; // Copy intervals after GTI to be inserted for (int i = inx+1; i < num; ++i) { start[i] = m_start[i-1]; stop[i] = m_stop[i-1]; } // Free memory if (m_start != NULL) delete [] m_start; if (m_stop != NULL) delete [] m_stop; // Set new memory m_start = start; m_stop = stop; // Set number of elements m_num = num; // Set attributes set_attributes(); // Return return; }
/***********************************************************************//** * @brief Invalid Good Time Interval found * * @param[in] origin Method that throws the error. * @param[in] tstart Good Time Interval start time. * @param[in] tstop Good Time Interval stop time. * @param[in] message Optional error message. ***************************************************************************/ GException::gti_invalid::gti_invalid(std::string origin, GTime tstart, GTime tstop, std::string message) { // Set method name m_origin = origin; // Set error message m_message = "Invalid Good Time Interval (" + tstart.print() + "-" + tstop.print() + ") specified."; if (message.length() > 0) { m_message += " " + message; } // Return return; }
/***********************************************************************//** * @brief Initialise class members ***************************************************************************/ void GGti::init_members(void) { // Initialise members m_num = 0; m_tstart.clear(); m_tstop.clear(); m_ontime = 0.0; m_telapse = 0.0; m_start = NULL; m_stop = NULL; // Initialise time reference with native reference GTime time; m_reference = time.reference(); // Return return; }
/***********************************************************************//** * @brief Evaluate function * * @param[in] srcTime True photon arrival time (not used). * @param[in] gradients Compute gradients? * @return Value of light curve model. * * Computes * * \f[ * S_{\rm t}(t) = r(t) \times {\tt m\_norm} * \f] * * where * \f$r(t)\f$ is the light curve, computed by linear interpolation between * the nodes in a FITS file, and \f${\tt m\_norm}\f$ is the normalization * constant. * * If the @p gradients flag is true the method will also evaluate the partial * derivatives of the model with respect to the normalization parameter using * * \f[ * \frac{\delta S_{\rm t}(t)}{\delta {\tt m\_norm}} = r(t) * \f] ***************************************************************************/ double GModelTemporalLightCurve::eval(const GTime& srcTime, const bool& gradients) const { // Initialise value double value = 0.0; // Optionally initialise gradient if (gradients) { m_norm.factor_gradient(0.0); } // Set value if the time is within the validity range if (srcTime >= m_tmin && srcTime <= m_tmax) { // Interpolate file function double func = m_nodes.interpolate(srcTime.convert(m_timeref), m_values); // Compute function value value = m_norm.value() * func; // Optionally compute gradients if (gradients) { // Compute partial derivatives of the parameter values double g_norm = (m_norm.is_free()) ? m_norm.scale() * func : 0.0; // Set gradients m_norm.factor_gradient(g_norm); } // endif: gradient computation was requested } // endif: time was within the validity range // Return return value; }
/***********************************************************************//** * @brief Simulate source events from photon list * * @param[in] obs Pointer on CTA observation. * @param[in] models Model list. * @param[in] ran Random number generator. * @param[in] wrklog Pointer to logger. * * Simulate source events from a photon list for a given CTA observation. * The events are stored in as event list in the observation. * * This method does nothing if the observation pointer is NULL. It also * verifies if the observation has a valid pointing and response. ***************************************************************************/ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, GRan& ran, GLog* wrklog) { // Continue only if observation pointer is valid if (obs != NULL) { // If no logger is specified then use the default logger if (wrklog == NULL) { wrklog = &log; } // Get CTA response const GCTAResponseIrf* rsp = dynamic_cast<const GCTAResponseIrf*>(obs->response()); if (rsp == NULL) { std::string msg = "Response is not an IRF response.\n" + obs->response()->print(); throw GException::invalid_value(G_SIMULATE_SOURCE, msg); } // Get pointer on event list (circumvent const correctness) GCTAEventList* events = static_cast<GCTAEventList*>(const_cast<GEvents*>(obs->events())); // Extract simulation region. GSkyDir dir = events->roi().centre().dir(); double rad = events->roi().radius() + g_roi_margin; // Dump simulation cone information if (logNormal()) { *wrklog << gammalib::parformat("Simulation area"); *wrklog << m_area << " cm2" << std::endl; *wrklog << gammalib::parformat("Simulation cone"); *wrklog << "RA=" << dir.ra_deg() << " deg"; *wrklog << ", Dec=" << dir.dec_deg() << " deg"; *wrklog << ", r=" << rad << " deg" << std::endl; } // Initialise indentation for logging int indent = 0; // Loop over all Good Time Intervals for (int it = 0; it < events->gti().size(); ++it) { // Extract time interval GTime tmin = events->gti().tstart(it); GTime tmax = events->gti().tstop(it); // Dump time interval if (logNormal()) { if (events->gti().size() > 1) { indent++; wrklog->indent(indent); } *wrklog << gammalib::parformat("Time interval", indent); *wrklog << tmin.convert(m_cta_ref); *wrklog << " - "; *wrklog << tmax.convert(m_cta_ref); *wrklog << " s" << std::endl; } // Loop over all energy boundaries for (int ie = 0; ie < events->ebounds().size(); ++ie) { // Extract energy boundaries GEnergy emin = events->ebounds().emin(ie); GEnergy emax = events->ebounds().emax(ie); // Set true photon energy limits for simulation. If observation // has energy dispersion then add margin GEnergy e_true_min = emin; GEnergy e_true_max = emax; if (rsp->use_edisp()) { e_true_min = rsp->ebounds(e_true_min).emin(); e_true_max = rsp->ebounds(e_true_max).emax(); } // Dump energy range if (logNormal()) { if (events->ebounds().size() > 1) { indent++; wrklog->indent(indent); } *wrklog << gammalib::parformat("Photon energy range", indent); *wrklog << e_true_min << " - " << e_true_max << std::endl; *wrklog << gammalib::parformat("Event energy range", indent); *wrklog << emin << " - " << emax << std::endl; } // Loop over all sky models for (int i = 0; i < models.size(); ++i) { // Get sky model (NULL if not a sky model) const GModelSky* model = dynamic_cast<const GModelSky*>(models[i]); // If we have a sky model that applies to the present // observation then simulate events if (model != NULL && model->is_valid(obs->instrument(), obs->id())) { // Determine duration of a time slice by limiting the // number of simulated photons to m_max_photons. // The photon rate is estimated from the model flux // and used to set the duration of the time slice. double flux = get_model_flux(model, emin, emax, dir, rad); double rate = flux * m_area; double duration = 1800.0; // default: 1800 sec if (rate > 0.0) { duration = m_max_photons / rate; if (duration < 1.0) { // not <1 sec duration = 1.0; } else if (duration > 180000.0) { // not >50 hr duration = 180000.0; } } GTime tslice(duration, "sec"); // If photon rate exceeds the maximum photon rate // then throw an exception if (rate > m_max_rate) { std::string modnam = (model->name().length() > 0) ? model->name() : "Unknown"; std::string msg = "Photon rate "+ gammalib::str(rate)+ " photons/sec for model \""+ modnam+"\" exceeds maximum" " allowed photon rate of "+ gammalib::str(m_max_rate)+ " photons/sec. Please check" " the model parameters for" " model \""+modnam+"\" or" " increase the value of the" " hidden \"maxrate\"" " parameter."; throw GException::invalid_value(G_SIMULATE_SOURCE, msg); } // Dump length of time slice and rate if (logExplicit()) { *wrklog << gammalib::parformat("Photon rate", indent); *wrklog << rate << " photons/sec"; if (model->name().length() > 0) { *wrklog << " [" << model->name() << "]"; } *wrklog << std::endl; } // To reduce memory requirements we split long time // intervals into several slices. GTime tstart = tmin; GTime tstop = tstart + tslice; // Initialise cumulative photon counters int nphotons = 0; // Loop over time slices while (tstart < tmax) { // Make sure that tstop <= tmax if (tstop > tmax) { tstop = tmax; } // Dump time slice if (logExplicit()) { if (tmax - tmin > tslice) { indent++; wrklog->indent(indent); } *wrklog << gammalib::parformat("Time slice", indent); *wrklog << tstart.convert(m_cta_ref); *wrklog << " - "; *wrklog << tstop.convert(m_cta_ref); *wrklog << " s"; if (model->name().length() > 0) { *wrklog << " [" << model->name() << "]"; } *wrklog << std::endl; } // Get photons GPhotons photons = model->mc(m_area, dir, rad, e_true_min, e_true_max, tstart, tstop, ran); // Dump number of simulated photons if (logExplicit()) { *wrklog << gammalib::parformat("MC source photons/slice", indent); *wrklog << photons.size(); if (model->name().length() > 0) { *wrklog << " [" << model->name() << "]"; } *wrklog << std::endl; } // Simulate events from photons for (int i = 0; i < photons.size(); ++i) { // Increment photon counter nphotons++; // Simulate event. Note that this method // includes the deadtime correction. GCTAEventAtom* event = rsp->mc(m_area, photons[i], *obs, ran); if (event != NULL) { // Use event only if it falls within ROI // energy boundary and time slice if (events->roi().contains(*event) && event->energy() >= emin && event->energy() <= emax && event->time() >= tstart && event->time() <= tstop) { event->event_id(m_event_id); events->append(*event); m_event_id++; } delete event; } } // endfor: looped over events // Go to next time slice tstart = tstop; tstop = tstart + tslice; // Reset indentation if (logExplicit()) { if (tmax - tmin > tslice) { indent--; wrklog->indent(indent); } } } // endwhile: looped over time slices // Dump simulation results if (logNormal()) { *wrklog << gammalib::parformat("MC source photons", indent); *wrklog << nphotons; if (model->name().length() > 0) { *wrklog << " [" << model->name() << "]"; } *wrklog << std::endl; *wrklog << gammalib::parformat("MC source events", indent); *wrklog << events->size(); if (model->name().length() > 0) { *wrklog << " [" << model->name() << "]"; } *wrklog << std::endl; } } // endif: model was a sky model } // endfor: looped over models // Dump simulation results if (logNormal()) { *wrklog << gammalib::parformat("MC source events", indent); *wrklog << events->size(); *wrklog << " (all source models)"; *wrklog << std::endl; } // Reset indentation if (logNormal()) { if (events->ebounds().size() > 1) { indent--; wrklog->indent(indent); } } } // endfor: looped over all energy boundaries // Reset indentation if (logNormal()) { if (events->gti().size() > 1) { indent--; wrklog->indent(indent); } } } // endfor: looped over all time intervals // Reset indentation wrklog->indent(0); } // endif: observation pointer was valid // Return return; }
/***********************************************************************//** * @brief Simulate source events from photon list * * @param[in] obs Pointer on CTA observation. * @param[in] models Model list. * @param[in] ran Random number generator. * @param[in] wrklog Pointer to logger. * * Simulate source events from a photon list for a given CTA observation. * The events are stored in as event list in the observation. * * This method does nothing if the observation pointer is NULL. It also * verifies if the observation has a valid pointing and response. ***************************************************************************/ void ctobssim::simulate_source(GCTAObservation* obs, const GModels& models, GRan& ran, GLog* wrklog) { // Continue only if observation pointer is valid if (obs != NULL) { // If no logger is specified then use the default logger if (wrklog == NULL) { wrklog = &log; } // Get pointer on CTA response. Throw an exception if the response // is not defined. const GCTAResponse& rsp = obs->response(); // Make sure that the observation holds a CTA event list. If this // is not the case then allocate and attach a CTA event list now. if (dynamic_cast<const GCTAEventList*>(obs->events()) == NULL) { set_list(obs); } // Get pointer on event list (circumvent const correctness) GCTAEventList* events = static_cast<GCTAEventList*>(const_cast<GEvents*>(obs->events())); // Extract simulation region. GSkyDir dir = events->roi().centre().dir(); double rad = events->roi().radius() + g_roi_margin; // Dump simulation cone information if (logNormal()) { *wrklog << gammalib::parformat("Simulation area"); *wrklog << m_area << " cm2" << std::endl; *wrklog << gammalib::parformat("Simulation cone"); *wrklog << "RA=" << dir.ra_deg() << " deg"; *wrklog << ", Dec=" << dir.dec_deg() << " deg"; *wrklog << ", r=" << rad << " deg" << std::endl; } // Initialise indentation for logging int indent = 0; // Loop over all Good Time Intervals for (int it = 0; it < events->gti().size(); ++it) { // Extract time interval GTime tmin = events->gti().tstart(it); GTime tmax = events->gti().tstop(it); // Dump time interval if (logNormal()) { if (events->gti().size() > 1) { indent++; wrklog->indent(indent); } *wrklog << gammalib::parformat("Time interval", indent); *wrklog << tmin.convert(m_cta_ref); *wrklog << " - "; *wrklog << tmax.convert(m_cta_ref); *wrklog << " s" << std::endl; } // Loop over all energy boundaries for (int ie = 0; ie < events->ebounds().size(); ++ie) { // Extract energy boundaries GEnergy emin = events->ebounds().emin(ie); GEnergy emax = events->ebounds().emax(ie); // Dump energy range if (logNormal()) { if (events->ebounds().size() > 1) { indent++; wrklog->indent(indent); } *wrklog << gammalib::parformat("Energy range", indent); *wrklog << emin << " - " << emax << std::endl; } // Loop over all sky models for (int i = 0; i < models.size(); ++i) { // Get sky model (NULL if not a sky model) const GModelSky* model = dynamic_cast<const GModelSky*>(models[i]); // If we have a sky model that applies to the present // observation then simulate events if (model != NULL && model->is_valid(obs->instrument(), obs->id())) { // Determine duration of a time slice by limiting the // number of simulated photons to m_max_photons. // The photon rate is estimated from the model flux // and used to set the duration of the time slice. double flux = model->spectral()->flux(emin, emax); double rate = flux * m_area; double duration = 1800.0; // default: 1800 sec if (rate > 0.0) { duration = m_max_photons / rate; if (duration < 1.0) { // not <1 sec duration = 1.0; } else if (duration > 180000.0) { // not >50 hr duration = 180000.0; } } GTime tslice(duration, "sec"); // To reduce memory requirements we split long time // intervals into several slices. GTime tstart = tmin; GTime tstop = tstart + tslice; // Initialise cumulative photon counters int nphotons = 0; // Loop over time slices while (tstart < tmax) { // Make sure that tstop <= tmax if (tstop > tmax) { tstop = tmax; } // Dump time slice if (logExplicit()) { if (tmax - tmin > tslice) { indent++; wrklog->indent(indent); } *wrklog << gammalib::parformat("Time slice", indent); *wrklog << tstart.convert(m_cta_ref); *wrklog << " - "; *wrklog << tstop.convert(m_cta_ref); *wrklog << " s" << std::endl; } // Get photons GPhotons photons = model->mc(m_area, dir, rad, emin, emax, tstart, tstop, ran); // Dump number of simulated photons if (logExplicit()) { *wrklog << gammalib::parformat("MC source photons/slice", indent); *wrklog << photons.size(); if (model->name().length() > 0) { *wrklog << " [" << model->name() << "]"; } *wrklog << std::endl; } // Simulate events from photons for (int i = 0; i < photons.size(); ++i) { // Increment photon counter nphotons++; // Simulate event. Note that this method // includes the deadtime correction. GCTAEventAtom* event = rsp.mc(m_area, photons[i], *obs, ran); if (event != NULL) { // Use event only if it falls within ROI if (events->roi().contains(*event)) { event->event_id(m_event_id); events->append(*event); m_event_id++; } delete event; } } // endfor: looped over events // Go to next time slice tstart = tstop; tstop = tstart + tslice; // Reset indentation if (logExplicit()) { if (tmax - tmin > tslice) { indent--; wrklog->indent(indent); } } } // endwhile: looped over time slices // Dump simulation results if (logNormal()) { *wrklog << gammalib::parformat("MC source photons", indent); *wrklog << nphotons; if (model->name().length() > 0) { *wrklog << " [" << model->name() << "]"; } *wrklog << std::endl; *wrklog << gammalib::parformat("MC source events", indent); *wrklog << events->size(); if (model->name().length() > 0) { *wrklog << " [" << model->name() << "]"; } *wrklog << std::endl; } } // endif: model was a sky model } // endfor: looped over models // Dump simulation results if (logNormal()) { *wrklog << gammalib::parformat("MC source events", indent); *wrklog << events->size(); *wrklog << " (all source models)"; *wrklog << std::endl; } // Reset indentation if (logNormal()) { if (events->ebounds().size() > 1) { indent--; wrklog->indent(indent); } } } // endfor: looped over all energy boundaries // Reset indentation if (logNormal()) { if (events->gti().size() > 1) { indent--; wrklog->indent(indent); } } } // endfor: looped over all time intervals // Reset indentation wrklog->indent(0); } // endif: observation pointer was valid // Return return; }
/***********************************************************************//** * @brief Set empty CTA event list * * @param[in] obs CTA observation. * * Attaches an empty event list to CTA observation. The method also sets the * pointing direction using the m_ra and m_dec members, the ROI based on * m_ra, m_dec and m_rad, a single GTI based on m_tmin and m_tmax, and a * single energy boundary based on m_emin and m_emax. The method furthermore * sets the ontime, livetime and deadtime correction factor. ***************************************************************************/ void ctobssim::set_list(GCTAObservation* obs) { // Continue only if observation is valid if (obs != NULL) { // Get CTA observation parameters m_ra = (*this)["ra"].real(); m_dec = (*this)["dec"].real(); m_rad = (*this)["rad"].real(); m_tmin = (*this)["tmin"].real(); m_tmax = (*this)["tmax"].real(); m_emin = (*this)["emin"].real(); m_emax = (*this)["emax"].real(); m_deadc = (*this)["deadc"].real(); // Allocate CTA event list GCTAEventList events; // Set pointing direction GCTAPointing pnt; GSkyDir skydir; skydir.radec_deg(m_ra, m_dec); pnt.dir(skydir); // Set ROI GCTAInstDir instdir(skydir); GCTARoi roi(instdir, m_rad); // Set GTI GGti gti(m_cta_ref); GTime tstart; GTime tstop; tstart.set(m_tmin, m_cta_ref); tstop.set(m_tmax, m_cta_ref); gti.append(tstart, tstop); // Set energy boundaries GEbounds ebounds; GEnergy emin; GEnergy emax; emin.TeV(m_emin); emax.TeV(m_emax); ebounds.append(emin, emax); // Set CTA event list attributes events.roi(roi); events.gti(gti); events.ebounds(ebounds); // Attach event list to CTA observation obs->events(events); // Set observation ontime, livetime and deadtime correction factor obs->ontime(gti.ontime()); obs->livetime(gti.ontime()*m_deadc); obs->deadc(m_deadc); } // endif: oberservation was valid // Return return; }
/***********************************************************************//** * @brief Reduce Good Time Intervals to specified interval * * @param[in] tstart Start time of interval. * @param[in] tstop Stop time of interval. * * @exception GException::invalid_argument * Start time is later than stop time * * Reduces the Good Time Intervals to the specified interval. Reducing means * that all Good Time Intervals are dropped that fall outside the specified * interval [@p tstart, @p tstop], and Good Time Intervals will be limited * to >@p tstart and <=@p tstop in case that their boundaries are outside * [@p tstart, @p tstop]. ***************************************************************************/ void GGti::reduce(const GTime& tstart, const GTime& tstop) { // Throw an exception if time interval is invalid if (tstart > tstop) { std::string msg = "Invalid time interval specified. Start time "+ tstart.print(NORMAL)+" can not be later than " "stop time "+tstop.print(NORMAL)+"."; throw GException::invalid_argument(G_REDUCE, msg); } // Adjust existing GTIs. This will limit all GTIs to [tstart,tstop]. // All GTIs outside [tstart,tstop] will have start > stop. The number // of valid GTIs will also be determined. int num = 0; for (int i = 0; i < m_num; ++i) { if (m_start[i] < tstart) { m_start[i] = tstart; } if (m_stop[i] > tstop) { m_stop[i] = tstop; } if (m_start[i] <= m_stop[i]) { num++; } } // If we still have valid GTIs then allocate memory for them, copy // over the start and stop times, and update the attributes if (num > 0) { // Allocate new intervals GTime* start = new GTime[num]; GTime* stop = new GTime[num]; // Copy valid intervals for (int i = 0; i < m_num; ++i) { if (m_start[i] <= m_stop[i]) { start[i] = m_start[i]; stop[i] = m_stop[i]; } } // Free old memory if (m_start != NULL) delete [] m_start; if (m_stop != NULL) delete [] m_stop; // Set new memory m_start = start; m_stop = stop; // Set attributes m_num = num; set_attributes(); } // endif: there were still valid GTIs // ... otherwise we remove all GTIs else { clear(); } // Return return; }