Commit 63eefbeaefac759af3fb7d5b15582b94e9c402e3
1 parent
dcc6376a
Parallelise cslightcrv (#2421)
Showing
8 changed files
with
127 additions
and
57 deletions
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 |
NEWS
| 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) { |