File: | src/sky/GSkymap.cpp |
Location: | line 1059, column 13 |
Description: | Value stored to 'loaded' is never read |
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 | ***************************************************************************/ |
83 | GSkymap::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 | ***************************************************************************/ |
98 | GSkymap::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 | ***************************************************************************/ |
124 | GSkymap::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 | ***************************************************************************/ |
172 | GSkymap::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 | ***************************************************************************/ |
230 | GSkymap::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 | ***************************************************************************/ |
246 | GSkymap::~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 | ***************************************************************************/ |
268 | GSkymap& 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 | ***************************************************************************/ |
302 | double& 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 | ***************************************************************************/ |
335 | const 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 | ***************************************************************************/ |
370 | double& 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 | ***************************************************************************/ |
408 | const 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 | ***************************************************************************/ |
448 | double 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 | ***************************************************************************/ |
531 | void 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 | ***************************************************************************/ |
549 | GSkymap* 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 | ***************************************************************************/ |
566 | GSkyPixel 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 | ***************************************************************************/ |
596 | GSkyDir 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 | ***************************************************************************/ |
625 | GSkyDir 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 | ***************************************************************************/ |
672 | int 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 | ***************************************************************************/ |
710 | int 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 | ***************************************************************************/ |
737 | GSkyPixel 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 | ***************************************************************************/ |
764 | double 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 | ***************************************************************************/ |
791 | double 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 | ***************************************************************************/ |
846 | void 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 | ***************************************************************************/ |
869 | bool 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 | ***************************************************************************/ |
888 | bool 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 | ***************************************************************************/ |
928 | void 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 | ***************************************************************************/ |
998 | void 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 | ***************************************************************************/ |
1038 | void 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 | ***************************************************************************/ |
1074 | void 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 | ***************************************************************************/ |
1113 | std::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 | ***************************************************************************/ |
1161 | void 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 | ***************************************************************************/ |
1179 | void 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 | ***************************************************************************/ |
1205 | void 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 | ***************************************************************************/ |
1235 | void 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 | ***************************************************************************/ |
1280 | void 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 | ***************************************************************************/ |
1334 | void 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 | ***************************************************************************/ |
1451 | void 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 | ***************************************************************************/ |
1525 | void 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 | ***************************************************************************/ |
1565 | GFitsBinTable* 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 | ***************************************************************************/ |
1624 | GFitsImageDouble* 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 | } |