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,9 +46,10 @@ fix_bkg, b, h, no,,, "Fix background parameters"
46 # 46 #
47 # Standard parameters 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,6 +21,33 @@
21 import sys 21 import sys
22 import gammalib 22 import gammalib
23 import ctools 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,6 +75,7 @@ class csspec(ctools.csobservation):
48 self._binned_mode = False 75 self._binned_mode = False
49 self._onoff_mode = False 76 self._onoff_mode = False
50 self._method = 'AUTO' 77 self._method = 'AUTO'
  78 + self._nthreads = 0
51 79
52 # Return 80 # Return
53 return 81 return
@@ -59,6 +87,48 @@ class csspec(ctools.csobservation): @@ -59,6 +87,48 @@ class csspec(ctools.csobservation):
59 # Return 87 # Return
60 return 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 # Private methods 133 # Private methods
64 def _get_parameters(self): 134 def _get_parameters(self):
@@ -141,6 +211,9 @@ class csspec(ctools.csobservation): @@ -141,6 +211,9 @@ class csspec(ctools.csobservation):
141 # Write input parameters into logger 211 # Write input parameters into logger
142 self._log_parameters(gammalib.TERSE) 212 self._log_parameters(gammalib.TERSE)
143 213
  214 + # Set number of processes for multiprocessing
  215 + self._nthreads = mputils.nthreads(self)
  216 +
144 # Write spectrum method header and parameters 217 # Write spectrum method header and parameters
145 self._log_header1(gammalib.TERSE, 'Spectrum method') 218 self._log_header1(gammalib.TERSE, 'Spectrum method')
146 self._log_value(gammalib.TERSE, 'Unbinned CTA observations', n_unbinned) 219 self._log_value(gammalib.TERSE, 'Unbinned CTA observations', n_unbinned)
@@ -575,6 +648,10 @@ class csspec(ctools.csobservation): @@ -575,6 +648,10 @@ class csspec(ctools.csobservation):
575 result : dict 648 result : dict
576 Dictionary with fit results 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 # Get energy boundaries 655 # Get energy boundaries
579 emin = self._ebounds.emin(i) 656 emin = self._ebounds.emin(i)
580 emax = self._ebounds.emax(i) 657 emax = self._ebounds.emax(i)
@@ -692,17 +769,35 @@ class csspec(ctools.csobservation): @@ -692,17 +769,35 @@ class csspec(ctools.csobservation):
692 # Initialise results 769 # Initialise results
693 results = [] 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 # Return results 802 # Return results
708 return results 803 return results
test/test_csspec.py
@@ -231,6 +231,32 @@ class Test(test): @@ -231,6 +231,32 @@ class Test(test):
231 # Check result file 231 # Check result file
232 self._check_result_file('csspec_py5.fits', 10) 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 # Return 260 # Return
235 return 261 return
236 262