cstsmapmerge.py
12.7 KB
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
381
382
383
384
385
386
387
388
389
390
391
392
393
394
395
396
397
398
399
400
401
402
403
404
405
406
407
#!/usr/bin/env python
# ==========================================================================
# Merges sliced TS map files into one map
#
# Copyright (C) 2015-2016 Michael Mayer
#
# This program is free software: you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation, either version 3 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
# GNU General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program. If not, see <http://www.gnu.org/licenses/>.
#
# ==========================================================================
import gammalib
import ctools
import sys
import glob
import os
# ================== #
# cstsmapmerge class #
# ================== #
class cstsmapmerge(ctools.cscript):
"""
This class merges TS map files into one TS map
"""
def __init__(self, *argv):
"""
Constructor.
"""
# Set name
self.name = "cstsmapmerge"
self.version = "1.1.0"
# Make sure that parfile exists
file = self.parfile()
# Initialise application
if len(argv) == 0:
ctools.cscript.__init__(self, self.name, self.version)
elif len(argv) == 1:
ctools.cscript.__init__(self, self.name, self.version, *argv)
else:
raise TypeError("Invalid number of arguments given.")
# Set logger properties
self.log_header()
self.log.date(True)
# Return
return
def __del__(self):
"""
Destructor.
"""
# Return
return
def parfile(self):
"""
Check if parfile exists. If parfile does not exist then create a
default parfile. This kluge avoids shipping the cscript with a
parfile.
"""
# Set parfile name
parfile = self.name+".par"
try:
pars = gammalib.GApplicationPars(parfile)
except:
# Signal that parfile was not found
print("Parfile \""+parfile+"\" not found. Create default parfile.")
# Create default parfile
pars = gammalib.GApplicationPars()
pars.append(gammalib.GApplicationPar("inmaps","s","a","tsmap.fits","","","Input TS map FITS files"))
pars.append(gammalib.GApplicationPar("outmap","f","a","NONE","","","Output TS map FITS file"))
pars.append(gammalib.GApplicationPar("overwrite","b","h","yes","","","Overwrite previously filled bins?"))
pars.append(gammalib.GApplicationPar("delete","b","h","no","","","Delete merged files?"))
pars.append_standard()
pars.append(gammalib.GApplicationPar("logfile","f","h","cstsmapmerge.log","","","Log filename"))
pars.save(parfile)
# Return
return
def get_parameters(self):
"""
Get parameters from parfile and setup the observation.
"""
# Get input models
self.inmodels = self["inmaps"].string()
# Interpet inmodels string
# Handle ascii files
if "@" == self.inmodels[0]:
self.files = open(self.inmodels.replace("@","")).read().splitlines()
# Handle wild card strings
elif "*" in self.inmodels:
self.files = glob.glob(self.inmodels)
# Handle space-separated list
elif " " in self.inmodels:
self.files = self.inmodels.split(" ")
# Handle comma-separated list
elif "," in self.inmodels:
self.files = self.inmodels.split(",")
# Throw exception if input models cannot be decoded
else:
msg = "Parameter \"inmmaps\" must contain either an @ASCII file,"+\
" a comma-separated or whitespace-separated list of files"+\
" or a wildcard string"
raise RuntimeError(msg)
# Check number of files. We need at least two files.
if len(self.files) <= 1:
msg = "Need at least two files to start merging, "+\
str(len(self.files))+" files given."
raise RuntimeError(msg)
# Get output file
self.outmap = self["outmap"].filename()
# Get other parameters
self.overwrite = self["overwrite"].boolean()
self.delete = self["delete"].boolean()
# Return
return
def init_map(self, fitsfile):
"""
"""
# Set filename
self.in_filename = fitsfile
# Open FITS file
fits = gammalib.GFits(fitsfile)
self.tsmap = gammalib.GSkyMap()
self.tsmap.read(fits[0])
self.statusmap = gammalib.GSkyMap()
self.statusmap.read(fits["STATUS MAP"])
# Get other maps
self.maps = []
self.mapnames = []
# Loop over extensions
for hdu in fits:
# Leave out primary and status extension
if hdu.extname() != "IMAGE" and hdu.extname() != "STATUS MAP":
# Add present maps
skymap = gammalib.GSkyMap()
skymap.read(hdu)
self.maps.append(skymap)
self.mapnames.append(hdu.extname())
# Close FITS file
fits.close()
# Return
return
# Add map instances to each other. In this way the TS maps get merged
def add(self, fitsfile):
# open FITS file
fits = gammalib.GFits(fitsfile)
add_tsmap = gammalib.GSkyMap()
add_tsmap.read(fits[0])
add_statusmap = gammalib.GSkyMap()
add_statusmap.read(fits["STATUS MAP"])
# Get other maps
add_maps = []
# Loop over extensions
for hdu in fits:
# Leave out primary and status extension
if hdu.extname() != "IMAGE" and hdu.extname() != "STATUS MAP":
# Add present maps
skymap = gammalib.GSkyMap()
skymap.read(hdu)
add_maps.append(skymap)
# Close FITS file
fits.close()
# Compare size of other maps
if not len(add_maps) == len(self.maps):
self.error("Maps cannot be added: Maps from \""+self.in_filename+"\" do not match from \""+fitsfile+"\"")
# Loop over bins
for i in range(self.tsmap.npix()):
if add_statusmap[i] > 0.5:
# Throw exception if this bin has already been computed
if self.statusmap[i] > 0.5 and not self.overwrite:
msg = "Attempt to merge bin which apparently has already"+\
" been merged. File \""+fitsfile+"\" contains"+\
" already merged bins. Set hidden parameter"+\
" overwrite=yes to avoid this error."
raise RuntimeError(msg)
# Copy TS values
self.tsmap[i] = add_tsmap[i]
# Copy status
self.statusmap[i] = add_statusmap[i]
# Loop over maps and copy entries
for j in range(len(self.maps)):
self.maps[j][i] = add_maps[j][i]
# Return
return
def run(self):
"""
Run the script.
"""
# Switch screen logging on in debug mode
if self.logDebug():
self.log.cout(True)
# Get parameters
self.get_parameters()
# Write input parameters into logger
if self.logTerse():
self.log_parameters()
self.log("\n")
if self.logTerse():
self.log("\n")
self.log.header1("Merging sliced TS map files")
self.log("\n")
# Initialise file to start with
file0 = ""
self.added_files = []
# Test files for the entry status map
# use the first one to appear useful
for fitsfile in self.files:
if not gammalib.GFilename(fitsfile).is_fits():
self.log("Skipping file \""+fitsfile+" (not a FITS file)\n")
fits = gammalib.GFits(fitsfile)
if fits.contains("STATUS MAP"):
self.log("Using file \""+fitsfile+"\" as initialising map\n")
file0 = fitsfile
break
else:
if self.logExplicit():
self.log("File \""+fitsfile+"\" has not \"STATUS MAP\" extension\n")
# Print an error message if no suitable file was provided
if file0 == "":
if self.logTerse():
self.log("None of the provided file seems to be a sliced ts map file (no \"STATUS MAP\" extension)\n")
# Otherwise merge files
else:
# copy file list
workfiles = self.files
# Remove entry which will be used to initalise the map
workfiles.remove(file0)
# Initialise map from first file
self.init_map(file0)
# Append to added files
self.added_files.append(file0)
# Loop over files
for fitsfile in workfiles:
# Skip if file is not FITS
if not gammalib.GFilename(fitsfile).is_fits():
if self.logTerse():
self.log("Skipping file \""+fitsfile+" (not a FITS file)\n")
continue
# Skip if file does not contain status map
fits = gammalib.GFits(fitsfile)
if not fits.contains("STATUS MAP"):
if self.logTerse():
self.log("Skipping file \""+fitsfile+" (not a FITS file)\n")
continue
# Logging
if self.logTerse():
self.log("Adding TS map slice \""+fitsfile+"\"\n")
# Add file
self.add(fitsfile)
# Append to added files
self.added_files.append(fitsfile)
# Return
return
def save(self):
"""
Save merged tsmap file and remove slices if requested
"""
# Logging
if self.logExplicit():
self.log("\n")
self.log.header1("Saving merged TS map")
self.log("\n")
# Create FITS file
fits = gammalib.GFits()
# Write TS map into primary
self.tsmap.write(fits)
# Loop over maps and write them to fits
for i in range(len(self.maps)):
self.maps[i].write(fits)
# Set map names as extensions
for i in range(len(self.mapnames)):
fits[i+1].extname(self.mapnames[i])
# Check if map is fully done
done = True
for pix in self.statusmap:
if pix < 0.5:
done = False
break
# Write Status map if we are not done yet
if not done:
self.statusmap.write(fits)
fits[fits.size()-1].extname("STATUS MAP")
# Save FITS file
fits.saveto(self.outmap, self.clobber())
if self.logExplicit():
self.log("Saved output map to \""+self.outmap+"\"\n")
if self.delete:
if self.logTerse():
self.log("\n")
self.log.header1("Deleting slices")
self.log("\n")
for filename in self.added_files:
if self.logExplicit():
self.log("Deleting file \""+filename+"\"\n")
os.remove(filename)
# Return
return
def execute(self):
"""
Execute the script.
"""
# Run the script
self.run()
# Save ds9 file if required
self.save()
# Return
return
# ======================== #
# Main routine entry point #
# ======================== #
if __name__ == '__main__':
"""
Merges ts map slices.
"""
# Create instance of application
app = cstsmapmerge(sys.argv)
# Open logfile
app.logFileOpen()
# Execute application
app.execute()