ctools 2.1.0.dev
Loading...
Searching...
No Matches
csresmap.py
Go to the documentation of this file.
1#! /usr/bin/env python
2# ==========================================================================
3# Generates a residual map.
4#
5# Copyright (C) 2014-2022 Michael Mayer
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# ==========================================================================
21import sys
22import gammalib
23import ctools
24from cscripts import obsutils
25
26
27# ============== #
28# csresmap class #
29# ============== #
30class csresmap(ctools.csobservation):
31 """
32 Generates a residual map
33 """
34
35 # Constructor
36 def __init__(self, *argv):
37 """
38 Constructor
39 """
40 # Initialise application by calling the appropriate class constructor
41 self._init_csobservation(self.__class__.__name__, ctools.__version__, argv)
42
43 # Initialise class members
44 self._resmap = None
45 self._use_maps = False
46 self._skip_binning = False
47
48 # Return
49 return
50
51
52 # Private methods
53 def _get_parameters(self):
54 """
55 Get parameters from parfile and setup the observation
56 """
57 # Initialise some flags
58 self._use_maps = False
59 self._skip_binning = False
60
61 # If there are no observations in the observation container then check
62 # if the "inobs" parameter is a counts cube. If the "inobs" parameter
63 # represents a FITS file and if this FITS file is a counts cube then
64 # set self._skip_binning=True
65 if self.obs().size() == 0 and self['inobs'].filename() != 'NONE':
66 filename = gammalib.GFilename(self['inobs'].filename())
67 if filename.is_fits():
68 cta = gammalib.GCTAObservation()
69 cta.load(filename)
70 if cta.eventtype() == 'CountsCube':
71 self._skip_binning = True
72
73 # If we have a counts cube, then ask whether we also have a model cube.
74 # If a model cube name is given then set self._use_maps=True
75 if self._skip_binning:
76 self._use_maps = self['modcube'].is_valid()
77
78 # If not two maps are given, proceed to set up observation
79 if not self._use_maps:
80
81 # Set observation if not done before
82 if self.obs().size() == 0:
83 self._require_inobs('csresmap.get_parameters()')
84 self.obs(self._get_observations())
85
86 # If we have exactly one binned CTA observation then signal that
87 # the binning can be skipped
88 if self.obs().size() == 1 and \
89 self.obs()[0].classname() == 'GCTAObservation' and \
90 self.obs()[0].eventtype() == 'CountsCube':
91 self._skip_binning = True
92
93 # Set models if we have none
94 if self.obs().models().size() == 0:
95 self.obs().models(self['inmodel'].filename())
96
97 # If no binning is provided in the observation then query now
98 # the counts cube binning parameters
99 if not self._skip_binning:
100 self['xref'].real()
101 self['yref'].real()
102 self['coordsys'].string()
103 self['proj'].string()
104 self['nxpix'].integer()
105 self['nypix'].integer()
106 self['binsz'].real()
107 self['ebinalg'].string()
108 if self['ebinalg'].string() == 'FILE':
109 self['ebinfile'].filename()
110 else:
111 self['emin'].real()
112 self['emax'].real()
113 self['enumbins'].integer()
114 if self['ebinalg'].string() == 'POW':
115 self['ebingamma'].real()
116
117 # Query parameters
118 self['edisp'].boolean()
119 self['algorithm'].string()
120 self['publish'].boolean()
121 self['chatter'].integer()
122 self['clobber'].boolean()
123 self['debug'].boolean()
124
125 # Query ahead output parameters
126 if (self._read_ahead()):
127 self['outmap'].filename()
128
129 # Write input parameters into logger
130 self._log_parameters(gammalib.TERSE)
131
132 # Return
133 return
134
135
136 # Public methods
137 def process(self):
138 """
139 Process the script
140 """
141 # Get parameters
142 self._get_parameters()
143
144 # Write observation into logger
145 self._log_observations(gammalib.NORMAL, self.obs(), 'Observation')
146
147 # If a counts and model cube are specified then load them as sky map
148 if self._use_maps:
149 countmap = gammalib.GSkyMap(self['inobs'].filename())
150 modelmap = gammalib.GSkyMap(self['modcube'].filename())
151
152 # ... otherwise build a counts cube and model cube
153 else:
154
155 # Do not build counts cube if we have already one in the observation
156 # container
157 if self._skip_binning:
158 cta_counts_cube = gammalib.GCTAEventCube(self.obs()[0].events())
159
160 # ... otherwise generate one now from the event list
161 else:
162
163 # Write header
164 self._log_header1(gammalib.TERSE, 'Generate binned map (ctbin)')
165
166 # Create counts cube
167 cta_counts_cube = obsutils.create_counts_cube(self, self.obs())
168
169 # Assign GCTAEventCube to skymap
170 countmap = cta_counts_cube.counts()
171
172 # Write header
173 self._log_header1(gammalib.TERSE, 'Generate model map (ctmodel)')
174
175 # Create model map
176 model = ctools.ctmodel(self.obs())
177 model.cube(cta_counts_cube)
178 model['chatter'] = self['chatter'].integer()
179 model['clobber'] = self['clobber'].boolean()
180 model['debug'] = self['debug'].boolean()
181 model['edisp'] = self['edisp'].boolean()
182 model.run()
183
184 # Get model map into GSkyMap object
185 modelmap = model.cube().counts().copy()
186
187 # Calculate residual maps
188 # Note that we need a special
189 # construct here to avoid memory leaks. This seems to be a SWIG feature
190 # as SWIG creates a new object when calling binning.cube()
191 countmap1 = countmap.copy()
192 countmap1.stack_maps()
193 modelmap.stack_maps()
194 self._resmap = obsutils.residuals(self,countmap1,modelmap)
195
196 # Optionally publish map
197 if self['publish'].boolean():
198 self.publish()
199
200 # Return
201 return
202
203 def save(self):
204 """
205 Save residual map
206 """
207 # Write header
208 self._log_header1(gammalib.TERSE, 'Save residual map')
209
210 # Get outmap parameter
211 outmap = self['outmap'].filename()
212
213 # Continue only filename and residual map are valid
214 if self._resmap != None:
215
216 # Log file name
217 self._log_value(gammalib.TERSE, 'Residual map file', outmap.url())
218
219 # Save residual map
220 self._resmap.save(outmap, self['clobber'].boolean())
221
222 # Stamp residual map
223 self._stamp(outmap)
224
225 # Return
226 return
227
228 def publish(self, name=''):
229 """
230 Publish residual map
231
232 Parameters
233 ----------
234 name : str, optional
235 Name of residual map
236 """
237 # Write header
238 self._log_header1(gammalib.TERSE, 'Publish residual map')
239
240 # Continue only if residual map is valid
241 if self._resmap != None:
242
243 # Set default name is user name is empty
244 if not name:
245 user_name = self._name()
246 else:
247 user_name = name
248
249 # Log map name
250 self._log_value(gammalib.TERSE, 'Residual map name', user_name)
251
252 # Publish map
253 self._resmap.publish(user_name)
254
255 # Return
256 return
257
258 def models(self, models):
259 """
260 Set model
261 """
262 # Copy models
263 self.obs().models(models)
264
265 # Return
266 return
267
268 def resmap(self):
269 """
270 Return residual map
271
272 Returns
273 -------
274 map : `~gammalib.GSkyMap'
275 Residual sky map
276 """
277 # Return
278 return self._resmap
279
280
281# ======================== #
282# Main routine entry point #
283# ======================== #
284if __name__ == '__main__':
285
286 # Create instance of application
287 app = csresmap(sys.argv)
288
289 # Execute application
290 app.execute()
publish(self, name='')
Definition csresmap.py:228