Commit 6473def5bf7fa14d901be473a69568a8b6884179
1 parent
8efc6377
Integrate code
Showing
9 changed files
with
263 additions
and
179 deletions
AUTHORS
| @@ -15,5 +15,6 @@ Michael Mayer (michael.mayer@physik.hu-berlin.de) | @@ -15,5 +15,6 @@ Michael Mayer (michael.mayer@physik.hu-berlin.de) | ||
| 15 | Stefan Ohm (stefan.ohm81@gmail.com) | 15 | Stefan Ohm (stefan.ohm81@gmail.com) |
| 16 | David Sanchez (david.sanchez@lapp.in2p3.fr) | 16 | David Sanchez (david.sanchez@lapp.in2p3.fr) |
| 17 | Hubert Siejkowski (h.siejkowski@cyfronet.pl) | 17 | Hubert Siejkowski (h.siejkowski@cyfronet.pl) |
| 18 | +Andreas Specovius (andreas.specovius@fau.de) | ||
| 18 | Luigi Tibaldo (luigi.tibaldo@irap.omp.eu) | 19 | Luigi Tibaldo (luigi.tibaldo@irap.omp.eu) |
| 19 | Alexander Ziegler (alexander.ziegler@fau.de) | 20 | Alexander Ziegler (alexander.ziegler@fau.de) |
ChangeLog
| 1 | -2017-11-28 | 1 | +2018-01-12 |
| 2 | 2 | ||
| 3 | * Version 1.5.0 released | 3 | * Version 1.5.0 released |
| 4 | ======================== | 4 | ======================== |
| 5 | 5 | ||
| 6 | + Add CUSTOM background method to csphagen script (#2284) | ||
| 6 | Support On/Off analysis in cslightcrv and csphasecrv (#2273) | 7 | Support On/Off analysis in cslightcrv and csphasecrv (#2273) |
| 7 | Add tutorial for classical analysis (#2267) | 8 | Add tutorial for classical analysis (#2267) |
| 8 | Fix chatter level handling in ctpsfcube (#2262) | 9 | Fix chatter level handling in ctpsfcube (#2262) |
NEWS
| 1 | New Features and Important Changes in ctools 1.5.0 | 1 | New Features and Important Changes in ctools 1.5.0 |
| 2 | 2 | ||
| 3 | -28 November 2017 | 3 | +12 January 2018 |
| 4 | 4 | ||
| 5 | 5 | ||
| 6 | Introduction | 6 | Introduction |
| @@ -219,6 +219,11 @@ None | @@ -219,6 +219,11 @@ None | ||
| 219 | 219 | ||
| 220 | csphagen - Generate On/Off observations | 220 | csphagen - Generate On/Off observations |
| 221 | --------------------------------------- | 221 | --------------------------------------- |
| 222 | +The CUSTOM background method was added to allow specifying On and Off regions | ||
| 223 | +from a region file or FITS WCS map. For multiple observations, a custom Off | ||
| 224 | +region per observation can be specified in the observation definition XML file | ||
| 225 | +using the OffRegions parameter (#2284). | ||
| 226 | + | ||
| 222 | The script was added to allow the generation of PHA, ARF and RMF datasets for classical On/Off IACT analysis (#2208). | 227 | The script was added to allow the generation of PHA, ARF and RMF datasets for classical On/Off IACT analysis (#2208). |
| 223 | 228 | ||
| 224 | 229 |
cscripts/csphagen.par
| @@ -26,27 +26,27 @@ prefix, s, h, onoff,,, "Prefix for output files" | @@ -26,27 +26,27 @@ prefix, s, h, onoff,,, "Prefix for output files" | ||
| 26 | # | 26 | # |
| 27 | # Script parameters | 27 | # Script parameters |
| 28 | #================== | 28 | #================== |
| 29 | -emin, r, a, 0.1,,, "Lower energy limit (TeV)" | ||
| 30 | -emax, r, a, 100.0,,, "Upper energy limit (TeV)" | ||
| 31 | -enumbins, i, a, 120,,, "Number of energy bins" | ||
| 32 | -ebinalg, s, a, LOG,LIN|LOG|FILE,, "Binning algorithm" | ||
| 33 | -ebinfile, f, a, NONE,,, "Name of the file containing the energy bin definition" | ||
| 34 | -srcshape, s, h, CIRCLE,CIRCLE,, "Shape of the source region" | ||
| 35 | -coordsys, s, a, CEL,CEL|GAL,, "Coordinate system (CEL - celestial, GAL - galactic)" | ||
| 36 | -ra, r, a, 83.63,0,360, "Right Ascension of source region centre (deg)" | ||
| 37 | -dec, r, a, 22.01,-90,90, "Declination of source region centre (deg)" | ||
| 38 | -glon, r, a, 184.56,0,360, "Galactic longitude of source region centre (deg)" | ||
| 39 | -glat, r, a, -5.79,-90,90, "Galactic latitude of source region centre (deg)" | ||
| 40 | -rad, r, a, 0.2,0,180, "Radius of source region circle (deg)" | ||
| 41 | -bkgmethod, s, h, REFLECTED,REFLECTED|CUSTOM,, "Method for background estimation" | ||
| 42 | -bkgregmin, i, h, 2,1,1000, "Minimum number of background regions" | ||
| 43 | -maxoffset, r, h, 4.0,,, "Maximum offset of source from camera center to accept observation" | ||
| 44 | -stack, b, a, no,,, "Stack multiple observations into single PHA, ARF and RMF files?" | ||
| 45 | -etruemin, r, h, 0.01,,, "Minimum true energy (TeV)" | ||
| 46 | -etruemax, r, h, 300.0,,, "Maximum true energy (TeV)" | ||
| 47 | -etruebins, i, h, 30,,, "Number of bins per decade for true energy bins" | ||
| 48 | -bkgreg, f, a, bkg.reg,,, "Background regions file (ds9 or FITS WCS)" | ||
| 49 | -srcreg, f, a, on.reg,,, "Source region file (ds9 or FITS WCS)" | 29 | +emin, r, a, 0.1,,, "Lower energy limit (TeV)" |
| 30 | +emax, r, a, 100.0,,, "Upper energy limit (TeV)" | ||
| 31 | +enumbins, i, a, 120,,, "Number of energy bins" | ||
| 32 | +ebinalg, s, a, LOG,LIN|LOG|FILE,, "Binning algorithm" | ||
| 33 | +ebinfile, f, a, NONE,,, "Name of the file containing the energy bin definition" | ||
| 34 | +srcshape, s, h, CIRCLE,CIRCLE,, "Shape of the source region" | ||
| 35 | +coordsys, s, a, CEL,CEL|GAL,, "Coordinate system (CEL - celestial, GAL - galactic)" | ||
| 36 | +ra, r, a, 83.63,0,360, "Right Ascension of source region centre (deg)" | ||
| 37 | +dec, r, a, 22.01,-90,90, "Declination of source region centre (deg)" | ||
| 38 | +glon, r, a, 184.56,0,360, "Galactic longitude of source region centre (deg)" | ||
| 39 | +glat, r, a, -5.79,-90,90, "Galactic latitude of source region centre (deg)" | ||
| 40 | +rad, r, a, 0.2,0,180, "Radius of source region circle (deg)" | ||
| 41 | +srcregfile, f, a, on.reg,,, "Source region file (ds9 or FITS WCS)" | ||
| 42 | +bkgmethod, s, a, REFLECTED,REFLECTED|CUSTOM,, "Method for background estimation" | ||
| 43 | +bkgregfile, f, a, bkg.reg,,, "Background regions file (ds9 or FITS WCS)" | ||
| 44 | +bkgregmin, i, h, 2,1,1000, "Minimum number of background regions" | ||
| 45 | +maxoffset, r, h, 4.0,,, "Maximum offset of source from camera center to accept observation" | ||
| 46 | +stack, b, a, no,,, "Stack multiple observations into single PHA, ARF and RMF files?" | ||
| 47 | +etruemin, r, h, 0.01,,, "Minimum true energy (TeV)" | ||
| 48 | +etruemax, r, h, 300.0,,, "Maximum true energy (TeV)" | ||
| 49 | +etruebins, i, h, 30,,, "Number of bins per decade for true energy bins" | ||
| 50 | 50 | ||
| 51 | # | 51 | # |
| 52 | # Standard parameters | 52 | # Standard parameters |
cscripts/csphagen.py
| @@ -3,7 +3,7 @@ | @@ -3,7 +3,7 @@ | ||
| 3 | # Computes the PHA spectra for source/background and ARF/RMF files using the | 3 | # Computes the PHA spectra for source/background and ARF/RMF files using the |
| 4 | # reflected region method | 4 | # reflected region method |
| 5 | # | 5 | # |
| 6 | -# Copyright (C) 2017 Luigi Tibaldo | 6 | +# Copyright (C) 2017-2018 Luigi Tibaldo |
| 7 | # | 7 | # |
| 8 | # This program is free software: you can redistribute it and/or modify | 8 | # This program is free software: you can redistribute it and/or modify |
| 9 | # it under the terms of the GNU General Public License as published by | 9 | # it under the terms of the GNU General Public License as published by |
| @@ -55,8 +55,9 @@ class csphagen(ctools.csobservation): | @@ -55,8 +55,9 @@ class csphagen(ctools.csobservation): | ||
| 55 | # Return | 55 | # Return |
| 56 | return | 56 | return |
| 57 | 57 | ||
| 58 | + | ||
| 58 | # Private methods | 59 | # Private methods |
| 59 | - def __query_src_direction(self): | 60 | + def _query_src_direction(self): |
| 60 | """ | 61 | """ |
| 61 | Set up the source direction parameter. | 62 | Set up the source direction parameter. |
| 62 | Query relevant parameters. | 63 | Query relevant parameters. |
| @@ -72,101 +73,137 @@ class csphagen(ctools.csobservation): | @@ -72,101 +73,137 @@ class csphagen(ctools.csobservation): | ||
| 72 | glat = self['glat'].real() | 73 | glat = self['glat'].real() |
| 73 | self._src_dir.lb_deg(glon, glat) | 74 | self._src_dir.lb_deg(glon, glat) |
| 74 | 75 | ||
| 75 | - def _get_parameters(self): | 76 | + def _get_parameters_bkgmethod_reflected(self): |
| 76 | """ | 77 | """ |
| 77 | - Get parameters from parfile and setup observations | ||
| 78 | - | ||
| 79 | - Raises | ||
| 80 | - ------ | ||
| 81 | - RuntimeError | ||
| 82 | - Multiple On-Regions in on region file or missing Off-Regions files. | 78 | + Get parameters for REFLECTED background method |
| 83 | """ | 79 | """ |
| 84 | - # Setup observations (require response and allow event list, don't | ||
| 85 | - # allow counts cube) | ||
| 86 | - self._setup_observations(self.obs(), True, True, False) | ||
| 87 | - | ||
| 88 | - # Set energy bounds | ||
| 89 | - self._ebounds = self._create_ebounds() | ||
| 90 | - | ||
| 91 | - # Initialize empty src regions container | ||
| 92 | - self._src_reg = gammalib.GSkyRegions() | 80 | + # Get source shape |
| 81 | + self._srcshape = self['srcshape'].string() | ||
| 93 | 82 | ||
| 94 | - # Query background estimation method and parameters | ||
| 95 | - bkgmethod = self['bkgmethod'].string() | ||
| 96 | - if bkgmethod == 'REFLECTED': | 83 | + # Set source region (so far only CIRCLE is supported) |
| 84 | + if self._srcshape == 'CIRCLE': | ||
| 97 | 85 | ||
| 98 | - # Always query src direction | ||
| 99 | - self.__query_src_direction() | ||
| 100 | - | ||
| 101 | - # Query region parameters | ||
| 102 | - self._srcshape = self['srcshape'].string() | ||
| 103 | - if self._srcshape == 'CIRCLE': | ||
| 104 | - self._rad = self['rad'].real() | ||
| 105 | - self._src_reg.append(gammalib.GSkyRegionCircle(self._src_dir, self._rad)) | 86 | + # Query source direction |
| 87 | + self._query_src_direction() | ||
| 106 | 88 | ||
| 89 | + # Query minimum number of background regions | ||
| 107 | self['bkgregmin'].integer() | 90 | self['bkgregmin'].integer() |
| 108 | 91 | ||
| 109 | - elif bkgmethod == 'CUSTOM': | 92 | + # Set circular source region |
| 93 | + self._rad = self['rad'].real() | ||
| 94 | + self._src_reg.append(gammalib.GSkyRegionCircle(self._src_dir, self._rad)) | ||
| 110 | 95 | ||
| 111 | - # Set up src region. Only 1 region is allowed. | ||
| 112 | - src_reg_file = self['srcreg'].filename() | ||
| 113 | - self._src_reg = gammalib.GSkyRegions(src_reg_file) | 96 | + # Return |
| 97 | + return | ||
| 114 | 98 | ||
| 115 | - if len(self._src_reg) != 1: | ||
| 116 | - raise RuntimeError('Only 1 ON region is allowed.') | 99 | + def _get_parameters_bkgmethod_custom(self): |
| 100 | + """ | ||
| 101 | + Get parameters for CUSTOM background method | ||
| 117 | 102 | ||
| 118 | - # Set up src direction. Query if neccessary. | ||
| 119 | - if isinstance(self._src_reg[0], gammalib.GSkyRegionCircle): | ||
| 120 | - self._src_dir = self._src_reg[0].centre() | ||
| 121 | - self._rad = self._src_reg[0].radius() | 103 | + Raises |
| 104 | + ------ | ||
| 105 | + RuntimeError | ||
| 106 | + Multiple On-Regions in on region file or missing Off-Regions files. | ||
| 107 | + """ | ||
| 108 | + # Set up source region | ||
| 109 | + src_reg_file = self['srcregfile'].filename() | ||
| 110 | + self._src_reg = gammalib.GSkyRegions(src_reg_file) | ||
| 111 | + | ||
| 112 | + # Raise an exception if there is more than one source region | ||
| 113 | + if len(self._src_reg) != 1: | ||
| 114 | + raise RuntimeError('Only 1 On region is allowed.') | ||
| 115 | + | ||
| 116 | + # Set up source direction. Query parameters if neccessary. | ||
| 117 | + if isinstance(self._src_reg[0], gammalib.GSkyRegionCircle): | ||
| 118 | + self._src_dir = self._src_reg[0].centre() | ||
| 119 | + self._rad = self._src_reg[0].radius() | ||
| 120 | + else: | ||
| 121 | + self._query_src_direction() | ||
| 122 | + | ||
| 123 | + # Try opening file as XML file. If this files we have probably a FITS | ||
| 124 | + # events file on input, hence we query later one background region | ||
| 125 | + # file | ||
| 126 | + try: | ||
| 127 | + # Open observation definition XML file | ||
| 128 | + obs_file = self['inobs'].filename() | ||
| 129 | + xml = gammalib.GXml(obs_file) | ||
| 130 | + | ||
| 131 | + # Go through elements in <observationlist> | ||
| 132 | + for elem in xml[0]: | ||
| 133 | + | ||
| 134 | + # Get observation id from <observation> header | ||
| 135 | + obs_id = elem.attribute('id') | ||
| 136 | + | ||
| 137 | + # Get region file path from <observation> body | ||
| 138 | + off_regions_file = '' | ||
| 139 | + for entry in elem: | ||
| 140 | + | ||
| 141 | + # <parameter name="OffRegions" file=".."/> contains region file | ||
| 142 | + if entry.attribute('name') == 'OffRegions': | ||
| 143 | + off_regions_file = entry.attribute('file') | ||
| 144 | + break | ||
| 145 | + | ||
| 146 | + # Store file paths | ||
| 147 | + self._bkg_reg_files[obs_id] = gammalib.GFilename(off_regions_file) | ||
| 148 | + | ||
| 149 | + # Not existing background region files are set to None (for every obs) | ||
| 150 | + if not self._bkg_reg_files[obs_id].exists(): | ||
| 151 | + self._bkg_reg_files[obs_id] = None | ||
| 152 | + | ||
| 153 | + # XML file opening failed | ||
| 154 | + except: | ||
| 155 | + self._bkg_reg_files = {0: None} | ||
| 156 | + | ||
| 157 | + # Query missing background region file | ||
| 158 | + if len([True for x in self._bkg_reg_files if self._bkg_reg_files[x] is None]) > 0: | ||
| 159 | + if len(self._bkg_reg_files) > 1: | ||
| 160 | + # Querying of multiple regions not supported | ||
| 161 | + raise RuntimeError('There are missing bkg region files in the ' | ||
| 162 | + 'observation definition XML file. Please ' | ||
| 163 | + 'specify all background region files.') | ||
| 122 | else: | 164 | else: |
| 123 | - self.__query_src_direction() | ||
| 124 | - | ||
| 125 | - # Set up bkg regions | ||
| 126 | - obs_file = self['inobs'].filename() | 165 | + # Query bkg region file for single observation |
| 166 | + self._bkg_reg_files[self._bkg_reg_files.keys()[0]] = \ | ||
| 167 | + self['bkgregfile'].filename() | ||
| 127 | 168 | ||
| 128 | - # obs def XML: look for region files | ||
| 129 | - if obs_file.file()[-3:] == 'xml': | ||
| 130 | - # open and load XML obs definition file | ||
| 131 | - xml = gammalib.GXml() | ||
| 132 | - xml.load(obs_file) | 169 | + # Return |
| 170 | + return | ||
| 133 | 171 | ||
| 134 | - # Go through elements in <observationlist> | ||
| 135 | - for elem in xml[0]: | 172 | + def _get_parameters_bkgmethod(self): |
| 173 | + """ | ||
| 174 | + Get background method parameters | ||
| 175 | + """ | ||
| 176 | + # Get background method | ||
| 177 | + bkgmethod = self['bkgmethod'].string() | ||
| 136 | 178 | ||
| 137 | - # Get observation id from <observation> header | ||
| 138 | - obs_id = elem.attribute('id') | 179 | + # Get background method dependent parameters |
| 180 | + if bkgmethod == 'REFLECTED': | ||
| 181 | + self._get_parameters_bkgmethod_reflected() | ||
| 182 | + elif bkgmethod == 'CUSTOM': | ||
| 183 | + self._get_parameters_bkgmethod_custom() | ||
| 139 | 184 | ||
| 140 | - # Get region file path from <observation> body | ||
| 141 | - off_regions_file = '' | ||
| 142 | - for entry in elem: | 185 | + # Query parameters that are needed for all background methods |
| 186 | + self['maxoffset'].real() | ||
| 143 | 187 | ||
| 144 | - # <parameter name="OffRegions" file=".."/> contains region file | ||
| 145 | - if entry.attribute('name') == 'OffRegions': | ||
| 146 | - off_regions_file = entry.attribute('file') | 188 | + # Return |
| 189 | + return | ||
| 147 | 190 | ||
| 148 | - # Store file paths | ||
| 149 | - self._bkg_reg_files[obs_id] = gammalib.GFilename(off_regions_file) | 191 | + def _get_parameters(self): |
| 192 | + """ | ||
| 193 | + Get parameters from parfile and setup observations | ||
| 194 | + """ | ||
| 195 | + # Setup observations (require response and allow event list, don't | ||
| 196 | + # allow counts cube) | ||
| 197 | + self._setup_observations(self.obs(), True, True, False) | ||
| 150 | 198 | ||
| 151 | - # Not existing bkg region files are set to None (for every obs) | ||
| 152 | - if not self._bkg_reg_files[obs_id].exists(): | ||
| 153 | - self._bkg_reg_files[obs_id] = None | 199 | + # Set energy bounds |
| 200 | + self._ebounds = self._create_ebounds() | ||
| 154 | 201 | ||
| 155 | - else: | ||
| 156 | - # event FITS files: query later 1 bkg region file | ||
| 157 | - self._bkg_reg_files = {0:None} | ||
| 158 | - | ||
| 159 | - # Query missing bkg region file | ||
| 160 | - if len([True for x in self._bkg_reg_files if self._bkg_reg_files[x] is None]) > 0: | ||
| 161 | - if len(self._bkg_reg_files) > 1: | ||
| 162 | - # Querying of multiple regions not supported | ||
| 163 | - raise RuntimeError('There are missing bkg region files in the obs definition' | ||
| 164 | - +' XML. Please specify all bkg region files!') | ||
| 165 | - else: | ||
| 166 | - # Query bkg region file for single observation | ||
| 167 | - self._bkg_reg_files[self._bkg_reg_files.keys()[0]] = self['bkgreg'].filename() | 202 | + # Initialize empty src regions container |
| 203 | + self._src_reg = gammalib.GSkyRegions() | ||
| 168 | 204 | ||
| 169 | - self['maxoffset'].real() | 205 | + # Get background method parameters |
| 206 | + self._get_parameters_bkgmethod() | ||
| 170 | 207 | ||
| 171 | # Exclusion map | 208 | # Exclusion map |
| 172 | if self['inexclusion'].filename().is_fits(): | 209 | if self['inexclusion'].filename().is_fits(): |
| @@ -260,7 +297,9 @@ class csphagen(ctools.csobservation): | @@ -260,7 +297,9 @@ class csphagen(ctools.csobservation): | ||
| 260 | 297 | ||
| 261 | def _regions_from_file(self, obs, file_path): | 298 | def _regions_from_file(self, obs, file_path): |
| 262 | """ | 299 | """ |
| 263 | - Read list of reflected regions for a single observation (pointing) from file. | 300 | + Read list of reflected regions for a single observation (pointing) |
| 301 | + from file. | ||
| 302 | + | ||
| 264 | Perform basic tests for circle shaped regions. | 303 | Perform basic tests for circle shaped regions. |
| 265 | 304 | ||
| 266 | Parameters | 305 | Parameters |
| @@ -278,12 +317,13 @@ class csphagen(ctools.csobservation): | @@ -278,12 +317,13 @@ class csphagen(ctools.csobservation): | ||
| 278 | # Load regions from ds9 file of FITS WCS map | 317 | # Load regions from ds9 file of FITS WCS map |
| 279 | regions = gammalib.GSkyRegions( file_path ) | 318 | regions = gammalib.GSkyRegions( file_path ) |
| 280 | 319 | ||
| 281 | - # Do region tests only for circle shaped on-region. Else simply return list. | 320 | + # Do region tests only for circle shaped on-region, simply return list |
| 321 | + # for other shapes. | ||
| 282 | on_region = self._src_reg[0] | 322 | on_region = self._src_reg[0] |
| 283 | if isinstance(on_region, gammalib.GSkyRegionCircle): | 323 | if isinstance(on_region, gammalib.GSkyRegionCircle): |
| 284 | 324 | ||
| 285 | # Prepare parameters for comparison | 325 | # Prepare parameters for comparison |
| 286 | - pnt_dir = obs.pointing().dir() | 326 | + pnt_dir = obs.pointing().dir() |
| 287 | offset_on = pnt_dir.dist_deg(self._src_dir) | 327 | offset_on = pnt_dir.dist_deg(self._src_dir) |
| 288 | radius_on = on_region.radius() | 328 | radius_on = on_region.radius() |
| 289 | 329 | ||
| @@ -297,27 +337,31 @@ class csphagen(ctools.csobservation): | @@ -297,27 +337,31 @@ class csphagen(ctools.csobservation): | ||
| 297 | offset_off = pnt_dir.dist_deg(region.centre()) | 337 | offset_off = pnt_dir.dist_deg(region.centre()) |
| 298 | radius_off = region.radius() | 338 | radius_off = region.radius() |
| 299 | 339 | ||
| 300 | - # Warn: different radius | 340 | + # Warning: different radius |
| 301 | if radius_off != radius_on: | 341 | if radius_off != radius_on: |
| 302 | - self._log_string(gammalib.EXPLICIT, 'Off region radius differs from on' | ||
| 303 | - 'region radius: %.2f vs %.2f' % ((radius_off, radius_on))) | 342 | + self._log_string(gammalib.EXPLICIT, 'Off region radius ' |
| 343 | + 'differs from On region radius: %.2f ' | ||
| 344 | + 'vs %.2f' % ((radius_off, radius_on))) | ||
| 304 | 345 | ||
| 305 | - # Warn: offset is too small or too large | 346 | + # Warning: offset is too small or too large |
| 306 | if offset_off <= radius_on or offset_off >= self['maxoffset'].real(): | 347 | if offset_off <= radius_on or offset_off >= self['maxoffset'].real(): |
| 307 | - self._log_string(gammalib.EXPLICIT, 'Region offset invalid for observation ' | ||
| 308 | - '%s (%.3f deg) ' % ((obs.id(), offset_off))) | 348 | + self._log_string(gammalib.EXPLICIT, 'Region offset ' |
| 349 | + 'invalid for observation %s ' | ||
| 350 | + '(%.3f deg) ' % ((obs.id(), offset_off))) | ||
| 309 | 351 | ||
| 310 | - # Warn: offset of off and on region differ | 352 | + # Warning: offset of off and on region differ |
| 311 | if offset_off != offset_on: | 353 | if offset_off != offset_on: |
| 312 | - self._log_string(gammalib.EXPLICIT, 'Off region offset differs ' | ||
| 313 | - '%.3f deg from on region offset' % (offset_off-offset_on)) | 354 | + self._log_string(gammalib.EXPLICIT, 'Off region offset ' |
| 355 | + 'differs %.3f deg from On region ' | ||
| 356 | + 'offset' % (offset_off-offset_on)) | ||
| 314 | 357 | ||
| 315 | # end: off-regions test for circle shaped regions | 358 | # end: off-regions test for circle shaped regions |
| 316 | # end: for loop iterating over off regions | 359 | # end: for loop iterating over off regions |
| 317 | # end: do region tests only if on-region is circle shaped | 360 | # end: do region tests only if on-region is circle shaped |
| 318 | 361 | ||
| 319 | # Inform user how many regions were loaded | 362 | # Inform user how many regions were loaded |
| 320 | - self._log_string(gammalib.NORMAL, 'Read %i regions from file %s.' % (regions.size(), file_path.url())) | 363 | + self._log_string(gammalib.NORMAL, 'Read %i regions from file %s' % \ |
| 364 | + (regions.size(), file_path.url())) | ||
| 321 | 365 | ||
| 322 | # return list of regions | 366 | # return list of regions |
| 323 | return regions | 367 | return regions |
| @@ -390,6 +434,45 @@ class csphagen(ctools.csobservation): | @@ -390,6 +434,45 @@ class csphagen(ctools.csobservation): | ||
| 390 | # Return energy boundaries | 434 | # Return energy boundaries |
| 391 | return ebounds | 435 | return ebounds |
| 392 | 436 | ||
| 437 | + def _set_background_regions(self, obs): | ||
| 438 | + """ | ||
| 439 | + Set background regions for an observation | ||
| 440 | + | ||
| 441 | + Parameters | ||
| 442 | + ---------- | ||
| 443 | + obs : `~gammalib.GCTAObservation()` | ||
| 444 | + CTA observation | ||
| 445 | + | ||
| 446 | + Returns | ||
| 447 | + ------- | ||
| 448 | + regions : `~gammalib.GSkyRegions()` | ||
| 449 | + Background regions | ||
| 450 | + """ | ||
| 451 | + # Initialise empty background regions for this observation | ||
| 452 | + bkg_reg = gammalib.GSkyRegions() | ||
| 453 | + | ||
| 454 | + # If reflected background is requested then created reflected | ||
| 455 | + # background regions | ||
| 456 | + if self['bkgmethod'].string() == 'REFLECTED': | ||
| 457 | + bkg_reg = self._reflected_regions(obs) | ||
| 458 | + | ||
| 459 | + # ... otherwise if custom background is requested the get the background | ||
| 460 | + # regions from a region file | ||
| 461 | + elif self['bkgmethod'].string() == 'CUSTOM': | ||
| 462 | + | ||
| 463 | + # Get file path of background region file from dictionary | ||
| 464 | + if len(self._bkg_reg_files) > 1: | ||
| 465 | + bkg_reg_file = self._bkg_reg_files[obs.id()] | ||
| 466 | + else: | ||
| 467 | + # for inobs==event list no obs id is set. | ||
| 468 | + bkg_reg_file = self._bkg_reg_files[self._bkg_reg_files.keys()[0]] | ||
| 469 | + | ||
| 470 | + # Load background regions from region file for current observation | ||
| 471 | + bkg_reg = self._regions_from_file(obs, bkg_reg_file) | ||
| 472 | + | ||
| 473 | + # Return background regions | ||
| 474 | + return bkg_reg | ||
| 475 | + | ||
| 393 | 476 | ||
| 394 | # Public methods | 477 | # Public methods |
| 395 | def run(self): | 478 | def run(self): |
| @@ -432,26 +515,10 @@ class csphagen(ctools.csobservation): | @@ -432,26 +515,10 @@ class csphagen(ctools.csobservation): | ||
| 432 | # Log current observation | 515 | # Log current observation |
| 433 | self._log_string(gammalib.NORMAL, 'Process Observation %s' % (obs.id())) | 516 | self._log_string(gammalib.NORMAL, 'Process Observation %s' % (obs.id())) |
| 434 | 517 | ||
| 435 | - # Initialise background regions for this observation | ||
| 436 | - bkg_reg = gammalib.GSkyRegions() | ||
| 437 | - | ||
| 438 | - # If reflected background is requested then created reflected | ||
| 439 | - # background regions | ||
| 440 | - if self['bkgmethod'].string() == 'REFLECTED': | ||
| 441 | - bkg_reg = self._reflected_regions(obs) | ||
| 442 | - elif self['bkgmethod'].string() == 'CUSTOM': | ||
| 443 | - # Get file path of bkg region file from dictionary | ||
| 444 | - if len(self._bkg_reg_files) > 1: | ||
| 445 | - bkg_reg_file = self._bkg_reg_files[obs.id()] | ||
| 446 | - else: | ||
| 447 | - # for inobs==event list no obs id is set. | ||
| 448 | - bkg_reg_file = self._bkg_reg_files[self._bkg_reg_files.keys()[0]] | ||
| 449 | - | ||
| 450 | - # Load off regions from region file for current observation | ||
| 451 | - bkg_reg = self._regions_from_file(obs, bkg_reg_file) | ||
| 452 | - | 518 | + # Set background regions for this observation |
| 519 | + bkg_reg = self._set_background_regions(obs) | ||
| 453 | 520 | ||
| 454 | - # If there are reflected regions then create On/Off observation | 521 | + # If there are background regions then create On/Off observation |
| 455 | # and append it to the output container | 522 | # and append it to the output container |
| 456 | if bkg_reg.size() >= self['bkgregmin'].integer(): | 523 | if bkg_reg.size() >= self['bkgregmin'].integer(): |
| 457 | onoff = gammalib.GCTAOnOffObservation(obs, self._src_dir, | 524 | onoff = gammalib.GCTAOnOffObservation(obs, self._src_dir, |
cscripts/obsutils.py
| 1 | # ========================================================================== | 1 | # ========================================================================== |
| 2 | # Utility functions for observation handling | 2 | # Utility functions for observation handling |
| 3 | # | 3 | # |
| 4 | -# Copyright (C) 2011-2017 Juergen Knoedlseder | 4 | +# Copyright (C) 2011-2018 Juergen Knoedlseder |
| 5 | # | 5 | # |
| 6 | # This program is free software: you can redistribute it and/or modify | 6 | # This program is free software: you can redistribute it and/or modify |
| 7 | # it under the terms of the GNU General Public License as published by | 7 | # it under the terms of the GNU General Public License as published by |
| @@ -130,6 +130,7 @@ def sim(obs, log=False, debug=False, chatter=2, edisp=False, seed=0, | @@ -130,6 +130,7 @@ def sim(obs, log=False, debug=False, chatter=2, edisp=False, seed=0, | ||
| 130 | phagen['rad'] = onrad | 130 | phagen['rad'] = onrad |
| 131 | phagen['stack'] = False | 131 | phagen['stack'] = False |
| 132 | phagen['inexclusion'] = 'NONE' | 132 | phagen['inexclusion'] = 'NONE' |
| 133 | + phagen['bkgmethod'] = 'REFLECTED' | ||
| 133 | 134 | ||
| 134 | # Optionally open the log file | 135 | # Optionally open the log file |
| 135 | if log: | 136 | if log: |
doc/source/admin/release_history/1.5.rst
| @@ -24,6 +24,8 @@ Bug fixes | @@ -24,6 +24,8 @@ Bug fixes | ||
| 24 | Improvements | 24 | Improvements |
| 25 | ------------ | 25 | ------------ |
| 26 | 26 | ||
| 27 | +* [`2284 <https://cta-redmine.irap.omp.eu/issues/2284>`_] - | ||
| 28 | + Add ``CUSTOM`` background method to :ref:`csphagen` script | ||
| 27 | * [`2273 <https://cta-redmine.irap.omp.eu/issues/2273>`_] - | 29 | * [`2273 <https://cta-redmine.irap.omp.eu/issues/2273>`_] - |
| 28 | Support On/Off analysis in :ref:`cslightcrv` and :ref:`csphasecrv` | 30 | Support On/Off analysis in :ref:`cslightcrv` and :ref:`csphasecrv` |
| 29 | * [`2267 <https://cta-redmine.irap.omp.eu/issues/2267>`_] - | 31 | * [`2267 <https://cta-redmine.irap.omp.eu/issues/2267>`_] - |
doc/source/users/reference_manual/csphagen.rst
| @@ -31,50 +31,48 @@ General parameters | @@ -31,50 +31,48 @@ General parameters | ||
| 31 | ------------------ | 31 | ------------------ |
| 32 | 32 | ||
| 33 | ``inobs [file]`` | 33 | ``inobs [file]`` |
| 34 | - Input event list or observation definition XML file. | 34 | + Input event list or observation definition XML file |
| 35 | 35 | ||
| 36 | ``caldb [string]`` | 36 | ``caldb [string]`` |
| 37 | - Calibration database. | 37 | + Calibration database |
| 38 | 38 | ||
| 39 | ``irf [string]`` | 39 | ``irf [string]`` |
| 40 | - Instrument response function. | 40 | + Instrument response function |
| 41 | 41 | ||
| 42 | ``(inexclusion = NONE) [file]`` | 42 | ``(inexclusion = NONE) [file]`` |
| 43 | Optional FITS file containing a WCS map in the first hdu that defines sky | 43 | Optional FITS file containing a WCS map in the first hdu that defines sky |
| 44 | - regions not to be used for background estimation (where map value != 0). | 44 | + regions not to be used for background estimation (where map value != 0) |
| 45 | 45 | ||
| 46 | ``outobs [string]`` | 46 | ``outobs [string]`` |
| 47 | - Output observation definition XML file. | 47 | + Output observation definition XML file |
| 48 | 48 | ||
| 49 | ``(prefix = onoff) [string]`` | 49 | ``(prefix = onoff) [string]`` |
| 50 | - Prefix of the file name for output PHA, ARF, RMF, XML, and DS9 region files. | 50 | + Prefix of the file name for output PHA, ARF, RMF, XML, and DS9 region files |
| 51 | 51 | ||
| 52 | ``emin [real]`` | 52 | ``emin [real]`` |
| 53 | - Lower energy limit (TeV) if ``LIN`` or ``LOG`` binning algorithms are used. | 53 | + Lower energy limit (TeV) if ``LIN`` or ``LOG`` binning algorithms are used |
| 54 | 54 | ||
| 55 | ``emax [real]`` | 55 | ``emax [real]`` |
| 56 | - Upper energy limit (TeV) if ``LIN`` or ``LOG`` binning algorithms are used. | 56 | + Upper energy limit (TeV) if ``LIN`` or ``LOG`` binning algorithms are used |
| 57 | 57 | ||
| 58 | ``enumbins [integer]`` | 58 | ``enumbins [integer]`` |
| 59 | Number of energy bins. At least 30 bins per decade are recommended for | 59 | Number of energy bins. At least 30 bins per decade are recommended for |
| 60 | proper evaluation of the instrument response. | 60 | proper evaluation of the instrument response. |
| 61 | 61 | ||
| 62 | -``ebinalg [string]`` | ||
| 63 | - Energy binning algorithm: | ||
| 64 | - ``LOG`` : logarithmically spaced energy bins; | ||
| 65 | - ``LIN`` : linearly spaced energy bins; | ||
| 66 | - ``FILE``: energy bounds retrieved from file. | 62 | +``ebinalg <FILE|LIN|LOG> [string]`` |
| 63 | + Algorithm for defining energy bins (``FILE``: energy bounds retrieved from | ||
| 64 | + file, see ``ebinfile`` parameter; ``LIN``: linearly spaced energy bins; | ||
| 65 | + ``LOG``: logarithmically spaced energy bins) | ||
| 67 | 66 | ||
| 68 | ``ebinfile [file]`` | 67 | ``ebinfile [file]`` |
| 69 | Name of the file containing the energy bin definition if ``FILE`` algorithm | 68 | Name of the file containing the energy bin definition if ``FILE`` algorithm |
| 70 | - is used. | 69 | + is used |
| 71 | 70 | ||
| 72 | -``(srcshape = CIRCLE) [string]`` | ||
| 73 | - Shape of the source region. | ||
| 74 | - ``CIRCLE``: circular region around given position. | 71 | +``(srcshape = CIRCLE) <CIRCLE> [string]`` |
| 72 | + Shape of the source region (``CIRCLE``: circular region around given position) | ||
| 75 | 73 | ||
| 76 | -``coordsys [string]`` | ||
| 77 | - Coordinate system (``CEL`` - celestial, ``GAL`` - galactic) | 74 | +``coordsys <CEL|GAL> [string]`` |
| 75 | + Coordinate system (``CEL``: celestial; ``GAL``: galactic) | ||
| 78 | 76 | ||
| 79 | ``ra [real]`` | 77 | ``ra [real]`` |
| 80 | Right Ascension of source region centre (deg) | 78 | Right Ascension of source region centre (deg) |
| @@ -91,17 +89,25 @@ General parameters | @@ -91,17 +89,25 @@ General parameters | ||
| 91 | ``rad [real]`` | 89 | ``rad [real]`` |
| 92 | Radius of source region circle (deg) | 90 | Radius of source region circle (deg) |
| 93 | 91 | ||
| 94 | -``(bkgmethod = REFLECTED) [string]`` | ||
| 95 | - Method for background estimation. | ||
| 96 | - ``REFLECTED:`` background evaluated in regions with the same shape as | ||
| 97 | - source region reflected w.r.t. pointing direction for each observation. | ||
| 98 | - ``CUSTOM:`` background evaluated in regions specified by user. | ||
| 99 | - For event list or single obs in an obs definition XML: region files can | ||
| 100 | - be queried. | ||
| 101 | - For multiple observations: those have to be specified in the obs def XML. | ||
| 102 | - Here use parameter name="OffRegions" (per observation) with appropriate | ||
| 103 | - <file> entry. Files can be ds9 regions or FITS WCS maps. The on region | ||
| 104 | - will always be queried. | 92 | +``srcregfile [file]`` |
| 93 | + Source region file (ds9 or FITS WCS map) | ||
| 94 | + | ||
| 95 | +``bkgmethod <REFLECTED|CUSTOM> [string]`` | ||
| 96 | + Method for background estimation: | ||
| 97 | + | ||
| 98 | + - ``REFLECTED``: background is evaluated in regions with the same shape as | ||
| 99 | + the source region reflected w.r.t. pointing direction for each observation | ||
| 100 | + | ||
| 101 | + - ``CUSTOM``: background is evaluated in regions specified by user. For an | ||
| 102 | + event list or a single observation in the observation definition XML file | ||
| 103 | + a region file will be queried (see ``bkgregfile`` parameter). For multiple | ||
| 104 | + observations specified in the observation definition XML file the name of | ||
| 105 | + the region file will be extracted from the ``OffRegions`` parameter that | ||
| 106 | + needs to be specified for each observation in the observation definition | ||
| 107 | + XML file. Off region files can be either ds9 region files or FITS WCS maps. | ||
| 108 | + | ||
| 109 | +``bkgregfile [file]`` | ||
| 110 | + Background regions file (ds9 or FITS WCS map) | ||
| 105 | 111 | ||
| 106 | ``(bkgregmin = 2) [integer]`` | 112 | ``(bkgregmin = 2) [integer]`` |
| 107 | Minimum number of background regions that are required for an observation. | 113 | Minimum number of background regions that are required for an observation. |
| @@ -110,26 +116,20 @@ General parameters | @@ -110,26 +116,20 @@ General parameters | ||
| 110 | 116 | ||
| 111 | ``(maxoffset = 4.0) [real]`` | 117 | ``(maxoffset = 4.0) [real]`` |
| 112 | Maximum offset in degrees of source from camera center to accept the | 118 | Maximum offset in degrees of source from camera center to accept the |
| 113 | - observation. | 119 | + observation |
| 114 | 120 | ||
| 115 | ``stack [boolean]`` | 121 | ``stack [boolean]`` |
| 116 | Specifies whether multiple observations should be stacked (``yes``) or | 122 | Specifies whether multiple observations should be stacked (``yes``) or |
| 117 | - whether run-wise PHA, ARF and RMF files should be produced (``no``). | 123 | + whether run-wise PHA, ARF and RMF files should be produced (``no``) |
| 118 | 124 | ||
| 119 | ``(etruemin = 0.01) [real]`` | 125 | ``(etruemin = 0.01) [real]`` |
| 120 | - Minimum true energy (TeV). | 126 | + Minimum true energy (TeV) |
| 121 | 127 | ||
| 122 | ``(etruemax = 0.01) [real]`` | 128 | ``(etruemax = 0.01) [real]`` |
| 123 | - Maximum true energy (TeV). | 129 | + Maximum true energy (TeV) |
| 124 | 130 | ||
| 125 | ``(etruebins = 30) [integer]`` | 131 | ``(etruebins = 30) [integer]`` |
| 126 | - Number of bins per decade for true energy bins. | ||
| 127 | - | ||
| 128 | -``(bkgreg = bkg.reg) [file]`` | ||
| 129 | - Background regions file (ds9 or FITS WCS map). | ||
| 130 | - | ||
| 131 | -``(srcreg = on.reg) [file]`` | ||
| 132 | - Source region file (ds9 or FITS WCS map). | 132 | + Number of bins per decade for true energy bins |
| 133 | 133 | ||
| 134 | 134 | ||
| 135 | Standard parameters | 135 | Standard parameters |
test/test_csphagen.py
| @@ -92,7 +92,8 @@ class Test(test): | @@ -92,7 +92,8 @@ class Test(test): | ||
| 92 | ' coordsys="CEL" ra=83.633 dec=22.0145' + \ | 92 | ' coordsys="CEL" ra=83.633 dec=22.0145' + \ |
| 93 | ' rad=0.2 stack="no" inexclusion="' + \ | 93 | ' rad=0.2 stack="no" inexclusion="' + \ |
| 94 | self._exclusion + \ | 94 | self._exclusion + \ |
| 95 | - '" outobs="csphagen_cmd1.xml" prefix="csphagen_cmd1" ' + \ | 95 | + '" bkgmethod="REFLECTED" '+ \ |
| 96 | + 'outobs="csphagen_cmd1.xml" prefix="csphagen_cmd1" ' + \ | ||
| 96 | 'logfile="csphagen_cmd1.log" chatter=2' | 97 | 'logfile="csphagen_cmd1.log" chatter=2' |
| 97 | 98 | ||
| 98 | # Check if execution of wrong command fails | 99 | # Check if execution of wrong command fails |
| @@ -119,7 +120,8 @@ class Test(test): | @@ -119,7 +120,8 @@ class Test(test): | ||
| 119 | ' coordsys="CEL" ra=83.633 dec=22.0145' + \ | 120 | ' coordsys="CEL" ra=83.633 dec=22.0145' + \ |
| 120 | ' rad=0.2 stack="no" inexclusion="' + \ | 121 | ' rad=0.2 stack="no" inexclusion="' + \ |
| 121 | self._exclusion + \ | 122 | self._exclusion + \ |
| 122 | - '" outobs="csphagen_cmd2.xml" prefix="csphagen_cmd2" ' + \ | 123 | + '" bkgmethod="REFLECTED" '+ \ |
| 124 | + 'outobs="csphagen_cmd2.xml" prefix="csphagen_cmd2" ' + \ | ||
| 123 | 'logfile="csphagen_cmd2.log" debug=yes chatter=1' | 125 | 'logfile="csphagen_cmd2.log" debug=yes chatter=1' |
| 124 | 126 | ||
| 125 | # Check if execution failed | 127 | # Check if execution failed |
| @@ -151,6 +153,7 @@ class Test(test): | @@ -151,6 +153,7 @@ class Test(test): | ||
| 151 | phagen['rad'] = 0.2 | 153 | phagen['rad'] = 0.2 |
| 152 | phagen['stack'] = False | 154 | phagen['stack'] = False |
| 153 | phagen['inexclusion'] = self._exclusion | 155 | phagen['inexclusion'] = self._exclusion |
| 156 | + phagen['bkgmethod'] = 'REFLECTED' | ||
| 154 | phagen['etruemin'] = 0.05 | 157 | phagen['etruemin'] = 0.05 |
| 155 | phagen['etruemax'] = 150.0 | 158 | phagen['etruemax'] = 150.0 |
| 156 | phagen['etruebins'] = 5 | 159 | phagen['etruebins'] = 5 |
| @@ -180,6 +183,7 @@ class Test(test): | @@ -180,6 +183,7 @@ class Test(test): | ||
| 180 | phagen['dec'] = 22.0145 | 183 | phagen['dec'] = 22.0145 |
| 181 | phagen['rad'] = 0.2 | 184 | phagen['rad'] = 0.2 |
| 182 | phagen['stack'] = False | 185 | phagen['stack'] = False |
| 186 | + phagen['bkgmethod'] = 'REFLECTED' | ||
| 183 | phagen['etruemin'] = 0.05 | 187 | phagen['etruemin'] = 0.05 |
| 184 | phagen['etruemax'] = 150.0 | 188 | phagen['etruemax'] = 150.0 |
| 185 | phagen['etruebins'] = 5 | 189 | phagen['etruebins'] = 5 |
| @@ -216,6 +220,7 @@ class Test(test): | @@ -216,6 +220,7 @@ class Test(test): | ||
| 216 | phagen['rad'] = 0.2 | 220 | phagen['rad'] = 0.2 |
| 217 | phagen['stack'] = False | 221 | phagen['stack'] = False |
| 218 | phagen['inexclusion'] = self._exclusion | 222 | phagen['inexclusion'] = self._exclusion |
| 223 | + phagen['bkgmethod'] = 'REFLECTED' | ||
| 219 | phagen['etruemin'] = 0.05 | 224 | phagen['etruemin'] = 0.05 |
| 220 | phagen['etruemax'] = 150.0 | 225 | phagen['etruemax'] = 150.0 |
| 221 | phagen['etruebins'] = 5 | 226 | phagen['etruebins'] = 5 |
| @@ -246,6 +251,7 @@ class Test(test): | @@ -246,6 +251,7 @@ class Test(test): | ||
| 246 | phagen['rad'] = 0.2 | 251 | phagen['rad'] = 0.2 |
| 247 | phagen['stack'] = True | 252 | phagen['stack'] = True |
| 248 | phagen['inexclusion'] = self._exclusion | 253 | phagen['inexclusion'] = self._exclusion |
| 254 | + phagen['bkgmethod'] = 'REFLECTED' | ||
| 249 | phagen['etruemin'] = 0.05 | 255 | phagen['etruemin'] = 0.05 |
| 250 | phagen['etruemax'] = 150.0 | 256 | phagen['etruemax'] = 150.0 |
| 251 | phagen['etruebins'] = 5 | 257 | phagen['etruebins'] = 5 |
| @@ -293,9 +299,10 @@ class Test(test): | @@ -293,9 +299,10 @@ class Test(test): | ||
| 293 | 'inexclusion="' + self._exclusion + '" ' + \ | 299 | 'inexclusion="' + self._exclusion + '" ' + \ |
| 294 | 'bkgmethod="CUSTOM" ' + \ | 300 | 'bkgmethod="CUSTOM" ' + \ |
| 295 | 'rad=0.2 ' + \ | 301 | 'rad=0.2 ' + \ |
| 296 | - 'srcreg="' + self._regfile_src + '" ' + \ | ||
| 297 | - 'bkgreg="' + self._regfile_bkg + '" ' + \ | ||
| 298 | - 'outobs="csphagen_regfiles_cmd1.xml" prefix="csphagen_regfiles_cmd1" ' + \ | 302 | + 'srcregfile="' + self._regfile_src + '" ' + \ |
| 303 | + 'bkgregfile="' + self._regfile_bkg + '" ' + \ | ||
| 304 | + 'outobs="csphagen_regfiles_cmd1.xml" ' + \ | ||
| 305 | + 'prefix="csphagen_regfiles_cmd1" ' + \ | ||
| 299 | 'logfile="csphagen_regfiles_cmd1.log" chatter=2 ' + \ | 306 | 'logfile="csphagen_regfiles_cmd1.log" chatter=2 ' + \ |
| 300 | 'coordsys="CEL" ra=83.633 dec=22.0145' | 307 | 'coordsys="CEL" ra=83.633 dec=22.0145' |
| 301 | 308 |