Bug Summary

File:src/sky/GSkymap.cpp
Location:line 1059, column 13
Description:Value stored to 'loaded' is never read

Annotated Source Code

1/***************************************************************************
2 * GSkymap.cpp - Sky map class *
3 * ----------------------------------------------------------------------- *
4 * copyright (C) 2010-2013 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 GSkymap.cpp
23 * @brief Sky map class implementation
24 * @author Juergen Knoedlseder
25 */
26
27/* __ Includes ___________________________________________________________ */
28#ifdef HAVE_CONFIG_H1
29#include <config.h>
30#endif
31#include "GException.hpp"
32#include "GTools.hpp"
33#include "GSkymap.hpp"
34#include "GHealpix.hpp"
35#include "GWcsRegistry.hpp"
36#include "GWcs.hpp"
37#include "GFits.hpp"
38#include "GFitsTableDoubleCol.hpp"
39#include "GFitsImageDouble.hpp"
40
41/* __ Method name definitions ____________________________________________ */
42#define G_CONSTRUCT_HPX"GSkymap::GSkymap(std::string&, int&," " std::string&, int&)" "GSkymap::GSkymap(std::string&, int&,"\
43 " std::string&, int&)"
44#define G_CONSTRUCT_MAP"GSkymap::GSkymap(std::string&, std::string&," " double&, double&, double& double&, int&, int&, int&)" "GSkymap::GSkymap(std::string&, std::string&,"\
45 " double&, double&, double& double&, int&, int&, int&)"
46#define G_OP_ACCESS_1D"GSkymap::operator(int&, int&)" "GSkymap::operator(int&, int&)"
47#define G_OP_ACCESS_2D"GSkymap::operator(GSkyPixel&, int&)" "GSkymap::operator(GSkyPixel&, int&)"
48#define G_OP_VALUE"GSkymap::operator(GSkyDir&, int&)" "GSkymap::operator(GSkyDir&, int&)"
49#define G_INX2DIR"GSkymap::inx2dir(int&)" "GSkymap::inx2dir(int&)"
50#define G_PIX2DIR"GSkymap::pix2dir(GSkyPixel&)" "GSkymap::pix2dir(GSkyPixel&)"
51#define G_DIR2INX"GSkymap::dir2inx(GSkyDir&)" "GSkymap::dir2inx(GSkyDir&)"
52#define G_DIR2PIX"GSkymap::dir2pix(GSkyDir&)" "GSkymap::dir2pix(GSkyDir&)"
53#define G_SOLIDANGLE1"GSkymap::solidangle(int&)" "GSkymap::solidangle(int&)"
54#define G_SOLIDANGLE2"GSkymap::solidangle(GSkyPixel&)" "GSkymap::solidangle(GSkyPixel&)"
55#define G_READ"GSkymap::read(const GFitsHDU&)" "GSkymap::read(const GFitsHDU&)"
56#define G_SET_WCS"GSkymap::set_wcs(std::string&, std::string&, double&,"
" double&, double&, double&, double&, double&,"
" GMatrix&, GVector&)"
"GSkymap::set_wcs(std::string&, std::string&, double&,"\
57 " double&, double&, double&, double&, double&,"\
58 " GMatrix&, GVector&)"
59#define G_READ_HEALPIX"GSkymap::read_healpix(GFitsTable*)" "GSkymap::read_healpix(GFitsTable*)"
60#define G_READ_WCS"GSkymap::read_wcs(GFitsImage*)" "GSkymap::read_wcs(GFitsImage*)"
61#define G_ALLOC_WCS"GSkymap::alloc_wcs(GFitsImage*)" "GSkymap::alloc_wcs(GFitsImage*)"
62
63/* __ Macros _____________________________________________________________ */
64
65/* __ Coding definitions _________________________________________________ */
66
67/* __ Debug definitions __________________________________________________ */
68//#define G_READ_HEALPIX_DEBUG // Debug read_healpix
69//#define G_READ_WCS_DEBUG // Debug read_wcs
70
71/* __ Prototype __________________________________________________________ */
72
73
74/*==========================================================================
75 = =
76 = Constructors/destructors =
77 = =
78 ==========================================================================*/
79
80/***********************************************************************//**
81 * @brief Void constructor
82 ***************************************************************************/
83GSkymap::GSkymap(void)
84{
85 // Initialise class members for clean destruction
86 init_members();
87
88 // Return
89 return;
90}
91
92
93/***********************************************************************//**
94 * @brief FITS file constructor
95 *
96 * @param[in] filename FITS file name.
97 ***************************************************************************/
98GSkymap::GSkymap(const std::string& filename)
99{
100 // Initialise class members for clean destruction
101 init_members();
102
103 // Load skymap
104 load(filename);
105
106 // Return
107 return;
108}
109
110
111/***********************************************************************//**
112 * @brief Healpix sky map constructor
113 *
114 * @param[in] coords Coordinate System (CEL or GAL).
115 * @param[in] nside Nside parameter.
116 * @param[in] order Pixel ordering (RING or NEST).
117 * @param[in] nmaps Number of maps in set (default=1).
118 *
119 * @exception GException::skymap_bad_par
120 * Invalid sky map parameter.
121 *
122 * Constructs sky map in Healpix pixelisation.
123 ***************************************************************************/
124GSkymap::GSkymap(const std::string& coords,
125 const int& nside,
126 const std::string& order,
127 const int& nmaps)
128{
129 // Initialise class members for clean destruction
130 init_members();
131
132 // Check if nmaps parameter is >0
133 if (nmaps < 1) {
134 throw GException::skymap_bad_par(G_CONSTRUCT_HPX"GSkymap::GSkymap(std::string&, int&," " std::string&, int&)", nmaps,
135 "nmaps parameter must be >0.");
136 }
137
138 // Allocate Healpix projection
139 GHealpix* projection = new GHealpix(nside, order, coords);
140 m_proj = projection;
141
142 // Set number of pixels and number of maps
143 m_num_pixels = projection->npix();
144 m_num_maps = nmaps;
145
146 // Allocate pixels
147 alloc_pixels();
148
149 // Return
150 return;
151}
152
153
154/***********************************************************************//**
155 * @brief WCS sky map constructor
156 *
157 * @param[in] wcs World Coordinate System.
158 * @param[in] coords Coordinate System (CEL or GAL).
159 * @param[in] x X coordinate of sky map centre (deg).
160 * @param[in] y Y coordinate of sky map centre (deg).
161 * @param[in] dx Pixel size in x direction at centre (deg/pixel).
162 * @param[in] dy Pixel size in y direction at centre (deg/pixel).
163 * @param[in] nx Number of pixels in x direction.
164 * @param[in] ny Number of pixels in y direction.
165 * @param[in] nmaps Number of maps in set (default=1).
166 *
167 * @exception GException::skymap_bad_par
168 * Invalid sky map parameter.
169 *
170 * Constructs sky map in World Coordinate System projection.
171 ***************************************************************************/
172GSkymap::GSkymap(const std::string& wcs,
173 const std::string& coords,
174 const double& x,
175 const double& y,
176 const double& dx,
177 const double& dy,
178 const int& nx,
179 const int& ny,
180 const int& nmaps)
181{
182 // Initialise class members for clean destruction
183 init_members();
184
185 // Check parameters
186 if (nx < 1) {
187 throw GException::skymap_bad_par(G_CONSTRUCT_MAP"GSkymap::GSkymap(std::string&, std::string&," " double&, double&, double& double&, int&, int&, int&)", nx,
188 "nx parameter must be >0.");
189 }
190 if (ny < 1) {
191 throw GException::skymap_bad_par(G_CONSTRUCT_MAP"GSkymap::GSkymap(std::string&, std::string&," " double&, double&, double& double&, int&, int&, int&)", ny,
192 "ny parameter must be >0.");
193 }
194 if (nmaps < 1) {
195 throw GException::skymap_bad_par(G_CONSTRUCT_MAP"GSkymap::GSkymap(std::string&, std::string&," " double&, double&, double& double&, int&, int&, int&)", nmaps,
196 "nmaps parameter must be >0.");
197 }
198
199 // Set WCS
200 double crval1 = x;
201 double crval2 = y;
202 double crpix1 = double(nx+1)/2.0;
203 double crpix2 = double(ny+1)/2.0;
204 double cdelt1 = dx;
205 double cdelt2 = dy;
206 GMatrix cd(2,2);
207 GVector pv2(21);
208 set_wcs(wcs, coords, crval1, crval2, crpix1, crpix2, cdelt1, cdelt2,
209 cd, pv2);
210
211 // Set number of pixels and number of maps
212 m_num_x = nx;
213 m_num_y = ny;
214 m_num_pixels = m_num_x * m_num_y;
215 m_num_maps = nmaps;
216
217 // Allocate pixels
218 alloc_pixels();
219
220 // Return
221 return;
222}
223
224
225/***********************************************************************//**
226 * @brief Copy constructor
227 *
228 * @param[in] map Sky map.
229 ***************************************************************************/
230GSkymap::GSkymap(const GSkymap& map)
231{
232 // Initialise class members for clean destruction
233 init_members();
234
235 // Copy members
236 copy_members(map);
237
238 // Return
239 return;
240}
241
242
243/***********************************************************************//**
244 * @brief Destructor
245 ***************************************************************************/
246GSkymap::~GSkymap(void)
247{
248 // Free members
249 free_members();
250
251 // Return
252 return;
253}
254
255
256/*==========================================================================
257 = =
258 = Operators =
259 = =
260 ==========================================================================*/
261
262/***********************************************************************//**
263 * @brief Assignment operator
264 *
265 * @param[in] map Sky map.
266 * @return Sky map.
267 ***************************************************************************/
268GSkymap& GSkymap::operator=(const GSkymap& map)
269{
270 // Execute only if object is not identical
271 if (this != &map) {
272
273 // Free members
274 free_members();
275
276 // Initialise private members for clean destruction
277 init_members();
278
279 // Copy members
280 copy_members(map);
281
282 } // endif: object was not identical
283
284 // Return this object
285 return *this;
286}
287
288
289/***********************************************************************//**
290 * @brief Pixel index access operator
291 *
292 * @param[in] index Pixel index [0,...,npix()-1].
293 * @param[in] map Map index [0,...,nmaps()-1].
294 * @return Sky map pixel value.
295 *
296 * @exception GException::out_of_range
297 * Pixel index and/or map index are outside valid range.
298 *
299 * Access sky map pixel by its index, where the most quickly varying axis is
300 * the x axis of the map.
301 ***************************************************************************/
302double& GSkymap::operator()(const int& index, const int& map)
303{
304 // Throw an error if pixel index or map index is not in valid range
305 #if defined(G_RANGE_CHECK1)
306 if (index < 0 || index >= m_num_pixels) {
307 throw GException::out_of_range(G_OP_ACCESS_1D"GSkymap::operator(int&, int&)",
308 "Sky map pixel index",
309 index, m_num_pixels);
310 }
311 if (map < 0 || map >= m_num_maps) {
312 throw GException::out_of_range(G_OP_ACCESS_1D"GSkymap::operator(int&, int&)",
313 "Sky map map index",
314 map, m_num_maps);
315 }
316 #endif
317
318 // Return reference to pixel value
319 return m_pixels[index+m_num_pixels*map];
320}
321
322
323/***********************************************************************//**
324 * @brief Pixel index access operator (const variant)
325 *
326 * @param[in] index Pixel index [0,...,npix()-1].
327 * @param[in] map Map index [0,...,nmaps()-1].
328 *
329 * @exception GException::out_of_range
330 * Pixel index and/or map index are outside valid range.
331 *
332 * Access sky map pixel by its index, where the most quickly varying axis is
333 * the x axis of the map.
334 ***************************************************************************/
335const double& GSkymap::operator()(const int& index, const int& map) const
336{
337 // Throw an error if pixel index or map index is not in valid range
338 #if defined(G_RANGE_CHECK1)
339 if (index < 0 || index >= m_num_pixels) {
340 throw GException::out_of_range(G_OP_ACCESS_1D"GSkymap::operator(int&, int&)",
341 "Sky map pixel index",
342 index, m_num_pixels);
343 }
344 if (map < 0 || map >= m_num_maps) {
345 throw GException::out_of_range(G_OP_ACCESS_1D"GSkymap::operator(int&, int&)",
346 "Sky map map index",
347 map, m_num_maps);
348 }
349 #endif
350
351 // Return reference to pixel value
352 return m_pixels[index+m_num_pixels*map];
353}
354
355
356/***********************************************************************//**
357 * @brief Sky map pixel access operator
358 *
359 * @param[in] pixel Sky map pixel.
360 * @param[in] map Map index [0,...,nmaps()-1].
361 *
362 * @exception GException::out_of_range
363 * Sky pixel and/or map index are outside valid range.
364 *
365 * Access sky map pixel by its 2D index (x,y) that is implemented by the
366 * GSkyPixel class.
367 *
368 * @todo Implement proper skymap exception (actual is for matrix elements)
369 ***************************************************************************/
370double& GSkymap::operator()(const GSkyPixel& pixel, const int& map)
371{
372 // Throw an error if pixel index or map index is not in valid range
373 #if defined(G_RANGE_CHECK1)
374 if (!contains(pixel)) {
375 throw GException::out_of_range(G_OP_ACCESS_2D"GSkymap::operator(GSkyPixel&, int&)",
376 int(pixel.x()), int(pixel.y()),
377 m_num_x-1, m_num_y-1);
378 }
379 if (map < 0 || map >= m_num_maps) {
380 throw GException::out_of_range(G_OP_ACCESS_2D"GSkymap::operator(GSkyPixel&, int&)",
381 "Sky map map index",
382 map, m_num_maps);
383 }
384 #endif
385
386 // Get pixel index
387 int index = pix2inx(pixel);
388
389 // Return reference to pixel value
390 return m_pixels[index+m_num_pixels*map];
391}
392
393
394/***********************************************************************//**
395 * @brief Sky map pixel access operator
396 *
397 * @param[in] pixel Sky map pixel.
398 * @param[in] map Map index [0,...,nmaps()-1].
399 *
400 * @exception GException::out_of_range
401 * Sky pixel and/or map index are outside valid range.
402 *
403 * Access sky map pixel by its 2D index (x,y) that is implemented by the
404 * GSkyPixel class.
405 *
406 * @todo Implement proper skymap exception (actual is for matrix elements)
407 ***************************************************************************/
408const double& GSkymap::operator()(const GSkyPixel& pixel, const int& map) const
409{
410 // Throw an error if pixel index or map index is not in valid range
411 #if defined(G_RANGE_CHECK1)
412 if (!contains(pixel)) {
413 throw GException::out_of_range(G_OP_ACCESS_2D"GSkymap::operator(GSkyPixel&, int&)",
414 int(pixel.x()), int(pixel.y()),
415 m_num_x-1, m_num_y-1);
416 }
417 if (map < 0 || map >= m_num_maps) {
418 throw GException::out_of_range(G_OP_ACCESS_2D"GSkymap::operator(GSkyPixel&, int&)",
419 "Sky map map index",
420 map, m_num_maps);
421 }
422 #endif
423
424 // Get pixel index
425 int index = pix2inx(pixel);
426
427 // Return reference to pixel value
428 return m_pixels[index+m_num_pixels*map];
429}
430
431
432/***********************************************************************//**
433 * @brief Return interpolated skymap value for sky direction
434 *
435 * @param[in] dir Sky direction.
436 * @param[in] map Map index [0,...,nmaps()-1].
437 *
438 * @exception GException::out_of_range
439 * Map index lies outside valid range.
440 *
441 * Returns the skymap value for a given sky direction, obtained by bi-linear
442 * interpolation of the neighbouring pixels. If the sky direction falls
443 * outside the area covered by the skymap, a value of 0 is returned.
444 *
445 * @todo The actual method only works on 2D images. It will fail for Healpix
446 * pixelisations.
447 ***************************************************************************/
448double GSkymap::operator()(const GSkyDir& dir, const int& map) const
449{
450 // Throw an error if the map index is not in valid range
451 #if defined(G_RANGE_CHECK1)
452 if (map < 0 || map >= m_num_maps) {
453 throw GException::out_of_range(G_OP_VALUE"GSkymap::operator(GSkyDir&, int&)",
454 "Sky map map index",
455 map, m_num_maps);
456 }
457 #endif
458
459 // Initialise intensity
460 double intensity = 0.0;
461
462 // Determine sky pixel
463 GSkyPixel pixel = dir2pix(dir);
464
465 // Continue only if pixel is within the map
466 if (contains(pixel)) {
467
468 // Set left indices for interpolation. The left index is comprised
469 // between 0 and npixels-2. By definition, the right index is then
470 // the left index + 1
471 int inx_x = int(pixel.x());
472 int inx_y = int(pixel.y());
473 if (inx_x < 0) {
474 inx_x = 0;
475 }
476 else if (inx_x > m_num_x-2) {
477 inx_x = m_num_x - 2;
478 }
479 if (inx_y < 0) {
480 inx_y = 0;
481 }
482 else if (inx_y > m_num_y-2) {
483 inx_y = m_num_y - 2;
484 }
485
486 // Set weighting factors for interpolation
487 double wgt_x_right = (pixel.x() - inx_x);
488 double wgt_x_left = 1.0 - wgt_x_right;
489 double wgt_y_right = (pixel.y() - inx_y);
490 double wgt_y_left = 1.0 - wgt_y_right;
491
492 // Compute skymap pixel indices for bi-linear interpolation
493 int inx1 = inx_x + inx_y * m_num_x;
494 int inx2 = inx1 + m_num_x;
495 int inx3 = inx1 + 1;
496 int inx4 = inx2 + 1;
497
498 // Compute weighting factors for bi-linear interpolation
499 double wgt1 = wgt_x_left * wgt_y_left;
500 double wgt2 = wgt_x_left * wgt_y_right;
501 double wgt3 = wgt_x_right * wgt_y_left;
502 double wgt4 = wgt_x_right * wgt_y_right;
503
504 // Compute map offset
505 int offset = m_num_pixels * map;
506
507 // Compute interpolated skymap value
508 intensity = wgt1 * m_pixels[inx1 + offset] +
509 wgt2 * m_pixels[inx2 + offset] +
510 wgt3 * m_pixels[inx3 + offset] +
511 wgt4 * m_pixels[inx4 + offset];
512
513 } // endif: pixel was within map
514
515 // Return intensity
516 return intensity;
517}
518
519
520/*==========================================================================
521 = =
522 = Public methods =
523 = =
524 ==========================================================================*/
525
526 /***********************************************************************//**
527 * @brief Clear instance.
528 *
529 * Resets the sky map to the initial state.
530 ***************************************************************************/
531void GSkymap::clear(void)
532{
533 // Free class members
534 free_members();
535
536 // Initialise members
537 init_members();
538
539 // Return
540 return;
541}
542
543
544/***********************************************************************//**
545 * @brief Clone sky map
546 *
547 * @return Pointer to deep copy of sky map.
548 ***************************************************************************/
549GSkymap* GSkymap::clone(void) const
550{
551 return new GSkymap(*this);
552}
553
554
555/***********************************************************************//**
556 * @brief Converts pixel index into sky map pixel
557 *
558 * @param[in] index Pixel index [0,...,npix()-1].
559 * @return Sky map pixel.
560 *
561 * Converts the pixel @p index into a sky map pixel (GSkyPixel).The dimension
562 * of GSkyPixel will be identical to the dimension of the sky map (i.e. a 1D
563 * sky map leads to a 1D GSkyPixel object, a 2D sky map leads to a 2D
564 * GSkyPixel object.
565 ***************************************************************************/
566GSkyPixel GSkymap::inx2pix(const int& index) const
567{
568 // Initialise sky map pixel
569 GSkyPixel pixel;
570
571 // Get x and y indices
572 if (m_num_x != 0) { //!< 2D sky map
573 pixel.x(double(index % m_num_x));
574 pixel.y(double(index / m_num_x));
575 }
576 else { //!< 1D sky map
577 pixel.index(index);
578 }
579
580 // Return pixel
581 return pixel;
582}
583
584
585/***********************************************************************//**
586 * @brief Returns sky direction of pixel
587 *
588 * @param[in] index Pixel index [0,...,npix()-1].
589 * @return Sky direction.
590 *
591 * @exception GException::invalid_value
592 * No valid sky projection found.
593 *
594 * Returns sky direction for a given pixel index.
595 ***************************************************************************/
596GSkyDir GSkymap::inx2dir(const int& index) const
597{
598 // Throw error if sky projection is not valid
599 if (m_proj == NULL__null) {
600 std::string msg = "Sky projection has not been defined.";
601 throw GException::invalid_value(G_INX2DIR"GSkymap::inx2dir(int&)", msg);
602 }
603
604 // Determine sky direction from pixel index.
605 GSkyDir dir = m_proj->pix2dir(inx2pix(index));
606
607 // Return sky direction
608 return dir;
609}
610
611
612/***********************************************************************//**
613 * @brief Returns sky direction of pixel
614 *
615 * @param[in] pixel Sky map pixel.
616 * @return Sky direction.
617 *
618 * @exception GException::invalid_value
619 * No valid sky projection found.
620 * @exception GException::invalid_argument
621 * 2D sky map pixel used to access 1D projection.
622 *
623 * Returns sky direction for a given sky map @p pixel.
624 ***************************************************************************/
625GSkyDir GSkymap::pix2dir(const GSkyPixel& pixel) const
626{
627 // Throw error if WCS is not valid
628 if (m_proj == NULL__null) {
629 std::string msg = "Sky projection has not been defined.";
630 throw GException::invalid_value(G_PIX2DIR"GSkymap::pix2dir(GSkyPixel&)", msg);
631 }
632
633 // Initialise sky direction
634 GSkyDir dir;
635
636 // If pixel size matches the projection size then perform a straight
637 // forward conversion
638 if (m_proj->size() == pixel.size()) {
639 dir = m_proj->pix2dir(pixel);
640 }
641
642 // ... otherwise, if we have a 2D projection but a 1D pixel then
643 // interpret the pixel as the linear index in the pixel array
644 else if (m_proj->size() == 2) {
645 dir = m_proj->pix2dir(GSkyPixel(inx2pix(int(pixel))));
646 }
647
648 // ... otherwise we have a 1D projection but a 2D pixel. There is
649 // no unambiguous way to handle this case, hence we throw an exception
650 else {
651 std::string msg = "A 2-dimensional sky map pixel "+pixel.print()+
652 " is used to determine the sky direction for"
653 " the 1-dimensional sky projection \""+
654 m_proj->name()+"\"\n"
655 "Please specify a 1-dimensional sky map pixel.";
656 throw GException::invalid_argument(G_PIX2DIR"GSkymap::pix2dir(GSkyPixel&)", msg);
657 }
658
659 // Return sky direction
660 return dir;
661}
662
663
664/***********************************************************************//**
665 * @brief Converts sky map pixel into pixel index
666 *
667 * @param[in] pixel Sky map pixel.
668 * @return Pixel index [0,...,npix()-1].
669 *
670 * Converts a sky map @p pixel into the pixel index.
671 ***************************************************************************/
672int GSkymap::pix2inx(const GSkyPixel& pixel) const
673{
674 // Initialise pixel index
675 int index = 0;
676
677 // Handle 1D sky map pixel
678 if (pixel.is1D()) {
679 index = int(pixel);
680 }
681
682 // Handle 2D sky map pixel
683 else if (pixel.is2D()) {
684
685 // Get x and y indices by rounding the (x,y) values
686 int ix = int(pixel.x()+0.5);
687 int iy = int(pixel.y()+0.5);
688
689 // Set index
690 index = ix + iy * m_num_x;
691
692 }
693
694 // Return index
695 return index;
696}
697
698
699/***********************************************************************//**
700 * @brief Returns pixel index for a given sky direction
701 *
702 * @param[in] dir Sky direction.
703 * @return Pixel index [0,...,npix()-1].
704 *
705 * @exception GException::invalid_value
706 * No valid sky projection found.
707 *
708 * Returns sky map pixel index for a given sky direction.
709 ***************************************************************************/
710int GSkymap::dir2inx(const GSkyDir& dir) const
711{
712 // Throw error if WCS is not valid
713 if (m_proj == NULL__null) {
714 std::string msg = "Sky projection has not been defined.";
715 throw GException::invalid_value(G_DIR2INX"GSkymap::dir2inx(GSkyDir&)", msg);
716 }
717
718 // Determine pixel index for a given sky direction
719 int index = pix2inx(m_proj->dir2pix(dir));
720
721 // Return pixel index
722 return index;
723}
724
725
726/***********************************************************************//**
727 * @brief Returns sky map pixel for a given sky direction
728 *
729 * @param[in] dir Sky direction.
730 * @return Sky map pixel.
731 *
732 * @exception GException::invalid_value
733 * No valid sky projection found.
734 *
735 * Returns sky map pixel for a given sky direction.
736 ***************************************************************************/
737GSkyPixel GSkymap::dir2pix(const GSkyDir& dir) const
738{
739 // Throw error if WCS is not valid
740 if (m_proj == NULL__null) {
741 std::string msg = "Sky projection has not been defined.";
742 throw GException::invalid_value(G_DIR2PIX"GSkymap::dir2pix(GSkyDir&)", msg);
743 }
744
745 // Determine pixel for a given sky direction
746 GSkyPixel pixel = m_proj->dir2pix(dir);
747
748 // Return pixel
749 return pixel;
750}
751
752
753/***********************************************************************//**
754 * @brief Returns solid angle of pixel
755 *
756 * @param[in] index Pixel index [0,...,npix()-1].
757 * @return Solid angle (steradians)
758 *
759 * @exception GException::invalid_value
760 * No valid sky projection found.
761 *
762 * Returns the solid angle of the pixel with the specified @p index.
763 ***************************************************************************/
764double GSkymap::solidangle(const int& index) const
765{
766 // Throw error if WCS is not valid
767 if (m_proj == NULL__null) {
768 std::string msg = "Sky projection has not been defined.";
769 throw GException::invalid_value(G_SOLIDANGLE1"GSkymap::solidangle(int&)", msg);
770 }
771
772 // Determine solid angle from pixel index.
773 double solidangle = m_proj->solidangle(inx2pix(index));
774
775 // Return solid angle
776 return solidangle;
777}
778
779
780/***********************************************************************//**
781 * @brief Returns solid angle of pixel
782 *
783 * @param[in] pixel Sky map pixel.
784 * @return Solid angle (steradians)
785 *
786 * @exception GException::invalid_value
787 * No valid sky projection found.
788 *
789 * Returns the solid angle of the specified sky map @p pixel.
790 ***************************************************************************/
791double GSkymap::solidangle(const GSkyPixel& pixel) const
792{
793 // Throw error if WCS is not valid
794 if (m_proj == NULL__null) {
795 std::string msg = "Sky projection has not been defined.";
796 throw GException::invalid_value(G_SOLIDANGLE2"GSkymap::solidangle(GSkyPixel&)", msg);
797 }
798
799 // Initialise solid angle
800 double solidangle = 0.0;
801
802 // If pixel size matches the projection size then perform a straight
803 // forward solid angle determination
804 if (m_proj->size() == pixel.size()) {
805 solidangle = m_proj->solidangle(pixel);
806 }
807
808 // ... otherwise, if we have a 2D projection but a 1D pixel then
809 // interpret the pixel as the linear index in the pixel array
810 else if (m_proj->size() == 2) {
811 solidangle = m_proj->solidangle(GSkyPixel(inx2pix(int(pixel))));
812 }
813
814 // ... otherwise we have a 1D projection but a 2D pixel. There is
815 // no unambiguous way to handle this case, hence we throw an exception
816 else {
817 std::string msg = "A 2-dimensional sky map pixel "+pixel.print()+
818 " is used to determine the solid angle for"
819 " the 1-dimensional sky projection \""+
820 m_proj->name()+"\"\n"
821 "Please specify a 1-dimensional sky map pixel.";
822 throw GException::invalid_argument(G_SOLIDANGLE2"GSkymap::solidangle(GSkyPixel&)", msg);
823 }
824
825 // Return solid angle
826 return solidangle;
827}
828
829
830/***********************************************************************//**
831 * @brief Set sky projection
832 *
833 * @param[in] proj Sky projection.
834 *
835 * Sets the projection from celestial to pixel coordinates. The method
836 * performs a deep copy of @p proj, allowing to destroy the argument after
837 * using the method.
838 *
839 * Warning: this method may corrupt the GSkymap object as it allows assigning
840 * for example a 1D projection to a 2D skymap. Please use this method only
841 * when you know what you're doing.
842 *
843 * @todo We may restrict this method to not allow changing the projection
844 * dimension.
845 ***************************************************************************/
846void GSkymap::projection(const GSkyProjection& proj)
847{
848 // Free any existing WCS
849 if (m_proj != NULL__null) delete m_proj;
850
851 // Clone input WCS
852 m_proj = proj.clone();
853
854 // Return
855 return;
856}
857
858
859/***********************************************************************//**
860 * @brief Verifies if sky direction falls in map
861 *
862 * @param[in] dir Sky direction.
863 *
864 * This method checks if the specified sky direction falls within the pixels
865 * covered by the skymap. The method uses the dir2xy method to convert the
866 * sky direction into 2D pixel indices, and then checks whether the pixel
867 * indices fall in the skymap.
868 ***************************************************************************/
869bool GSkymap::contains(const GSkyDir& dir) const
870{
871 // Convert sky direction into sky pixel
872 GSkyPixel pixel = dir2pix(dir);
873
874 // Return location flag
875 return (contains(pixel));
876}
877
878
879/***********************************************************************//**
880 * @brief Checks if sky map pixel falls in map
881 *
882 * @param[in] pixel Sky map pixel.
883 * @return Trus if pixels is within map, false otherwise.
884 *
885 * Checks whether the specified sky map @p pixel falls within the skymap
886 * or not.
887 ***************************************************************************/
888bool GSkymap::contains(const GSkyPixel& pixel) const
889{
890 // Initialise containment flag
891 bool inmap = false;
892
893 // Test 1D pixels
894 if (pixel.is1D()) {
895 if (pixel.index()+0.5 >= 0.0 && pixel.index()-0.5 < m_num_pixels) {
896 inmap = true;
897 }
898 }
899
900 // Test 2D pixels
901 else if (pixel.is2D()) {
902
903 // If pixel is in range then set containment flag to true
904 if ((pixel.x()+0.5 >= 0.0 && pixel.x()-0.5 < m_num_x) &&
905 (pixel.y()+0.5 >= 0.0 && pixel.y()-0.5 < m_num_y)) {
906 inmap = true;
907 }
908
909 }
910
911 // Return containment flag
912 return inmap;
913}
914
915
916/***********************************************************************//**
917 * @brief Load skymap from FITS file.
918 *
919 * @param[in] filename FITS file name..
920 *
921 * Loads HEALPix and non HEALPix skymaps. First searches for HEALPix map in
922 * FITS file by scanning all HDUs for PIXTYPE=HEALPIX. If no HEALPix map has
923 * been found then search load first non-empty image.
924 *
925 * @todo Do we have to restrict a HEALPix map to a BinTable and a WCS map
926 * to a Double precision image???
927 ***************************************************************************/
928void GSkymap::load(const std::string& filename)
929{
930 // Free memory and initialise members
931 free_members();
932 init_members();
933
934 // Open FITS file
935 GFits fits(filename);
936
937 // Get number of HDUs
938 int num = fits.size();
939
940 // Initialize load flag
941 bool loaded = false;
942
943 // First search for HEALPix extension. We can skip the first extension
944 // since this is always an image and a HEALPix map is stored in a
945 // binary table
946 for (int extno = 1; extno < num; ++extno) {
947
948 // Get reference to HDU
949 const GFitsHDU& hdu = *fits.at(extno);
950
951 // If PIXTYPE keyword equals "HEALPIX" then load map
952 if (hdu.hascard("PIXTYPE") && hdu.string("PIXTYPE") == "HEALPIX") {
953 read_healpix(static_cast<const GFitsTable&>(hdu));
954 loaded = true;
955 break;
956 }
957
958 } // endfor: looped over HDUs
959
960 // If we have not found a HEALPIX map then search now for image.
961 // Skip empty images
962 if (!loaded) {
963 for (int extno = 0; extno < num; ++extno) {
964
965 // Get referene to HDU
966 const GFitsHDU& hdu = *fits.at(extno);
967
968 // Skip if extension is not an image
969 if (extno > 0) {
970 if (hdu.string("XTENSION") != "IMAGE")
971 continue;
972 }
973
974 // Load WCS map
975 read_wcs(static_cast<const GFitsImage&>(hdu));
976 loaded = true;
977 break;
978
979 } // endfor: looped over HDUs
980 } // endif: no HEALPix map found
981
982 // Close FITS file
983 fits.close();
984
985 // Return
986 return;
987}
988
989
990/***********************************************************************//**
991 * @brief Save skymap into FITS file.
992 *
993 * @param[in] filename FITS file name.
994 * @param[in] clobber Overwrite existing file? (true=yes)
995 *
996 * The method does nothing if the skymap holds no valid WCS.
997 ***************************************************************************/
998void GSkymap::save(const std::string& filename, bool clobber) const
999{
1000 // Continue only if we have data to save
1001 if (m_proj != NULL__null) {
1002
1003 // Initialise HDU pointer
1004 GFitsHDU* hdu = NULL__null;
1005
1006 // Case A: Skymap is Healpix
1007 if (m_proj->code() == "HPX") {
1008 hdu = create_healpix_hdu();
1009 }
1010
1011 // Case B: Skymap is not Healpix
1012 else {
1013 hdu = create_wcs_hdu();
1014 }
1015
1016 // Create FITS file and save it to disk
1017 if (hdu != NULL__null) {
1018 GFits fits;
1019 fits.append(*hdu);
1020 fits.saveto(filename, clobber);
1021 }
1022
1023 // Delete HDU
1024 if (hdu != NULL__null) delete hdu;
1025
1026 } // endif: we had data to save
1027
1028 // Return
1029 return;
1030}
1031
1032
1033/***********************************************************************//**
1034 * @brief Read skymap from FITS HDU
1035 *
1036 * @param[in] hdu FITS HDU.
1037 ***************************************************************************/
1038void GSkymap::read(const GFitsHDU& hdu)
1039{
1040 // Free memory and initialise members
1041 free_members();
1042 init_members();
1043
1044 // Initialize load flag
1045 bool loaded = false;
1046
1047 // If PIXTYPE keyword equals "HEALPIX" then load map
1048 if (hdu.hascard("PIXTYPE") && hdu.string("PIXTYPE") == "HEALPIX") {
1049 read_healpix(static_cast<const GFitsTable&>(hdu));
1050 loaded = true;
1051 }
1052
1053 // ... otherwise try loading as non HEALPix map
1054 if (!loaded) {
1055
1056 // Load only if HDU contains an image
1057 if (hdu.exttype() == 0) {
1058 read_wcs(static_cast<const GFitsImage&>(hdu));
1059 loaded = true;
Value stored to 'loaded' is never read
1060 }
1061
1062 } // endif
1063
1064 // Return
1065 return;
1066}
1067
1068
1069/***********************************************************************//**
1070 * @brief Write skymap into FITS file
1071 *
1072 * @param[in] file FITS file pointer.
1073 ***************************************************************************/
1074void GSkymap::write(GFits& file) const
1075{
1076 // Continue only if we have data to save
1077 if (m_proj != NULL__null) {
1078
1079 // Initialise HDU pointer
1080 GFitsHDU* hdu = NULL__null;
1081
1082 // Case A: Skymap is Healpix
1083 if (m_proj->code() == "HPX") {
1084 hdu = create_healpix_hdu();
1085 }
1086
1087 // Case B: Skymap is not Healpix
1088 else {
1089 hdu = create_wcs_hdu();
1090 }
1091
1092 // Append HDU to FITS file.
1093 if (hdu != NULL__null) {
1094 file.append(*hdu);
1095 }
1096
1097 // Delete HDU
1098 if (hdu != NULL__null) delete hdu;
1099
1100 } // endif: we had data to save
1101
1102 // Return
1103 return;
1104}
1105
1106
1107/***********************************************************************//**
1108 * @brief Print sky map
1109 *
1110 * @param[in] chatter Chattiness (defaults to NORMAL).
1111 * @return String containing sky map information.
1112 ***************************************************************************/
1113std::string GSkymap::print(const GChatter& chatter) const
1114{
1115 // Initialise result string
1116 std::string result;
1117
1118 // Continue only if chatter is not silent
1119 if (chatter != SILENT) {
1120
1121 // Append header
1122 result.append("=== GSkymap ===");
1123
1124 // Append information
1125 result.append("\n"+gammalib::parformat("Number of pixels"));
1126 result.append(gammalib::str(m_num_pixels));
1127 result.append("\n"+gammalib::parformat("Number of maps"));
1128 result.append(gammalib::str(m_num_maps));
1129 if (m_proj != NULL__null && m_proj->size() == 2) {
1130 result.append("\n"+gammalib::parformat("X axis dimension"));
1131 result.append(gammalib::str(m_num_x));
1132 result.append("\n"+gammalib::parformat("Y axis dimension"));
1133 result.append(gammalib::str(m_num_y));
1134 }
1135
1136 // Append sky projection information
1137 if (m_proj != NULL__null) {
1138 result.append("\n"+m_proj->print(chatter));
1139 }
1140 else {
1141 result.append("\n"+gammalib::parformat("Sky projection"));
1142 result.append("not defined");
1143 }
1144
1145 } // endif: chatter was not silent
1146
1147 // Return result
1148 return result;
1149}
1150
1151
1152/*==========================================================================
1153 = =
1154 = Private methods =
1155 = =
1156 ==========================================================================*/
1157
1158/***********************************************************************//**
1159 * @brief Initialise class members
1160 ***************************************************************************/
1161void GSkymap::init_members(void)
1162{
1163 // Initialise members
1164 m_num_pixels = 0;
1165 m_num_maps = 0;
1166 m_num_x = 0;
1167 m_num_y = 0;
1168 m_proj = NULL__null;
1169 m_pixels = NULL__null;
1170
1171 // Return
1172 return;
1173}
1174
1175
1176/***********************************************************************//**
1177 * @brief Allocate skymap pixels
1178 ***************************************************************************/
1179void GSkymap::alloc_pixels(void)
1180{
1181 // Compute data size
1182 int size = m_num_pixels * m_num_maps;
1183
1184 // Continue only if there are pixels
1185 if (size > 0) {
1186
1187 // Allocate pixels and initialize them to 0
1188 m_pixels = new double[size];
1189 for (int i = 0; i < size; ++i) {
1190 m_pixels[i] = 0.0;
1191 }
1192
1193 } // endif: there were pixels
1194
1195 // Return
1196 return;
1197}
1198
1199
1200/***********************************************************************//**
1201 * @brief Copy class members
1202 *
1203 * @param[in] map Sky map.
1204 ***************************************************************************/
1205void GSkymap::copy_members(const GSkymap& map)
1206{
1207 // Copy attributes
1208 m_num_pixels = map.m_num_pixels;
1209 m_num_maps = map.m_num_maps;
1210 m_num_x = map.m_num_x;
1211 m_num_y = map.m_num_y;
1212
1213 // Clone sky projection if it is valid
1214 if (map.m_proj != NULL__null) m_proj = map.m_proj->clone();
1215
1216 // Compute data size
1217 int size = m_num_pixels * m_num_maps;
1218
1219 // Copy pixels
1220 if (size > 0 && map.m_pixels != NULL__null) {
1221 alloc_pixels();
1222 for (int i = 0; i < size; ++i) {
1223 m_pixels[i] = map.m_pixels[i];
1224 }
1225 }
1226
1227 // Return
1228 return;
1229}
1230
1231
1232/***********************************************************************//**
1233 * @brief Delete class members
1234 ***************************************************************************/
1235void GSkymap::free_members(void)
1236{
1237 // Free memory
1238 if (m_proj != NULL__null) delete m_proj;
1239 if (m_pixels != NULL__null) delete [] m_pixels;
1240
1241 // Signal free pointers
1242 m_proj = NULL__null;
1243 m_pixels = NULL__null;
1244
1245 // Reset number of pixels
1246 m_num_pixels = 0;
1247 m_num_maps = 0;
1248 m_num_x = 0;
1249 m_num_y = 0;
1250
1251 // Return
1252 return;
1253}
1254
1255
1256/***********************************************************************//**
1257 * @brief Set World Coordinate System
1258 *
1259 * @param[in] wcs World Coordinate System code.
1260 * @param[in] coords Coordinate system.
1261 * @param[in] crval1 X value of reference pixel.
1262 * @param[in] crval2 Y value of reference pixel.
1263 * @param[in] crpix1 X index of reference pixel.
1264 * @param[in] crpix2 Y index of reference pixel.
1265 * @param[in] cdelt1 Increment in x direction at reference pixel (deg).
1266 * @param[in] cdelt2 Increment in y direction at reference pixel (deg).
1267 * @param[in] cd Astrometry parameters (2x2 matrix, deg/pixel).
1268 * @param[in] pv2 Projection parameters (length WCS type dependent).
1269 *
1270 * @exception GException::wcs_invalid
1271 * Invalid wcs parameter (World Coordinate System not known).
1272 *
1273 * This method sets the WCS projection pointer based on the WCS code and
1274 * sky map parameters. It makes use of the GWcsRegistry class to allocate
1275 * the correct derived class. Note that this method does not support the
1276 * HPX projection.
1277 *
1278 * @todo Remove cd and pv2 parameters.
1279 ***************************************************************************/
1280void GSkymap::set_wcs(const std::string& wcs, const std::string& coords,
1281 const double& crval1, const double& crval2,
1282 const double& crpix1, const double& crpix2,
1283 const double& cdelt1, const double& cdelt2,
1284 const GMatrix& cd, const GVector& pv2)
1285{
1286 // Convert WCS to upper case
1287 std::string uwcs = gammalib::toupper(wcs);
1288
1289 // Check if HPX was requested (since this is not allowed)
1290 if (uwcs == "HPX") {
1291 throw GException::wcs_invalid(G_SET_WCS"GSkymap::set_wcs(std::string&, std::string&, double&,"
" double&, double&, double&, double&, double&,"
" GMatrix&, GVector&)"
, uwcs,
1292 "Method not valid for HPX projection.");
1293 }
1294
1295 // ... otherwise get projection from registry
1296 else {
1297 // Allocate WCS registry
1298 GWcsRegistry registry;
1299
1300 // Allocate projection from registry
1301 GWcs* projection = registry.alloc(uwcs);
1302 m_proj = projection;
1303
1304 // Signal if projection type is not known
1305 if (projection == NULL__null) {
1306 std::string message = "Projection code not known. "
1307 "Should be one of "+registry.list()+".";
1308 throw GException::wcs_invalid(G_SET_WCS"GSkymap::set_wcs(std::string&, std::string&, double&,"
" double&, double&, double&, double&, double&,"
" GMatrix&, GVector&)"
, uwcs, message);
1309 }
1310
1311 // Setup WCS
1312 projection->set(coords, crval1, crval2, crpix1, crpix2,
1313 cdelt1, cdelt2);
1314
1315 } // endelse: got projection from registry
1316
1317 // Return
1318 return;
1319}
1320
1321
1322/***********************************************************************//**
1323 * @brief Read Healpix data from FITS table.
1324 *
1325 * @param[in] table FITS table.
1326 *
1327 * HEALPix data may be stored in various formats depending on the
1328 * application that has writted the data. HEALPix IDL, for example, may
1329 * store the data in vectors of length 1024 if the number of pixels is
1330 * a multiple of 1024. On the other hand, vectors may also be used to store
1331 * several HEALPix maps into a single column. Alternatively, multiple maps
1332 * may be stored in multiple columns.
1333 ***************************************************************************/
1334void GSkymap::read_healpix(const GFitsTable& table)
1335{
1336 // Determine number of rows and columns in table
1337 int nrows = table.nrows();
1338 int ncols = table.ncols();
1339 #if defined(G_READ_HEALPIX_DEBUG)
1340 std::cout << "nrows=" << nrows << " ncols=" << ncols << std::endl;
1341 #endif
1342
1343 // Allocate Healpix projection
1344 m_proj = new GHealpix;
1345
1346 // Read WCS information from FITS header
1347 m_proj->read(table);
1348
1349 // Set number of pixels based on NSIDE parameter
1350 m_num_pixels = static_cast<GHealpix*>(m_proj)->npix();
1351 #if defined(G_READ_HEALPIX_DEBUG)
1352 std::cout << "m_num_pixels=" << m_num_pixels << std::endl;
1353 #endif
1354
1355 // Number of map pixels has to be a multiple of the number of
1356 // rows in column
1357 if (m_num_pixels % nrows != 0) {
1358 throw GException::skymap_bad_size(G_READ_HEALPIX"GSkymap::read_healpix(GFitsTable*)", nrows,
1359 m_num_pixels);
1360 }
1361
1362 // Determine vector length for HEALPix data storage
1363 int nentry = m_num_pixels / nrows;
1364 #if defined(G_READ_HEALPIX_DEBUG)
1365 std::cout << "nentry=" << nentry << std::endl;
1366 #endif
1367
1368 // Determine number of maps from the number of maps that fit into
1369 // all columns. Only count columns that can fully hold the map.
1370 m_num_maps = 0;
1371 for (int icol = 0; icol < ncols; ++icol) {
1372 const GFitsTableCol* col = table[icol];
1373 if (col->number() % nentry == 0) {
1374 m_num_maps += col->number() / nentry;
1375 }
1376 }
1377 #if defined(G_READ_HEALPIX_DEBUG)
1378 std::cout << "m_num_maps=" << m_num_maps << std::endl;
1379 #endif
1380
1381 // Allocate pixels to hold the map
1382 alloc_pixels();
1383
1384 // Initialise map counter
1385 int imap = 0;
1386
1387 // Loop over all columns
1388 for (int icol = 0; icol < ncols; ++icol) {
1389
1390 // Get next column
1391 const GFitsTableCol* col = table[icol];
1392
1393 // Only consider columns that can fully hold maps
1394 if (col->number() % nentry == 0) {
1395
1396 // Determine number of maps in column
1397 int num = col->number() / nentry;
1398
1399 // Loop over all maps in column
1400 int inx_start = 0;
1401 int inx_end = nentry;
1402 for (int i = 0; i < num; ++i) {
1403
1404 // Load map
1405 double *ptr = m_pixels + m_num_pixels*imap;
1406 for (int row = 0; row < col->length(); ++row) {
1407 for (int inx = inx_start; inx < inx_end; ++inx) {
1408 *ptr++ = col->real(row,inx);
1409 }
1410 }
1411 #if defined(G_READ_HEALPIX_DEBUG)
1412 std::cout << "Load map=" << imap << " index="
1413 << inx_start << "-" << inx_end << std::endl;
1414 #endif
1415
1416 // Increment index range
1417 inx_start = inx_end;
1418 inx_end += nentry;
1419
1420 // Increment map counter
1421 imap++;
1422
1423 // Break if we have loaded all maps
1424 if (imap >= m_num_maps) {
1425 break;
1426 }
1427
1428 } // endfor: looped over all maps in column
1429 } // endif: column could fully hold maps
1430
1431 // Break if we have loaded all maps
1432 if (imap >= m_num_maps) {
1433 break;
1434 }
1435
1436 } // endfor: looped over all columns
1437
1438 // Return
1439 return;
1440}
1441
1442
1443/***********************************************************************//**
1444 * @brief Read WCS image from FITS HDU
1445 *
1446 * @param[in] image FITS image.
1447 *
1448 * @exception GException::skymap_bad_image_dim
1449 * WCS image has invalid dimension (naxis=2 or 3).
1450 ***************************************************************************/
1451void GSkymap::read_wcs(const GFitsImage& image)
1452{
1453 // Allocate WCS
1454 alloc_wcs(image);
1455
1456 // Read projection information from FITS header
1457 m_proj->read(image);
1458
1459 // Extract map dimension and number of maps from image
1460 if (image.naxis() == 2) {
1461 m_num_x = image.naxes(0);
1462 m_num_y = image.naxes(1);
1463 m_num_maps = 1;
1464 }
1465 else if (image.naxis() >= 3) {
1466 m_num_x = image.naxes(0);
1467 m_num_y = image.naxes(1);
1468 m_num_maps = image.naxes(2);
1469 }
1470 else {
1471 throw GException::skymap_bad_image_dim(G_READ_WCS"GSkymap::read_wcs(GFitsImage*)", image.naxis());
1472 }
1473 #if defined(G_READ_WCS_DEBUG)
1474 std::cout << "m_num_x=" << m_num_x << std::endl;
1475 std::cout << "m_num_y=" << m_num_y << std::endl;
1476 std::cout << "m_num_maps=" << m_num_maps << std::endl;
1477 #endif
1478
1479 // Compute number of pixels
1480 m_num_pixels = m_num_x * m_num_y;
1481 #if defined(G_READ_WCS_DEBUG)
1482 std::cout << "m_num_pixels=" << m_num_pixels << std::endl;
1483 #endif
1484
1485 // Allocate pixels to hold the map
1486 alloc_pixels();
1487
1488 // Read image
1489 if (image.naxis() == 2) {
1490 double* ptr = m_pixels;
1491 for (int iy = 0; iy < m_num_y; ++iy) {
1492 for (int ix = 0; ix < m_num_x; ++ix) {
1493 *ptr++ = image.pixel(ix,iy);
1494 }
1495 }
1496 }
1497 else {
1498 double* ptr = m_pixels;
1499 for (int imap = 0; imap < m_num_maps; ++imap) {
1500 for (int iy = 0; iy < m_num_y; ++iy) {
1501 for (int ix = 0; ix < m_num_x; ++ix) {
1502 *ptr++ = image.pixel(ix,iy,imap);
1503 }
1504 }
1505 }
1506 }
1507
1508 // Return
1509 return;
1510}
1511
1512
1513/***********************************************************************//**
1514 * @brief Allocate WCS class
1515 *
1516 * @param[in] image FITS image.
1517 *
1518 * @exception GException::fits_key_not_found
1519 * Unable to find required FITS header keyword.
1520 * @exception GException::skymap_bad_ctype
1521 * CTYPE1 and CTYPE2 keywords are incompatible.
1522 * @exception GException::wcs_invalid
1523 * WCS projection of FITS file not supported by GammaLib.
1524 ***************************************************************************/
1525void GSkymap::alloc_wcs(const GFitsImage& image)
1526{
1527 // Get standard keywords
1528 std::string ctype1 = image.string("CTYPE1");
1529 std::string ctype2 = image.string("CTYPE2");
1530
1531 // Extract projection type
1532 std::string xproj = ctype1.substr(5,3);
1533 std::string yproj = ctype2.substr(5,3);
1534
1535 // Check that projection type is identical on both axes
1536 if (xproj != yproj) {
1537 throw GException::skymap_bad_ctype(G_ALLOC_WCS"GSkymap::alloc_wcs(GFitsImage*)",
1538 ctype1, ctype2);
1539 }
1540
1541 // Allocate WCS registry
1542 GWcsRegistry registry;
1543
1544 // Allocate projection from registry
1545 m_proj = registry.alloc(xproj);
1546
1547 // Signal if projection type is not known
1548 if (m_proj == NULL__null) {
1549 std::string message = "Projection code not known. "
1550 "Should be one of "+registry.list()+".";
1551 throw GException::wcs_invalid(G_ALLOC_WCS"GSkymap::alloc_wcs(GFitsImage*)", xproj, message);
1552 }
1553
1554 // Return
1555 return;
1556}
1557
1558
1559/***********************************************************************//**
1560 * @brief Create FITS HDU containing Healpix data
1561 *
1562 * This method allocates a binary table HDU that contains the Healpix data.
1563 * Deallocation of the table has to be done by the client.
1564 ***************************************************************************/
1565GFitsBinTable* GSkymap::create_healpix_hdu(void) const
1566{
1567 // Initialise result to NULL pointer
1568 GFitsBinTable* hdu = NULL__null;
1569
1570 // Compute size of Healpix data
1571 int size = m_num_pixels * m_num_maps;
1572
1573 // Continue only if we have pixels
1574 if (size > 0) {
1575
1576 // Set number of rows and columns
1577 int rows = m_num_pixels;
1578 int number = m_num_maps;
1579
1580 // Create column to hold Healpix data
1581 GFitsTableDoubleCol column = GFitsTableDoubleCol("DATA", rows, number);
1582
1583 // Fill data into column
1584 double* ptr = m_pixels;
1585 for (int inx = 0; inx < number; ++inx) {
1586 for (int row = 0; row < rows; ++row) {
1587 column(row,inx) = *ptr++;
1588 }
1589 }
1590
1591 // Create HDU that contains Healpix map in a binary table
1592 hdu = new GFitsBinTable(rows);
1593 hdu->append(column);
1594
1595 } // endif: there were pixels
1596
1597 // ... otherwise create an empty header
1598 else {
1599 hdu = new GFitsBinTable;
1600 }
1601
1602 // Set extension name
1603 hdu->extname("HEALPIX");
1604
1605 // If we have WCS information then write into FITS header
1606 if (m_proj != NULL__null) m_proj->write(*hdu);
1607
1608 // Set additional keywords
1609 hdu->card("NBRBINS", m_num_maps, "Number of HEALPix maps");
1610
1611 // Return HDU
1612 return hdu;
1613}
1614
1615
1616/***********************************************************************//**
1617 * @brief Create FITS HDU containing WCS image
1618 *
1619 * This method allocates an image HDU that contains the WCS image data.
1620 * Deallocation of the image has to be done by the client.
1621 *
1622 * @todo Set additional keywords.
1623 ***************************************************************************/
1624GFitsImageDouble* GSkymap::create_wcs_hdu(void) const
1625{
1626 // Initialise result to NULL pointer
1627 GFitsImageDouble* hdu = NULL__null;
1628
1629 // Compute size of Healpix data
1630 int size = m_num_pixels * m_num_maps;
1631
1632 // Continue only if we have pixels
1633 if (size > 0) {
1634
1635 // Set axis parameters for image construction
1636 int naxis = (m_num_maps == 1) ? 2 : 3;
1637 int naxes[] = {m_num_x, m_num_y, m_num_maps};
1638
1639 // Allocate image
1640 hdu = new GFitsImageDouble(naxis, naxes);
1641
1642 // Store data in image
1643 if (naxis == 2) {
1644 double* ptr = m_pixels;
1645 for (int iy = 0; iy < m_num_y; ++iy) {
1646 for (int ix = 0; ix < m_num_x; ++ix) {
1647 (*hdu)(ix,iy) = *ptr++;
1648 }
1649 }
1650 }
1651 else {
1652 double* ptr = m_pixels;
1653 for (int imap = 0; imap < m_num_maps; ++imap) {
1654 for (int iy = 0; iy < m_num_y; ++iy) {
1655 for (int ix = 0; ix < m_num_x; ++ix) {
1656 (*hdu)(ix,iy,imap) = *ptr++;
1657 }
1658 }
1659 }
1660 }
1661
1662 } // endif: there were pixels
1663
1664 // ... otherwise create an empty header
1665 else {
1666 hdu = new GFitsImageDouble;
1667 }
1668
1669 // Set extension name
1670 hdu->extname("IMAGE");
1671
1672 // If we have sky projection information then write into FITS header
1673 if (m_proj != NULL__null) m_proj->write(*hdu);
1674
1675 // Set additional keywords
1676 //TODO
1677
1678 // Return HDU
1679 return hdu;
1680}