pull_OnOff.py

Martin Pierrick, 03/11/2016 05:57 PM

Download (23.9 KB)

 
1
#! /Applications/Anaconda/bin/python
2
# ====================================================================
3
# This script tests the ON-OFF analysis functionality of the gammalib
4
# ====================================================================
5

    
6
from ctools import *
7
from gammalib import *
8
from math import *
9

    
10
import os
11
import glob
12
import sys
13

    
14
import numpy as np
15

    
16
import matplotlib.pyplot as plt
17
import matplotlib.cm as cm
18
import matplotlib.patches as ptch
19

    
20
# ======================== #
21
# Setup single observation #
22
# ======================== #
23
def single_obs(pntdir, tstart=0.0, duration=1800.0, deadc=0.95, \
24
            emin=0.1, emax=100.0, rad=5.0, \
25
            irf="South_50h", caldb="prod2", id="000000", instrument="CTA"):
26
    """
27
    Returns a single CTA observation.
28

29
    Parameters:
30
     pntdir   - Pointing direction [GSkyDir]
31
    Keywords:
32
     tstart     - Start time [seconds] (default: 0.0)
33
     duration   - Duration of observation [seconds] (default: 1800.0)
34
     deadc      - Deadtime correction factor (default: 0.95)
35
     emin       - Minimum event energy [TeV] (default: 0.1)
36
     emax       - Maximum event energy [TeV] (default: 100.0)
37
     rad        - ROI radius used for analysis [deg] (default: 5.0)
38
     irf        - Instrument response function (default: cta_dummy_irf)
39
     caldb      - Calibration database path (default: "dummy")
40
     id         - Run identifier (default: "000000")
41
     instrument - Intrument (default: "CTA")
42
    """
43
    # Allocate CTA observation
44
    obs_cta = GCTAObservation(instrument)
45

    
46
    # Set calibration database
47
    db = GCaldb()
48
    if (os.path.isdir(caldb)):
49
        db.rootdir(caldb)
50
    else:
51
        db.open("cta", caldb)
52

    
53
    # Set pointing direction
54
    pnt = GCTAPointing()
55
    pnt.dir(pntdir)
56
    obs_cta.pointing(pnt)
57

    
58
    # Set ROI
59
    roi     = GCTARoi()
60
    instdir = GCTAInstDir()
61
    instdir.dir(pntdir)
62
    roi.centre(instdir)
63
    roi.radius(rad)
64

    
65
    # Set GTI
66
    gti = GGti()
67
    gti.append(GTime(tstart), GTime(tstart+duration))
68

    
69
    # Set energy boundaries
70
    ebounds = GEbounds(GEnergy(emin, "TeV"), \
71
                                GEnergy(emax, "TeV"))
72

    
73
    # Allocate event list
74
    events = GCTAEventList()
75
    events.roi(roi)
76
    events.gti(gti)
77
    events.ebounds(ebounds)
78
    obs_cta.events(events)
79

    
80
    # Set instrument response
81
    obs_cta.response(irf, db)
82

    
83
    # Set ontime, livetime, and deadtime correction factor
84
    obs_cta.ontime(duration)
85
    obs_cta.livetime(duration*deadc)
86
    obs_cta.deadc(deadc)
87
    obs_cta.id(id)
88

    
89
    # Return CTA observation
90
    return obs_cta
91

    
92

    
93
# ======================================== #
94
# Add CTA background model to observations #
95
# ======================================== #
96
def add_background_model(models,name="Background",instru="CTA",id="",bgd_file="",bgd_sigma=0.0):
97
    
98
    """
99
    Add CTA background model to a model container.
100

101
    Parameters:
102
     models - a model container
103
     bgd_file - file function for background spectral dependence
104
     bgd_sigma - sigma parameter for the gaussian offset angle dependence of the background rate
105
    """
106
    
107
    # Gaussian radial dependence model
108
    if bgd_sigma > 0.0:
109
        
110
        # Spatial part
111
        bgd_radial = GCTAModelRadialGauss(bgd_sigma)
112
    
113
        # Spectral part
114
        if len(bgd_file) > 0:
115
            bgd_spectrum = GModelSpectralFunc(bgd_file,1.0)
116
        else:
117
            pivot_nrj=GEnergy(1.0e6, "MeV")
