/*************************************************************************** * test_GSky.cpp - Test sky module * * ----------------------------------------------------------------------- * * copyright (C) 2010-2016 by Juergen Knoedlseder * * ----------------------------------------------------------------------- * * * * 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 Juergen Knoedlseder */ /* __ Includes ___________________________________________________________ */ #ifdef HAVE_CONFIG_H #include #endif #include // cout, cerr #include // std::exception #include // for system #include "test_GSky.hpp" #include "GTools.hpp" /* __ Namespaces _________________________________________________________ */ /* __ Globals ____________________________________________________________ */ /* __ Debug definitions __________________________________________________ */ #define G_WCS_FORTH_BACK_PIXEL_DEBUG #define G_WCS_COPY_DEBUG /* __ Constants __________________________________________________________ */ const std::string datadir = std::getenv("TEST_DATA"); const std::string sky_region = datadir + "/test_circle_region.reg"; /***********************************************************************//** * @brief Set parameters and tests ***************************************************************************/ void TestGSky::set(void){ // Test name name("GSky"); // Append tests append(static_cast(&TestGSky::test_GWcs), "Test GWcs"); append(static_cast(&TestGSky::test_GSkyPixel), "Test GSkyPixel"); append(static_cast(&TestGSky::test_GSkyMap_healpix_construct), "Test Healpix GSkyMap constructors"); append(static_cast(&TestGSky::test_GSkyMap_healpix_io), "Test Healpix GSkyMap I/O"); append(static_cast(&TestGSky::test_GSkyMap_wcs_construct), "Test WCS GSkyMap constructors"); append(static_cast(&TestGSky::test_GSkyMap_wcs_io), "Test WCS GSkyMap I/O"); append(static_cast(&TestGSky::test_GSkyMap), "Test GSkyMap"); append(static_cast(&TestGSky::test_GSkyMap_io), "Test GSkyMap I/O"); append(static_cast(&TestGSky::test_GSkyRegions_io), "Test GSkyRegions"); append(static_cast(&TestGSky::test_GSkyRegionCircle_construct), "Test GSkyRegionCircle constructors"); append(static_cast(&TestGSky::test_GSkyRegionCircle_logic), "Test GSkyRegionCircle logic"); append(static_cast(&TestGSky::test_GHorizDir), "Test GHorizDir"); // Return return; } /***********************************************************************//** * @brief Clone test suite * * @return Pointer to deep copy of test suite. ***************************************************************************/ TestGSky* TestGSky::clone(void) const { // Clone test suite return new TestGSky(*this); } /***********************************************************************//** * @brief Test consistency of forward and background transformations * * @param[in] wcs WCS object * @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 TestGSky::wcs_forth_back_pixel(GWcs* 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->pix2dir(pix_in); // Back: Transform to pixel GSkyPixel pix_out = wcs->dir2pix(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 << wcs->code() << ":"; 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] wcs WCS object * @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 TestGSky::wcs_copy(GWcs* wcs, int nx, int ny, double& crpix1, double& crpix2) { // Make a copy using clone GWcs* 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->pix2dir(pix_in); GSkyDir dir2 = cpy->pix2dir(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->dir2pix(dir1); GSkyPixel pix_out2 = cpy->dir2pix(dir2); // Compute distance double dx = pix_out1.x()-pix_out2.x(); double dy = pix_out1.y()-pix_out2.y(); double dist = std::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 // Delete copy delete cpy; // Return return ((dist_max > angle_max) ? dist_max : angle_max); } /***********************************************************************//** * @brief Test GSkyPixel class * * Test GSkyPixel class. ***************************************************************************/ void TestGSky::test_GSkyPixel(void) { // Test void constructor test_try("Test void constructor"); try { GSkyPixel pixel; test_value(pixel.size(), 0); test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test 1D constructor test_try("Test 1D constructor (int version)"); try { GSkyPixel pixel(41); test_assert(pixel.is_1D(), "Pixel is not 1D"); test_assert(!pixel.is_2D(), "Pixel is 2D but it should be 1D"); test_value(pixel.size(), 1); test_value(pixel.index(), 41.0); test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test 1D constructor test_try("Test 1D constructor (double version)"); try { GSkyPixel pixel(41.001); test_assert(pixel.is_1D(), "Pixel is not 1D"); test_assert(!pixel.is_2D(), "Pixel is 2D but it should be 1D"); test_value(pixel.size(), 1); test_value(pixel.index(), 41.001); test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test 2D constructor test_try("Test 2D constructor (int version)"); try { GSkyPixel pixel(41,14); test_assert(!pixel.is_1D(), "Pixel is 1D but it should be 2D"); test_assert(pixel.is_2D(), "Pixel is not 2D"); test_value(pixel.size(), 2); test_value(pixel.x(), 41.0); test_value(pixel.y(), 14.0); test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test 2D constructor test_try("Test 2D constructor (double version)"); try { GSkyPixel pixel(41.001,14.003); test_assert(!pixel.is_1D(), "Pixel is 1D but it should be 2D"); test_assert(pixel.is_2D(), "Pixel is not 2D"); test_value(pixel.size(), 2); test_value(pixel.x(), 41.001); test_value(pixel.y(), 14.003); test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test 1D indexing test_try("Test 1D indexing"); try { GSkyPixel pixel; test_value(pixel.size(), 0); pixel = 41; int index = pixel; test_value(index, 41); pixel = 41.001; index = pixel; test_value(index, 41); double dindex = pixel; test_value(dindex, 41.001); test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test cloning test_try("Test cloning"); try { GSkyPixel pixel; test_value(pixel.size(), 0); GSkyPixel* clone = pixel.clone(); test_value(clone->size(), 0); delete clone; pixel = 41; clone = pixel.clone(); test_value(clone->size(), 1); int index = pixel; test_value(index, 41); delete clone; pixel.x(41.001); pixel.y(14.003); clone = pixel.clone(); test_value(clone->size(), 2); test_value(clone->x(), 41.001); test_value(clone->y(), 14.003); delete clone; test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Return return; } /***********************************************************************//** * @brief Test GWcs projections * * This method tests all WCS projections that have been registered. ***************************************************************************/ void TestGSky::test_GWcs(void) { // Allocate parameters for testing double crval1 = 83.63; double crval2 = 22.01; double crpix1 = 100.5; double crpix2 = 100.5; double cdelt1 = 0.1; double cdelt2 = 0.1; int nx = 200; int ny = 200; // Loop over all non-HealPix projections GWcsRegistry registry; for (int i = 0; i < registry.size(); ++i) { // Set header std::string test_class = "GWcs" + registry.code(i); // Perform tests test_try("Test "+test_class); try { // Allocate projection CEL and GAL GWcs *cel = dynamic_cast(registry.alloc(registry.code(i))); GWcs *gal = dynamic_cast(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 exception_error("Could not allocate"+test_class); } // Set projections test_try("Set projections"); try { cel->set("CEL", crval1, crval2, crpix1, crpix2, cdelt1, cdelt2); gal->set("GAL", crval1, crval2, crpix1, crpix2, cdelt1, cdelt2); test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test forth-back CEL conversion test_try("Test forth-back CEL conversion"); try { double tol = 0.0; if ((tol = wcs_forth_back_pixel(cel, nx, ny, crpix1, crpix2)) > 1.0e-10) { throw exception_failure("CEL forth-back transformation" " tolerance 1.0e-10 exceeded: "+ gammalib::str(tol)); } test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test forth-back GAL conversion test_try("Test forth-back GAL conversion"); try { double tol = 0.0; if ((tol = wcs_forth_back_pixel(gal, nx, ny, crpix1, crpix2)) > 1.0e-10) { throw exception_failure("GAL forth-back transformation" " tolerance 1.0e-10 exceeded: "+ gammalib::str(tol)); } test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test CEL copy test_try("Test CEL copy"); try { double tol = 0.0; if ((tol = wcs_copy(cel, nx, ny, crpix1, crpix2)) > 1.0e-4) { throw exception_failure("CEL copy tolerance 1.0e-4" " exceeded: "+gammalib::str(tol)); } test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test GAL copy test_try("Test GAL copy"); try { double tol = 0.0; if ((tol = wcs_copy(gal, nx, ny, crpix1, crpix2)) > 1.0e-4) { throw exception_failure("GAL copy tolerance 1.0e-4" " exceeded: "+gammalib::str(tol)); } test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Free memory delete cel; delete gal; // Signal success test_try_success(); } catch (std::exception &e) { test_try_failure(e); } } // endfor: looped over all non-HealPix projections // Exit test return; } /*************************************************************************** * @brief GSkyMap_healpix_construct ***************************************************************************/ void TestGSky::test_GSkyMap_healpix_construct(void) { // Test void constructor test_try("Test void constructor"); try { GSkyMap map; test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test correct Healpix constructors test_try("Test correct Healpix constructors"); try { GSkyMap ring1("GAL", 1, "RING", 1); GSkyMap ring2("GAL", 2, "RING", 1); GSkyMap ring4("GAL", 4, "RING", 1); GSkyMap ring8("GAL", 8, "RING", 1); GSkyMap ring16("GAL", 16, "RING", 1); GSkyMap ring32("GAL", 32, "RING", 1); GSkyMap ring64("GAL", 64, "RING", 1); GSkyMap ring128("GAL", 128, "RING", 1); GSkyMap ring256("GAL", 256, "RING", 1); GSkyMap ring512("GAL", 512, "RING", 1); GSkyMap nest1("GAL", 1, "NEST", 1); GSkyMap nest2("GAL", 2, "NEST", 1); GSkyMap nest4("GAL", 4, "NEST", 1); GSkyMap nest8("GAL", 8, "NEST", 1); GSkyMap nest16("GAL", 16, "NEST", 1); GSkyMap nest32("GAL", 32, "NEST", 1); GSkyMap nest64("GAL", 64, "NEST", 1); GSkyMap nest128("GAL", 128, "NEST", 1); GSkyMap nest256("GAL", 256, "NEST", 1); GSkyMap nest512("GAL", 512, "NEST", 1); GSkyMap map1("CEL", 1, "RING", 1); GSkyMap map2("CEL", 1, "RING", 2); GSkyMap map3("EQU", 1, "RING", 1); GSkyMap map4("EQU", 1, "NESTED", 1); test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test Healpix copy constructor test_try("Test Healpix copy constructor"); try { GSkyMap ring1("GAL", 1, "RING", 1); GSkyMap ring2 = ring1; test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test invalid coordsys in constructor test_try("Test invalid coordsys in constructor"); try { GSkyMap map("HOR", 1, "RING", 1); test_try_failure(); } catch (GException::wcs_bad_coords &e) { test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test invalid nside in constructor test_try("Test invalid nside in constructor"); try { GSkyMap map("GAL", 3, "RING", 1); test_try_failure(); } catch (GException::wcs_hpx_bad_nside &e) { test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test invalid ordering in constructor test_try("Test invalid ordering in constructor"); try { GSkyMap map("GAL", 2, "SPHERICAL", 1); test_try_failure(); } catch (GException::wcs_hpx_bad_ordering &e) { test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test invalid nmaps in constructor test_try("Test invalid nmaps in constructor"); try { GSkyMap map("GAL", 2, "NEST", 0); test_try_failure(); } catch (GException::skymap_bad_par &e) { test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Exit test return; } /*************************************************************************** * @brief GSkyMap_healpix_io ***************************************************************************/ void TestGSky::test_GSkyMap_healpix_io(void) { // Set filenames const std::string file1 = "test_skymap_hpx_1.fits"; // Define Healpix map for comparison GSkyMap refmap("GAL", 4, "RING", 1); // Test Healpix map saving test_try("Test Healpix map saving"); try { for (int pix = 0; pix < refmap.npix(); ++pix) refmap(pix) = pix+1; refmap.save(file1, true); test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test Healpix map loading test_try("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) { throw exception_error("Loaded file differs from saved file."); } test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test Healpix map instantiation test_try("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) { throw exception_error("Loaded file differs from saved file."); } test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Exit test return; } /*************************************************************************** * @brief GSkyMap_wcs_construct ***************************************************************************/ void TestGSky::test_GSkyMap_wcs_construct(void) { // Set precision double eps = 1.0e-5; // Test void constructor test_try("Test void constructor"); try { GSkyMap map; test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test non-Healpix constructors test_try("Test non-Healpix constructors"); try { GSkyMap map1("CAR", "GAL", 0.0, 0.0, 1.0, 1.0, 100, 100); test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test CAR projection test_try("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.dir2pix(dir); GSkyDir dir_back = map1.pix2dir(pixel); double dist = dir.dist_deg(dir_back); if (dist > eps) { throw exception_failure("Sky direction differs: dir="+ dir.print()+" pixel="+ pixel.print()+" dir_back"+ dir_back.print()+" dist="+ gammalib::str(dist)+" deg"); } } } test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Exit test return; } /*************************************************************************** * @brief GSkyMap_wcs_io ***************************************************************************/ void TestGSky::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"; // 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 test_try("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); test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test WCS map loading (1) test_try("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) { throw exception_error("Loaded file "+file1+ " differs from saved file."); } test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test WCS map loading (2) test_try("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) { throw exception_error("Loaded file "+file2+ " differs from saved file."); } test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Exit test return; } /*************************************************************************** * @brief GSkyMap * * This method tests the GSkyMap class. ***************************************************************************/ void TestGSky::test_GSkyMap(void) { // Remove result files system("rm -rf test_map_src.fits"); system("rm -rf test_map_dst.fits"); system("rm -rf test_map_shape*.fits"); // Define empty sky map GSkyMap empty_map; // Test that empty map is indeed empty test_assert(empty_map.is_empty(), "Check for empty sky map"); test_value(empty_map.nmaps(), 0, "Check for no sky maps"); test_value(empty_map.npix(), 0, "Check number of empty sky map pixels"); test_value(empty_map.nx(), 0, "Check number of empty sky map X pixels"); test_value(empty_map.ny(), 0, "Check number of empty sky map X pixels"); test_value(empty_map.ndim(), 0, "Check empty sky map dimension"); test_value(empty_map.shape().size(), 0, "Check empty sky map shape"); // Test that writing, publishing and printing of empty sky map does not // lead to a segmentation fault empty_map.save("test_empty_map.fits", true); empty_map.publish("Empty sky map"); empty_map.print(); // Define several maps for comparison GSkyMap map_src("CAR", "GAL", 0.0, 0.0, -1.0, 1.0, 10, 10, 2); GSkyMap map_dst("CAR", "GAL", 0.0, 0.0, -0.1, 0.1, 100, 100, 2); GSkyMap map_new("CAR", "GAL", 0.0, 0.0, -0.1, 0.1, 100, 100, 2); // Test map dimensions and shape test_value(map_src.nmaps(), 2, "Check that sky map contains 2 maps"); test_value(map_src.ndim(), 1, "Check that sky map has one dimension"); test_value(map_src.shape().size(), 1, "Check that sky map has a shape size of 1"); test_value(map_src.shape()[0], 2, "Check that sky map has 2 maps"); // Fill map pixels double total_src = 0.0; for (int pix = 0; pix < map_src.npix(); ++pix) { for (int k = 0; k < map_src.nmaps(); ++k) { map_src(pix,k) = pix+1; total_src += map_src(pix,k); } } // Add pixels to destination map map_new = map_dst + map_src; map_dst += map_src; // Check total in destination map. Note that the total in the destination // map should be 100 times the total in the source map as the operator // is expected to perform strict bi-linear interpolation double total_dst = 0.0; double total_new = 0.0; double total_ref = 0.0; for (int pix = 0; pix < map_dst.npix(); ++pix) { for (int k = 0; k < map_dst.nmaps(); ++k) { total_dst += map_dst(pix,k); total_new += map_new(pix,k); total_ref += map_src(map_dst.pix2dir(pix),k); } } total_dst /= 100.0; total_new /= 100.0; total_ref /= 100.0; test_value(total_dst, total_ref, 1.0e-3, "Test operator+=(GSkyMap)"); test_value(total_new, total_ref, 1.0e-3, "Test operator+(GSkyMap)"); // Subtract pixels from destination map map_new = map_dst - map_src; map_dst -= map_src; // Check total in destination map. Note that the total in the destination // map should be zero. total_dst = 0.0; total_new = 0.0; for (int pix = 0; pix < map_dst.npix(); ++pix) { for (int k = 0; k < map_dst.nmaps(); ++k) { total_dst += map_dst(pix,k); total_new += map_dst(pix,k); } } test_value(total_dst, 0.0, 1.0e-3, "Test operator-=(GSkyMap)"); test_value(total_new, 0.0, 1.0e-3, "Test operator-(GSkyMap)"); // Check map multiplication GSkyMap test_map = map_src; test_map *= map_src; map_new = map_src * map_src; double total_test = 0.0; total_ref = 0.0; total_new = 0.0; for (int pix = 0; pix < test_map.npix(); ++pix) { for (int k = 0; k < test_map.nmaps(); ++k) { total_test += test_map(pix,k); total_new += map_new(pix,k); total_ref += map_src(pix,k) * map_src(pix,k); } } test_value(total_test, total_ref, 1.0e-3, "Test operator*=(GSkyMap)"); test_value(total_new, total_ref, 1.0e-3, "Test operator*(GSkyMap)"); // Check map division test_map = map_src; test_map /= map_src; map_new = map_src / map_src; total_test = 0.0; total_ref = 0.0; total_new = 0.0; for (int pix = 0; pix < test_map.npix(); ++pix) { for (int k = 0; k < test_map.nmaps(); ++k) { total_test += test_map(pix,k); total_new += map_new(pix,k); total_ref += map_src(pix,k) / map_src(pix,k); } } test_value(total_test, total_ref, 1.0e-3, "Test operator/=(GSkyMap)"); test_value(total_new, total_ref, 1.0e-3, "Test operator/(GSkyMap)"); // Check map scaling test_map = map_src; test_map *= 3.3; total_test = 0.0; for (int pix = 0; pix < test_map.npix(); ++pix) { for (int k = 0; k < test_map.nmaps(); ++k) { total_test += test_map(pix,k); } } test_value(total_test, total_src*3.3, 1.0e-3, "Test operator*=(double)"); // Check map division test_map = map_src; test_map /= 3.3; total_test = 0.0; for (int pix = 0; pix < test_map.npix(); ++pix) { for (int k = 0; k < test_map.nmaps(); ++k) { total_test += test_map(pix,k); } } test_value(total_test, total_src/3.3, 1.0e-3, "Test operator/=(double)"); // Check map value addition test_map = map_src; test_map += 3.3; total_test = 0.0; double ref = total_src + 3.3*test_map.npix()*test_map.nmaps(); for (int pix = 0; pix < test_map.npix(); ++pix) { for (int k = 0; k < test_map.nmaps(); ++k) { total_test += test_map(pix,k); } } test_value(total_test, ref, 1.0e-3, "Test operator+=(double)"); // Check map value subtraction test_map = map_src; test_map -= 3.3; total_test = 0.0; ref = total_src - 3.3*test_map.npix()*test_map.nmaps(); for (int pix = 0; pix < test_map.npix(); ++pix) { for (int k = 0; k < test_map.nmaps(); ++k) { total_test += test_map(pix,k); } } test_value(total_test, ref, 1.0e-3, "Test operator-=(double)"); // Save maps map_src.save("test_map_src.fits", true); map_dst.save("test_map_dst.fits", true); // Test map stacking GSkyMap map_stacked = map_src; map_stacked.stack_maps(); double total_stacked = 0.0; for (int pix = 0; pix < map_stacked.npix(); ++pix) { total_stacked += map_stacked(pix); } test_value(total_stacked, total_src, 1.0e-3, "Test stack_maps() method"); test_value(map_stacked.nmaps(), 1, "Test stack_maps() method"); // Test map number changing GSkyMap map_more = map_src; map_more.nmaps(4); double total_more = 0.0; for (int k = 0; k < map_more.nmaps(); ++k) { for (int pix = 0; pix < map_more.npix(); ++pix) { total_more += map_more(pix,k); } } test_value(total_more, total_src, 1.0e-3, "Test nmaps() method with more maps"); test_value(map_more.nmaps(), 4, "Test nmaps() method with more maps"); GSkyMap map_less = map_src; map_less.nmaps(1); double total_less = 0.0; for (int k = 0; k < map_less.nmaps(); ++k) { for (int pix = 0; pix < map_less.npix(); ++pix) { total_less += map_less(pix,k); } } test_value(total_less, 0.5*total_src, 1.0e-3, "Test nmaps() method with less maps"); test_value(map_less.nmaps(), 1, "Test nmaps() method with less maps"); // Test map extraction GSkyMap map_extract = map_src.extract(0); double total_extract = 0.0; for (int k = 0; k < map_extract.nmaps(); ++k) { for (int pix = 0; pix < map_extract.npix(); ++pix) { total_extract += map_extract(pix,k); } } test_value(total_extract, 0.5*total_src, 1.0e-3, "Test extract() method with 1 map"); test_value(map_extract.nmaps(), 1, "Test extract() method with 1 map"); map_extract = map_src.extract(0,2); total_extract = 0.0; for (int k = 0; k < map_extract.nmaps(); ++k) { for (int pix = 0; pix < map_extract.npix(); ++pix) { total_extract += map_extract(pix,k); } } test_value(total_extract, total_src, 1.0e-3, "Test extract() method with 2 maps"); test_value(map_extract.nmaps(), 2, "Test extract() method with 2 maps"); // Define one more map for shaping manipulation GSkyMap map_shape0("CAR", "GAL", 0.0, 0.0, -1.0, 1.0, 10, 10); // Test map dimensions and shape test_value(map_shape0.nmaps(), 1, "Check that sky map contains one map"); test_value(map_shape0.ndim(), 1, "Check that sky map has one dimension"); test_value(map_shape0.shape().size(), 1, "Check that sky map has a shape size of 1"); test_value(map_shape0.shape()[0], 1, "Check that sky map has one map"); // Save map map_shape0.save("test_map_shape0.fits", true); // Load map GSkyMap map_load_shape0("test_map_shape0.fits"); // Test map dimensions and shape test_value(map_load_shape0.nmaps(), 1, "Check that sky map contains one map"); test_value(map_load_shape0.ndim(), 1, "Check that sky map has one dimension"); test_value(map_load_shape0.shape().size(), 1, "Check that sky map has a shape size of 1"); test_value(map_load_shape0.shape()[0], 1, "Check that sky map has one map"); // Define one more map for shaping manipulation GSkyMap map_shape("CAR", "GAL", 0.0, 0.0, -1.0, 1.0, 10, 10, 12); // Test initial map dimensions and shape test_value(map_shape.nmaps(), 12, "Check that sky map contains 12 maps"); test_value(map_shape.ndim(), 1, "Check that sky map has one dimension"); test_value(map_shape.shape().size(), 1, "Check that sky map has a shape size of 1"); test_value(map_shape.shape()[0], 12, "Check that sky map has 12 maps"); // Save map map_shape.save("test_map_shape1.fits", true); // Load map GSkyMap map_load_shape1("test_map_shape1.fits"); // Test loaded map dimensions and shape test_value(map_load_shape1.nmaps(), 12, "Check that sky map contains 12 maps"); test_value(map_load_shape1.ndim(), 1, "Check that sky map has one dimension"); test_value(map_load_shape1.shape().size(), 1, "Check that sky map has a shape size of 1"); test_value(map_load_shape1.shape()[0], 12, "Check that sky map has 12 maps"); // Set new map shape map_shape.shape(3,4); // Test map dimensions and shape test_value(map_shape.nmaps(), 12, "Check that sky map contains 12 maps"); test_value(map_shape.ndim(), 2, "Check that sky map has two dimensions"); test_value(map_shape.shape().size(), 2, "Check that sky map has a shape size of 2"); test_value(map_shape.shape()[0], 3, "Check that sky map has 3 maps in first dimension"); test_value(map_shape.shape()[1], 4, "Check that sky map has 4 maps in second dimension"); // Save map map_shape.save("test_map_shape2.fits", true); // Load map GSkyMap map_load_shape2("test_map_shape2.fits"); // Test map dimensions and shape test_value(map_load_shape2.nmaps(), 12, "Check that sky map contains 12 maps"); test_value(map_load_shape2.ndim(), 2, "Check that sky map has two dimensions"); test_value(map_load_shape2.shape().size(), 2, "Check that sky map has a shape size of 2"); test_value(map_load_shape2.shape()[0], 3, "Check that sky map has 3 maps in first dimension"); test_value(map_load_shape2.shape()[1], 4, "Check that sky map has 4 maps in second dimension"); // Set new map shape map_shape.shape(2,3,2); // Test map dimensions and shape test_value(map_shape.nmaps(), 12, "Check that sky map contains 12 maps"); test_value(map_shape.ndim(), 3, "Check that sky map has three dimensions"); test_value(map_shape.shape().size(), 3, "Check that sky map has a shape size of 3"); test_value(map_shape.shape()[0], 2, "Check that sky map has 2 maps in first dimension"); test_value(map_shape.shape()[1], 3, "Check that sky map has 3 maps in second dimension"); test_value(map_shape.shape()[2], 2, "Check that sky map has 2 maps in third dimension"); // Save map map_shape.save("test_map_shape3.fits", true); // Load map GSkyMap map_load_shape3("test_map_shape3.fits"); // Test map dimensions and shape test_value(map_load_shape3.nmaps(), 12, "Check that sky map contains 12 maps"); test_value(map_load_shape3.ndim(), 3, "Check that sky map has three dimensions"); test_value(map_load_shape3.shape().size(), 3, "Check that sky map has a shape size of 3"); test_value(map_load_shape3.shape()[0], 2, "Check that sky map has 2 maps in first dimension"); test_value(map_load_shape3.shape()[1], 3, "Check that sky map has 3 maps in second dimension"); test_value(map_load_shape3.shape()[2], 2, "Check that sky map has 2 maps in third dimension"); // Exit test return; } /*************************************************************************** * @brief GSkyMap * * This method tests the GSkyMap class input and output. Specifically, the * test verifies that saving of a HEALPix and WCS map in the same FITS file * is possible, and that upon opening the correct extension is selected. ***************************************************************************/ void TestGSky::test_GSkyMap_io(void) { // Set filename GFilename filename("test_skymap.fits"); filename.remove(); // Create HEALPix and WCS maps and save them to FITS file GSkyMap healpix1("GAL", 4, "RING", 1); GSkyMap healpix2("GAL", 2, "RING", 1); GSkyMap wcs1("CAR", "GAL", 0.0, 0.0, -1.0, 1.0, 10, 10); GSkyMap wcs2("CAR", "GAL", 0.0, 0.0, -1.0, 1.0, 5, 5); GSkyMap wcs3("CAR", "GAL", 0.0, 0.0, -1.0, 1.0, 5, 5, 12); for (int i = 0; i < healpix1.npix(); ++i) { healpix1(i) = double(i+1); } for (int i = 0; i < healpix2.npix(); ++i) { healpix2(i) = 3.0*double(i+1); } for (int i = 0; i < wcs1.npix(); ++i) { wcs1(i) = double(i+1); } for (int i = 0; i < wcs2.npix(); ++i) { wcs2(i) = 3.0*double(i+1); } for (int k = 0; k < 12; ++k) { for (int i = 0; i < wcs3.npix(); ++i) { wcs3(i,k) = 3.0*double(i+k+1); } } GFits fits(filename, true); healpix1.write(fits, "HEALPIX1"); wcs1.write(fits, "WCS1"); healpix2.write(fits, "HEALPIX2"); wcs2.write(fits, "WCS2"); wcs3.shape(2,2,3); wcs3.write(fits, "WCS3"); fits.save(true); // Load HEALPix map and check content GSkyMap map1(filename+"[HEALPIX1]"); test_value(map1.npix(), healpix1.npix(), "Check number of HEALPix pixels"); int failures1(0); for (int i = 0; i < map1.npix(); ++i) { if (std::abs(map1(i)-double(i+1)) > 1.0e-6) { failures1++; } } test_value(failures1, 0, "Check number of invalid HEALPix pixel values"); // Load WCS1 map and check content GSkyMap map2(filename+"[WCS1]"); test_value(map2.npix(), wcs1.npix(), "Check number of WCS pixels"); int failures2(0); for (int i = 0; i < map2.npix(); ++i) { if (std::abs(map2(i)-double(i+1)) > 1.0e-6) { failures2++; } } test_value(failures2, 0, "Check number of invalid WCS pixel values"); // Load WCS3 map and check content GSkyMap map3(filename+"[WCS3]"); test_value(map3.npix(), wcs3.npix(), "Check number of WCS pixels"); test_value(map3.nmaps(), wcs3.nmaps(), "Check number of WCS maps"); test_value(map3.ndim(), wcs3.ndim(), "Check dimension of WCS maps"); int failures3(0); for (int k = 0; k < 12; ++k) { for (int i = 0; i < map3.npix(); ++i) { if (std::abs(map3(i,k)-3.0*double(i+k+1)) > 1.0e-6) { failures3++; } } } test_value(failures3, 0, "Check number of invalid WCS pixel values"); // Exit test return; } /*************************************************************************** * @brief GSkyRegionCircle_construct ***************************************************************************/ void TestGSky::test_GSkyRegionCircle_construct(void) { // Define region for comparison GSkyDir refdir_radeczerozero = GSkyDir(); refdir_radeczerozero.radec_deg(0,0); double refradius = 10.; // Test constructing: test_try("Test constructor"); try { GSkyRegionCircle circle(refdir_radeczerozero,refradius); test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test constructing with radius 0 test_try("Test constructor2"); try { GSkyRegionCircle circle(refdir_radeczerozero,-1); test_try_failure(); } catch (GException::invalid_argument &e) { test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test constructing with radius 0 test_try("Test radius assignment after"); try { GSkyRegionCircle circle(refdir_radeczerozero,refradius); circle.radius(-1.0); test_try_failure(); } catch (GException::invalid_argument &e) { test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Check radius assignment GSkyRegionCircle refregion(refdir_radeczerozero,refradius); double refradius_check = refregion.radius(); test_value(refradius,refradius_check,1.0e-10, "Test radius assignment"); // Check solid angle assignment double solidangle_check = refregion.solidangle(); double solidangle = 2*gammalib::pi*(1- std::cos(refradius /180 * gammalib::pi)); test_value(solidangle_check,solidangle,1.0e-10, "Test solid angle assignment"); //exit test return; } /*************************************************************************** * @brief GSkyRegions_logic ***************************************************************************/ void TestGSky::test_GSkyRegionCircle_logic(void) { // set input files /filenames // const std::string file1 = "test_GSkyRegionCircle1.reg"; // const std::string file2 = "test_GSkyRegionCircle2.reg"; //set reference values GSkyDir refdir_radeczerozero = GSkyDir(); refdir_radeczerozero.radec_deg(0,0); GSkyDir refdir_lbzerozero = GSkyDir(); refdir_lbzerozero.lb_deg(0,0); GSkyDir refdir_outside_refregion = GSkyDir(); refdir_outside_refregion.radec_deg(100,80); GSkyDir refdir_raoffset = GSkyDir(); refdir_raoffset.radec_deg(5,0); GSkyDir refdir_decpole = GSkyDir(); refdir_decpole.radec_deg(0,89); GSkyDir refdir_ndecpole = GSkyDir(); refdir_ndecpole.radec_deg(100,89); GSkyDir refdir_rapole = GSkyDir(); refdir_rapole.radec_deg(359,0); GSkyRegionCircle refregion(refdir_radeczerozero,10); GSkyDir centre = refregion.centre(); GSkyRegionCircle refregion_smaller(refdir_radeczerozero,5); GSkyRegionCircle refregion_larger(refdir_radeczerozero,20); GSkyRegionCircle refregion_raoffset(refdir_raoffset,10); GSkyRegionCircle refregion_rapole(refdir_rapole,3); GSkyRegionCircle refregion_decpole(refdir_decpole,3); // Test contain dirs test_assert(refregion.contains(refdir_radeczerozero),"test for containment"); test_assert(refregion.contains(centre), "test if centre in circle"); test_assert(!refregion.contains(refdir_outside_refregion), "test2 for containment"); // Test contain regions test_assert(refregion.contains(refregion_smaller),"test for containment region"); test_assert(!refregion.contains(refregion_larger), "test for containment region2 "); test_assert(refregion.contains(refregion), "test3 for containment region"); test_assert(refregion.contains(refdir_rapole), "rapole for containment region"); test_assert(refregion_decpole.contains(refdir_ndecpole), "rapole for containment region"); // Test overlaps test_assert(refregion.overlaps(refregion_smaller),"test for overlap"); test_assert(refregion.overlaps(refregion_larger),"test2 for overlap"); test_assert(refregion.overlaps(refregion_raoffset),"test3 for overlap"); test_assert(!refregion.overlaps(refregion_decpole),"test4 for overlap"); // Exit test return; } /*************************************************************************** * @brief Test GSkyRegions input and output ***************************************************************************/ void TestGSky::test_GSkyRegions_io(void) { // Allocate regions GSkyRegions regions; // Test regions loading test_try("Test regions loading"); try { regions.load(sky_region); test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Check if region was loaded correctly GSkyRegionCircle* circle = dynamic_cast(regions[0]); test_assert(circle->type() == "Circle", "Region is not a circle"); test_value(circle->radius(), 10.0, 1.0e-10); test_value(circle->ra(), 0.1, 1.0e-10); test_value(circle->dec(), -35.6, 1.0e-10); // Test regions saving test_try("Test regions saving"); try { regions.save("region.reg"); test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Test regions reloading test_try("Test regions reloading"); try { regions.load("region.reg"); test_try_success(); } catch (std::exception &e) { test_try_failure(e); } // Check if region was loaded correctly circle = dynamic_cast(regions[0]); test_assert(circle->type() == "Circle", "Region is not a circle"); test_value(circle->radius(), 10.0, 1.0e-10); test_value(circle->ra(), 0.1, 1.0e-10); test_value(circle->dec(), -35.6, 1.0e-10); // Exit test return; } /*************************************************************************** * @brief Test GHorizDir class ***************************************************************************/ void TestGSky::test_GHorizDir(void){ // Empty horizontal direction GHorizDir nulldir; // Set position GHorizDir altaz; double testalt = 45.0; double testaz = 180.0; altaz.altaz_deg(testalt, testaz); // Retrieve position double newalt = altaz.alt_deg(); double newaz = altaz.az_deg(); // Test position test_value(newalt, testalt, 1e-10, "Altitude" ); test_value(newaz, testaz, 1e-10, "Azimuth" ); test_value(altaz.zenith_deg(), 90.0-testalt, 1e-10, "Zenith angle"); // Return return; } /*************************************************************************** * @brief Main test function ***************************************************************************/ int main(void) { GTestSuites testsuites("GSky"); bool was_successful = true; // Create a test suite TestGSky test; // Append to the container testsuites.append(test); // Run was_successful=testsuites.run(); // Save xml report testsuites.save("reports/GSky.xml"); // Return return was_successful ? 0:1; }