Commit 56569b2ea8d1b7f6e23fe3e3e4b23ddec884923e

Authored by Luigi Tibaldo
1 parent b3f8e6c6

parallelized csspec

cscripts/csspec.par
... ... @@ -46,9 +46,10 @@ fix_bkg, b, h, no,,, "Fix background parameters"
46 46 #
47 47 # Standard parameters
48 48 #====================
49   -publish, b, h, no,,, "Publish spectrum on VO Hub?"
50   -chatter, i, h, 2,0,4, "Chattiness of output"
51   -clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
52   -debug, b, h, no,,, "Activate debugging mode?"
53   -mode, s, h, ql,,, "Mode of automatic parameters"
54   -logfile, f, h, csspec.log,,, "Log filename"
  49 +nthreads, i, h, 0,0,1000, "Number of parallel processes (0=use all available CPUs)"
  50 +publish, b, h, no,,, "Publish spectrum on VO Hub?"
  51 +chatter, i, h, 2,0,4, "Chattiness of output"
  52 +clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
  53 +debug, b, h, no,,, "Activate debugging mode?"
  54 +mode, s, h, ql,,, "Mode of automatic parameters"
  55 +logfile, f, h, csspec.log,,, "Log filename"
... ...
cscripts/csspec.py
... ... @@ -21,6 +21,33 @@
21 21 import sys
22 22 import gammalib
23 23 import ctools
  24 +from cscripts import mputils
  25 +
  26 +# ============================================ #
  27 +# Global functions for multiprocessing support #
  28 +# ============================================ #
  29 +def _multiprocessing_func_wrapper(args):
  30 + return _multiprocessing_func(*args)
  31 +def _multiprocessing_func(cls, i):
  32 +
  33 + # Initialise thread logger
  34 + cls._log.clear()
  35 + cls._log.buffer_size(100000)
  36 +
  37 + # Compute light curve bin
  38 + cstart = cls.celapse()
  39 + result = cls._fit_energy_bin(i)
  40 + celapse = cls.celapse() - cstart
  41 + buffer = cls._log.buffer()
  42 +
  43 + # Close logger
  44 + cls._log.close()
  45 +
  46 + # Collect thread information
  47 + info = {'celapse': celapse, 'log': buffer}
  48 +
  49 + # Return light curve bin result and thread information
  50 + return result, info
24 51  
25 52  
26 53 # ============ #
... ... @@ -48,6 +75,7 @@ class csspec(ctools.csobservation):
48 75 self._binned_mode = False
49 76 self._onoff_mode = False
50 77 self._method = 'AUTO'
  78 + self._nthreads = 0
51 79  
52 80 # Return
53 81 return
... ... @@ -59,6 +87,48 @@ class csspec(ctools.csobservation):
59 87 # Return
60 88 return
61 89  
  90 + # State methods por pickling
  91 + def __getstate__(self):
  92 + """
  93 + Extend ctools.csobservation getstate method to include some members
  94 +
  95 + Returns
  96 + -------
  97 + state : dict
  98 + Pickled instance
  99 + """
  100 + # Set pickled dictionary
  101 + state = {'base' : ctools.csobservation.__getstate__(self),
  102 + 'ebounds' : self._ebounds,
  103 + 'fits' : self._fits,
  104 + 'binned_mode' : self._binned_mode,
  105 + 'onoff_mode' : self._onoff_mode,
  106 + 'method' : self._method,
  107 + 'nthreads' : self._nthreads}
  108 +
  109 + # Return pickled dictionary
  110 + return state
  111 +
  112 + def __setstate__(self, state):
  113 + """
  114 + Extend ctools.csobservation setstate method to include some members
  115 +
  116 + Parameters
  117 + ----------
  118 + state : dict
  119 + Pickled instance
  120 + """
  121 + ctools.csobservation.__setstate__(self, state['base'])
  122 + self._ebounds = state['ebounds']
  123 + self._fits = state['fits']
  124 + self._binned_mode = state['binned_mode']
  125 + self._onoff_mode = state['onoff_mode']
  126 + self._method = state['method']
  127 + self._nthreads = state['nthreads']
  128 +
  129 + # Return
  130 + return
  131 +
