csbutterfly.py

Mayer Michael, 07/18/2014 02:10 PM

Download (10 KB)

 
1
#! /usr/bin/env python
2
# ==========================================================================
3
# This script generates the pull distribution for all model parameters.
4
#
5
# Copyright (C) 2011-2014 Juergen Knoedlseder
6
#
7
# This program is free software: you can redistribute it and/or modify
8
# it under the terms of the GNU General Public License as published by
9
# the Free Software Foundation, either version 3 of the License, or
10
# (at your option) any later version.
11
#
12
# This program is distributed in the hope that it will be useful,
13
# but WITHOUT ANY WARRANTY; without even the implied warranty of
14
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
15
# GNU General Public License for more details.
16
#
17
# You should have received a copy of the GNU General Public License
18
# along with this program.  If not, see <http://www.gnu.org/licenses/>.
19
#
20
# ==========================================================================
21

    
22
import gammalib as gl
23
import ctools as ct
24
import sys
25
import math
26

    
27

    
28
# ============ #
29
# csbutterfly class #
30
# ============ #
31
class csbutterfly(gl.GApplication):
32
    """
33
    This class implements an the computation of a butterfly. 
34
    It derives from the GammaLib::GApplication class which 
35
    provides support for parameter files, command line arguments,
36
    and logging. In that way the Python script behaves just as a 
37
    regular ctool.
38
    """
39
    def __init__(self, *argv):
40

    
41
        """
42
        Constructor.
43
        """
44

    
45
        # Set name
46
        self.name    = "csbutterfly"
47
        self.version = "0.0.1"
48
         
49
        # Initialise some members
50
        if isinstance(argv[0],gl.GObservations):
51
            self.obs = argv[0]
52
        else:      
53
            self.obs      = gl.GObservations()
54
        
55
        self.source = "CrabNebula"
56
        self.m_sigma = 1 
57
        self.m_emin = 0.0 #TeV
58
        self.m_emax = 0.0 #TeV 
59
        self.m_nbins = 100
60

    
61
        
62
        # Make sure that parfile exists
63
        file = self.parfile()
64

    
65
        # Initialise application
66
        if len(argv) == 1:
67
            gl.GApplication.__init__(self, self.name, self.version)
68
        elif len(argv) ==2:
69
            gl.GApplication.__init__(self, self.name, self.version, argv[1:])
70
        else:
71
            raise TypeError("Invalid number of arguments given.")
72
        
73
        # Set logger properties
74
        self.log_header()
75
        self.log.date(True)
76
 
77
        # Return
78
        return
79
    
80
    def __del__(self):
81
        """
82
        Destructor.
83
        """
84
        #  Write separator into logger
85
        if self.logTerse():
86
            self.log("\n")
87
        
88
        # Return
89
        return
90

    
91
    def parfile(self):
92
        """
93
        Check if parfile exists. If parfile does not exist then create a
94
        default parfile. This kluge avoids shipping the cscript with a parfile.
95
        """
96
        # Set parfile name
97
        parfile = self.name+".par"
98
        
99
        try:
100
            pars = gl.GApplicationPars(parfile)
101
        except:
102
            # Signal if parfile was not found
103
            sys.stdout.write("Parfile "+parfile+" not found. Create default parfile.\n")
104
            
105
            # Create default parfile
106
            pars = gl.GApplicationPars()
107
            pars.append(gl.GApplicationPar("infile", "f", "a", "events.fits","","","observation definition file"))
108
            pars.append(gl.GApplicationPar("stat","s","h","POISSON","","","Optimization statistics"))
109
            pars.append(gl.GApplicationPar("refit",  "b", "h", "no","","", "Do refitting?"))
110
            pars.append(gl.GApplicationPar("srcmdl","f","a","$CTOOLS/share/models/crab.xml","","","Source model"))
111
            pars.append(gl.GApplicationPar("caldb","s","h","","","","Calibration database"))
112
            pars.append(gl.GApplicationPar("irf","s","a","cta_dummy_irf","","","Instrument response function"))
113
            pars.append(gl.GApplicationPar("edisp","b","h","no","","","Apply energy dispersion?"))
114
            pars.append(gl.GApplicationPar("logfile", "f", "h", "csbutterfly.log","","", "Log filename"))
115
            pars.append(gl.GApplicationPar("outfile", "f", "a", "CrabNebula.bf","","", "Outfile name"))
116
            pars.append(gl.GApplicationPar("Emin", "r", "a", "0.1","","TeV", "Minimum Energy"))
117
            pars.append(gl.GApplicationPar("Emax", "r", "a", "100","","TeV", "Maximum Energy"))
118
            pars.append(gl.GApplicationPar("nbins", "i", "h", "100","","", "Butterfly spacing"))
119
            pars.append(gl.GApplicationPar("sigma", "f", "h", "1","","", "Butterfly spacing"))
120
            pars.append_standard()
121
            pars.save(parfile)
122
        
123
        # Return
124
        return
125

    
126

    
127

    
128
        
129
    def get_parameters(self):
130
        """
131
        Get parameters from parfile and setup the observation.
132
        """
133
         
134
        # Setup obs if it isn't already set
135
        if self.obs.size() == 0:
136
            
137
            infile = self["infile"].filename()
138
            try:      
139
                self.obs = gl.GObservations(infile)
140
            except:
141
                obs0 = gl.GCTAObservation(infile)
142
                self.obs.append(obs0)
143
            mdlfile = self["srcmdl"].filename()
144
            self.obs.models(mdlfile)
