/***********************************************************************//** * @brief Save event list into FITS file * * @param[in] obs Pointer to CTA observation. * @param[in] infile Input file name. * @param[in] outfile Output file name. * * Saves an event list into a FITS file and copy all others extensions from * the input file to the output file. ***************************************************************************/ void ctselect::save_event_list(const GCTAObservation* obs, const std::string& infile, const std::string& outfile) const { // Save only if observation is valid if (obs != NULL) { // Save observation into FITS file obs->save(outfile, clobber()); // Copy all extensions other than EVENTS and GTI from the input to // the output event list. The EVENTS and GTI extensions are written // by the save method, all others that may eventually be present // have to be copied by hand. GFits infits(infile); GFits outfits(outfile); for (int extno = 1; extno < infits.size(); ++extno) { GFitsHDU* hdu = infits.hdu(extno); if (hdu->extname() != "EVENTS" && hdu->extname() != "GTI") { outfits.append(*hdu); } } // Close input file infits.close(); // Save file to disk and close it (we need both operations) outfits.save(true); outfits.close(); } // endif: observation was valid // Return return; }
/***********************************************************************//** * @brief Read exposure attributes * * @param[in] hdu FITS HDU. * * Reads CTA exposure attributes from the HDU. ***************************************************************************/ void GCTACubeExposure::read_attributes(const GFitsHDU& hdu) { // Read mandatory attributes m_livetime = (hdu.has_card("LIVETIME")) ? hdu.real("LIVETIME") : 0.0; // Return return; }
/***********************************************************************//** * @brief Return Good Time Intervals extension name from data sub-space keywords * * @param[in] hdu FITS HDU * @return Good Time Interval extension name * * @exception GException::invalid_value * Invalid Good Time Intervals data sub-space encountered * * Returns the name of the FITS extension that contains the Good Time * Intervals by screening the data sub-space keywords that are present in * the FITS header. The method searches for a DSTYPx keyword named "TIME" * and a corresponding DSVALx keyword named "TABLE", and the extension name * is extracted from the corresponding DSREFx keyword. Note that by * convention the extension name is preceeded by a colon, which is stripped * by this method. ***************************************************************************/ std::string gammalib::read_ds_gti_extname(const GFitsHDU& hdu) { // Initialise extension name std::string extname; // Get number of data sub-space keys (default to 0 if "NDSKEYS" keyword // is not found) int ndskeys = (hdu.has_card("NDSKEYS")) ? hdu.integer("NDSKEYS") : 0; // Loop over all data sub-space keys for (int i = 1; i <= ndskeys; ++i) { // Set data sub-space key strings std::string type_key = "DSTYP"+gammalib::str(i); std::string unit_key = "DSUNI"+gammalib::str(i); std::string value_key = "DSVAL"+gammalib::str(i); std::string ref_key = "DSREF"+gammalib::str(i); // Skip if DSTYPi keyword does not exist, or if it is not "TIME" if (!hdu.has_card(type_key) || hdu.string(type_key) != "TIME") { continue; } // If DSVALi keyword does not exist or if it's value is not // "TABLE" then throw an exception if (!hdu.has_card(value_key)) { std::string msg = "Keyword \""+value_key+"\" missing for data " "sub-space selection of type "+type_key+ "=\"TIME\". Please correct FITS header."; throw GException::invalid_value(G_READ_DS_GTI, msg); } if (hdu.string(value_key) != "TABLE") { std::string msg = "Cannot interpret keyword \""+value_key+"\" " "value \""+hdu.string(value_key)+"\". Only " "the value \"TABLE\" is supported."; throw GException::invalid_value(G_READ_DS_GTI, msg); } // If DSREFi keyword does not exist then throw an exception if (!hdu.has_card(ref_key)) { std::string msg = "Keyword \""+ref_key+"\" missing for data " "sub-space selection of type "+type_key+ "=\"TIME\". Please correct FITS header."; throw GException::invalid_value(G_READ_DS_GTI, msg); } // Get extension name (strip any leading and trailing colons) extname = gammalib::strip_whitespace(gammalib::strip_chars(hdu.string(ref_key), ":")); } // endfor: looped over data sub-space keywords // Return return extname; }
/***********************************************************************//** * @brief Extract ROI from data sub-space keywords * * @param[in] hdu FITS HDU * * @exception GException::invalid_value * Invalid ROI data sub-space encountered * * Reads the ROI data sub-space keywords by searching for a DSTYPx keyword * named "POS(RA,DEC)". The data sub-space information is expected to be in * the format "CIRCLE(267.0208,-24.78,4.5)", where the 3 arguments are Right * Ascension, Declination and radius in units of degrees. No detailed syntax * checking is performed. * * If no ROI information has been found, an GCTARoi object with initial * values will be returned. ***************************************************************************/ GCTARoi gammalib::read_ds_roi(const GFitsHDU& hdu) { // Initialise ROI GCTARoi roi; // Get number of data sub-space keywords (default to 0 if keyword is // not found) int ndskeys = (hdu.has_card("NDSKEYS")) ? hdu.integer("NDSKEYS") : 0; // Loop over all data selection keys for (int i = 1; i <= ndskeys; ++i) { // Set data sub-space key strings std::string type_key = "DSTYP"+gammalib::str(i); //std::string unit_key = "DSUNI"+gammalib::str(i); std::string value_key = "DSVAL"+gammalib::str(i); // Continue only if type_key is found and if this key is POS(RA,DEC) if (hdu.has_card(type_key) && hdu.string(type_key) == "POS(RA,DEC)") { // ... //std::string unit = gammalib::toupper(hdu.string(unit_key)); std::string value = hdu.string(value_key); std::string value_proc = gammalib::strip_chars(value, "CIRCLE("); value_proc = gammalib::strip_chars(value_proc, ")"); std::vector<std::string> args = gammalib::split(value_proc, ","); if (args.size() == 3) { double ra = gammalib::todouble(args[0]); double dec = gammalib::todouble(args[1]); double rad = gammalib::todouble(args[2]); GCTAInstDir dir; dir.dir().radec_deg(ra, dec); roi.centre(dir); roi.radius(rad); } else { std::string msg = "Invalid acceptance cone value \""+value+ "\" encountered in data sub-space " "key \""+value_key+"\"."; throw GException::invalid_value(G_READ_DS_ROI, msg); } } // endif: POS(RA,DEC) type found } // endfor: looped over data sub-space keys // Return roi return roi; }
/***********************************************************************//** * @brief Publish FITS HDU * * @param[in] hdu FITS HDU * * Publishes a FITS HDU. ***************************************************************************/ void GVOClient::publish(const GFitsHDU& hdu) { // Signal that client should be disconnected after sending the image // to Hub bool disconnected = !is_connected(); // Make sure that the client is connected to a Hub if (disconnected) { connect(); } // Save FITS HDU into a temporary file std::string samp_share = std::tmpnam(NULL); GFits fits; fits.append(hdu); fits.saveto(samp_share, true); // Get FITS extension name std::string extname = hdu.extname(); if (extname.empty()) { extname = "FITS Image"; } // Compose notification to be passed to the Hub std::string hub_command = ""; hub_command.append("<?xml version=\"1.0\"?>\n"); hub_command.append("<methodCall>\n"); hub_command.append(" <methodName>samp.hub.notifyAll</methodName>\n"); hub_command.append(" <params>\n"); hub_command.append(" <param><value>image.load.fits</value></param>\n"); hub_command.append(" <param><value>"+m_secret+"</value></param>\n"); hub_command.append(" <param><value><struct>\n"); hub_command.append(" <member><name>samp.params</name><value><struct>\n"); hub_command.append(" <member><name>name</name><value>"+extname+"</value></member>\n"); hub_command.append(" <member><name>url</name><value>file://localhost"+samp_share+"</value></member>\n"); hub_command.append(" <member><name>image-id</name><value>Gammalib Data</value></member>\n"); hub_command.append(" </struct></value></member>\n"); hub_command.append(" <member><name>samp.mtype</name><value>image.load.fits</value></member>\n"); hub_command.append(" </struct></value></param>\n"); hub_command.append(" </params>\n"); hub_command.append("</methodCall>\n"); // Send notification execute(hub_command); // Disconnect client from Hub if (disconnected) { disconnect(); } // Return return; }
/***********************************************************************//** * @brief Read energy boundary data sub-space keywords * * @param[in] hdu FITS HDU * * @exception GException::invalid_value * Invalid energy data sub-space encountered * * Reads the energy boundary data sub-space keywords by searching for a * DSTYPx keyword named "ENERGY". The data sub-space information is expected * to be in the format "200:50000", where the 2 arguments are the minimum * and maximum energy. The energy unit is given by the keyword DSUNIx, which * supports keV, MeV, GeV and TeV (case independent). No detailed syntax * checking is performed. ***************************************************************************/ GEbounds gammalib::read_ds_ebounds(const GFitsHDU& hdu) { // Initialise energy boundaries GEbounds ebounds; // Get number of data sub-space keywords (default to 0 if keyword is // not found) int ndskeys = (hdu.has_card("NDSKEYS")) ? hdu.integer("NDSKEYS") : 0; // Loop over all data sub-space keys for (int i = 1; i <= ndskeys; ++i) { // Set data sub-space key strings std::string type_key = "DSTYP"+gammalib::str(i); std::string unit_key = "DSUNI"+gammalib::str(i); std::string value_key = "DSVAL"+gammalib::str(i); // Continue only if type_key is found and if this key is ENERGY if (hdu.has_card(type_key) && hdu.string(type_key) == "ENERGY") { // Extract energy boundaries std::string value = hdu.string(value_key); std::string unit = hdu.string(unit_key); std::vector<std::string> values = gammalib::split(value, ":"); if (values.size() == 2) { double emin = gammalib::todouble(values[0]); double emax = gammalib::todouble(values[1]); GEnergy e_min(emin, unit); GEnergy e_max(emax, unit); ebounds.append(e_min, e_max); } else { std::string msg = "Invalid energy value \""+value+ "\" encountered in data selection key \""+ value_key+"\""; throw GException::invalid_value(G_READ_DS_EBOUNDS, msg); } } // endif: ENERGY type_key found } // endfor: looped over data selection keys // Return return ebounds; }
/***********************************************************************//** * @brief Write attributes to exposure extension * * @param[in] hdu FITS HDU. ***************************************************************************/ void GCTACubeExposure::write_attributes(GFitsHDU& hdu) const { // Compute some attributes double tstart = m_gti.tstart().convert(m_gti.reference()); double tstop = m_gti.tstop().convert(m_gti.reference()); double telapse = m_gti.telapse(); double ontime = m_gti.ontime(); double deadc = (ontime > 0.0 && m_livetime > 0.0) ? m_livetime / ontime : 1.0; std::string utc_obs = m_gti.tstart().utc(); std::string utc_end = m_gti.tstop().utc(); std::string date_obs = utc_obs.substr(0, 10); std::string time_obs = utc_obs.substr(11, 8); std::string date_end = utc_end.substr(0, 10); std::string time_end = utc_end.substr(11, 8); // Set observation information hdu.card("CREATOR", "GammaLib", "Program which created the file"); hdu.card("TELESCOP", "unknown", "Telescope"); hdu.card("OBS_ID", "unknown", "Observation identifier"); hdu.card("DATE_OBS", date_obs, "Observation start date"); hdu.card("TIME_OBS", time_obs, "Observation start time"); hdu.card("DATE_END", date_end, "Observation end date"); hdu.card("TIME_END", time_end, "Observation end time"); // Set observation time information hdu.card("TSTART", tstart, "[s] Mission time of start of observation"); hdu.card("TSTOP", tstop, "[s] Mission time of end of observation"); m_gti.reference().write(hdu); hdu.card("TELAPSE", telapse, "[s] Mission elapsed time"); hdu.card("ONTIME", ontime, "[s] Total good time including deadtime"); hdu.card("LIVETIME", m_livetime, "[s] Total livetime"); hdu.card("DEADC", deadc, "Deadtime correction factor"); hdu.card("TIMEDEL", 1.0, "Time resolution"); // Return return; }
/***********************************************************************//** * @brief Read data selection keywords from FITS HDU. * * @param[in] hdu FITS HDU pointer. * * @todo Declared header card const in to GFitsHDU. * @todo Add check key method to GFitsHDU to avoid unneccesary try/catch * blocks. ***************************************************************************/ void GLATEventList::read_ds_keys(const GFitsHDU& hdu) { // Get number of data selection keys int ds_num = hdu.integer("NDSKEYS"); // Get data selection keys if (ds_num > 0) { // Circumvent const correctness. We need this because the header() // card method is not declared const. This should be corrected. //GFitsHDU* ptr = (GFitsHDU*)&hdu; // Reserve space m_ds_type.reserve(ds_num); m_ds_unit.reserve(ds_num); m_ds_value.reserve(ds_num); m_ds_reference.reserve(ds_num); // Allocate space for the keyword char keyword[10]; // Get columns for (int i = 0; i < ds_num; ++i) { // Get DSTYPnn std::sprintf(keyword, "DSTYP%d", i+1); if (hdu.has_card(std::string(keyword))) { m_ds_type.push_back(hdu.string(std::string(keyword))); } else { m_ds_type.push_back(""); } // Get DSUNInn std::sprintf(keyword, "DSUNI%d", i+1); if (hdu.has_card(std::string(keyword))) { m_ds_unit.push_back(hdu.string(std::string(keyword))); } else { m_ds_unit.push_back(""); } // Get DSVALnn std::sprintf(keyword, "DSVAL%d", i+1); if (hdu.has_card(std::string(keyword))) { m_ds_value.push_back(hdu.string(std::string(keyword))); } else { m_ds_value.push_back(""); } // Get DSREFnn std::sprintf(keyword, "DSREF%d", i+1); if (hdu.has_card(std::string(keyword))) { m_ds_reference.push_back(hdu.string(std::string(keyword))); } else { m_ds_reference.push_back(""); } } // endfor: looped over data selection keys } // endif: there were data selection keys // Return return; }