62 132  
63 133 # Private methods
64 134 def _get_parameters(self):
... ... @@ -141,6 +211,9 @@ class csspec(ctools.csobservation):
141 211 # Write input parameters into logger
142 212 self._log_parameters(gammalib.TERSE)
143 213  
  214 + # Set number of processes for multiprocessing
  215 + self._nthreads = mputils.nthreads(self)
  216 +
144 217 # Write spectrum method header and parameters
145 218 self._log_header1(gammalib.TERSE, 'Spectrum method')
146 219 self._log_value(gammalib.TERSE, 'Unbinned CTA observations', n_unbinned)
... ... @@ -575,6 +648,10 @@ class csspec(ctools.csobservation):
575 648 result : dict
576 649 Dictionary with fit results
577 650 """
  651 +
  652 + # Write header for energy bin
  653 + self._log_header2(gammalib.EXPLICIT, 'Energy bin ' + str(i + 1))
  654 +
578 655 # Get energy boundaries
579 656 emin = self._ebounds.emin(i)
580 657 emax = self._ebounds.emax(i)
... ... @@ -692,17 +769,35 @@ class csspec(ctools.csobservation):
692 769 # Initialise results
693 770 results = []
694 771  
695   - # Loop over energy bins
696   - for i in range(self._ebounds.size()):
  772 + # If using multiprocessing
  773 + if self._nthreads > 1:
697 774  
698   - # Write header for energy bin
699   - self._log_header2(gammalib.EXPLICIT, 'Energy bin '+str(i+1))
  775 + # Create pool of workers
  776 + from multiprocessing import Pool
  777 + pool = Pool(processes = self._nthreads)
700 778  
701   - # Fit energy bin
702   - result = self._fit_energy_bin(i)
  779 + # Run energy bin analysis in parallel with map
  780 + args = [(self, i) for i in range(self._ebounds.size())]
  781 + poolresults = pool.map(_multiprocessing_func_wrapper, args)
703 782  
704   - # Append results
705   - results.append(result)
  783 + # Close pool and join
  784 + pool.close()
  785 + pool.join()
  786 +
  787 + # Construct results
  788 + for i in range(self._ebounds.size()):
  789 + results.append(poolresults[i][0])
  790 + self._log_string(gammalib.TERSE, poolresults[i][1]['log'], False)
  791 +
  792 + # Otherwise, loop over energy bins
  793 + else:
  794 + for i in range(self._ebounds.size()):
  795 +
  796 + # Fit energy bin
  797 + result = self._fit_energy_bin(i)
  798 +
  799 + # Append results
  800 + results.append(result)
706 801  
707 802 # Return results
708 803 return results
... ...
test/test_csspec.py
... ... @@ -231,6 +231,32 @@ class Test(test):
231 231 # Check result file
232 232 self._check_result_file('csspec_py5.fits', 10)
233 233  
  234 + # Set-up csspec without multiprocessing
  235 + spec = cscripts.csspec()
  236 + spec['inobs'] = self._events
  237 + spec['inmodel'] = self._model
  238 + spec['srcname'] = 'Crab'
  239 + spec['caldb'] = self._caldb
  240 + spec['irf'] = self._irf
  241 + spec['method'] = 'AUTO'
  242 + spec['ebinalg'] = 'LOG'
  243 + spec['enumbins'] = 5
  244 + spec['emin'] = 0.1
  245 + spec['emax'] = 100.0
  246 + spec['outfile'] = 'csspec_py6.fits'
  247 + spec['logfile'] = 'csspec_py6.log'
  248 + spec['chatter'] = 2
  249 + spec['publish'] = True
  250 + spec['nthreads'] = 1
  251 +
  252 + # Run csspec script
  253 + spec.logFileOpen() # Make sure we get a log file
  254 + spec.run()
  255 + spec.save()
  256 +
  257 + # Check result file
  258 + self._check_result_file('csspec_py6.fits', 5)
  259 +
234 260 # Return
235 261 return
236 262  
... ...