Commit fad9ee4cd232cb3937566a316688a5a8c65edc4b

Authored by Luigi Tibaldo
1 parent 92a76a88

parallelised cspull

cscripts/cspull.par
... ... @@ -50,8 +50,9 @@ seed, i, h, 1,,, "Initial random number generator seed"
50 50 #
51 51 # Standard parameters
52 52 #====================
53   -chatter, i, h, 2,0,4, "Chattiness of output"
54   -clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
55   -debug, b, h, no,,, "Activate debugging mode?"
56   -mode, s, h, ql,,, "Mode of automatic parameters"
57   -logfile, f, h, cspull.log,,, "Log filename"
  53 +nthreads, i, h, 0,0,1000, "Number of parallel processes (0=use all available CPUs)"
  54 +chatter, i, h, 2,0,4, "Chattiness of output"
  55 +clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
  56 +debug, b, h, no,,, "Activate debugging mode?"
  57 +mode, s, h, ql,,, "Mode of automatic parameters"
  58 +logfile, f, h, cspull.log,,, "Log filename"
... ...
cscripts/cspull.py
... ... @@ -23,6 +23,33 @@ import gammalib
23 23 import ctools
24 24 from cscripts import obsutils
25 25 from cscripts import ioutils
  26 +from cscripts import mputils
  27 +
  28 +# ============================================ #
  29 +# Global functions for multiprocessing support #
  30 +# ============================================ #
  31 +def _multiprocessing_func_wrapper(args):
  32 + return _multiprocessing_func(*args)
  33 +def _multiprocessing_func(cls, i):
  34 +
  35 + # Initialise thread logger
  36 + cls._log.clear()
  37 + cls._log.buffer_size(100000)
  38 +
  39 + # Compute light curve bin
  40 + cstart = cls.celapse()
  41 + result = cls._trial(i)
  42 + celapse = cls.celapse() - cstart
  43 + buffer = cls._log.buffer()
  44 +
  45 + # Close logger
  46 + cls._log.close()
  47 +
  48 + # Collect thread information
  49 + info = {'celapse': celapse, 'log': buffer}
  50 +
  51 + # Return light curve bin result and thread information
  52 + return result, info
26 53  
27 54  
28 55 # ============ #
... ... @@ -40,9 +67,43 @@ class cspull(ctools.csobservation):
40 67 # Initialise application by calling the appropriate class constructor
41 68 self._init_csobservation(self.__class__.__name__, ctools.__version__, argv)
42 69  
  70 + # Initialise some members
  71 + self._nthreads = 0
  72 +
43 73 # Return
44 74 return
45 75  
  76 + # State methods por pickling
  77 + def __getstate__(self):
  78 + """
  79 + Extend ctools.csobservation getstate method to include some members
  80 +
  81 + Returns
  82 + -------
  83 + state : dict
  84 + Pickled instance
  85 + """
  86 + # Set pickled dictionary
  87 + state = {'base' : ctools.csobservation.__getstate__(self),
  88 + 'nthreads' : self._nthreads}
  89 +
  90 + # Return pickled dictionary
  91 + return state
  92 +
  93 + def __setstate__(self, state):
  94 + """
  95 + Extend ctools.csobservation setstate method to include some members
  96 +
  97 + Parameters
  98 + ----------
  99 + state : dict
  100 + Pickled instance
  101 + """
  102 + ctools.csobservation.__setstate__(self, state['base'])
  103 + self._nthreads = state['nthreads']
  104 +
  105 + # Return
  106 + return
46 107  
47 108 # Private methods
48 109 def _get_parameters(self):
... ... @@ -92,6 +153,9 @@ class cspull(ctools.csobservation):
92 153 # Write input parameters into logger
93 154 self._log_parameters(gammalib.TERSE)
94 155  
  156 + # Set number of processes for multiprocessing
  157 + self._nthreads = mputils.nthreads(self)
  158 +
95 159 # Return
96 160 return
97 161  
... ... @@ -310,6 +374,29 @@ class cspull(ctools.csobservation):
310 374 # Write header
311 375 self._log_header1(gammalib.TERSE, 'Generate pull distribution')
312 376  
  377 + # If using multiprocessing
  378 + if self._nthreads > 1:
  379 +
  380 + # Create pool of workers
  381 + from multiprocessing import Pool
  382 + pool = Pool(processes = self._nthreads)
  383 +
  384 + # Run time bin analysis in parallel with map
  385 + args = [(self, seed + self['seed'].integer())
  386 + for seed in range(self['ntrials'].integer())]
  387 + poolresults = pool.map(_multiprocessing_func_wrapper, args)
  388 +
  389 + # Close pool and join
  390 + pool.close()
  391 + pool.join()
  392 +
  393 + # Write results
  394 + for seed in range(self['ntrials'].integer()):
  395 + result = poolresults[seed][0]
  396 + ioutils.write_csv_row(self['outfile'].filename().url(), seed,
  397 + result['colnames'], result['values'])
  398 + self._log_string(gammalib.TERSE, poolresults[seed][1]['log'], False)
  399 +
313 400 # Loop over trials
314 401 for seed in range(self['ntrials'].integer()):
315 402  
... ...
test/test_cspull.py
... ... @@ -260,6 +260,34 @@ class Test(test):
260 260 # Check pull distribution file
261 261 self._check_pull_file('cspull_py6.dat', rows=2)
262 262  
  263 + # Set-up cspull without multiprocessing
  264 + pull = cscripts.cspull()
  265 + pull['inmodel'] = self._model
  266 + pull['onsrc'] = 'NONE'
  267 + pull['outfile'] = 'cspull_py7.dat'
  268 + pull['ntrials'] = 2
  269 + pull['caldb'] = self._caldb
  270 + pull['irf'] = self._irf
  271 + pull['ra'] = 83.6331
  272 + pull['dec'] = 22.0145
  273 + pull['emin'] = 0.1
  274 + pull['emax'] = 100.0
  275 + pull['enumbins'] = 0
  276 + pull['tmin'] = 0.0
  277 + pull['tmax'] = 100.0
  278 + pull['deadc'] = 0.98
  279 + pull['rad'] = 5.0
  280 + pull['logfile'] = 'cspull_py7.log'
  281 + pull['chatter'] = 2
  282 + pull['nthreads'] = 1
  283 +
  284 + # Run cspull script
  285 + pull.logFileOpen() # Make sure we get a log file
  286 + pull.run()
  287 +
  288 + # Check pull distribution file
  289 + self._check_pull_file('cspull_py7.dat')
  290 +
263 291 # Return
264 292 return
265 293  
... ...