ctools 2.1.0.dev
Loading...
Searching...
No Matches
ctcubemask.cpp
Go to the documentation of this file.
1/***************************************************************************
2 * ctcubemask - Cube filter tool *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2014-2022 by Chia-Chun Lu *
5 * ----------------------------------------------------------------------- *
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 ***************************************************************************/
21/**
22 * @file ctcubemask.cpp
23 * @brief Cube filter tool implementation
24 * @author Chia-Chun Lu
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H
29#include <config.h>
30#endif
31#include <cstdio>
32#include "ctcubemask.hpp"
33#include "GTools.hpp"
34
35
36/* __ Method name definitions ____________________________________________ */
37#define G_APPLY_MASK "ctcubemask::apply_mask(GCTAObservation*)"
38
39/* __ Debug definitions __________________________________________________ */
40
41/* __ Coding definitions _________________________________________________ */
42
43
44/*==========================================================================
45 = =
46 = Constructors/destructors =
47 = =
48 ==========================================================================*/
49
50/***********************************************************************//**
51 * @brief Void constructor
52 ***************************************************************************/
54{
55 // Initialise members
57
58 // Return
59 return;
60}
61
62
63/***********************************************************************//**
64 * @brief Observations constructor
65 *
66 * param[in] obs Observation container.
67 *
68 * This constructor creates an instance of the class that is initialised from
69 * an observation container.
70 ***************************************************************************/
71ctcubemask::ctcubemask(const GObservations& obs) :
72 ctobservation(CTCUBEMASK_NAME, VERSION, obs)
73{
74 // Initialise members
76
77 // Return
78 return;
79}
80
81
82
83
84/***********************************************************************//**
85 * @brief Command line constructor
86 *
87 * @param[in] argc Number of arguments in command line.
88 * @param[in] argv Array of command line arguments.
89 ***************************************************************************/
90ctcubemask::ctcubemask(int argc, char *argv[]) :
91 ctobservation(CTCUBEMASK_NAME, VERSION, argc, argv)
92{
93 // Initialise members
95
96 // Return
97 return;
98}
99
100
101/***********************************************************************//**
102 * @brief Copy constructor
103 *
104 * @param[in] app Application.
105 ***************************************************************************/
107{
108 // Initialise members
109 init_members();
110
111 // Copy members
112 copy_members(app);
113
114 // Return
115 return;
116}
117
118
119/***********************************************************************//**
120 * @brief Destructor
121 ***************************************************************************/
123{
124 // Free members
125 free_members();
126
127 // Return
128 return;
129}
130
131
132/*==========================================================================
133 = =
134 = Operators =
135 = =
136 ==========================================================================*/
137
138/***********************************************************************//**
139 * @brief Assignment operator
140 *
141 * @param[in] app Application.
142 * @return Application.
143 ***************************************************************************/
145{
146 // Execute only if object is not identical
147 if (this != &app) {
148
149 // Copy base class members
150 this->ctobservation::operator=(app);
151
152 // Free members
153 free_members();
154
155 // Initialise members
156 init_members();
157
158 // Copy members
159 copy_members(app);
160
161 } // endif: object was not identical
162
163 // Return this object
164 return *this;
165}
166
167
168/*==========================================================================
169 = =
170 = Public methods =
171 = =
172 ==========================================================================*/
173
174/***********************************************************************//**
175 * @brief Clear ctcubemask tool
176 *
177 * Clears ctcubemask tool.
178 ***************************************************************************/
180{
181 // Free members
182 free_members();
184 this->ctool::free_members();
185
186 // Clear base class (needed to conserve tool name and version)
187 this->GApplication::clear();
188
189 // Initialise members
190 this->ctool::init_members();
192 init_members();
193
194 // Write header into logger
195 log_header();
196
197 // Return
198 return;
199}
200
201
202/***********************************************************************//**
203 * @brief Mask data cube
204 *
205 * This method reads in the application parameters and loops over all
206 * observations that were found to apply a mask on the event cube.
207 ***************************************************************************/
209{
210 // Get parameters
212
213 // Write input observation container into logger
214 log_observations(NORMAL, m_obs, "Input observation");
215
216 // Write header into logger
217 log_header1(TERSE, "Apply mask");
218
219 // Initialise counters
220 int n_observations = 0;
221
222 // Loop over all observation in the container
223 for (int i = 0; i < m_obs.size(); ++i) {
224
225 // Initialise event input and output filenames
226 m_infiles.push_back("");
227
228 // Get CTA observation
229 GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]);
230
231 // Continue only if observation is a CTA observation
232 if (obs != NULL) {
233
234 // Write header for the current observation
235 log_header3(TERSE, get_obs_header(obs));
236
237 // Increment counter
238 n_observations++;
239
240 // Save event file name (for possible saving)
241 m_infiles[i] = obs->eventfile();
242
243 // Apply mask on the event cube
245
246 } // endif: had a CTA observation
247
248 } // endfor: looped over all observations
249
250 // If more than a single observation has been handled then make sure that
251 // an XML file will be used for storage
252 if (n_observations > 1) {
253 m_use_xml = true;
254 }
255
256 // Write resulting observation container into logger
257 log_observations(NORMAL, m_obs, "Observations after event bin masking");
258
259 // Optionally publish counts cube
260 if (m_publish) {
261 publish();
262 }
263
264 // Return
265 return;
266}
267
268
269/***********************************************************************//**
270 * @brief Save the masked event cube(s)
271 *
272 * This method saves the masked event cube(s) into FITS file(s). There are
273 * two modes, depending on the m_use_xml flag.
274 *
275 * If m_use_xml is true, all masked event cube(s) will be saved into FITS
276 * files, where the output filenames are constructued from the input
277 * filenames by prepending the m_prefix string to name. Any path information
278 * will be stripped form the input name, hence event cube files will be written
279 * into the local working directory (unless some path information is present
280 * in the prefix). In addition, an XML file will be created that gathers
281 * the filename information for the masked event cube(s). If an XML file
282 * was present on input, all metadata information will be copied from this
283 * input file.
284 *
285 * If m_use_xml is false, the masked event cubes will be saved into a FITS
286 * file.
287 ***************************************************************************/
289{
290 // Write header into logger
291 log_header1(TERSE, gammalib::number("Save counts cube", m_obs.size()));
292
293 // Get counts cube filename
294 m_outcube = (*this)["outcube"].filename();
295
296 // Case A: Save counts cube(s) and XML metadata information
297 if (m_use_xml) {
298
299 // Get prefix
300 m_prefix = (*this)["prefix"].string();
301
302 // Save XML
303 save_xml();
304 }
305
306 // Case B: Save counts cube as FITS file
307 else {
308 save_fits();
309 }
310
311 // Return
312 return;
313}
314
315
316/***********************************************************************//**
317 * @brief Publish counts cube
318 *
319 * @param[in] name Counts cube name.
320 *
321 * Publishes the first counts cube in the observation container on the VO
322 * Hub.
323 ***************************************************************************/
324void ctcubemask::publish(const std::string& name)
325{
326 // Write header into logger
327 log_header1(TERSE, "Publish counts cube");
328
329 // Set default name is user name is empty
330 std::string user_name(name);
331 if (user_name.empty()) {
332 user_name = CTCUBEMASK_NAME;
333 }
334
335 // Get first CTA observation from observation container
336 GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[0]);
337 if (obs != NULL) {
338
339 // Get counts cube
340 GCTAEventCube* cube = dynamic_cast<GCTAEventCube*>(obs->events());
341 if (cube != NULL) {
342
343 // Log counts cube name
344 log_value(NORMAL, "Counts cube name", user_name);
345
346 // Publish counts cube
347 cube->counts().publish(user_name);
348
349 }
350 }
351
352 // Return
353 return;
354}
355
356
357/*==========================================================================
358 = =
359 = Private methods =
360 = =
361 ==========================================================================*/
362
363/***********************************************************************//**
364 * @brief Initialise class members
365 ***************************************************************************/
367{
368 // Initialise parameters
369 m_outcube.clear();
370 m_prefix.clear();
371 m_emin = 0.0;
372 m_emax = 0.0;
373 m_publish = false;
374
375 // Initialise protected members
376 m_infiles.clear();
377 m_select_energy = true;
378
379 // Return
380 return;
381}
382
383
384/***********************************************************************//**
385 * @brief Copy class members
386 *
387 * @param[in] app Application.
388 ***************************************************************************/
390{
391 // Copy parameters
392 m_outcube = app.m_outcube;
393 m_prefix = app.m_prefix;
394 m_emin = app.m_emin;
395 m_emax = app.m_emax;
396 m_publish = app.m_publish;
397
398 // Copy protected members
399 m_infiles = app.m_infiles;
400 m_select_energy = app.m_select_energy;
401
402 // Return
403 return;
404}
405
406
407/***********************************************************************//**
408 * @brief Delete class members
409 ***************************************************************************/
411{
412 // Return
413 return;
414}
415
416
417/***********************************************************************//**
418 * @brief Get application parameters
419 *
420 * Get all task parameters from parameter file or (if required) by querying
421 * the user.
422 *
423 * This method also loads observations if no observations are yet allocated.
424 * Observations are either loaded from a single CTA even cube, or from a
425 * XML file using the metadata information that is stored in that file.
426 ***************************************************************************/
428{
429 // Initialise selection flags
430 m_select_energy = true;
431
432 // Setup observations from "inobs" parameter. Do not request response
433 // information and do not accept event lists.
434 setup_observations(m_obs, false, false, true);
435
436 // Query "regfile" parameter
437 (*this)["regfile"].query();
438
439 // Query the RoI
440 GCTARoi roi = get_roi();
441
442 // Check for sanity of energy selection parameters
443 if ((*this)["emin"].is_valid() && (*this)["emax"].is_valid()) {
444 m_emin = (*this)["emin"].real();
445 m_emax = (*this)["emax"].real();
446 m_select_energy = true;
447 }
448 else {
449 m_select_energy = false;
450 }
451
452 // Get remaining parameters
453 m_publish = (*this)["publish"].boolean();
454
455 // If needed later, query output filename and prefix now
456 if (read_ahead()) {
457 (*this)["outcube"].query();
458 (*this)["prefix"].query();
459 }
460
461 // Write parameters into logger
462 log_parameters(TERSE);
463
464 // Return
465 return;
466}
467
468
469/***********************************************************************//**
470 * @brief Apply mask to event cube
471 *
472 * @param[in] obs CTA observation.
473 *
474 * Apply mask to an event cube. The mask sets content of event bins
475 * outside the region of interest or the energy of interest to -1.
476 * These pixels will be ignored in likelihood fitting.
477 ***************************************************************************/
478void ctcubemask::apply_mask(GCTAObservation* obs)
479{
480 // Get pointer to CTA event cube. Continue only if we have a cube
481 GCTAEventCube* cube = dynamic_cast<GCTAEventCube*>
482 (const_cast<GEvents*>(obs->events()));
483 if (cube != NULL) {
484
485 // Extract event cube and energy boundaries
486 GSkyMap map = cube->counts();
487 const GEbounds& ebounds = cube->ebounds();
488
489 // If no energy selection is required set energy boundaries to cube boundaries
490 if (!m_select_energy) {
491 m_emin = ebounds.emin().TeV();
492 m_emax = ebounds.emax().TeV();
493 }
494
495 // Initialise energy selection
496 int npix = map.npix();
497 int n_ebin = ebounds.size();
498 int e_idx1 = 0;
499 int e_idx2 = n_ebin;
500
501 // Determine number of events before masking
502 double sum_before = 0.0;
503 for (int i = 0; i < n_ebin; ++i) {
504 for (int pixel = 0; pixel < npix; ++pixel) {
505 if (map(pixel, i) >= 0.0) {
506 sum_before += map(pixel, i);
507 }
508 }
509 }
510
511 // Loop over ebounds to find the first valid energy band
512 for (int i = 0; i < n_ebin; ++i) {
513 double emin = ebounds.emin(i).TeV() + 1.0e-6; // Rounding tolerance
514 if (emin >= m_emin) {
515 e_idx1 = i;
516 break;
517 }
518 }
519
520 // Loop over ebounds to find the last valid energy band
521 for (int i = n_ebin-1; i >= 0; i--) {
522 double emax = ebounds.emax(i).TeV() - 1.0e-6; // Rounding tolerance
523 if (emax <= m_emax) {
524 e_idx2 = i;
525 break;
526 }
527 }
528
529 // Set all pixels outside the desired energy bands to -1.0
530 for (int i = 0; i < e_idx1; ++i) {
531 for (int pixel = 0; pixel < npix; ++pixel) {
532 map(pixel,i) = -1.0;
533 }
534 }
535 for (int i = e_idx2 + 1; i < n_ebin; ++i) {
536 for (int pixel = 0; pixel < npix; ++pixel) {
537 map(pixel,i) = -1.0;
538 }
539 }
540
541 // Log selected energy band
542 log_value(NORMAL, "Selected energy band",
543 gammalib::str(ebounds.emin(e_idx1).TeV())+" - "+
544 gammalib::str(ebounds.emax(e_idx2).TeV())+" TeV");
545
546 // Set all pixels inside selected energy bands but outside RoI
547 // to -1.0 if requested
548 GCTARoi roi = get_roi(obs->pointing());
549 if (roi.is_valid()) {
550 GSkyRegionCircle circle(roi.centre().dir(), roi.radius());
551 for (int i = e_idx1; i <= e_idx2; ++i) {
552 for (int pixel = 0; pixel < npix; ++pixel) {
553 GSkyDir dir = map.inx2dir(pixel);
554 if (!circle.contains(dir)) {
555 map(pixel,i) = -1.0;
556 }
557 }
558 }
559
560 // Log selected RoI
561 log_value(NORMAL, "Selected RoI",
562 "RA="+gammalib::str(circle.centre().ra_deg())+" deg, "+
563 "DEC="+gammalib::str(circle.centre().dec_deg())+" deg, "+
564 "Radius="+gammalib::str(circle.radius())+" deg");
565
566 } // endif: applied RoI selection
567
568 // Set all pixels inside selected energy bands and inside exclusion
569 // regions to -1.0
570 if ((*this)["regfile"].is_valid()) {
571 GSkyRegions regions = GSkyRegions((*this)["regfile"].filename());
572 for (int i = e_idx1; i <= e_idx2; ++i) {
573 for (int pixel = 0; pixel < npix; ++pixel) {
574 GSkyDir dir = map.inx2dir(pixel);
575 if (regions.contains(dir)) {
576 map(pixel,i) = -1.0;
577 }
578 }
579 }
580
581 // Log exclusion regions
582 for (int i = 0; i < regions.size(); ++i) {
583 log_value(NORMAL, "Exclusion region "+gammalib::str(i+1),
584 region_string(*(regions[i])));
585 }
586 }
587 else {
588 log_value(NORMAL, "Exclusion regions", "None");
589 }
590
591 // Determine number of events after masking
592 double sum_after = 0.0;
593 for (int i = 0; i < n_ebin; ++i) {
594 for (int pixel = 0; pixel < npix; ++pixel) {
595 if (map(pixel, i) >= 0.0) {
596 sum_after += map(pixel, i);
597 }
598 }
599 }
600
601 // Write number of events before and after masking into logger
602 log_value(NORMAL, "Events before masking", sum_before);
603 log_value(NORMAL, "Events after masking", sum_after);
604
605 // Put back map into the event cube
606 cube->counts(map);
607
608 } // endif: observation contained an event cube
609
610 // Return
611 return;
612}
613
614
615/***********************************************************************//**
616 * @brief Return region string
617 *
618 * @param[in] region Sky region.
619 *
620 * Returns a formatted region string for logging.
621 ***************************************************************************/
622std::string ctcubemask::region_string(const GSkyRegion& region) const
623{
624 // Initialise region string
625 std::string rstring;
626
627 // Get pointer to circle
628 const GSkyRegionCircle* circle = dynamic_cast<const GSkyRegionCircle*>(&region);
629
630 // If the sky region is a circle then append Right Ascenscion, Declination
631 // and Radius to the region string
632 if (circle != NULL) {
633 rstring.append("RA="+gammalib::str(circle->centre().ra_deg())+" deg, "+
634 "DEC="+gammalib::str(circle->centre().dec_deg())+" deg, "+
635 "Radius="+gammalib::str(circle->radius())+" deg");
636 }
637
638 // Return region string
639 return rstring;
640}
641
642
643/***********************************************************************//**
644 * @brief Set output file name.
645 *
646 * @param[in] filename Input file name.
647 *
648 * This converts an input filename into an output filename by prepending a
649 * prefix to the input filename. Any path will be stripped from the input
650 * filename.
651 ***************************************************************************/
652std::string ctcubemask::set_outfile_name(const std::string& filename) const
653{
654 // Split input filename into path elements
655 std::vector<std::string> elements = gammalib::split(filename, "/");
656
657 // The last path element is the filename
658 std::string outname = m_prefix + elements[elements.size()-1];
659
660 // Return output filename
661 return outname;
662}
663
664
665/***********************************************************************//**
666 * @brief Save counts cube in FITS format.
667 *
668 * Save the counts cube as a FITS file. The filename of the FITS file is
669 * specified by the m_outfile member.
670 ***************************************************************************/
672{
673 // Save only if there are observations
674 if (m_obs.size() > 0) {
675
676 // Get CTA observation from observation container
677 GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[0]);
678
679 // Handle only CTA observations
680 if (obs != NULL) {
681
682 // Log counts cube file name
683 log_value(NORMAL, "Counts cube file", m_outcube.url());
684
685 // Save counts cube
686 obs->save(m_outcube, clobber());
687
688 // Stamp counts cube
689 stamp(m_outcube);
690
691 } // endif: observation was a CTA observation
692
693 }
694
695 // Return
696 return;
697}
698
699
700/***********************************************************************//**
701 * @brief Save counts cube(s) in XML format.
702 *
703 * Save the counts cube(s) into FITS files and write the file path
704 * information into an XML file. The filename of the XML file is specified by
705 * the m_outfile member, the filename(s) of the counts cube(s) are built by
706 * prepending the prefix given by the m_prefix member to the input counts
707 * cube(s) filenames. Any path present in the input filename will be
708 * stripped, i.e. the counts cube(s) will be written in the local working
709 * directory (unless a path is specified in the m_prefix member).
710 ***************************************************************************/
712{
713 // Issue warning if output filename has no .xml suffix
714 log_string(TERSE, warn_xml_suffix(m_outcube.url()));
715
716 // Loop over all observation in the container
717 for (int i = 0; i < m_obs.size(); ++i) {
718
719 // Get CTA observation
720 GCTAObservation* obs = dynamic_cast<GCTAObservation*>(m_obs[i]);
721
722 // Handle only CTA observations
723 if (obs != NULL) {
724
725 // Set event output file name
726 std::string outfile = set_outfile_name(m_infiles[i]);
727
728 // Store output file name in observation
729 obs->eventfile(outfile);
730
731 // Log counts cube file name
732 log_value(NORMAL, "Counts cube file", outfile);
733
734 // Save counts cube
735 obs->save(outfile, clobber());
736
737 // Stamp counts cube
738 stamp(outfile);
739
740 } // endif: observation was a CTA observations
741
742 } // endfor: looped over observations
743
744 // Save observations in XML file
745 m_obs.save(m_outcube);
746
747 // Return
748 return;
749}
Cube filter tool.
double m_emin
Lower energy.
std::string set_outfile_name(const std::string &filename) const
Set output file name.
std::vector< std::string > m_infiles
Input event filenames.
void clear(void)
Clear ctcubemask tool.
std::string m_prefix
Prefix for multiple counts maps.
bool m_select_energy
Perform energy selection.
bool m_publish
Publish counts cube?
void get_parameters(void)
Get application parameters.
GFilename m_outcube
Output event list or XML file.
void copy_members(const ctcubemask &app)
Copy class members.
virtual ~ctcubemask(void)
Destructor.
void process(void)
Mask data cube.
void save(void)
Save the masked event cube(s)
void save_xml(void)
Save counts cube(s) in XML format.
ctcubemask & operator=(const ctcubemask &app)
Assignment operator.
double m_emax
Upper energy.
void init_members(void)
Initialise class members.
void apply_mask(GCTAObservation *obs)
Apply mask to event cube.
void publish(const std::string &name="")
Publish counts cube.
ctcubemask(void)
Void constructor.
void free_members(void)
Delete class members.
void save_fits(void)
Save counts cube in FITS format.
std::string region_string(const GSkyRegion &region) const
Return region string.
Base class for observation tools.
void free_members(void)
Delete class members.
ctobservation & operator=(const ctobservation &app)
Assignment operator.
GObservations m_obs
Observation container.
const GObservations & obs(void) const
Return observation container.
void init_members(void)
Initialise class members.
bool m_use_xml
Use XML file instead of FITS file for observations.
Definition ctool.hpp:162
void free_members(void)
Delete class members.
Definition ctool.cpp:357
void log_observations(const GChatter &chatter, const GObservations &obs, const std::string &what="Observation")
Log observation container.
Definition ctool.cpp:1251
const bool & read_ahead(void) const
Signal whether parameters should be read ahead.
Definition ctool.hpp:177
void log_parameters(const GChatter &chatter)
Log application parameters.
Definition ctool.cpp:1208
void init_members(void)
Initialise class members.
Definition ctool.cpp:321
void setup_observations(GObservations &obs, const bool &response=true, const bool &list=true, const bool &cube=true)
Setup observation container.
Definition ctool.cpp:431
std::string warn_xml_suffix(const GFilename &filename) const
Set warning string if file has no .xml suffix.
Definition ctool.cpp:2427
std::string get_obs_header(const GObservation *obs) const
Return observation header string.
Definition ctool.cpp:2090
GCTARoi get_roi(const GCTAPointing &pnt=GCTAPointing())
Return RoI from User parameters.
Definition ctool.cpp:1325
Cube filter tool definition.
#define CTCUBEMASK_NAME