Commit b621fc01d46c65b11690a49d0767c8a935081683
1 parent
acab87bd
added upper limit computation
Showing
2 changed files
with
54 additions
and
21 deletions
cscripts/csscs.par
| @@ -27,7 +27,7 @@ caldb, s, a, prod2,,, "Calibration database" | @@ -27,7 +27,7 @@ caldb, s, a, prod2,,, "Calibration database" | ||
| 27 | irf, s, a, South_0.5h,,, "Instrument response function" | 27 | irf, s, a, South_0.5h,,, "Instrument response function" |
| 28 | inexclusion, f, a, NONE,,, "Exclusion regions TODO: add meaningful default" | 28 | inexclusion, f, a, NONE,,, "Exclusion regions TODO: add meaningful default" |
| 29 | edisp, b, h, no,,, "Apply energy dispersion?" | 29 | edisp, b, h, no,,, "Apply energy dispersion?" |
| 30 | -outfile, f, a, map.fits,,, "Output map" | 30 | +outfile, f, a, maps.fits,,, "Output maps" |
| 31 | 31 | ||
| 32 | # | 32 | # |
| 33 | # Script parameters | 33 | # Script parameters |
| @@ -56,9 +56,9 @@ etruemin, r, h, 0.01,,, "Minimum true energy (TeV)" | @@ -56,9 +56,9 @@ etruemin, r, h, 0.01,,, "Minimum true energy (TeV)" | ||
| 56 | etruemax, r, h, 300.0,,, "Maximum true energy (TeV)" | 56 | etruemax, r, h, 300.0,,, "Maximum true energy (TeV)" |
| 57 | etruebins, i, h, 30,,, "Number of bins per decade for true energy bins" | 57 | etruebins, i, h, 30,,, "Number of bins per decade for true energy bins" |
| 58 | calc_ts, b, h, yes,,, "Compute TS value in each bin" | 58 | calc_ts, b, h, yes,,, "Compute TS value in each bin" |
| 59 | -calc_ulim, b, h, yes,,, "Compute upper limit in each bin" | ||
| 60 | -fix_srcs, b, h, yes,,, "Fix other skymodel parameters" | ||
| 61 | -fix_bkg, b, h, no,,, "Fix background parameters" | 59 | +calc_ulim, b, h, no,,, "Compute upper limit in each bin" |
| 60 | +fix_srcs, b, h, yes,,, "Fix other skymodel normalisations" | ||
| 61 | +fix_bkg, b, h, no,,, "Fix background normalisation" | ||
| 62 | 62 | ||
| 63 | # | 63 | # |
| 64 | # Standard parameters | 64 | # Standard parameters |
cscripts/csscs.py
| @@ -498,7 +498,7 @@ class csscs(ctools.csobservation): | @@ -498,7 +498,7 @@ class csscs(ctools.csobservation): | ||
| 498 | result[name] = {'flux' : 0.0, | 498 | result[name] = {'flux' : 0.0, |
| 499 | 'flux_err': 0.0, | 499 | 'flux_err': 0.0, |
| 500 | 'TS' : 0.0, | 500 | 'TS' : 0.0, |
| 501 | - 'ulimit' : 0.0} | 501 | + 'ulimit' : -1.0} |
| 502 | 502 | ||
| 503 | # Mask observations | 503 | # Mask observations |
| 504 | self._log_header3(gammalib.EXPLICIT, 'Masking observations') | 504 | self._log_header3(gammalib.EXPLICIT, 'Masking observations') |
| @@ -542,10 +542,12 @@ class csscs(ctools.csobservation): | @@ -542,10 +542,12 @@ class csscs(ctools.csobservation): | ||
| 542 | # Get flux | 542 | # Get flux |
| 543 | # Integrate spectral model between emin and emax | 543 | # Integrate spectral model between emin and emax |
| 544 | flux = source.spectral().flux(emin,emax) | 544 | flux = source.spectral().flux(emin,emax) |
| 545 | - # Multiply by flux from spatial component in ROI | ||
| 546 | - flux *= source.spatial().flux(roi) | ||
| 547 | - # Divide by solid angle of ROI | ||
| 548 | - flux /= gammalib.twopi * (1 - math.cos(math.radians(self['rad'].real()))) | 545 | + # Calculate correction factor |
| 546 | + # Spatial model flux over ROI divided by ROI solid angle | ||
| 547 | + corr_factor = source.spatial().flux(roi) | ||
| 548 | + corr_factor /= gammalib.twopi * (1 - math.cos(math.radians(self['rad'].real()))) | ||
| 549 | + # Multiply flux by correction factor | ||
| 550 | + flux *= corr_factor | ||
| 549 | result[name]['flux'] = flux | 551 | result[name]['flux'] = flux |
| 550 | 552 | ||
| 551 | # Get flux error | 553 | # Get flux error |
| @@ -564,8 +566,35 @@ class csscs(ctools.csobservation): | @@ -564,8 +566,35 @@ class csscs(ctools.csobservation): | ||
| 564 | if self['calc_ts'].boolean(): | 566 | if self['calc_ts'].boolean(): |
| 565 | result[name]['TS'] = source.ts() | 567 | result[name]['TS'] = source.ts() |
| 566 | 568 | ||
| 567 | - # Upper limit | ||
| 568 | - # TODO | 569 | + # If requested compute upper flux limit |
| 570 | + if self['calc_ulim'].boolean(): | ||
| 571 | + | ||
| 572 | + # Logging information | ||
| 573 | + self._log_header3(gammalib.EXPLICIT, | ||
| 574 | + 'Computing upper limit for source ' + name) | ||
| 575 | + | ||
| 576 | + # Create upper limit object | ||
| 577 | + ulimit = ctools.ctulimit(like.obs()) | ||
| 578 | + ulimit['srcname'] = name | ||
| 579 | + ulimit['emin'] = self['emin'].real() | ||
| 580 | + ulimit['emax'] = self['emax'].real() | ||
| 581 | + | ||
| 582 | + # If chatter level is verbose and debugging is requested | ||
| 583 | + # then switch also on the debug model in ctulimit | ||
| 584 | + if self._logVerbose() and self._logDebug(): | ||
| 585 | + ulimit['debug'] = True | ||
| 586 | + | ||
| 587 | + # Try to run upper limit and catch exceptions | ||
| 588 | + try: | ||
| 589 | + ulimit.run() | ||
| 590 | + ulimit_value = ulimit.flux_ulimit() | ||
| 591 | + # Multiply by correction factor to get flux per solid angle in ROI | ||
| 592 | + ulimit_value *= corr_factor | ||
| 593 | + result[name]['ulimit'] = ulimit_value | ||
| 594 | + except: | ||
| 595 | + self._log_string(gammalib.EXPLICIT, 'Upper limit ' | ||
| 596 | + 'calculation failed.') | ||
| 597 | + | ||
| 569 | 598 | ||
| 570 | else: | 599 | else: |
| 571 | value = 'Likelihood is zero. Bin is skipped.' | 600 | value = 'Likelihood is zero. Bin is skipped.' |
| @@ -604,24 +633,22 @@ class csscs(ctools.csobservation): | @@ -604,24 +633,22 @@ class csscs(ctools.csobservation): | ||
| 604 | # Loop over target sources | 633 | # Loop over target sources |
| 605 | for s, name in enumerate(self._srcnames): | 634 | for s, name in enumerate(self._srcnames): |
| 606 | 635 | ||
| 607 | - # Create minimal set of skymaps to store fluxes and flux errors | 636 | + # Create skymaps to store results |
| 637 | + # Maps for TS and upper limits created and filled to avoid if statements | ||
| 638 | + # Will not be saved in the end if not requested | ||
| 608 | fmap = self._create_map() | 639 | fmap = self._create_map() |
| 609 | errmap = self._create_map() | 640 | errmap = self._create_map() |
| 610 | - | ||
| 611 | - #Create map for TS | ||
| 612 | - if self['calc_ts'].boolean(): | ||
| 613 | - tsmap = self._create_map() | 641 | + tsmap = self._create_map() |
| 642 | + ulmap = self._create_map() | ||
| 614 | 643 | ||
| 615 | # Loop over pixels and fill maps | 644 | # Loop over pixels and fill maps |
| 616 | for inx in range(fmap.npix()): | 645 | for inx in range(fmap.npix()): |
| 617 | 646 | ||
| 618 | - # Fill flux and flux error | 647 | + # Fill maps |
| 619 | fmap[inx,0] = results[inx][name]['flux'] | 648 | fmap[inx,0] = results[inx][name]['flux'] |
| 620 | errmap[inx, 0] = results[inx][name]['flux_error'] | 649 | errmap[inx, 0] = results[inx][name]['flux_error'] |
| 621 | - | ||
| 622 | - # If requested fill TS | ||
| 623 | - if self['calc_ts'].boolean(): | ||
| 624 | - tsmap[inx, 0] = results[inx][name]['TS'] | 650 | + tsmap[inx, 0] = results[inx][name]['TS'] |
| 651 | + ulmap[inx, 0] = results[inx][name]['ulimit'] | ||
| 625 | 652 | ||
| 626 | # Write maps to Fits | 653 | # Write maps to Fits |
| 627 | fhdu = fmap.write(fits, name + ' FLUX') | 654 | fhdu = fmap.write(fits, name + ' FLUX') |
| @@ -638,6 +665,12 @@ class csscs(ctools.csobservation): | @@ -638,6 +665,12 @@ class csscs(ctools.csobservation): | ||
| 638 | tshdu = tsmap.write(fits, name + ' TS') | 665 | tshdu = tsmap.write(fits, name + ' TS') |
| 639 | tshdu.header().append(roiszcard) | 666 | tshdu.header().append(roiszcard) |
| 640 | 667 | ||
| 668 | + # If requested write upper limit map to fits | ||
| 669 | + if self['calc_ulim'].boolean(): | ||
| 670 | + ulhdu = ulmap.write(fits, name + ' FLUX UPPER LIMIT') | ||
| 671 | + ulhdu.header().append(fcard) | ||
| 672 | + ulhdu.header().append(roiszcard) | ||
| 673 | + | ||
| 641 | # Return | 674 | # Return |
| 642 | return fits | 675 | return fits |
| 643 | 676 |