ctools  2.0.0
 All Classes Namespaces Files Functions Variables Macros Pages
ctmapcube.cpp
Go to the documentation of this file.
1 /***************************************************************************
2  * ctmapcube - Map cube generation tool *
3  * ----------------------------------------------------------------------- *
4  * copyright (C) 2016-2022 by Juergen Knoedlseder *
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 ctmapcube.cpp
23  * @brief Map cube generation tool implementation
24  * @author Juergen Knoedlseder
25  */
26 
27 /* __ Includes ___________________________________________________________ */
28 #ifdef HAVE_CONFIG_H
29 #include <config.h>
30 #endif
31 #include <cstdio>
32 #include "ctmapcube.hpp"
33 #include "GTools.hpp"
34 
35 /* __ Method name definitions ____________________________________________ */
36 
37 /* __ Debug definitions __________________________________________________ */
38 
39 /* __ Coding definitions _________________________________________________ */
40 
41 /* __ Constants __________________________________________________________ */
42 
43 
44 /*==========================================================================
45  = =
46  = Constructors/destructors =
47  = =
48  ==========================================================================*/
49 
50 /***********************************************************************//**
51  * @brief Void constructor
52  ***************************************************************************/
54 {
55  // Initialise members
56  init_members();
57 
58  // Return
59  return;
60 }
61 
62 
63 /***********************************************************************//**
64  * @brief Command line constructor
65  *
66  * @param[in] argc Number of arguments in command line.
67  * @param[in] argv Array of command line arguments.
68  ***************************************************************************/
69 ctmapcube::ctmapcube(int argc, char *argv[]) :
70  ctool(CTMAPCUBE_NAME, VERSION, argc, argv)
71 {
72  // Initialise members
73  init_members();
74 
75  // Return
76  return;
77 }
78 
79 
80 /***********************************************************************//**
81  * @brief Copy constructor
82  *
83  * @param[in] app Application.
84  ***************************************************************************/
86 {
87  // Initialise members
88  init_members();
89 
90  // Copy members
91  copy_members(app);
92 
93  // Return
94  return;
95 }
96 
97 
98 /***********************************************************************//**
99  * @brief Destructor
100  ***************************************************************************/
102 {
103  // Free members
104  free_members();
105 
106  // Return
107  return;
108 }
109 
110 
111 /*==========================================================================
112  = =
113  = Operators =
114  = =
115  ==========================================================================*/
116 
117 /***********************************************************************//**
118  * @brief Assignment operator
119  *
120  * @param[in] app Application.
121  * @return Application.
122  ***************************************************************************/
124 {
125  // Execute only if object is not identical
126  if (this != &app) {
127 
128  // Copy base class members
129  this->ctool::operator=(app);
130 
131  // Free members
132  free_members();
133 
134  // Initialise members
135  init_members();
136 
137  // Copy members
138  copy_members(app);
139 
140  } // endif: object was not identical
141 
142  // Return this object
143  return *this;
144 }
145 
146 
147 /*==========================================================================
148  = =
149  = Public methods =
150  = =
151  ==========================================================================*/
152 
153 /***********************************************************************//**
154  * @brief Clear ctmapcube tool
155  *
156  * Clears ctmapcube tool.
157  ***************************************************************************/
159 {
160  // Free members
161  free_members();
162  this->ctool::free_members();
163 
164  // Clear base class (needed to conserve tool name and version)
165  this->GApplication::clear();
166 
167  // Initialise members
168  this->ctool::init_members();
169  init_members();
170 
171  // Write header into logger
172  log_header();
173 
174  // Return
175  return;
176 }
177 
178 
179 /***********************************************************************//**
180  * @brief Generate map cube.
181  *
182  * This method reads the task parameters from the parfile and generates the
183  * map cube.
184  ***************************************************************************/
186 {
187  // Get task parameters
188  get_parameters();
189 
190  // Write input model container into logger
191  log_models(NORMAL, m_models, "Input model");
192 
193  // Generate map cube
194  create_cube();
195 
196  // Write result cube into logger
197  log_header1(NORMAL, "Map cube");
198  log_string(NORMAL, m_cube.print(m_chatter));
199 
200  // Optionally publish map cube
201  if (m_publish) {
202  publish();
203  }
204 
205  // Return
206  return;
207 }
208 
209 
210 /***********************************************************************//**
211  * @brief Save map cube
212  *
213  * Saves the map cube into a FITS file.
214  ***************************************************************************/
215 void ctmapcube::save(void)
216 {
217  // Write header
218  log_header1(TERSE, "Save map cube");
219 
220  // Save map cube if filename is valid and the map cube is not empty
221  if ((*this)["outcube"].is_valid() && !m_cube.cube().is_empty()) {
222 
223  // Get map cube filename
224  m_outcube = (*this)["outcube"].filename();
225 
226  // Save map cube
227  m_cube.save(m_outcube, clobber());
228 
229  // Stamp map cube
230  stamp(m_outcube);
231  }
232 
233  // Write into logger what has been done
234  std::string fname = (m_outcube.is_empty()) ? "NONE" : m_outcube.url();
235  if (m_cube.cube().is_empty()) {
236  fname.append(" (cube is empty, no file created)");
237  }
238  log_value(NORMAL, "Map cube file", fname);
239 
240  // Return
241  return;
242 }
243 
244 
245 /***********************************************************************//**
246  * @brief Publish map cube
247  *
248  * @param[in] name Map cube name.
249  *
250  * Publishes the map cube on a VO Hub.
251  ***************************************************************************/
252 void ctmapcube::publish(const std::string& name)
253 {
254  // Write header into logger
255  log_header1(TERSE, "Publish map cube");
256 
257  // Set default name is user name is empty
258  std::string user_name(name);
259  if (user_name.empty()) {
260  user_name = CTMAPCUBE_NAME;
261  }
262 
263  // Write map cube name into logger
264  log_value(NORMAL, "Map cube name", user_name);
265 
266  // Publish map cube
267  m_cube.cube().publish(user_name);
268 
269  // Return
270  return;
271 }
272 
273 
274 /*==========================================================================
275  = =
276  = Private methods =
277  = =
278  ==========================================================================*/
279 
280 /***********************************************************************//**
281  * @brief Initialise class members
282  ***************************************************************************/
284 {
285  // Initialise members
286  m_outcube.clear();
287  m_ptsrcsig = 1.0;
288  m_publish = false;
289  m_chatter = static_cast<GChatter>(2);
290 
291  // Initialise protected members
292  m_models.clear();
293  m_cube.clear();
294 
295  // Return
296  return;
297 }
298 
299 
300 /***********************************************************************//**
301  * @brief Copy class members
302  *
303  * @param[in] app Application.
304  ***************************************************************************/
306 {
307  // Copy attributes
308  m_outcube = app.m_outcube;
309  m_ptsrcsig = app.m_ptsrcsig;
310  m_publish = app.m_publish;
311  m_chatter = app.m_chatter;
312 
313  // Copy protected members
314  m_models = app.m_models;
315  m_cube = app.m_cube;
316 
317  // Return
318  return;
319 }
320 
321 
322 /***********************************************************************//**
323  * @brief Delete class members
324  ***************************************************************************/
326 {
327  // Return
328  return;
329 }
330 
331 
332 /***********************************************************************//**
333  * @brief Get application parameters
334  *
335  * Get all task parameters from parameter file or (if required) by querying
336  * the user.
337  ***************************************************************************/
339 {
340  // Read model definition file if required
341  if (m_models.size() == 0) {
342 
343  // Get model filename
344  GFilename inmodel = (*this)["inmodel"].filename();
345 
346  // Load models from file
347  m_models.load(inmodel);
348 
349  } // endif: there were no models
350 
351  // Get energy binning parameters
352  GEnergies energies(create_ebounds());
353 
354  // Get spatial binning parameters
355  double xref = (*this)["xref"].real();
356  double yref = (*this)["yref"].real();
357  std::string proj = (*this)["proj"].string();
358  std::string coordsys = (*this)["coordsys"].string();
359  double binsz = (*this)["binsz"].real();
360  int nxpix = (*this)["nxpix"].integer();
361  int nypix = (*this)["nypix"].integer();
362 
363  // Get remaining hidden parameters
364  m_ptsrcsig = (*this)["ptsrcsig"].real();
365  m_publish = (*this)["publish"].boolean();
366  m_chatter = static_cast<GChatter>((*this)["chatter"].integer());
367 
368  // If needed later, query output filename now
369  if (read_ahead()) {
370  (*this)["outcube"].query();
371  }
372 
373  // Allocate map cube
374  GSkyMap cube(proj, coordsys, xref, yref, -binsz, binsz, nxpix, nypix,
375  energies.size());
376 
377  // Allocate map cube
378  m_cube = GModelSpatialDiffuseCube(cube, energies);
379 
380  // Write parameters into logger
381  log_parameters(TERSE);
382 
383  // Return
384  return;
385 }
386 
387 
388 /***********************************************************************//**
389  * @brief Generate map cube
390  *
391  * Generate map cube by looping over all sky models in the container.
392  ***************************************************************************/
394 {
395  // Write header into logger
396  log_header1(TERSE, "Generate map cube");
397 
398  // Loop over all models
399  for (int i = 0; i < m_models.size(); ++i) {
400 
401  // Get pointer to sky model
402  GModelSky* model = dynamic_cast<GModelSky*>(m_models[i]);
403 
404  // Fall through if model is not a sky model
405  if (model == NULL) {
406 
407  // Signal that model is skipped
408  log_value(NORMAL, "Skip model", m_models[i]->name());
409 
410  // Continue
411  continue;
412 
413  }
414 
415  // Signal that model is used
416  log_value(NORMAL, "Use model", m_models[i]->name());
417 
418  // Add sky model
419  if (dynamic_cast<GModelSpatialPointSource*>(model->spatial()) != NULL) {
420  add_ptsrc_model(model);
421  }
422  else {
423  add_model(model);
424  }
425 
426  } // endfor: looped over energies
427 
428  // Return
429  return;
430 }
431 
432 
433 /***********************************************************************//**
434  * @brief Add one model to map cube
435  *
436  * @param[in] model Pointer to point source sky model.
437  *
438  * Adds one model to map cube.
439  ***************************************************************************/
440 void ctmapcube::add_model(GModelSky* model)
441 {
442  // Get cube energies
443  GEnergies energies = m_cube.energies();
444 
445  // Get pointer to sky map
446  GSkyMap* map = const_cast<GSkyMap*>(&m_cube.cube());
447 
448  // Get the model's bounding circle
449  GSkyDir centre;
450  double radius;
451  get_bounding_circle(model, &centre, &radius);
452 
453  // Add some margin to circle radius
454  radius += 0.1;
455 
456  // Loop over all map cube pixels
457  for (int ipixel = 0; ipixel < map->npix(); ++ipixel) {
458 
459  // Get pixel sky direction
460  GSkyDir dir = map->inx2dir(ipixel);
461 
462  // Skip pixel if it's outside the bounding circle
463  if (centre.dist_deg(dir) > radius) {
464  continue;
465  }
466 
467  // Loop over all energy bins
468  for (int iebin = 0; iebin < energies.size(); ++iebin) {
469 
470  // Set photon
471  GPhoton photon(dir, energies[iebin], GTime());
472 
473  // Add model value
474  map->operator()(ipixel, iebin) += model->value(photon);
475 
476  } // endfor: looped over all energies
477 
478  } // endfor: looped over all pixels
479 
480  // Return
481  return;
482 }
483 
484 
485 /***********************************************************************//**
486  * @brief Add one point source model to map cube
487  *
488  * @param[in] model Pointer to point source sky model.
489  *
490  * Adds one point source model to map cube.
491  ***************************************************************************/
492 void ctmapcube::add_ptsrc_model(GModelSky* model)
493 {
494  // Get pointer to sky map
495  GSkyMap* map = const_cast<GSkyMap*>(&m_cube.cube());
496 
497  // If Gaussian sigma is positive then replace the point sources by a
498  // Gaussian with the user defined width
499  if (m_ptsrcsig > 0.0) {
500 
501  // Get the point source centre (radius is ignored)
502  GSkyDir centre;
503  double radius;
504  get_bounding_circle(model, &centre, &radius);
505 
506  // Set the Gaussian sigma in degrees (m_ptsrcsig is in arcmin)
507  double sigma = m_ptsrcsig/60.0;
508 
509  // Create a Gaussian spatial model
510  GModelSpatialRadialGauss spatial(centre, sigma);
511 
512  // Create a new model reusing the spectral and temporal components
513  // of the original model
514  GModelSky skymodel(spatial, *(model->spectral()), *(model->temporal()));
515 
516  // Add model
517  add_model(&skymodel);
518 
519  } // endif: Gaussian sigma was positive
520 
521  // ... otherwise set a single map pixel
522  else {
523 
524  // Get point source spatial component
525  GModelSpatialPointSource* ptsrc =
526  static_cast<GModelSpatialPointSource*>(model->spatial());
527 
528  // Get point source direction
529  GSkyDir dir = ptsrc->dir();
530 
531  // Get cube energies
532  GEnergies energies = m_cube.energies();
533 
534  // Get test sky map for flux computation
535  GSkyMap test_map(*map);
536 
537  // Continue only if map contains point source sky direction
538  if (map->contains(dir)) {
539 
540  // Get map pixel
541  int ipixel = map->dir2inx(dir);
542 
543  // Loop over all energy bins
544  for (int iebin = 0; iebin < energies.size(); ++iebin) {
545 
546  // Set photon using the point source sky direction
547  GPhoton photon(dir, energies[iebin], GTime());
548 
549  // Compute model value
550  double value = model->value(photon);
551 
552  // Compute flux normalization
553  test_map(ipixel, iebin) = value;
554  double flux = test_map.flux(ipixel, iebin);
555  double norm = (flux > 0.0) ? value / flux : 0.0;
556 
557  // Add model to sky map
558  map->operator()(ipixel, iebin) += norm * value;
559 
560  } // endfor: looped over all energies
561 
562  } // endif: map contained sky direction
563 
564  } // endelse: Gaussian sigma was non positive
565 
566  // Return
567  return;
568 }
569 
570 
571 /***********************************************************************//**
572  * @brief Get bounding circle for a sky model
573  *
574  * @param[in] model Pointer to sky model.
575  * @param[out] dir Centre of bounding circle.
576  * @param[out] radius Radius of bounding circle (degrees).
577  *
578  * Determine for any spatial model the bounding circle. The bounding circle
579  * is a circular region that fully enclosed the model.
580  *
581  * The method does not verify the validity of the pointer arguments.
582  ***************************************************************************/
583 void ctmapcube::get_bounding_circle(GModelSky* model,
584  GSkyDir* dir,
585  double* radius) const
586 {
587  // Interpret the spatial model component as point source, radial source
588  // or elliptical source
589  GModelSpatialPointSource* ptsrc =
590  dynamic_cast<GModelSpatialPointSource*>(model->spatial());
591  GModelSpatialRadial* radial =
592  dynamic_cast<GModelSpatialRadial*>(model->spatial());
593  GModelSpatialElliptical* elliptical =
594  dynamic_cast<GModelSpatialElliptical*>(model->spatial());
595 
596  // If the spatial component as a point source then extract the source
597  // position and set the radius of the bounding box to 0.1 degrees
598  if (ptsrc != NULL) {
599  *dir = ptsrc->dir();
600  *radius = 0.1;
601  }
602 
603  // ... otherwise, if the spatial component is a radial source then extract
604  // the source position and set the radius of the bounding box from the
605  // value returned by theta_max() in radians
606  else if (radial != NULL) {
607  *dir = radial->dir();
608  *radius = radial->theta_max() * gammalib::rad2deg;
609  }
610 
611  // ... otherwise, if the spatial component is an elliptical source then
612  // extract the source position and set the radius of the bounding box from
613  // the value returned by theta_max() in radians
614  else if (elliptical != NULL) {
615  *dir = elliptical->dir();
616  *radius = elliptical->theta_max() * gammalib::rad2deg;
617  }
618 
619  // ... otherwise use the entire sky
620  else {
621  *radius = 180.0;
622  }
623 
624  // Return
625  return;
626 }
void clear(void)
Clear ctmapcube tool.
Definition: ctmapcube.cpp:158
void free_members(void)
Delete class members.
Definition: ctmapcube.cpp:325
void log_models(const GChatter &chatter, const GModels &models, const std::string &what="Model")
Log model container.
Definition: ctool.cpp:1285
void init_members(void)
Initialise class members.
Definition: ctmapcube.cpp:283
void save(void)
Save map cube.
Definition: ctmapcube.cpp:215
virtual ~ctmapcube(void)
Destructor.
Definition: ctmapcube.cpp:101
Map cube generation tool definition.
void get_bounding_circle(GModelSky *model, GSkyDir *dir, double *radius) const
Get bounding circle for a sky model.
Definition: ctmapcube.cpp:583
void publish(const std::string &name="")
Publish map cube.
Definition: ctmapcube.cpp:252
void process(void)
Generate map cube.
Definition: ctmapcube.cpp:185
ctmapcube(void)
Void constructor.
Definition: ctmapcube.cpp:53
void init_members(void)
Initialise class members.
Definition: ctool.cpp:321
Base class for ctools.
Definition: ctool.hpp:50
GModels m_models
Model container.
Definition: ctmapcube.hpp:84
GFilename m_outcube
Output map cube filename.
Definition: ctmapcube.hpp:78
void copy_members(const ctmapcube &app)
Copy class members.
Definition: ctmapcube.cpp:305
GChatter m_chatter
Chattiness.
Definition: ctmapcube.hpp:81
ctmapcube & operator=(const ctmapcube &app)
Assignment operator.
Definition: ctmapcube.cpp:123
void log_parameters(const GChatter &chatter)
Log application parameters.
Definition: ctool.cpp:1208
GEbounds create_ebounds(void)
Create energy boundaries from user parameters.
Definition: ctool.cpp:612
GModelSpatialDiffuseCube m_cube
Map cube.
Definition: ctmapcube.hpp:85
Map cube generation tool.
Definition: ctmapcube.hpp:44
void add_model(GModelSky *model)
Add one model to map cube.
Definition: ctmapcube.cpp:440
void free_members(void)
Delete class members.
Definition: ctool.cpp:357
ctool & operator=(const ctool &app)
Assignment operator.
Definition: ctool.cpp:221
const bool & read_ahead(void) const
Signal whether parameters should be read ahead.
Definition: ctool.hpp:177
double m_ptsrcsig
Point source sigma (arcmin)
Definition: ctmapcube.hpp:79
#define CTMAPCUBE_NAME
Definition: ctmapcube.hpp:36
void create_cube(void)
Generate map cube.
Definition: ctmapcube.cpp:393
void add_ptsrc_model(GModelSky *model)
Add one point source model to map cube.
Definition: ctmapcube.cpp:492
bool m_publish
Publish map cube?
Definition: ctmapcube.hpp:80
void get_parameters(void)
Get application parameters.
Definition: ctmapcube.cpp:338