145
            self.m_caldb    = self["caldb"].string()
146
            self.m_irf      = self["irf"].string()
147
            
148
            
149
        else:
150
            self.m_caldb = ""
151
            self.m_irf = ""
152
                    
153
        # get hidden parameters
154
        self.m_stat = self["stat"].string()
155
        self.m_refit = self["refit"].boolean()
156
        self.m_edisp = self["edisp"].boolean()
157
        self.m_chatter = self["chatter"].integer()
158
        self.m_debug = self["debug"].boolean()
159
        self.m_clobber = self["clobber"].boolean()
160
        self.m_mode = self["mode"].string()
161
        self.m_logfile = self["logfile"].filename()
162
        
163
        if self.m_emin == 0.0 or self.m_emax == 0.0:
164
            self.m_emin = self["Emin"].real()
165
            self.m_emax = self["Emax"].real()
166
        self.m_nbins = self["nbins"].integer()
167

    
168
       
169
    def execute(self):
170
        """
171
        Execute the script.
172
        """
173
        # Run the script
174
        self.run()
175
         
176
        # Return
177
        return
178

    
179

    
180
    def obs(self):
181
        """
182
        Return observations
183
        """
184
        return self.obs.clone()    
185
    
186

    
187
    def run(self):
188
        """
189
        Run the fit.
190
        """
191
 
192
        # Switch screen logging on in debug mode
193
        if self.logDebug():
194
            self.log.cout(True)
195

    
196
        
197
        # Get parameters
198
        self.get_parameters()
199
 
200
        #  Write input parameters into logger
201
        if self.logTerse():
202
            self.log_parameters()
203
            self.log("\n")
204
        
205
        # Write observation into logger
206
        if self.logTerse():
207
            self.log("\n")
208
            self.log.header1("Observation")
209
            self.log(str(self.obs))
210
            self.log("\n")
211

    
212
        # Write header
213
        if self.logTerse():
214
            self.log("\n")
215
            self.log.header1("Generate butterfly")
216

    
217
        # Check if observation container is already optimised
218
        # might add a flag in the future for that
219
        if self.obs.function().value() == 0.0:
220
            print "Optimising observation container"
221
            like = ct.ctlike(self.obs)
222
            like.run()
223
            self.covar = like.obs().function().curvature().invert()
224
            self.obs.models(like.obs().models().clone())
225
        else:
226
            self.covar = self.obs.function().curvature().invert()
227
         
228
        try:
229
            m = self.obs.models()[self.source]
230
        except RuntimeError:
231
            sys.exit("Source \""+self.source+"\" not found in model container",sys._getframe().f_code.co_name)
232

    
233
        # Initialise energies in log binning
234
        energies = []
235
        step = (math.log10(self.m_emax)-math.log10(self.m_emin) )/ (self.m_nbins-1)
236
        for ibin in range(self.m_nbins):
237
            loge = math.log10(self.m_emin)+ibin*step
238
            energies.append(pow(10,loge))
239

    
240
        fluxes = []
241
        errors = []
242
        t=gl.GTime()
243

    
244
        self.fluxes = []
245
        self.errors = []
246
        for energy in energies:
247
            npars = self.obs.models().npars()
248
            grad = gl.GVector(npars)
249
            e = gl.GEnergy(energy,"TeV") 
250
            k=0
251
            value=0            
252
            for m in self.obs.models():                
253
                if m.name() == self.source: 
254
                    k+=m.spatial().size()
255
                    spec = m.spectral()
256
                    value = spec.eval_gradients(e,t)
257
                    for i in range(spec.size()):  
258
                        grad[k] = spec[i].gradient()
259
                        k+=1
260
                    k+=1
261
                else:
262
                    k+=m.size()
263
            fluxes.append(value)
264
            vect = self.covar * grad
265
            err2 = grad * vect
266
            err = math.sqrt(err2)            
267
            errors.append(err)
268
#             if self.verbose:
269
#                 self.success("E = "+str(e)+", Flux = "+str("%.3e" % value)+" +- "+str("%.3e" % err)+" 1/cm2/s/MeV")
270

    
271
        energies_MeV = []
272
        for e in energies:
273
            energies_MeV.append(e*1e6)
274

    
275

    
276
        self.save(self.outfile,energies_MeV,fluxes,errors)
277
        print "Finished: output written to "+self.outfile
278
 
279
 
280
 
281
 
282
    def save(self,outfile,energies,fluxes,errors):
283
        f=open(outfile,"w")
284
        f.write("# 1 energy [MeV] \n")
285
        f.write("# 2 value [1/cm2/s/MeV] \n")
286
        for i in range(len(energies)):
287
            y= fluxes[i]+errors[i]
288
            f.write(str(energies[i])+" "+str(y)+" \n")
289
        for i in range(len(energies)):
290
            y = fluxes[-(i+1)]-errors[-(i+1)]
291
            if y <1e-35:
292
                y=1e-35
293
            f.write(str(energies[-(i+1)])+" "+str(y)+" \n")            
294
        f.write(str(energies[0])+" "+str((fluxes[0]+errors[0]))+" \n")
295
        f.close()   
296
 
297
 
298
 
299
 
300

    
301

    
302

    
303
# ======================== #
304
# Main routine entry point #
305
# ======================== #
306
if __name__ == '__main__':
307
    """
308
    Generates butterfly for a source model.
309
    """
310
    # Create instance of application
311
    app = csbutterfly(sys.argv)
312
     
313
    # Open logfile
314
    app.logFileOpen()
315
     
316
    # Execute application
317
    app.execute()
318