/***********************************************************************//** * @brief Read Auxiliary Response File * * @param[in] table ARF FITS table. * * Reads the Auxiliary Response File from a FITS table. The true energy * boundaries are expected in the `ENERG_LO` and `ENERG_HI` columns, the * response information is expected in the `SPECRESP` column. * * The method will analyze the unit of the `SPECRESP` column, and if either * `m^2` or `m2` are encountered, multiply the values of the column by * \f$10^4\f$ to convert the response into units of \f$cm^2\f$. Units of the * `ENERG_LO` and `ENERG_HI` columns are also interpreted for conversion. * * See * http://heasarc.gsfc.nasa.gov/docs/heasarc/caldb/docs/memos/cal_gen_92_002/cal_gen_92_002.html#tth_sEc4 * for details about the Auxiliary Response File format. ***************************************************************************/ void GArf::read(const GFitsTable& table) { // Clear members clear(); // Get pointer to data columns const GFitsTableCol* energy_lo = table["ENERG_LO"]; const GFitsTableCol* energy_hi = table["ENERG_HI"]; const GFitsTableCol* specresp = table["SPECRESP"]; // Determine effective area conversion factor. Internal // units are cm^2 std::string u_specresp = gammalib::tolower(gammalib::strip_whitespace(specresp->unit())); double c_specresp = 1.0; if (u_specresp == "m^2" || u_specresp == "m2") { c_specresp = 10000.0; } // Extract number of energy bins int num = energy_lo->length(); // Set energy bins for (int i = 0; i < num; ++i) { // Append energy bin GEnergy emin(energy_lo->real(i), energy_lo->unit()); GEnergy emax(energy_hi->real(i), energy_hi->unit()); m_ebounds.append(emin, emax); // Append effective area value double aeff = specresp->real(i) * c_specresp; m_specresp.push_back(aeff); } // endfor: looped over energy bins // Read any additional columns for (int icol = 0; icol < table.ncols(); ++icol) { // Fall through if the column is a standard column std::string colname(table[icol]->name()); if ((colname == "ENERG_LO") || (colname == "ENERG_HI") || (colname == "SPECRESP")) { continue; } // Get pointer to column const GFitsTableCol* column = table[icol]; // Set column vector std::vector<double> coldata; for (int i = 0; i < num; ++i) { coldata.push_back(column->real(i)); } // Append column append(colname, coldata); } // endfor: looped over all additional columns // Return return; }
/***********************************************************************//** * @brief Read spectrum from FITS file * * @param[in] table FITS table. * * @exception GMWLException::bad_file_format * Table has invalid format * * Read spectrum from FITS table. The table is expected to be in one of the * three following formats: * 2 columns: energy, flux * 3 columns: energy, flux, e_flux * 4 columns or more: energy, e_energy, flux, e_flux, ... * * @todo Investigate whether we can exploit UCDs for identifying the correct * columns or for determining the units. ***************************************************************************/ void GMWLSpectrum::read_fits(const GFitsTable& table) { // Reset spectrum m_data.clear(); // Initialise column pointers columns const GFitsTableCol* c_energy = NULL; const GFitsTableCol* c_energy_err = NULL; const GFitsTableCol* c_flux = NULL; const GFitsTableCol* c_flux_err = NULL; // Extract column pointers if (table.ncols() == 2) { c_energy = table[0]; c_flux = table[1]; } else if (table.ncols() == 3) { c_energy = table[0]; c_flux = table[1]; c_flux_err = table[2]; } else if (table.ncols() > 3) { c_energy = table[0]; c_energy_err = table[1]; c_flux = table[2]; c_flux_err = table[3]; } else { throw GMWLException::bad_file_format(G_READ_FITS, "At least 2 columns are expected is table \""+ table.extname()+"\"."); } // Read spectral points and add to spectrum for (int i = 0; i < table.nrows(); ++i) { GMWLDatum datum; if (c_energy != NULL) { datum.m_eng = conv_energy(c_energy->real(i), c_energy->unit()); } if (c_energy_err != NULL) { datum.m_eng_err = conv_energy(c_energy_err->real(i), c_energy->unit()); } if (c_flux != NULL) { datum.m_flux = conv_flux(datum.m_eng, c_flux->real(i), c_flux->unit()); } if (c_flux_err != NULL) { datum.m_flux_err = conv_flux(datum.m_eng, c_flux_err->real(i), c_flux_err->unit()); } m_data.push_back(datum); } // Get telescope name if (table.has_card("TELESCOP")) { m_telescope = table.string("TELESCOP"); } else { m_telescope = "unknown"; } // Get instrument name if (table.has_card("INSTRUME")) { m_instrument = table.string("INSTRUME"); } else { m_instrument = "unknown"; } // Set energy boundaries set_ebounds(); // Return return; }
/***********************************************************************//** * @brief Read column names from FITS HDU * * @param[in] hdu Response table HDU. * * @exception GCTAException::bad_rsp_table_format * Bad response table format encountered in FITS HDU. * * Read the response table column names from the HDU. Column names * terminating with "_LO" and "_HI" define the parameter space axes, while * all other column names define response parameter data cubes. It is * assumed that parameter space axes are given in subsequent order, with * the first column corresponding to the lower bin boundaries of the first * axis. Lower bin boundaries are indicated by the "_LO" termination. Upper * bin boundaries are assumed to follow immediately the lower bin boundaires * and are designated by the "_HI" termination. * * This method sets the following members: * m_colname_lo - Column names of lower boundaries * m_colname_hi - Column names of upper boundaries * m_colname_par - Column names of parameters * m_naxes - Number of axes * m_npars - Number of parameters * * In case that the HDU pointer is not valid (NULL), this method clears the * column names and does nothing else. * * @todo Implement exceptions for invalid HDU format ***************************************************************************/ void GCTAResponseTable::read_colnames(const GFitsTable& hdu) { // Clear column name arrays m_naxes = 0; m_npars = 0; m_colname_lo.clear(); m_colname_hi.clear(); m_colname_par.clear(); // Initialise search mode. There are three search modes: // 0 - we're looking for the next axis by searching for a column // terminating with "_LO" // 1 - we're looking for the upper boundary of an axis, terminating // with "_HI" // 2 - we're looking for a parameter column int mode = 0; std::string lo_column; std::string next_column; // Extract column names for all axes for (int i = 0; i < hdu.ncols(); ++i) { // Get column name std::string colname = hdu[i]->name(); // If we search for a "_LO" column, check if we have one. If one // is found, change the search mode to 1 and set the expected name // for the "_HI" column. If none is found, change the search // mode to 2 since from now on we should only have parameter // columns. if (mode == 0) { size_t pos = colname.rfind("_LO"); if (pos != std::string::npos) { mode = 1; lo_column = colname; next_column = colname.substr(0, pos) + "_HI"; } else { if (colname.rfind("_HI") != std::string::npos) { std::string message = "Column '" + colname + "' encountered without" " preceeding '_LO' column."; throw GCTAException::bad_rsp_table_format(G_READ_COLNAMES, message); } else { mode = 2; m_colname_par.push_back(colname); } } } // If we search for a "_HI" column, check if we have the // expected column name. If this is the case, switch back to // search mode 0 to get the next "_LO" column. Otherwise // throw an exception. else if (mode == 1) { if (colname == next_column) { mode = 0; m_colname_lo.push_back(lo_column); m_colname_hi.push_back(next_column); } else { std::string message = "Expected column '" + next_column + "' not found. '_HI' columns have" " to be placed immediately after" " corresponding '_LO' columns."; throw GCTAException::bad_rsp_table_format(G_READ_COLNAMES, message); } } // If we search for a parameter column, make sure that we have // neither a "_LO" nor a "_HI" column. else { if (colname.rfind("_LO") != std::string::npos) { std::string message = "Column '" + colname + "' found. All '_LO' columns have to" " be placed before the parameter" " columns."; throw GCTAException::bad_rsp_table_format(G_READ_COLNAMES, message); } else if (colname.rfind("_HI") != std::string::npos) { std::string message = "Column '" + colname + "' found. All '_HI' columns have to" " be placed before the parameter" " columns."; throw GCTAException::bad_rsp_table_format(G_READ_COLNAMES, message); } else { m_colname_par.push_back(colname); } } } // endfor: looped over all column names // Store number of axes m_naxes = m_colname_lo.size(); // Store number of parameters m_npars = m_colname_par.size(); // Return return; }