118
            bgd_spectrum = GModelSpectralPlaw(1.0e-6, -2.0, pivot_nrj)
119
            bgd_spectrum["Prefactor"].value(61.8e-6)
120
            bgd_spectrum["Prefactor"].scale(1.0e-6)
121
            bgd_spectrum["PivotEnergy"].value(1.0)
122
            bgd_spectrum["PivotEnergy"].scale(1.0e6)
123
            bgd_spectrum["Index"].value(-1.85)
124
            bgd_spectrum["Index"].scale(1.0)
125
    
126
            # Full model
127
            bgd_model = GCTAModelRadialAcceptance(bgd_radial, bgd_spectrum)
128
    
129
    # IRF-defined model
130
    else:
131
        
132
            # Spectral model
133
            pivot_nrj=GEnergy(1.0e6, "MeV")
134
            bgd_spectrum = GModelSpectralPlaw(1.0e-6, -2.0, pivot_nrj)
135
            bgd_spectrum["Prefactor"].value(1.0)
136
            bgd_spectrum["Prefactor"].scale(1.0)
137
            bgd_spectrum["PivotEnergy"].value(1.0)
138
            bgd_spectrum["PivotEnergy"].scale(1.0e6)
139
            bgd_spectrum["Index"].value(0.0)
140
            bgd_spectrum["Index"].scale(1.0)
141
            
142
            # Full model
143
            bgd_model = GCTAModelIrfBackground(bgd_spectrum)
144
    
145
    # Set other background properties
146
    if (len(name) > 0):
147
        bgd_model.name(name)
148
    else:
149
        bgd_model.name("Background")
150
    if (len(instru) > 0):
151
        bgd_model.instruments(instru)
152
    else:
153
        bgd_model.instruments("CTA")
154
    if (len(id) > 0):
155
        bgd_model.ids(id)
156
    
157
    # By default, set model to be fitted
158
    if (len(bgd_file) > 0):
159
        bgd_model['Normalization'].free()
160
    else:
161
        bgd_model['Prefactor'].free()
162
        bgd_model['Index'].free()
163
    
164
    # Add background model to container
165
    models.append(bgd_model)
166
    
167
    # Return model container
168
    return models
169

    
170

    
171
# =========================== #
172
# Set any general type source #
173
# =========================== #
174
def add_source_model(models, name, ra, dec, coord='CEL', \
175
                     skymap='', specfile='', \
176
                     flux=5.7e-16, index=-2.5, pivot=3.0e5, \
177
                     type="point", sigma=1.0, radius=1.0, width=0.1, \
178
                     nnode=0, emin=1.0, emax=10.0, \
179
                     pivot_scale=1e6, flux_scale=1.0e-16):
180
    """
181
    Adds a single point-source with power-law spectrum to a model container.
182
    The default is crab-like.
183

184
    Parameters:
185
     models - a model container
186
     name   - Unique source name
187
     ra     - RA of source location [deg]
188
     dec    - Declination of source location [deg]
189
    Keywords:
190
     flux   - Source flux density in 1.0e-16 ph/cm2/s/MeV
191
     index  - Source spectral index
192
     pivot  - Pivot energy in TeV
193
     type   - Source spatial model
194
     sigma/radius/width  - Spatial model parameters
195
     nnode  - Number of nodes (if > 0, spectral model is a node function)
196
    """
197
    
198
    # Set source spectral model
199
    if (nnode > 0) and (emin != emax):
200
        spectrum = GModelSpectralNodes()
201
        dloge=log10(emax/emin)/nnode
202
        logemin=math.log10(emin)
203
        spectrum.reserve(nnode)
204
        for i in range(nnode):
205
                    enode = GEnergy()
206
                    enode.TeV(10.0**(logemin+(i+0.5)*dloge))
207
                    inode=flux*(enode.MeV()/pivot)**(index)
208
                    spectrum.append(enode, inode)
209
                    spectrum[i*2].scale(pivot_scale)
210
                    spectrum[i*2].fix()
211
                    spectrum[i*2+1].scale(flux_scale)
212
                    spectrum[i*2+1].free()    
213
    # Set source spectral model
214
    elif (len(specfile) > 0):
215
        spectrum = GModelSpectralFunc(specfile)
