1 /* 2 * This file is part of Healpix_cxx. 3 * 4 * Healpix_cxx is free software; you can redistribute it and/or modify 5 * it under the terms of the GNU General Public License as published by 6 * the Free Software Foundation; either version 2 of the License, or 7 * (at your option) any later version. 8 * 9 * Healpix_cxx is distributed in the hope that it will be useful, 10 * but WITHOUT ANY WARRANTY; without even the implied warranty of 11 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 12 * GNU General Public License for more details. 13 * 14 * You should have received a copy of the GNU General Public License 15 * along with Healpix_cxx; if not, write to the Free Software 16 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA 17 * 18 * For more information about HEALPix, see http://healpix.sourceforge.net 19 */ 20 21 /* 22 * Healpix_cxx is being developed at the Max-Planck-Institut fuer Astrophysik 23 * and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt 24 * (DLR). 25 */ 26 27 /*! \file healpix_base.h 28 * 29 * \copyright Copyright (C) 2003-2020 Max-Planck-Society 30 * \author Martin Reinecke 31 */ 32 33 #ifndef HEALPIX_BASE_H 34 #define HEALPIX_BASE_H 35 36 #include <array> 37 #include <cmath> 38 #include <vector> 39 #include "ducc0/infra/error_handling.h" 40 #include "ducc0/math/math_utils.h" 41 #include "ducc0/math/vec3.h" 42 #include "ducc0/healpix/healpix_tables.h" 43 #include "ducc0/math/pointing.h" 44 #include "ducc0/math/rangeset.h" 45 46 namespace ducc0 { 47 48 namespace detail_healpix { 49 50 template<typename I> struct Orderhelper__ {}; 51 template<> struct Orderhelper__<int> {enum{omax=13};}; 52 template<> struct Orderhelper__<int64_t> {enum{omax=29};}; 53 54 /*! Functionality related to the HEALPix pixelisation. */ 55 template<typename I> class T_Healpix_Base: public Healpix_Tables 56 { 57 protected: 58 /*! The order of the map; -1 for nonhierarchical map. */ 59 int order_; 60 /*! The N_side parameter of the map; 0 if not allocated. */ 61 I nside_; 62 I npface_, ncap_, npix_; 63 double fact1_, fact2_; 64 /*! The map's ordering scheme. */ 65 Ordering_Scheme scheme_; 66 67 /*! Returns the number of the next ring to the north of \a z=cos(theta). 68 It may return 0; in this case \a z lies north of all rings. */ 69 inline I ring_above (double z) const; 70 void in_ring (I iz, double phi0, double dphi, rangeset<I> &pixset) const; 71 72 template<typename I2> void query_multidisc (const std::vector<vec3> &norm, 73 const std::vector<double> &rad, int fact, rangeset<I2> &pixset) const; 74 75 void query_multidisc_general (const std::vector<vec3> &norm, const std::vector<double> &rad, 76 bool inclusive, const std::vector<int> &cmds, rangeset<I> &pixset) const; 77 78 void query_strip_internal (double theta1, double theta2, bool inclusive, 79 rangeset<I> &pixset) const; 80 81 I xyf2nest(int ix, int iy, int face_num) const; 82 void nest2xyf(I pix, int &ix, int &iy, int &face_num) const; 83 I xyf2ring(int ix, int iy, int face_num) const; 84 void ring2xyf(I pix, int &ix, int &iy, int &face_num) const; 85 86 I loc2pix (double z, double phi, double sth, bool have_sth) const; 87 void pix2loc (I pix, double &z, double &phi, double &sth, bool &have_sth) 88 const; 89 90 void xyf2loc(double x, double y, int face, double &z, double &ph, 91 double &sth, bool &have_sth) const; 92 93 I nest_peano_helper (I pix, int dir) const; 94 95 typedef I (T_Healpix_Base::*swapfunc)(I pix) const; 96 // using swapfunc = I(I) const; 97 98 public: 99 enum {order_max=Orderhelper__<I>::omax}; 100 101 /*! Calculates the map order from its \a N_side parameter. 102 Returns -1 if \a nside is not a power of 2. 103 \param nside the \a N_side parameter */ 104 static int nside2order (I nside); 105 /*! Calculates the \a N_side parameter from the number of pixels. 106 \param npix the number of pixels */ 107 static I npix2nside (I npix); 108 /*! Constructs an unallocated object. */ 109 T_Healpix_Base (); 110 /*! Constructs an object with a given \a order and the ordering 111 scheme \a scheme. */ 112 T_Healpix_Base (int order, Ordering_Scheme scheme) 113 { Set (order, scheme); } 114 /*! Constructs an object with a given \a nside and the ordering 115 scheme \a scheme. The \a nside_dummy parameter must be set to 116 SET_NSIDE. */ 117 T_Healpix_Base (I nside, Ordering_Scheme scheme, const nside_dummy) 118 { SetNside (nside, scheme); } 119 120 /*! Adjusts the object to \a order and \a scheme. */ 121 void Set (int order, Ordering_Scheme scheme); 122 /*! Adjusts the object to \a nside and \a scheme. */ 123 void SetNside (I nside, Ordering_Scheme scheme); 124 125 /*! Returns the z-coordinate of the ring \a ring. This also works 126 for the (not really existing) rings 0 and 4*nside. */ 127 double ring2z (I ring) const; 128 /*! Returns the number of the ring in which \a pix lies. */ 129 I pix2ring (I pix) const; 130 131 I xyf2pix(int ix, int iy, int face_num) const 132 { 133 return (scheme_==RING) ? 134 xyf2ring(ix,iy,face_num) : xyf2nest(ix,iy,face_num); 135 } 136 void pix2xyf(I pix, int &ix, int &iy, int &face_num) const 137 { 138 (scheme_==RING) ? 139 ring2xyf(pix,ix,iy,face_num) : nest2xyf(pix,ix,iy,face_num); 140 } 141 142 /*! Translates a pixel number from NEST to RING. */ 143 I nest2ring (I pix) const; 144 /*! Translates a pixel number from RING to NEST. */ 145 I ring2nest (I pix) const; 146 /*! Translates a pixel number from NEST to its Peano index. */ 147 I nest2peano (I pix) const; 148 /*! Translates a pixel number from its Peano index to NEST. */ 149 I peano2nest (I pix) const; 150 151 /*! Returns the number of the pixel which contains the angular coordinates 152 (\a z:=cos(theta), \a phi). 153 \note This method is inaccurate near the poles at high resolutions. */ 154 I zphi2pix (double z, double phi) const 155 { return loc2pix(z,phi,0.,false); } 156 157 /*! Returns the number of the pixel which contains the angular coordinates 158 \a ang. */ 159 I ang2pix (const pointing &ang) const 160 { 161 const double pi_=3.141592653589793238462643383279502884197; 162 MR_assert((ang.theta>=0)&&(ang.theta<=pi_),"invalid theta value"); 163 return ((ang.theta<0.01) || (ang.theta > 3.14159-0.01)) ? 164 loc2pix(cos(ang.theta),ang.phi,sin(ang.theta),true) : 165 loc2pix(cos(ang.theta),ang.phi,0.,false); 166 } 167 /*! Returns the number of the pixel which contains the vector \a vec 168 (\a vec is normalized if necessary). */ 169 I vec2pix (const vec3 &vec) const 170 { 171 double xl = 1./vec.Length(); 172 double phi = safe_atan2(vec.y,vec.x); 173 double nz = vec.z*xl; 174 if (std::abs(nz)>0.99) 175 return loc2pix (nz,phi,std::sqrt(vec.x*vec.x+vec.y*vec.y)*xl,true); 176 else 177 return loc2pix (nz,phi,0,false); 178 } 179 180 /*! Returns the angular coordinates (\a z:=cos(theta), \a phi) of the center 181 of the pixel with number \a pix. 182 \note This method is inaccurate near the poles at high resolutions. */ 183 void pix2zphi (I pix, double &z, double &phi) const 184 { 185 bool dum_b; 186 double dum_d; 187 pix2loc(pix,z,phi,dum_d,dum_b); 188 } 189 190 /*! Returns the angular coordinates of the center of the pixel with 191 number \a pix. */ 192 pointing pix2ang (I pix) const 193 { 194 double z, phi, sth; 195 bool have_sth; 196 pix2loc (pix,z,phi,sth,have_sth); 197 return have_sth ? pointing(atan2(sth,z),phi) : pointing(acos(z),phi); 198 } 199 /*! Returns the vector to the center of the pixel with number \a pix. */ 200 vec3 pix2vec (I pix) const 201 { 202 double z, phi, sth; 203 bool have_sth; 204 pix2loc (pix,z,phi,sth,have_sth); 205 if (have_sth) 206 return vec3(sth*cos(phi),sth*sin(phi),z); 207 else 208 { 209 vec3 res; 210 res.set_z_phi (z, phi); 211 return res; 212 } 213 } 214 /*! Returns the pixel number for this T_Healpix_Base corresponding to the 215 pixel number \a pix in \a b. 216 \note \a b.Nside()\%Nside() must be 0. */ 217 I pixel_import (I pix, const T_Healpix_Base &b) const 218 { 219 I ratio = b.nside_/nside_; 220 MR_assert(nside_*ratio==b.nside_,"bad nside ratio"); 221 int x, y, f; 222 b.pix2xyf(pix, x, y, f); 223 x/=ratio; y/=ratio; 224 return xyf2pix(x, y, f); 225 } 226 227 template<typename I2> void query_disc_internal (pointing ptg, double radius, 228 int fact, rangeset<I2> &pixset) const; 229 230 /*! Returns the range set of all pixels whose centers lie within the disk 231 defined by \a dir and \a radius. 232 \param dir the angular coordinates of the disk center 233 \param radius the radius (in radians) of the disk 234 \param pixset a \a rangeset object containing the indices of all pixels 235 whose centers lie inside the disk 236 \note This method is more efficient in the RING scheme. */ 237 void query_disc (pointing ptg, double radius, rangeset<I> &pixset) const; 238 /*! Returns the range set of all pixels whose centers lie within the disk 239 defined by \a dir and \a radius. 240 \param dir the angular coordinates of the disk center 241 \param radius the radius (in radians) of the disk 242 \note This method is more efficient in the RING scheme. */ 243 rangeset<I> query_disc (pointing ptg, double radius) const 244 { 245 rangeset<I> res; 246 query_disc(ptg, radius, res); 247 return res; 248 } 249 /*! Returns the range set of all pixels which overlap with the disk 250 defined by \a dir and \a radius. 251 \param dir the angular coordinates of the disk center 252 \param radius the radius (in radians) of the disk 253 \param pixset a \a rangeset object containing the indices of all pixels 254 overlapping with the disk. 255 \param fact The overlapping test will be done at the resolution 256 \a fact*nside. For NESTED ordering, \a fact must be a power of 2, 257 else it can be any positive integer. A typical choice would be 4. 258 \note This method may return some pixels which don't overlap with 259 the disk at all. The higher \a fact is chosen, the fewer false 260 positives are returned, at the cost of increased run time. 261 \note This method is more efficient in the RING scheme. */ 262 void query_disc_inclusive (pointing ptg, double radius, rangeset<I> &pixset, 263 int fact=1) const; 264 /*! Returns the range set of all pixels which overlap with the disk 265 defined by \a dir and \a radius. 266 \param dir the angular coordinates of the disk center 267 \param radius the radius (in radians) of the disk 268 \param fact The overlapping test will be done at the resolution 269 \a fact*nside. For NESTED ordering, \a fact must be a power of 2, 270 else it can be any positive integer. A typical choice would be 4. 271 \note This method may return some pixels which don't overlap with 272 the disk at all. The higher \a fact is chosen, the fewer false 273 positives are returned, at the cost of increased run time. 274 \note This method is more efficient in the RING scheme. */ 275 rangeset<I> query_disc_inclusive (pointing ptg, double radius, 276 int fact=1) const 277 { 278 rangeset<I> res; 279 query_disc_inclusive(ptg, radius, res, fact); 280 return res; 281 } 282 283 /*! \deprecated Please use the version based on \a rangeset */ 284 void query_disc (const pointing &dir, double radius, 285 std::vector<I> &listpix) const 286 { 287 rangeset<I> pixset; 288 query_disc(dir,radius,pixset); 289 pixset.toVector(listpix); 290 } 291 /*! \deprecated Please use the version based on \a rangeset */ 292 void query_disc_inclusive (const pointing &dir, double radius, 293 std::vector<I> &listpix, int fact=1) const 294 { 295 rangeset<I> pixset; 296 query_disc_inclusive(dir,radius,pixset,fact); 297 pixset.toVector(listpix); 298 } 299 300 template<typename I2> void query_polygon_internal 301 (const std::vector<pointing> &vertex, int fact, 302 rangeset<I2> &pixset) const; 303 304 /*! Returns a range set of pixels whose centers lie within the convex 305 polygon defined by the \a vertex array. 306 \param vertex array containing the vertices of the polygon. 307 \param pixset a \a rangeset object containing the indices of all pixels 308 whose centers lie inside the polygon 309 \note This method is more efficient in the RING scheme. */ 310 void query_polygon (const std::vector<pointing> &vertex, 311 rangeset<I> &pixset) const; 312 /*! Returns a range set of pixels whose centers lie within the convex 313 polygon defined by the \a vertex array. 314 \param vertex array containing the vertices of the polygon. 315 \note This method is more efficient in the RING scheme. */ 316 rangeset<I> query_polygon (const std::vector<pointing> &vertex) const 317 { 318 rangeset<I> res; 319 query_polygon(vertex, res); 320 return res; 321 } 322 323 /*! Returns a range set of pixels which overlap with the convex 324 polygon defined by the \a vertex array. 325 \param vertex array containing the vertices of the polygon. 326 \param pixset a \a rangeset object containing the indices of all pixels 327 overlapping with the polygon. 328 \param fact The overlapping test will be done at the resolution 329 \a fact*nside. For NESTED ordering, \a fact must be a power of 2, 330 else it can be any positive integer. A typical choice would be 4. 331 \note This method may return some pixels which don't overlap with 332 the polygon at all. The higher \a fact is chosen, the fewer false 333 positives are returned, at the cost of increased run time. 334 \note This method is more efficient in the RING scheme. */ 335 void query_polygon_inclusive (const std::vector<pointing> &vertex, 336 rangeset<I> &pixset, int fact=1) const; 337 /*! Returns a range set of pixels which overlap with the convex 338 polygon defined by the \a vertex array. 339 \param vertex array containing the vertices of the polygon. 340 \param fact The overlapping test will be done at the resolution 341 \a fact*nside. For NESTED ordering, \a fact must be a power of 2, 342 else it can be any positive integer. A typical choice would be 4. 343 \note This method may return some pixels which don't overlap with 344 the polygon at all. The higher \a fact is chosen, the fewer false 345 positives are returned, at the cost of increased run time. 346 \note This method is more efficient in the RING scheme. */ 347 rangeset<I> query_polygon_inclusive (const std::vector<pointing> &vertex, 348 int fact=1) const 349 { 350 rangeset<I> res; 351 query_polygon_inclusive(vertex, res, fact); 352 return res; 353 } 354 355 /*! Returns a range set of pixels whose centers lie within the colatitude 356 range defined by \a theta1 and \a theta2 (if \a inclusive==false), or 357 which overlap with this region (if \a inclusive==true). If 358 \a theta1<theta2, the region between both angles is considered, 359 otherwise the regions \a 0<theta<theta2 and \a theta1<theta<pi. 360 \param theta1 first colatitude 361 \param theta2 second colatitude 362 \param inclusive if \a false, return the exact set of pixels whose 363 pixels centers lie within the region; if \a true, return all pixels 364 that overlap with the region. */ 365 void query_strip (double theta1, double theta2, bool inclusive, 366 rangeset<I> &pixset) const; 367 /*! Returns a range set of pixels whose centers lie within the colatitude 368 range defined by \a theta1 and \a theta2 (if \a inclusive==false), or 369 which overlap with this region (if \a inclusive==true). If 370 \a theta1<theta2, the region between both angles is considered, 371 otherwise the regions \a 0<theta<theta2 and \a theta1<theta<pi. 372 \param theta1 first colatitude 373 \param theta2 second colatitude 374 \param inclusive if \a false, return the exact set of pixels whose 375 pixels centers lie within the region; if \a true, return all pixels 376 that overlap with the region. */ 377 rangeset<I> query_strip (double theta1, double theta2, bool inclusive) const 378 { 379 rangeset<I> res; 380 query_strip(theta1, theta2, inclusive, res); 381 return res; 382 } 383 384 /*! Returns useful information about a given ring of the map. 385 \param ring the ring number (the number of the first ring is 1) 386 \param startpix the number of the first pixel in the ring 387 (NOTE: this is always given in the RING numbering scheme!) 388 \param ringpix the number of pixels in the ring 389 \param costheta the cosine of the colatitude of the ring 390 \param sintheta the sine of the colatitude of the ring 391 \param shifted if \a true, the center of the first pixel is not at 392 \a phi=0 */ 393 void get_ring_info (I ring, I &startpix, I &ringpix, 394 double &costheta, double &sintheta, bool &shifted) const; 395 /*! Returns useful information about a given ring of the map. 396 \param ring the ring number (the number of the first ring is 1) 397 \param startpix the number of the first pixel in the ring 398 (NOTE: this is always given in the RING numbering scheme!) 399 \param ringpix the number of pixels in the ring 400 \param theta the colatitude (in radians) of the ring 401 \param shifted if \a true, the center of the first pixel is not at 402 \a phi=0 */ 403 void get_ring_info2 (I ring, I &startpix, I &ringpix, 404 double &theta, bool &shifted) const; 405 /*! Returns useful information about a given ring of the map. 406 \param ring the ring number (the number of the first ring is 1) 407 \param startpix the number of the first pixel in the ring 408 (NOTE: this is always given in the RING numbering scheme!) 409 \param ringpix the number of pixels in the ring 410 \param shifted if \a true, the center of the first pixel is not at 411 \a phi=0 */ 412 void get_ring_info_small (I ring, I &startpix, I &ringpix, 413 bool &shifted) const; 414 /*! Returns the neighboring pixels of \a pix in \a result. 415 On exit, \a result contains (in this order) 416 the pixel numbers of the SW, W, NW, N, NE, E, SE and S neighbor 417 of \a pix. If a neighbor does not exist (this can only be the case 418 for the W, N, E and S neighbors), its entry is set to -1. 419 420 \note This method works in both RING and NEST schemes, but is 421 considerably faster in the NEST scheme. */ 422 void neighbors (I pix, std::array<I,8> &result) const; 423 /*! Returns interpolation information for the direction \a ptg. 424 The surrounding pixels are returned in \a pix, their corresponding 425 weights in \a wgt. 426 \note This method works in both RING and NEST schemes, but is 427 considerably faster in the RING scheme. */ 428 void get_interpol (const pointing &ptg, std::array<I,4> &pix, 429 std::array<double,4> &wgt) const; 430 431 /*! Returns the order parameter of the object. */ 432 int Order() const { return order_; } 433 /*! Returns the \a N_side parameter of the object. */ 434 I Nside() const { return nside_; } 435 /*! Returns the number of pixels of the object. */ 436 I Npix() const { return npix_; } 437 /*! Returns the ordering scheme of the object. */ 438 Ordering_Scheme Scheme() const { return scheme_; } 439 440 /*! Returns \a true, if both objects have the same nside and scheme, 441 else \a false. */ 442 bool conformable (const T_Healpix_Base &other) const 443 { return ((nside_==other.nside_) && (scheme_==other.scheme_)); } 444 445 /*! Swaps the contents of two Healpix_Base objects. */ 446 void swap (T_Healpix_Base &other); 447 448 /*! Returns the maximum angular distance (in radian) between any pixel 449 center and its corners. */ 450 double max_pixrad() const; 451 452 /*! Returns the maximum angular distance (in radian) between any pixel 453 center and its corners in a given ring. */ 454 double max_pixrad(I ring) const; 455 456 /*! Returns a set of points along the boundary of the given pixel. 457 \a step=1 gives 4 points on the corners. The first point corresponds 458 to the northernmost corner, the subsequent points follow the pixel 459 boundary through west, south and east corners. 460 \param pix pixel index number 461 \param step the number of returned points is 4*step. */ 462 void boundaries (I pix, size_t step, std::vector<vec3> &out) const; 463 464 std::vector<int> swap_cycles() const; 465 }; 466 467 /*! T_Healpix_Base for Nside up to 2^13. */ 468 typedef T_Healpix_Base<int> Healpix_Base; 469 /*! T_Healpix_Base for Nside up to 2^29. */ 470 typedef T_Healpix_Base<int64_t> Healpix_Base2; 471 472 } 473 474 using detail_healpix::Healpix_Base; 475 using detail_healpix::Healpix_Base2; 476 477 } 478 479 #endif 480