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 | 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 | ... | ... |
NEWS
| 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) { | ... | ... |