216
        spectrum["Normalization"].value(1.0)
217
        spectrum["Normalization"].free()
218
    else:
219
        pivot_nrj=GEnergy()
220
        pivot_nrj.TeV(pivot*pivot_scale/1e6)
221
        spectrum = GModelSpectralPlaw(flux, index,pivot_nrj)
222
        spectrum["Prefactor"].scale(flux_scale)
223
        spectrum["Prefactor"].value(flux)
224
        spectrum["Prefactor"].free()
225
        spectrum["PivotEnergy"].scale(pivot_scale)
226
        spectrum["PivotEnergy"].value(pivot)
227
        spectrum["Index"].value(index)
228
        spectrum["Index"].scale(1.0)
229
        spectrum["Index"].free()        
230
        
231
    # Set source spatial model
232
    location = GSkyDir()
233
    if (coord == 'CEL'):
234
        location.radec_deg(ra, dec)
235
    else:
236
        location.lb_deg(ra, dec)    
237
    if (len(skymap) > 0):
238
        spatial = GModelSpatialDiffuseMap(skymap,1.0)
239
        source = GModelSky(spatial, spectrum)
240
        spatial[0].free()
241
    elif type == "point":
242
        spatial = GModelSpatialPointSource(location)
243
        spatial[0].free()
244
        spatial[1].free()
245
        source  = GModelSky(spatial, spectrum)
246
    elif type == "gauss":
247
        radial = GModelSpatialRadialGauss(location, sigma)
248
        radial[0].free()
249
        radial[1].free()
250
        radial[2].free()
251
        source = GModelSky(radial, spectrum)
252
    elif type == "disk":
253
        radial = GModelSpatialRadialDisk(location, radius)
254
        radial[0].free()
255
        radial[1].free()
256
        radial[2].free()
257
        source = GModelSky(radial, spectrum)
258
    elif type == "shell":
259
        radial = GModelSpatialRadialShell(location, radius, width)
260
        radial[0].free()
261
        radial[1].free()
262
        radial[2].free()
263
        radial[3].free()
264
        source = GModelSky(radial, spectrum)
265
    else:
266
        print "ERROR: Unknown source type '"+type+"'."
267
        return None
268
    
269
    # Set source name
270
    source.name(name)
271
    
272
    # Append source model to model container
273
    models.append(source)
274
    
275
    # Return source
276
    return models
277

    
278
# ======================================== #
279
# Set the fit parameters for a given model #
280
# ======================================== #
281
def set_fit_param(model, parname=[], parfit=[], parval=[]):
282
    """
283
    Set the fit parameters for a given model
284
    
285
    Arguments
286
    - model: a model container
287
    - parname: array of parameters names
288
    - parfit: array of fit/fix flags (True=fit,False=fix)
289
    - parval: array of initial/fix parameters values
290
    
291
    Notes
292
    - Arrays should have same numbers of elements
293
    - A way to not set a value but just the fit/fix flag is to pass/leave parval empty
294
    - If among several parameters some values must be set and others not, separate these and call the function two times
295
    """
296

    
297
    # Count/check number of parameters to be set
298
    if (len(parname) != len(parfit)):
299
        print "Incorrect input. Fit parameters not set or modified."
300
        return 0
301
    else:
302
        num_toset=len(parname)
303
                    
304
    # Loop over parameters
305
    for i in range(model.size()):
306
        name=model[i].name()
307
        if (name in parname):
308
            # Get index of matching name
309
            i_par=parname.index(name)
310
            # Set the parameter to be fix/free
311
            if (parfit[i_par]):
312
                model[name].free()
313
            else:
314
                model[name].fix()
315
            # Optionally set the value
316
            if (len(parval) > 0): 
317
                model[name].value(parval[i_par])
318

    
319
    # Exit point
320
    return model
321

    
322

    
323
# ===================== #
324
# Simulate observations #
325
# ===================== #
326
def sim(obs, log=False, debug=False, chatter=2, edisp=False, seed=0, nbins=0,
327
        binsz=0.05, npix=200, proj="TAN", coord="GAL", outfile=""):
