ctools 2.1.0.dev
Loading...
Searching...
No Matches
csobsselect.py
Go to the documentation of this file.
1#!/usr/bin/env python
2# ==========================================================================
3# Selects observations from an observation definition XML file
4#
5# Copyright (C) 2016-2022 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# ==========================================================================
21import sys
22import gammalib
23import ctools
24
25
26# ================= #
27# csobsselect class #
28# ================= #
29class csobsselect(ctools.csobservation):
30 """
31 Selects observations from an observation definition XML file
32 """
33
34 # Constructor
35 def __init__(self, *argv):
36 """
37 Constructor
38 """
39 # Initialise application by calling the appropriate class constructor
40 self._init_csobservation(self.__class__.__name__, ctools.__version__, argv)
41
42 # Return
43 return
44
45
46 # Private methods
47 def _get_parameters(self):
48 """
49 Get parameters from parfile and setup observations
50 """
51 # If there are no observations in container then query the inobs
52 # parameter
53 if self.obs().is_empty():
54 self['inobs'].filename()
55
56 # Query relevant pointing selection parameters
57 pntselect = self['pntselect'].string()
58 coordsys = self['coordsys'].string()
59 if coordsys == 'CEL':
60 self['ra'].real()
61 self['dec'].real()
62 else:
63 self['glon'].real()
64 self['glat'].real()
65 if pntselect == 'CIRCLE':
66 self['rad'].real()
67 else:
68 self['width'].real()
69 self['height'].real()
70
71 # Query time interval. The GammaLib time reference is specified as a
72 # dummy argument since the relevant intervals will be queried later
73 # using the time reference for each observation
74 self._get_gti(gammalib.GTimeReference())
75
76 # Query ahead output model filename
77 if self._read_ahead():
78 self['outobs'].filename()
79
80 # If there are no observations in container then get them from the
81 # parameter file
82 if self.obs().is_empty():
83 self.obs(self._get_observations(False))
84
85 # Write input parameters into logger
86 self._log_parameters(gammalib.TERSE)
87
88 # Return
89 return
90
91 def _log_selection(self, obs, msg):
92 """
93 Log observation selection
94
95 Parameters
96 ----------
97 obs : `~gammalib.GObservation`
98 Observation
99 msg : str
100 Message
101 """
102 # Set observation name
103 if len(obs.name()) > 0:
104 name = obs.name()
105 else:
106 name = 'Observation'
107
108 # Prepend obervation ID
109 if len(obs.id()) > 0:
110 msg = obs.id()+' '+msg
111
112 # Log observation selection
113 self._log_value(gammalib.NORMAL, name, msg)
114
115 # Return
116 return
117
118 def _select_observation(self, obs):
119 """
120 Select observation
121
122 Parameters
123 ----------
124 obs : `~gammalib.GObservation`
125 Observation
126
127 Returns
128 -------
129 select : bool
130 Observation selection flag
131 """
132 # Initialise selection flag
133 select = False
134
135 # Continue only if observation is a CTA observation
136 if obs.classname() == 'GCTAObservation':
137
138 # Get observation start and stop time
139 obs_gti = obs.gti()
140 obs_tstart = obs_gti.tstart()
141 obs_tstop = obs_gti.tstop()
142
143 # Get User start and stop time in the time reference of the CTA
144 # observations
145 gti = self._get_gti(obs_gti.reference())
146 tstart = gti.tstart()
147 tstop = gti.tstop()
148
149 # If there is a valid User start and stop time and the observation
150 # stop is before the start time or the observation start after the
151 # stop time, then skip the observation
152 if gti.size() > 0 and (obs_tstop < tstart or obs_tstart > tstop):
153 self._log_selection(obs, 'outside time interval')
154
155 # ... otherwise select spatially
156 else:
157
158 # Get selection type
159 pntselect = self['pntselect'].string()
160
161 # Dispatch according to selection type
162 if pntselect == 'CIRCLE':
163 select = self._select_circle(obs)
164 else:
165 select = self._select_box(obs)
166
167 # Return selection flag
168 return select
169
170 def _select_circle(self, obs):
171 """
172 Select observation in a pointing circle
173
174 Parameters
175 ----------
176 obs : `~gammalib.GCTAObservation`
177 CTA observation
178
179 Returns
180 -------
181 select : bool
182 Observation selection flag
183 """
184 # Get coordinate system of selection circle
185 coordsys = self['coordsys'].string()
186
187 # Get pointing direction
188 pnt = obs.pointing().dir()
189
190 # Set selection circle centre
191 centre = gammalib.GSkyDir()
192 if coordsys == 'CEL':
193 centre.radec_deg(self['ra'].real(), self['dec'].real())
194 else:
195 centre.lb_deg(self['glon'].real(), self['glat'].real())
196
197 # Set selection flag according to distance
198 if centre.dist_deg(pnt) <= self['rad'].real():
199 select = True
200 msg = 'inside selection circle'
201 else:
202 select = False
203 msg = 'outside selection circle'
204
205 # Log observation selection
206 self._log_selection(obs, msg)
207
208 # Return selection flag
209 return select
210
211 def _select_box(self, obs):
212 """
213 Select observation in a pointing box
214
215 Parameters
216 ----------
217 obs : `~gammalib.GCTAObservation`
218 CTA observation
219
220 Returns
221 -------
222 select : bool
223 Observation selection flag
224 """
225 # Initialise selection flag
226 select = False
227 msg = 'outside selection box'
228
229 # Get coordinate system of selection circle
230 coordsys = self['coordsys'].string()
231
232 # Get pointing direction
233 pnt = obs.pointing().dir()
234
235 # Get selection box width and height
236 width = self['width'].real()
237 height = self['height'].real()
238
239 # Make selection for celestial coordinates ...
240 if coordsys == 'CEL':
241
242 # Determine box boundaries
243 ra = self['ra'].real()
244 dec = self['dec'].real()
245 ra_min = ra - 0.5 * width
246 ra_max = ra + 0.5 * width
247 dec_min = dec - 0.5 * height
248 dec_max = dec + 0.5 * height
249
250 # Check if pointing lies within boundaries
251 ra = pnt.ra_deg()
252 ra_plus = ra + 360.0
253 ra_minus = ra - 360.0
254 dec = pnt.dec_deg()
255 if dec >= dec_min and dec <= dec_max:
256 if ra >= ra_min and ra <= ra_max or \
257 ra_plus >= ra_min and ra_plus <= ra_max or \
258 ra_minus >= ra_min and ra_minus <= ra_max:
259 select = True
260 msg = 'inside selection box'
261
262 # ... or galactic coordinates
263 else:
264
265 # Determine box boundaries
266 glon = self['glon'].real()
267 glat = self['glat'].real()
268 glon_min = glon - 0.5 * width
269 glon_max = glon + 0.5 * width
270 glat_min = glat - 0.5 * height
271 glat_max = glat + 0.5 * height
272
273 # Check if pointing lies within boundaries
274 glon = pnt.l_deg()
275 glon_plus = glon + 360.0
276 glon_minus = glon - 360.0
277 glat = pnt.b_deg()
278 if glat >= glat_min and glat <= glat_max:
279 if glon >= glon_min and glon <= glon_max or \
280 glon_plus >= glon_min and glon_plus <= glon_max or \
281 glon_minus >= glon_min and glon_minus <= glon_max:
282 select = True
283 msg = 'inside selection box'
284
285 # Log observation selection
286 self._log_selection(obs, msg)
287
288 # Return selection flag
289 return select
290
291
292 # Public methods
293 def process(self):
294 """
295 Process the script
296 """
297 # Get parameters
298 self._get_parameters()
299
300 # Initialise empty observation container for selected observations
301 selected_obs = gammalib.GObservations()
302
303 # Set models
304 selected_obs.models(self.obs().models())
305
306 # Write input observation container into logger
307 self._log_observations(gammalib.NORMAL, self.obs(), 'Input observation')
308
309 # Write header
310 self._log_header1(gammalib.TERSE, 'Observation selection')
311
312 # Loop over observations
313 for obs in self.obs():
314
315 # If observation is selected then append observation
316 if self._select_observation(obs):
317 selected_obs.append(obs)
318
319 # Copy selected observations into observation
320 self.obs(selected_obs)
321
322 # Write input observation container into logger
323 self._log_observations(gammalib.NORMAL, self.obs(), 'Selected observation')
324
325 # Return
326 return
327
328 def save(self):
329 """
330 Save observation definition XML file
331 """
332 # Write header
333 self._log_header1(gammalib.TERSE, 'Save observations')
334
335 # Get output filename
336 outobs = self['outobs'].filename()
337
338 # If file exists and clobber flag is false then raise an exception
339 if outobs.exists() and not self._clobber:
340 msg = ('Cannot save "'+outobs.url()+'": File already exists. '
341 'Use parameter clobber=yes to allow overwriting of files.')
342 raise RuntimeError(msg)
343
344 # Otherwise log filename and save file
345 else:
346 # Log filename
347 self._log_value(gammalib.NORMAL, 'Obs. definition XML file',
348 outobs.url())
349
350 # Save observations
351 self.obs().save(outobs)
352
353 # Return
354 return
355
356
357# ======================== #
358# Main routine entry point #
359# ======================== #
360if __name__ == '__main__':
361
362 # Create instance of application
363 app = csobsselect(sys.argv)
364
365 # Execute application
366 app.execute()