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 * Version 1.6.0 released 3 * Version 1.6.0 released
4 ======================== 4 ========================
@@ -7,6 +7,7 @@ @@ -7,6 +7,7 @@
7 Change formula for number of true energy bins in csphagen (#2490) 7 Change formula for number of true energy bins in csphagen (#2490)
8 Remove ctools::is_valid_filename() method 8 Remove ctools::is_valid_filename() method
9 Fix bug when using precomputed model in csresspec (#2448) 9 Fix bug when using precomputed model in csresspec (#2448)
  10 + Parallelise cslightcrv (#2421)
10 Keep existing library path in installation script on Mac OS X (#2420) 11 Keep existing library path in installation script on Mac OS X (#2420)
11 csphagen produces Xspec compliant data (#2404) 12 csphagen produces Xspec compliant data (#2404)
12 Add show_rmf.py example script 13 Add show_rmf.py example script
1 New Features and Important Changes in ctools 1.6.0 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 Introduction 6 Introduction
@@ -193,6 +193,9 @@ None @@ -193,6 +193,9 @@ None
193 193
194 cslightcrv - Generate light curve 194 cslightcrv - Generate light curve
195 --------------------------------- 195 ---------------------------------
  196 +Add hidden "nthreads" parameter and implement parallelisation of light
  197 +curve computation (#2421).
  198 +
196 Add hidden "mjdref" parameter for the specification of the MET reference 199 Add hidden "mjdref" parameter for the specification of the MET reference
197 (#2054). 200 (#2054).
198 201
cscripts/cslightcrv.par
@@ -62,13 +62,13 @@ fix_bkg, b, h, no,,, "Fix background model parameters?" @@ -62,13 +62,13 @@ fix_bkg, b, h, no,,, "Fix background model parameters?"
62 # 62 #
63 # Standard parameters 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,6 +26,33 @@ from cscripts import ioutils
26 from cscripts import mputils 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 # cslightcrv class # 57 # cslightcrv class #
31 # ================ # 58 # ================ #
@@ -73,11 +100,12 @@ class cslightcrv(ctools.csobservation): @@ -73,11 +100,12 @@ class cslightcrv(ctools.csobservation):
73 self._init_csobservation(self.__class__.__name__, ctools.__version__, argv) 100 self._init_csobservation(self.__class__.__name__, ctools.__version__, argv)
74 101
75 # Initialise some members 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 # Return 110 # Return
83 return 111 return
@@ -87,31 +115,42 @@ class cslightcrv(ctools.csobservation): @@ -87,31 +115,42 @@ class cslightcrv(ctools.csobservation):
87 """ 115 """
88 Extend ctools.csobservation getstate method to include some members 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 state = {'base' : ctools.csobservation.__getstate__(self), 124 state = {'base' : ctools.csobservation.__getstate__(self),
95 'srcname' : self._srcname, 125 'srcname' : self._srcname,
96 'tbins' : self._tbins, 126 'tbins' : self._tbins,
97 'stacked' : self._stacked, 127 'stacked' : self._stacked,
98 'onoff' : self._onoff, 128 'onoff' : self._onoff,
99 - 'fits' : self._fits} 129 + 'fits' : self._fits,
  130 + 'nthreads' : self._nthreads}
  131 +
  132 + # Return pickled dictionary
100 return state 133 return state
101 134
102 def __setstate__(self, state): 135 def __setstate__(self, state):
103 """ 136 """
104 Extend ctools.csobservation setstate method to include some members 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 ctools.csobservation.__setstate__(self, state['base']) 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 # Private methods 155 # Private methods
117 def _get_parameters(self): 156 def _get_parameters(self):
@@ -399,16 +438,20 @@ class cslightcrv(ctools.csobservation): @@ -399,16 +438,20 @@ class cslightcrv(ctools.csobservation):
399 # Return upper limit tuple 438 # Return upper limit tuple
400 return ul_diff, ul_flux, ul_eflux 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 # Get names of free parameters 455 # Get names of free parameters
413 pars = self._get_free_par_names() 456 pars = self._get_free_par_names()
414 457
@@ -611,8 +654,19 @@ class cslightcrv(ctools.csobservation): @@ -611,8 +654,19 @@ class cslightcrv(ctools.csobservation):
611 pool = Pool(processes = self._nthreads) 654 pool = Pool(processes = self._nthreads)
612 655
613 # Run time bin analysis in parallel with map 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 # Otherwise loop over time bins and run time bin analysis 670 # Otherwise loop over time bins and run time bin analysis
617 else: 671 else:
618 results = [] 672 results = []
cscripts/mputils.py
1 # ========================================================================== 1 # ==========================================================================
2 # Utility functions for multiprocessing handling 2 # Utility functions for multiprocessing handling
3 # 3 #
4 -# Copyright (C) 2018- Luigi Tibaldo 4 +# Copyright (C) 2018 Luigi Tibaldo
5 # 5 #
6 # This program is free software: you can redistribute it and/or modify 6 # This program is free software: you can redistribute it and/or modify
7 # it under the terms of the GNU General Public License as published by 7 # it under the terms of the GNU General Public License as published by
@@ -23,44 +23,50 @@ import gammalib @@ -23,44 +23,50 @@ import gammalib
23 # ==================== # 23 # ==================== #
24 # Number of processes # 24 # Number of processes #
25 # ==================== # 25 # ==================== #
26 -  
27 def nthreads(cls): 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 cscript class 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 # Log multiprocessing configuration 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 try: 47 try:
42 from multiprocessing import cpu_count 48 from multiprocessing import cpu_count
43 ncpus = cpu_count() 49 ncpus = cpu_count()
  50 + cls._log_value(gammalib.NORMAL, 'Multiprocessing', 'available')
44 cls._log_value(gammalib.EXPLICIT, 'Number of CPUs available', ncpus) 51 cls._log_value(gammalib.EXPLICIT, 'Number of CPUs available', ncpus)
45 52
46 # Set processes to number of CPUs if requested by the user 53 # Set processes to number of CPUs if requested by the user
47 if cls['nthreads'].integer() == 0: 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 else: 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 cls['nthreads'].integer()) 61 cls['nthreads'].integer())
54 - nthr = cls['nthreads'].integer() 62 + nthreads = cls['nthreads'].integer()
55 63
56 except: 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 # Log number of processes 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,6 +12,7 @@ In particular, this release provides:
12 12
13 * Support for Xspec spectral analysis 13 * Support for Xspec spectral analysis
14 * Improved computation speed for :ref:`ctskymap` and :ref:`csphagen` 14 * Improved computation speed for :ref:`ctskymap` and :ref:`csphagen`
  15 +* Parallelisation of :ref:`cslightcrv`
15 * Support for Python pickeling 16 * Support for Python pickeling
16 17
17 18
@@ -31,6 +32,8 @@ Improvements @@ -31,6 +32,8 @@ Improvements
31 Transparently update parameter files 32 Transparently update parameter files
32 * [`2490 <https://cta-redmine.irap.omp.eu/issues/2490>`_] - 33 * [`2490 <https://cta-redmine.irap.omp.eu/issues/2490>`_] -
33 Change formula for number of true energy bins in :ref:`csphagen` 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 * [`2404 <https://cta-redmine.irap.omp.eu/issues/2404>`_] - 37 * [`2404 <https://cta-redmine.irap.omp.eu/issues/2404>`_] -
35 :ref:`csphagen` produces Xspec compliant data 38 :ref:`csphagen` produces Xspec compliant data
36 * Add ``show_rmf.py`` example script 39 * Add ``show_rmf.py`` example script
doc/source/users/reference_manual/cslightcrv.rst
@@ -177,6 +177,9 @@ General parameters @@ -177,6 +177,9 @@ General parameters
177 Standard parameters 177 Standard parameters
178 ------------------- 178 -------------------
179 179
  180 +``(nthreads = 0) [integer]``
  181 + Number of parallel processes (0=use all available CPUs).
  182 +
180 ``(publish = no) [boolean]`` 183 ``(publish = no) [boolean]``
181 Specifies whether the light curve should be published on VO Hub. 184 Specifies whether the light curve should be published on VO Hub.
182 185
pyext/ctool.i
@@ -222,9 +222,9 @@ public: @@ -222,9 +222,9 @@ public:
222 const std::string& what = "Observation") { 222 const std::string& what = "Observation") {
223 self->log_observations(GChatter(chatter), obs, what); 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 self->log_models(GChatter(chatter), models, what); 228 self->log_models(GChatter(chatter), models, what);
229 } 229 }
230 void _read_ahead(const bool& flag) { 230 void _read_ahead(const bool& flag) {