328
    """
329
    Simulate events for all observations in the container.
330

331
    Parameters:
332
     obs   - Observation container
333
    Keywords:
334
     log   - Create log file(s)
335
     debug - Create console dump?
336
     edisp - Apply energy dispersion?
337
     seed  - Seed value for simulations (default: 0)
338
     nbins - Number of energy bins (default: 0=unbinned)
339
     binsz - Pixel size for binned simulation (deg/pixel)
340
     npix  - Number of pixels in X and Y for binned simulation
341
    """
342

    
343
    # Allocate ctobssim application and set parameters
344
    sim = ctobssim(obs)
345
    sim["seed"] = seed
346
    sim["edisp"] = edisp
347
    sim["outevents"] = outfile
348

    
349
    # Optionally open the log file
350
    if log:
351
        sim.logFileOpen()
352

    
353
    # Optionally switch-on debugging model
354
    if debug:
355
        sim["debug"] = True
356

    
357
    # Set chatter level
358
    sim["chatter"] = chatter
359

    
360
    # Run ctobssim application. This will loop over all observations in the
361
    # container and simulation the events for each observation. Note that
362
    # events are not added together, they still apply to each observation
363
    # separately.
364
    sim.run()
365

    
366
    # Binned option?
367
    if nbins > 0:
368

    
369
        # Determine common energy boundaries for observations
370
        emin = None
371
        emax = None
372
        for run in sim.obs():
373
            run_emin = run.events().ebounds().emin().TeV()
374
            run_emax = run.events().ebounds().emax().TeV()
375
            if emin == None:
376
                emin = run_emin
377
            elif run_emin > emin:
378
                emin = run_emin
379
            if emax == None:
380
                emax = run_emax
381
            elif run_emax > emax:
382
                emax = run_emax
383

    
384
        # Allocate ctbin application and set parameters
385
        bin = ctbin(sim.obs())
386
        bin["ebinalg"] = "LOG"
387
        bin["emin"] = emin
388
        bin["emax"] = emax
389
        bin["enumbins"] = nbins
390
        bin["usepnt"] = True # Use pointing for map centre
391
        bin["nxpix"] = npix
392
        bin["nypix"] = npix
393
        bin["binsz"] = binsz
394
        bin["coordsys"] = coord
395
        bin["proj"] = proj
396

    
397
        # Optionally open the log file
398
        if log:
399
            bin.logFileOpen()
400

    
401
        # Optionally switch-on debugging model
402
        if debug:
403
            bin["debug"] = True
404

    
405
        # Set chatter level
406
        bin["chatter"] = chatter
407

    
408
        # Run ctbin application. This will loop over all observations in
409
        # the container and bin the events in counts maps
410
        bin.run()
411

    
412
        # Make a deep copy of the observation that will be returned
413
        # (the ctbin object will go out of scope one the function is
414
        # left)
415
        obs = bin.obs().copy()
416

    
417
    else:
418

    
419
        # Make a deep copy of the observation that will be returned
420
        # (the ctobssim object will go out of scope one the function is
421
        # left)
422
        obs = sim.obs().copy()
423
        
424
    # Optionally save file
425
    if (len(outfile) > 0):
426
        sim.save()
427
        
428
    # Delete the simulation
429
    del sim
430

    
431
    # Return observation container
432
    return obs
433

    
434

    
435
# =================== #
436
# Make a simple model #
437
# =================== #
438
def make_simple_model(models,name,ra,dec,flux,idx):
439
    
440
    # Add background model (one for each pointing)
441
    models = add_background_model(models,bgd_sigma=0.0,instru='CTA',id="0001",name="Background left")
442
    set_fit_param(models["Background left"],parname=['Sigma','Normalization','Prefactor','Index'],parfit=[False,True,True,False])
443
    models = add_background_model(models,bgd_sigma=0.0,instru='CTA',id="0002",name="Background right")
444
    set_fit_param(models["Background right"],parname=['Sigma','Normalization','Prefactor','Index'],parfit=[False,True,True,False])
445
    
446
    # Add source model
447
    models = add_source_model(models, name, ra, dec, flux=flux, index=idx, pivot=1.0e6, type="point", pivot_scale=1e6, flux_scale=1.0e-16)
448
    set_fit_param(models["Test source"],parname=['Prefactor','Index','RA','DEC'],parfit=[True,True,False,False])
449
    
450
    # Exit
