Commit d1842e6f4bea3ddac7735cd948b3efa2e3ff7aa5

Authored by Jürgen Knödlseder
2 parents 7f2ae9e0 cbde4004

Merge branch '1600-GCTAEventList-flexible-reading-writing' into integration

ChangeLog
1   -2015-12-02 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
  1 +2015-12-16 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
2 2  
3 3 * Version 1.1.0 released
4 4 =========================
5 5  
  6 + Read only mandatary columns in GCTAEventList (#1600)
6 7 Add GModel::has_ts() method (#1578)
7 8  
8 9  
... ...
... ... @@ -2,7 +2,7 @@ New Features and Important Changes in GammaLib 1.1.0
2 2  
3 3 Author(s) : Juergen Knoedlseder
4 4  
5   -2 December 2015
  5 +16 December 2015
6 6  
7 7  
8 8 1. Introduction
... ... @@ -109,9 +109,12 @@ None
109 109  
110 110 20. CTA interface
111 111 -----------------
112   -The IRF loaders now check the existence of the file before loading, and now throw
  112 +The IRF loaders now check the existence of the file before loading, and now throws
113 113 appropriate error messages in case that the files do not exist (#1586).
114 114  
  115 +Only manadatory columns are read by GCTAEventsList, while any other columns will only
  116 +be stored for back writing in a FITS file.
  117 +
115 118  
116 119 21. COMPTEL interface
117 120 ---------------------
... ...
inst/cta/include/GCTAEventAtom.hpp
... ... @@ -72,10 +72,8 @@ public:
72 72 // Other methods
73 73 const int& index(void) const;
74 74 const unsigned long& event_id(void) const;
75   - const unsigned long& obs_id(void) const;
76 75 const float& phase(void) const;
77 76 void event_id(const unsigned long& id);
78   - void obs_id(const unsigned long& id);
79 77 void phase(const float& phase);
80 78  
81 79 protected:
... ... @@ -90,24 +88,6 @@ protected:
90 88 GEnergy m_energy; //!< Event energy
91 89 GTime m_time; //!< Event time
92 90 unsigned long m_event_id; //!< Event identifier
93   - unsigned long m_obs_id; //!< Observation identifier
94   - int m_multip; //!< Multiplicity
95   - char m_telmask; //!< Telescope mask
96   - float m_dir_err; //!< Error on event direction
97   - float m_alt; //!< Event altitude
98   - float m_az; //!< Event azimuth
99   - float m_corex; //!< Position on ground (m)
100   - float m_corey; //!< Position on ground (m)
101   - float m_core_err; //!< Error on core reconstruction
102   - float m_xmax; //!< Position of shower max (g/cm2)
103   - float m_xmax_err; //!< Error on shower max (g/cm2)
104   - float m_shwidth; //!< Shower width (m)
105   - float m_shlength; //!< Shower length (m)
106   - float m_energy_err; //!< Error on event energy (MeV)
107   - float m_hil_msw; //!< Hillas MSW
108   - float m_hil_msw_err; //!< Hillas MSW error
109   - float m_hil_msl; //!< Hillas MSL
110   - float m_hil_msl_err; //!< Hillas MSL error
111 91 float m_phase; //!< Optional phase
112 92 };
113 93  
... ... @@ -226,18 +206,6 @@ const unsigned long&amp; GCTAEventAtom::event_id(void) const
226 206  
227 207  
228 208 /***********************************************************************//**
229   - * @brief Return observation identifier
230   - *
231   - * @return Observation identifier.
232   - ***************************************************************************/
233   -inline
234   -const unsigned long& GCTAEventAtom::obs_id(void) const
235   -{
236   - return (m_obs_id);
237   -}
238   -
239   -
240   -/***********************************************************************//**
241 209 * @brief Return event phase
242 210 *
243 211 * @return Event phase.
... ... @@ -263,19 +231,6 @@ void GCTAEventAtom::event_id(const unsigned long&amp; id)
263 231  
264 232  
265 233 /***********************************************************************//**
266   - * @brief Set observation identifier
267   - *
268   - * @param[in] id Observation identifier.
269   - ***************************************************************************/
270   -inline
271   -void GCTAEventAtom::obs_id(const unsigned long& id)
272   -{
273   - m_obs_id = id;
274   - return;
275   -}
276   -
277   -
278   -/***********************************************************************//**
279 234 * @brief Set event phase
280 235 *
281 236 * @param[in] phase Event phase.
... ...
inst/cta/include/GCTAEventList.hpp
... ... @@ -88,19 +88,18 @@ protected:
88 88 void free_members(void);
89 89 virtual void set_energies(void) { return; }
90 90 virtual void set_times(void) { return; }
91   - void read_events(const GFitsTable& hdu);
92   - void read_events_v0(const GFitsTable& hdu);
93   - void read_events_v1(const GFitsTable& hdu);
94   - void read_events_hillas(const GFitsTable& hdu);
95   - void write_events(GFitsBinTable& hdu) const;
  91 + void read_events(const GFitsTable& table);
  92 + void write_events(GFitsBinTable& table) const;
96 93 void write_ds_keys(GFitsHDU& hdu) const;
97 94 int irf_cache_init(const std::string& name) const;
98 95 int irf_cache_index(const std::string& name) const;
99 96  
100 97 // Protected members
101   - GCTARoi m_roi; //!< Region of interest
102   - std::vector<GCTAEventAtom> m_events; //!< Events
103   - bool m_has_phase; //!< Signal presence of phase
  98 + GCTARoi m_roi; //!< Region of interest
  99 + std::vector<GCTAEventAtom> m_events; //!< Events
  100 + std::vector<GFitsTableCol*> m_columns; //!< Pointers to optional columns
  101 + bool m_has_phase; //!< Signal presence of phase
  102 + bool m_has_detxy; //!< Signal presence of detector coordinates
104 103  
105 104 // IRF cache for diffuse models
106 105 mutable std::vector<std::string> m_irf_names; //!< Model names
... ...
inst/cta/pyext/GCTAEventAtom.i
... ... @@ -55,10 +55,8 @@ public:
55 55 // Other methods
56 56 const int& index(void) const;
57 57 const unsigned long& event_id(void) const;
58   - const unsigned long& obs_id(void) const;
59 58 const float& phase(void) const;
60 59 void event_id(const unsigned long& id);
61   - void obs_id(const unsigned long& id);
62 60 void phase(const float& phase);
63 61 };
64 62  
... ...
inst/cta/src/GCTAEventAtom.cpp
... ... @@ -207,27 +207,9 @@ void GCTAEventAtom::init_members(void)
207 207 m_dir.clear();
208 208 m_time.clear();
209 209 m_energy.clear();
210   - m_index = 0;
211   - m_event_id = 0;
212   - m_obs_id = 0;
213   - m_multip = 0;
214   - m_telmask = 0;
215   - m_dir_err = 0.0;
216   - m_alt = 0.0;
217   - m_az = 0.0;
218   - m_corex = 0.0;
219   - m_corey = 0.0;
220   - m_core_err = 0.0;
221   - m_xmax = 0.0;
222   - m_xmax_err = 0.0;
223   - m_shwidth = 0.0;
224   - m_shlength = 0.0;
225   - m_energy_err = 0.0;
226   - m_hil_msw = 0.0;
227   - m_hil_msw_err = 0.0;
228   - m_hil_msl = 0.0;
229   - m_hil_msl_err = 0.0;
230   - m_phase = 0.0;
  210 + m_index = 0;
  211 + m_event_id = 0;
  212 + m_phase = 0.0;
231 213  
232 214 // Return
233 215 return;
... ... @@ -242,30 +224,12 @@ void GCTAEventAtom::init_members(void)
242 224 void GCTAEventAtom::copy_members(const GCTAEventAtom& atom)
243 225 {
244 226 // Copy members
245   - m_dir = atom.m_dir;
246   - m_time = atom.m_time;
247   - m_energy = atom.m_energy;
248   - m_index = atom.m_index;
249   - m_event_id = atom.m_event_id;
250   - m_obs_id = atom.m_obs_id;
251   - m_multip = atom.m_multip;
252   - m_telmask = atom.m_telmask;
253   - m_dir_err = atom.m_dir_err;
254   - m_alt = atom.m_alt;
255   - m_az = atom.m_az;
256   - m_corex = atom.m_corex;
257   - m_corey = atom.m_corey;
258   - m_core_err = atom.m_core_err;
259   - m_xmax = atom.m_xmax;
260   - m_xmax_err = atom.m_xmax_err;
261   - m_shwidth = atom.m_shwidth;
262   - m_shlength = atom.m_shlength;
263   - m_energy_err = atom.m_energy_err;
264   - m_hil_msw = atom.m_hil_msw;
265   - m_hil_msw_err = atom.m_hil_msw_err;
266   - m_hil_msl = atom.m_hil_msl;
267   - m_hil_msl_err = atom.m_hil_msl_err;
268   - m_phase = atom.m_phase;
  227 + m_dir = atom.m_dir;
  228 + m_time = atom.m_time;
  229 + m_energy = atom.m_energy;
  230 + m_index = atom.m_index;
  231 + m_event_id = atom.m_event_id;
  232 + m_phase = atom.m_phase;
269 233  
270 234 // Return
271 235 return;
... ...
inst/cta/src/GCTAEventList.cpp
... ... @@ -572,7 +572,9 @@ void GCTAEventList::init_members(void)
572 572 // Initialise members
573 573 m_roi.clear();
574 574 m_events.clear();
  575 + m_columns.clear();
575 576 m_has_phase = false;
  577 + m_has_detxy = true;
576 578  
577 579 // Initialise cache
578 580 m_irf_names.clear();
... ... @@ -594,11 +596,18 @@ void GCTAEventList::copy_members(const GCTAEventList&amp; list)
594 596 m_roi = list.m_roi;
595 597 m_events = list.m_events;
596 598 m_has_phase = list.m_has_phase;
  599 + m_has_detxy = list.m_has_detxy;
597 600  
598 601 // Copy cache
599 602 m_irf_names = list.m_irf_names;
600 603 m_irf_values = list.m_irf_values;
601 604  
  605 + // Copy column pointers
  606 + m_columns.clear();
  607 + for (int i = 0; i < list.m_columns.size(); ++i) {
  608 + m_columns.push_back((list.m_columns[i]->clone()));
  609 + }
  610 +
602 611 // Return
603 612 return;
604 613 }
... ... @@ -609,6 +618,12 @@ void GCTAEventList::copy_members(const GCTAEventList&amp; list)
609 618 ***************************************************************************/
610 619 void GCTAEventList::free_members(void)
611 620 {
  621 + // Free columns
  622 + for (int i = 0; i < m_columns.size(); ++i) {
  623 + delete m_columns[i];
  624 + m_columns[i] = NULL;
  625 + }
  626 +
612 627 // Return
613 628 return;
614 629 }
... ... @@ -619,52 +634,26 @@ void GCTAEventList::free_members(void)
619 634 *
620 635 * @param[in] table FITS table.
621 636 *
622   - * This method reads the CTA event list from a FITS table HDU into memory.
623   - * Depending on the columns existing in the file, it either selects v0 or
624   - * v1 of the event list reader.
625   - ***************************************************************************/
626   -void GCTAEventList::read_events(const GFitsTable& table)
627   -{
628   - // Clear existing events
629   - m_events.clear();
630   -
631   - // Extract number of events in FITS file
632   - int num = table.integer("NAXIS2");
633   -
634   - // Continue only if there are events
635   - if (num > 0) {
636   -
637   - // Read events for v1
638   - if (table.contains("SHWIDTH") && table.contains("SHLENGTH")) {
639   - read_events_v1(table);
640   - }
641   -
642   - // ... otherwise read events for v0
643   - else {
644   - read_events_v0(table);
645   - }
646   -
647   - // Read (optional) Hillas parameters
648   - read_events_hillas(table);
649   -
650   - } // endif: there were events
651   -
652   - // Return
653   - return;
654   -}
655   -
656   -
657   -/***********************************************************************//**
658   - * @brief Read CTA events from FITS table (version 0)
  637 + * This method reads the CTA event list from a FITS table into memory.
  638 + * The following columns are mandatory in the FITS table:
659 639 *
660   - * @param[in] table FITS table.
  640 + * - EVENT_ID
  641 + * - TIME
  642 + * - RA
  643 + * - DEC
  644 + * - ENERGY
  645 + *
  646 + * Optionally, the
661 647 *
662   - * This method reads the CTA event list from a FITS table HDU into memory.
663   - * It is a minimal event reader that is compliant with the initial data
664   - * format distributed by Karl Kosack. Information that is not present in
665   - * that format is set to 0.
  648 + * - DETX
  649 + * - DETY
  650 + * - PHASE
  651 + *
  652 + * columns are read. Any other columns present in the FITS table will also be
  653 + * read, and written into the FITS table when the write_events() method is
  654 + * called.
666 655 ***************************************************************************/
667   -void GCTAEventList::read_events_v0(const GFitsTable& table)
  656 +void GCTAEventList::read_events(const GFitsTable& table)
668 657 {
669 658 // Clear existing events
670 659 m_events.clear();
... ... @@ -679,120 +668,25 @@ void GCTAEventList::read_events_v0(const GFitsTable&amp; table)
679 668 m_events.reserve(num);
680 669  
681 670 // Get column pointers
682   - const GFitsTableCol* ptr_eid = table["EVENT_ID"];
683   - const GFitsTableCol* ptr_time = table["TIME"];
684   - const GFitsTableCol* ptr_multip = table["MULTIP"];
685   - const GFitsTableCol* ptr_ra = table["RA"];
686   - const GFitsTableCol* ptr_dec = table["DEC"];
687   - const GFitsTableCol* ptr_dir_err = table["DIR_ERR"];
688   - const GFitsTableCol* ptr_detx = table["DETX"];
689   - const GFitsTableCol* ptr_dety = table["DETY"];
690   - const GFitsTableCol* ptr_alt = table["ALT"];
691   - const GFitsTableCol* ptr_az = table["AZ"];
692   - const GFitsTableCol* ptr_corex = table["COREX"];
693   - const GFitsTableCol* ptr_corey = table["COREY"];
694   - const GFitsTableCol* ptr_core_err = table["CORE_ERR"];
695   - const GFitsTableCol* ptr_xmax = table["XMAX"];
696   - const GFitsTableCol* ptr_xmax_err = table["XMAX_ERR"];
697   - const GFitsTableCol* ptr_energy = table["ENERGY"];
698   - const GFitsTableCol* ptr_energy_err = table["ENERGY_ERR"];
699   -
700   - // Check for phase column
701   - const GFitsTableCol* ptr_phase;
702   - if (table.contains("PHASE")) {
703   - m_has_phase = true;
704   - ptr_phase = table["PHASE"];
  671 + const GFitsTableCol* ptr_eid = table["EVENT_ID"];
  672 + const GFitsTableCol* ptr_time = table["TIME"];
  673 + const GFitsTableCol* ptr_ra = table["RA"];
  674 + const GFitsTableCol* ptr_dec = table["DEC"];
  675 + const GFitsTableCol* ptr_energy = table["ENERGY"];
  676 +
  677 + // Check for DETX and DETY columns
  678 + const GFitsTableCol* ptr_detx;
  679 + const GFitsTableCol* ptr_dety;
  680 + if (table.contains("DETX") && table.contains("DETY")) {
  681 + m_has_detxy = true;
  682 + ptr_detx = table["DETX"];
  683 + ptr_dety = table["DETY"];
705 684 }
706 685 else {
707   - m_has_phase = false;
708   - }
709   -
710   - // Copy data from columns into GCTAEventAtom objects
711   - GCTAEventAtom event;
712   - for (int i = 0; i < num; ++i) {
713   - event.m_index = i;
714   - event.m_time.set(ptr_time->real(i), m_gti.reference());
715   - event.m_dir.dir().radec_deg(ptr_ra->real(i), ptr_dec->real(i));
716   - event.m_dir.detx(ptr_detx->real(i)*gammalib::deg2rad);
717   - event.m_dir.dety(ptr_dety->real(i)*gammalib::deg2rad);
718   - event.m_energy.TeV(ptr_energy->real(i));
719   - event.m_event_id = ptr_eid->integer(i);
720   - event.m_obs_id = 0;
721   - event.m_multip = ptr_multip->integer(i);
722   - event.m_telmask = 0;
723   - event.m_dir_err = ptr_dir_err->real(i);
724   - event.m_alt = ptr_alt->real(i);
725   - event.m_az = ptr_az->real(i);
726   - event.m_corex = ptr_corex->real(i);
727   - event.m_corey = ptr_corey->real(i);
728   - event.m_core_err = ptr_core_err->real(i);
729   - event.m_xmax = ptr_xmax->real(i);
730   - event.m_xmax_err = ptr_xmax_err->real(i);
731   - event.m_shwidth = 0.0;
732   - event.m_shlength = 0.0;
733   - event.m_energy_err = ptr_energy_err->real(i);
734   -
735   - // Set pulse phase if available
736   - if (m_has_phase) {
737   - event.m_phase = ptr_phase->real(i);
738   - }
739   -
740   - m_events.push_back(event);
  686 + m_has_detxy = false;
741 687 }
742 688  
743   - } // endif: there were events
744   -
745   - // Return
746   - return;
747   -}
748   -
749   -
750   -/***********************************************************************//**
751   - * @brief Read CTA events from FITS table (version 1)
752   - *
753   - * @param[in] table FITS table.
754   - *
755   - * This method reads the CTA event list from a FITS table HDU into memory.
756   - *
757   - * @todo Implement agreed column format
758   - ***************************************************************************/
759   -void GCTAEventList::read_events_v1(const GFitsTable& table)
760   -{
761   - // Clear existing events
762   - m_events.clear();
763   -
764   - // Extract number of events in FITS file
765   - int num = table.nrows();
766   -
767   - // If there are events then load them
768   - if (num > 0) {
769   -
770   - // Reserve data
771   - m_events.reserve(num);
772   -
773   - // Get column pointers
774   - const GFitsTableCol* ptr_eid = table["EVENT_ID"];
775   - const GFitsTableCol* ptr_oid = table["OBS_ID"];
776   - const GFitsTableCol* ptr_time = table["TIME"];
777   - const GFitsTableCol* ptr_multip = table["MULTIP"];
778   - const GFitsTableCol* ptr_ra = table["RA"];
779   - const GFitsTableCol* ptr_dec = table["DEC"];
780   - const GFitsTableCol* ptr_dir_err = table["DIR_ERR"];
781   - const GFitsTableCol* ptr_detx = table["DETX"];
782   - const GFitsTableCol* ptr_dety = table["DETY"];
783   - const GFitsTableCol* ptr_alt = table["ALT"];
784   - const GFitsTableCol* ptr_az = table["AZ"];
785   - const GFitsTableCol* ptr_corex = table["COREX"];
786   - const GFitsTableCol* ptr_corey = table["COREY"];
787   - const GFitsTableCol* ptr_core_err = table["CORE_ERR"];
788   - const GFitsTableCol* ptr_xmax = table["XMAX"];
789   - const GFitsTableCol* ptr_xmax_err = table["XMAX_ERR"];
790   - const GFitsTableCol* ptr_shw = table["SHWIDTH"];
791   - const GFitsTableCol* ptr_shl = table["SHLENGTH"];
792   - const GFitsTableCol* ptr_energy = table["ENERGY"];
793   - const GFitsTableCol* ptr_energy_err = table["ENERGY_ERR"];
794   -
795   - // Check for phase column
  689 + // Check for PHASE column
796 690 const GFitsTableCol* ptr_phase;
797 691 if (table.contains("PHASE")) {
798 692 m_has_phase = true;
... ... @@ -805,98 +699,57 @@ void GCTAEventList::read_events_v1(const GFitsTable&amp; table)
805 699 // Copy data from columns into GCTAEventAtom objects
806 700 GCTAEventAtom event;
807 701 for (int i = 0; i < num; ++i) {
808   - event.m_index = i;
  702 +
  703 + // Set mandatory information
809 704 event.m_time.set(ptr_time->real(i), m_gti.reference());
810 705 event.m_dir.dir().radec_deg(ptr_ra->real(i), ptr_dec->real(i));
811   - event.m_dir.detx(ptr_detx->real(i)*gammalib::deg2rad);
812   - event.m_dir.dety(ptr_dety->real(i)*gammalib::deg2rad);
813 706 event.m_energy.TeV(ptr_energy->real(i));
814   - event.m_event_id = ptr_eid->integer(i);
815   - event.m_obs_id = ptr_oid->integer(i);
816   - event.m_multip = ptr_multip->integer(i);
817   - event.m_telmask = 0;
818   - event.m_dir_err = ptr_dir_err->real(i);
819   - event.m_alt = ptr_alt->real(i);
820   - event.m_az = ptr_az->real(i);
821   - event.m_corex = ptr_corex->real(i);
822   - event.m_corey = ptr_corey->real(i);
823   - event.m_core_err = ptr_core_err->real(i);
824   - event.m_xmax = ptr_xmax->real(i);
825   - event.m_xmax_err = ptr_xmax_err->real(i);
826   - event.m_shwidth = ptr_shw->real(i);
827   - event.m_shlength = ptr_shl->real(i);
828   - event.m_energy_err = ptr_energy_err->real(i);
829   -
830   - // Set phase if available
  707 + event.m_event_id = ptr_eid->integer(i);
  708 + event.m_index = i;
  709 +
  710 + // If available, set detector coordinates in radians
  711 + if (m_has_detxy) {
  712 + event.m_dir.detx(ptr_detx->real(i)*gammalib::deg2rad);
  713 + event.m_dir.dety(ptr_dety->real(i)*gammalib::deg2rad);
  714 + }
  715 +
  716 + // If available, set pulse phase
831 717 if (m_has_phase) {
832 718 event.m_phase = ptr_phase->real(i);
833 719 }
834 720  
  721 + // Append event
835 722 m_events.push_back(event);
836   - }
837 723  
838   - } // endif: there were events
  724 + } // endfor: looped over all events
839 725  
840   - // Return
841   - return;
842   -}
  726 + // Loop over table and find optional columns
  727 + for (int i = 0; i < table.ncols(); ++i) {
843 728  
  729 + // Get column pointer
  730 + const GFitsTableCol* col = table[i];
844 731  
845   -/***********************************************************************//**
846   - * @brief Read Hillas information for CTA events from FITS table
847   - *
848   - * @param[in] table FITS table.
849   - *
850   - * This method reads the Hillas reconstruction information for CTA events
851   - * from an EVENTS file. It searches for the columns HIL_MSW, HIL_MSW_ERR,
852   - * HIL_MSL, and HIL_MSL_ERR in the FITS table and extracts the relevant
853   - * columns from the FITS file. If a column is not found, no action is
854   - * performed.
855   - *
856   - * @todo Verify consistency of event list size
857   - ***************************************************************************/
858   -void GCTAEventList::read_events_hillas(const GFitsTable& table)
859   -{
860   - // Extract number of events in FITS file
861   - int num = table.nrows();
  732 + // Get column name
  733 + const std::string name = col->name();
862 734  
863   - //TODO: Make sure that dimension is consistent with existing event
864   - // list
865   -
866   - // Continue only if there are events
867   - if (num > 0) {
868   -
869   - // HIL_MSW
870   - if (table.contains("HIL_MSW")) {
871   - const GFitsTableCol* ptr = table["HIL_MSW"];
872   - for (int i = 0; i < num; ++i) {
873   - m_events[i].m_hil_msw = ptr->real(i);
874   - }
875   - }
876   -
877   - // HIL_MSW_ERR
878   - if (table.contains("HIL_MSW_ERR")) {
879   - const GFitsTableCol* ptr = table["HIL_MSW_ERR"];
880   - for (int i = 0; i < num; ++i) {
881   - m_events[i].m_hil_msw_err = ptr->real(i);
  735 + // If column was mandatory or optional then skip it ...
  736 + if (name == "EVENT_ID" ||
  737 + name == "TIME" ||
  738 + name == "RA" ||
  739 + name == "DEC" ||
  740 + name == "ENERGY" ||
  741 + name == "DETX" ||
  742 + name == "DETY" ||
  743 + name == "PHASE") {
  744 + continue;
882 745 }
883   - }
884 746  
885   - // HIL_MSL
886   - if (table.contains("HIL_MSL")) {
887   - const GFitsTableCol* ptr = table["HIL_MSL"];
888   - for (int i = 0; i < num; ++i) {
889   - m_events[i].m_hil_msl = ptr->real(i);
  747 + // ... otherwise keep a copy
  748 + else {
  749 + m_columns.push_back(col->clone());
890 750 }
891   - }
892 751  
893   - // HIL_MSL_ERR
894   - if (table.contains("HIL_MSL_ERR")) {
895   - const GFitsTableCol* ptr = table["HIL_MSL_ERR"];
896   - for (int i = 0; i < num; ++i) {
897   - m_events[i].m_hil_msl_err = ptr->real(i);
898   - }
899   - }
  752 + } // endfor: loop over optional columns
900 753  
901 754 } // endif: there were events
902 755  
... ... @@ -908,12 +761,26 @@ void GCTAEventList::read_events_hillas(const GFitsTable&amp; table)
908 761 /***********************************************************************//**
909 762 * @brief Write CTA events into FITS table
910 763 *
911   - * @param[in] hdu FITS table HDU.
  764 + * @param[in] table FITS binary table.
912 765 *
913   - * Write the CTA event list into FITS table.
  766 + * Write the CTA event list into a FITS binary table.
914 767 *
915   - * @todo The TELMASK column is allocated with a dummy length of 100.
916   - * @todo Implement agreed column format
  768 + * The following mandatory columns will be written into the FITS table:
  769 + *
  770 + * - EVENT_ID
  771 + * - TIME
  772 + * - RA
  773 + * - DEC
  774 + * - ENERGY
  775 + *
  776 + * If available, also the
  777 + *
  778 + * - DETX
  779 + * - DETY
  780 + * - PHASE
  781 + *
  782 + * columns are written. Any other columns that were read by the read_events()
  783 + * method will be also written into the table.
917 784 ***************************************************************************/
918 785 void GCTAEventList::write_events(GFitsBinTable& hdu) const
919 786 {
... ... @@ -923,109 +790,55 @@ void GCTAEventList::write_events(GFitsBinTable&amp; hdu) const
923 790 // If there are events then write them now
924 791 if (size() > 0) {
925 792  
926   - // Allocate columns
927   - GFitsTableULongCol col_eid = GFitsTableULongCol("EVENT_ID", size());
928   - GFitsTableULongCol col_oid = GFitsTableULongCol("OBS_ID", size());
929   - GFitsTableDoubleCol col_time = GFitsTableDoubleCol("TIME", size());
930   - GFitsTableDoubleCol col_live = GFitsTableDoubleCol("TLIVE", size());
931   - GFitsTableShortCol col_multip = GFitsTableShortCol("MULTIP", size());
932   - GFitsTableBitCol col_telmask = GFitsTableBitCol("TELMASK", size(), 100);
933   - GFitsTableFloatCol col_ra = GFitsTableFloatCol("RA", size());
934   - GFitsTableFloatCol col_dec = GFitsTableFloatCol("DEC", size());
935   - GFitsTableFloatCol col_direrr = GFitsTableFloatCol("DIR_ERR", size());
936   - GFitsTableFloatCol col_detx = GFitsTableFloatCol("DETX", size());
937   - GFitsTableFloatCol col_dety = GFitsTableFloatCol("DETY", size());
938   - GFitsTableFloatCol col_alt = GFitsTableFloatCol("ALT", size());
939   - GFitsTableFloatCol col_az = GFitsTableFloatCol("AZ", size());
940   - GFitsTableFloatCol col_corex = GFitsTableFloatCol("COREX", size());
941   - GFitsTableFloatCol col_corey = GFitsTableFloatCol("COREY", size());
942   - GFitsTableFloatCol col_core_err = GFitsTableFloatCol("CORE_ERR", size());
943   - GFitsTableFloatCol col_xmax = GFitsTableFloatCol("XMAX", size());
944   - GFitsTableFloatCol col_xmax_err = GFitsTableFloatCol("XMAX_ERR", size());
945   - GFitsTableFloatCol col_shw = GFitsTableFloatCol("SHWIDTH", size());
946   - GFitsTableFloatCol col_shl = GFitsTableFloatCol("SHLENGTH", size());
947   - GFitsTableFloatCol col_energy = GFitsTableFloatCol("ENERGY", size());
948   - GFitsTableFloatCol col_energy_err = GFitsTableFloatCol("ENERGY_ERR", size());
949   - GFitsTableFloatCol col_hil_msw = GFitsTableFloatCol("HIL_MSW", size());
950   - GFitsTableFloatCol col_hil_msw_err = GFitsTableFloatCol("HIL_MSW_ERR", size());
951   - GFitsTableFloatCol col_hil_msl = GFitsTableFloatCol("HIL_MSL", size());
952   - GFitsTableFloatCol col_hil_msl_err = GFitsTableFloatCol("HIL_MSL_ERR", size());
953   -
954   - // Create phase column if required
955   - GFitsTableFloatCol col_phase;
956   - if (m_has_phase) {
957   - col_phase = GFitsTableFloatCol("PHASE", size());
958   - }
  793 + // Allocate mandatory columns
  794 + GFitsTableULongCol col_eid = GFitsTableULongCol("EVENT_ID", size());
  795 + GFitsTableDoubleCol col_time = GFitsTableDoubleCol("TIME", size());
  796 + GFitsTableFloatCol col_ra = GFitsTableFloatCol("RA", size());
  797 + GFitsTableFloatCol col_dec = GFitsTableFloatCol("DEC", size());
  798 + GFitsTableFloatCol col_energy = GFitsTableFloatCol("ENERGY", size());
959 799  
960   - // Fill columns
  800 + // Fill mandatory columns
961 801 for (int i = 0; i < size(); ++i) {
962   - col_eid(i) = m_events[i].m_event_id;
963   - col_oid(i) = m_events[i].m_obs_id;
964   - col_time(i) = m_events[i].time().convert(m_gti.reference());
965   - col_live(i) = 0.0;
966   - col_multip(i) = 0;
967   - //col_telmask
968   - col_ra(i) = m_events[i].dir().dir().ra_deg();
969   - col_dec(i) = m_events[i].dir().dir().dec_deg();
970   - col_direrr(i) = m_events[i].m_dir_err;
971   - col_detx(i) = m_events[i].dir().detx() * gammalib::rad2deg;
972   - col_dety(i) = m_events[i].dir().dety() * gammalib::rad2deg;
973   - col_alt(i) = m_events[i].m_alt;
974   - col_az(i) = m_events[i].m_az;
975   - col_corex(i) = m_events[i].m_corex;
976   - col_corey(i) = m_events[i].m_corey;
977   - col_core_err(i) = m_events[i].m_core_err;
978   - col_xmax(i) = m_events[i].m_xmax;
979   - col_xmax_err(i) = m_events[i].m_xmax_err;
980   - col_shw(i) = m_events[i].m_shwidth;
981   - col_shl(i) = m_events[i].m_shlength;
982   - col_energy(i) = m_events[i].energy().TeV();
983   - col_energy_err(i) = m_events[i].m_energy_err;
984   - col_hil_msw(i) = m_events[i].m_hil_msw;
985   - col_hil_msw_err(i) = m_events[i].m_hil_msw_err;
986   - col_hil_msl(i) = m_events[i].m_hil_msl;
987   - col_hil_msl_err(i) = m_events[i].m_hil_msl_err;
988   -
989   - // Optionally fill pulse phase column
990   - if (m_has_phase) {
991   - col_phase(i) = m_events[i].m_phase;
992   - }
993   -
994   - } // endfor: looped over rows
  802 + col_eid(i) = m_events[i].m_event_id;
  803 + col_time(i) = m_events[i].time().convert(m_gti.reference());
  804 + col_ra(i) = m_events[i].dir().dir().ra_deg();
  805 + col_dec(i) = m_events[i].dir().dir().dec_deg();
  806 + col_energy(i) = m_events[i].energy().TeV();
  807 + }
995 808  
996   - // Append columns to table
  809 + // Append mandatory columns to table
997 810 hdu.append(col_eid);
998   - hdu.append(col_oid);
999 811 hdu.append(col_time);
1000   - hdu.append(col_live);
1001   - hdu.append(col_multip);
1002   - hdu.append(col_telmask);
1003 812 hdu.append(col_ra);
1004 813 hdu.append(col_dec);
1005   - hdu.append(col_direrr);
1006   - hdu.append(col_detx);
1007   - hdu.append(col_dety);
1008   - hdu.append(col_alt);
1009   - hdu.append(col_az);
1010   - hdu.append(col_corex);
1011   - hdu.append(col_corey);
1012   - hdu.append(col_core_err);
1013   - hdu.append(col_xmax);
1014   - hdu.append(col_xmax_err);
1015   - hdu.append(col_shw);
1016   - hdu.append(col_shl);
1017 814 hdu.append(col_energy);
1018   - hdu.append(col_energy_err);
1019   - hdu.append(col_hil_msw);
1020   - hdu.append(col_hil_msw_err);
1021   - hdu.append(col_hil_msl);
1022   - hdu.append(col_hil_msl_err);
1023 815  
1024   - // Optionally write phase column
  816 + // If available, add detector coordinates in degrees
  817 + if (m_has_detxy) {
  818 + GFitsTableFloatCol col_detx = GFitsTableFloatCol("DETX", size());
  819 + GFitsTableFloatCol col_dety = GFitsTableFloatCol("DETY", size());
  820 + for (int i = 0; i < size(); ++i) {
  821 + col_detx(i) = m_events[i].dir().detx() * gammalib::rad2deg;
  822 + col_dety(i) = m_events[i].dir().dety() * gammalib::rad2deg;
  823 + }
  824 + hdu.append(col_detx);
  825 + hdu.append(col_dety);
  826 + }
  827 +
  828 + // If available, add event phase
1025 829 if (m_has_phase) {
  830 + GFitsTableFloatCol col_phase = GFitsTableFloatCol("PHASE", size());
  831 + for (int i = 0; i < size(); ++i) {
  832 + col_phase(i) = m_events[i].m_phase;
  833 + }
1026 834 hdu.append(col_phase);
1027 835 }
1028 836  
  837 + // Append other columns to table
  838 + for (int i = 0; i < m_columns.size(); ++i) {
  839 + hdu.append(*m_columns[i]);
  840 + }
  841 +
1029 842 } // endif: there were events to write
1030 843  
1031 844 // Return
... ...