/***************************************************************************
* test_GSky.cpp - test GSky classes *
* ----------------------------------------------------------------------- *
* copyright (C) 2010-2011 by Jurgen Knodlseder *
* ----------------------------------------------------------------------- *
* *
* This program is free software: you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation, either version 3 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program. If not, see . *
* *
***************************************************************************/
/**
* @file test_GSky.cpp
* @brief Testing of sky module.
* @author J. Knodlseder
*/
/* __ Includes ___________________________________________________________ */
#ifdef HAVE_CONFIG_H
#include
#endif
#include
#include "GammaLib.hpp"
#include // cout, cerr
#include // std::exception
/* __ Namespaces _________________________________________________________ */
/* __ Globals ____________________________________________________________ */
/* __ Debug definitions __________________________________________________ */
#define G_WCS_FORTH_BACK_PIXEL_DEBUG
#define G_WCS_COPY_DEBUG
/***********************************************************************//**
* @brief Test consistency of forward and background transformations
*
* @param[in] nx Number of points in X
* @param[in] ny Number of points in Y
* @param[in] crpix1 Reference pixel in X
* @param[in] crpix2 Reference pixel in Y
***************************************************************************/
double wcs_forth_back_pixel(GWcslib* wcs, int nx, int ny, double& crpix1, double& crpix2)
{
// Initialise maximal distance
double dist_max = 0.0;
// Loop over x pixels
for (int ix = -nx; ix <= nx; ++ix) {
// Set x value
double x = double(ix) + crpix1;
// Skip pixels outside valid range (they are not expected to
// transform bijectively)
if (x < 0 || x >= nx)
continue;
// Loop over y pixels
for (int iy = -ny; iy <= ny; ++iy) {
// Set y value
double y = double(iy) + crpix2;
// Skip pixels outside valid range (they are not expected to
// transform bijectively)
if (y < 0 || y >= ny)
continue;
// Set sky pixel
GSkyPixel pix_in(x,y);
// Forth: Transform to world
GSkyDir dir = wcs->xy2dir(pix_in);
// Back: Transform to pixel
GSkyPixel pix_out = wcs->dir2xy(dir);
// Compute distance
double dx = pix_in.x()-pix_out.x();
double dy = pix_in.y()-pix_out.y();
double dist = sqrt(dx*dx+dy*dy);
// Debug option: Dump discrepancies
#if defined(G_WCS_FORTH_BACK_PIXEL_DEBUG)
if (dist > 0.001) {
std::cout << std::endl;
std::cout << "dist=" << dist;
std::cout << " dx=" << dx;
std::cout << " dy=" << dy;
std::cout << " pix_in=" << pix_in;
std::cout << " pix_out=" << pix_out;
std::cout << " (x,y)=(" << x << "," << y << ")";
std::cout << " dir=" << dir;
}
#endif
// Store maximum distance
if (dist > dist_max)
dist_max = dist;
} // endfor: y pixels
} // endfor: x pixels
// Return
return dist_max;
}
/***********************************************************************//**
* @brief Test consistency of copy
*
* @param[in] nx Number of points in X
* @param[in] ny Number of points in Y
* @param[in] crpix1 Reference pixel in X
* @param[in] crpix2 Reference pixel in Y
***************************************************************************/
double wcs_copy(GWcslib* wcs, int nx, int ny, double& crpix1, double& crpix2)
{
// Make a copy using clone
GWcslib* cpy = wcs->clone();
// Initialise maximal angle and distance
double angle_max = 0.0;
double dist_max = 0.0;
// Loop over x pixels
for (int ix = -nx; ix <= nx; ++ix) {
// Set x value
double x = double(ix) + crpix1;
// Skip pixels outside valid range (they are not expected to
// transform bijectively)
if (x < 0 || x >= nx)
continue;
// Loop over y pixels
for (int iy = -ny; iy <= ny; ++iy) {
// Set y value
double y = double(iy) + crpix2;
// Skip pixels outside valid range (they are not expected to
// transform bijectively)
if (y < 0 || y >= ny)
continue;
// Set sky pixel
GSkyPixel pix_in(x,y);
// Transform to world
GSkyDir dir1 = wcs->xy2dir(pix_in);
GSkyDir dir2 = cpy->xy2dir(pix_in);
double angle = dir1.dist_deg(dir2);
if (angle > angle_max)
angle_max = angle;
// Debug option: Dump discrepancies
#if defined(G_WCS_COPY_DEBUG)
if (angle > 0.001) {
std::cout << std::endl;
std::cout << "angle=" << angle;
std::cout << " dir1=" << dir1;
std::cout << " dir2=" << dir2;
}
#endif
// Transform to pixel
GSkyPixel pix_out1 = wcs->dir2xy(dir1);
GSkyPixel pix_out2 = cpy->dir2xy(dir2);
// Compute distance
double dx = pix_out1.x()-pix_out2.x();
double dy = pix_out1.y()-pix_out2.y();
double dist = sqrt(dx*dx+dy*dy);
if (dist > dist_max)
dist_max = dist;
// Debug option: Dump discrepancies
#if defined(G_WCS_COPY_DEBUG)
if (dist > 0.001) {
std::cout << std::endl;
std::cout << "dist=" << dist;
std::cout << " dx=" << dx;
std::cout << " dy=" << dy;
std::cout << " pix_out1=" << pix_out1;
std::cout << " pix_out2=" << pix_out2;
std::cout << " dir1=" << dir1;
std::cout << " dir2=" << dir2;
}
#endif
} // endfor: y pixels
} // endfor: x pixels
// Return
return ((dist_max > angle_max) ? dist_max : angle_max);
}
/***********************************************************************//**
* @brief Test GWcslib projections
*
* This function test all non-HealPix projections that have been registered.
***************************************************************************/
void test_GWcslib(void)
{
// Allocate parameters for testing
double crval1 = 83.63;
double crval2 = 22.01;
double crpix1 = 100.5;
double crpix2 = 100.5;
double cdelt1 = 0.5;
double cdelt2 = 0.5;
int nx = 200;
int ny = 200;
// Main test protection
try {
// Loop over all non-HealPix projections
GWcsRegistry registry;
for (int i = 0; i < registry.size(); ++i) {
// Skip HealPix
if (registry.code(i) == "HPX")
continue;
// Dump header
std::string test_class = "GWcs" + registry.code(i);
std::cout << "Test "+test_class+": ";
// Perform tests
try {
// Allocate projection CEL and GAL
GWcslib *cel = (GWcslib*)registry.alloc(registry.code(i));
GWcslib *gal = (GWcslib*)registry.alloc(registry.code(i));
// Throw an error if allocation failed
if (cel == NULL || gal == NULL) {
std::cout << std::endl
<< "TEST ERROR: Could not allocate "+test_class+"."
<< std::endl;
throw;
}
// Set projections
try {
cel->set("CEL", crval1, crval2, crpix1, crpix2, cdelt1, cdelt2);
gal->set("GAL", crval1, crval2, crpix1, crpix2, cdelt1, cdelt2);
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Error occured while setting up "+test_class+"."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test forth-back CEL conversion
try {
double tol = 0.0;
if ((tol = wcs_forth_back_pixel(cel, nx, ny, crpix1, crpix2)) > 1.0e-10) {
std::cout << std::endl
<< "TEST ERROR: CEL forth-back transformation tolerance 1.0e-10 exceeded: "
<< tol << std::endl;
throw;
}
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Error while testing CEL forth-back transformations."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test forth-back GAL conversion
try {
double tol = 0.0;
if ((tol = wcs_forth_back_pixel(gal, nx, ny, crpix1, crpix2)) > 1.0e-10) {
std::cout << std::endl
<< "TEST ERROR: GAL forth-back transformation tolerance 1.0e-10 exceeded: "
<< tol << std::endl;
throw;
}
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Error while testing GAL forth-back transformations."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test CEL copy
try {
double tol = 0.0;
if ((tol = wcs_copy(cel, nx, ny, crpix1, crpix2)) > 1.0e-4) {
std::cout << std::endl
<< "TEST ERROR: CEL copy tolerance 1.0e-4 exceeded: "
<< tol << std::endl;
throw;
}
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Error while testing CEL copy."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test GAL copy
try {
double tol = 0.0;
if ((tol = wcs_copy(gal, nx, ny, crpix1, crpix2)) > 1.0e-4) {
std::cout << std::endl
<< "TEST ERROR: GAL copy tolerance 1.0e-4 exceeded: "
<< tol << std::endl;
throw;
}
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Error while testing GAL copy."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
} // endtry: main test block
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Error occured while testing "+test_class+"."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Signal final test success
std::cout << " ok." << std::endl;
} // endfor: looped over all non-HealPix projections
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Error occured while testing GWcslib projections."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
// Exit test
return;
}
/***************************************************************************
* Test: GSkymap_healpix_construct *
***************************************************************************/
void test_GSkymap_healpix_construct(void)
{
// Dump header
std::cout << "Test Healpix GSkymap constructors: ";
// Test void constructor
try {
GSkymap map;
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Unable to construct empty map."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test correct Healpix constructors
try {
GSkymap ring1("HPX", "GAL", 1, "RING", 1);
GSkymap ring2("HPX", "GAL", 2, "RING", 1);
GSkymap ring4("HPX", "GAL", 4, "RING", 1);
GSkymap ring8("HPX", "GAL", 8, "RING", 1);
GSkymap ring16("HPX", "GAL", 16, "RING", 1);
GSkymap ring32("HPX", "GAL", 32, "RING", 1);
GSkymap ring64("HPX", "GAL", 64, "RING", 1);
GSkymap ring128("HPX", "GAL", 128, "RING", 1);
GSkymap ring256("HPX", "GAL", 256, "RING", 1);
GSkymap ring512("HPX", "GAL", 512, "RING", 1);
/*
GSkymap ring1024("HPX", "GAL", 1024, "RING", 1);
GSkymap ring2048("HPX", "GAL", 2048, "RING", 1);
GSkymap ring4096("HPX", "GAL", 4096, "RING", 1);
GSkymap ring8192("HPX", "GAL", 8192, "RING", 1);
*/
GSkymap nest1("HPX", "GAL", 1, "NEST", 1);
GSkymap nest2("HPX", "GAL", 2, "NEST", 1);
GSkymap nest4("HPX", "GAL", 4, "NEST", 1);
GSkymap nest8("HPX", "GAL", 8, "NEST", 1);
GSkymap nest16("HPX", "GAL", 16, "NEST", 1);
GSkymap nest32("HPX", "GAL", 32, "NEST", 1);
GSkymap nest64("HPX", "GAL", 64, "NEST", 1);
GSkymap nest128("HPX", "GAL", 128, "NEST", 1);
GSkymap nest256("HPX", "GAL", 256, "NEST", 1);
GSkymap nest512("HPX", "GAL", 512, "NEST", 1);
/*
GSkymap nest1024("HPX", "GAL", 1024, "NEST", 1);
GSkymap nest2048("HPX", "GAL", 2048, "NEST", 1);
GSkymap nest4096("HPX", "GAL", 4096, "NEST", 1);
GSkymap nest8192("HPX", "GAL", 8192, "NEST", 1);
*/
GSkymap map1("HPX", "CEL", 1, "RING", 1);
GSkymap map2("HPX", "CEL", 1, "RING", 2);
GSkymap map3("HPX", "EQU", 1, "RING", 1);
GSkymap map4("HPX", "EQU", 1, "NESTED", 1);
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Unable to construct Healpix map."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test Healpix copy constructor
try {
GSkymap ring1("HPX", "GAL", 1, "RING", 1);
GSkymap ring2 = ring1;
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Unable to copy construct Healpix map."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test invalid wcs in constructor
try {
GSkymap map("CAR", "GAL", 1, "RING", 1);
}
catch (GException::wcs_invalid &e) {
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Did not detect invalid WCS."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test invalid coordsys in constructor
try {
GSkymap map("HPX", "HOR", 1, "RING", 1);
}
catch (GException::wcs_bad_coords &e) {
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Did not detect invalid coordinate system."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test invalid nside in constructor
try {
GSkymap map("HPX", "GAL", 3, "RING", 1);
}
catch (GException::wcs_hpx_bad_nside &e) {
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Did not detect invalid nside parameter."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test invalid ordering in constructor
try {
GSkymap map("HPX", "GAL", 2, "SPHERICAL", 1);
}
catch (GException::wcs_hpx_bad_ordering &e) {
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Did not detect invalid ordering parameter."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test invalid nmaps in constructor
try {
GSkymap map("HPX", "GAL", 2, "NEST", 0);
}
catch (GException::skymap_bad_par &e) {
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Did not detect invalid ordering parameter."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Signal final test success
std::cout << " ok." << std::endl;
// Exit test
return;
}
/***************************************************************************
* Test: GSkymap_healpix_io *
***************************************************************************/
void test_GSkymap_healpix_io(void)
{
// Set filenames
const std::string file1 = "test_skymap_hpx_1.fits";
const std::string file2 = "test_skymap_hpx_2.fits";
// Dump header
std::cout << "Test Healpix GSkymap I/O: ";
// Define Healpix map for comparison
GSkymap refmap("HPX", "GAL", 4, "RING", 1);
// Test Healpix map saving
try {
for (int pix = 0; pix < refmap.npix(); ++pix)
refmap(pix) = pix+1;
refmap.save(file1, true);
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Unable to save Healpix map."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test Healpix map loading
try {
GSkymap map;
map.load(file1);
int diff = 0;
for (int pix = 0; pix < refmap.npix(); ++pix) {
if (map(pix) != refmap(pix))
diff++;
}
if (diff > 0) {
std::cout << std::endl
<< "TEST ERROR: Loaded file differs from saved file ."
<< std::endl;
throw;
}
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Unable to load Healpix map."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test Healpix map instantiation
try {
GSkymap map(file1);
int diff = 0;
for (int pix = 0; pix < refmap.npix(); ++pix) {
if (map(pix) != refmap(pix))
diff++;
}
if (diff > 0) {
std::cout << std::endl
<< "TEST ERROR: Loaded file differs from saved file ."
<< std::endl;
throw;
}
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Unable to create Healpix instance"
" from FITS file." << std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Signal final test success
std::cout << " ok." << std::endl;
// Exit test
return;
}
/***************************************************************************
* Test: GSkymap_wcs_construct *
***************************************************************************/
void test_GSkymap_wcs_construct(void)
{
// Set precision
double eps = 1.0e-5;
// Dump header
std::cout << "Test WCS GSkymap constructors: ";
// Test void constructor
try {
GSkymap map;
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Unable to construct empty map."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test non-Healpix constructors
try {
GSkymap map1("CAR", "GAL", 0.0, 0.0, 1.0, 1.0, 100, 100);
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Unable to construct sky map(s)."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test CAR projection
try {
GSkymap map1("CAR", "GAL", 138.817, 37.293, 0.521, 0.931, 100, 100);
GSkyDir dir;
for (int l = -180; l < 180; ++l) {
for (int b = -90; b < 90; ++b) {
dir.lb_deg(double(l),double(b));
GSkyPixel pixel = map1.dir2xy(dir);
GSkyDir dir_back = map1.xy2dir(pixel);
double dist = dir.dist_deg(dir_back);
if (dist > eps) {
std::cout << std::endl
<< "TEST ERROR: Sky direction differs:"
<< " dir=" << dir
<< " pixel=" << pixel
<< " dir_back=" << dir_back
<< " dist=" << dist << " deg" << std::endl;
throw;
}
}
}
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Unable to construct sky map(s)."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Signal final test success
std::cout << " ok." << std::endl;
// Exit test
return;
}
/***************************************************************************
* Test: GSkymap_wcs_io *
***************************************************************************/
void test_GSkymap_wcs_io(void)
{
// Set filenames
const std::string file1 = "test_skymap_wcs_1.fits";
const std::string file2 = "test_skymap_wcs_2.fits";
// Dump header
std::cout << "Test WCS GSkymap I/O: ";
// Define WCS map for comparison
GSkymap refmap1("CAR", "GAL", 0.0, 0.0, -1.0, 1.0, 100, 100);
GSkymap refmap2("CAR", "CEL", 0.0, 0.0, -0.3, 0.3, 200, 200);
// Test WCS map saving
try {
for (int pix = 0; pix < refmap1.npix(); ++pix)
refmap1(pix) = pix+1;
refmap1.save(file1, 1);
for (int pix = 0; pix < refmap2.npix(); ++pix)
refmap2(pix) = pix+1;
refmap2.save(file2, 1);
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Unable to save WCS map."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test WCS map loading (1)
try {
GSkymap map;
map.load(file1);
int diff = 0;
for (int pix = 0; pix < refmap1.npix(); ++pix) {
if (map(pix) != refmap1(pix))
diff++;
}
if (diff > 0) {
std::cout << std::endl
<< "TEST ERROR: Loaded file "+file1+
" differs from saved file ."
<< std::endl;
throw;
}
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Unable to load WCS map."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Test WCS map loading (2)
try {
GSkymap map;
map.load(file2);
int diff = 0;
for (int pix = 0; pix < refmap2.npix(); ++pix) {
if (map(pix) != refmap2(pix))
diff++;
}
if (diff > 0) {
std::cout << std::endl
<< "TEST ERROR: Loaded file "+file2+
" differs from saved file ."
<< std::endl;
throw;
}
}
catch (std::exception &e) {
std::cout << std::endl
<< "TEST ERROR: Unable to load WCS map."
<< std::endl;
std::cout << e.what() << std::endl;
throw;
}
std::cout << ".";
// Signal final test success
std::cout << " ok." << std::endl;
// Exit test
return;
}
/***************************************************************************
* Main test function *
***************************************************************************/
int main(void)
{
// Dump header
std::cout << std::endl;
std::cout << "************************" << std::endl;
std::cout << "* GSky classes testing *" << std::endl;
std::cout << "************************" << std::endl;
// Execute Healpix tests
test_GWcslib();
test_GSkymap_healpix_construct();
test_GSkymap_healpix_io();
test_GSkymap_wcs_construct();
test_GSkymap_wcs_io();
// Return
return 0;
}