/***********************************************************************//** * @brief Set exposure cube from one CTA observation * * @param[in] obs CTA observation. * * Set the exposure cube from a single CTA observations. The cube pixel * values are computed as product of the effective area and the livetime. * * @todo: Throw an exception if response is not valid ***************************************************************************/ void GCTACubeExposure::set(const GCTAObservation& obs) { // Clear GTIs, reset livetime and exposure cube pixels m_gti.clear(); m_livetime = 0.0; m_cube = 0.0; // Extract region of interest from CTA observation GCTARoi roi = obs.roi(); // Get references on CTA response and pointing direction const GCTAResponseIrf* rsp = dynamic_cast<const GCTAResponseIrf*>(obs.response()); const GSkyDir& pnt = obs.pointing().dir(); // Continue only if response is valid if (rsp != NULL) { // Loop over all pixels in sky map for (int pixel = 0; pixel < m_cube.npix(); ++pixel) { // Get pixel sky direction GSkyDir dir = m_cube.inx2dir(pixel); // Continue only if pixel is within RoI if (roi.centre().dir().dist_deg(dir) <= roi.radius()) { // Compute theta angle with respect to pointing direction // in radians double theta = pnt.dist(dir); // Loop over all exposure cube energy bins for (int iebin = 0; iebin < m_ebounds.size(); ++iebin){ // Get logE/TeV double logE = m_ebounds.elogmean(iebin).log10TeV(); // Set exposure cube (effective area * lifetime) m_cube(pixel, iebin) = rsp->aeff(theta, 0.0, 0.0, 0.0, logE) * obs.livetime(); } // endfor: looped over energy bins } // endif: pixel was within RoI } // endfor: looped over all pixels // Append GTIs and increment livetime m_gti.extend(obs.gti()); m_livetime += obs.livetime(); } // endif: response was valid // Return return; }
/***********************************************************************//** * @brief Test CTA Npred computation * * Tests the Npred computation for the diffuse source model. This is done * by loading the model from the XML file and by calling the * GCTAObservation::npred method which in turn calls the * GCTAResponse::npred_diffuse method. The test takes a few seconds. ***************************************************************************/ void TestGCTAResponse::test_response_npred_diffuse(void) { // Set reference value double ref = 11212.26274; // Set parameters double src_ra = 201.3651; double src_dec = -43.0191; double roi_rad = 4.0; // Setup ROI centred on Cen A with a radius of 4 deg GCTARoi roi; GCTAInstDir instDir; instDir.radec_deg(src_ra, src_dec); roi.centre(instDir); roi.radius(roi_rad); // Setup pointing on Cen A GSkyDir skyDir; skyDir.radec_deg(src_ra, src_dec); GCTAPointing pnt; pnt.dir(skyDir); // Setup dummy event list GGti gti; GEbounds ebounds; GTime tstart(0.0); GTime tstop(1800.0); GEnergy emin; GEnergy emax; emin.TeV(0.1); emax.TeV(100.0); gti.append(tstart, tstop); ebounds.append(emin, emax); GCTAEventList events; events.roi(roi); events.gti(gti); events.ebounds(ebounds); // Setup dummy CTA observation GCTAObservation obs; obs.ontime(1800.0); obs.livetime(1600.0); obs.deadc(1600.0/1800.0); obs.response(cta_irf, cta_caldb); obs.events(&events); obs.pointing(pnt); // Load models for Npred computation GModels models(cta_rsp_xml); // Perform Npred computation double npred = obs.npred(models, NULL); // Test Npred test_value(npred, ref, 1.0e-5, "Diffuse Npred computation"); // Return return; }
/***********************************************************************//** * @brief Test CTA IRF computation for diffuse source model * * Tests the IRF computation for the diffuse source model. This is done * by calling the GCTAObservation::model method which in turn calls the * GCTAResponse::irf_diffuse method. The test is done for a small counts * map to keep the test executing reasonably fast. ***************************************************************************/ void TestGCTAResponse::test_response_irf_diffuse(void) { // Set reference value double ref = 13803.800313356; // Set parameters double src_ra = 201.3651; double src_dec = -43.0191; int nebins = 5; // Setup pointing on Cen A GSkyDir skyDir; skyDir.radec_deg(src_ra, src_dec); GCTAPointing pnt; pnt.dir(skyDir); // Setup skymap (10 energy layers) GSkymap map("CAR", "CEL", src_ra, src_dec, 0.5, 0.5, 10, 10, nebins); // Setup time interval GGti gti; GTime tstart(0.0); GTime tstop(1800.0); gti.append(tstart, tstop); // Setup energy boundaries GEbounds ebounds; GEnergy emin; GEnergy emax; emin.TeV(0.1); emax.TeV(100.0); ebounds.setlog(emin, emax, nebins); // Setup event cube centered on Cen A GCTAEventCube cube(map, ebounds, gti); // Setup dummy CTA observation GCTAObservation obs; obs.ontime(1800.0); obs.livetime(1600.0); obs.deadc(1600.0/1800.0); obs.response(cta_irf, cta_caldb); obs.events(&cube); obs.pointing(pnt); // Load model for IRF computation GModels models(cta_rsp_xml); // Reset sum double sum = 0.0; // Iterate over all bins in event cube for (int i = 0; i < obs.events()->size(); ++i) { // Get event pointer const GEventBin* bin = (*(static_cast<const GEventCube*>(obs.events())))[i]; // Get model and add to sum double model = obs.model(models, *bin, NULL) * bin->size(); sum += model; } // Test sum test_value(sum, ref, 1.0e-5, "Diffuse IRF computation"); // Return return; }
/***********************************************************************//** * @brief Setup observation container * * @exception GException::no_cube * No event cube found in CTA observation. * * This method sets up the observation container for processing. There are * two cases: * * If there are no observations in the actual observation container, the * method will check in "infile" parameter. If this parameter is "NONE" or * empty, the task parameters will be used to construct a model map. * Otherwise, the method first tries to interpret the "infile" parameter as * a counts map, and attemps loading of the file in an event cube. If this * fails, the method tries to interpret the "infile" parameter as an * observation definition XML file. If this also fails, an exception will * be thrown. * * If observations exist already in the observation container, the method * will simply keep them. * * Test if all CTA observations contain counts maps. * * Finally, if no models exist so far in the observation container, the * models will be loaded from the model XML file. ***************************************************************************/ void ctmodel::setup_obs(void) { // If there are no observations in the container then try to build some if (m_obs.size() == 0) { // If no input filename has been specified, then create a model map // from the task parameters if ((m_infile == "NONE") || (gammalib::strip_whitespace(m_infile) == "")) { // Set pointing direction GCTAPointing pnt; GSkyDir skydir; skydir.radec_deg(m_ra, m_dec); pnt.dir(skydir); // Setup energy range covered by model GEnergy emin(m_emin, "TeV"); GEnergy emax(m_emax, "TeV"); GEbounds ebds(m_enumbins, emin, emax); // Setup time interval covered by model GGti gti; GTime tmin(m_tmin); GTime tmax(m_tmax); gti.append(tmin, tmax); // Setup skymap GSkymap map = GSkymap(m_proj, m_coordsys, m_xref, m_yref, -m_binsz, m_binsz, m_nxpix, m_nypix, m_enumbins); // Create model cube from sky map GCTAEventCube cube(map, ebds, gti); // Allocate CTA observation GCTAObservation obs; // Set CTA observation attributes obs.pointing(pnt); obs.ontime(gti.ontime()); obs.livetime(gti.ontime()*m_deadc); obs.deadc(m_deadc); // Set event cube in observation obs.events(cube); // Append CTA observation to container m_obs.append(obs); // Signal that no XML file should be used for storage m_use_xml = false; } // endif: created model map from task parameters // ... otherwise try to load information from the file else { // First try to open the file as a counts map try { // Allocate CTA observation GCTAObservation obs; // Load counts map in CTA observation obs.load_binned(m_infile); // Append CTA observation to container m_obs.append(obs); // Signal that no XML file should be used for storage m_use_xml = false; } // ... otherwise try to open as XML file catch (GException::fits_open_error &e) { // Load observations from XML file. This will throw // an exception if it fails. m_obs.load(m_infile); // Signal that XML file should be used for storage m_use_xml = true; } } // endelse: loaded information from input file } // endif: there was no observation in the container // If there are no models associated with the observations then // load now the model definition from the XML file if (m_obs.models().size() == 0) { m_obs.models(GModels(m_srcmdl)); } // Check if all CTA observations contain an event cube and setup response // for all observations for (int i = 0; i < m_obs.size(); ++i) { // Is this observation a CTA observation? GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]); // Yes ... if (obs != NULL) { // Throw an exception if this observation does not contain // an event cube if (dynamic_cast<const GCTAEventCube*>(obs->events()) == NULL) { throw GException::no_cube(G_SETUP_OBS); } // Set response if it isn't set already if (obs->response().aeff() == NULL) { // Set calibration database. If specified parameter is a // directory then use this as the pathname to the calibration // database. Otherwise interpret this as the instrument name, // the mission being "cta" GCaldb caldb; if (gammalib::dir_exists(m_caldb)) { caldb.rootdir(m_caldb); } else { caldb.open("cta", m_caldb); } // Set reponse obs->response(m_irf, caldb); } // endif: observation already has a response } // endif: observation was a CTA observation } // endfor: looped over all observations // 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; }