451
    return models
452

    
453

    
454
# =================== #
455
# Make a simple model #
456
# =================== #
457
def reset_simple_model(models,ra,dec,flux,idx):
458
    
459
    # Add background model (one for each pointing)
460
    set_fit_param(models["Background left"],parname=['Sigma','Normalization','Prefactor','Index'],parfit=[False,True,True,False],parval=[0.0,1.0,1.0,0.0])
461
    set_fit_param(models["Background right"],parname=['Sigma','Normalization','Prefactor','Index'],parfit=[False,True,True,False],parval=[0.0,1.0,1.0,0.0])
462
    set_fit_param(models["Test source"],parname=['Prefactor','Index','RA','DEC'],parfit=[True,True,False,False],parval=[flux,idx,ra,dec])
463
    
464
    # Exit
465
    return models
466

    
467

    
468
# ================ #
469
# Make a histogram #
470
# ================ #
471
def make_histogram(arr,n):
472
        
473
    # Make histogram
474
    dbin=(max(arr)-min(arr))/n
475
    hist=np.histogram(np.array(arr), bins=n)
476
    yhist=hist[0]
477
    xhist=np.linspace(min(arr)+0.5*dbin, max(arr)-0.5*dbin, num=n, endpoint=True)
478

    
479
    # Exit
480
    return xhist,yhist
481

    
482

    
483
# =========== #
484
# Make a plot #
485
# =========== #
486
def plot_histogram(x,n):
487

    
488
    # Plot
489
    plt.figure()
490
    plt.hist(x,n)
491
    plt.xscale('linear')
492
    plt.yscale('linear')
493
    plt.xlabel('Parameter',labelpad=10)
494
    plt.ylabel('Number',labelpad=10)
495

    
496

    
497
# ======================== #
498
# Set plotting environment #
499
# ======================== #
500
def prepare_plots():
501
    
502
    # Set
503
    params = {'legend.fontsize': 14,
504
              'legend.labelspacing': 0.2,
505
              'figure.figsize': (8,8),
506
              'figure.facecolor': 'white',
507
              'lines.linewidth': 2,
508
              'axes.titlesize': 'large',
509
              'axes.labelsize': 'large'}
510
    # Assign
511
    plt.rcParams.update(params)
512
    return    
513

    
514

    
515
# =========== #
516
# Make a plot #
517
# =========== #
518
def plot_results(x,y):
519

    
520
    # Plot
521
    plt.figure()
522
    plt.plot(x,y)
523
    plt.xscale('linear')
524
    plt.yscale('linear')
525
    plt.xlabel('Parameter',labelpad=10)
526
    plt.ylabel('Number',labelpad=10)
527
    xmin=0.95*min(x)
528
    xmax=1.05*max(x)
529
    ymin=0.95*min(y)
530
    ymax=1.05*max(y)
531
    plt.xlim([xmin,xmax])
532
    plt.ylim([ymin,ymax])
533

    
534

    
535
# ===================== #
536
# Print out fit results #
537
# ===================== #
538
def print_fit_results(obslist):
539
    
540
    # Print
541
    print "Background left prefactor: %.3e +/- %.3e " % (obslist.models()["Background left"]['Prefactor'].value(),obslist.models()["Background left"]['Prefactor'].error())
542
    print "Background left index: %.3e +/- %.3e " % (obslist.models()["Background left"]['Index'].value(),obslist.models()["Background left"]['Index'].error())
543
    print "Background right prefactor: %.3e +/- %.3e " % (obslist.models()["Background right"]['Prefactor'].value(),obslist.models()["Background right"]['Prefactor'].error())
544
    print "Background right index: %.3e +/- %.3e " % (obslist.models()["Background right"]['Index'].value(),obslist.models()["Background right"]['Index'].error())
545
    print "Source prefactor: %.3e +/- %.3e " % (obslist.models()["Test source"]['Prefactor'].value(),obslist.models()["Test source"]['Prefactor'].error())
546
    print "Source index: %.3e +/- %.3e " % (obslist.models()["Test source"]['Index'].value(),obslist.models()["Test source"]['Index'].error())
547
    print "Fit ended with value %.3e and status %d after %d iterations." % (opt.value(),opt.status(),opt.iter())
548
    
