Commit b6b50dc00463c2ae4f00ba9da68a9f8f687aa7bb

Authored by Jürgen Knödlseder
2 parents 89317305 bc79a4f9

Merge branch 'devel' into release

# Conflicts:
#	ChangeLog
#	NEWS
#	README
#	inst/cta/src/GCTAEdisp2D.cpp
ChangeLog
1   -2015-12-17 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
  1 +2015-12-18 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
2 2  
3 3 * Version 1.0.0 released
4 4 =========================
5 5  
6 6 Ignore errors for El Capitan post processing (#1605)
  7 + Read only mandatary columns in GCTAEventList (#1600)
  8 + Add GModel::has_ts() method (#1578)
7 9 Remove extname arguments from classes (#1601)
8 10 Add GFilename class (#1599)
9 11 Check existence of files in CTA response loading (#1586)
10 12 GSkyMap::__getitem__ throw exception if out of bound (#1581)
11 13 Handle ~ in filenames (#1580)
  14 + Add GModel::has_ts() method (#1578)
12 15 Perform __init__.py creation only in build step (#1569)
13 16 Remove access by name methods from GSkyRegions (#1564)
14 17 Resolve Python test problem on El Capitan (#1563)
... ...
... ... @@ -58,7 +58,8 @@ None
58 58  
59 59 8. Model module
60 60 ---------------
61   -None
  61 +Added GModel::has_ts() method that signals if a TS value has been computed
  62 +for a given model.
62 63  
63 64  
64 65 9. Numerics module
... ... @@ -134,9 +135,12 @@ None
134 135  
135 136 20. CTA interface
136 137 -----------------
137   -The IRF loaders now check the existence of the file before loading, and now throw
  138 +The IRF loaders now check the existence of the file before loading, and now throws
138 139 appropriate error messages in case that the files do not exist (#1586).
139 140  
  141 +Only manadatory columns are read by GCTAEventsList, while any other columns will only
  142 +be stored for back writing in a FITS file.
  143 +
140 144  
141 145 21. COMPTEL interface
142 146 ---------------------
... ...
configure.ac
... ... @@ -29,7 +29,7 @@
29 29 #############################################################################
30 30 # Initialisation #
31 31 #############################################################################
32   -AC_INIT([gammalib], [1.0.0], [jurgen.knodlseder@irap.omp.eu], [gammalib])
  32 +AC_INIT([gammalib], [1.1.0.dev], [jurgen.knodlseder@irap.omp.eu], [gammalib])
33 33 AC_CONFIG_SRCDIR([src/support/GTools.cpp])
34 34 AC_CONFIG_MACRO_DIR([m4])
35 35 AM_INIT_AUTOMAKE([gnu no-dependencies -Wno-portability subdir-objects])
... ...
doc/Doxyfile
... ... @@ -32,7 +32,7 @@ PROJECT_NAME = GammaLib
32 32 # This could be handy for archiving the generated documentation or
33 33 # if some version control system is used.
34 34  
35   -PROJECT_NUMBER = 1.0.0
  35 +PROJECT_NUMBER = 1.1.0.dev
36 36  
37 37 # Using the PROJECT_BRIEF tag one can provide an optional one line description
38 38 # for a project that appears at the top of each page and should give viewer
... ...
doc/source/conf.py
... ... @@ -55,9 +55,10 @@ copyright = u&#39;2006-2015, GammaLib developers&#39;
55 55 # built documents.
56 56 #
57 57 # The short X.Y version.
58   -version = '1.0'
  58 +version = '1.1'
  59 +
59 60 # The full version, including alpha/beta/rc tags.
60   -release = '1.0.0'
  61 +release = '1.1.0.dev'
61 62  
62 63 # The language for content autogenerated by Sphinx. Refer to documentation
63 64 # for a list of supported languages.
... ...
include/GModel.hpp
... ... @@ -139,6 +139,7 @@ public:
139 139 void ts(const double& ts);
140 140 const bool& tscalc(void) const;
141 141 void tscalc(const bool& tscalc);
  142 + const bool& has_ts(void) const;
142 143 std::string instruments(void) const;
143 144 void instruments(const std::string& instruments);
144 145 GModelPar scale(const std::string& instrument) const;
... ... @@ -314,7 +315,7 @@ void GModel::tscalc(const bool&amp; tscalc)
314 315 /***********************************************************************//**
315 316 * @brief Signals that model has scales
316 317 *
317   - * @return True is model has scale factors.
  318 + * @return True if model has scale factors.
318 319 ***************************************************************************/
319 320 inline
320 321 bool GModel::has_scales(void) const
... ... @@ -322,4 +323,16 @@ bool GModel::has_scales(void) const
322 323 return (!m_scales.empty());
323 324 }
324 325  
  326 +
  327 +/***********************************************************************//**
  328 + * @brief Signals that model has Test Statistics value
  329 + *
  330 + * @return True if model has TS value.
  331 + ***************************************************************************/
  332 +inline
  333 +const bool& GModel::has_ts(void) const
  334 +{
  335 + return m_has_ts;
  336 +}
  337 +
325 338 #endif /* GMODEL_HPP */
... ...
include/GVOHub.hpp
... ... @@ -108,11 +108,14 @@ protected:
108 108  
109 109 // Low-level methods
110 110 void create_samp_file(void) const;
  111 + void delete_samp_file(void) const;
  112 + int get_socket(void);
111 113 void post_samp_ok(const socklen_t& sock) const;
112 114 void post_samp_void(const socklen_t& sock) const;
113 115 void post_string(const std::string& content, const socklen_t& sock) const;
114 116 void notify(const std::string& url, const std::string& notification) const;
115 117 std::string random_string(const size_t& length) const;
  118 + std::string hub_url(void) const;
116 119  
117 120 // Protected structure
118 121 struct client {
... ... @@ -132,7 +135,6 @@ protected:
132 135  
133 136 // Protected members
134 137 std::string m_secret; //!< Secret Hub key
135   - std::string m_hub_url; //!< The XML-RPC endpoint for communication with the hub
136 138 std::string m_hub_host; //!< Hub host
137 139 std::string m_hub_port; //!< Hub port
138 140 std::string m_hub_path; //!< Hub path
... ...
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
... ...
pyext/GModel.i
... ... @@ -72,6 +72,7 @@ public:
72 72 void ts(const double& ts);
73 73 const bool& tscalc(void) const;
74 74 void tscalc(const bool& tscalc);
  75 + const bool& has_ts(void) const;
75 76 GModelPar scale(const std::string& instrument) const;
76 77 void scale(const GModelPar& par);
77 78 std::string ids(void) const;
... ...
src/vo/GVOClient.cpp
... ... @@ -517,7 +517,7 @@ bool GVOClient::find_hub(void)
517 517 if (!lockurl.empty()) {
518 518  
519 519 // If we have a file:// prefix then strip it now. This is a kluge
520   - // and should be remplaced by a method that allows opening any kind
  520 + // and should be replaced by a method that allows opening any kind
521 521 // of URL
522 522 if (lockurl.compare(0, 7, "file://") == 0) {
523 523 lockurl = lockurl.substr(7, std::string::npos);
... ... @@ -955,7 +955,6 @@ std::string GVOClient::receive_string(void) const
955 955 int n = 0;
956 956 do {
957 957 n = gammalib::recv(m_socket, buffer, 1000, 0, timeout);
958   - //n = recv(m_socket, buffer, 1000, 0);
959 958 if (n > 0) {
960 959 buffer[n] = '\0';
961 960 result.append(std::string(buffer));
... ... @@ -1074,7 +1073,7 @@ std::string GVOClient::get_hub_lockfile(void) const
1074 1073 char* hub_ptr = std::getenv("SAMP_HUB");
1075 1074 if (hub_ptr != NULL) {
1076 1075  
1077   - // Check for mandatory std-lockurl: prefix (no other prefixe is
  1076 + // Check for mandatory std-lockurl: prefix (no other prefix is
1078 1077 // supported so far)
1079 1078 std::string lockurl = std::string(hub_ptr);
1080 1079 if (lockurl.compare(0, 12, "std-lockurl:") == 0) {
... ... @@ -1084,7 +1083,7 @@ std::string GVOClient::get_hub_lockfile(void) const
1084 1083  
1085 1084 } // endif: std-lockurl: prefix found
1086 1085  
1087   - }
  1086 + } // endif: SAMP_HUB environment variable found
1088 1087  
1089 1088 // ... otherwise the lockfile should be $HOME/.samp
1090 1089 else {
... ...
src/vo/GVOHub.cpp
... ... @@ -47,6 +47,7 @@
47 47  
48 48 /* __ Method name definitions ____________________________________________ */
49 49 #define G_START_HUB "GVOHub::start_hub()"
  50 +#define G_START_SOCKET "GVOHub::start_socket()"
50 51  
51 52 /* __ Macros _____________________________________________________________ */
52 53  
... ... @@ -179,9 +180,6 @@ GVOHub* GVOHub::clone(void) const
179 180 ***************************************************************************/
180 181 void GVOHub::start(void)
181 182 {
182   - // Create SAMP file
183   - create_samp_file();
184   -
185 183 // Start Hub
186 184 start_hub();
187 185  
... ... @@ -210,7 +208,7 @@ std::string GVOHub::print(const GChatter&amp; chatter) const
210 208 // Append Hub information
211 209 result.append("\n"+gammalib::parformat("Hub identifier")+m_hub_id);
212 210 result.append("\n"+gammalib::parformat("Hub key")+m_secret);
213   - result.append("\n"+gammalib::parformat("Hub URL")+m_hub_url);
  211 + result.append("\n"+gammalib::parformat("Hub URL")+hub_url());
214 212 result.append("\n"+gammalib::parformat("Hub host")+m_hub_host);
215 213 result.append("\n"+gammalib::parformat("Hub port")+m_hub_port);
216 214 result.append("\n"+gammalib::parformat("Hub path")+m_hub_path);
... ... @@ -240,7 +238,6 @@ void GVOHub::init_members(void)
240 238 m_hub_host = "127.0.0.1";
241 239 m_hub_port = "2526";
242 240 m_hub_path = "xmlrpc";
243   - m_hub_url = "http://"+m_hub_host+":"+m_hub_port+"/"+m_hub_path;
244 241 m_version = "1.3";
245 242 m_hub_id = "gammalib_hub";
246 243 m_socket = -1; // Signals no socket
... ... @@ -261,7 +258,6 @@ void GVOHub::copy_members(const GVOHub&amp; hub)
261 258 {
262 259 // Copy members
263 260 m_secret = hub.m_secret;
264   - m_hub_url = hub.m_hub_url;
265 261 m_hub_host = hub.m_hub_host;
266 262 m_hub_port = hub.m_hub_port;
267 263 m_hub_path = hub.m_hub_path;
... ... @@ -288,8 +284,7 @@ void GVOHub::free_members(void)
288 284 }
289 285  
290 286 // Remove lockfile
291   - std::string lockurl = get_hub_lockfile();
292   - std::remove(lockurl.c_str());
  287 + delete_samp_file();
293 288  
294 289 // Return
295 290 return;
... ... @@ -306,46 +301,13 @@ void GVOHub::free_members(void)
306 301 ***************************************************************************/
307 302 void GVOHub::start_hub(void)
308 303 {
309   - // Prepare TCP/IP structure
310   - struct sockaddr_in serv_addr;
311   - std::memset(&serv_addr, 0, sizeof(serv_addr));
312   - serv_addr.sin_family = AF_INET;
313   - serv_addr.sin_addr.s_addr = inet_addr(m_hub_host.c_str());
314   - serv_addr.sin_port = htons(gammalib::toint(m_hub_port));
315   -
316   - // Create Hub socket
317   - m_socket = socket(AF_INET, SOCK_STREAM, 0);
318   -
319   - // Creation of hub main socket
320   - if (m_socket < 0) {
321   - std::string msg = "Unable to create Hub socket. Errno="+
322   - gammalib::str(errno);
323   - throw GException::runtime_error(G_START_HUB, msg);
324   - }
325   -
326   - // Set hub main socket to allow multiple connections
327   - int opt = 1;
328   - if (setsockopt(m_socket, SOL_SOCKET, SO_REUSEADDR, (char*)&opt, sizeof(opt)) < 0) {
329   - std::string msg = "Unable to set Hub socket to multiple connections."
330   - " Errno="+gammalib::str(errno);
331   - throw GException::runtime_error(G_START_HUB, msg);
332   - }
333   - #ifdef SO_REUSEPORT
334   - if (setsockopt(m_socket, SOL_SOCKET, SO_REUSEPORT, (char*)&opt, sizeof(opt)) < 0) {
335   - std::string msg = "Unable to set Hub socket to multiple connections."
336   - " Errno="+gammalib::str(errno);
337   - throw GException::runtime_error(G_START_HUB, msg);
338   - }
339   - #endif
340   -
341   - // Server socket is opened. Now, bind it to the port, with family etc.
342   - if (bind(m_socket, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
343   - std::string msg = "Unable to bind Hub socket to server socket. Errno="+
344   - gammalib::str(errno);
345   - throw GException::runtime_error(G_START_HUB, msg);
346   - }
  304 + // Get socket
  305 + m_socket = get_socket();
  306 +
  307 + // Create SAMP file
  308 + create_samp_file();
347 309  
348   - // Now start listening for the clients: 5 requests simultaneously pending
  310 + // Start listening for the clients: 5 requests simultaneously pending
349 311 // at maximum
350 312 if (listen(m_socket, 5) < 0) {
351 313 std::string msg = "Unable to start listening on Hub socket. Errno="+
... ... @@ -385,6 +347,9 @@ void GVOHub::start_hub(void)
385 347 close(m_socket);
386 348 m_socket = -1;
387 349  
  350 + // Delete SAMP file
  351 + delete_samp_file();
  352 +
388 353 // Return
389 354 return;
390 355 }
... ... @@ -596,7 +561,7 @@ void GVOHub::request_register(const GXml&amp; xml, const socklen_t&amp; sock)
596 561 response.append(" </member>\n");
597 562 response.append(" <member>\n");
598 563 response.append(" <name>samp.url-translator</name>\n");
599   - response.append(" <value>"+m_hub_url+"</value>\n");
  564 + response.append(" <value>"+hub_url()+"</value>\n");
600 565 response.append(" </member>\n");
601 566 response.append(" </struct></value></param>\n");
602 567 response.append("</params>\n");
... ... @@ -1628,9 +1593,10 @@ void GVOHub::send_notifications(const std::string&amp; method,
1628 1593  
1629 1594  
1630 1595 /***********************************************************************//**
1631   - * @brief Creates the lockfile, fill it
  1596 + * @brief Create the lockfile
1632 1597 *
1633   - * Implements IVOA standard REC-SAMP-1.3-20120411.
  1598 + * Creates the SAMP lockfile and fill it with information. Implements IVOA
  1599 + * standard REC-SAMP-1.3-20120411.
1634 1600 ***************************************************************************/
1635 1601 void GVOHub::create_samp_file(void) const
1636 1602 {
... ... @@ -1647,7 +1613,7 @@ void GVOHub::create_samp_file(void) const
1647 1613 fprintf(fptr, "# SAMP lockfile\n");
1648 1614 fprintf(fptr, "# Required keys:\n");
1649 1615 fprintf(fptr, "samp.secret=%s\n", m_secret.c_str());
1650   - fprintf(fptr, "samp.hub.xmlrpc.url=%s\n", m_hub_url.c_str());
  1616 + fprintf(fptr, "samp.hub.xmlrpc.url=%s\n", hub_url().c_str());
1651 1617 fprintf(fptr, "samp.profile.version=%s\n", m_version.c_str());
1652 1618 fprintf(fptr, "# Info stored by hub for some private reason:\n");
1653 1619 fprintf(fptr, "gammalib.hubid=%s\n", m_hub_id.c_str());
... ... @@ -1663,6 +1629,87 @@ void GVOHub::create_samp_file(void) const
1663 1629  
1664 1630  
1665 1631 /***********************************************************************//**
  1632 + * @brief Delete the lockfile
  1633 + *
  1634 + * Deletes the SAMP lockfile on disk.
  1635 + ***************************************************************************/
  1636 +void GVOHub::delete_samp_file(void) const
  1637 +{
  1638 + // Get lockfile URL
  1639 + std::string lockurl = get_hub_lockfile();
  1640 +
  1641 + // Delete lockfile
  1642 + std::remove(lockurl.c_str());
  1643 +
  1644 + // Return
  1645 + return;
  1646 +}
  1647 +
  1648 +
  1649 +/***********************************************************************//**
  1650 + * @brief Get Hub socket
  1651 + *
  1652 + * @return Hub socket (-1 if no socket was found).
  1653 + *
  1654 + * Returns Hub socket. Starting from an initial port of 2526 the method
  1655 + * searches for the next free port and binds it to a socket.
  1656 + ***************************************************************************/
  1657 +int GVOHub::get_socket(void)
  1658 +{
  1659 + // Initialise socket, port and socket address structure
  1660 + int sock = -1;
  1661 + int port = 2526;
  1662 + struct sockaddr_in serv_addr;
  1663 +
  1664 + // Loop over 100 ports at most
  1665 + for (int i = 0; i < 100; ++i) {
  1666 +
  1667 + // Clean TCP/IP structure
  1668 + std::memset(&serv_addr, 0, sizeof(serv_addr));
  1669 +
  1670 + // Set TCP/IP structure
  1671 + serv_addr.sin_family = AF_INET;
  1672 + serv_addr.sin_addr.s_addr = inet_addr(m_hub_host.c_str());
  1673 + serv_addr.sin_port = htons(port);
  1674 +
  1675 + // Create Hub socket
  1676 + sock = socket(AF_INET, SOCK_STREAM, 0);
  1677 +
  1678 + // Creation of hub main socket
  1679 + if (sock < 0) {
  1680 + std::string msg = "Unable to create Hub socket. Errno="+
  1681 + gammalib::str(errno);
  1682 + throw GException::runtime_error(G_START_SOCKET, msg);
  1683 + }
  1684 +
  1685 + // Now bind socket to the address and port
  1686 + if (bind(sock, (struct sockaddr*)&serv_addr, sizeof(serv_addr)) < 0) {
  1687 + if (errno == EADDRINUSE) {
  1688 + port++;
  1689 + close(sock);
  1690 + }
  1691 + else {
  1692 + std::string msg = "Unable to bind Hub socket to address "+
  1693 + m_hub_host+":"+gammalib::str(port)+
  1694 + ". Errno="+gammalib::str(errno);
  1695 + throw GException::runtime_error(G_START_HUB, msg);
  1696 + }
  1697 + }
  1698 + else {
  1699 + break;
  1700 + }
  1701 +
  1702 + } // endfor: looped over ports
  1703 +
  1704 + // Store port as string
  1705 + m_hub_port = gammalib::str(port);
  1706 +
  1707 + // Return socket
  1708 + return sock;
  1709 +}
  1710 +
  1711 +
  1712 +/***********************************************************************//**
1666 1713 * @brief Post string content to client
1667 1714 *
1668 1715 * @param[in] content String content to post.
... ... @@ -1948,3 +1995,20 @@ std::string GVOHub::random_string(const size_t&amp; length) const
1948 1995 return str;
1949 1996 }
1950 1997  
  1998 +
  1999 +/***********************************************************************//**
  2000 + * @brief Return Hub URL
  2001 + *
  2002 + * @return Hub URL.
  2003 + *
  2004 + * Returns the XML-RPC endpoint for communication with the hub.
  2005 + ***************************************************************************/
  2006 +std::string GVOHub::hub_url(void) const
  2007 +{
  2008 + // Set Hub URL
  2009 + std::string hub_url = "http://"+m_hub_host+":"+m_hub_port+"/"+m_hub_path;
  2010 +
  2011 + // Return Hub URL
  2012 + return (hub_url);
  2013 +}
  2014 +
... ...
test/test_GVO.cpp
... ... @@ -175,6 +175,10 @@ int main(void)
175 175 // Allocate test suit container
176 176 GTestSuites testsuites("VO module");
177 177  
  178 + // Unset HOME environment variable (so that the .samp file is written
  179 + // into the test directory)
  180 + unsetenv("HOME");
  181 +
178 182 // Initially assume that we pass all tests
179 183 bool success = true;
180 184  
... ...