/***********************************************************************//** * @brief Set position of radial spatial model ***************************************************************************/ void GModelSpatialRadial::dir(const GSkyDir& dir) { // Assign Right Ascension and Declination m_ra.value(dir.ra_deg()); m_dec.value(dir.dec_deg()); // Return return; }
/***********************************************************************//** * @brief Read model from XML element * * @param[in] xml XML element. * * @exception GException::model_invalid_parnum * Invalid number of model parameters found in XML element. * @exception GException::model_invalid_parnames * Invalid model parameter names found in XML element. * * Reads the elliptical source location and position angle information from * an XML element in the following format * * <spatialModel type="..."> * <parameter name="RA" scale="1" value="83.63" min="-360" max="360" free="1"/> * <parameter name="DEC" scale="1" value="22.01" min="-90" max="90" free="1"/> * <parameter name="PA" scale="1" value="45.0" min="-360" max="360" free="1"/> * ... * </spatialModel> * * or * * <spatialModel type="..."> * <parameter name="GLON" scale="1" value="83.63" min="-360" max="360" free="1"/> * <parameter name="GLAT" scale="1" value="22.01" min="-90" max="90" free="1"/> * <parameter name="PA" scale="1" value="45.0" min="-360" max="360" free="1"/> * ... * </spatialModel> * ***************************************************************************/ void GModelSpatialElliptical::read(const GXmlElement& xml) { // Read RA/DEC parameters if (gammalib::xml_has_par(xml, "RA") && gammalib::xml_has_par(xml, "DEC")) { // Get parameters const GXmlElement* ra = gammalib::xml_get_par(G_READ, xml, "RA"); const GXmlElement* dec = gammalib::xml_get_par(G_READ, xml, "DEC"); // Read parameters m_ra.read(*ra); m_dec.read(*dec); } // ... otherwise read GLON/GLAT parameters else { // Get parameters const GXmlElement* glon = gammalib::xml_get_par(G_READ, xml, "GLON"); const GXmlElement* glat = gammalib::xml_get_par(G_READ, xml, "GLAT"); // Read parameters m_ra.read(*glon); m_dec.read(*glat); // Convert into RA/DEC GSkyDir dir; dir.lb_deg(ra(), dec()), m_ra.value(dir.ra_deg()); m_dec.value(dir.dec_deg()); // Set names to RA/DEC m_ra.name("RA"); m_dec.name("DEC"); } // Get other parameters const GXmlElement* pa = gammalib::xml_get_par(G_READ, xml, m_posangle.name()); // Read other parameters m_posangle.read(*pa); // 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 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 Read model from XML element * * @param[in] xml XML element. * * @exception GException::model_invalid_parnum * Invalid number of model parameters found in XML element. * @exception GException::model_invalid_parnames * Invalid model parameter names found in XML element. * * Reads the radial source location and position angle information from an * XML element in the following format * * <spatialModel type="..."> * <parameter name="RA" scale="1" value="83.63" min="-360" max="360" free="1"/> * <parameter name="DEC" scale="1" value="22.01" min="-90" max="90" free="1"/> * ... * </spatialModel> * * or * * <spatialModel type="..."> * <parameter name="GLON" scale="1" value="83.63" min="-360" max="360" free="1"/> * <parameter name="GLAT" scale="1" value="22.01" min="-90" max="90" free="1"/> * ... * </spatialModel> * ***************************************************************************/ void GModelSpatialRadial::read(const GXmlElement& xml) { // Determine number of parameter nodes in XML element int npars = xml.elements("parameter"); // Verify that XML element has at least 2 parameters if (xml.elements() < 2 || npars < 2) { throw GException::model_invalid_parnum(G_READ, xml, "Radial model requires at least 2 parameters."); } // Extract model parameters bool has_glon = false; bool has_glat = false; int npar[2] = {0, 0}; for (int i = 0; i < npars; ++i) { // Get parameter element const GXmlElement* par = xml.element("parameter", i); // Handle RA/GLON if (par->attribute("name") == "RA") { m_ra.read(*par); npar[0]++; } else if (par->attribute("name") == "GLON") { m_ra.read(*par); npar[0]++; has_glon = true; } // Handle DEC/GLAT else if (par->attribute("name") == "DEC") { m_dec.read(*par); npar[1]++; } else if (par->attribute("name") == "GLAT") { m_dec.read(*par); npar[1]++; has_glat = true; } } // endfor: looped over all parameters // Check if we have to convert GLON/GLAT into RA/DEC if (has_glon && has_glat) { GSkyDir dir; dir.lb_deg(ra(), dec()), m_ra.value(dir.ra_deg()); m_dec.value(dir.dec_deg()); } else if (has_glon || has_glat) { throw GException::model_invalid_parnames(G_READ, xml, "Require either \"RA\"/\"DEC\" or \"GLON\"/\"GLAT\"."); } // Verify that all parameters were found if (npar[0] != 1 || npar[1] != 1) { throw GException::model_invalid_parnames(G_READ, xml, "Require \"RA\"/\"DEC\" and \"GLON\"/\"GLAT\" parameters."); } // 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 Create output observation container. * * Creates an output observation container that combines all input CTA * observation into a single cube-style observation. All non CTA observations * present in the observation container are kept. The method furthermore * conserves any response information in case that a single CTA observation * is provided. This supports the original binned analysis. ***************************************************************************/ void ctbin::obs_cube(void) { // If we have only a single CTA observation in the container, then // keep that observation and just attach the event cube to it. Reset // the filename, otherwise we still will have the old event filename // in the log file. if (m_obs.size() == 1) { // Attach event cube to CTA observation GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[0]); if (obs != NULL) { obs->events(this->cube()); obs->eventfile(""); } } // ... otherwise put a single CTA observation in container else { // Allocate observation container GObservations container; // Allocate CTA observation. GCTAObservation obs; // Attach event cube to CTA observation obs.events(this->cube()); // Set map centre as pointing GSkyPixel pixel(0.5*double(m_cube.nx()), 0.5*double(m_cube.ny())); GSkyDir centre = m_cube.pix2dir(pixel); GCTAPointing pointing(centre); // Compute deadtime correction double deadc = (m_ontime > 0.0) ? m_livetime / m_ontime : 0.0; // Set CTA observation attributes obs.pointing(pointing); obs.obs_id(0); obs.ra_obj(centre.ra_deg()); //!< Dummy obs.dec_obj(centre.dec_deg()); //!< Dummy obs.ontime(m_ontime); obs.livetime(m_livetime); obs.deadc(deadc); // Set models in observation container container.models(m_obs.models()); // Append CTA observation container.append(obs); // Copy over all remaining non-CTA observations for (int i = 0; i < m_obs.size(); ++i) { GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); if (obs == NULL) { container.append(*m_obs[i]); } } // Set observation container m_obs = container; } // endelse: there was not a single CTA observation // Return return; }