Commit af530c3337fce06cff37f9d26a28523a2a121a5d
1 parent
8bcf40c9
small improvements
Showing
1 changed file
with
65 additions
and
775 deletions
scripts/obsutils.py
| 1 | # ========================================================================== | 1 | # ========================================================================== |
| 2 | # This script provides a number of functions that are useful for handling | 2 | # This script provides a number of functions that are useful for handling |
| 3 | -# CTA data. | 3 | +# CTA observations. |
| 4 | # | 4 | # |
| 5 | # Copyright (C) 2011 Jurgen Knodlseder | 5 | # Copyright (C) 2011 Jurgen Knodlseder |
| 6 | # | 6 | # |
| @@ -20,7 +20,7 @@ | @@ -20,7 +20,7 @@ | ||
| 20 | # ========================================================================== | 20 | # ========================================================================== |
| 21 | from ctatools import * | 21 | from ctatools import * |
| 22 | from gammalib import * | 22 | from gammalib import * |
| 23 | -from math import * | 23 | +#from math import * |
| 24 | #import os | 24 | #import os |
| 25 | #import glob | 25 | #import glob |
| 26 | #import sys | 26 | #import sys |
| @@ -32,7 +32,7 @@ from math import * | @@ -32,7 +32,7 @@ from math import * | ||
| 32 | # ===================== # | 32 | # ===================== # |
| 33 | # Simulate observations # | 33 | # Simulate observations # |
| 34 | # ===================== # | 34 | # ===================== # |
| 35 | -def sim_obs(obs, log=False, seed=0, nbins=0, binsz=0.05, npix=200): | 35 | +def sim(obs, log=False, debug=True, seed=0, nbins=0, binsz=0.05, npix=200): |
| 36 | """ | 36 | """ |
| 37 | Simulate events for all observations in the container. | 37 | Simulate events for all observations in the container. |
| 38 | 38 | ||
| @@ -40,6 +40,7 @@ def sim_obs(obs, log=False, seed=0, nbins=0, binsz=0.05, npix=200): | @@ -40,6 +40,7 @@ def sim_obs(obs, log=False, seed=0, nbins=0, binsz=0.05, npix=200): | ||
| 40 | obs - Observation container | 40 | obs - Observation container |
| 41 | Keywords: | 41 | Keywords: |
| 42 | log - Create log file(s) | 42 | log - Create log file(s) |
| 43 | + debug - Create screen dump | ||
| 43 | seed - Seed value for simulations (default: 0) | 44 | seed - Seed value for simulations (default: 0) |
| 44 | nbins - Number of energy bins (default: 0=unbinned) | 45 | nbins - Number of energy bins (default: 0=unbinned) |
| 45 | binsz - Pixel size for binned simulation (deg/pixel) | 46 | binsz - Pixel size for binned simulation (deg/pixel) |
| @@ -52,6 +53,10 @@ def sim_obs(obs, log=False, seed=0, nbins=0, binsz=0.05, npix=200): | @@ -52,6 +53,10 @@ def sim_obs(obs, log=False, seed=0, nbins=0, binsz=0.05, npix=200): | ||
| 52 | # Optionally open the log file | 53 | # Optionally open the log file |
| 53 | if log: | 54 | if log: |
| 54 | sim.logFileOpen() | 55 | sim.logFileOpen() |
| 56 | + | ||
| 57 | + # Optionally switch-on debugging model | ||
| 58 | + if debug: | ||
| 59 | + sim["debug"].boolean(True) | ||
| 55 | 60 | ||
| 56 | # Run ctobssim application. This will loop over all observations in the | 61 | # Run ctobssim application. This will loop over all observations in the |
| 57 | # container and simulation the events for each observation. Note that | 62 | # container and simulation the events for each observation. Note that |
| @@ -92,6 +97,10 @@ def sim_obs(obs, log=False, seed=0, nbins=0, binsz=0.05, npix=200): | @@ -92,6 +97,10 @@ def sim_obs(obs, log=False, seed=0, nbins=0, binsz=0.05, npix=200): | ||
| 92 | if log: | 97 | if log: |
| 93 | bin.logFileOpen() | 98 | bin.logFileOpen() |
| 94 | 99 | ||
| 100 | + # Optionally switch-on debugging model | ||
| 101 | + if debug: | ||
| 102 | + bin["debug"].boolean(True) | ||
| 103 | + | ||
| 95 | # Run ctbin application. This will loop over all observations in | 104 | # Run ctbin application. This will loop over all observations in |
| 96 | # the container and bin the events in counts maps | 105 | # the container and bin the events in counts maps |
| 97 | bin.run() | 106 | bin.run() |
| @@ -115,14 +124,15 @@ def sim_obs(obs, log=False, seed=0, nbins=0, binsz=0.05, npix=200): | @@ -115,14 +124,15 @@ def sim_obs(obs, log=False, seed=0, nbins=0, binsz=0.05, npix=200): | ||
| 115 | # ================ # | 124 | # ================ # |
| 116 | # Fit observations # | 125 | # Fit observations # |
| 117 | # ================ # | 126 | # ================ # |
| 118 | -def fit_obs(obs, log=False): | 127 | +def fit(obs, log=False, debug=False): |
| 119 | """ | 128 | """ |
| 120 | Perform maximum likelihood fitting of observations in the container. | 129 | Perform maximum likelihood fitting of observations in the container. |
| 121 | 130 | ||
| 122 | Parameters: | 131 | Parameters: |
| 123 | - obs - Observation container | 132 | + obs - Observation container |
| 124 | Keywords: | 133 | Keywords: |
| 125 | - log - Create log file(s) | 134 | + log - Create log file(s) |
| 135 | + debug - Create screen dump | ||
| 126 | """ | 136 | """ |
| 127 | # Allocate ctlike application | 137 | # Allocate ctlike application |
| 128 | like = ctlike(obs) | 138 | like = ctlike(obs) |
| @@ -130,6 +140,9 @@ def fit_obs(obs, log=False): | @@ -130,6 +140,9 @@ def fit_obs(obs, log=False): | ||
| 130 | # Optionally open the log file | 140 | # Optionally open the log file |
| 131 | if log: | 141 | if log: |
| 132 | like.logFileOpen() | 142 | like.logFileOpen() |
| 143 | + | ||
| 144 | + # Optionally switch-on debugging model | ||
| 145 | + if debug: | ||
| 133 | like["debug"].boolean(True) | 146 | like["debug"].boolean(True) |
| 134 | 147 | ||
| 135 | # Run ctlike application. | 148 | # Run ctlike application. |
| @@ -142,25 +155,27 @@ def fit_obs(obs, log=False): | @@ -142,25 +155,27 @@ def fit_obs(obs, log=False): | ||
| 142 | # ================= # | 155 | # ================= # |
| 143 | # Create counts map # | 156 | # Create counts map # |
| 144 | # ================= # | 157 | # ================= # |
| 145 | -def make_counts_map(obs, proj="TAN", coord="GAL", xval=0.0, yval=0.0, \ | ||
| 146 | - nxpix=600, nypix=200, pixsize=0.05, \ | ||
| 147 | - outname="survey_cntmap.fits"): | 158 | +def cntmap(obs, proj="TAN", coord="GAL", xval=0.0, yval=0.0, \ |
| 159 | + binsz=0.05, nxpix=200, nypix=200, \ | ||
| 160 | + outname="cntmap.fits"): | ||
| 148 | """ | 161 | """ |
| 149 | Creates a counts map by combining the events of all observations. | 162 | Creates a counts map by combining the events of all observations. |
| 150 | The counts map will be a summed map over all energies. | 163 | The counts map will be a summed map over all energies. |
| 151 | 164 | ||
| 152 | Parameters: | 165 | Parameters: |
| 153 | - obs - Observation container | 166 | + obs - Observation container |
| 154 | Keywords: | 167 | Keywords: |
| 155 | - xval - Reference longitude value [deg] | ||
| 156 | - yval - Reference latitude value [deg] | ||
| 157 | - nxpix - Number of pixels in longitude axis | ||
| 158 | - nypix - Number of pixels in latitude axis | ||
| 159 | - pixsize - Pixel size [deg] | ||
| 160 | - outname - Counts map FITS filename | 168 | + proj - Projection type (e.g. TAN, CAR, STG, ...) (default: TAN) |
| 169 | + coord - Coordinate type (GAL, CEL) (default: GAL) | ||
| 170 | + xval - Reference longitude value [deg] (default: 0.0) | ||
| 171 | + yval - Reference latitude value [deg] (default: 0.0) | ||
| 172 | + binsz - Pixel size [deg/pixel] (default: 0.05) | ||
| 173 | + nxpix - Number of pixels in X direction (default: 200) | ||
| 174 | + nypix - Number of pixels in Y direction (default: 200) | ||
| 175 | + outname - Counts map FITS filename (default: cntmap.fits) | ||
| 161 | """ | 176 | """ |
| 162 | # Allocate counts map | 177 | # Allocate counts map |
| 163 | - cntmap = GSkymap(proj, coord, xval, yval, -pixsize, pixsize, nxpix, nypix, 1) | 178 | + map = GSkymap(proj, coord, xval, yval, -binsz, binsz, nxpix, nypix, 1) |
| 164 | 179 | ||
| 165 | # Fill all observations | 180 | # Fill all observations |
| 166 | for run in obs: | 181 | for run in obs: |
| @@ -173,43 +188,45 @@ def make_counts_map(obs, proj="TAN", coord="GAL", xval=0.0, yval=0.0, \ | @@ -173,43 +188,45 @@ def make_counts_map(obs, proj="TAN", coord="GAL", xval=0.0, yval=0.0, \ | ||
| 173 | 188 | ||
| 174 | # Determine sky pixel | 189 | # Determine sky pixel |
| 175 | skydir = event.dir().skydir() | 190 | skydir = event.dir().skydir() |
| 176 | - pixel = cntmap.dir2pix(skydir) | 191 | + pixel = map.dir2pix(skydir) |
| 177 | 192 | ||
| 178 | # Set pixel | 193 | # Set pixel |
| 179 | - cntmap[pixel] += 1.0 | 194 | + map[pixel] += 1.0 |
| 180 | 195 | ||
| 181 | # Save sky map. The clobber flag is set to True, so any existing FITS | 196 | # Save sky map. The clobber flag is set to True, so any existing FITS |
| 182 | # file will be overwritten. | 197 | # file will be overwritten. |
| 183 | - cntmap.save(outname, True) | 198 | + map.save(outname, True) |
| 184 | 199 | ||
| 185 | # Return counts map | 200 | # Return counts map |
| 186 | - return cntmap | 201 | + return map |
| 187 | 202 | ||
| 188 | 203 | ||
| 189 | # ================ # | 204 | # ================ # |
| 190 | # Create model map # | 205 | # Create model map # |
| 191 | # ================ # | 206 | # ================ # |
| 192 | -def make_model_map(obs, eref=0.1, proj="TAN", coord="GAL", xval=0.0, yval=0.0, \ | ||
| 193 | - nxpix=600, nypix=200, pixsize=0.05, \ | ||
| 194 | - outname="survey_modmap.fits"): | 207 | +def modmap(obs, eref=0.1, proj="TAN", coord="GAL", xval=0.0, yval=0.0, \ |
| 208 | + binsz=0.05, nxpix=200, nypix=200, \ | ||
| 209 | + outname="modmap.fits"): | ||
| 195 | """ | 210 | """ |
| 196 | Make model map for a given reference energy by combining all observations. | 211 | Make model map for a given reference energy by combining all observations. |
| 197 | The model map will be evaluated for a given reference energy 'eref' and will | 212 | The model map will be evaluated for a given reference energy 'eref' and will |
| 198 | be given in units of [counts/(sr MeV s)]. | 213 | be given in units of [counts/(sr MeV s)]. |
| 199 | 214 | ||
| 200 | Parameters: | 215 | Parameters: |
| 201 | - obs - Observation container | 216 | + obs - Observation container |
| 202 | Keywords: | 217 | Keywords: |
| 203 | - eref - Reference energy for which model is created [TeV] | ||
| 204 | - xval - Reference longitude value [deg] | ||
| 205 | - yval - Reference latitude value [deg] | ||
| 206 | - nxpix - Number of pixels in longitude axis | ||
| 207 | - nypix - Number of pixels in latitude axis | ||
| 208 | - pixsize - Pixel size [deg] | ||
| 209 | - outname - Counts map FITS filename | 218 | + eref - Reference energy for which model is created [TeV] (default: 0.1) |
| 219 | + proj - Projection type (e.g. TAN, CAR, STG, ...) (default: TAN) | ||
| 220 | + coord - Coordinate type (GAL, CEL) (default: GAL) | ||
| 221 | + xval - Reference longitude value [deg] (default: 0.0) | ||
| 222 | + yval - Reference latitude value [deg] (default: 0.0) | ||
| 223 | + binsz - Pixel size [deg/pixel] (default: 0.05) | ||
| 224 | + nxpix - Number of pixels in X direction (default: 200) | ||
| 225 | + nypix - Number of pixels in Y direction (default: 200) | ||
| 226 | + outname - Model map FITS filename (default: modmap.fits) | ||
| 210 | """ | 227 | """ |
| 211 | # Allocate model map | 228 | # Allocate model map |
| 212 | - modmap = GSkymap(proj, coord, xval, yval, -pixsize, pixsize, nxpix, nypix, 1) | 229 | + map = GSkymap(proj, coord, xval, yval, -binsz, binsz, nxpix, nypix, 1) |
| 213 | 230 | ||
| 214 | # Set reference energy, time and direction. The time is not initialised and is | 231 | # Set reference energy, time and direction. The time is not initialised and is |
| 215 | # in fact not used (as the IRF is assumed to be time independent for now). | 232 | # in fact not used (as the IRF is assumed to be time independent for now). |
| @@ -220,10 +237,10 @@ def make_model_map(obs, eref=0.1, proj="TAN", coord="GAL", xval=0.0, yval=0.0, \ | @@ -220,10 +237,10 @@ def make_model_map(obs, eref=0.1, proj="TAN", coord="GAL", xval=0.0, yval=0.0, \ | ||
| 220 | energy.TeV(eref) | 237 | energy.TeV(eref) |
| 221 | 238 | ||
| 222 | # Loop over all map pixels | 239 | # Loop over all map pixels |
| 223 | - for pixel in range(modmap.npix()): | 240 | + for pixel in range(map.npix()): |
| 224 | 241 | ||
| 225 | # Get sky direction | 242 | # Get sky direction |
| 226 | - skydir = modmap.pix2dir(pixel) | 243 | + skydir = map.pix2dir(pixel) |
| 227 | instdir.skydir(skydir) | 244 | instdir.skydir(skydir) |
| 228 | 245 | ||
| 229 | # Create event atom for map pixel | 246 | # Create event atom for map pixel |
| @@ -240,21 +257,21 @@ def make_model_map(obs, eref=0.1, proj="TAN", coord="GAL", xval=0.0, yval=0.0, \ | @@ -240,21 +257,21 @@ def make_model_map(obs, eref=0.1, proj="TAN", coord="GAL", xval=0.0, yval=0.0, \ | ||
| 240 | value += obs.models().eval(atom, run) | 257 | value += obs.models().eval(atom, run) |
| 241 | 258 | ||
| 242 | # Set map value | 259 | # Set map value |
| 243 | - modmap[pixel] = value | 260 | + map[pixel] = value |
| 244 | 261 | ||
| 245 | # Save sky map | 262 | # Save sky map |
| 246 | - modmap.save(outname, True) | 263 | + map.save(outname, True) |
| 247 | 264 | ||
| 248 | # Return model map | 265 | # Return model map |
| 249 | - return modmap | 266 | + return map |
| 250 | 267 | ||
| 251 | 268 | ||
| 252 | # ======================= # | 269 | # ======================= # |
| 253 | # Set one CTA observation # | 270 | # Set one CTA observation # |
| 254 | # ======================= # | 271 | # ======================= # |
| 255 | -def set_one_obs(pntdir, tstart=0.0, duration=1800.0, \ | ||
| 256 | - emin=0.1, emax=100.0, rad=5.0, \ | ||
| 257 | - irf="kb_E_50h_v3", caldb="/usr/local/gamma/share/caldb/cta"): | 272 | +def set(pntdir, tstart=0.0, duration=1800.0, \ |
| 273 | + emin=0.1, emax=100.0, rad=5.0, \ | ||
| 274 | + irf="kb_E_50h_v3", caldb="$GAMMALIB/share/caldb/cta"): | ||
| 258 | """ | 275 | """ |
| 259 | Returns a single CTA observation. By looping over this function we can | 276 | Returns a single CTA observation. By looping over this function we can |
| 260 | add CTA observations to the observation container. | 277 | add CTA observations to the observation container. |
| @@ -262,13 +279,13 @@ def set_one_obs(pntdir, tstart=0.0, duration=1800.0, \ | @@ -262,13 +279,13 @@ def set_one_obs(pntdir, tstart=0.0, duration=1800.0, \ | ||
| 262 | Parameters: | 279 | Parameters: |
| 263 | pntdir - Pointing direction | 280 | pntdir - Pointing direction |
| 264 | Keywords: | 281 | Keywords: |
| 265 | - tstart - Start time [seconds] | ||
| 266 | - duration - Duration of observation [seconds] | ||
| 267 | - emin - Minimum event energy [TeV] | ||
| 268 | - emax - Maximum event energy [TeV] | ||
| 269 | - rad - ROI radius used for analysis [deg] | ||
| 270 | - irf - Instrument response function | ||
| 271 | - caldb - Calibration database path | 282 | + tstart - Start time [seconds] (default: 0.0) |
| 283 | + duration - Duration of observation [seconds] (default: 1800.0) | ||
| 284 | + emin - Minimum event energy [TeV] (default: 0.1) | ||
| 285 | + emax - Maximum event energy [TeV] (default: 100.0) | ||
| 286 | + rad - ROI radius used for analysis [deg] (default: 5.0) | ||
| 287 | + irf - Instrument response function (default: kb_E_50h_v3) | ||
| 288 | + caldb - Calibration database path (default: $GAMMALIB/share/caldb/cta) | ||
| 272 | """ | 289 | """ |
| 273 | # Allocate CTA observation | 290 | # Allocate CTA observation |
| 274 | obs = GCTAObservation() | 291 | obs = GCTAObservation() |
| @@ -310,733 +327,6 @@ def set_one_obs(pntdir, tstart=0.0, duration=1800.0, \ | @@ -310,733 +327,6 @@ def set_one_obs(pntdir, tstart=0.0, duration=1800.0, \ | ||
| 310 | 327 | ||
| 311 | # Set instrument response | 328 | # Set instrument response |
| 312 | obs.response(irf, caldb) | 329 | obs.response(irf, caldb) |
| 313 | - #print obs | ||
| 314 | 330 | ||
| 315 | # Return observation | 331 | # Return observation |
| 316 | return obs | 332 | return obs |
| 317 | - | ||
| 318 | - | ||
| 319 | -# ================== # | ||
| 320 | -# Setup source model # | ||
| 321 | -# ================== # | ||
| 322 | -def add_source_model(models, source): | ||
| 323 | - """ | ||
| 324 | - This function adds one source model to the observations container. | ||
| 325 | - | ||
| 326 | - Parameters: | ||
| 327 | - obs - Observations container | ||
| 328 | - source - Source to be added to container | ||
| 329 | - """ | ||
| 330 | - # Append source to model container | ||
| 331 | - models.append(source) | ||
| 332 | - | ||
| 333 | - # Return model container | ||
| 334 | - return models | ||
| 335 | - | ||
| 336 | - | ||
| 337 | -# ======================================== # | ||
| 338 | -# Add CTA background model to observations # | ||
| 339 | -# ======================================== # | ||
| 340 | -def add_background_model(models): | ||
| 341 | - """ | ||
| 342 | - Add standard CTA background model to observations container. | ||
| 343 | - We use a simple power law here, scaled to Konrad's E configuration | ||
| 344 | - performance table. | ||
| 345 | - | ||
| 346 | - Parameters: | ||
| 347 | - obs - Observation container | ||
| 348 | - """ | ||
| 349 | - # Define background model | ||
| 350 | - bgd_radial = GCTAModelRadialGauss(3.0) | ||
| 351 | - bgd_spectrum = GModelSpectralPlaw(61.8, -1.85) | ||
| 352 | - bgd_spectrum["Prefactor"].scale(1.0e-6) | ||
| 353 | - bgd_spectrum["PivotEnergy"].value(1.0) | ||
| 354 | - bgd_spectrum["PivotEnergy"].scale(1.0e6) | ||
| 355 | - bgd_model = GCTAModelRadialAcceptance(bgd_radial, bgd_spectrum) | ||
| 356 | - bgd_model.name("Background") | ||
| 357 | - bgd_model.instruments("CTA") | ||
| 358 | - | ||
| 359 | - # Add background model to container | ||
| 360 | - models.append(bgd_model) | ||
| 361 | - | ||
| 362 | - # Return model container | ||
| 363 | - return models | ||
| 364 | - | ||
| 365 | - | ||
| 366 | -# ==================== # | ||
| 367 | -# Set Crab-like source # | ||
| 368 | -# ==================== # | ||
| 369 | -def crab_like(name, l, b, flux=1.0, type="point", sigma=1.0, radius=1.0, width=0.1, \ | ||
| 370 | - fitpos=True): | ||
| 371 | - """ | ||
| 372 | - Returns a single source with Crab-like spectrum. The source flux | ||
| 373 | - can be scaled in Crab units. | ||
| 374 | - | ||
| 375 | - Parameters: | ||
| 376 | - name - Unique source name | ||
| 377 | - l - Galactic longitude of source location [deg] | ||
| 378 | - b - Galactic latitude of source location [deg] | ||
| 379 | - Keywords: | ||
| 380 | - flux - Source flux in Crab units | ||
| 381 | - type - Source type ("point", "gauss", "disk", "shell") | ||
| 382 | - sigma - Gaussian sigma (for type="gauss") | ||
| 383 | - radius - Disk or shell inner radius [deg] (for type="disk" and type="shell") | ||
| 384 | - width - Shell width [deg] (for type="shell") | ||
| 385 | - fitpos - Specifies if position should be fitted or not | ||
| 386 | - """ | ||
| 387 | - # Set source location | ||
| 388 | - location = GSkyDir() | ||
| 389 | - location.lb_deg(l, b) | ||
| 390 | - | ||
| 391 | - # Set source spectrum | ||
| 392 | - spectrum = crab_spec(flux=flux) | ||
| 393 | - | ||
| 394 | - # Set source | ||
| 395 | - if type == "point": | ||
| 396 | - spatial = GModelSpatialPtsrc(location) | ||
| 397 | - if fitpos: | ||
| 398 | - spatial[0].free() | ||
| 399 | - spatial[1].free() | ||
| 400 | - source = GModelPointSource(spatial, spectrum) | ||
| 401 | - elif type == "gauss": | ||
| 402 | - radial = GModelRadialGauss(location, sigma) | ||
| 403 | - if fitpos: | ||
| 404 | - radial[0].free() | ||
| 405 | - radial[1].free() | ||
| 406 | - source = GModelExtendedSource(radial, spectrum) | ||
| 407 | - elif type == "disk": | ||
| 408 | - radial = GModelRadialDisk(location, radius) | ||
| 409 | - if fitpos: | ||
| 410 | - radial[0].free() | ||
| 411 | - radial[1].free() | ||
| 412 | - source = GModelExtendedSource(radial, spectrum) | ||
| 413 | - elif type == "shell": | ||
| 414 | - radial = GModelRadialShell(location, radius, width) | ||
| 415 | - if fitpos: | ||
| 416 | - radial[0].free() | ||
| 417 | - radial[1].free() | ||
| 418 | - source = GModelExtendedSource(radial, spectrum) | ||
| 419 | - else: | ||
| 420 | - print "ERROR: Unknown source type '"+type+"'." | ||
| 421 | - return None | ||
| 422 | - | ||
| 423 | - # Set source name | ||
| 424 | - source.name(name) | ||
| 425 | - | ||
| 426 | - # Return source | ||
| 427 | - return source | ||
| 428 | - | ||
| 429 | - | ||
| 430 | -# ================= # | ||
| 431 | -# Set Crab spectrum # | ||
| 432 | -# ================= # | ||
| 433 | -def crab_spec(flux=1.0): | ||
| 434 | - """ | ||
| 435 | - Set Crab spectrum based on MAGIC observations | ||
| 436 | - (Albert et al. 2008, ApJ, 674, 1037) | ||
| 437 | - | ||
| 438 | - Keywords: | ||
| 439 | - flux - Source flux in Crab units | ||
| 440 | - """ | ||
| 441 | - # Set parameters | ||
| 442 | - spectrum = GModelSpectralPlaw(flux, -2.48) | ||
| 443 | - spectrum["Prefactor"].scale(5.7e-16) | ||
| 444 | - spectrum["PivotEnergy"].value(0.3) | ||
| 445 | - spectrum["PivotEnergy"].scale(1.0e6) | ||
| 446 | - | ||
| 447 | - # Return spectrum | ||
| 448 | - return spectrum | ||
| 449 | - | ||
| 450 | - | ||
| 451 | -# ========================= # | ||
| 452 | -# Set any point-like source # | ||
| 453 | -# ========================= # | ||
| 454 | -def any_pointlike(name, l, b, flux=1.0, index=-2.48, fitpos=True, fitidx=True): | ||
| 455 | - """ | ||
| 456 | - Returns a single point-source with power-law spectrum. | ||
| 457 | - The source flux can be scaled in Crab units. | ||
| 458 | - | ||
| 459 | - Parameters: | ||
| 460 | - name - Unique source name | ||
| 461 | - l - Galactic longitude of source location [deg] | ||
| 462 | - b - Galactic latitude of source location [deg] | ||
| 463 | - Keywords: | ||
| 464 | - flux - Source flux in Crab units | ||
| 465 | - fitpos - Specifies if position should be fitted or not | ||
| 466 | - fitidx - Specifies if index should be fitted or not | ||
| 467 | - """ | ||
| 468 | - # Set source location | ||
| 469 | - location = GSkyDir() | ||
| 470 | - location.lb_deg(l, b) | ||
| 471 | - | ||
| 472 | - | ||
| 473 | - # Set source spatial model | ||
| 474 | - spatial = GModelSpatialPtsrc(location) | ||
| 475 | - | ||
| 476 | - # Set source spectral model | ||
| 477 | - spectrum = GModelSpectralPlaw(flux, index) | ||
| 478 | - spectrum["Prefactor"].scale(5.7e-16) | ||
| 479 | - spectrum["PivotEnergy"].value(0.3) | ||
| 480 | - spectrum["PivotEnergy"].scale(1.0e6) | ||
| 481 | - | ||
| 482 | - # Set fit properties | ||
| 483 | - if fitpos: | ||
| 484 | - spatial[0].free() | ||
| 485 | - spatial[1].free() | ||
| 486 | - else: | ||
| 487 | - spatial[0].fix() | ||
| 488 | - spatial[1].fix() | ||
| 489 | - | ||
| 490 | - if fitidx: | ||
| 491 | - spectrum["Index"].free() | ||
| 492 | - else: | ||
| 493 | - spectrum["Index"].fix() | ||
| 494 | - | ||
| 495 | - # Assign spatial and spectral models to source object | ||
| 496 | - source = GModelPointSource(spatial, spectrum) | ||
| 497 | - | ||
| 498 | - # Set source name | ||
| 499 | - source.name(name) | ||
| 500 | - | ||
| 501 | - # Return source | ||
| 502 | - return source | ||
| 503 | - | ||
| 504 | - | ||
| 505 | -# =============================== # | ||
| 506 | -# Setup single observation survey # | ||
| 507 | -# =============================== # | ||
| 508 | -def survey_single(caldb, irf, lpnt=0.0, bpnt=0.0): | ||
| 509 | - """ | ||
| 510 | - This is an example of how to create a pointing strategy. Here, we | ||
| 511 | - only have a single CTA pointing, so this is a very basic pointing | ||
| 512 | - strategy. | ||
| 513 | - | ||
| 514 | - Parameters: | ||
| 515 | - caldb - Calibration database | ||
| 516 | - irf - Response function | ||
| 517 | - lpnt - Galactic longitude of pointing [deg] | ||
| 518 | - bpnt - Galactic latitude of pointing [deg] | ||
| 519 | - """ | ||
| 520 | - # Allocate observation container | ||
| 521 | - obs = GObservations() | ||
| 522 | - | ||
| 523 | - # Set single pointing at galactic centre | ||
| 524 | - pntdir = GSkyDir() | ||
| 525 | - pntdir.lb_deg(lpnt, bpnt) | ||
| 526 | - run = set_one_obs(pntdir, caldb=caldb, irf=irf) | ||
| 527 | - obs.append(run) | ||
| 528 | - | ||
| 529 | - # Return observation container | ||
| 530 | - return obs | ||
| 531 | - | ||
| 532 | - | ||
| 533 | -# =========================== # | ||
| 534 | -# Setup Galactic plane survey # | ||
| 535 | -# =========================== # | ||
| 536 | -def survey_gplane(caldb, irf, bpnt=0.0, lrange=10, lstep=2): | ||
| 537 | - """ | ||
| 538 | - Creates a single observation survey for test purposes. | ||
| 539 | - | ||
| 540 | - Keywords: | ||
| 541 | - bpnt - Latitude value for scan [deg] | ||
| 542 | - lrange - Longitude range (integer deg) | ||
| 543 | - lstep - Longitude step size (integer deg) | ||
| 544 | - """ | ||
| 545 | - # Allocate observation container | ||
| 546 | - obs = GObservations() | ||
| 547 | - | ||
| 548 | - # Loop over longitudes | ||
| 549 | - for l in range(-lrange,lrange+lstep,lstep): | ||
| 550 | - | ||
| 551 | - # Set pointing | ||
| 552 | - pntdir = GSkyDir() | ||
| 553 | - pntdir.lb_deg(l, bpnt) | ||
| 554 | - run = set_one_obs(pntdir, caldb=caldb, irf=irf) | ||
| 555 | - obs.append(run) | ||
| 556 | - | ||
| 557 | - # Return observation container | ||
| 558 | - return obs | ||
| 559 | - | ||
| 560 | - | ||
| 561 | -# =========================== # | ||
| 562 | -# Setup Galactic plane survey # | ||
| 563 | -# =========================== # | ||
| 564 | -def survey_square(caldb, irf, lrange=2.0, lstep=2.0, duration=1800.0, \ | ||
| 565 | - emin=0.1, emax=100.0): | ||
| 566 | - """ | ||
| 567 | - Creates a single observation survey over a square grid. | ||
| 568 | - For the moment, the grid is centred on (l,b)=(0,0) | ||
| 569 | - | ||
| 570 | - Arguments: | ||
| 571 | - lrange - Longitude/latitude range (float deg) | ||
| 572 | - lstep - Longitude/latitude step size (float deg) | ||
| 573 | - duration/emin/emax - See set_one_obs function | ||
| 574 | - """ | ||
| 575 | - # Allocate observation container | ||
| 576 | - obs = GObservations() | ||
| 577 | - | ||
| 578 | - # Compute number of points along each axis | ||
| 579 | - num_pnt= int(round(2.0*lrange/lstep)+1.0) | ||
| 580 | - | ||
| 581 | - # Loop over longitudes and latitudes | ||
| 582 | - for i in range(0,num_pnt): | ||
| 583 | - for j in range(0,num_pnt): | ||
| 584 | - | ||
| 585 | - # Set pointing | ||
| 586 | - l= -lrange+i*lstep | ||
| 587 | - b= -lrange+j*lstep | ||
| 588 | - pntdir = GSkyDir() | ||
| 589 | - pntdir.lb_deg(l, b) | ||
| 590 | - run = set_one_obs(pntdir, caldb=caldb, irf=irf, duration=duration, \ | ||
| 591 | - emin=emin, emax=emax) | ||
| 592 | - obs.append(run) | ||
| 593 | - | ||
| 594 | - # Return observation container | ||
| 595 | - return obs | ||
| 596 | - | ||
| 597 | - | ||
| 598 | -# =========================== # | ||
| 599 | -# Setup Galactic plane survey # | ||
| 600 | -# =========================== # | ||
| 601 | -def survey_galplane(caldb, irf, lmin=-2.0, lstep=2.0, nstep=3, duration=1800.0, \ | ||
| 602 | - emin=0.1, emax=100.0): | ||
| 603 | - """ | ||
| 604 | - Creates a single observation survey along the galactic plane | ||
| 605 | - | ||
| 606 | - Arguments: | ||
| 607 | - lmin - Starting longitude(float deg) | ||
| 608 | - lstep - Longitude step size (float deg) | ||
| 609 | - nstep - Number of steps/pointings | ||
| 610 | - duration/emin/emax - See set_one_obs function | ||
| 611 | - """ | ||
| 612 | - # Allocate observation container | ||
| 613 | - obs = GObservations() | ||
| 614 | - | ||
| 615 | - # Loop over longitudes | ||
| 616 | - for i in range(0,nstep): | ||
| 617 | - | ||
| 618 | - # Set pointing | ||
| 619 | - l= lmin+i*lstep | ||
| 620 | - b= 0.0 | ||
| 621 | - pntdir = GSkyDir() | ||
| 622 | - pntdir.lb_deg(l, b) | ||
| 623 | - run = set_one_obs(pntdir, caldb=caldb, irf=irf, duration=duration, \ | ||
| 624 | - emin=emin, emax=emax) | ||
| 625 | - obs.append(run) | ||
| 626 | - | ||
| 627 | - # Return observation container | ||
| 628 | - return obs | ||
| 629 | - | ||
| 630 | -# ===================================== # | ||
| 631 | -# Setup set of point source Crab models # | ||
| 632 | -# ===================================== # | ||
| 633 | -def add_point_sources(obs): | ||
| 634 | - """ | ||
| 635 | - Add point-source model made of Crab-like sources. | ||
| 636 | - """ | ||
| 637 | - # Add point-source Crabs | ||
| 638 | - obs = add_source_model(obs, crab_like("Crab", 0.0, 0.0)) | ||
| 639 | - obs = add_source_model(obs, crab_like("Crab 1deg off", 1.0, 0.0)) | ||
| 640 | - obs = add_source_model(obs, crab_like("Crab 2deg off", 2.0, 0.0)) | ||
| 641 | - obs = add_source_model(obs, crab_like("Crab 3deg off", 3.0, 0.0)) | ||
| 642 | - obs = add_source_model(obs, crab_like("Crab 4deg off", 4.0, 0.0)) | ||
| 643 | - obs = add_source_model(obs, crab_like("Crab 5deg off", 5.0, 0.0)) | ||
| 644 | - | ||
| 645 | - # Return | ||
| 646 | - return obs | ||
| 647 | - | ||
| 648 | - | ||
| 649 | -# ================= # | ||
| 650 | -# Setup disk models # | ||
| 651 | -# ================= # | ||
| 652 | -def add_disk_sources(obs): | ||
| 653 | - """ | ||
| 654 | - Add disk-source model made of Crab-like sources. | ||
| 655 | - """ | ||
| 656 | - # Add disk Crabs | ||
| 657 | - obs = add_source_model(obs, crab_like("Disk 0deg off", 0.0, 0.0, type="disk", radius=0.3)) | ||
| 658 | - obs = add_source_model(obs, crab_like("Disk 1deg off", -1.0, 0.0, type="disk", radius=0.3)) | ||
| 659 | - obs = add_source_model(obs, crab_like("Disk 2deg off", -2.0, 0.0, type="disk", radius=0.3)) | ||
| 660 | - obs = add_source_model(obs, crab_like("Disk 3deg off", -3.0, 0.0, type="disk", radius=0.3)) | ||
| 661 | - #obs = add_source_model(obs, crab_like("Disk 4deg off", -4.0, 0.0, type="disk", radius=0.3)) | ||
| 662 | - #obs = add_source_model(obs, crab_like("Disk 5deg off", -5.0, 0.0, type="disk", radius=0.3)) | ||
| 663 | - | ||
| 664 | - # Return | ||
| 665 | - return obs | ||
| 666 | - | ||
| 667 | - | ||
| 668 | -# ================== # | ||
| 669 | -# Setup Gauss models # | ||
| 670 | -# ================== # | ||
| 671 | -def add_gauss_sources(obs): | ||
| 672 | - """ | ||
| 673 | - Add Gauss-source model made of Crab-like sources. | ||
| 674 | - """ | ||
| 675 | - # Add Gauss Crabs | ||
| 676 | - obs = add_source_model(obs, crab_like("Gauss 0deg off", 0.0, 0.0, type="gauss", sigma=0.3)) | ||
| 677 | - obs = add_source_model(obs, crab_like("Gauss 1deg off", -1.0, 0.0, type="gauss", sigma=0.3)) | ||
| 678 | - obs = add_source_model(obs, crab_like("Gauss 2deg off", -2.0, 0.0, type="gauss", sigma=0.3)) | ||
| 679 | - obs = add_source_model(obs, crab_like("Gauss 3deg off", -3.0, 0.0, type="gauss", sigma=0.3)) | ||
| 680 | - #obs = add_source_model(obs, crab_like("Gauss 4deg off", -4.0, 0.0, type="gauss", sigma=0.3)) | ||
| 681 | - #obs = add_source_model(obs, crab_like("Gauss 5deg off", -5.0, 0.0, type="gauss", sigma=0.3)) | ||
| 682 | - | ||
| 683 | - # Return | ||
| 684 | - return obs | ||
| 685 | - | ||
| 686 | - | ||
| 687 | -# ================== # | ||
| 688 | -# Setup Shell models # | ||
| 689 | -# ================== # | ||
| 690 | -def add_shell_sources(obs): | ||
| 691 | - """ | ||
| 692 | - Add shell-source model made of Crab-like sources. | ||
| 693 | - """ | ||
| 694 | - # Add Shell Crabs | ||
| 695 | - obs = add_source_model(obs, crab_like("Shell 0deg off", 0.0, 0.0, type="shell", radius=0.3, width=0.1)) | ||
| 696 | - obs = add_source_model(obs, crab_like("Shell 1deg off", -1.0, 0.0, type="shell", radius=0.3, width=0.1)) | ||
| 697 | - obs = add_source_model(obs, crab_like("Shell 2deg off", -2.0, 0.0, type="shell", radius=0.3, width=0.1)) | ||
| 698 | - #obs = add_source_model(obs, crab_like("Shell 3deg off", -3.0, 0.0, type="shell", radius=0.3, width=0.1)) | ||
| 699 | - #obs = add_source_model(obs, crab_like("Shell 4deg off", -4.0, 0.0, type="shell", radius=0.3, width=0.1)) | ||
| 700 | - #obs = add_source_model(obs, crab_like("Shell 5deg off", -5.0, 0.0, type="shell", radius=0.3, width=0.1)) | ||
| 701 | - | ||
| 702 | - # Return | ||
| 703 | - return obs | ||
| 704 | - | ||
| 705 | - | ||
| 706 | -# ==================== # | ||
| 707 | -# Setup big disk model # | ||
| 708 | -# ==================== # | ||
| 709 | -def add_big_disk_source(obs): | ||
| 710 | - """ | ||
| 711 | - Add big disk-source model. | ||
| 712 | - """ | ||
| 713 | - # Add one big offset disk Crab | ||
| 714 | - obs = add_source_model(obs, crab_like("Big Disk", 1.0, 1.0, type="disk", radius=1.0)) | ||
| 715 | - | ||
| 716 | - # Return | ||
| 717 | - return obs | ||
| 718 | - | ||
| 719 | - | ||
| 720 | -# ===================== # | ||
| 721 | -# Setup big Gauss model # | ||
| 722 | -# ===================== # | ||
| 723 | -def add_big_gauss_source(obs): | ||
| 724 | - """ | ||
| 725 | - Add big gauss-source model. | ||
| 726 | - """ | ||
| 727 | - # Add one big offset Gauss Crab | ||
| 728 | - obs = add_source_model(obs, crab_like("Big Gauss", -1.0, 1.0, type="gauss", sigma=1.0)) | ||
| 729 | - | ||
| 730 | - # Return | ||
| 731 | - return obs | ||
| 732 | - | ||
| 733 | - | ||
| 734 | -# ===================== # | ||
| 735 | -# Setup big shell model # | ||
| 736 | -# ===================== # | ||
| 737 | -def add_big_shell_source(obs): | ||
| 738 | - """ | ||
| 739 | - Add big shell-source model. | ||
| 740 | - """ | ||
| 741 | - # Add one big offset Shell Crab | ||
| 742 | - obs = add_source_model(obs, crab_like("Big Shell", -1.0, -1.0, type="shell", radius=1.0, width=0.1)) | ||
| 743 | - | ||
| 744 | - # Return | ||
| 745 | - return obs | ||
| 746 | - | ||
| 747 | - | ||
| 748 | -# ================================================= # | ||
| 749 | -# Setup set of point source for the survey analysis # | ||
| 750 | -# ================================================= # | ||
| 751 | -def add_survey_sources(obs): | ||
| 752 | - """ | ||
| 753 | - Add point-source model made of Crab-like sources. | ||
| 754 | - """ | ||
| 755 | - # Add point-source Crabs | ||
| 756 | - obs = add_source_model(obs, crab_like("Source 1", 0.0, 0.0, flux=0.1, type="point")) | ||
| 757 | - obs = add_source_model(obs, crab_like("Source 2", 1.0, 0.0, flux=0.2, type="point")) | ||
| 758 | - obs = add_source_model(obs, crab_like("Source 3", -1.0, 0.0, flux=0.5, type="point")) | ||
| 759 | - obs = add_source_model(obs, crab_like("Source 4", 0.0, 1.0, flux=1.0, type="point")) | ||
| 760 | - obs = add_source_model(obs, crab_like("Source 5", 0.0, -1.0, flux=2.0, type="point")) | ||
| 761 | - obs = add_source_model(obs, crab_like("Source 6", 0.0, 4.0, flux=5.0, type="point")) | ||
| 762 | - | ||
| 763 | - # Return | ||
| 764 | - return obs | ||
| 765 | - | ||
| 766 | - | ||
| 767 | -# ================================================= # | ||
| 768 | -# Setup set of point source for the survey analysis # | ||
| 769 | -# ================================================= # | ||
| 770 | -def add_random_sources(model): | ||
| 771 | - """ | ||
| 772 | - Add point-sources uniformly distributed over the sky, with a parameterised distribution in flux. | ||
| 773 | - | ||
| 774 | - Arguments | ||
| 775 | - - model: a source model container to hold the source model over the loop | ||
| 776 | - | ||
| 777 | - Notes | ||
| 778 | - - Contrary to other add_source functions, this one works on a model container and not on an observation container | ||
| 779 | - - This is because we need to reuse the same random source model in a loop over pointing strategies | ||
| 780 | - """ | ||
| 781 | - # Define source population characteristics | ||
| 782 | - flux_min=0.001 | ||
| 783 | - flux_max=10.0 | ||
| 784 | - flux_index=-2.0 | ||
| 785 | - field=4.0 | ||
| 786 | - l_min=0.0-0.5*field | ||
| 787 | - b_min=0.0-0.5*field | ||
| 788 | - num_sources=4 | ||
| 789 | - | ||
| 790 | - # Loop over sources to be generated | ||
| 791 | - for i in range(0,num_sources): | ||
| 792 | - | ||
| 793 | - # Get random flux | ||
| 794 | - flux=math.log10(flux_min)+(math.log10(flux_max)-math.log10(flux_min))*random.random() | ||
| 795 | - flux=math.pow(10.0,flux) | ||
| 796 | - | ||
| 797 | - # Get random longitude/latitude | ||
| 798 | - l=l_min+field*random.random() | ||
| 799 | - b=b_min+field*random.random() | ||
| 800 | - | ||
| 801 | - # Add point-source Crabs | ||
| 802 | - sourcename="Source "+str(i) | ||
| 803 | - model.append(crab_like(sourcename, l, b, flux=flux, type="point")) | ||
| 804 | - | ||
| 805 | - # Return | ||
| 806 | - return model | ||
| 807 | - | ||
| 808 | - | ||
| 809 | -# ================================================= # | ||
| 810 | -# Setup a test point source for the survey analysis # | ||
| 811 | -# ================================================= # | ||
| 812 | -def add_test_sources(models, l=0.0, b=0.0, flux=1.0, index=-2.5): | ||
| 813 | - """ | ||
| 814 | - Add a test point-source with specified position, flux, and spectral index | ||
| 815 | - | ||
| 816 | - Arguments | ||
| 817 | - - l: longitude | ||
| 818 | - - b: latitude | ||
| 819 | - - flux: flux in Crab units | ||
| 820 | - - index: spectral index | ||
| 821 | - """ | ||
| 822 | - | ||
| 823 | - # Set source name | ||
| 824 | - sourcename="Test" | ||
| 825 | - | ||
| 826 | - # Add it to container | ||
| 827 | - models = add_source_model(models, any_pointlike(sourcename, l, b, \ | ||
| 828 | - flux=flux, index=index, fitpos=False, fitidx=False)) | ||
| 829 | - | ||
| 830 | - # Return | ||
| 831 | - return models | ||
| 832 | - | ||
| 833 | - | ||
| 834 | -#==============================# | ||
| 835 | -# Modified routine entry point # | ||
| 836 | -#==============================# | ||
| 837 | -if __name__ == '__main__': | ||
| 838 | - """ | ||
| 839 | - CTA survey simulation and analysis script. | ||
| 840 | - | ||
| 841 | - Notes: | ||
| 842 | - - Based on the initial script | ||
| 843 | - - Added functions: survey_square, add_survey_sources, add_random_sources | ||
| 844 | - - Added import: math, random | ||
| 845 | - | ||
| 846 | - """ | ||
| 847 | - # Set job parameters | ||
| 848 | - irf = "kb_E_50h_v3" # IRF | ||
| 849 | - survey_time = 50.0*3600.0 # Total survey time | ||
| 850 | - pnt_step = 1.0 # Spacing between pointings | ||
| 851 | - pnt_mintime = 3600.0 # Minimum duration of a pointing | ||
| 852 | - pnt_fov = 1.0 # Typical FoV size (useful to know where to probe sensitivity) | ||
| 853 | - pnt_maxnum = 1 # Maximum number of pointings | ||
| 854 | - emin = 0.1 # minimum energy (TeV) | ||
| 855 | - emax = 100.0 # maximum energy (TeV) | ||
| 856 | - #emin = 1.0 # minimum energy (TeV) | ||
| 857 | - #emax = 5.0 # maximum energy (TeV) | ||
| 858 | - nbins = 20 # number of logarithmic energy bins | ||
| 859 | - test_thres = 25.0 # Reference TS | ||
| 860 | - index = -3.0 # Spectral index | ||
| 861 | - | ||
| 862 | - # Initialise response database | ||
| 863 | - caldb = "/usr/local/gamma/share/caldb/cta" | ||
| 864 | - | ||
| 865 | - # Initialise flags | ||
| 866 | - need_help = False | ||
| 867 | - | ||
| 868 | - # Test for command line arguments | ||
| 869 | - if (len(sys.argv) > 1): | ||
| 870 | - surveyrange= float(sys.argv[1]) | ||
| 871 | - | ||
| 872 | - if (len(sys.argv) > 2): | ||
| 873 | - surveystep= float(sys.argv[2]) | ||
| 874 | - | ||
| 875 | - if (len(sys.argv) > 3): | ||
| 876 | - irf=sys.argv[3] | ||
| 877 | - | ||
| 878 | - # Print help if needed and exit | ||
| 879 | - if need_help: | ||
| 880 | - print "Usage: example_survey.py [OPTIONS]" | ||
| 881 | - print " galscan Simulate Galactic plane scan" | ||
| 882 | - print " extended Simulate also extended sources" | ||
| 883 | - print " -h Display this usage message" | ||
| 884 | - sys.exit() | ||
| 885 | - | ||
| 886 | - # Dump header | ||
| 887 | - print "***********************" | ||
| 888 | - print "* Simulate CTA survey *" | ||
| 889 | - print "***********************" | ||
| 890 | - | ||
| 891 | - # Remove any existing result files | ||
| 892 | - list = [glob.glob("*.fits"), glob.glob("*.log"), glob.glob("*.xml")] | ||
| 893 | - for files in list: | ||
| 894 | - for file in files: | ||
| 895 | - os.remove(file) | ||
| 896 | - | ||
| 897 | - # Set number of observations | ||
| 898 | - first = True | ||
| 899 | - results_file = 'sensitivity.dat' | ||
| 900 | - for i in range(1,pnt_maxnum+1): | ||
| 901 | - | ||
| 902 | - # Initialise models | ||
| 903 | - bkg_model = GModels() | ||
| 904 | - full_model = GModels() | ||
| 905 | - | ||
| 906 | - # Setup models | ||
| 907 | - bkg_model = add_background_model(bkg_model) | ||
| 908 | - full_model = add_background_model(full_model) | ||
| 909 | - full_model = add_test_sources(full_model, 0.0, 0.0, flux=1.0, index=index) | ||
| 910 | - | ||
| 911 | - # Compute duration of pointings and starting longitude | ||
| 912 | - pnt_duration = survey_time/float(i) | ||
| 913 | - pnt_lmin = 0.0-float(i-1)*pnt_step/2.0 | ||
| 914 | - | ||
| 915 | - # Setup observations for survey | ||
| 916 | - survey = survey_galplane(caldb, irf, lmin=pnt_lmin, lstep=pnt_step, \ | ||
| 917 | - nstep=i, duration=pnt_duration, \ | ||
| 918 | - emin=emin, emax=emax) | ||
| 919 | - | ||
| 920 | - print "" | ||
| 921 | - print "Simulating an array of "+str(i)+" observations along the plane" | ||
| 922 | - | ||
| 923 | - # Look for smallest flux for detection | ||
| 924 | - test_num = 0 | ||
| 925 | - test_max = 50 | ||
| 926 | - test_flux = 0.001 | ||
| 927 | - | ||
| 928 | - # Loop | ||
| 929 | - flux_value = [] | ||
| 930 | - while True: | ||
| 931 | - | ||
| 932 | - # Update test counter | ||
| 933 | - test_num = test_num + 1 | ||
| 934 | - | ||
| 935 | - # Set test flux | ||
| 936 | - full_model[1]['Prefactor'].value(test_flux) | ||
| 937 | - survey.models(full_model) | ||
| 938 | - | ||
| 939 | - # Simulate events | ||
| 940 | - obs = sim_obs(survey, nbins=nbins, seed=test_num) | ||
| 941 | - | ||
| 942 | - # Determine number of events in simulation | ||
| 943 | - nevents = 0.0 | ||
| 944 | - for x in obs: | ||
| 945 | - nevents += x.events().number() | ||
| 946 | - | ||
| 947 | - # Fit background only | ||
| 948 | - obs.models(bkg_model) | ||
| 949 | - like = fit_obs(obs,log=False) | ||
| 950 | - | ||
| 951 | - # Store results | ||
| 952 | - LogL_bgm = like.opt().value() | ||
| 953 | - Pre_bgm = like.obs().models()[0]['Prefactor'].value() | ||
| 954 | - ePre_bgm = like.obs().models()[0]['Prefactor'].error() | ||
| 955 | - Inx_bgm = like.obs().models()[0]['Index'].value() | ||
| 956 | - eInx_bgm = like.obs().models()[0]['Index'].error() | ||
| 957 | - npred_bgm = like.obs().npred() | ||
| 958 | - | ||
| 959 | - # Fit background and test source | ||
| 960 | - obs.models(full_model) | ||
| 961 | - like = fit_obs(obs,log=False) | ||
| 962 | - | ||
| 963 | - # Store results | ||
| 964 | - LogL_all = like.opt().value() | ||
| 965 | - test_ts = 2.0*(LogL_bgm-LogL_all) | ||
| 966 | - Pre_all = like.obs().models()[0]['Prefactor'].value() | ||
| 967 | - ePre_all = like.obs().models()[0]['Prefactor'].error() | ||
| 968 | - Inx_all = like.obs().models()[0]['Index'].value() | ||
| 969 | - eInx_all = like.obs().models()[0]['Index'].error() | ||
| 970 | - SPre_all = like.obs().models()[1]['Prefactor'].value() | ||
| 971 | - eSPre_all = like.obs().models()[1]['Prefactor'].error() | ||
| 972 | - SInx_all = like.obs().models()[1]['Index'].value() | ||
| 973 | - eSInx_all = like.obs().models()[1]['Index'].error() | ||
| 974 | - npred_all = like.obs().npred() | ||
| 975 | - if test_ts > 0: | ||
| 976 | - flux = math.sqrt(test_thres/test_ts)*SPre_all | ||
| 977 | - else: | ||
| 978 | - flux = 0.0 | ||
| 979 | - flux_value.append(flux) | ||
| 980 | - | ||
| 981 | - # Compute sliding average | ||
| 982 | - flux = 0.0 | ||
| 983 | - num = 0.0 | ||
| 984 | - for k in range(3): | ||
| 985 | - inx = test_num - k - 1 | ||
| 986 | - if inx >= 0: | ||
| 987 | - flux += flux_value[inx] | ||
| 988 | - num += 1.0 | ||
| 989 | - flux /= num | ||
| 990 | - | ||
| 991 | - # Print results | ||
| 992 | - print "TS=%9.2f %8.5f lnL(BGD)=%8.1f lnL(ALL)=%8.1f #%5d" \ | ||
| 993 | - " BGD: #%8.2f %5.2f+/-%4.2f %5.2f+/-%5.3f" \ | ||
| 994 | - " ALL: #%8.2f %5.2f+/-%4.2f %5.2f+/-%5.3f" \ | ||
| 995 | - " %8.5f+/-%7.5f %5.2f+/-%5.3f Flux=%8.5f" % \ | ||
| 996 | - (test_ts, test_flux, LogL_bgm, LogL_all, nevents, \ | ||
| 997 | - npred_bgm, Pre_bgm, ePre_bgm, Inx_bgm, eInx_bgm, \ | ||
| 998 | - npred_all, Pre_all, ePre_all, Inx_all, eInx_all, \ | ||
| 999 | - SPre_all, eSPre_all, SInx_all, eSInx_all, \ | ||
| 1000 | - flux) | ||
| 1001 | - | ||
| 1002 | - # Compare average flux to last average | ||
| 1003 | - if test_num > 3: | ||
| 1004 | - ratio = flux/test_flux | ||
| 1005 | - if ratio >= 0.99 and ratio <= 1.01: | ||
| 1006 | - print "Converged ("+str(ratio)+")" | ||
| 1007 | - break | ||
| 1008 | - | ||
| 1009 | - # Use average for next iteration | ||
| 1010 | - test_flux = flux | ||
| 1011 | - | ||
| 1012 | - # Exit loop if number of trials exhausted | ||
| 1013 | - if (test_num >= test_max): | ||
| 1014 | - print "Test ended after "+str(test_max)+" iterations." | ||
| 1015 | - break | ||
| 1016 | - | ||
| 1017 | - # Print results | ||
| 1018 | - print "Sensitivity of "+str(i)+" observations: "+str(flux*1000.0)+" mCrab" | ||
| 1019 | - | ||
| 1020 | - # Write to CSV file | ||
| 1021 | - result = {} | ||
| 1022 | - colnames = ['emin', 'emax', 'observations', 'sensitivity'] | ||
| 1023 | - result['emin'] = emin | ||
| 1024 | - result['emax'] = emax | ||
| 1025 | - result['observations'] = i | ||
| 1026 | - result['sensitivity'] = flux | ||
| 1027 | - if first: | ||
| 1028 | - f = open(results_file, 'w') | ||
| 1029 | - writer = csv.DictWriter(f, colnames) | ||
| 1030 | - writer.writerow(dict((_,_) for _ in colnames)) | ||
| 1031 | - first = False | ||
| 1032 | - else: | ||
| 1033 | - f = open(results_file, 'a') | ||
| 1034 | - writer = csv.DictWriter(f, colnames) | ||
| 1035 | - writer.writerow(result) | ||
| 1036 | - f.close() | ||
| 1037 | - | ||
| 1038 | - # Delete some objects | ||
| 1039 | - del obs | ||
| 1040 | - del like | ||
| 1041 | - | ||
| 1042 | - |