ctools 2.1.0.dev
Loading...
Searching...
No Matches
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
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 ***************************************************************************/
69ctmapcube::ctmapcube(int argc, char *argv[]) :
70 ctool(CTMAPCUBE_NAME, VERSION, argc, argv)
71{
72 // Initialise 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
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
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 ***************************************************************************/
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 ***************************************************************************/
252void 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 ***************************************************************************/
440void 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 ***************************************************************************/
492void 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 ***************************************************************************/
583void 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}
Map cube generation tool.
Definition ctmapcube.hpp:44
void save(void)
Save map cube.
void init_members(void)
Initialise class members.
void get_bounding_circle(GModelSky *model, GSkyDir *dir, double *radius) const
Get bounding circle for a sky model.
ctmapcube(void)
Void constructor.
Definition ctmapcube.cpp:53
void create_cube(void)
Generate map cube.
GChatter m_chatter
Chattiness.
Definition ctmapcube.hpp:81
GFilename m_outcube
Output map cube filename.
Definition ctmapcube.hpp:78
void clear(void)
Clear ctmapcube tool.
void add_ptsrc_model(GModelSky *model)
Add one point source model to map cube.
void publish(const std::string &name="")
Publish map cube.
ctmapcube & operator=(const ctmapcube &app)
Assignment operator.
void copy_members(const ctmapcube &app)
Copy class members.
GModels m_models
Model container.
Definition ctmapcube.hpp:84
double m_ptsrcsig
Point source sigma (arcmin)
Definition ctmapcube.hpp:79
GModelSpatialDiffuseCube m_cube
Map cube.
Definition ctmapcube.hpp:85
void add_model(GModelSky *model)
Add one model to map cube.
void process(void)
Generate map cube.
bool m_publish
Publish map cube?
Definition ctmapcube.hpp:80
void get_parameters(void)
Get application parameters.
virtual ~ctmapcube(void)
Destructor.
void free_members(void)
Delete class members.
Base class for ctools.
Definition ctool.hpp:50
GEbounds create_ebounds(void)
Create energy boundaries from user parameters.
Definition ctool.cpp:612
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
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 log_models(const GChatter &chatter, const GModels &models, const std::string &what="Model")
Log model container.
Definition ctool.cpp:1285
Map cube generation tool definition.
#define CTMAPCUBE_NAME
Definition ctmapcube.hpp:36