549
    # Exit
550
    return
551
    
552

    
553
#=====================#
554
# Routine entry point #
555
#=====================#
556
if __name__ == '__main__':
557

    
558
    """
559
    Aims:
560
    This script tests the ON-OFF analysis functionality of the gammalib
561
    
562
    Arguments:
563
    - None
564
    
565
    Notes:
566
    - Hard-coded source, observations, and regions (more flexible script later...)
567
    - Approximate method to set OFF regions (works only on equator)
568
    - Have to set up path to data base (db and irf)
569
    - Source flux set as flux density at 1TeV
570
    """
571
    
572
    # Job parameters
573
    # CTA
574
    db="prod2"
575
    irf="South_50h"
576
    bgd=""
577
    rsp_sigma=4.0
578
    bgd_sigma=4.0
579
    duration=1800.0
580
    rad=5.0
581
    # Energy
582
    emin=0.1
583
    emax=100.0
584
    nbins=9
585
    nnodes=5
586
    # Source
587
    name="Test source"
588
    ra=0.0
589
    dec=0.0
590
    flux=1.0e-16
591
    idx=-2.3
592
    dflux=1.5  # Offset factor by which true value is rescaled before fit
593
    didx=0.3   # Offset factor by which true value is rescaled before fit
594
    # ON-OFF
595
    onshift=1.0
596
    onsize=0.3
597
    noff=3
598
    # Others
599
    npull=100
600
    nhist=10
601
    chatter=4
602
    seed=5
603
    
604
    # Create observation container
605
    obslist = GObservations()
606
    
607
    # Add two offset observations
608
    leftdir = GSkyDir()
609
    leftdir.radec_deg(ra+onshift, dec)
610
    obs=single_obs(leftdir, tstart=0.0, duration=duration, deadc=0.95, \
611
                   emin=emin, emax=emax, rad=rad, \
612
                   irf=irf, caldb=db, id="000000", instrument="CTA")
613
    obs.name("Left")
614
    obs.id("0001")
615
    obslist.append(obs)
616
    rightdir = GSkyDir()
617
    rightdir.radec_deg(ra-onshift, dec)
618
    obs=single_obs(rightdir, tstart=0.0, duration=duration, deadc=0.95, \
619
                   emin=emin, emax=emax, rad=rad, \
620
                   irf=irf, caldb=db, id="000000", instrument="CTA")
621
    obs.name("Right")
622
    obs.id("0002")
623
    obslist.append(obs)    
624
    
625
    # Create a model container
626
    models = GModels()   
627
    # Make a simple model for two observations
628
    models = make_simple_model(models,name,ra,dec,flux,idx)
629
    # Add model to the container
630
    obslist.models(models)
631
    
632
    # Define ON region
633
    ondir = GSkyDir()
634
    ondir.radec_deg(0.0,0.0)
635
    on = GSkyRegions()
636
    onreg=GSkyRegionCircle(ondir,onsize)
637
    on.append(onreg)
638
    
639
    # Define OFF regions
640
    offleft = GSkyRegions()
641
    offright = GSkyRegions()
642
    for i in range(noff):
643
        phi=(i+1)*360./(noff+1.0)
644
        # Left pointing  
645
        offdir = GSkyDir(leftdir)       
646
        offdir.rotate_deg(phi-90., onshift)
647
        offreg=GSkyRegionCircle(offdir, onsize)
648
        offleft.append(offreg)
649
        # Right pointing
650
        offdir = GSkyDir(rightdir)       
651
        offdir.rotate_deg(phi+90.0, onshift)       
652
        offreg=GSkyRegionCircle(offdir, onsize)
653
        offright.append(offreg)
654
            
655
    # Create ON-OFF analysis object
656
    onofflist = GCTAOnOffObservations()
657
    
658
    # Define energy binning
659
    etrue = GEbounds(nbins, GEnergy(emin, "TeV"), GEnergy(emax, "TeV"))
660
    ereco = GEbounds(nbins, GEnergy(emin, "TeV"), GEnergy(emax, "TeV"))
661
    
662
    # Append ON-OFF observations
663
    obs=GCTAOnOffObservation(ereco, on, offleft)
664
    obs.name("Left")
665
    obs.id("0001")
666
    onofflist.append(obs)
