Commit e991511e54f5ee19e93596921bb0166b32c91af5

Authored by Jürgen Knödlseder
1 parent 6124ca81

Adapt to ctools coding conventions, clean-up and test code, and add a unit test.

... ... @@ -2,3 +2,4 @@ Juergen Knoedlseder (jurgen.knodlseder@irap.omp.eu)
2 2 Jean-Baptiste Cayrou (cayrou@etud.insa-toulouse.fr)
3 3 Christoph Deil (Christoph.Deil@mpi-hd.mpg.de)
4 4 Michael Mayer (michael.mayer@desy.de)
  5 +Chia-Chun Lu (Chia-Chun.Lu@mpi-hd.mpg.de)
... ...
ChangeLog
1   -2014-07-18 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
  1 +2014-07-20 Juergen Knoedlseder <jurgen.knodlseder@irap.omp.eu>
2 2  
3 3 * Version 0.8.0 released
4 4 ========================
... ... @@ -6,6 +6,7 @@
6 6 Adapt to GammaLib 0.9.0 interface
7 7 ctbin now always merges event lists into a single counts cube
8 8 Add ctexpcube tool
  9 + Add ctcubemask tool
9 10 Support energy dispersion in ctobssim, ctlike and ctmodel
10 11 Correct ctobssim for thread safety
11 12 Enhance documentation
... ...
... ... @@ -2,7 +2,7 @@ New Features and Important Changes in ctools 00-08-00
2 2  
3 3 Author(s) : Juergen Knoedlseder
4 4  
5   -18 July 2014
  5 +20 July 2014
6 6  
7 7  
8 8 1. Introduction
... ... @@ -88,12 +88,19 @@ file. The cube definition may be taken from a counts map or may be
88 88 specified by user parameters.
89 89  
90 90  
91   -11. Examples
  91 +11. ctcubemask - CTA cube filtering
  92 +-----------------------------------
  93 +The first version of the ctcubemask tool is included in the release.
  94 +ctcubemask allows filtering of bins in a counts cube by setting the
  95 +bin content to -1. Filtering can be done by energy, for a circular
  96 +Region of Interest (ROI) or using ds9 exclusion regions.
  97 +
  98 +12. Examples
92 99 ------------
93 100 None
94 101  
95 102  
96   -12. Scripts
  103 +13. Scripts
97 104 -----------
98 105 Add logL and event statistics to cspull output file.
99 106  
... ... @@ -102,11 +109,11 @@ Convert all tabs into spaces.
102 109 The obsutils script has now been moved into the ctools module namespace.
103 110  
104 111  
105   -13. caldb
  112 +14. caldb
106 113 ---------
107 114 None
108 115  
109 116  
110   -14. models
  117 +15. models
