Commit 63eefbeaefac759af3fb7d5b15582b94e9c402e3

Authored by Jürgen Knödlseder
1 parent dcc6376a

Parallelise cslightcrv (#2421)

ChangeLog
1   -2018-06-29
  1 +2018-07-03
2 2  
3 3 * Version 1.6.0 released
4 4 ========================
... ... @@ -7,6 +7,7 @@
7 7 Change formula for number of true energy bins in csphagen (#2490)
8 8 Remove ctools::is_valid_filename() method
9 9 Fix bug when using precomputed model in csresspec (#2448)
  10 + Parallelise cslightcrv (#2421)
10 11 Keep existing library path in installation script on Mac OS X (#2420)
11 12 csphagen produces Xspec compliant data (#2404)
12 13 Add show_rmf.py example script
... ...
1 1 New Features and Important Changes in ctools 1.6.0
2 2  
3   -29 June 2018
  3 +3 July 2018
4 4  
5 5  
6 6 Introduction
... ... @@ -193,6 +193,9 @@ None
193 193  
194 194 cslightcrv - Generate light curve
195 195 ---------------------------------
  196 +Add hidden "nthreads" parameter and implement parallelisation of light
  197 +curve computation (#2421).
  198 +
196 199 Add hidden "mjdref" parameter for the specification of the MET reference
197 200 (#2054).
198 201  
... ...
cscripts/cslightcrv.par
... ... @@ -62,13 +62,13 @@ fix_bkg, b, h, no,,, "Fix background model parameters?"
62 62 #
63 63 # Standard parameters
64 64 #====================
65   -publish, b, h, no,,, "Publish light curve on VO Hub?"
66   -chatter, i, h, 2,0,4, "Chattiness of output"
67   -clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
68   -debug, b, h, no,,, "Activate debugging mode?"
69   -mode, s, h, ql,,, "Mode of automatic parameters"
70   -logfile, f, h, cslightcrv.log,,, "Log filename"
71   -nthreads,i, h, 0,0,1000, "Number of parallel processes. 0 = number of available CPUs."
  65 +nthreads, i, h, 0,0,1000, "Number of parallel processes (0=use all available CPUs)"
  66 +publish, b, h, no,,, "Publish light curve on VO Hub?"
  67 +chatter, i, h, 2,0,4, "Chattiness of output"
  68 +clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
  69 +debug, b, h, no,,, "Activate debugging mode?"
  70 +mode, s, h, ql,,, "Mode of automatic parameters"
  71 +logfile, f, h, cslightcrv.log,,, "Log filename"
72 72  
73 73  
74 74  
... ...
cscripts/cslightcrv.py
... ... @@ -26,6 +26,33 @@ from cscripts import ioutils
26 26 from cscripts import mputils
27 27  
28 28  
  29 +# ============================================ #
  30 +# Global functions for multiprocessing support #
  31 +# ============================================ #
  32 +def _multiprocessing_func_wrapper(args):
  33 + return _multiprocessing_func(*args)
  34 +def _multiprocessing_func(cls, i):
  35 +
  36 + # Initialise thread logger
  37 + cls._log.clear()
  38 + cls._log.buffer_size(100000)
  39 +
  40 + # Compute light curve bin
  41 + cstart = cls.celapse()
  42 + result = cls._timebin(i)
  43 + celapse = cls.celapse() - cstart
  44 + buffer = cls._log.buffer()
  45 +
  46 + # Close logger
  47 + cls._log.close()
  48 +
  49 + # Collect thread information
  50 + info = {'celapse': celapse, 'log': buffer}
  51 +
  52 + # Return light curve bin result and thread information
  53 + return result, info
  54 +
  55 +
29 56 # ================ #
30 57 # cslightcrv class #
31 58 # ================ #
... ... @@ -73,11 +100,12 @@ class cslightcrv(ctools.csobservation):
73 100 self._init_csobservation(self.__class__.__name__, ctools.__version__, argv)
74 101  
75 102 # Initialise some members
76   - self._srcname = ''
77   - self._tbins = gammalib.GGti()
78   - self._onoff = False
79   - self._stacked = False
80   - self._fits = gammalib.GFits()
  103 + self._srcname = ''
  104 + self._tbins = gammalib.GGti()
  105 + self._onoff = False
  106 + self._stacked = False
  107 + self._fits = gammalib.GFits()
  108 + self._nthreads = 0
81 109  
82 110 # Return
83 111 return
... ... @@ -87,31 +115,42 @@ class cslightcrv(ctools.csobservation):
87 115 """
88 116 Extend ctools.csobservation getstate method to include some members
89 117  
90   - :return: dictionary
91   - state
  118 + Returns
  119 + -------
  120 + state : dict
  121 + Pickled instance
92 122 """
93   -
  123 + # Set pickled dictionary
94 124 state = {'base' : ctools.csobservation.__getstate__(self),
95 125 'srcname' : self._srcname,
96 126 'tbins' : self._tbins,
97 127 'stacked' : self._stacked,
98 128 'onoff' : self._onoff,
99   - 'fits' : self._fits}
  129 + 'fits' : self._fits,
  130 + 'nthreads' : self._nthreads}
  131 +
  132 + # Return pickled dictionary
100 133 return state
101 134  
102 135 def __setstate__(self, state):
103 136 """
104 137 Extend ctools.csobservation setstate method to include some members
105 138  
106   - :param state: dictionary of class state
  139 + Parameters
  140 + ----------
  141 + state : dict
  142 + Pickled instance
107 143 """
108   -
109 144 ctools.csobservation.__setstate__(self, state['base'])
110   - self._srcname = state['srcname']
111   - self._tbins = state['tbins']
112   - self._onoff = state['onoff']
113   - self._stacked = state['stacked']
114   - self._fits = state['fits']
  145 + self._srcname = state['srcname']
  146 + self._tbins = state['tbins']
  147 + self._onoff = state['onoff']
  148 + self._stacked = state['stacked']
  149 + self._fits = state['fits']
  150 + self._nthreads = state['nthreads']
  151 +
  152 + # Return
  153 + return
115 154  
116 155 # Private methods
117 156 def _get_parameters(self):
... ... @@ -399,16 +438,20 @@ class cslightcrv(ctools.csobservation):
399 438 # Return upper limit tuple
400 439 return ul_diff, ul_flux, ul_eflux
401 440  
402   -
403   - def _timebin(self,i):
  441 + def _timebin(self, i):
404 442 """
405   - Run likelihood analysis in one time bin.
  443 + Run likelihood analysis in one time bin
406 444  
407   - :param i: integer, time bin number
408   - :return: dictionary,
409   - results of the likelihood analysis
410   - """
  445 + Parameters
  446 + ----------
  447 + i : int
  448 + time bin number
411 449  
  450 + Returns
  451 + -------
  452 + result : dict
  453 + Results of the likelihood analysis
  454 + """
412 455 # Get names of free parameters
413 456 pars = self._get_free_par_names()
414 457  
... ... @@ -611,8 +654,19 @@ class cslightcrv(ctools.csobservation):
611 654 pool = Pool(processes = self._nthreads)
612 655  
613 656 # Run time bin analysis in parallel with map
614   - results = pool.map(self._timebin,range(self._tbins.size()))
615   -
  657 + args = [(self, i) for i in range(self._tbins.size())]
  658 + poolresults = pool.map(_multiprocessing_func_wrapper, args)
  659 +
  660 + # Close pool and join
  661 + pool.close()
  662 + pool.join()
  663 +
  664 + # Construct results
  665 + results = []
  666 + for i in range(self._tbins.size()):
  667 + results.append(poolresults[i][0])
  668 + self._log_string(gammalib.TERSE, poolresults[i][1]['log'], False)
  669 +
616 670 # Otherwise loop over time bins and run time bin analysis
617 671 else:
618 672 results = []
... ...
cscripts/mputils.py
1 1 # ==========================================================================
2 2 # Utility functions for multiprocessing handling
3 3 #
4   -# Copyright (C) 2018- Luigi Tibaldo
  4 +# Copyright (C) 2018 Luigi Tibaldo
5 5 #
6 6 # This program is free software: you can redistribute it and/or modify
7 7 # it under the terms of the GNU General Public License as published by
... ... @@ -23,44 +23,50 @@ import gammalib
23 23 # ==================== #
24 24 # Number of processes #
25 25 # ==================== #
26   -
27 26 def nthreads(cls):
28 27 """
29   - Determines the number of parallel processes to use,
30   - based on user parameters and availability of multiprocessing module
  28 + Determines the number of parallel processes to use.
  29 +
  30 + The number is based on the user parameter "nthreads" and the availability
  31 + of the multiprocessing module.
31 32  
32   - :param cls: `~ctools.cscript`
  33 + Parameters
  34 + ----------
  35 + cls : `~ctools.cscript`
33 36 cscript class
34   - :return: int
35   - number of parallel processes
36   - """
37 37  
  38 + Returns
  39 + -------
  40 + nthreads : int
  41 + Number of parallel processes
  42 + """
38 43 # Log multiprocessing configuration
39   - cls._log_header1(gammalib.NORMAL, "Multiprocessing")
  44 + cls._log_header1(gammalib.NORMAL, 'Multiprocessing')
40 45  
  46 + # Try getting multiprocessing support
41 47 try:
42 48 from multiprocessing import cpu_count
43 49 ncpus = cpu_count()
  50 + cls._log_value(gammalib.NORMAL, 'Multiprocessing', 'available')
44 51 cls._log_value(gammalib.EXPLICIT, 'Number of CPUs available', ncpus)
45 52  
46 53 # Set processes to number of CPUs if requested by the user
47 54 if cls['nthreads'].integer() == 0:
48   - nthr = ncpus
  55 + nthreads = ncpus
49 56  
50   - # Otherwise use the number requested
  57 + # ... otherwise use the number requested
51 58 else:
52   - cls._log_value(gammalib.EXPLICIT, 'Number of processes requested by the user',
  59 + cls._log_value(gammalib.EXPLICIT,
  60 + 'Number of processes requested',
53 61 cls['nthreads'].integer())
54   - nthr = cls['nthreads'].integer()
  62 + nthreads = cls['nthreads'].integer()
55 63  
56 64 except:
57   - nthr = 1
58   - cls._log_value(gammalib.EXPLICIT,
59   - 'Multiprocessing not available. Number of processes', nthr)
60   -
  65 + nthreads = 1
  66 + cls._log_value(gammalib.NORMAL, 'Multiprocessing', 'not available')
61 67  
62 68 # Log number of processes
63   - cls._log_value(gammalib.NORMAL, 'Number of parallel processes in use', nthr)
  69 + cls._log_value(gammalib.NORMAL, 'Number of processes in use', nthreads)
64 70  
65   - # return number of processes to be used
66   - return nthr
  71 + # Return number of processes to be used
  72 + return nthreads
... ...
doc/source/admin/release_history/1.6.rst
... ... @@ -12,6 +12,7 @@ In particular, this release provides:
12 12  
13 13 * Support for Xspec spectral analysis
14 14 * Improved computation speed for :ref:`ctskymap` and :ref:`csphagen`
  15 +* Parallelisation of :ref:`cslightcrv`
15 16 * Support for Python pickeling
16 17  
17 18  
... ... @@ -31,6 +32,8 @@ Improvements
31 32 Transparently update parameter files
32 33 * [`2490 <https://cta-redmine.irap.omp.eu/issues/2490>`_] -
33 34 Change formula for number of true energy bins in :ref:`csphagen`
  35 +* [`2421 <https://cta-redmine.irap.omp.eu/issues/2421>`_] -
  36 + Parallelise :ref:`cslightcrv`
34 37 * [`2404 <https://cta-redmine.irap.omp.eu/issues/2404>`_] -
35 38 :ref:`csphagen` produces Xspec compliant data
36 39 * Add ``show_rmf.py`` example script
... ...
doc/source/users/reference_manual/cslightcrv.rst
... ... @@ -177,6 +177,9 @@ General parameters
177 177 Standard parameters
178 178 -------------------
179 179  
  180 +``(nthreads = 0) [integer]``
  181 + Number of parallel processes (0=use all available CPUs).
  182 +
180 183 ``(publish = no) [boolean]``
181 184 Specifies whether the light curve should be published on VO Hub.
182 185  
... ...
pyext/ctool.i
... ... @@ -222,9 +222,9 @@ public:
222 222 const std::string& what = "Observation") {
223 223 self->log_observations(GChatter(chatter), obs, what);
224 224 }
225   - void _log_models(const int& chatter,
226   - const GModels& models,
227   - const std::string& what = "Model") {
  225 + void _log_models(const int& chatter,
  226 + const GModels& models,
  227 + const std::string& what = "Model") {
228 228 self->log_models(GChatter(chatter), models, what);
229 229 }
230 230 void _read_ahead(const bool& flag) {
... ...