667
    obs=GCTAOnOffObservation(ereco, on, offright)
668
    obs.name("Right")
669
    obs.id("0002")
670
    onofflist.append(obs)
671
    
672
    # Create arrays to store pull results
673
    onoff_flux=[]
674
    onoff_idx=[]
675
    unbinned_flux=[]
676
    unbinned_idx=[]
677
    
678
    # Repeat the run...
679
    # (make each time new copies of obslist and onofflist otherwise something accumulates and goes wrong)
680
    for i in range(npull):
681
    
682
        # Print
683
        print '\nRun ',i
684
        
685
        # Make event list
686
        theobslist=GObservations(obslist)
687
        theobslist = sim(theobslist, log=False, debug=False, chatter=chatter, edisp=False, seed=seed+i, nbins=0)
688
       
689
        # Load data and save (fills ON and OFF spectra, ON and OFF observing time, and alpha parameter)
690
        theonofflist=GCTAOnOffObservations(onofflist)
691
        theonofflist[0].fill(theobslist[0])
692
        theonofflist[1].fill(theobslist[1])
693
    
694
            # Compute responses and save
695
        theonofflist[0].compute_response(theobslist[0],models,etrue)
696
        theonofflist[1].compute_response(theobslist[1],models,etrue)    
697
       
698
        # Reset model container and append it to observation list
699
        models=reset_simple_model(models,ra,dec,dflux*flux,idx-didx)
700
        theonofflist.models(models)
701
    
702
        # Set optimizer and logger
703
        log=GLog('fit_onoff_%d.log' % (i),True)
704
        log.chatter(chatter)
705
        opt=GOptimizerLM(log)
706
    
707
        # Optimize for ON-OFF analysis
708
        print '\nON-OFF fitting...'
709
        theonofflist.optimize(opt)
710
        theonofflist.errors(opt)
711
        print_fit_results(theonofflist)
712
        
713
        # Append results
714
        onoff_flux.append(theonofflist.models()["Test source"]['Prefactor'].value())
715
        onoff_idx.append(theonofflist.models()["Test source"]['Index'].value())
716
    
717
        # Free memory
718
        del opt
719
        del log
720
        del theonofflist
721
         
722
        # Reset model container and append it to observation list
723
        models=reset_simple_model(models,ra,dec,dflux*flux,idx-didx)
724
        theobslist.models(models)
725
    
726
        # Set optimizer and logger
727
        log=GLog('fit_unbinned_%d.log' % (i),True)
728
        log.chatter(chatter)
729
        opt=GOptimizerLM(log)
730
    
731
        # Optimize for Fermi-style analysis
732
        print '\nUnbinned fitting...'
733
        theobslist.optimize(opt)
734
        theobslist.errors(opt)
735
        print_fit_results(theobslist)
736
        
737
        # Append results
738
        unbinned_flux.append(theobslist.models()["Test source"]['Prefactor'].value())
739
        unbinned_idx.append(theobslist.models()["Test source"]['Index'].value())
740
    
741
        # Free memory
742
        del opt
743
        del log
744
        del theobslist
745
        
746
    # Print out statistics
747
    print '\nTrue values: prefactor=%.3e and index=%.3f \n' % (flux,idx)
748
    print 'ON-OFF analysis'
749
    print 'Prefactor: mean= %.3e +/- %.3e' % (np.mean(np.array(onoff_flux)),np.std(np.array(onoff_flux)))
750
    print 'Index= %.3f +/- %.3f \n' % (np.mean(np.array(onoff_idx)),np.std(np.array(onoff_idx)))
751
    print 'Unbinned analysis'
752
    print 'Prefactor: mean= %.3e +/- %.3e' % (np.mean(np.array(unbinned_flux)),np.std(np.array(unbinned_flux)))
753
    print 'Index= %.3f +/- %.3f \n' % (np.mean(np.array(unbinned_idx)),np.std(np.array(unbinned_idx)))
754
    
755
    # Plot results
756
    prepare_plots()
757
    plot_histogram(unbinned_flux,nhist)
758
    plot_histogram(unbinned_idx,nhist)
759
    plot_histogram(onoff_flux,nhist)
760
    plot_histogram(onoff_idx,nhist)
761
    plt.show()
762
    
763