111 118 ----------
112 119 None
... ...
configure.ac
... ... @@ -883,6 +883,7 @@ AC_CONFIG_FILES([Makefile
883 883 src/ctskymap/Makefile
884 884 src/ctselect/Makefile
885 885 src/ctexpcube/Makefile
  886 + src/ctcubemask/Makefile
886 887 src/ctools-setup
887 888 test/Makefile
888 889 test/test_cscripts.sh
... ...
pyext/ctcubemask.i
1 1 /***************************************************************************
2   - * ctcubemask - CTA mask cube tool *
  2 + * ctcubemask.i - CTA mask cube tool *
3 3 * ----------------------------------------------------------------------- *
4 4 * copyright (C) 2014 Chia-Chun Lu *
5 5 * ----------------------------------------------------------------------- *
... ... @@ -20,7 +20,7 @@
20 20 ***************************************************************************/
21 21 /**
22 22 * @file ctcubemask.i
23   - * @brief CTA data selection tool Python interface definition
  23 + * @brief CTA mask cube interface definition
24 24 * @author Chia-Chun Lu
25 25 */
26 26 %{
... ... @@ -49,9 +49,9 @@ public:
49 49 void execute(void);
50 50 void run(void);
51 51 void save(void);
52   - GObservations& obs(void) { return m_obs; }
  52 + GObservations& obs(void);
53 53 void get_parameters(void);
54   - void apply_mask(GCTAObservation* obs, const std::string& filename);
  54 + void apply_mask(GCTAObservation* obs);
55 55 };
56 56  
57 57  
... ...
src/Makefile.am
... ... @@ -12,7 +12,7 @@ SUBDIRS = ctbin \
12 12 ctselect \
13 13 ctskymap \
14 14 ctexpcube \
15   - ctcubemask
  15 + ctcubemask
16 16  
17 17 # Scripts to be distributed
18 18 scripts = ctools-setup \
... ... @@ -31,7 +31,7 @@ libctools_la_LIBADD = ctbin/libctbin.la \
31 31 ctselect/libctselect.la \
32 32 ctskymap/libctskymap.la \
33 33 ctexpcube/libctexpcube.la \
34   - ctcubemask/libctcubemask.la
  34 + ctcubemask/libctcubemask.la
35 35  
36 36 # Distribute scripts
37 37 EXTRA_DIST = $(scripts)
... ...
src/ctcubemask/ctcubemask.cpp
1 1 /***************************************************************************
2   - * ctfilter - CTA cube filter tool *
  2 + * ctcubemask.cpp - CTA cube filter tool *
3 3 * ----------------------------------------------------------------------- *
4 4 * copyright (C) 2014 by Chia-Chun Lu *
5 5 * ----------------------------------------------------------------------- *
... ... @@ -34,9 +34,8 @@
34 34  
35 35  
36 36 /* __ Method name definitions ____________________________________________ */
37   -#define G_RUN "ctcubemask::run()"
38   -#define G_APPLY_MASK "ctcubemask::apply_mask(GCTAObservation*,"\
39   - "std::string&)"
  37 +#define G_RUN "ctcubemask::run()"
  38 +#define G_APPLY_MASK "ctcubemask::apply_mask(GCTAObservation*)"
40 39  
41 40 /* __ Debug definitions __________________________________________________ */
42 41  
... ... @@ -96,7 +95,7 @@ ctcubemask::ctcubemask(GObservations obs) : GApplication(CTCUBEMASK_NAME, CTCUBE
96 95 * @param[in] argv Array of command line arguments.
97 96 ***************************************************************************/
98 97 ctcubemask::ctcubemask(int argc, char *argv[]) :
99   - GApplication(CTCUBEMASK_NAME, CTCUBEMASK_VERSION, argc, argv)
  98 + GApplication(CTCUBEMASK_NAME, CTCUBEMASK_VERSION, argc, argv)
100 99 {
101 100 // Initialise members
102 101 init_members();
... ... @@ -151,7 +150,7 @@ ctcubemask::~ctcubemask(void)
151 150 *
152 151 * @param[in] app Application.
153 152 ***************************************************************************/
154   -ctcubemask& ctcubemask::operator= (const ctcubemask& app)
  153 +ctcubemask& ctcubemask::operator=(const ctcubemask& app)
155 154 {
156 155 // Execute only if object is not identical
157 156 if (this != &app) {
... ... @@ -287,33 +286,9 @@ void ctcubemask::run(void)
287 286 // Save event file name (for possible saving)
288 287 m_infiles[i] = obs->eventfile();
289 288  
290   - // Get temporary file name
291   - std::string filename = std::tmpnam(NULL);
292   -
293   - // Save observation in temporary file
294   - obs->save(filename, true);
295   -
296   - // Log saved FITS file
297   - if (logExplicit()) {
298   - GFits tmpfile(filename);
299   - log << std::endl;
300   - log.header1("FITS file content of temporary file");
301   - log << tmpfile << std::endl;
302   - tmpfile.close();
303   - }
304   -
305   - // Check temporary file
306   - std::string message = check_infile(filename);
307   - if (message.length() > 0) {
308   - throw GException::app_error(G_RUN, message);
309   - }
310   -
311 289 // Load observation from temporary file, including event selection
312   - apply_mask(obs, filename);
  290 + apply_mask(obs);
313 291  
314   - // Remove temporary file
315   - std::remove(filename.c_str());
316   -
317 292 } // endif: had a CTA observation
318 293  
319 294 } // endfor: looped over all observations
... ... @@ -409,7 +384,7 @@ void ctcubemask::get_parameters(void)
409 384 try {
410 385  
411 386 // Load event list in CTA observation
412   - obs.load_binned(m_infile);
  387 + obs.load(m_infile);
413 388  
414 389 // Append CTA observation to container
415 390 m_obs.append(obs);
... ... @@ -455,115 +430,119 @@ void ctcubemask::get_parameters(void)
455 430  
456 431  
457 432 /***********************************************************************//**
458   - * @brief Select events
  433 + * @brief Apply mask to counts cube
459 434 *
460 435 * @param[in] obs CTA observation.
461   - * @param[in] filename File name.
462 436 *
463   - * Select events from a FITS file by making use of the selection possibility
464   - * of the cfitsio library on loading a file. A selection string is created
465   - * from the specified criteria that is appended to the filename so that
466   - * cfitsio will automatically filter the event data. This selection string
467   - * is then applied when opening the FITS file. The opened FITS file is then
468   - * saved into a temporary file which is the loaded into the actual CTA
469   - * observation, overwriting the old CTA observation. The ROI, GTI and EBounds
470   - * of the CTA event list are then set accordingly to the specified selection.
471   - * Finally, the temporary file created during this process is removed.
472   - *
473   - * Good Time Intervals of the observation will be limited to the time
474   - * interval [m_tmin, m_tmax]. If m_tmin=m_tmax=0, no time selection is
475   - * performed.
476   - *
477   - * @todo Use INDEF instead of 0.0 for pointing as RA/DEC selection
  437 + * Masks out event bins by setting their content to -1.
478 438 ***************************************************************************/
479   -void ctcubemask::apply_mask(GCTAObservation* obs, const std::string& filename)
  439 +void ctcubemask::apply_mask(GCTAObservation* obs)
480 440 {
481   - std::cout<< "start appply filter" << std::endl;
482   - // Open FITS file
483   - GFits file(filename);
484   - GCTAEventCube* cube = (GCTAEventCube*) obs->events();
485   - GEbounds ebounds = cube->ebounds();
486   - GSkymap map = cube->map();
487   -
488   - // Apply energy selection
489   - int e_idx1 = 0;
490   - int e_idx2 = 0;
491   - int n_ebin = ebounds.size();
492   -
493   - // Loop over ebounds to find the first energy band
494   - for ( int i = 0 ; i < ebounds.size() ; i++){
495   - double emin = ebounds.emin(i).TeV();
496   - if ( emin > m_emin ){
497   - e_idx1 = i;
498   - break;
499   - }
500   - }
  441 + // Get pointer to CTA event cube. Continue only if we have a cube
  442 + GCTAEventCube* cube = dynamic_cast<GCTAEventCube*>(const_cast<GEvents*>(obs->events()));
  443 + if (cube != NULL) {
  444 +
  445 + // Extract event cube and energy boundaries
  446 + GSkymap map = cube->map();
  447 + const GEbounds& ebounds = cube->ebounds();
  448 +
  449 + // Initialise energy selection
  450 + int n_ebin = ebounds.size();
  451 + int e_idx1 = 0;
  452 + int e_idx2 = n_ebin;
  453 +
  454 + // Loop over ebounds to find the first valid energy band
  455 + for (int i = 0; i < n_ebin; ++i) {
  456 + double emin = ebounds.emin(i).TeV() + 1.0e-6; // Rounding tolerance
  457 + if (emin >= m_emin) {
  458 + e_idx1 = i;
  459 + break;
  460 + }
  461 + }
501 462  
502   - std::cout << "finish looping over ebounds to find 1st" << std::endl;
503   - std::cout << "e_ix1 " << e_idx1 << std::endl;
  463 + // Loop over ebounds to find the last valid energy band
  464 + for (int i = n_ebin-1; i >= 0; i--) {
  465 + double emax = ebounds.emax(i).TeV() - 1.0e-6; // Rounding tolerance
  466 + if (emax <= m_emax) {
  467 + e_idx2 = i;
  468 + break;
  469 + }
  470 + }
504 471  
505   - // Loop over ebounds to find the last energy band
506   - for ( int i = ebounds.size()-1 ; i < ebounds.size() ; i--){
507   - double emin = ebounds.emin(i).TeV();
508   - if ( emin < m_emax ){
509   - e_idx2 = i-1;
510   - break;
511   - }
512   - }
513   - std::cout << "finish looping over ebounds to find 1st" << std::endl;
514   - std::cout << "e_ix2 " << e_idx2 << std::endl;
515   -
516   - // Set all pixels outside the desired energy bands negative
517   - int npix = map.npix();
518   - for ( int i = 0 ; i < e_idx1 ; i++){
519   - for ( int pixel = 0 ; pixel < npix ; pixel++){
520   - map(pixel,i) = -1;
521   - }
522   - }
523   - for ( int i = e_idx2 ; i < ebounds.size() ; i++){
524   - for ( int pixel = 0 ; pixel < npix ; pixel++){
525   - map(pixel,i) = -1;
526   - }
527   - }
528   - std::cout << "finish energy band filter" << std::endl;
529   -
530   -
531   -
532   - // Set all pixels inside the desired energy bands
533   - // but outside ROI or inside exlusion regions negative
534   - GSkyRegions regs = GSkyRegions(m_regfile);
535   - GSkyRegionCircle roi = GSkyRegionCircle(m_ra, m_dec, m_rad);
536   - for ( int i = e_idx1 ; i <= e_idx2 ; i++){
537   - for ( int pixel = 0 ; pixel < npix ; pixel++){
538   - GSkyDir dir = map.inx2dir(pixel);
539   - if ( roi.contains(dir) == false ||
540   - regs.contains(dir) == true){
541   - map(pixel,i) = -1;
542   - }
543   - }
544   - }
545   - std::cout << "finish roi selection" << std::endl;
546   -
547   - GCTAEventCube newcube( map, ebounds, obs->events()->gti());
548   - obs->events(newcube);
  472 + // Set all pixels outside the desired energy bands to -1.0
  473 + int npix = map.npix();
  474 + for (int i = 0; i < e_idx1; ++i) {
  475 + for (int pixel = 0; pixel < npix; ++pixel) {
  476 + map(pixel,i) = -1.0;
  477 + }
  478 + }
  479 + for (int i = e_idx2 + 1; i < n_ebin; ++i) {
  480 + for (int pixel = 0; pixel < npix; ++pixel) {
  481 + map(pixel,i) = -1.0;
  482 + }
  483 + }
549 484  
550   - // Log selected FITS file
551   - if (logExplicit()) {
552   - log << std::endl;
553   - log.header1("FITS file content after filter");
554   - log << file << std::endl;
555   - }
  485 + // Log selected energy band
  486 + if (logTerse()) {
  487 + log << gammalib::parformat("Selected energy band");
  488 + log << ebounds.emin(e_idx1).TeV() << " - ";
  489 + log << ebounds.emax(e_idx2).TeV() << " TeV";
  490 + log << std::endl;
  491 + }
556 492  
557   - // Check if we have an IMAGE HDU
558   - if (!file.contains("IMAGE")) {
559   - std::string message = "No \"IMAGE\" extension found in FITS file. ";
560   - throw GException::app_error(G_APPLY_MASK, message);
561   - }
  493 + // Set all pixels inside selected energy bands but outside ROI
  494 + // to -1.0
  495 + GSkyRegionCircle roi(m_ra, m_dec, m_rad);
  496 + for (int i = e_idx1; i <= e_idx2; ++i) {
  497 + for (int pixel = 0; pixel < npix; ++pixel) {
  498 + GSkyDir dir = map.inx2dir(pixel);
  499 + if (!roi.contains(dir)) {
  500 + map(pixel,i) = -1.0;
  501 + }
  502 + }
  503 + }
  504 +
  505 + // Log selected energy band
  506 + if (logTerse()) {
  507 + log << gammalib::parformat("Selected ROI");
  508 + log << "RA=" << m_ra << " deg, ";
  509 + log << "DEC=" << m_dec << " deg, ";
  510 + log << "Radius=" << m_rad << " deg";
  511 + log << std::endl;
  512 + }
  513 +
  514 + // Set all pixels inside selected energy bands and inside exclusion
  515 + // regions to -1.0
  516 + if (m_regfile != "NONE") {
  517 + GSkyRegions regions = GSkyRegions(m_regfile);
  518 + for (int i = e_idx1; i <= e_idx2; ++i) {
  519 + for (int pixel = 0; pixel < npix; ++pixel) {
  520 + GSkyDir dir = map.inx2dir(pixel);
  521 + if (regions.contains(dir)) {
  522 + map(pixel,i) = -1.0;
  523 + }
  524 + }
  525 + }
  526 + if (logTerse()) {
  527 + log << gammalib::parformat("Exclusion regions");
  528 + log << std::endl;
  529 + log.indent(1);
  530 + log << regions.print();
  531 + log << std::endl;
  532 + log.indent(0);
  533 + }
  534 + }
  535 + else {
  536 + if (logTerse()) {
  537 + log << gammalib::parformat("Exclusion regions");
  538 + log << "None" << std::endl;
  539 + }
  540 + }
562 541  
  542 + // Put back map into the event cube
  543 + cube->map(map);
563 544  
564   - // Get CTA event list pointer
565   - GCTAEventList* list =
566   - static_cast<GCTAEventList*>(const_cast<GEvents*>(obs->events()));
  545 + } // endif: observation contained an event cube
567 546  
568 547 // Return
569 548 return;
... ... @@ -798,7 +777,7 @@ void ctcubemask::save_xml(void)
798 777 * nothing if the observation pointer is not valid.
799 778 ***************************************************************************/
800 779 void ctcubemask::save_counts_map(const GCTAObservation* obs,
801   - const std::string& outfile) const
  780 + const std::string& outfile) const
802 781 {
803 782 // Save only if observation is valid
804 783 if (obs != NULL) {
... ...
src/ctcubemask/ctcubemask.hpp
1 1 /***************************************************************************
2   - * ctcubemask - CTA cube filter tool *
  2 + * ctcubemask.hpp - CTA cube filter tool *
3 3 * ----------------------------------------------------------------------- *
4 4 * copyright (C) 2014 by Chia-Chun Lu *
5 5 * ----------------------------------------------------------------------- *
... ... @@ -35,7 +35,7 @@
35 35  
36 36 /* __Definitions _________________________________________________________ */
37 37 #define CTCUBEMASK_NAME "ctcubemask"
38   -#define CTCUBEMASK_VERSION "00-05-00"
  38 +#define CTCUBEMASK_VERSION "00-01-00"
39 39  
40 40  
41 41 /***********************************************************************//**
... ... @@ -53,7 +53,7 @@ public:
53 53 virtual ~ctcubemask(void);
54 54  
55 55 // Operators
56   - ctcubemask& operator= (const ctcubemask& app);
  56 + ctcubemask& operator=(const ctcubemask& app);
57 57  
58 58 // Methods
59 59 void clear(void);
... ... @@ -62,7 +62,7 @@ public:
62 62 void save(void);
63 63 GObservations& obs(void) { return m_obs; }
64 64 void get_parameters(void);
65   - void apply_mask(GCTAObservation* obs, const std::string& filename);
  65 + void apply_mask(GCTAObservation* obs);
66 66  
67 67 protected:
68 68 // Protected methods
... ...
src/ctcubemask/ctcubemask.par
... ... @@ -4,23 +4,23 @@
4 4 # #
5 5 # ------------------------------------------------------------------------- #
6 6 # #
7   -# File: ctfilter.par #
8   -# Version: 00-04-00 #
  7 +# File: ctcubemask.par #
  8 +# Version: 00-01-00 #
9 9 # #
10 10 # Author: Chia-Chun Lu #
11 11 # c.lu@mpi-hd.mpg.de #
12 12 # IRAP #
13 13 # #
14   -# Purpose: Parameter file for the ctselect application #
  14 +# Purpose: Parameter file for the ctcubemask application #
15 15 # #
16 16 #############################################################################
17 17 #
18 18 # File information
19 19 #=================
20   -infile, f, a, "test/data/crab_events.fits.gz",,,"Input event list or observation definition file"
21   -regfile, f, a, "exlusion.reg",,,"exclusion region file in ds9 format"
22   -outfile, f, a, "filtered_cube.fits",,,"Output event list or observation definition file"
23   -prefix, s, h, "filtered_",,,"Prefix for counts maps in observation definition file"
  20 +infile, f, a, "cntmap.fits",,,"Input counts cube or observation definition file"
  21 +regfile, f, a, "NONE",,,"Exclusion region file in ds9 format"
  22 +outfile, f, a, "filtered_cube.fits",,,"Output event cube or observation definition file"
  23 +prefix, s, h, "filtered_",,,"Prefix for counts cube in observation definition file"
24 24 #
25 25 # Selection parameters
26 26 #=====================
... ...
test/data/exclusion.reg 0 → 100644
  1 +# Region file format: DS9 version 4.1
  2 +global color=green dashlist=8 3 width=1 font="helvetica 10 normal roman" select=1 highlite=1 dash=0 fixed=0 edit=1 move=1 delete=1 include=1 source=1
  3 +fk5
  4 +circle(83.63, 21.5, 0.4)
... ...
test/test_ctools.sh
... ... @@ -41,6 +41,7 @@ ctobssim=../src/ctobssim/ctobssim
41 41 ctselect=../src/ctselect/ctselect
42 42 ctskymap=../src/ctskymap/ctskymap
43 43 ctexpcube=../src/ctexpcube/ctexpcube
  44 +ctcubemask=../src/ctcubemask/ctcubemask
44 45  
45 46  
46 47 #
... ... @@ -387,3 +388,25 @@ else
387 388 $ECHO " expcube2.fits file is not valid"
388 389 exit 1
389 390 fi
  391 +
  392 +
  393 +#
  394 +# Test ctcubemask
  395 +# ===============
  396 +$ECHO -n "Test ctcubemask: "
  397 +$ctcubemask infile="data/crab_events.fits" \
  398 + regfile="data/exclusion.reg" \
  399 + outfile="filtered_cube.fits" \
  400 + ra=83.63 \
  401 + dec=22.01 \
  402 + rad=2.0 \
  403 + emin=0.1 \
  404 + emax=100.0
  405 +$ECHO -n "."
  406 +if [ -s "filtered_cube.fits" ]
  407 +then
  408 + $ECHO -n "."
  409 +else
  410 + $ECHO " filtered_cube.fits file is not valid"
  411 + exit 1
  412 +fi
... ...