/*************************************************************************** * GTimeReference.cpp - Time reference class * * ----------------------------------------------------------------------- * * copyright (C) 2012-2015 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see . * * * ***************************************************************************/ /** * @file GTimeReference.cpp * @brief Time reference class interface implementation * @author Juergen Knoedlseder */ /* __ Includes ___________________________________________________________ */ #ifdef HAVE_CONFIG_H #include #endif #include "GTimeReference.hpp" #include "GTools.hpp" #include "GException.hpp" #include "GFitsHDU.hpp" #include "GXmlElement.hpp" /* __ Constants __________________________________________________________ */ /* __ Method name definitions ____________________________________________ */ #define G_READ "GTimeReference::read(GFitsHDU&)" #define G_READ_XML "GTimeReference::read(GXmlElement&)" #define G_WRITE_XML "GTimeReference::write(GXmlElement&)" #define G_SET "GTimeReference::set(double&, std::string&, std::string&, "\ "std::string&)" /* __ Macros _____________________________________________________________ */ /* __ Coding definitions _________________________________________________ */ /* __ Debug definitions __________________________________________________ */ /*========================================================================== = = = Constructors/destructors = = = ==========================================================================*/ /***********************************************************************//** * @brief Void constructor ***************************************************************************/ GTimeReference::GTimeReference(void) { // Initialise private members init_members(); // Return return; } /***********************************************************************//** * @brief Copy constructor * * @param[in] ref Time reference. ***************************************************************************/ GTimeReference::GTimeReference(const GTimeReference& ref) { // Initialise private members init_members(); // Copy members copy_members(ref); // Return return; } /***********************************************************************//** * @brief Time reference constructor * * @param[in] mjdref Reference MJD (days). * @param[in] timeunit Time unit ("sec(s)", "day(s)"). * @param[in] timesys Time system (ignored so far). * @param[in] timeref Time reference (ignored so far). * * Sets the time reference from a MJD reference day, a time unit, a time * system and a time reference. ***************************************************************************/ GTimeReference::GTimeReference(const double& mjdref, const std::string& timeunit, const std::string& timesys, const std::string& timeref) { // Initialise private members init_members(); // Set time reference set(mjdref, timeunit, timesys, timeref); // Return return; } /***********************************************************************//** * @brief Time reference constructor * * @param[in] mjdrefi Integer part of reference MJD (days). * @param[in] mjdreff Fractional part of reference MJD (days). * @param[in] timeunit Time unit (sec, days). * @param[in] timesys Time system (TT). * @param[in] timeref Local time reference. * * Sets the time reference from a MJD reference day (specified by an integer * and a fractional part), a time unit, a time system and a time reference. ***************************************************************************/ GTimeReference::GTimeReference(const int& mjdrefi, const double& mjdreff, const std::string& timeunit, const std::string& timesys, const std::string& timeref) { // Initialise private members init_members(); // Set time reference set(mjdrefi, mjdreff, timeunit, timesys, timeref); // Return return; } /***********************************************************************//** * @brief FITS header constructor * * @param[in] hdu FITS extension. * * Constructs time reference from the information found in the FITS header. * See GTimeReference::read for more information on the expected format. ***************************************************************************/ GTimeReference::GTimeReference(const GFitsHDU& hdu) { // Initialise private members init_members(); // Read reference from FITS header read(hdu); // Return return; } /***********************************************************************//** * @brief Destructor ***************************************************************************/ GTimeReference::~GTimeReference(void) { // Free members free_members(); // Return return; } /*========================================================================== = = = Operators = = = ==========================================================================*/ /***********************************************************************//** * @brief Assignment operator * * @param[in] ref Time reference. ***************************************************************************/ GTimeReference& GTimeReference::operator= (const GTimeReference& ref) { // Execute only if object is not identical if (this != &ref) { // Free members free_members(); // Initialise private members init_members(); // Copy members copy_members(ref); } // endif: object was not identical // Return return *this; } /*========================================================================== = = = Public methods = = = ==========================================================================*/ /***********************************************************************//** * @brief Clear time reference ***************************************************************************/ void GTimeReference::clear(void) { // Free members free_members(); // Initialise members init_members(); // Return return; } /***********************************************************************//** * @brief Clone object * * @return Pointer to deep copy of time reference. ***************************************************************************/ GTimeReference* GTimeReference::clone(void) const { // Clone this image return new GTimeReference(*this); } /***********************************************************************//** * @brief Read time reference from FITS header * * @param[in] hdu FITS extension. * * GException::no_valid_time_ref * No valid reference MJD found in header. * * Reads the time reference information from a FITS header. The method * requires either the keyword "MJDREF" or the pair of keywords "MJDREFI" * and "MJDREFF" to be set. The following keywords are optional (the * assumed default values in absent of the keywords is given in parentheses): * * TIMEUNIT ("s") * TIMESYS ("TT") * TIMEREF ("LOCAL") * ***************************************************************************/ void GTimeReference::read(const GFitsHDU& hdu) { // Get reference MJD double mjdref = (hdu.has_card("MJDREF")) ? hdu.real("MJDREF") : 0.0; int mjdrefi = (hdu.has_card("MJDREFI")) ? hdu.integer("MJDREFI") : 0; double mjdreff = (hdu.has_card("MJDREFF")) ? hdu.real("MJDREFF") : 0.0; // Get remaining keywords. To accept a large variety of FITS headers, // all keywords are optionally. std::string timeunit = (hdu.has_card("TIMEUNIT")) ? hdu.string("TIMEUNIT") : "s"; std::string timesys = (hdu.has_card("TIMESYS")) ? hdu.string("TIMESYS") : "TT"; std::string timeref = (hdu.has_card("TIMEREF")) ? hdu.string("TIMEREF") : "LOCAL"; // Set time reference if (hdu.has_card("MJDREF")) { set(mjdref, timeunit, timesys, timeref); } else if (hdu.has_card("MJDREFI") && hdu.has_card("MJDREFF")) { set(mjdrefi, mjdreff, timeunit, timesys, timeref); } else { throw GException::no_valid_time_ref(G_READ, "Require either keyword \"MJDREF\" or keyword pair" " \"MJDREFI\" and \"MJDREFF\"."); } // Return return; } /***********************************************************************//** * @brief Write time reference into FITS header * * @param[in] hdu FITS extension. * * Writes or updates the time reference information in a FITS header. * Depending of whether the keyword "MJDREF" or the pair of keywords "MJDREFI" * and "MJDREFF" exist already in the header, the method either writes the * reference MJD as floating point value, or split into an integer and a * fractional part. If nothing has been written yet, splitting into an * integer and fractional part will be used as this preserves the highest * possible accuracy. * * The following additional keywords are written: * TIMEUNIT * TIMESYS * TIMEREF * ***************************************************************************/ void GTimeReference::write(GFitsHDU& hdu) const { // Case A: use floating point reference MJD if (hdu.has_card("MJDREF")) { hdu.card("MJDREF", mjdref(), "[days] Time reference MJD"); hdu.card("TIMEUNIT", timeunit(), "Time unit"); hdu.card("TIMESYS", timesys(), "Time system"); hdu.card("TIMEREF", timeref(), "Time reference"); } // Case B: use fractional reference MJD else { hdu.card("MJDREFI", mjdrefi(), "[days] Integer part of time reference MJD"); hdu.card("MJDREFF", mjdreff(), "[days] Fractional part of time reference MJD"); hdu.card("TIMEUNIT", timeunit(), "Time unit"); hdu.card("TIMESYS", timesys(), "Time system"); hdu.card("TIMEREF", timeref(), "Time reference"); } // Return return; } /***********************************************************************//** * @brief Read time reference from XML element * * @param[in] xml XML element. * * @exception GException::invalid_value * Invalid XML format encountered. * * Reads the time reference from an XML element. The format of the time * reference is * * * ***************************************************************************/ void GTimeReference::read(const GXmlElement& xml) { // Clear time reference clear(); // Get time reference parameter const GXmlElement* par = gammalib::xml_get_par(G_READ_XML, xml, "TimeReference"); // Initialise reference values int mjdrefi; double mjdreff; std::string timeunit; std::string timesys; std::string timeref; // Extract attributes if (par->has_attribute("mjdrefi")) { mjdrefi = gammalib::toint(par->attribute("mjdrefi")); } else { std::string msg = "Attribute \"mjdrefi\" not found in XML parameter" " \"TimeReference\"." " Please verify the XML format."; throw GException::invalid_value(G_READ_XML, msg); } if (par->has_attribute("mjdreff")) { mjdreff = gammalib::todouble(par->attribute("mjdreff")); } else { std::string msg = "Attribute \"mjdreff\" not found in XML parameter" " \"TimeReference\"." " Please verify the XML format."; throw GException::invalid_value(G_READ_XML, msg); } if (par->has_attribute("timeunit")) { timeunit = par->attribute("timeunit"); } else { std::string msg = "Attribute \"timeunit\" not found in XML parameter" " \"TimeReference\"." " Please verify the XML format."; throw GException::invalid_value(G_READ_XML, msg); } if (par->has_attribute("timesys")) { timesys = par->attribute("timesys"); } else { std::string msg = "Attribute \"timesys\" not found in XML parameter" " \"TimeReference\"." " Please verify the XML format."; throw GException::invalid_value(G_READ_XML, msg); } if (par->has_attribute("timeref")) { timeref = par->attribute("timeref"); } else { std::string msg = "Attribute \"timeref\" not found in XML parameter" " \"TimeReference\"." " Please verify the XML format."; throw GException::invalid_value(G_READ_XML, msg); } // Set time reference set(mjdrefi, mjdreff, timeunit, timesys, timeref); // Return return; } /***********************************************************************//** * @brief Write time reference into XML element * * @param[in] xml XML element. * * Writes the time reference into an XML element. The format of the time * reference is * * * ***************************************************************************/ void GTimeReference::write(GXmlElement& xml) const { // Get parameter GXmlElement* par = gammalib::xml_need_par(G_WRITE_XML, xml, "TimeReference"); // Write time reference par->attribute("mjdrefi", gammalib::str(mjdrefi())); par->attribute("mjdreff", gammalib::str(mjdreff())); par->attribute("timeunit", timeunit()); par->attribute("timesys", timesys()); par->attribute("timeref", timeref()); // Return return; } /***********************************************************************//** * @brief Set time reference * * @param[in] mjdref Reference MJD (days). * @param[in] timeunit Time unit ("s", "d", "sec(s)", "day(s)"). * @param[in] timesys Time system. * @param[in] timeref Time reference. * * @exception GException::time_invalid_unit * Invalid time unit specified. * * Sets the time reference from a MJD reference day, a time unit, a time * system and a time reference. * * @todo Implement checking of "timesys" and "timeref" parameters. ***************************************************************************/ void GTimeReference::set(const double& mjdref, const std::string& timeunit, const std::string& timesys, const std::string& timeref) { // Check timeunit string std::string ltimeunit = gammalib::tolower(timeunit); if (ltimeunit == "d" || ltimeunit == "day" || ltimeunit == "days") { m_unit_sec = false; } else if (ltimeunit == "s" || ltimeunit == "sec" || ltimeunit == "secs") { m_unit_sec = true; } else { throw GException::time_invalid_unit(G_SET, timeunit, "Valid timeunit values are: \"d\", \"day\", \"days\"," " \"s\", \"sec\" or \"secs\""); } // Set members m_mjdref = mjdref; m_timeunit = ltimeunit; m_timesys = gammalib::toupper(timesys); m_timeref = gammalib::toupper(timeref); // Return return; } /***********************************************************************//** * @brief Set time reference * * @param[in] mjdrefi Integer part of reference MJD (days). * @param[in] mjdreff Fractional part of reference MJD (days). * @param[in] timeunit Time unit (sec, days). * @param[in] timesys Time system (TT). * @param[in] timeref Local time reference. * * Sets the time reference from a MJD reference day (specified by an integer * and a fractional part), a time unit, a time system and a time reference. ***************************************************************************/ void GTimeReference::set(const int& mjdrefi, const double& mjdreff, const std::string& timeunit, const std::string& timesys, const std::string& timeref) { // Compute reference MJD double mjdref = double(mjdrefi) + mjdreff; // Set time set(mjdref, timeunit, timesys, timeref); // Return return; } /***********************************************************************//** * @brief Return MJD reference (units: days) * * @return Modified Julian reference day (days). * * Returns the Modified Julian reference day. ***************************************************************************/ const double& GTimeReference::mjdref(void) const { // Return MDJ reference return m_mjdref; } /***********************************************************************//** * @brief Returns integer part of MJD reference (units: days) * * @return Integer part of Modified Julian reference day (days). * * Returns the integer part of the Modified Julian reference day. ***************************************************************************/ int GTimeReference::mjdrefi(void) const { // Return integer part of MJD reference return int(m_mjdref); } /***********************************************************************//** * @brief Returns fractional part of MJD reference (units: days) * * @return Fractional part of Modified Julian reference day (days). * * Returns the fractional part of the Modified Julian reference day. ***************************************************************************/ double GTimeReference::mjdreff(void) const { // Return fractional part of MJD reference return (m_mjdref-double(mjdrefi())); } /***********************************************************************//** * @brief Return time unit * * @return Time unit. * * Returns the reference time unit. ***************************************************************************/ const std::string& GTimeReference::timeunit(void) const { // Return time unit return m_timeunit; } /***********************************************************************//** * @brief Return time system * * @return Time system. * * Returns the reference time system. ***************************************************************************/ const std::string& GTimeReference::timesys(void) const { // Return time system return m_timesys; } /***********************************************************************//** * @brief Return time reference * * @return Time reference. * * Returns the reference time reference. ***************************************************************************/ const std::string& GTimeReference::timeref(void) const { // Return time reference return m_timeref; } /***********************************************************************//** * @brief Return the time unit in seconds * * @return Time unit in seconds. * * Returns 1 if the time using is in seconds and 86400 if the time unit is * in days. ***************************************************************************/ double GTimeReference::unitseconds(void) const { // Set time unit in seconds double unit = (m_unit_sec) ? 1.0 : gammalib::sec_in_day; // Return time unit return unit; } /***********************************************************************//** * @brief Print time reference * * @param[in] chatter Chattiness (defaults to NORMAL). * @return String containing the time reference. ***************************************************************************/ std::string GTimeReference::print(const GChatter& chatter) const { // Initialise result string std::string result; // Continue only if chatter is not silent if (chatter != SILENT) { // Append header result.append("=== GTimeReference ==="); // Append information result.append("\n"+gammalib::parformat("MJD reference time")); result.append(gammalib::str(mjdref())); result.append("\n"+gammalib::parformat("Time unit")+timeunit()); result.append("\n"+gammalib::parformat("Time system")+timesys()); result.append("\n"+gammalib::parformat("Time reference")+timeref()); } // endif: chatter was not silent // Return return result; } /*========================================================================== = = = Private methods = = = ==========================================================================*/ /***********************************************************************//** * @brief Initialise class members ***************************************************************************/ void GTimeReference::init_members(void) { // Initialise members m_mjdref = 0.0; m_timeunit = "secs"; m_timesys = "TT"; m_timeref = "local"; m_unit_sec = true; // Return return; } /***********************************************************************//** * @brief Copy class members * * @param[in] ref Time reference. ***************************************************************************/ void GTimeReference::copy_members(const GTimeReference& ref) { // Copy members m_mjdref = ref.m_mjdref; m_timeunit = ref.m_timeunit; m_timesys = ref.m_timesys; m_timeref = ref.m_timeref; m_unit_sec = ref.m_unit_sec; // Return return; } /***********************************************************************//** * @brief Delete class members ***************************************************************************/ void GTimeReference::free_members(void) { // Return return; }