/***********************************************************************//** * @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 Performs error computation by using a bisection method * * @param[in] min Minimum parameter value * @param[in] max Maximum parameter value * * This method calculates the error using a bisection method. ***************************************************************************/ double cterror::error_bisection(const double& min, const double& max) { // Copy values to working values double wrk_min = min; double wrk_max = max; // Initialise iteration counter int iter = 1; // Initialize mid value double mid = (wrk_min + wrk_max) / 2.0; // Loop until breaking condition is reached while (true) { // Throw exception if maximum iterations are reached if (iter > m_max_iter) { if (wrk_min - m_model_par->factor_min() < m_tol) { std::string msg = "The \""+m_model_par->name()+"\" parameter " "minimum has been reached during error " "calculation. To obtain accurate errors, " "consider setting the minimum parameter " "value to a lower value, and re-run " "cterror."; if (logTerse()) { log << msg; } break; } else if (m_model_par->factor_max() - wrk_max < m_tol) { std::string msg = "The \""+m_model_par->name()+"\" parameter " "maximum has been reached during error " "calculation. To obtain accurate errors, " "consider setting the maximum parameter " "value to a higher value, and re-run " "cterror."; if (logTerse()) { log << msg; } break; } else { std::string msg = "The maximum number of "+ gammalib::str(m_max_iter)+" iterations has " "been reached. Please increase the " "\"max_iter\" parameter, and re-run " "cterror."; throw GException::invalid_value(G_ERR_BISECTION, msg); } } // Compute center of boundary mid = (wrk_min + wrk_max) / 2.0; // Calculate function value double eval_mid = evaluate(mid); // Log interval if (logExplicit()) { log << gammalib::parformat(" Iteration "+gammalib::str(iter)); log << "["; log << wrk_min; log << ", "; log << wrk_max; log << "] "; log << eval_mid; log << std::endl; } // Check for convergence inside tolerance if (std::abs(eval_mid) < m_tol) { break; } // Check if interval is smaller than 1.0e-6 if (std::abs(wrk_max-wrk_min) < 1.0e-6) { break; } // If we are on the crescent side of the parabola ... if (mid > m_value) { // Change boundaries for further iteration if (eval_mid > 0.0) { wrk_max = mid; } else if (eval_mid < 0.0) { wrk_min = mid; } } // ... otherwise we are on the decrescent side of the parabola else { // Change boundaries for further iteration if (eval_mid > 0.0) { wrk_min = mid; } else if (eval_mid < 0.0) { wrk_max = mid; } } // Increment counter iter++; } // endwhile // Return mid value return mid; }
/***********************************************************************//** * @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 Fill events into counts cube * * @param[in] obs CTA observation. * * @exception GException::invalid_value * No event list found in observation. * * Fills the events from an event list in the counts cube setup by init_cube. ***************************************************************************/ void ctbin::fill_cube(GCTAObservation* obs) { // Continue only if observation pointer is valid if (obs != NULL) { // Make sure that the observation holds a CTA event list. If this // is not the case then throw an exception. const GCTAEventList* events = dynamic_cast<const GCTAEventList*>(obs->events()); if (events == NULL) { std::string msg = "CTA Observation does not contain an event " "list. Event list information is needed to " "fill the counts map."; throw GException::invalid_value(G_FILL_CUBE, msg); } // Get the RoI const GCTARoi& roi = events->roi(); // Initialise binning statistics int num_outside_roi = 0; int num_outside_map = 0; int num_outside_ebds = 0; int num_in_map = 0; // Fill sky map for (int i = 0; i < events->size(); ++i) { // Get event const GCTAEventAtom* event = (*events)[i]; // Determine sky pixel GCTAInstDir* inst = (GCTAInstDir*)&(event->dir()); GSkyDir dir = inst->dir(); GSkyPixel pixel = m_cube.dir2pix(dir); // Skip if pixel is outside RoI if (roi.centre().dir().dist_deg(dir) > roi.radius()) { num_outside_roi++; continue; } // Skip if pixel is out of range if (pixel.x() < -0.5 || pixel.x() > (m_cube.nx()-0.5) || pixel.y() < -0.5 || pixel.y() > (m_cube.ny()-0.5)) { num_outside_map++; continue; } // Determine energy bin. Skip if we are outside the energy range int index = m_ebounds.index(event->energy()); if (index == -1) { num_outside_ebds++; continue; } // Fill event in skymap m_cube(pixel, index) += 1.0; num_in_map++; } // endfor: looped over all events // Append GTIs m_gti.extend(events->gti()); // Update ontime and livetime m_ontime += obs->ontime(); m_livetime += obs->livetime(); // Log filling results if (logTerse()) { log << gammalib::parformat("Events in list"); log << obs->events()->size() << std::endl; log << gammalib::parformat("Events in cube"); log << num_in_map << std::endl; log << gammalib::parformat("Event bins outside RoI"); log << num_outside_roi << std::endl; log << gammalib::parformat("Events outside cube area"); log << num_outside_map << std::endl; log << gammalib::parformat("Events outside energy bins"); log << num_outside_ebds << std::endl; } // Log cube if (logExplicit()) { log.header1("Counts cube"); log << m_cube << std::endl; } } // endif: observation was valid // Return return; }
/***********************************************************************//** * @brief Fill model into model cube * * @param[in] obs CTA observation. * * Adds the expected number of events for a given observation to the events * that are already found in the model cube. The method also updates the * GTI of the model cube so that cube GTI is a list of the GTIs of all * observations that were used to generate the model cube. ***************************************************************************/ void ctmodel::fill_cube(const GCTAObservation* obs) { // Continue only if observation pointer is valid if (obs != NULL) { // Get GTI and energy boundaries references for observation const GGti& gti = obs->events()->gti(); const GEbounds& obs_ebounds = obs->ebounds(); // Get cube energy boundaries const GEbounds& cube_ebounds = m_cube.ebounds(); // Initialise empty, invalid RoI GCTARoi roi; // Retrieve RoI in case we have an unbinned observation if (obs->eventtype() == "EventList") { roi = obs->roi(); } // Initialise statistics double sum = 0.0; int num_outside_ebds = 0; int num_outside_roi = 0; // Setup cube GTIs for this observation m_cube.gti(obs->events()->gti()); // Loop over all cube bins for (int i = 0; i < m_cube.size(); ++i) { // Get cube bin GCTAEventBin* bin = m_cube[i]; // Skip bin if it is outside the energy range of the observation int index = cube_ebounds.index(bin->energy()); if (index == -1 || !obs_ebounds.contains(cube_ebounds.emin(index)+g_energy_margin, cube_ebounds.emax(index)-g_energy_margin)) { num_outside_ebds++; continue; } // Check if RoI is valid, i.e. check if we have an unbinned // observation if (roi.is_valid()) { // Skip bin if it is outside the RoI of the observation if (!roi.contains(*bin)) { num_outside_roi++; continue; } } // endif: RoI was not valid // Get actual bin value double value = bin->counts(); // Compute model value for cube bin double model = m_obs.models().eval(*bin, *obs) * bin->size(); // Add model to actual value value += model; sum += model; // Store value bin->counts(value); } // endfor: looped over all cube bins // Append GTIs of observation to list of GTIs m_gti.extend(gti); // Update GTIs m_cube.gti(m_gti); // Log results if (logTerse()) { log << gammalib::parformat("Model events in cube"); log << sum << std::endl; log << gammalib::parformat("Bins outside energy range"); log << num_outside_ebds << std::endl; log << gammalib::parformat("Bins outside RoI"); log << num_outside_roi << std::endl; } // Log cube if (logExplicit()) { log.header2("Model cube"); log << m_cube << std::endl; } } // endif: observation was valid // Return return; }
/***********************************************************************//** * @brief Select events * * @param[in] obs CTA observation. * @param[in] filename File name. * * Select events from a FITS file by making use of the selection possibility * of the cfitsio library on loading a file. A selection string is created * from the specified criteria that is appended to the filename so that * cfitsio will automatically filter the event data. This selection string * is then applied when opening the FITS file. The opened FITS file is then * saved into a temporary file which is the loaded into the actual CTA * observation, overwriting the old CTA observation. The ROI, GTI and EBounds * of the CTA event list are then set accordingly to the specified selection. * Finally, the temporary file created during this process is removed. * * Good Time Intervals of the observation will be limited to the time * interval [m_tmin, m_tmax]. If m_tmin=m_tmax=0, no time selection is * performed. * * @todo Use INDEF instead of 0.0 for pointing as RA/DEC selection ***************************************************************************/ void ctselect::select_events(GCTAObservation* obs, const std::string& filename) { // Allocate selection string std::string selection; char cmin[80]; char cmax[80]; char cra[80]; char cdec[80]; char crad[80]; // Set requested selections bool select_time = (m_tmin != 0.0 || m_tmax != 0.0); // Set RA/DEC selection double ra = m_ra; double dec = m_dec; if (m_usepnt) { const GCTAPointing *pnt = obs->pointing(); ra = pnt->dir().ra_deg(); dec = pnt->dir().dec_deg(); } // Set time selection interval. We make sure here that the time selection // interval cannot be wider than the GTIs covering the data. This is done // using GGti's reduce() method. if (select_time) { // Reduce GTIs to specified time interval. The complicated cast is // necessary here because the gti() method is declared const, so // we're not officially allowed to modify the GTIs. ((GGti*)(&obs->events()->gti()))->reduce(m_timemin, m_timemax); } // endif: time selection was required // Save GTI for later usage GGti gti = obs->events()->gti(); // Make time selection if (select_time) { // Extract effective time interval in CTA reference time. We need // this reference for filtering. double tmin = gti.tstart().convert(m_cta_ref); double tmax = gti.tstop().convert(m_cta_ref); // Format time with sufficient accuracy and add to selection string sprintf(cmin, "%.8f", tmin); sprintf(cmax, "%.8f", tmax); selection = "TIME >= "+std::string(cmin)+" && TIME <= "+std::string(cmax); if (logTerse()) { log << parformat("Time range"); log << tmin << " - " << tmax << " s" << std::endl; } if (selection.length() > 0) { selection += " && "; } } // Make energy selection sprintf(cmin, "%.8f", m_emin); sprintf(cmax, "%.8f", m_emax); selection += "ENERGY >= "+std::string(cmin)+" && ENERGY <= "+std::string(cmax); if (logTerse()) { log << parformat("Energy range"); log << m_emin << " - " << m_emax << " TeV" << std::endl; } if (selection.length() > 0) { selection += " && "; } // Make ROI selection sprintf(cra, "%.6f", ra); sprintf(cdec, "%.6f", dec); sprintf(crad, "%.6f", m_rad); selection += "ANGSEP("+std::string(cra)+"," + std::string(cdec)+",RA,DEC) <= " + std::string(crad); if (logTerse()) { log << parformat("Acceptance cone centre"); log << "RA=" << ra << ", DEC=" << dec << " deg" << std::endl; log << parformat("Acceptance cone radius"); log << m_rad << " deg" << std::endl; } if (logTerse()) { log << parformat("cfitsio selection"); log << selection << std::endl; } // Add additional expression if (strip_whitespace(m_expr).length() > 0) { if (selection.length() > 0) { selection += " && "; } selection += "("+strip_whitespace(m_expr)+")"; } // Build input filename including selection expression std::string expression = filename; if (selection.length() > 0) expression += "[EVENTS]["+selection+"]"; if (logTerse()) { log << parformat("FITS filename"); log << expression << std::endl; } // Open FITS file GFits file(expression); // Log selected FITS file if (logExplicit()) { log << std::endl; log.header1("FITS file content after selection"); log << file << std::endl; } // Check if we have an EVENTS HDU if (!file.hashdu("EVENTS")) { std::string message = "No \"EVENTS\" extension found in FITS file "+ expression+"."; throw GException::app_error(G_SELECT_EVENTS, message); } // Determine number of events in EVENTS HDU int nevents = file.table("EVENTS")->nrows(); // If the selected event list is empty then append an empty event list // to the observation. Otherwise load the data from the temporary file. if (nevents < 1) { // Create empty event list GCTAEventList eventlist; // Append list to observation obs->events(&eventlist); } else { // Get temporary file name std::string tmpname = std::tmpnam(NULL); // Save FITS file to temporary file file.saveto(tmpname, true); // Load observation from temporary file obs->load_unbinned(tmpname); // Remove temporary file std::remove(tmpname.c_str()); } // Get CTA event list pointer GCTAEventList* list = static_cast<GCTAEventList*>(const_cast<GEvents*>(obs->events())); // Set ROI GCTARoi roi; GCTAInstDir instdir; instdir.radec_deg(ra, dec); roi.centre(instdir); roi.radius(m_rad); list->roi(roi); // Set GTI list->gti(gti); // Set energy boundaries GEbounds ebounds; GEnergy emin; GEnergy emax; emin.TeV(m_emin); emax.TeV(m_emax); ebounds.append(emin, emax); list->ebounds(ebounds); // Recompute ontime and livetime. GTime meantime = 0.5 * (gti.tstart() + gti.tstop()); obs->ontime(gti.ontime()); obs->livetime(gti.ontime() * obs->deadc(meantime)); // Return return; }
/***********************************************************************//** * @brief Select event data * * This method reads in the application parameters and loops over all * observations that were found to perform an event selection. Event * selection is done by writing each observation to a temporary file and * re-opening the temporary file using the cfitsio event filter syntax. * The temporary file is deleted after this action so that no disk overflow * will occur. ***************************************************************************/ void ctselect::run(void) { // Switch screen logging on in debug mode if (logDebug()) { log.cout(true); } // Get parameters get_parameters(); // Write parameters into logger if (logTerse()) { log_parameters(); log << std::endl; } // Write observation(s) into logger if (logTerse()) { log << std::endl; log.header1("Observations before selection"); log << m_obs << std::endl; } // Write header if (logTerse()) { log << std::endl; log.header1("Event selection"); } // Initialise counters int n_observations = 0; // Loop over all observation in the container for (int i = 0; i < m_obs.size(); ++i) { // Initialise event input and output filenames m_infiles.push_back(""); // Get CTA observation GCTAObservation* obs = dynamic_cast<GCTAObservation*>(&m_obs[i]); // Continue only if observation is a CTA observation if (obs != NULL) { // Write header for observation if (logTerse()) { if (obs->name().length() > 1) { log.header3("Observation "+obs->name()); } else { log.header3("Observation"); } } // Increment counter n_observations++; // Save event file name (for possible saving) m_infiles[i] = obs->eventfile(); // Get temporary file name std::string filename = std::tmpnam(NULL); // Save observation in temporary file obs->save(filename, true); // Log saved FITS file if (logExplicit()) { GFits tmpfile(filename); log << std::endl; log.header1("FITS file content of temporary file"); log << tmpfile << std::endl; tmpfile.close(); } // Check temporary file std::string message = check_infile(filename); if (message.length() > 0) { throw GException::app_error(G_RUN, message); } // Load observation from temporary file, including event selection select_events(obs, filename); // Remove temporary file std::remove(filename.c_str()); } // endif: had a CTA observation } // endfor: looped over all observations // If more than a single observation has been handled then make sure that // an XML file will be used for storage if (n_observations > 1) { m_use_xml = true; } // Write observation(s) into logger if (logTerse()) { log << std::endl; log.header1("Observations after selection"); log << m_obs << std::endl; } // Return return; }