Commit e0f8913415367049fbebbb8113377267990aba7c

Authored by Luigi Tibaldo
1 parent d0da27ce

minimally working for binned and unbinned analysis

cscripts/Makefile.am
@@ -43,78 +43,42 @@ @@ -43,78 +43,42 @@
43 # Scripts to be distributed in $(pyexecdir)/cscripts 43 # Scripts to be distributed in $(pyexecdir)/cscripts
44 44
45 pythonscripts = $(top_builddir)/cscripts/__init__.py \ 45 pythonscripts = $(top_builddir)/cscripts/__init__.py \
46 -  
47 $(srcdir)/csbkgmodel.py \ 46 $(srcdir)/csbkgmodel.py \
48 -  
49 $(srcdir)/cscaldb.py \ 47 $(srcdir)/cscaldb.py \
50 -  
51 $(srcdir)/csebins.py \ 48 $(srcdir)/csebins.py \
52 -  
53 $(srcdir)/csinfo.py \ 49 $(srcdir)/csinfo.py \
54 -  
55 $(srcdir)/cslightcrv.py \ 50 $(srcdir)/cslightcrv.py \
56 -  
57 $(srcdir)/csmodelinfo.py \ 51 $(srcdir)/csmodelinfo.py \
58 -  
59 $(srcdir)/csmodelmerge.py \ 52 $(srcdir)/csmodelmerge.py \
60 -  
61 $(srcdir)/csmodelselect.py \ 53 $(srcdir)/csmodelselect.py \
62 -  
63 $(srcdir)/csmodelsois.py \ 54 $(srcdir)/csmodelsois.py \
64 -  
65 $(srcdir)/csobs2caldb.py \ 55 $(srcdir)/csobs2caldb.py \
66 -  
67 $(srcdir)/csobsdef.py \ 56 $(srcdir)/csobsdef.py \
68 -  
69 $(srcdir)/csobsinfo.py \ 57 $(srcdir)/csobsinfo.py \
70 -  
71 $(srcdir)/csobsselect.py \ 58 $(srcdir)/csobsselect.py \
72 -  
73 $(srcdir)/csphagen.py \ 59 $(srcdir)/csphagen.py \
74 -  
75 $(srcdir)/csphasecrv.py \ 60 $(srcdir)/csphasecrv.py \
76 -  
77 $(srcdir)/cspull.py \ 61 $(srcdir)/cspull.py \
78 -  
79 $(srcdir)/csresmap.py \ 62 $(srcdir)/csresmap.py \
80 -  
81 $(srcdir)/csresspec.py \ 63 $(srcdir)/csresspec.py \
82 -  
83 $(srcdir)/csroot2caldb.py \ 64 $(srcdir)/csroot2caldb.py \
84 -  
85 $(srcdir)/cssens.py \ 65 $(srcdir)/cssens.py \
86 -  
87 $(srcdir)/csspec.py \ 66 $(srcdir)/csspec.py \
88 -  
89 $(srcdir)/cssrcdetect.py \ 67 $(srcdir)/cssrcdetect.py \
90 -  
91 $(srcdir)/cstsdist.py \ 68 $(srcdir)/cstsdist.py \
92 -  
93 $(srcdir)/cstsmapmerge.py \ 69 $(srcdir)/cstsmapmerge.py \
94 -  
95 $(srcdir)/cstsmapsplit.py \ 70 $(srcdir)/cstsmapsplit.py \
96 -  
97 $(srcdir)/csviscube.py \ 71 $(srcdir)/csviscube.py \
98 -  
99 $(srcdir)/csscs.py \ 72 $(srcdir)/csscs.py \
100 $(srcdir)/csworkflow.py \ 73 $(srcdir)/csworkflow.py \
101 -  
102 $(srcdir)/csfindobs.py \ 74 $(srcdir)/csfindobs.py \
103 -  
104 $(srcdir)/csiactcopy.py \ 75 $(srcdir)/csiactcopy.py \
105 -  
106 $(srcdir)/csiactdata.py \ 76 $(srcdir)/csiactdata.py \
107 -  
108 $(srcdir)/csiactobs.py \ 77 $(srcdir)/csiactobs.py \
109 -  
110 $(srcdir)/obsutils.py \ 78 $(srcdir)/obsutils.py \
111 -  
112 $(srcdir)/modutils.py \ 79 $(srcdir)/modutils.py \
113 -  
114 $(srcdir)/calutils.py \ 80 $(srcdir)/calutils.py \
115 -  
116 $(srcdir)/ioutils.py \ 81 $(srcdir)/ioutils.py \
117 -  
118 $(srcdir)/mputils.py 82 $(srcdir)/mputils.py
119 83
120 84
@@ -122,64 +86,35 @@ pythonscripts = $(top_builddir)/cscripts/__init__.py \ @@ -122,64 +86,35 @@ pythonscripts = $(top_builddir)/cscripts/__init__.py \
122 # Parfiles to be distributed in $(prefix)/syspfiles 86 # Parfiles to be distributed in $(prefix)/syspfiles
123 87
124 parfiles = $(srcdir)/csbkgmodel.par \ 88 parfiles = $(srcdir)/csbkgmodel.par \
125 -  
126 $(srcdir)/cscaldb.par \ 89 $(srcdir)/cscaldb.par \
127 -  
128 $(srcdir)/csebins.par \ 90 $(srcdir)/csebins.par \
129 -  
130 $(srcdir)/cslightcrv.par \ 91 $(srcdir)/cslightcrv.par \
131 -  
132 $(srcdir)/csmodelinfo.par \ 92 $(srcdir)/csmodelinfo.par \
133 -  
134 $(srcdir)/csmodelmerge.par \ 93 $(srcdir)/csmodelmerge.par \
135 -  
136 $(srcdir)/csmodelselect.par \ 94 $(srcdir)/csmodelselect.par \
137 -  
138 $(srcdir)/csmodelsois.par \ 95 $(srcdir)/csmodelsois.par \
139 -  
140 $(srcdir)/csobs2caldb.par \ 96 $(srcdir)/csobs2caldb.par \
141 -  
142 $(srcdir)/csobsdef.par \ 97 $(srcdir)/csobsdef.par \
143 -  
144 $(srcdir)/csobsinfo.par \ 98 $(srcdir)/csobsinfo.par \
145 -  
146 $(srcdir)/csobsselect.par \ 99 $(srcdir)/csobsselect.par \
147 -  
148 $(srcdir)/csphagen.par \ 100 $(srcdir)/csphagen.par \
149 -  
150 $(srcdir)/csphasecrv.par \ 101 $(srcdir)/csphasecrv.par \
151 -  
152 $(srcdir)/cspull.par \ 102 $(srcdir)/cspull.par \
153 -  
154 $(srcdir)/csresmap.par \ 103 $(srcdir)/csresmap.par \
155 -  
156 $(srcdir)/csresspec.par \ 104 $(srcdir)/csresspec.par \
157 -  
158 $(srcdir)/csroot2caldb.par \ 105 $(srcdir)/csroot2caldb.par \
159 -  
160 $(srcdir)/cssens.par \ 106 $(srcdir)/cssens.par \
161 -  
162 $(srcdir)/csspec.par \ 107 $(srcdir)/csspec.par \
163 -  
164 $(srcdir)/cssrcdetect.par \ 108 $(srcdir)/cssrcdetect.par \
165 -  
166 $(srcdir)/cstsdist.par \ 109 $(srcdir)/cstsdist.par \
167 -  
168 $(srcdir)/cstsmapmerge.par \ 110 $(srcdir)/cstsmapmerge.par \
169 -  
170 $(srcdir)/cstsmapsplit.par \ 111 $(srcdir)/cstsmapsplit.par \
171 -  
172 $(srcdir)/csviscube.par \ 112 $(srcdir)/csviscube.par \
173 -  
174 $(srcdir)/csscs.par \ 113 $(srcdir)/csscs.par \
175 $(srcdir)/csworkflow.par \ 114 $(srcdir)/csworkflow.par \
176 -  
177 $(srcdir)/csfindobs.par \ 115 $(srcdir)/csfindobs.par \
178 -  
179 $(srcdir)/csiactcopy.par \ 116 $(srcdir)/csiactcopy.par \
180 -  
181 $(srcdir)/csiactdata.par \ 117 $(srcdir)/csiactdata.par \
182 -  
183 $(srcdir)/csiactobs.par 118 $(srcdir)/csiactobs.par
184 119
185 120
@@ -187,66 +122,36 @@ parfiles = $(srcdir)/csbkgmodel.par \ @@ -187,66 +122,36 @@ parfiles = $(srcdir)/csbkgmodel.par \
187 # Scripts for which symbolic links will be created in bindir 122 # Scripts for which symbolic links will be created in bindir
188 123
189 linkscripts = csbkgmodel \ 124 linkscripts = csbkgmodel \
190 -  
191 cscaldb \ 125 cscaldb \
192 -  
193 csebins \ 126 csebins \
194 -  
195 csinfo \ 127 csinfo \
196 -  
197 cslightcrv \ 128 cslightcrv \
198 -  
199 csmodelinfo \ 129 csmodelinfo \
200 -  
201 csmodelmerge \ 130 csmodelmerge \
202 -  
203 csmodelselect \ 131 csmodelselect \
204 -  
205 csmodelsois \ 132 csmodelsois \
206 -  
207 csobs2caldb \ 133 csobs2caldb \
208 -  
209 csobsdef \ 134 csobsdef \
210 -  
211 csobsinfo \ 135 csobsinfo \
212 -  
213 csobsselect \ 136 csobsselect \
214 -  
215 csphagen \ 137 csphagen \
216 -  
217 csphasecrv \ 138 csphasecrv \
218 -  
219 cspull \ 139 cspull \
220 -  
221 csresmap \ 140 csresmap \
222 -  
223 csresspec \ 141 csresspec \
224 -  
225 csroot2caldb \ 142 csroot2caldb \
226 -  
227 cssens \ 143 cssens \
228 -  
229 csspec \ 144 csspec \
230 -  
231 cssrcdetect \ 145 cssrcdetect \
232 -  
233 cstsdist \ 146 cstsdist \
234 -  
235 cstsmapmerge \ 147 cstsmapmerge \
236 -  
237 cstsmapsplit \ 148 cstsmapsplit \
238 -  
239 csviscube \ 149 csviscube \
240 -  
241 csscs \ 150 csscs \
242 csworkflow \ 151 csworkflow \
243 -  
244 csfindobs \ 152 csfindobs \
245 -  
246 csiactcopy \ 153 csiactcopy \
247 -  
248 csiactdata \ 154 csiactdata \
249 -  
250 csiactobs 155 csiactobs
251 156
252 157
@@ -254,78 +159,42 @@ linkscripts = csbkgmodel \ @@ -254,78 +159,42 @@ linkscripts = csbkgmodel \
254 # Test scripts to be distributed in $(pyexecdir)/cscripts/tests 159 # Test scripts to be distributed in $(pyexecdir)/cscripts/tests
255 160
256 testscripts = $(srcdir)/tests/__init__.py \ 161 testscripts = $(srcdir)/tests/__init__.py \
257 -  
258 $(top_srcdir)/test/testing.py \ 162 $(top_srcdir)/test/testing.py \
259 -  
260 $(top_srcdir)/test/test_python_cscripts.py \ 163 $(top_srcdir)/test/test_python_cscripts.py \
261 -  
262 $(top_srcdir)/test/test_cscript.py \ 164 $(top_srcdir)/test/test_cscript.py \
263 -  
264 $(top_srcdir)/test/test_cscaldb.py \ 165 $(top_srcdir)/test/test_cscaldb.py \
265 -  
266 $(top_srcdir)/test/test_csbkgmodel.py \ 166 $(top_srcdir)/test/test_csbkgmodel.py \
267 -  
268 $(top_srcdir)/test/test_csebins.py \ 167 $(top_srcdir)/test/test_csebins.py \
269 -  
270 $(top_srcdir)/test/test_csfindobs.py \ 168 $(top_srcdir)/test/test_csfindobs.py \
271 -  
272 $(top_srcdir)/test/test_csinfo.py \ 169 $(top_srcdir)/test/test_csinfo.py \
273 -  
274 $(top_srcdir)/test/test_cslightcrv.py \ 170 $(top_srcdir)/test/test_cslightcrv.py \
275 -  
276 $(top_srcdir)/test/test_csmodelinfo.py \ 171 $(top_srcdir)/test/test_csmodelinfo.py \
277 -  
278 $(top_srcdir)/test/test_csmodelmerge.py \ 172 $(top_srcdir)/test/test_csmodelmerge.py \
279 -  
280 $(top_srcdir)/test/test_csmodelselect.py \ 173 $(top_srcdir)/test/test_csmodelselect.py \
281 -  
282 $(top_srcdir)/test/test_csmodelsois.py \ 174 $(top_srcdir)/test/test_csmodelsois.py \
283 -  
284 $(top_srcdir)/test/test_csobs2caldb.py \ 175 $(top_srcdir)/test/test_csobs2caldb.py \
285 -  
286 $(top_srcdir)/test/test_csobsdef.py \ 176 $(top_srcdir)/test/test_csobsdef.py \
287 -  
288 $(top_srcdir)/test/test_csobsinfo.py \ 177 $(top_srcdir)/test/test_csobsinfo.py \
289 -  
290 $(top_srcdir)/test/test_csobsselect.py \ 178 $(top_srcdir)/test/test_csobsselect.py \
291 -  
292 $(top_srcdir)/test/test_csphagen.py \ 179 $(top_srcdir)/test/test_csphagen.py \
293 -  
294 $(top_srcdir)/test/test_csphasecrv.py \ 180 $(top_srcdir)/test/test_csphasecrv.py \
295 -  
296 $(top_srcdir)/test/test_cspull.py \ 181 $(top_srcdir)/test/test_cspull.py \
297 -  
298 $(top_srcdir)/test/test_csresmap.py \ 182 $(top_srcdir)/test/test_csresmap.py \
299 -  
300 $(top_srcdir)/test/test_csresspec.py \ 183 $(top_srcdir)/test/test_csresspec.py \
301 -  
302 $(top_srcdir)/test/test_csroot2caldb.py \ 184 $(top_srcdir)/test/test_csroot2caldb.py \
303 -  
304 $(top_srcdir)/test/test_cssens.py \ 185 $(top_srcdir)/test/test_cssens.py \
305 -  
306 $(top_srcdir)/test/test_csspec.py \ 186 $(top_srcdir)/test/test_csspec.py \
307 -  
308 $(top_srcdir)/test/test_cssrcdetect.py \ 187 $(top_srcdir)/test/test_cssrcdetect.py \
309 -  
310 $(top_srcdir)/test/test_cstsdist.py \ 188 $(top_srcdir)/test/test_cstsdist.py \
311 -  
312 $(top_srcdir)/test/test_cstsmapmerge.py \ 189 $(top_srcdir)/test/test_cstsmapmerge.py \
313 -  
314 $(top_srcdir)/test/test_cstsmapsplit.py \ 190 $(top_srcdir)/test/test_cstsmapsplit.py \
315 -  
316 $(top_srcdir)/test/test_csviscube.py \ 191 $(top_srcdir)/test/test_csviscube.py \
317 -  
318 $(top_srcdir)/test/test_csscs.py \ 192 $(top_srcdir)/test/test_csscs.py \
319 $(top_srcdir)/test/test_csworkflow.py \ 193 $(top_srcdir)/test/test_csworkflow.py \
320 -  
321 $(top_srcdir)/test/test_obsutils.py \ 194 $(top_srcdir)/test/test_obsutils.py \
322 -  
323 $(top_srcdir)/test/test_mputils.py \ 195 $(top_srcdir)/test/test_mputils.py \
324 -  
325 $(top_srcdir)/test/test_csiactcopy.py \ 196 $(top_srcdir)/test/test_csiactcopy.py \
326 -  
327 $(top_srcdir)/test/test_csiactdata.py \ 197 $(top_srcdir)/test/test_csiactdata.py \
328 -  
329 $(top_srcdir)/test/test_csiactobs.py 198 $(top_srcdir)/test/test_csiactobs.py
330 199
331 200
@@ -333,153 +202,79 @@ testscripts = $(srcdir)/tests/__init__.py \ @@ -333,153 +202,79 @@ testscripts = $(srcdir)/tests/__init__.py \
333 # Test data to be distributed in $(pyexecdir)/cscripts/tests/data 202 # Test data to be distributed in $(pyexecdir)/cscripts/tests/data
334 203
335 testdata = $(top_srcdir)/test/data/crab.xml \ 204 testdata = $(top_srcdir)/test/data/crab.xml \
336 -  
337 $(top_srcdir)/test/data/obs_unbinned.xml \ 205 $(top_srcdir)/test/data/obs_unbinned.xml \
338 -  
339 $(top_srcdir)/test/data/obs_unbinned_two.xml \ 206 $(top_srcdir)/test/data/obs_unbinned_two.xml \
340 -  
341 $(top_srcdir)/test/data/obs_stacked.xml \ 207 $(top_srcdir)/test/data/obs_stacked.xml \
342 -  
343 $(top_srcdir)/test/data/obs_stacked_two.xml \ 208 $(top_srcdir)/test/data/obs_stacked_two.xml \
344 -  
345 $(top_srcdir)/test/data/crab_events.fits \ 209 $(top_srcdir)/test/data/crab_events.fits \
346 -  
347 $(top_srcdir)/test/data/crab_cntmap.fits \ 210 $(top_srcdir)/test/data/crab_cntmap.fits \
348 -  
349 $(top_srcdir)/test/data/crab_expcube.fits.gz \ 211 $(top_srcdir)/test/data/crab_expcube.fits.gz \
350 -  
351 $(top_srcdir)/test/data/crab_psfcube.fits.gz \ 212 $(top_srcdir)/test/data/crab_psfcube.fits.gz \
352 -  
353 $(top_srcdir)/test/data/crab_edispcube.fits.gz \ 213 $(top_srcdir)/test/data/crab_edispcube.fits.gz \
354 -  
355 $(top_srcdir)/test/data/crab_bkgcube.fits.gz \ 214 $(top_srcdir)/test/data/crab_bkgcube.fits.gz \
356 -  
357 $(top_srcdir)/test/data/crab_onoff.xml \ 215 $(top_srcdir)/test/data/crab_onoff.xml \
358 -  
359 $(top_srcdir)/test/data/crab_offaxis1.fits.gz \ 216 $(top_srcdir)/test/data/crab_offaxis1.fits.gz \
360 -  
361 $(top_srcdir)/test/data/crab_offaxis2.fits.gz \ 217 $(top_srcdir)/test/data/crab_offaxis2.fits.gz \
362 -  
363 $(top_srcdir)/test/data/crab_exclusion.fits.gz \ 218 $(top_srcdir)/test/data/crab_exclusion.fits.gz \
364 -  
365 $(top_srcdir)/test/data/crab_src_reg.reg \ 219 $(top_srcdir)/test/data/crab_src_reg.reg \
366 -  
367 $(top_srcdir)/test/data/crab_bkg_reg.reg \ 220 $(top_srcdir)/test/data/crab_bkg_reg.reg \
368 -  
369 $(top_srcdir)/test/data/tsmap_0.fits \ 221 $(top_srcdir)/test/data/tsmap_0.fits \
370 -  
371 $(top_srcdir)/test/data/tsmap_1.fits \ 222 $(top_srcdir)/test/data/tsmap_1.fits \
372 -  
373 $(top_srcdir)/test/data/exclusion.reg \ 223 $(top_srcdir)/test/data/exclusion.reg \
374 -  
375 $(top_srcdir)/test/data/pntdef_minimal.dat \ 224 $(top_srcdir)/test/data/pntdef_minimal.dat \
376 -  
377 $(top_srcdir)/test/data/pntdef_maximal.dat \ 225 $(top_srcdir)/test/data/pntdef_maximal.dat \
378 -  
379 $(top_srcdir)/test/data/models.txt \ 226 $(top_srcdir)/test/data/models.txt \
380 -  
381 $(top_srcdir)/test/data/tsmaps.txt \ 227 $(top_srcdir)/test/data/tsmaps.txt \
382 -  
383 $(top_srcdir)/test/data/model_cube_background1.xml \ 228 $(top_srcdir)/test/data/model_cube_background1.xml \
384 -  
385 $(top_srcdir)/test/data/model_cube_background2.xml \ 229 $(top_srcdir)/test/data/model_cube_background2.xml \
386 -  
387 $(top_srcdir)/test/data/crab_bkgcube.xml \ 230 $(top_srcdir)/test/data/crab_bkgcube.xml \
388 -  
389 $(top_srcdir)/test/data/irf.root \ 231 $(top_srcdir)/test/data/irf.root \
390 -  
391 $(top_srcdir)/test/data/irf_file.fits.gz \ 232 $(top_srcdir)/test/data/irf_file.fits.gz \
392 -  
393 $(top_srcdir)/test/data/workflow.xml \ 233 $(top_srcdir)/test/data/workflow.xml \
394 -  
395 $(top_srcdir)/test/data/butterfly.txt \ 234 $(top_srcdir)/test/data/butterfly.txt \
396 -  
397 $(top_srcdir)/test/data/pha.fits \ 235 $(top_srcdir)/test/data/pha.fits \
398 -  
399 $(top_srcdir)/test/data/pha_channels.fits \ 236 $(top_srcdir)/test/data/pha_channels.fits \
400 -  
401 $(top_srcdir)/test/data/pull.dat \ 237 $(top_srcdir)/test/data/pull.dat \
402 -  
403 $(top_srcdir)/test/data/sensitivity.dat \ 238 $(top_srcdir)/test/data/sensitivity.dat \
404 -  
405 $(top_srcdir)/test/data/sensitivity_integral.dat \ 239 $(top_srcdir)/test/data/sensitivity_integral.dat \
406 -  
407 $(top_srcdir)/test/data/skymap.fits \ 240 $(top_srcdir)/test/data/skymap.fits \
408 -  
409 $(top_srcdir)/test/data/spectrum.fits \ 241 $(top_srcdir)/test/data/spectrum.fits \
410 -  
411 $(top_srcdir)/test/data/residual.fits \ 242 $(top_srcdir)/test/data/residual.fits \
412 -  
413 $(top_srcdir)/test/data/residual_onoff.fits \ 243 $(top_srcdir)/test/data/residual_onoff.fits \
414 -  
415 $(top_srcdir)/test/data/lightcurve.fits \ 244 $(top_srcdir)/test/data/lightcurve.fits \
416 -  
417 $(top_srcdir)/test/data/ts.dat \ 245 $(top_srcdir)/test/data/ts.dat \
418 -  
419 $(top_srcdir)/test/data/models_spatial.xml \ 246 $(top_srcdir)/test/data/models_spatial.xml \
420 -  
421 $(top_srcdir)/test/data/models_spectral.xml \ 247 $(top_srcdir)/test/data/models_spectral.xml \
422 -  
423 $(top_srcdir)/test/data/model_filefunction.txt \ 248 $(top_srcdir)/test/data/model_filefunction.txt \
424 -  
425 $(top_srcdir)/test/data/model_map.fits.gz \ 249 $(top_srcdir)/test/data/model_map.fits.gz \
426 -  
427 $(top_srcdir)/test/data/model_mapcube.fits.gz \ 250 $(top_srcdir)/test/data/model_mapcube.fits.gz \
428 -  
429 $(top_srcdir)/test/data/iact_runlist.dat \ 251 $(top_srcdir)/test/data/iact_runlist.dat \
430 -  
431 $(top_srcdir)/test/data/iact_runlist_1.dat \ 252 $(top_srcdir)/test/data/iact_runlist_1.dat \
432 -  
433 $(top_srcdir)/test/data/iact_runlist_2.dat \ 253 $(top_srcdir)/test/data/iact_runlist_2.dat \
434 -  
435 $(top_srcdir)/test/data/model_temporal_phasecurve.xml \ 254 $(top_srcdir)/test/data/model_temporal_phasecurve.xml \
436 -  
437 $(top_srcdir)/test/data/model_temporal_phasecurve.fits \ 255 $(top_srcdir)/test/data/model_temporal_phasecurve.fits \
438 -  
439 $(top_srcdir)/test/data/phased_events.fits.gz \ 256 $(top_srcdir)/test/data/phased_events.fits.gz \
440 -  
441 $(top_srcdir)/test/data/onoff_arf.fits.gz \ 257 $(top_srcdir)/test/data/onoff_arf.fits.gz \
442 -  
443 $(top_srcdir)/test/data/onoff_arf1.fits.gz \ 258 $(top_srcdir)/test/data/onoff_arf1.fits.gz \
444 -  
445 $(top_srcdir)/test/data/onoff_arf2.fits.gz \ 259 $(top_srcdir)/test/data/onoff_arf2.fits.gz \
446 -  
447 $(top_srcdir)/test/data/onoff_model.xml \ 260 $(top_srcdir)/test/data/onoff_model.xml \
448 -  
449 $(top_srcdir)/test/data/onoff_obs.xml \ 261 $(top_srcdir)/test/data/onoff_obs.xml \
450 -  
451 $(top_srcdir)/test/data/onoff_obs1.xml \ 262 $(top_srcdir)/test/data/onoff_obs1.xml \
452 -  
453 $(top_srcdir)/test/data/onoff_obs2.xml \ 263 $(top_srcdir)/test/data/onoff_obs2.xml \
454 -  
455 $(top_srcdir)/test/data/onoff_obs_stacked.xml \ 264 $(top_srcdir)/test/data/onoff_obs_stacked.xml \
456 -  
457 $(top_srcdir)/test/data/onoff_pha_off.fits.gz \ 265 $(top_srcdir)/test/data/onoff_pha_off.fits.gz \
458 -  
459 $(top_srcdir)/test/data/onoff_pha_off1.fits.gz \ 266 $(top_srcdir)/test/data/onoff_pha_off1.fits.gz \
460 -  
461 $(top_srcdir)/test/data/onoff_pha_off2.fits.gz \ 267 $(top_srcdir)/test/data/onoff_pha_off2.fits.gz \
462 -  
463 $(top_srcdir)/test/data/onoff_pha_on.fits.gz \ 268 $(top_srcdir)/test/data/onoff_pha_on.fits.gz \
464 -  
465 $(top_srcdir)/test/data/onoff_pha_on1.fits.gz \ 269 $(top_srcdir)/test/data/onoff_pha_on1.fits.gz \
466 -  
467 $(top_srcdir)/test/data/onoff_pha_on2.fits.gz \ 270 $(top_srcdir)/test/data/onoff_pha_on2.fits.gz \
468 -  
469 $(top_srcdir)/test/data/onoff_rmf.fits.gz \ 271 $(top_srcdir)/test/data/onoff_rmf.fits.gz \
470 -  
471 $(top_srcdir)/test/data/onoff_rmf1.fits.gz \ 272 $(top_srcdir)/test/data/onoff_rmf1.fits.gz \
472 -  
473 $(top_srcdir)/test/data/onoff_rmf2.fits.gz \ 273 $(top_srcdir)/test/data/onoff_rmf2.fits.gz \
474 -  
475 $(top_srcdir)/test/data/model_crab_radialacceptance.xml \ 274 $(top_srcdir)/test/data/model_crab_radialacceptance.xml \
476 -  
477 $(top_srcdir)/test/data/sigdist_map.fits.gz \ 275 $(top_srcdir)/test/data/sigdist_map.fits.gz \
478 -  
479 $(top_srcdir)/test/data/variability.fits.gz \ 276 $(top_srcdir)/test/data/variability.fits.gz \
480 -  
481 $(top_srcdir)/test/data/viscube.fits.gz \ 277 $(top_srcdir)/test/data/viscube.fits.gz \
482 -  
483 $(top_srcdir)/test/data/hess_bkg_lookup.fits 278 $(top_srcdir)/test/data/hess_bkg_lookup.fits
484 279
485 280
@@ -487,9 +282,7 @@ testdata = $(top_srcdir)/test/data/crab.xml \ @@ -487,9 +282,7 @@ testdata = $(top_srcdir)/test/data/crab.xml \
487 # Test data to be distributed in $(pyexecdir)/cscripts/tests/data/iactdata 282 # Test data to be distributed in $(pyexecdir)/cscripts/tests/data/iactdata
488 283
489 testiactdata = $(top_srcdir)/test/data/iactdata/hdu-index.fits.gz \ 284 testiactdata = $(top_srcdir)/test/data/iactdata/hdu-index.fits.gz \
490 -  
491 $(top_srcdir)/test/data/iactdata/master.json \ 285 $(top_srcdir)/test/data/iactdata/master.json \
492 -  
493 $(top_srcdir)/test/data/iactdata/obs-index.fits.gz 286 $(top_srcdir)/test/data/iactdata/obs-index.fits.gz
494 287
495 288
@@ -497,23 +290,14 @@ testiactdata = $(top_srcdir)/test/data/iactdata/hdu-index.fits.gz \ @@ -497,23 +290,14 @@ testiactdata = $(top_srcdir)/test/data/iactdata/hdu-index.fits.gz \
497 # Test data to be distributed in $(pyexecdir)/cscripts/tests/data/iactdata/events 290 # Test data to be distributed in $(pyexecdir)/cscripts/tests/data/iactdata/events
498 291
499 testiactevents = $(top_srcdir)/test/data/iactdata/events/irf_file.fits.gz \ 292 testiactevents = $(top_srcdir)/test/data/iactdata/events/irf_file.fits.gz \
500 -  
501 $(top_srcdir)/test/data/iactdata/events/events_0.fits.gz \ 293 $(top_srcdir)/test/data/iactdata/events/events_0.fits.gz \
502 -  
503 $(top_srcdir)/test/data/iactdata/events/events_1.fits.gz \ 294 $(top_srcdir)/test/data/iactdata/events/events_1.fits.gz \
504 -  
505 $(top_srcdir)/test/data/iactdata/events/events_2.fits.gz \ 295 $(top_srcdir)/test/data/iactdata/events/events_2.fits.gz \
506 -  
507 $(top_srcdir)/test/data/iactdata/events/events_3.fits.gz \ 296 $(top_srcdir)/test/data/iactdata/events/events_3.fits.gz \
508 -  
509 $(top_srcdir)/test/data/iactdata/events/events_4.fits.gz \ 297 $(top_srcdir)/test/data/iactdata/events/events_4.fits.gz \
510 -  
511 $(top_srcdir)/test/data/iactdata/events/events_5.fits.gz \ 298 $(top_srcdir)/test/data/iactdata/events/events_5.fits.gz \
512 -  
513 $(top_srcdir)/test/data/iactdata/events/events_6.fits.gz \ 299 $(top_srcdir)/test/data/iactdata/events/events_6.fits.gz \
514 -  
515 $(top_srcdir)/test/data/iactdata/events/events_7.fits.gz \ 300 $(top_srcdir)/test/data/iactdata/events/events_7.fits.gz \
516 -  
517 $(top_srcdir)/test/data/iactdata/events/events_8.fits.gz 301 $(top_srcdir)/test/data/iactdata/events/events_8.fits.gz
518 302
519 303
@@ -557,9 +341,7 @@ testiactevents_DATA = $(testiactevents) @@ -557,9 +341,7 @@ testiactevents_DATA = $(testiactevents)
557 # Files to be distributed in the tar file 341 # Files to be distributed in the tar file
558 342
559 EXTRA_DIST = $(binscripts) $(pythonscripts) $(parfiles) \ 343 EXTRA_DIST = $(binscripts) $(pythonscripts) $(parfiles) \
560 -  
561 $(testscripts) $(testdata) $(testiactdata) \ 344 $(testscripts) $(testdata) $(testiactdata) \
562 -  
563 $(testiactevents) 345 $(testiactevents)
564 346
565 347
@@ -569,23 +351,15 @@ EXTRA_DIST = $(binscripts) $(pythonscripts) $(parfiles) \ @@ -569,23 +351,15 @@ EXTRA_DIST = $(binscripts) $(pythonscripts) $(parfiles) \
569 install-data-hook: 351 install-data-hook:
570 352
571 @binlist='$(binscripts)';\ 353 @binlist='$(binscripts)';\
572 -  
573 for p in $$binlist; do \ 354 for p in $$binlist; do \
574 -  
575 chmod +x "$(DESTDIR)$(bindir)/$$p"; \ 355 chmod +x "$(DESTDIR)$(bindir)/$$p"; \
576 -  
577 done 356 done
578 357
579 @linklist='$(linkscripts)';\ 358 @linklist='$(linkscripts)';\
580 -  
581 for p in $$linklist; do \ 359 for p in $$linklist; do \
582 -  
583 rm -rf "$(DESTDIR)$(bindir)/$$p"; \ 360 rm -rf "$(DESTDIR)$(bindir)/$$p"; \
584 -  
585 cp "$(DESTDIR)$(pyexecdir)/cscripts/$$p.py" "$(DESTDIR)$(bindir)/$$p"; \ 361 cp "$(DESTDIR)$(pyexecdir)/cscripts/$$p.py" "$(DESTDIR)$(bindir)/$$p"; \
586 -  
587 chmod +x "$(DESTDIR)$(bindir)/$$p"; \ 362 chmod +x "$(DESTDIR)$(bindir)/$$p"; \
588 -  
589 done 363 done
590 364
591 365
@@ -595,11 +369,8 @@ install-data-hook: @@ -595,11 +369,8 @@ install-data-hook:
595 uninstall-hook: 369 uninstall-hook:
596 370
597 @linklist='$(linkscripts)';\ 371 @linklist='$(linkscripts)';\
598 -  
599 for p in $$linklist; do \ 372 for p in $$linklist; do \
600 -  
601 rm -rf "$(DESTDIR)$(bindir)/$$p"; \ 373 rm -rf "$(DESTDIR)$(bindir)/$$p"; \
602 -  
603 done 374 done
604 375
605 376
@@ -609,21 +380,13 @@ uninstall-hook: @@ -609,21 +380,13 @@ uninstall-hook:
609 clean-local: 380 clean-local:
610 381
611 @if ! [ '@top_srcdir@' -ef '@top_builddir@' ]; then \ 382 @if ! [ '@top_srcdir@' -ef '@top_builddir@' ]; then \
612 -  
613 rm -rf $(top_builddir)/cscripts/cs*.py; \ 383 rm -rf $(top_builddir)/cscripts/cs*.py; \
614 -  
615 rm -rf $(top_builddir)/cscripts/obsutils.py; \ 384 rm -rf $(top_builddir)/cscripts/obsutils.py; \
616 -  
617 rm -rf $(top_builddir)/cscripts/modutils.py; \ 385 rm -rf $(top_builddir)/cscripts/modutils.py; \
618 -  
619 rm -rf $(top_builddir)/cscripts/calutils.py; \ 386 rm -rf $(top_builddir)/cscripts/calutils.py; \
620 -  
621 rm -rf $(top_builddir)/cscripts/ioutils.py; \ 387 rm -rf $(top_builddir)/cscripts/ioutils.py; \
622 -  
623 rm -rf $(top_builddir)/cscripts/mputils.py; \ 388 rm -rf $(top_builddir)/cscripts/mputils.py; \
624 -  
625 rm -rf $(top_builddir)/cscripts/*.par; \ 389 rm -rf $(top_builddir)/cscripts/*.par; \
626 -  
627 fi 390 fi
628 391
629 rm -rf $(top_builddir)/cscripts/*.pyc 392 rm -rf $(top_builddir)/cscripts/*.pyc
cscripts/csscs.par
@@ -14,13 +14,56 @@ @@ -14,13 +14,56 @@
14 # # 14 # #
15 ############################################################################# 15 #############################################################################
16 # 16 #
17 -# General parameters  
18 -#===================  
19 -# Your parameters go here 17 +# Input and output parameters
  18 +#============================
  19 +inobs, f, a, events.fits,,, "Input event list, counts cube, or observation definition XML file"
  20 +inmodel, f, a, $CTOOLS/share/models/crab.xml,,, "Input model definition XML file"
  21 +srcnames, s, a, Crab,,, "Semicolon separated list of sources"
  22 +expcube, f, a, NONE,,, "Input exposure cube file"
  23 +psfcube, f, a, NONE,,, "Input PSF cube file"
  24 +edispcube, f, a, NONE,,, "Input energy dispersion cube file"
  25 +bkgcube, f, a, NONE,,, "Input background cube file"
  26 +caldb, s, a, prod2,,, "Calibration database"
  27 +irf, s, a, South_0.5h,,, "Instrument response function"
  28 +inexclusion, f, h, NONE,,, "Exclusion regions"
  29 +edisp, b, h, no,,, "Apply energy dispersion?"
  30 +outfile, f, a, map.fits,,, "Output map"
  31 +
  32 +#
  33 +# Script parameters
  34 +#==================
  35 +coordsys, s, a, CEL,CEL|GAL,, "Coordinate System"
  36 +proj, s, a, CAR,AIT|AZP|CAR|GLS|MER|MOL|SFL|SIN|STG|TAN,, "Projection method"
  37 +xref, r, a, 83.63,0,360, "First coordinate of image center in degrees (RA or galactic l)"
  38 +yref, r, a, 22.51,-90,90, "Second coordinate of image center in degrees (DEC or galactic b)"
  39 +nxpix, i, a, 20,,, "Size of the X axis in pixels"
  40 +nypix, i, a, 20,,, "Size of the Y axis in pixels"
  41 +binsz, r, a, 0.1,,, "Pixel size (deg/pixel)"
  42 +roisz, r, a, 2.,1.42,1000, "Size of the region of interest (numbers of binsz)"
  43 +statistic, s, h, DEFAULT,DEFAULT|CSTAT|WSTAT|CHI2,, "Optimization statistic"
  44 +method, s, a, 3D, 3D|ONOFF,, "Analysis method"
  45 +ebinalg, s, a, LOG,FILE|LIN|LOG,, "Algorithm for defining energy bins"
  46 +emin, r, a, 0.1,,, "Lower energy limit (TeV)"
  47 +emax, r, a, 100.0,,, "Upper energy limit (TeV)"
  48 +enumbins, i, a, 20,,, "Number of energy bins"
  49 +bkgmethod, s, h, REFLECTED,REFLECTED,, "Method for background estimation"
  50 +srcshape, s, h, CIRCLE,CIRCLE,, "Shape of the source region"
  51 +bkgregmin, i, h, 2,1,1000, "Minimum number of background regions"
  52 +use_model_bkg, b, h, yes,,, "Use background model?"
  53 +maxoffset, r, h, 4.0,,, "Maximum offset of source from camera center to accept observation"
  54 +etruemin, r, h, 0.01,,, "Minimum true energy (TeV)"
  55 +etruemax, r, h, 300.0,,, "Maximum true energy (TeV)"
  56 +etruebins, i, h, 30,,, "Number of bins per decade for true energy bins"
  57 +calc_ts, b, h, yes,,, "Compute TS value in each bin"
  58 +calc_ulim, b, h, yes,,, "Compute upper limit in each bin"
  59 +fix_srcs, b, h, yes,,, "Fix other skymodel parameters"
  60 +fix_bkg, b, h, no,,, "Fix background parameters"
20 61
21 # 62 #
22 # Standard parameters 63 # Standard parameters
23 #==================== 64 #====================
  65 +nthreads, i, h, 0,0,1000, "Number of parallel processes (0=use all available CPUs)"
  66 +publish, b, h, no,,, "Publish output map on VO Hub?"
24 chatter, i, h, 2,0,4, "Chattiness of output" 67 chatter, i, h, 2,0,4, "Chattiness of output"
25 clobber, b, h, yes,,, "Overwrite existing output files with new output files?" 68 clobber, b, h, yes,,, "Overwrite existing output files with new output files?"
26 debug, b, h, no,,, "Activate debugging mode?" 69 debug, b, h, no,,, "Activate debugging mode?"
cscripts/csscs.py
@@ -21,6 +21,9 @@ @@ -21,6 +21,9 @@
21 import sys 21 import sys
22 import gammalib 22 import gammalib
23 import ctools 23 import ctools
  24 +from cscripts import mputils
  25 +from cscripts import obsutils
  26 +import math
24 27
25 28
26 # ================= # 29 # ================= #
@@ -45,6 +48,13 @@ class csscs(ctools.csobservation): @@ -45,6 +48,13 @@ class csscs(ctools.csobservation):
45 # Initialise application by calling the base class constructor 48 # Initialise application by calling the base class constructor
46 self._init_csobservation(self.__class__.__name__, ctools.__version__, argv) 49 self._init_csobservation(self.__class__.__name__, ctools.__version__, argv)
47 50
  51 + # Initialise data members
  52 + self._nthreads = 0
  53 + self._roisz = 0.
  54 + self._srcnames = []
  55 + self._fits = None
  56 + self._excl_reg_map = None # Exclusion region map for on/off analysis
  57 +
48 # Return 58 # Return
49 return 59 return
50 60
@@ -59,7 +69,13 @@ class csscs(ctools.csobservation): @@ -59,7 +69,13 @@ class csscs(ctools.csobservation):
59 Pickled instance 69 Pickled instance
60 """ 70 """
61 # Set pickled dictionary 71 # Set pickled dictionary
62 - state = {'base' : ctools.csobservation.__getstate__(self)} 72 + # Set pickled dictionary
  73 + state = {'base' : ctools.csobservation.__getstate__(self),
  74 + 'nthreads' : self._nthreads,
  75 + 'roisz' : self._roisz,
  76 + 'srcnames' : self._srcnames,
  77 + 'fits' : self._fits,
  78 + 'excl_reg_map' : self._excl_reg_map}
63 79
64 # Return pickled dictionary 80 # Return pickled dictionary
65 return state 81 return state
@@ -75,6 +91,11 @@ class csscs(ctools.csobservation): @@ -75,6 +91,11 @@ class csscs(ctools.csobservation):
75 """ 91 """
76 # Set state 92 # Set state
77 ctools.csobservation.__setstate__(self, state['base']) 93 ctools.csobservation.__setstate__(self, state['base'])
  94 + self._nthreads = state['nthreads']
  95 + self._roisz = state['roisz']
  96 + self._srcnames = state['srcnames']
  97 + self._fits = state['fits']
  98 + self._excl_reg_map = state['excl_reg_map']
78 99
79 # Return 100 # Return
80 return 101 return
@@ -85,14 +106,497 @@ class csscs(ctools.csobservation): @@ -85,14 +106,497 @@ class csscs(ctools.csobservation):
85 """ 106 """
86 Get parameters from parfile 107 Get parameters from parfile
87 """ 108 """
88 - # TODO: Add code to query all relevant parameters 109 +
  110 + # Set observation if not done before
  111 + if self.obs().is_empty():
  112 + self.obs(self._get_observations())
  113 +
  114 + # Collect number of unbinned, binned and On/Off observations in
  115 + # observation container
  116 + n_unbinned = 0
  117 + n_binned = 0
  118 + n_onoff = 0
  119 + for obs in self.obs():
  120 + if obs.classname() == 'GCTAObservation':
  121 + if obs.eventtype() == 'CountsCube':
  122 + n_binned += 1
  123 + else:
  124 + n_unbinned += 1
  125 + elif obs.classname() == 'GCTAOnOffObservation':
  126 + n_onoff += 1
  127 +
  128 + # Check that we have at least one unbinned or binned CTA observation
  129 + if n_unbinned == 0 and n_binned == 0:
  130 + msg = 'No unbinned or binned CTA observations found. ' \
  131 + 'Please provide at least one unbinned or binned ' \
  132 + 'CTA observation.'
  133 + raise RuntimeError(msg)
  134 +
  135 + # Set observation statistic
  136 + self._set_obs_statistic(gammalib.toupper(self['statistic'].string()))
  137 +
  138 + # Set models if there are none in the container
  139 + if self.obs().models().size() == 0:
  140 + self.obs().models(self['inmodel'].filename())
  141 +
  142 + # Query exclusion region
  143 + self["inexclusion"].query()
  144 +
  145 + # Query the map definition parameters
  146 + self['xref'].real()
  147 + self['yref'].real()
  148 + self['coordsys'].string()
  149 + self['proj'].string()
  150 + self['nxpix'].integer()
  151 + self['nypix'].integer()
  152 +
  153 + # Compute the size of the ROIs for the analysis in deg
  154 + self._roisz = self['binsz'].real() * self['roisz'].real()
  155 +
  156 + # Query energy boundaries
  157 + self["emin"].real()
  158 + self["emax"].real()
  159 +
  160 + # If we have unbinned observations query the analysis method
  161 + if n_unbinned > 0:
  162 + # If method is ONOFF query some csphagen parameters
  163 + if self['method'].string() == 'ONOFF':
  164 + pass
  165 + # TODO: implement Onoff analysis
  166 + # self["enumbins"].integer()
  167 + # self['use_model_bkg'].boolean()
  168 + # if self["bkgmethod"].string() == "REFLECTED":
  169 + # self["srcshape"].string()
  170 + # self["bkgregmin"].integer()
  171 + # self["maxoffset"].real()
  172 + # self["etruemin"].real()
  173 + # self["etruemax"].real()
  174 + # self["etruebins"].integer()
  175 +
  176 + # Query target source names
  177 + srcnames = self['srcnames'].string()
  178 +
  179 + # Fashion target sources into Python list
  180 + self._srcnames = srcnames.split(';')
  181 + # Strip leading and trailing spaces from names
  182 + for s, name in enumerate(self._srcnames):
  183 + self._srcnames[s] = name.strip()
  184 +
  185 + # Verify that the target sources are in the model
  186 + src_in_model = True
  187 + for name in self._srcnames:
  188 + src_in_model = src_in_model and self.obs().models().contains(name)
  189 + if src_in_model == False:
  190 + msg = 'Not all target sources are present in input model.'
  191 + raise RuntimeError(msg)
  192 +
  193 + # Query the hidden parameters, just in case
  194 + self['edisp'].boolean()
  195 + self['calc_ulim'].boolean()
  196 + self['calc_ts'].boolean()
  197 + self['fix_bkg'].boolean()
  198 + self['fix_srcs'].boolean()
  199 +
  200 + # Read ahead output parameters
  201 + if self._read_ahead():
  202 + self['outfile'].query()
89 203
90 # Write input parameters into logger 204 # Write input parameters into logger
91 self._log_parameters(gammalib.TERSE) 205 self._log_parameters(gammalib.TERSE)
92 206
  207 + # Set number of processes for multiprocessing
  208 + self._nthreads = mputils.nthreads(self)
  209 +
  210 + # Return
  211 + return
  212 +
  213 + def _create_map(self):
  214 + """
  215 + Create a gammalib.GSkyMap object to store the output
  216 +
  217 + Returns
  218 + -------
  219 + skymap : `~gammalib.GSkyMap`
  220 + """
  221 +
  222 + skymap = gammalib.GSkyMap(self['proj'].string(), self['coordsys'].string(),
  223 + self['xref'].real(), self['yref'].real(),
  224 + -self['binsz'].real(), self['binsz'].real(),
  225 + self['nxpix'].integer(), self['nypix'].integer(),
  226 + 1)
  227 +
  228 + return skymap
  229 +
  230 + def _adjust_model_pars(self):
  231 + """
  232 + Adjust model parameters
  233 + """
  234 + # Write header
  235 + self._log_header1(gammalib.TERSE, 'Adjust model parameters')
  236 +
  237 + # Adjust model parameters dependent on input user parameters
  238 + for model in self.obs().models():
  239 +
  240 + # Initialise TS flag for all models to false
  241 + model.tscalc(False)
  242 +
  243 + # Log model name
  244 + self._log_header3(gammalib.EXPLICIT, model.name())
  245 +
  246 + # Freeze all parameters except the normalization
  247 + # which is assumed to be the first spectral parameter
  248 + normpar = model.spectral()[0]
  249 + for par in model:
  250 + if par.name() == normpar.name():
  251 + pass
  252 + else:
  253 + if par.is_free():
  254 + self._log_string(gammalib.EXPLICIT, ' Fixing "' + par.name() + '"')
  255 + par.fix()
  256 +
  257 + # Deal with the target sources
  258 + if model.name() in self._srcnames:
  259 +
  260 + # Free the normalisation parameter which is assumed to be
  261 + # the first spectral parameter
  262 + if normpar.is_fixed():
  263 + self._log_string(gammalib.EXPLICIT, ' Freeing "'+normpar.name()+'"')
  264 + normpar.free()
  265 +
  266 + # Optionally compute Test Statistic value
  267 + if self['calc_ts'].boolean():
  268 + model.tscalc(True)
  269 +
  270 + # Deal with background models
  271 + elif self['fix_bkg'].boolean() and not model.classname() == 'GModelSky':
  272 +
  273 + if normpar.is_free():
  274 + self._log_string(gammalib.EXPLICIT, ' Fixing "'+normpar.name()+'"')
  275 + normpar.fix()
  276 +
  277 +
  278 + # Deal with background sources
  279 + elif self['fix_srcs'].boolean() and model.classname() == 'GModelSky':
  280 +
  281 + if normpar.is_free():
  282 + self._log_string(gammalib.EXPLICIT, ' Fixing "'+normpar.name()+'"')
  283 + normpar.fix()
  284 +
93 # Return 285 # Return
94 return 286 return
95 287
  288 + def _mask_cube(self,obs,ra,dec,rad):
  289 + """
  290 + Mask cube observation
  291 +
  292 + Parameters
  293 + ----------
  294 + obs : `gammalib.GCTAObservation` Input observation of type cube
  295 + ra : `float` R.A. (deg)
  296 + dec : `float` Dec (deg)
  297 + rad : `float` radius (deg)
  298 +
  299 + Returns
  300 + -------
  301 + new_obs : `gammalib.GCTAObservation`
  302 + Output observation with masked cube
  303 + """
  304 +
  305 + # Put observation in container
  306 + container = gammalib.GObservations()
  307 + container.append(obs)
  308 +
  309 + # Filter cube according to ROI and user energy range
  310 + cubemask = ctools.ctcubemask(container)
  311 + cubemask['ra'] = ra
  312 + cubemask['dec'] = dec
  313 + cubemask['rad'] = rad
  314 + cubemask['regfile'] = 'NONE'
  315 + cubemask['emin'] = self['emin'].real()
  316 + cubemask['emax'] = self['emax'].real()
  317 + cubemask.run()
  318 +
  319 + # Get deep copy of filtered observation
  320 + new_obs = cubemask.obs()[0].copy()
  321 +
  322 + # Return
  323 + return new_obs
  324 +
  325 + def _mask_evlist(self,obs,ra,dec,rad):
  326 + """
  327 + Mask event list
  328 +
  329 + Parameters
  330 + ----------
  331 + obs : `gammalib.GCTAObservation` Input observation of type cube
  332 + ra : `float` R.A. (deg)
  333 + dec : `float` Dec (deg)
  334 + rad : `float` radius (deg)
  335 +
  336 + Returns
  337 + -------
  338 + new_obs : `gammalib.GCTAObservation`
  339 + Output observation with masked event list
  340 + """
  341 +
  342 + # Put observation in container
  343 + container = gammalib.GObservations()
  344 + container.append(obs)
  345 +
  346 + # Filter event list according to ROI and user energy range
  347 + select = ctools.ctselect(container)
  348 + select['ra'] = ra
  349 + select['dec'] = dec
  350 + select['rad'] = rad
  351 + select['emin'] = self['emin'].real()
  352 + select['emax'] = self['emax'].real()
  353 + select['tmin'] = 'INDEF'
  354 + select['tmax'] = 'INDEF'
  355 + select.run()
  356 +
  357 + # Get deep copy of filtered observation
  358 + new_obs = select.obs()[0].copy()
  359 +
  360 + # Return
  361 + return new_obs
  362 +
  363 + def _mask_onoff(self,obs,ra,dec,rad):
  364 + """
  365 + Create On/Off observation
  366 + with On region matching the required mask
  367 +
  368 + Parameters
  369 + ----------
  370 + obs : `gammalib.GCTAObservation` Input observation of type cube
  371 + ra : `float` R.A. (deg)
  372 + dec : `float` Dec (deg)
  373 + rad : `float` radius (deg)
  374 +
  375 + Returns
  376 + -------
  377 + new_obs : `gammalib.GCTAOnoffObservation`
  378 + Output On/Off observation
  379 + """
  380 +
  381 + # Put observation in container
  382 + container = gammalib.GObservations()
  383 + container.append(obs)
  384 +
  385 + onoff_obs = obsutils.get_onoff_obs(self, container, ra=ra, dec=dec, rad=rad)
  386 +
  387 + return onoff_obs[0]
  388 +
  389 + def _mask_observations(self,ra,dec,rad):
  390 + """
  391 + Create observations restricted to circular ROI
  392 +
  393 + Parameters
  394 + ----------
  395 + ra : `float` R.A. (deg)
  396 + dec : `float` Dec (deg)
  397 + rad : `float` radius (deg)
  398 +
  399 + Returns
  400 + -------
  401 + new_obs : `~gammalib.GObservations`
  402 + Observations in circular ROI
  403 + """
  404 +
  405 + # Create output observation container
  406 + new_obs = gammalib.GObservations()
  407 +
  408 + # Loop over input observations
  409 + for obs in self.obs():
  410 + if obs.classname() == 'GCTAObservation':
  411 + if obs.eventtype() == 'CountsCube':
  412 + masked_obs = self._mask_cube(obs,ra,dec,rad)
  413 + else:
  414 + if self['method'].string() == '3D':
  415 + masked_obs = self._mask_evlist(obs,ra,dec,rad)
  416 + elif self['method'].string() == 'ONOFF':
  417 + pass
  418 + # TODO: implement Onoff analysis
  419 + # masked_obs = self._mask_onoff(obs, ra, dec, rad)
  420 + new_obs.append(masked_obs)
  421 + # Skip On-Off and non-CTA observations
  422 + else:
  423 + pass
  424 +
  425 + # Append models to output observations
  426 + new_obs.models(self.obs().models())
  427 +
  428 + # Return
  429 + return new_obs
  430 +
  431 + def _pixel_analysis(self,ra,dec):
  432 + """
  433 + Performs analysis over the region of interest
  434 + corresponding to a single pixel of output map
  435 +
  436 + Parameters
  437 + ----------
  438 + inx : `int` pixel index
  439 + ra : `float` R.A. (deg)
  440 + dec : `float` Dec (deg)
  441 +
  442 + Returns
  443 + -------
  444 + result : `dict` Results
  445 + """
  446 +
  447 + # Write header for spatial bin
  448 + msg = 'Spatial bin centred on (R.A.,Dec) = (%f,%f) deg' % (ra,dec)
  449 + self._log_header2(gammalib.EXPLICIT, msg)
  450 +
  451 + # Initialize results
  452 + result = {}
  453 + for name in self._srcnames:
  454 + result[name] = {'flux' : 0.0,
  455 + 'flux_err': 0.0,
  456 + 'TS' : 0.0,
  457 + 'ulimit' : 0.0}
  458 +
  459 + # Mask observations
  460 + self._log_header3(gammalib.EXPLICIT, 'Masking observations')
  461 + masked_obs = self._mask_observations(ra,dec,self._roisz)
  462 +
  463 + # Set up likelihood analysis
  464 + self._log_header3(gammalib.EXPLICIT, 'Performing fit in energy bin')
  465 + like = ctools.ctlike(masked_obs)
  466 + like['edisp'] = self['edisp'].boolean()
  467 + like['nthreads'] = 1 # Avoids OpenMP conflict
  468 +
  469 + # If chatter level is verbose and debugging is requested then
  470 + # switch also on the debug model in ctlike
  471 + if self._logVerbose() and self._logDebug():
  472 + like['debug'] = True
  473 +
  474 + # Perform maximum likelihood fit
  475 + like.run()
  476 +
  477 + # Write model results for explicit chatter level
  478 + self._log_string(gammalib.EXPLICIT, str(like.obs().models()))
  479 +
  480 + # Prepare objects for flux extraction
  481 + # ROI
  482 + centre = gammalib.GSkyDir()
  483 + centre.radec_deg(ra,dec)
  484 + roi = gammalib.GSkyRegionCircle(centre,self._roisz)
  485 + # Energy boundaries
  486 + emin = gammalib.GEnergy(self['emin'].real(),'TeV')
  487 + emax = gammalib.GEnergy(self['emax'].real(), 'TeV')
  488 +
  489 + # Continue only if log-likelihood is non-zero
  490 + if like.obs().logL() != 0.0:
  491 +
  492 + # Loop over target sources
  493 + for name in self._srcnames:
  494 +
  495 + # Get source
  496 + source = like.obs().models()[name]
  497 +
  498 + # Get flux
  499 + # Integrate spectral model between emin and emax
  500 + flux = source.spectral().flux(emin,emax)
  501 + # Multiply by flux from spatial component in ROI
  502 + flux *= source.spatial().flux(roi)
  503 + # Divide by solid angle of ROI
  504 + flux /= 1 - math.cos(math.radians(self._roisz))
  505 + result[name]['flux'] = flux
  506 +
  507 + # Get flux error
  508 + # Normalization parameter
  509 + normpar = source.spectral()[0]
  510 + # Only normalization parameter free
  511 + # Relative error on flux is same as on normalization
  512 + # Avoid zero division error
  513 + if normpar.value() > 0.:
  514 + flux_error = flux * normpar.error()/normpar.value()
  515 + else:
  516 + flux_error = 0.
  517 + result[name]['flux_error'] = flux_error
  518 +
  519 + # If requested get TS
  520 + if self['calc_ts'].boolean():
  521 + result[name]['TS'] = source.ts()
  522 +
  523 + # Upper limit
  524 + # TODO
  525 +
  526 + else:
  527 + value = 'Likelihood is zero. Bin is skipped.'
  528 + self._log_value(gammalib.TERSE, '(R.A.,Dec) = (%f,%f) deg' % (ra,dec), value)
  529 +
  530 + # Return result
  531 + return result
  532 +
  533 + def _fill_fits(self,results):
  534 + """
  535 + Fill FITS object to store the results
  536 +
  537 + Parameters
  538 + ----------
  539 + result : `dict` Results
  540 +
  541 + Returns
  542 + -------
  543 + fits : `~gammalib.GFits` Fits object
  544 + """
  545 +
  546 + # Create new Fits object
  547 + fits = gammalib.GFits()
  548 +
  549 + # If more than one source of interest
  550 + # append empty primary HDU
  551 + if len(self._srcnames) > 1:
  552 + fits.append(gammalib.GFitsImageDouble())
  553 +
  554 + # Prepare some header cards
  555 + # Flux units
  556 + fcard = gammalib.GFitsHeaderCard('BUNIT', 'ph/cm2/s/sr' , 'Photon flux')
  557 + txt = 'Correlation radius %f deg' %(self._roisz)
  558 + roiszcard = gammalib.GFitsHeaderCard('COMMENT', '' , txt)
  559 +
  560 + # Loop over target sources
  561 + for s, name in enumerate(self._srcnames):
  562 +
  563 + # Create minimal set of skymaps to store fluxes and flux errors
  564 + fmap = self._create_map()
  565 + errmap = self._create_map()
  566 +
  567 + #Create map for TS
  568 + if self['calc_ts'].boolean():
  569 + tsmap = self._create_map()
  570 +
  571 + # Loop over pixels and fill maps
  572 + for inx in range(fmap.npix()):
  573 +
  574 + # Fill flux and flux error
  575 + fmap[inx,0] = results[inx][name]['flux']
  576 + errmap[inx, 0] = results[inx][name]['flux_error']
  577 +
  578 + # If requested fill TS
  579 + if self['calc_ts'].boolean():
  580 + tsmap[inx, 0] = results[inx][name]['TS']
  581 +
  582 + # Write maps to Fits
  583 + fhdu = fmap.write(fits, name + ' FLUX')
  584 + errhdu = errmap.write(fits, name + ' FLUX ERROR')
  585 +
  586 + # Add units and comments to headers
  587 + fhdu.header().append(fcard)
  588 + errhdu.header().append(fcard)
  589 + fhdu.header().append(roiszcard)
  590 + errhdu.header().append(roiszcard)
  591 +
  592 + # If requested write TS map to fits
  593 + if self['calc_ts'].boolean():
  594 + tshdu = tsmap.write(fits, name + ' TS')
  595 + tshdu.header().append(roiszcard)
  596 +
  597 + # Return
  598 + return fits
  599 +
96 600
97 # Public methods 601 # Public methods
98 def run(self): 602 def run(self):
@@ -106,23 +610,77 @@ class csscs(ctools.csobservation): @@ -106,23 +610,77 @@ class csscs(ctools.csobservation):
106 # Get parameters 610 # Get parameters
107 self._get_parameters() 611 self._get_parameters()
108 612
109 - # TODO: Your code goes here 613 + # Write input observation container into logger
  614 + self._log_observations(gammalib.NORMAL, self.obs(), 'Input observation')
  615 +
  616 + # Create template for output map, to use to extract pixel values
  617 + outmap = self._create_map()
  618 +
  619 + # Adjust model parameters dependent on input user parameters
  620 + self._adjust_model_pars()
  621 +
  622 + # Loop over pixels and extract results
  623 + results = {}
  624 + for inx in range(outmap.npix()):
  625 +
  626 + # Determine pixel centre
  627 + pixdir = outmap.inx2dir(inx)
  628 + ra = pixdir.ra_deg()
  629 + dec = pixdir.dec_deg()
  630 +
  631 + # Analyse ROI
  632 + result = self._pixel_analysis(ra,dec)
  633 + results[inx] = result
  634 +
  635 + # Fill output Fits
  636 + self._fits = self._fill_fits(results)
110 637
111 # Return 638 # Return
112 return 639 return
113 640
114 def save(self): 641 def save(self):
115 """ 642 """
116 - Save something 643 + Save maps to Fits flie
117 """ 644 """
118 # Write header 645 # Write header
119 - self._log_header1(gammalib.TERSE, 'Save something') 646 + self._log_header1(gammalib.TERSE, 'Save maps')
  647 +
  648 + # Continue only if FITS file is valid
  649 + if self._fits != None:
  650 +
  651 + # Get outmap parameter
  652 + outfile = self['outfile'].filename()
120 653
121 - # TODO: Your code goes here 654 + # Log file name
  655 + self._log_value(gammalib.NORMAL, 'Output file', outfile.url())
  656 +
  657 + # Save spectrum
  658 + self._fits.saveto(outfile, self['clobber'].boolean())
122 659
123 # Return 660 # Return
124 return 661 return
125 662
  663 + def exclusion_map(self, object=None):
  664 + """
  665 + Return and optionally set the exclusion regions map
  666 +
  667 + Parameters
  668 + ----------
  669 + object : `~gammalib.GSkyRegion` or `~gammalib.GSkyMap` or `~gammalib.GFilename`
  670 + Exclusion regions object
  671 +
  672 + Returns
  673 + -------
  674 + region : `~gammalib.GSkyRegionMap`
  675 + Exclusion regions map
  676 + """
  677 + # If a regions object is provided then set the regions ...
  678 + if object is not None:
  679 + self._excl_reg_map = gammalib.GSkyRegionMap(object)
  680 +
  681 + # Return
  682 + return self._excl_reg_map
  683 +
126 684
127 # ======================== # 685 # ======================== #
128 # Main routine entry point # 686 # Main routine entry point #