Commit 9b24f41f0ffc461c5a5136969d6f08a6af38b3ba
1 parent
d3d48015
Add mputils.process() function and reduce code duplication
Showing
9 changed files
with
108 additions
and
113 deletions
cscripts/cslightcrv.py
| ... | ... | @@ -647,20 +647,13 @@ class cslightcrv(ctools.csobservation): |
| 647 | 647 | # Write header |
| 648 | 648 | self._log_header1(gammalib.TERSE, 'Generate lightcurve') |
| 649 | 649 | |
| 650 | - # If using multiprocessing | |
| 650 | + # If more than a single thread is requested then use multiprocessing | |
| 651 | 651 | if self._nthreads > 1: |
| 652 | 652 | |
| 653 | - # Create pool of workers | |
| 654 | - from multiprocessing import Pool | |
| 655 | - pool = Pool(processes = self._nthreads) | |
| 656 | - | |
| 657 | - # Run time bin analysis in parallel with map | |
| 653 | + # Compute time bins | |
| 658 | 654 | args = [(self, i) for i in range(self._tbins.size())] |
| 659 | - poolresults = pool.map(_multiprocessing_func_wrapper, args) | |
| 660 | - | |
| 661 | - # Close pool and join | |
| 662 | - pool.close() | |
| 663 | - pool.join() | |
| 655 | + poolresults = mputils.process(self._nthreads, | |
| 656 | + _multiprocessing_func_wrapper, args) | |
| 664 | 657 | |
| 665 | 658 | # Construct results |
| 666 | 659 | results = [] | ... | ... |
cscripts/csphagen.py
| ... | ... | @@ -578,17 +578,10 @@ class csphagen(ctools.csobservation): |
| 578 | 578 | # If there is more than one observation and we use multiprocessing |
| 579 | 579 | if self._nthreads > 1 and self.obs().size() > 1: |
| 580 | 580 | |
| 581 | - # Create pool of workers | |
| 582 | - from multiprocessing import Pool | |
| 583 | - pool = Pool(processes = self._nthreads) | |
| 584 | - | |
| 585 | - # Run time bin analysis in parallel with map | |
| 581 | + # Compute observations | |
| 586 | 582 | args = [(self, i) for i in range(self.obs().size())] |
| 587 | - poolresults = pool.map(_multiprocessing_func_wrapper, args) | |
| 588 | - | |
| 589 | - # Close pool and join | |
| 590 | - pool.close() | |
| 591 | - pool.join() | |
| 583 | + poolresults = mputils.process(self._nthreads, | |
| 584 | + _multiprocessing_func_wrapper, args) | |
| 592 | 585 | |
| 593 | 586 | # Construct results |
| 594 | 587 | for i in range(self.obs().size()): | ... | ... |
cscripts/csphasecrv.py
| ... | ... | @@ -493,20 +493,13 @@ class csphasecrv(ctools.csobservation): |
| 493 | 493 | # Write header |
| 494 | 494 | self._log_header1(gammalib.TERSE, 'Generate phase curve') |
| 495 | 495 | |
| 496 | - # If using multiprocessing | |
| 496 | + # If more than a single thread is requested then use multiprocessing | |
| 497 | 497 | if self._nthreads > 1: |
| 498 | 498 | |
| 499 | - # Create pool of workers | |
| 500 | - from multiprocessing import Pool | |
| 501 | - pool = Pool(processes = self._nthreads) | |
| 502 | - | |
| 503 | - # Run time bin analysis in parallel with map | |
| 499 | + # Compute phase bins | |
| 504 | 500 | args = [(self, phbin) for phbin in self._phbins] |
| 505 | - poolresults = pool.map(_multiprocessing_func_wrapper, args) | |
| 506 | - | |
| 507 | - # Close pool and join | |
| 508 | - pool.close() | |
| 509 | - pool.join() | |
| 501 | + poolresults = mputils.process(self._nthreads, | |
| 502 | + _multiprocessing_func_wrapper, args) | |
| 510 | 503 | |
| 511 | 504 | # Construct results |
| 512 | 505 | for i in range(len(self._phbins)): | ... | ... |
cscripts/cspull.py
| ... | ... | @@ -377,40 +377,34 @@ class cspull(ctools.csobservation): |
| 377 | 377 | # Write header |
| 378 | 378 | self._log_header1(gammalib.TERSE, 'Generate pull distribution') |
| 379 | 379 | |
| 380 | - # If using multiprocessing | |
| 381 | - if self._nthreads > 1: | |
| 382 | - | |
| 383 | - # Create pool of workers | |
| 384 | - from multiprocessing import Pool | |
| 385 | - pool = Pool(processes = self._nthreads) | |
| 386 | - | |
| 387 | - # Run time bin analysis in parallel with map | |
| 388 | - args = [(self, seed + self['seed'].integer()) | |
| 389 | - for seed in range(self['ntrials'].integer())] | |
| 390 | - poolresults = pool.map(_multiprocessing_func_wrapper, args) | |
| 380 | + # Get number of trials | |
| 381 | + ntrials = self['ntrials'].integer() | |
| 391 | 382 | |
| 392 | - # Close pool and join | |
| 393 | - pool.close() | |
| 394 | - pool.join() | |
| 383 | + # Get seed value | |
| 384 | + seed = self['seed'].integer() | |
| 395 | 385 | |
| 396 | - # Write results | |
| 397 | - for seed in range(self['ntrials'].integer()): | |
| 398 | - result = poolresults[seed][0] | |
| 399 | - ioutils.write_csv_row(self['outfile'].filename().url(), seed, | |
| 400 | - result['colnames'], result['values']) | |
| 401 | - self._log_string(gammalib.TERSE, poolresults[seed][1]['log'], False) | |
| 386 | + # If more than a single thread is requested then use multiprocessing | |
| 387 | + if self._nthreads > 1: | |
| 388 | + args = [(self, i + seed) for i in range(ntrials)] | |
| 389 | + poolresults = mputils.process(self._nthreads, | |
| 390 | + _multiprocessing_func_wrapper, args) | |
| 402 | 391 | |
| 403 | - # Otherwise, loop over trials | |
| 404 | - else: | |
| 392 | + # Continue with regular processing | |
| 393 | + for i in range(ntrials): | |
| 405 | 394 | |
| 406 | - for seed in range(self['ntrials'].integer()): | |
| 395 | + # If multiprocessing was used then recover results and put them | |
| 396 | + # into the log file | |
| 397 | + if self._nthreads > 1: | |
| 398 | + result = poolresults[i][0] | |
| 399 | + self._log_string(gammalib.TERSE, poolresults[i][1]['log'], False) | |
| 407 | 400 | |
| 408 | - # Make a trial and add initial seed | |
| 409 | - result = self._trial(seed + self['seed'].integer()) | |
| 401 | + # ... otherwise make a trial now | |
| 402 | + else: | |
| 403 | + result = self._trial(i + seed) | |
| 410 | 404 | |
| 411 | - # Write out trial result | |
| 412 | - ioutils.write_csv_row(self['outfile'].filename().url(), seed, | |
| 413 | - result['colnames'], result['values']) | |
| 405 | + # Write out trial result | |
| 406 | + ioutils.write_csv_row(self['outfile'].filename().url(), i, | |
| 407 | + result['colnames'], result['values']) | |
| 414 | 408 | |
| 415 | 409 | # Return |
| 416 | 410 | return | ... | ... |
cscripts/cssens.py
| ... | ... | @@ -715,17 +715,10 @@ class cssens(ctools.csobservation): |
| 715 | 715 | # If using multiprocessing |
| 716 | 716 | if self._nthreads > 1 and self._ebounds.size() > 1: |
| 717 | 717 | |
| 718 | - # Create pool of workers | |
| 719 | - from multiprocessing import Pool | |
| 720 | - pool = Pool(processes = self._nthreads) | |
| 721 | - | |
| 722 | - # Run energy bin analysis in parallel with map | |
| 718 | + # Compute phase bins | |
| 723 | 719 | args = [(self, ieng) for ieng in range(self._ebounds.size())] |
| 724 | - poolresults = pool.map(_multiprocessing_func_wrapper, args) | |
| 725 | - | |
| 726 | - # Close pool and join | |
| 727 | - pool.close() | |
| 728 | - pool.join() | |
| 720 | + poolresults = mputils.process(self._nthreads, | |
| 721 | + _multiprocessing_func_wrapper, args) | |
| 729 | 722 | |
| 730 | 723 | # Construct results |
| 731 | 724 | for ieng in range(self._ebounds.size()): | ... | ... |
cscripts/csspec.py
| ... | ... | @@ -771,20 +771,13 @@ class csspec(ctools.csobservation): |
| 771 | 771 | # Initialise results |
| 772 | 772 | results = [] |
| 773 | 773 | |
| 774 | - # If using multiprocessing | |
| 774 | + # If more than a single thread is requested then use multiprocessing | |
| 775 | 775 | if self._nthreads > 1: |
| 776 | 776 | |
| 777 | - # Create pool of workers | |
| 778 | - from multiprocessing import Pool | |
| 779 | - pool = Pool(processes = self._nthreads) | |
| 780 | - | |
| 781 | - # Run energy bin analysis in parallel with map | |
| 777 | + # Compute energy bins | |
| 782 | 778 | args = [(self, i) for i in range(self._ebounds.size())] |
| 783 | - poolresults = pool.map(_multiprocessing_func_wrapper, args) | |
| 784 | - | |
| 785 | - # Close pool and join | |
| 786 | - pool.close() | |
| 787 | - pool.join() | |
| 779 | + poolresults = mputils.process(self._nthreads, | |
| 780 | + _multiprocessing_func_wrapper, args) | |
| 788 | 781 | |
| 789 | 782 | # Construct results |
| 790 | 783 | for i in range(self._ebounds.size()): | ... | ... |
cscripts/cstsdist.py
| ... | ... | @@ -329,38 +329,30 @@ class cstsdist(ctools.csobservation): |
| 329 | 329 | # Write header |
| 330 | 330 | self._log_header1(gammalib.TERSE, 'Generate TS distribution') |
| 331 | 331 | |
| 332 | - # If using multiprocessing | |
| 333 | - if self._nthreads > 1: | |
| 334 | - | |
| 335 | - # Create pool of workers | |
| 336 | - from multiprocessing import Pool | |
| 337 | - pool = Pool(processes = self._nthreads) | |
| 338 | - | |
| 339 | - # Run time bin analysis in parallel with map | |
| 340 | - args = [(self, seed) for seed in range(self['ntrials'].integer())] | |
| 341 | - poolresults = pool.map(_multiprocessing_func_wrapper, args) | |
| 332 | + # Get number of trials | |
| 333 | + ntrials = self['ntrials'].integer() | |
| 342 | 334 | |
| 343 | - # Close pool and join | |
| 344 | - pool.close() | |
| 345 | - pool.join() | |
| 346 | - | |
| 347 | - # Write results | |
| 348 | - for seed in range(self['ntrials'].integer()): | |
| 349 | - result = poolresults[seed][0] | |
| 350 | - ioutils.write_csv_row(self['outfile'].filename().url(), seed, | |
| 351 | - result['colnames'], result['values']) | |
| 352 | - self._log_string(gammalib.TERSE, poolresults[seed][1]['log'], False) | |
| 335 | + # If more than a single thread is requested then use multiprocessing | |
| 336 | + if self._nthreads > 1: | |
| 337 | + args = [(self, i) for i in range(ntrials)] | |
| 338 | + poolresults = mputils.process(self._nthreads, | |
| 339 | + _multiprocessing_func_wrapper, args) | |
| 353 | 340 | |
| 354 | - # Otherwise, loop over trials | |
| 355 | - else: | |
| 341 | + # Continue with regular processing | |
| 342 | + for i in range(ntrials): | |
| 356 | 343 | |
| 357 | - for seed in range(self['ntrials'].integer()): | |
| 344 | + # If multiprocessing was used then recover results and put them | |
| 345 | + # into the log file | |
| 346 | + if self._nthreads > 1: | |
| 347 | + result = poolresults[i][0] | |
| 348 | + self._log_string(gammalib.TERSE, poolresults[i][1]['log'], False) | |
| 358 | 349 | |
| 359 | - # Make a trial | |
| 360 | - result = self._trial(seed) | |
| 350 | + # ... otherwise make a trial now | |
| 351 | + else: | |
| 352 | + result = self._trial(i) | |
| 361 | 353 | |
| 362 | - # Write out trial result | |
| 363 | - ioutils.write_csv_row(self['outfile'].filename().url(), seed, | |
| 354 | + # Write out trial result | |
| 355 | + ioutils.write_csv_row(self['outfile'].filename().url(), i, | |
| 364 | 356 | result['colnames'], result['values']) |
| 365 | 357 | |
| 366 | 358 | # Return | ... | ... |
cscripts/mputils.py
| ... | ... | @@ -20,12 +20,12 @@ |
| 20 | 20 | import gammalib |
| 21 | 21 | |
| 22 | 22 | |
| 23 | -# ==================== # | |
| 24 | -# Number of processes # | |
| 25 | -# ==================== # | |
| 23 | +# ====================== # | |
| 24 | +# Get number of threads # | |
| 25 | +# ====================== # | |
| 26 | 26 | def nthreads(cls): |
| 27 | 27 | """ |
| 28 | - Determines the number of parallel processes to use. | |
| 28 | + Determines the number of parallel processes to use | |
| 29 | 29 | |
| 30 | 30 | The number is based on the user parameter "nthreads" and the availability |
| 31 | 31 | of the multiprocessing module. |
| ... | ... | @@ -38,7 +38,7 @@ def nthreads(cls): |
| 38 | 38 | Returns |
| 39 | 39 | ------- |
| 40 | 40 | nthreads : int |
| 41 | - Number of parallel processes | |
| 41 | + Number of threads | |
| 42 | 42 | """ |
| 43 | 43 | # Log multiprocessing configuration |
| 44 | 44 | cls._log_header1(gammalib.NORMAL, 'Multiprocessing') |
| ... | ... | @@ -69,3 +69,41 @@ def nthreads(cls): |
| 69 | 69 | |
| 70 | 70 | # Return number of processes to be used |
| 71 | 71 | return nthreads |
| 72 | + | |
| 73 | + | |
| 74 | +# ============================ # | |
| 75 | +# Execute function in parallel # | |
| 76 | +# ============================ # | |
| 77 | +def process(nthreads, function, args): | |
| 78 | + """ | |
| 79 | + Execute function in parallel | |
| 80 | + | |
| 81 | + Parameters | |
| 82 | + ---------- | |
| 83 | + nthreads : int | |
| 84 | + Number of parallel threads | |
| 85 | + function : Python function | |
| 86 | + Function to be executed in parallel | |
| 87 | + args : list of tuples | |
| 88 | + Function arguments for each evaluation | |
| 89 | + | |
| 90 | + Returns | |
| 91 | + ------- | |
| 92 | + results : list of dicts | |
| 93 | + List of function evaluation results | |
| 94 | + """ | |
| 95 | + # Import Pool module from multiprocessing module | |
| 96 | + from multiprocessing import Pool | |
| 97 | + | |
| 98 | + # Create a pool of processes | |
| 99 | + pool = Pool(processes=nthreads) | |
| 100 | + | |
| 101 | + # Run function in parallel | |
| 102 | + results = pool.map(function, args) | |
| 103 | + | |
| 104 | + # Close pool and join | |
| 105 | + pool.close() | |
| 106 | + pool.join() | |
| 107 | + | |
| 108 | + # Return results | |
| 109 | + return results | ... | ... |
test/test_ctbutterfly.py
| ... | ... | @@ -123,6 +123,12 @@ class Test(test): |
| 123 | 123 | # Check result file |
| 124 | 124 | self._check_result_file('ctbutterfly_py1.dat') |
| 125 | 125 | |
| 126 | + # Check CSV result | |
| 127 | + self.test_value(butterfly.butterfly().nrows(), 100, | |
| 128 | + 'Check for 100 rows in CSV file') | |
| 129 | + self.test_value(butterfly.butterfly().ncols(), 4, | |
| 130 | + 'Check for 4 columns in CSV file') | |
| 131 | + | |
| 126 | 132 | # Set-up ctbutterfly |
| 127 | 133 | butterfly = ctools.ctbutterfly() |
| 128 | 134 | butterfly['inobs'] = self._events | ... | ... |