cslike.py

Mayer Michael, 07/07/2014 02:23 PM

Download (11 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
# cslike class #
30
# ============ #
31
class cslike(gl.GApplication):
32
    """
33
    This class implements an auxiliary python interface to ctlike.
34
    It offers some additional functionality, like computing TS values,
35
    and storing covariance matrix. It derives from the 
36
    GammaLib::GApplication class which provides support for parameter
37
    files, command line arguments, and logging. In that way the Python
38
    script behaves just as a regular ctool.
39
    """
40
    def __init__(self, *argv):
41

    
42
        """
43
        Constructor.
44
        """
45

    
46
        # Set name
47
        self.name    = "cslike"
48
        self.version = "0.0.1"
49
         
50
        # Initialise some members
51
        if isinstance(argv[0],gl.GObservations):
52
            self.obs = argv[0]
53
        else:      
54
            self.obs      = gl.GObservations()
55
        self.outfile = ""
56
        self.m_value=0
57
        self.m_covar = None
58
        self.m_status = -1
59
        self.m_ts_method = "BIASED"
60
        self.ts = {}
61
        self.LogL0 = {}
62
        
63
        # Make sure that parfile exists
64
        file = self.parfile()
65

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

    
92
    def parfile(self):
93
        """
94
        Check if parfile exists. If parfile does not exist then create a
95
        default parfile. This kluge avoids shipping the cscript with a parfile.
96
        """
97
        # Set parfile name
98
        parfile = self.name+".par"
99
        
100
        try:
101
            pars = gl.GApplicationPars(parfile)
102
        except:
103
            # Signal if parfile was not found
104
            sys.stdout.write("Parfile "+parfile+" not found. Create default parfile.\n")
105
            
106
            # Create default parfile
107
            pars = gl.GApplicationPars()
108
            pars.append(gl.GApplicationPar("infile", "f", "a", "events.fits","","","observation definition file"))
109
            pars.append(gl.GApplicationPar("stat","s","h","POISSON","","","Optimization statistics"))
110
            pars.append(gl.GApplicationPar("refit",  "b", "h", "no","","", "Do refitting?"))
111
            pars.append(gl.GApplicationPar("srcmdl","f","a","$CTOOLS/share/models/crab.xml","","","Source model"))
112
            pars.append(gl.GApplicationPar("outfile","f","a","crab_optmodel.xml","","","Output file name"))
113
            pars.append(gl.GApplicationPar("caldb","s","h","","","","Calibration database"))
114
            pars.append(gl.GApplicationPar("irf","s","a","cta_dummy_irf","","","Instrument response function"))
115
            pars.append(gl.GApplicationPar("TSmethod", "s", "h", "BIASED","BIASED|UNBIASED","","Method to compute TS values (BIASED is faster)"))
116
            pars.append(gl.GApplicationPar("edisp","b","h","no","","","Apply energy dispersion?"))
117
            pars.append(gl.GApplicationPar("logfile", "f", "h", "cslike.log","","", "Log filename"))
118
            pars.append_standard()
119
            pars.save(parfile)
120
        
121
        # Return
122
        return
123

    
124
    def _add_ts(self):
125
        """ appends TS value to xml file """ 
126
        
127
        xml = gl.GXml(self.m_outfile) 
128
        lib = xml.element("source_library", 0);        
129
        for src_name in self.ts.keys():    
130
            for i in range(lib.elements()):
131
                src_element = lib.element("source", i);
132
                if src_element.attribute("name") == src_name:
133
                    src_element.attribute("TS",str(self.ts[src_name]))
134
                    break
135
        xml.save(self.m_outfile)
136
        
137
        # append likelihood value to last line of the file
138
        f = open(self.m_outfile,"a")
139
        f.write("loglike="+str(self.m_value))
140
        f.close()
141
       
142
        
143
    def get_parameters(self):
144
        """
145
        Get parameters from parfile and setup the observation.
146
        """
147
         
148
        # Setup obs if it isn't already set
149
        if self.obs.size() == 0:
150
            
151
            infile = self["infile"].filename()
152
            try:      
153
                self.obs = gl.GObservations(infile)
154
            except:
155
                obs0 = gl.GCTAObservation(infile)
156
                self.obs.append(obs0)
157
            mdlfile = self["srcmdl"].filename()
158
            self.obs.models(mdlfile)
159
            self.m_caldb    = self["caldb"].string()
160
            self.m_irf      = self["irf"].string()
161
            
162
        else:
163
            self.m_caldb = ""
164
            self.m_irf = ""
165
            
166
        # get hidden parameters
167
        self.m_stat = self["stat"].string()
168
        self.m_refit = self["refit"].boolean()
169
        self.m_edisp = self["edisp"].boolean()
170
        self.m_chatter = self["chatter"].integer()
171
        self.m_debug = self["debug"].boolean()
172
        self.m_clobber = self["clobber"].boolean()
173
        self.m_mode = self["mode"].string()
174
        self.m_logfile = self["logfile"].filename()
175
        
176
        # get TS calculation method
177
        self.m_ts_method = self["TSmethod"].string()
178
              
179
        # get outfile
180
        if self.outfile == "":
181
            self.m_outfile  = self["outfile"].filename() 
182
        else:
183
            self.m_outfile = self.outfile 
184
            
185
       
186
    def execute(self):
187
        """
188
        Execute the script.
189
        """
190
        # Run the script
191
        self.run()
192
         
193
        # Return
194
        return
195

    
196
    def covar(self):
197
        """
198
        Return covariance matrix
199
        """
200
        return self.m_covar.clone()
201
    def obs(self):
202
        """
203
        Return observations
204
        """
205
        return self.obs.clone()    
206
    
207

    
208
    def run(self):
209
        """
210
        Run the fit.
211
        """
212
 
213
        # Switch screen logging on in debug mode
214
        if self.logDebug():
215
            self.log.cout(True)
216

    
217
        
218
        # Get parameters
219
        self.get_parameters()
220
 
221
        #  Write input parameters into logger
222
        if self.logTerse():
223
            self.log_parameters()
224
            self.log("\n")
225
        
226
        # Write observation into logger
227
        if self.logTerse():
228
            self.log("\n")
229
            self.log.header1("Observation")
230
            self.log(str(self.obs))
231
            self.log("\n")
232

    
233
        # Write header
234
        if self.logTerse():
235
            self.log("\n")
236
            self.log.header1("Generate pull distribution")
237

    
238
        # create ctlike instance with given parameters
239
        like = ct.ctlike(self.obs)
240
        like["stat"].string(self.m_stat)
241
        like["caldb"].string(self.m_caldb)
242
        like["irf"].string(self.m_irf)
243
        like["clobber"].boolean(self.m_clobber)
244
        like["debug"].boolean(self.m_debug)
245
        like["mode"].string(self.m_mode)
246
        like["logfile"].filename(self.m_logfile)
247
        like["edisp"].boolean(self.m_edisp)
248
        like["chatter"].integer(self["chatter"].integer())
249
        
250
        # Perform the fit
251
        if self["chatter"].integer()>0:
252
            print "Running ctlike ..."
253
        like.run()
254
        LogL1 = like.opt().value()
255
        
256
        # Store likelihood value and fit status
257
        self.m_value = LogL1
258
        self.m_status = like.opt().status()
259
        
260
        # Get covariance matrix if fit has converged
261
        try:
262
            self.m_covar = like.obs().function().curvature().invert().clone()
263
        except:
264
            print "WARNING: Covariance matrix not determined successfully, FitStatus = "+str(self.status),sys._getframe().f_code.co_name
265
        
266
        # save best fit results if outfile is given
267
        if not self.m_outfile == "":
268
            like.obs().models().save(self.m_outfile)
269
         
270
        # assign optimised models   
271
        self.obs.models(like.obs().models().clone())
272
        
273
        # Find sources with free parameters to calculate their TS values
274
        freemodelnames = []
275
        for m in like.obs().models():
276
            for par in m:
277
                if par.is_free():
278
                    freemodelnames.append(m.name())
279
                    break  
280
            # Fix parameters to speed up computations: Method is inspired
281
            # from Fermi Science tools, but might lead to biased results
282
            if self.m_ts_method == "BIASED":        
283
                for par in m:
284
                    par.fix()
285
                    
286
        # save initial models for TS computation            
287
        bck_models = like.obs().models().clone()
288
        
289
        # Loop over models with free parameters
290
        for name in freemodelnames: 
291
            # exclude background from TS computation
292
            if isinstance(like.obs().models()[name],gl.GModelData):
293
                continue 
294
            
295
            # remove respective model from container                
296
            like.obs().models().remove(name)
297
            
298
            # rerun ctlike without model
299
            like0 = ct.ctlike(like.obs())
300
            like0.run()
301
            
302
            # get loglike value
303
            loglike0 = like0.opt().value()
304
            TS = 2* (loglike0-LogL1)
305
            
306
            # append TS value to dictionary
307
            self.ts[name]=TS
308
            
309
            # store likelihood value
310
            self.LogL0[name]=loglike0
311
            
312
            if self.m_chatter > 0:
313
                print "TS value of "+name+": "+str(TS)
314
                    
315
            # Reset models to best-fit state
316
            like.obs().models(bck_models)
317
        
318
        # Add TS values to optimised model files   
319
        if not self.m_outfile == "":
320
            self._add_ts()
321
        
322

    
323

    
324
# ======================== #
325
# Main routine entry point #
326
# ======================== #
327
if __name__ == '__main__':
328
    """
329
    Runs ctlike with some extensions.
330
    """
331
    # Create instance of application
332
    app = cslike(sys.argv)
333
     
334
    # Open logfile
335
    app.logFileOpen()
336
     
337
    # Execute application
338
    app.execute()
339