Healpix C++  3.83
healpix_base.cc
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 /*
28  * Copyright (C) 2003-2024 Max-Planck-Society
29  * Author: Martin Reinecke
30  */
31 
32 #include "healpix_base.h"
33 #include "geom_utils.h"
34 #include "lsconstants.h"
35 
36 using namespace std;
37 
38 template<typename I> int T_Healpix_Base<I>::nside2order (I nside)
39  {
40  planck_assert (nside>I(0), "invalid value for Nside");
41  return ((nside)&(nside-1)) ? -1 : ilog2(nside);
42  }
43 template<typename I> I T_Healpix_Base<I>::npix2nside (I npix)
44  {
45  I res=isqrt(npix/I(12));
46  planck_assert (npix==res*res*I(12), "invalid value for npix");
47  return res;
48  }
49 
50 template<typename I> I T_Healpix_Base<I>::ring_above (double z) const
51  {
52  double az=abs(z);
53  if (az<=twothird) // equatorial region
54  return I(nside_*(2-1.5*z));
55  I iring = I(nside_*sqrt(3*(1-az)));
56  return (z>0) ? iring : 4*nside_-iring-1;
57  }
58 
59 namespace {
60 
61 /* Short note on the "zone":
62  zone = 0: pixel lies completely outside the queried shape
63  1: pixel may overlap with the shape, pixel center is outside
64  2: pixel center is inside the shape, but maybe not the complete pixel
65  3: pixel lies completely inside the shape */
66 
67 template<typename I, typename I2> inline void check_pixel (int o, int order_,
68  int omax, int zone, rangeset<I2> &pixset, I pix, vector<pair<I,int> > &stk,
69  bool inclusive, int &stacktop)
70  {
71  if (zone==0) return;
72 
73  if (o<order_)
74  {
75  if (zone>=3)
76  {
77  int sdist=2*(order_-o); // the "bit-shift distance" between map orders
78  pixset.append(pix<<sdist,(pix+1)<<sdist); // output all subpixels
79  }
80  else // (1<=zone<=2)
81  for (int i=0; i<4; ++i)
82  stk.push_back(make_pair(4*pix+3-i,o+1)); // add children
83  }
84  else if (o>order_) // this implies that inclusive==true
85  {
86  if (zone>=2) // pixel center in shape
87  {
88  pixset.append(pix>>(2*(o-order_))); // output the parent pixel at order_
89  stk.resize(stacktop); // unwind the stack
90  }
91  else // (zone==1): pixel center in safety range
92  {
93  if (o<omax) // check sublevels
94  for (int i=0; i<4; ++i) // add children in reverse order
95  stk.push_back(make_pair(4*pix+3-i,o+1));
96  else // at resolution limit
97  {
98  pixset.append(pix>>(2*(o-order_))); // output the parent pixel at order_
99  stk.resize(stacktop); // unwind the stack
100  }
101  }
102  }
103  else // o==order_
104  {
105  if (zone>=2)
106  pixset.append(pix);
107  else if (inclusive) // and (zone>=1)
108  {
109  if (order_<omax) // check sublevels
110  {
111  stacktop=stk.size(); // remember current stack position
112  for (int i=0; i<4; ++i) // add children in reverse order
113  stk.push_back(make_pair(4*pix+3-i,o+1));
114  }
115  else // at resolution limit
116  pixset.append(pix); // output the pixel
117  }
118  }
119  }
120 
121 template<typename I> bool check_pixel_ring (const T_Healpix_Base<I> &b1,
122  const T_Healpix_Base<I> &b2, I pix, I nr, I ipix1, int fct,
123  double cz, double cphi, double cosrp2, I cpix)
124  {
125  if (pix>=nr) pix-=nr;
126  if (pix<0) pix+=nr;
127  pix+=ipix1;
128  if (pix==cpix) return false; // disk center in pixel => overlap
129  int px,py,pf;
130  b1.pix2xyf(pix,px,py,pf);
131  for (int i=0; i<fct-1; ++i) // go along the 4 edges
132  {
133  I ox=fct*px, oy=fct*py;
134  double pz,pphi;
135  b2.pix2zphi(b2.xyf2pix(ox+i,oy,pf),pz,pphi);
136  if (cosdist_zphi(pz,pphi,cz,cphi)>cosrp2) // overlap
137  return false;
138  b2.pix2zphi(b2.xyf2pix(ox+fct-1,oy+i,pf),pz,pphi);
139  if (cosdist_zphi(pz,pphi,cz,cphi)>cosrp2) // overlap
140  return false;
141  b2.pix2zphi(b2.xyf2pix(ox+fct-1-i,oy+fct-1,pf),pz,pphi);
142  if (cosdist_zphi(pz,pphi,cz,cphi)>cosrp2) // overlap
143  return false;
144  b2.pix2zphi(b2.xyf2pix(ox,oy+fct-1-i,pf),pz,pphi);
145  if (cosdist_zphi(pz,pphi,cz,cphi)>cosrp2) // overlap
146  return false;
147  }
148  return true;
149  }
150 
151 } // unnamed namespace
152 
153 template<typename I> template<typename I2>
155  (pointing ptg, double radius, int fact, rangeset<I2> &pixset) const
156  {
157  bool inclusive = (fact!=0);
158  pixset.clear();
159  ptg.normalize();
160 
161  if (scheme_==RING)
162  {
163  I fct=1;
164  if (inclusive)
165  {
166  planck_assert (((I(1)<<order_max)/nside_)>=fact,
167  "invalid oversampling factor");
168  fct = fact;
169  }
170  T_Healpix_Base b2;
171  double rsmall, rbig;
172  if (fct>1)
173  {
174  b2.SetNside(fct*nside_,RING);
175  rsmall = radius+b2.max_pixrad();
176  rbig = radius+max_pixrad();
177  }
178  else
179  rsmall = rbig = inclusive ? radius+max_pixrad() : radius;
180 
181  if (rsmall>=pi)
182  { pixset.append(0,npix_); return; }
183 
184  rbig = min(pi,rbig);
185 
186  double cosrsmall = cos(rsmall);
187  double cosrbig = cos(rbig);
188 
189  double z0 = cos(ptg.theta);
190  double xa = 1./sqrt((1-z0)*(1+z0));
191 
192  I cpix=zphi2pix(z0,ptg.phi);
193 
194  double rlat1 = ptg.theta - rsmall;
195  double zmax = cos(rlat1);
196  I irmin = ring_above (zmax)+1;
197 
198  if ((rlat1<=0) && (irmin>1)) // north pole in the disk
199  {
200  I sp,rp; bool dummy;
201  get_ring_info_small(irmin-1,sp,rp,dummy);
202  pixset.append(0,sp+rp);
203  }
204 
205  if ((fct>1) && (rlat1>0)) irmin=max(I(1),irmin-1);
206 
207  double rlat2 = ptg.theta + rsmall;
208  double zmin = cos(rlat2);
209  I irmax = ring_above (zmin);
210 
211  if ((fct>1) && (rlat2<pi)) irmax=min(4*nside_-1,irmax+1);
212 
213  for (I iz=irmin; iz<=irmax; ++iz)
214  {
215  double z=ring2z(iz);
216  double x = (cosrbig-z*z0)*xa;
217  double ysq = 1-z*z-x*x;
218  double dphi=-1;
219  bool fullcircle = false;
220  if (ysq<=0) // no intersection, ring completely inside or outside
221  {
222  if (fct==1)
223  dphi = 0;
224  else
225  {
226  fullcircle = true;
227  dphi = pi-1e-15;
228  }
229  }
230  else
231  dphi = atan2(sqrt(ysq),x);
232  if (dphi>0)
233  {
234  I nr, ipix1;
235  bool shifted;
236  get_ring_info_small(iz,ipix1,nr,shifted);
237  double shift = shifted ? 0.5 : 0.;
238 
239  I ipix2 = ipix1 + nr - 1; // highest pixel number in the ring
240 
241  I ip_lo = ifloor<I>(nr*inv_twopi*(ptg.phi-dphi) - shift)+1;
242  I ip_hi = ifloor<I>(nr*inv_twopi*(ptg.phi+dphi) - shift);
243  if (fullcircle) // make sure we test the entire ring
244  {
245  if (ip_hi-ip_lo<nr-1)
246  {
247  if (ip_lo>0)
248  --ip_lo;
249  else
250  ++ip_hi;
251  }
252  }
253 
254  if (fct>1)
255  {
256  while ((ip_lo<=ip_hi) && check_pixel_ring
257  (*this,b2,ip_lo,nr,ipix1,fct,z0,ptg.phi,cosrsmall,cpix))
258  ++ip_lo;
259  while ((ip_hi>ip_lo) && check_pixel_ring
260  (*this,b2,ip_hi,nr,ipix1,fct,z0,ptg.phi,cosrsmall,cpix))
261  --ip_hi;
262  }
263 
264  if (ip_lo<=ip_hi)
265  {
266  if (ip_hi>=nr)
267  { ip_lo-=nr; ip_hi-=nr; }
268  if (ip_lo<0)
269  {
270  pixset.append(ipix1,ipix1+ip_hi+1);
271  pixset.append(ipix1+ip_lo+nr,ipix2+1);
272  }
273  else
274  pixset.append(ipix1+ip_lo,ipix1+ip_hi+1);
275  }
276  }
277  }
278  if ((rlat2>=pi) && (irmax+1<4*nside_)) // south pole in the disk
279  {
280  I sp,rp; bool dummy;
281  get_ring_info_small(irmax+1,sp,rp,dummy);
282  pixset.append(sp,npix_);
283  }
284  }
285  else // scheme_==NEST
286  {
287  if (radius>=pi) // disk covers the whole sphere
288  { pixset.append(0,npix_); return; }
289 
290  int oplus = 0;
291  if (inclusive)
292  {
293  planck_assert ((I(1)<<(order_max-order_))>=fact,
294  "invalid oversampling factor");
295  planck_assert ((fact&(fact-1))==0,
296  "oversampling factor must be a power of 2");
297  oplus=ilog2(fact);
298  }
299  int omax=order_+oplus; // the order up to which we test
300 
301  vec3 vptg(ptg);
302  arr<T_Healpix_Base<I> > base(omax+1);
303  arr<double> crpdr(omax+1), crmdr(omax+1);
304  double cosrad=cos(radius);
305  for (int o=0; o<=omax; ++o) // prepare data at the required orders
306  {
307  base[o].Set(o,NEST);
308  double dr=base[o].max_pixrad(); // safety distance
309  crpdr[o] = (radius+dr>pi) ? -1. : cos(radius+dr);
310  crmdr[o] = (radius-dr<0.) ? 1. : cos(radius-dr);
311  }
312  vector<pair<I,int> > stk; // stack for pixel numbers and their orders
313  stk.reserve(12+3*omax); // reserve maximum size to avoid reallocation
314  for (int i=0; i<12; ++i) // insert the 12 base pixels in reverse order
315  stk.push_back(make_pair(I(11-i),0));
316 
317  int stacktop=0; // a place to save a stack position
318 
319  while (!stk.empty()) // as long as there are pixels on the stack
320  {
321  // pop current pixel number and order from the stack
322  I pix=stk.back().first;
323  int o=stk.back().second;
324  stk.pop_back();
325 
326  double z,phi;
327  base[o].pix2zphi(pix,z,phi);
328  // cosine of angular distance between pixel center and disk center
329  double cangdist=cosdist_zphi(vptg.z,ptg.phi,z,phi);
330 
331  if (cangdist>crpdr[o])
332  {
333  int zone = (cangdist<cosrad) ? 1 : ((cangdist<=crmdr[o]) ? 2 : 3);
334 
335  check_pixel (o, order_, omax, zone, pixset, pix, stk, inclusive,
336  stacktop);
337  }
338  }
339  }
340  }
341 
342 template<typename I> void T_Healpix_Base<I>::query_disc
343  (pointing ptg, double radius, rangeset<I> &pixset) const
344  {
345  query_disc_internal (ptg, radius, 0, pixset);
346  }
347 
348 template<typename I> void T_Healpix_Base<I>::query_disc_inclusive
349  (pointing ptg, double radius, rangeset<I> &pixset, int fact) const
350  {
351  planck_assert(fact>0,"fact must be a positive integer");
352  if ((sizeof(I)<8) && (((I(1)<<order_max)/nside_)<fact))
353  {
354  T_Healpix_Base<int64> base2(nside_,scheme_,SET_NSIDE);
355  base2.query_disc_internal(ptg,radius,fact,pixset);
356  return;
357  }
358  query_disc_internal (ptg, radius, fact, pixset);
359  }
360 
361 template<typename I> template<typename I2>
362  void T_Healpix_Base<I>::query_multidisc (const arr<vec3> &norm,
363  const arr<double> &rad, int fact, rangeset<I2> &pixset) const
364  {
365  bool inclusive = (fact!=0);
366  tsize nv=norm.size();
367  planck_assert(nv==rad.size(),"inconsistent input arrays");
368  pixset.clear();
369 
370  if (scheme_==RING)
371  {
372  I fct=1;
373  if (inclusive)
374  {
375  planck_assert (((I(1)<<order_max)/nside_)>=fact,
376  "invalid oversampling factor");
377  fct = fact;
378  }
379  T_Healpix_Base b2;
380  double rpsmall, rpbig;
381  if (fct>1)
382  {
383  b2.SetNside(fct*nside_,RING);
384  rpsmall = b2.max_pixrad();
385  rpbig = max_pixrad();
386  }
387  else
388  rpsmall = rpbig = inclusive ? max_pixrad() : 0;
389 
390  I irmin=1, irmax=4*nside_-1;
391  vector<double> z0,xa,cosrsmall,cosrbig;
392  vector<pointing> ptg;
393  vector<I> cpix;
394  for (tsize i=0; i<nv; ++i)
395  {
396  double rsmall=rad[i]+rpsmall;
397  if (rsmall<pi)
398  {
399  double rbig=min(pi,rad[i]+rpbig);
400  pointing pnt=pointing(norm[i]);
401  cosrsmall.push_back(cos(rsmall));
402  cosrbig.push_back(cos(rbig));
403  double cth=cos(pnt.theta);
404  z0.push_back(cth);
405  if (fct>1) cpix.push_back(zphi2pix(cth,pnt.phi));
406  xa.push_back(1./sqrt((1-cth)*(1+cth)));
407  ptg.push_back(pnt);
408 
409  double rlat1 = pnt.theta - rsmall;
410  double zmax = cos(rlat1);
411  I irmin_t = (rlat1<=0) ? 1 : ring_above (zmax)+1;
412 
413  if ((fct>1) && (rlat1>0)) irmin_t=max(I(1),irmin_t-1);
414 
415  double rlat2 = pnt.theta + rsmall;
416  double zmin = cos(rlat2);
417  I irmax_t = (rlat2>=pi) ? 4*nside_-1 : ring_above (zmin);
418 
419  if ((fct>1) && (rlat2<pi)) irmax_t=min(4*nside_-1,irmax_t+1);
420 
421  if (irmax_t < irmax) irmax=irmax_t;
422  if (irmin_t > irmin) irmin=irmin_t;
423  }
424  }
425 
426  for (I iz=irmin; iz<=irmax; ++iz)
427  {
428  double z=ring2z(iz);
429  I ipix1,nr;
430  bool shifted;
431  get_ring_info_small(iz,ipix1,nr,shifted);
432  double shift = shifted ? 0.5 : 0.;
433  rangeset<I2> tr;
434  tr.append(ipix1,ipix1+nr);
435  for (tsize j=0; j<z0.size(); ++j)
436  {
437  double x = (cosrbig[j]-z*z0[j])*xa[j];
438  double ysq = 1.-z*z-x*x;
439  if (ysq>0)
440  {
441  double dphi = atan2(sqrt(ysq),x);
442  I ip_lo = ifloor<I>(nr*inv_twopi*(ptg[j].phi-dphi) - shift)+1;
443  I ip_hi = ifloor<I>(nr*inv_twopi*(ptg[j].phi+dphi) - shift);
444  if (fct>1)
445  {
446  while ((ip_lo<=ip_hi) && check_pixel_ring
447  (*this,b2,ip_lo,nr,ipix1,fct,z0[j],ptg[j].phi,cosrsmall[j],cpix[j]))
448  ++ip_lo;
449  while ((ip_hi>ip_lo) && check_pixel_ring
450  (*this,b2,ip_hi,nr,ipix1,fct,z0[j],ptg[j].phi,cosrsmall[j],cpix[j]))
451  --ip_hi;
452  }
453  if (ip_hi>=nr)
454  { ip_lo-=nr; ip_hi-=nr;}
455  if (ip_lo<0)
456  tr.remove(ipix1+ip_hi+1,ipix1+ip_lo+nr);
457  else
458  tr.intersect(ipix1+ip_lo,ipix1+ip_hi+1);
459  }
460  }
461  pixset.append(tr);
462  }
463  }
464  else // scheme_ == NEST
465  {
466  int oplus = 0;
467  if (inclusive)
468  {
469  planck_assert ((I(1)<<(order_max-order_))>=fact,
470  "invalid oversampling factor");
471  planck_assert ((fact&(fact-1))==0,
472  "oversampling factor must be a power of 2");
473  oplus=ilog2(fact);
474  }
475  int omax=order_+oplus; // the order up to which we test
476 
477  // TODO: ignore all disks with radius>=pi
478 
479  arr<T_Healpix_Base<I> > base(omax+1);
480  arr3<double> crlimit(omax+1,nv,3);
481  for (int o=0; o<=omax; ++o) // prepare data at the required orders
482  {
483  base[o].Set(o,NEST);
484  double dr=base[o].max_pixrad(); // safety distance
485  for (tsize i=0; i<nv; ++i)
486  {
487  crlimit(o,i,0) = (rad[i]+dr>pi) ? -1. : cos(rad[i]+dr);
488  crlimit(o,i,1) = (o==0) ? cos(rad[i]) : crlimit(0,i,1);
489  crlimit(o,i,2) = (rad[i]-dr<0.) ? 1. : cos(rad[i]-dr);
490  }
491  }
492 
493  vector<pair<I,int> > stk; // stack for pixel numbers and their orders
494  stk.reserve(12+3*omax); // reserve maximum size to avoid reallocation
495  for (int i=0; i<12; ++i) // insert the 12 base pixels in reverse order
496  stk.push_back(make_pair(I(11-i),0));
497 
498  int stacktop=0; // a place to save a stack position
499 
500  while (!stk.empty()) // as long as there are pixels on the stack
501  {
502  // pop current pixel number and order from the stack
503  I pix=stk.back().first;
504  int o=stk.back().second;
505  stk.pop_back();
506 
507  vec3 pv(base[o].pix2vec(pix));
508 
509  tsize zone=3;
510  for (tsize i=0; i<nv; ++i)
511  {
512  double crad=dotprod(pv,norm[i]);
513  for (tsize iz=0; iz<zone; ++iz)
514  if (crad<crlimit(o,i,iz))
515  if ((zone=iz)==0) goto bailout;
516  }
517 
518  check_pixel (o, order_, omax, zone, pixset, pix, stk, inclusive,
519  stacktop);
520  bailout:;
521  }
522  }
523  }
524 
525 template<typename I> void T_Healpix_Base<I>::query_multidisc_general
526  (const arr<vec3> &norm, const arr<double> &rad, bool inclusive,
527  const vector<int> &cmds, rangeset<I> &pixset) const
528  {
529  tsize nv=norm.size();
530  planck_assert(nv==rad.size(),"inconsistent input arrays");
531  pixset.clear();
532 
533  if (scheme_==RING)
534  {
535  planck_fail ("not yet implemented");
536  }
537  else // scheme_ == NEST
538  {
539  int oplus=inclusive ? 2 : 0;
540  int omax=min<int>(order_max,order_+oplus); // the order up to which we test
541 
542  // TODO: ignore all disks with radius>=pi
543 
544  arr<T_Healpix_Base<I> > base(omax+1);
545  arr3<double> crlimit(omax+1,nv,3);
546  for (int o=0; o<=omax; ++o) // prepare data at the required orders
547  {
548  base[o].Set(o,NEST);
549  double dr=base[o].max_pixrad(); // safety distance
550  for (tsize i=0; i<nv; ++i)
551  {
552  crlimit(o,i,0) = (rad[i]+dr>pi) ? -1. : cos(rad[i]+dr);
553  crlimit(o,i,1) = (o==0) ? cos(rad[i]) : crlimit(0,i,1);
554  crlimit(o,i,2) = (rad[i]-dr<0.) ? 1. : cos(rad[i]-dr);
555  }
556  }
557 
558  vector<pair<I,int> > stk; // stack for pixel numbers and their orders
559  stk.reserve(12+3*omax); // reserve maximum size to avoid reallocation
560  for (int i=0; i<12; ++i) // insert the 12 base pixels in reverse order
561  stk.push_back(make_pair(I(11-i),0));
562 
563  int stacktop=0; // a place to save a stack position
564  arr<tsize> zone(nv);
565 
566  vector<tsize> zstk; zstk.reserve(cmds.size());
567 
568  while (!stk.empty()) // as long as there are pixels on the stack
569  {
570  // pop current pixel number and order from the stack
571  I pix=stk.back().first;
572  int o=stk.back().second;
573  stk.pop_back();
574 
575  vec3 pv(base[o].pix2vec(pix));
576 
577  for (tsize i=0; i<nv; ++i)
578  {
579  zone[i]=3;
580  double crad=dotprod(pv,norm[i]);
581  for (tsize iz=0; iz<zone[i]; ++iz)
582  if (crad<crlimit(o,i,iz))
583  zone[i]=iz;
584  }
585 
586  for (tsize i=0; i<cmds.size(); ++i)
587  {
588  tsize tmp;
589  switch (cmds[i])
590  {
591  case -1: // union
592  tmp=zstk.back(); zstk.pop_back();
593  zstk.back() = max(zstk.back(),tmp);
594  break;
595  case -2: // intersection
596  tmp=zstk.back(); zstk.pop_back();
597  zstk.back() = min(zstk.back(),tmp);
598  break;
599  default: // add value
600  zstk.push_back(zone[cmds[i]]);
601  }
602  }
603  planck_assert(zstk.size()==1,"inconsistent commands");
604  tsize zn=zstk[0]; zstk.pop_back();
605 
606  check_pixel (o, order_, omax, zn, pixset, pix, stk, inclusive,
607  stacktop);
608  }
609  }
610  }
611 
612 #ifndef __BMI2__
613 
614 template<> inline int T_Healpix_Base<int>::spread_bits (int v) const
615  { return utab[v&0xff] | (utab[(v>>8)&0xff]<<16); }
616 template<> inline int64 T_Healpix_Base<int64>::spread_bits (int v) const
617  {
618  return int64(utab[ v &0xff]) | (int64(utab[(v>> 8)&0xff])<<16)
619  | (int64(utab[(v>>16)&0xff])<<32) | (int64(utab[(v>>24)&0xff])<<48);
620  }
621 
622 template<> inline int T_Healpix_Base<int>::compress_bits (int v) const
623  {
624  int raw = (v&0x5555) | ((v&0x55550000)>>15);
625  return ctab[raw&0xff] | (ctab[raw>>8]<<4);
626  }
627 template<> inline int T_Healpix_Base<int64>::compress_bits (int64 v) const
628  {
629  int64 raw = v&0x5555555555555555ull;
630  raw|=raw>>15;
631  return ctab[ raw &0xff] | (ctab[(raw>> 8)&0xff]<< 4)
632  | (ctab[(raw>>32)&0xff]<<16) | (ctab[(raw>>40)&0xff]<<20);
633  }
634 
635 #else
636 
637 #include <x86intrin.h>
638 
639 template<> inline int T_Healpix_Base<int>::spread_bits (int v) const
640  { return _pdep_u32(v,0x55555555u); }
641 template<> inline int64 T_Healpix_Base<int64>::spread_bits (int v) const
642  { return _pdep_u64(v,0x5555555555555555ull); }
643 template<> inline int T_Healpix_Base<int>::compress_bits (int v) const
644  { return _pext_u32(v,0x55555555u); }
645 template<> inline int T_Healpix_Base<int64>::compress_bits (int64 v) const
646  { return _pext_u64(v,0x5555555555555555ull); }
647 
648 #endif
649 
650 template<typename I> inline void T_Healpix_Base<I>::nest2xyf (I pix, int &ix,
651  int &iy, int &face_num) const
652  {
653  face_num = pix>>(2*order_);
654  pix &= (npface_-1);
655  ix = compress_bits(pix);
656  iy = compress_bits(pix>>1);
657  }
658 
659 template<typename I> inline I T_Healpix_Base<I>::xyf2nest (int ix, int iy,
660  int face_num) const
661  { return (I(face_num)<<(2*order_)) + spread_bits(ix) + (spread_bits(iy)<<1); }
662 
663 namespace {
664 
665 // low-level hack to accelerate divisions with a result of [0;3]
666 template<typename I> inline I special_div(I a, I b)
667  {
668  I t=(a>=(b<<1));
669  a-=t*(b<<1);
670  return (t<<1)+(a>=b);
671  }
672 
673 } // unnamed namespace
674 
675 template<typename I> void T_Healpix_Base<I>::ring2xyf (I pix, int &ix, int &iy,
676  int &face_num) const
677  {
678  I iring, iphi, kshift, nr;
679  I nl2 = 2*nside_;
680 
681  if (pix<ncap_) // North Polar cap
682  {
683  iring = (1+isqrt(1+2*pix))>>1; //counted from North pole
684  iphi = (pix+1) - 2*iring*(iring-1);
685  kshift = 0;
686  nr = iring;
687  face_num=special_div(iphi-1,nr);
688  }
689  else if (pix<(npix_-ncap_)) // Equatorial region
690  {
691  I ip = pix - ncap_;
692  I tmp = (order_>=0) ? ip>>(order_+2) : ip/(4*nside_);
693  iring = tmp+nside_;
694  iphi = ip-tmp*4*nside_ + 1;
695  kshift = (iring+nside_)&1;
696  nr = nside_;
697  I ire = tmp+1,
698  irm = nl2+1-tmp;
699  I ifm = iphi - (ire>>1) + nside_ -1,
700  ifp = iphi - (irm>>1) + nside_ -1;
701  if (order_>=0)
702  { ifm >>= order_; ifp >>= order_; }
703  else
704  { ifm /= nside_; ifp /= nside_; }
705  face_num = (ifp==ifm) ? (ifp|4) : ((ifp<ifm) ? ifp : (ifm+8));
706  }
707  else // South Polar cap
708  {
709  I ip = npix_ - pix;
710  iring = (1+isqrt(2*ip-1))>>1; //counted from South pole
711  iphi = 4*iring + 1 - (ip - 2*iring*(iring-1));
712  kshift = 0;
713  nr = iring;
714  iring = 2*nl2-iring;
715  face_num=special_div(iphi-1,nr)+8;
716  }
717 
718  I irt = iring - ((2+(face_num>>2))*nside_) + 1;
719  I ipt = 2*iphi- jpll[face_num]*nr - kshift -1;
720 // I ipt = 2*iphi- (((face_num&3)<<1)+1-((face_num>>2)&1))*nr - kshift -1;
721  if (ipt>=nl2) ipt-=8*nside_;
722 
723  ix = (ipt-irt) >>1;
724  iy = (-ipt-irt) >>1;
725  }
726 
727 template<typename I> I T_Healpix_Base<I>::xyf2ring (int ix, int iy,
728  int face_num) const
729  {
730  I nl4 = 4*nside_;
731  I jr = (jrll[face_num]*nside_) - ix - iy - 1;
732 
733  I nr, kshift, n_before;
734 
735  bool shifted;
736  get_ring_info_small(jr,n_before,nr,shifted);
737  nr>>=2;
738  kshift=1-shifted;
739  I jp = (jpll[face_num]*nr + ix - iy + 1 + kshift) / 2;
740  planck_assert(jp<=4*nr,"must not happen");
741  if (jp<1) jp+=nl4; // assumption: if this triggers, then nl4==4*nr
742 
743  return n_before + jp - 1;
744  }
745 
746 template<typename I> T_Healpix_Base<I>::T_Healpix_Base ()
747  : order_(-1), nside_(0), npface_(0), ncap_(0), npix_(0),
748  fact1_(0), fact2_(0), scheme_(RING) {}
749 
750 template<typename I> void T_Healpix_Base<I>::Set (int order,
752  {
753  planck_assert ((order>=0)&&(order<=order_max), "bad order");
754  order_ = order;
755  nside_ = I(1)<<order;
756  npface_ = nside_<<order_;
757  ncap_ = (npface_-nside_)<<1;
758  npix_ = 12*npface_;
759  fact2_ = 4./npix_;
760  fact1_ = (nside_<<1)*fact2_;
761  scheme_ = scheme;
762  }
763 template<typename I> void T_Healpix_Base<I>::SetNside (I nside,
765  {
766  order_ = nside2order(nside);
767  planck_assert ((scheme!=NEST) || (order_>=0),
768  "SetNside: nside must be power of 2 for nested maps");
769  nside_ = nside;
770  npface_ = nside_*nside_;
771  ncap_ = (npface_-nside_)<<1;
772  npix_ = 12*npface_;
773  fact2_ = 4./npix_;
774  fact1_ = (nside_<<1)*fact2_;
775  scheme_ = scheme;
776  }
777 
778 template<typename I> double T_Healpix_Base<I>::ring2z (I ring) const
779  {
780  if (ring<nside_)
781  return 1 - ring*ring*fact2_;
782  if (ring <=3*nside_)
783  return (2*nside_-ring)*fact1_;
784  ring=4*nside_ - ring;
785  return ring*ring*fact2_ - 1;
786  }
787 
788 template<typename I> I T_Healpix_Base<I>::pix2ring (I pix) const
789  {
790  if (scheme_==RING)
791  {
792  if (pix<ncap_) // North Polar cap
793  return (1+I(isqrt(1+2*pix)))>>1; // counted from North pole
794  else if (pix<(npix_-ncap_)) // Equatorial region
795  return (pix-ncap_)/(4*nside_) + nside_; // counted from North pole
796  else // South Polar cap
797  return 4*nside_-((1+I(isqrt(2*(npix_-pix)-1)))>>1);
798  }
799  else
800  {
801  int face_num, ix, iy;
802  nest2xyf(pix,ix,iy,face_num);
803  return (I(jrll[face_num])<<order_) - ix - iy - 1;
804  }
805  }
806 
807 template<typename I> I T_Healpix_Base<I>::nest2ring (I pix) const
808  {
809  planck_assert(order_>=0, "hierarchical map required");
810  int ix, iy, face_num;
811  nest2xyf (pix, ix, iy, face_num);
812  return xyf2ring (ix, iy, face_num);
813  }
814 
815 template<typename I> I T_Healpix_Base<I>::ring2nest (I pix) const
816  {
817  planck_assert(order_>=0, "hierarchical map required");
818  int ix, iy, face_num;
819  ring2xyf (pix, ix, iy, face_num);
820  return xyf2nest (ix, iy, face_num);
821  }
822 
823 template<typename I> inline I T_Healpix_Base<I>::nest_peano_helper
824  (I pix, int dir) const
825  {
826  int face = (pix>>(2*order_));
827  I result = 0;
828  int state = ((peano_face2path[dir][face]<<4))|(dir<<7);
829  int shift=2*order_-4;
830  for (; shift>=0; shift-=4)
831  {
832  state=peano_arr2[(state&0xF0) | ((pix>>shift)&0xF)];
833  result = (result<<4) | (state&0xF);
834  }
835  if (shift==-2)
836  {
837  state=peano_arr[((state>>2)&0xFC) | (pix&0x3)];
838  result = (result<<2) | (state&0x3);
839  }
840 
841  return result + (I(peano_face2face[dir][face])<<(2*order_));
842  }
843 
844 template<typename I> I T_Healpix_Base<I>::nest2peano (I pix) const
845  { return nest_peano_helper(pix,0); }
846 
847 template<typename I> I T_Healpix_Base<I>::peano2nest (I pix) const
848  { return nest_peano_helper(pix,1); }
849 
850 template<typename I> I T_Healpix_Base<I>::loc2pix (double z, double phi,
851  double sth, bool have_sth) const
852  {
853  double za = abs(z);
854  double tt = fmodulo(phi*inv_halfpi,4.0); // in [0,4)
855 
856  if (scheme_==RING)
857  {
858  if (za<=twothird) // Equatorial region
859  {
860  I nl4 = 4*nside_;
861  double temp1 = nside_*(0.5+tt);
862  double temp2 = nside_*z*0.75;
863  I jp = I(temp1-temp2); // index of ascending edge line
864  I jm = I(temp1+temp2); // index of descending edge line
865 
866  // ring number counted from z=2/3
867  I ir = nside_ + 1 + jp - jm; // in {1,2n+1}
868  I kshift = 1-(ir&1); // kshift=1 if ir even, 0 otherwise
869 
870  I t1 = jp+jm-nside_+kshift+1+nl4+nl4;
871  I ip = (order_>0) ?
872  (t1>>1)&(nl4-1) : ((t1>>1)%nl4); // in {0,4n-1}
873 
874  return ncap_ + (ir-1)*nl4 + ip;
875  }
876  else // North & South polar caps
877  {
878  double tp = tt-I(tt);
879  double tmp = ((za<0.99)||(!have_sth)) ?
880  nside_*sqrt(3*(1-za)) :
881  nside_*sth/sqrt((1.+za)/3.);
882 
883  I jp = I(tp*tmp); // increasing edge line index
884  I jm = I((1.0-tp)*tmp); // decreasing edge line index
885 
886  I ir = jp+jm+1; // ring number counted from the closest pole
887  I ip = I(tt*ir); // in {0,4*ir-1}
888  planck_assert((ip>=0)&&(ip<4*ir),"must not happen");
889  //ip %= 4*ir;
890 
891  return (z>0) ? 2*ir*(ir-1) + ip : npix_ - 2*ir*(ir+1) + ip;
892  }
893  }
894  else // scheme_ == NEST
895  {
896  if (za<=twothird) // Equatorial region
897  {
898  double temp1 = nside_*(0.5+tt);
899  double temp2 = nside_*(z*0.75);
900  I jp = I(temp1-temp2); // index of ascending edge line
901  I jm = I(temp1+temp2); // index of descending edge line
902  I ifp = jp >> order_; // in {0,4}
903  I ifm = jm >> order_;
904  int face_num = (ifp==ifm) ? (ifp|4) : ((ifp<ifm) ? ifp : (ifm+8));
905 
906  int ix = jm & (nside_-1),
907  iy = nside_ - (jp & (nside_-1)) - 1;
908  return xyf2nest(ix,iy,face_num);
909  }
910  else // polar region, za > 2/3
911  {
912  int ntt = min(3,int(tt));
913  double tp = tt-ntt;
914  double tmp = ((za<0.99)||(!have_sth)) ?
915  nside_*sqrt(3*(1-za)) :
916  nside_*sth/sqrt((1.+za)/3.);
917 
918  I jp = I(tp*tmp); // increasing edge line index
919  I jm = I((1.0-tp)*tmp); // decreasing edge line index
920  jp=min(jp,nside_-1); // for points too close to the boundary
921  jm=min(jm,nside_-1);
922  return (z>=0) ?
923  xyf2nest(nside_-jm -1,nside_-jp-1,ntt) : xyf2nest(jp,jm,ntt+8);
924  }
925  }
926  }
927 
928 template<typename I> void T_Healpix_Base<I>::pix2loc (I pix, double &z,
929  double &phi, double &sth, bool &have_sth) const
930  {
931  have_sth=false;
932  if (scheme_==RING)
933  {
934  if (pix<ncap_) // North Polar cap
935  {
936  I iring = (1+I(isqrt(1+2*pix)))>>1; // counted from North pole
937  I iphi = (pix+1) - 2*iring*(iring-1);
938 
939  double tmp=(iring*iring)*fact2_;
940  z = 1.0 - tmp;
941  if (z>0.99) { sth=sqrt(tmp*(2.-tmp)); have_sth=true; }
942  phi = (iphi-0.5) * halfpi/iring;
943  }
944  else if (pix<(npix_-ncap_)) // Equatorial region
945  {
946  I nl4 = 4*nside_;
947  I ip = pix - ncap_;
948  I tmp = (order_>=0) ? ip>>(order_+2) : ip/nl4;
949  I iring = tmp + nside_,
950  iphi = ip-nl4*tmp+1;
951  // 1 if iring+nside is odd, 1/2 otherwise
952  double fodd = ((iring+nside_)&1) ? 1 : 0.5;
953 
954  z = (2*nside_-iring)*fact1_;
955  phi = (iphi-fodd) * pi*0.75*fact1_;
956  }
957  else // South Polar cap
958  {
959  I ip = npix_ - pix;
960  I iring = (1+I(isqrt(2*ip-1)))>>1; // counted from South pole
961  I iphi = 4*iring + 1 - (ip - 2*iring*(iring-1));
962 
963  double tmp=(iring*iring)*fact2_;
964  z = tmp - 1.0;
965  if (z<-0.99) { sth=sqrt(tmp*(2.-tmp)); have_sth=true; }
966  phi = (iphi-0.5) * halfpi/iring;
967  }
968  }
969  else
970  {
971  int face_num, ix, iy;
972  nest2xyf(pix,ix,iy,face_num);
973 
974  I jr = (I(jrll[face_num])<<order_) - ix - iy - 1;
975 
976  I nr;
977  if (jr<nside_)
978  {
979  nr = jr;
980  double tmp=(nr*nr)*fact2_;
981  z = 1 - tmp;
982  if (z>0.99) { sth=sqrt(tmp*(2.-tmp)); have_sth=true; }
983  }
984  else if (jr > 3*nside_)
985  {
986  nr = nside_*4-jr;
987  double tmp=(nr*nr)*fact2_;
988  z = tmp - 1;
989  if (z<-0.99) { sth=sqrt(tmp*(2.-tmp)); have_sth=true; }
990  }
991  else
992  {
993  nr = nside_;
994  z = (2*nside_-jr)*fact1_;
995  }
996 
997  I tmp=I(jpll[face_num])*nr+ix-iy;
998  planck_assert(tmp<8*nr,"must not happen");
999  if (tmp<0) tmp+=8*nr;
1000  phi = (nr==nside_) ? 0.75*halfpi*tmp*fact1_ :
1001  (0.5*halfpi*tmp)/nr;
1002  }
1003  }
1004 
1005 template<typename I> template<typename I2>
1007  (const vector<pointing> &vertex, int fact, rangeset<I2> &pixset) const
1008  {
1009  bool inclusive = (fact!=0);
1010  tsize nv=vertex.size();
1011  tsize ncirc = inclusive ? nv+1 : nv;
1012  planck_assert(nv>=3,"not enough vertices in polygon");
1013  vector<vec3> vv(nv);
1014  for (tsize i=0; i<nv; ++i)
1015  vv[i]=vertex[i].to_vec3();
1016  arr<vec3> normal(ncirc);
1017  int flip=0;
1018  for (tsize i=0; i<nv; ++i)
1019  {
1020  normal[i]=crossprod(vv[i],vv[(i+1)%nv]).Norm();
1021  double hnd=dotprod(normal[i],vv[(i+2)%nv]);
1022  planck_assert(abs(hnd)>1e-10,"degenerate corner");
1023  if (i==0)
1024  flip = (hnd<0.) ? -1 : 1;
1025  else
1026  planck_assert(flip*hnd>0,"polygon is not convex");
1027  normal[i]*=flip;
1028  }
1029  arr<double> rad(ncirc,halfpi);
1030  if (inclusive)
1031  {
1032  double cosrad;
1033  find_enclosing_circle (vv, normal[nv], cosrad);
1034  rad[nv]=acos(cosrad);
1035  }
1036  query_multidisc(normal,rad,fact,pixset);
1037  }
1038 
1039 template<typename I> void T_Healpix_Base<I>::query_polygon
1040  (const vector<pointing> &vertex, rangeset<I> &pixset) const
1041  {
1042  query_polygon_internal(vertex, 0, pixset);
1043  }
1044 
1045 template<typename I> void T_Healpix_Base<I>::query_polygon_inclusive
1046  (const vector<pointing> &vertex, rangeset<I> &pixset, int fact) const
1047  {
1048  planck_assert(fact>0,"fact must be a positive integer");
1049  if ((sizeof(I)<8) && (((I(1)<<order_max)/nside_)<fact))
1050  {
1051  T_Healpix_Base<int64> base2(nside_,scheme_,SET_NSIDE);
1052  base2.query_polygon_internal(vertex,fact,pixset);
1053  return;
1054  }
1055  query_polygon_internal(vertex, fact, pixset);
1056  }
1057 
1058 template<typename I> void T_Healpix_Base<I>::query_strip_internal
1059  (double theta1, double theta2, bool inclusive, rangeset<I> &pixset) const
1060  {
1061  if (scheme_==RING)
1062  {
1063  I ring1 = max(I(1),1+ring_above(cos(theta1))),
1064  ring2 = min(4*nside_-1,ring_above(cos(theta2)));
1065  if (inclusive)
1066  {
1067  ring1 = max(I(1),ring1-1);
1068  ring2 = min(4*nside_-1,ring2+1);
1069  }
1070 
1071  I sp1,rp1,sp2,rp2;
1072  bool dummy;
1073  get_ring_info_small(ring1,sp1,rp1,dummy);
1074  get_ring_info_small(ring2,sp2,rp2,dummy);
1075  I pix1 = sp1,
1076  pix2 = sp2+rp2;
1077  if (pix1<=pix2) pixset.append(pix1,pix2);
1078  }
1079  else
1080  planck_fail("query_strip not yet implemented for NESTED");
1081  }
1082 
1083 template<typename I> void T_Healpix_Base<I>::query_strip (double theta1,
1084  double theta2, bool inclusive, rangeset<I> &pixset) const
1085  {
1086  pixset.clear();
1087 
1088  if (theta1<theta2)
1089  query_strip_internal(theta1,theta2,inclusive,pixset);
1090  else
1091  {
1092  query_strip_internal(0.,theta2,inclusive,pixset);
1093  rangeset<I> ps2;
1094  query_strip_internal(theta1,pi,inclusive,ps2);
1095  pixset.append(ps2);
1096  }
1097  }
1098 
1099 template<typename I> inline void T_Healpix_Base<I>::get_ring_info_small
1100  (I ring, I &startpix, I &ringpix, bool &shifted) const
1101  {
1102  if (ring < nside_)
1103  {
1104  shifted = true;
1105  ringpix = 4*ring;
1106  startpix = 2*ring*(ring-1);
1107  }
1108  else if (ring < 3*nside_)
1109  {
1110  shifted = ((ring-nside_) & 1) == 0;
1111  ringpix = 4*nside_;
1112  startpix = ncap_ + (ring-nside_)*ringpix;
1113  }
1114  else
1115  {
1116  shifted = true;
1117  I nr= 4*nside_-ring;
1118  ringpix = 4*nr;
1119  startpix = npix_-2*nr*(nr+1);
1120  }
1121  }
1122 
1123 template<typename I> void T_Healpix_Base<I>::get_ring_info (I ring, I &startpix,
1124  I &ringpix, double &costheta, double &sintheta, bool &shifted) const
1125  {
1126  I northring = (ring>2*nside_) ? 4*nside_-ring : ring;
1127  if (northring < nside_)
1128  {
1129  double tmp = northring*northring*fact2_;
1130  costheta = 1 - tmp;
1131  sintheta = sqrt(tmp*(2-tmp));
1132  ringpix = 4*northring;
1133  shifted = true;
1134  startpix = 2*northring*(northring-1);
1135  }
1136  else
1137  {
1138  costheta = (2*nside_-northring)*fact1_;
1139  sintheta = sqrt((1+costheta)*(1-costheta));
1140  ringpix = 4*nside_;
1141  shifted = ((northring-nside_) & 1) == 0;
1142  startpix = ncap_ + (northring-nside_)*ringpix;
1143  }
1144  if (northring != ring) // southern hemisphere
1145  {
1146  costheta = -costheta;
1147  startpix = npix_ - startpix - ringpix;
1148  }
1149  }
1150 template<typename I> void T_Healpix_Base<I>::get_ring_info2 (I ring,
1151  I &startpix, I &ringpix, double &theta, bool &shifted) const
1152  {
1153  I northring = (ring>2*nside_) ? 4*nside_-ring : ring;
1154  if (northring < nside_)
1155  {
1156  double tmp = northring*northring*fact2_;
1157  double costheta = 1 - tmp;
1158  double sintheta = sqrt(tmp*(2-tmp));
1159  theta = atan2(sintheta,costheta);
1160  ringpix = 4*northring;
1161  shifted = true;
1162  startpix = 2*northring*(northring-1);
1163  }
1164  else
1165  {
1166  theta = acos((2*nside_-northring)*fact1_);
1167  ringpix = 4*nside_;
1168  shifted = ((northring-nside_) & 1) == 0;
1169  startpix = ncap_ + (northring-nside_)*ringpix;
1170  }
1171  if (northring != ring) // southern hemisphere
1172  {
1173  theta = pi-theta;
1174  startpix = npix_ - startpix - ringpix;
1175  }
1176  }
1177 
1178 template<typename I> void T_Healpix_Base<I>::neighbors (I pix,
1179  fix_arr<I,8> &result) const
1180  {
1181  int ix, iy, face_num;
1182  (scheme_==RING) ?
1183  ring2xyf(pix,ix,iy,face_num) : nest2xyf(pix,ix,iy,face_num);
1184 
1185  const I nsm1 = nside_-1;
1186  if ((ix>0)&&(ix<nsm1)&&(iy>0)&&(iy<nsm1))
1187  {
1188  if (scheme_==RING)
1189  for (int m=0; m<8; ++m)
1190  result[m] = xyf2ring(ix+nb_xoffset[m],iy+nb_yoffset[m],face_num);
1191  else
1192  {
1193  I fpix = I(face_num)<<(2*order_),
1194  px0=spread_bits(ix ), py0=spread_bits(iy )<<1,
1195  pxp=spread_bits(ix+1), pyp=spread_bits(iy+1)<<1,
1196  pxm=spread_bits(ix-1), pym=spread_bits(iy-1)<<1;
1197 
1198  result[0] = fpix+pxm+py0; result[1] = fpix+pxm+pyp;
1199  result[2] = fpix+px0+pyp; result[3] = fpix+pxp+pyp;
1200  result[4] = fpix+pxp+py0; result[5] = fpix+pxp+pym;
1201  result[6] = fpix+px0+pym; result[7] = fpix+pxm+pym;
1202  }
1203  }
1204  else
1205  {
1206  for (int i=0; i<8; ++i)
1207  {
1208  int x=ix+nb_xoffset[i], y=iy+nb_yoffset[i];
1209  int nbnum=4;
1210  if (x<0)
1211  { x+=nside_; nbnum-=1; }
1212  else if (x>=nside_)
1213  { x-=nside_; nbnum+=1; }
1214  if (y<0)
1215  { y+=nside_; nbnum-=3; }
1216  else if (y>=nside_)
1217  { y-=nside_; nbnum+=3; }
1218 
1219  int f = nb_facearray[nbnum][face_num];
1220  if (f>=0)
1221  {
1222  int bits = nb_swaparray[nbnum][face_num>>2];
1223  if (bits&1) x=nside_-x-1;
1224  if (bits&2) y=nside_-y-1;
1225  if (bits&4) std::swap(x,y);
1226  result[i] = (scheme_==RING) ? xyf2ring(x,y,f) : xyf2nest(x,y,f);
1227  }
1228  else
1229  result[i] = -1;
1230  }
1231  }
1232  }
1233 
1234 template<typename I> void T_Healpix_Base<I>::get_interpol (const pointing &ptg,
1235  fix_arr<I,4> &pix, fix_arr<double,4> &wgt) const
1236  {
1237  planck_assert((ptg.theta>=0)&&(ptg.theta<=pi),"invalid theta value");
1238  double z = cos (ptg.theta);
1239  I ir1 = ring_above(z);
1240  I ir2 = ir1+1;
1241  double theta1, theta2, w1, tmp, dphi;
1242  I sp,nr;
1243  bool shift;
1244  I i1,i2;
1245  if (ir1>0)
1246  {
1247  get_ring_info2 (ir1, sp, nr, theta1, shift);
1248  dphi = twopi/nr;
1249  tmp = (ptg.phi/dphi - .5*shift);
1250  i1 = (tmp<0) ? I(tmp)-1 : I(tmp);
1251  w1 = (ptg.phi-(i1+.5*shift)*dphi)/dphi;
1252  i2 = i1+1;
1253  if (i1<0) i1 +=nr;
1254  if (i2>=nr) i2 -=nr;
1255  pix[0] = sp+i1; pix[1] = sp+i2;
1256  wgt[0] = 1-w1; wgt[1] = w1;
1257  }
1258  if (ir2<(4*nside_))
1259  {
1260  get_ring_info2 (ir2, sp, nr, theta2, shift);
1261  dphi = twopi/nr;
1262  tmp = (ptg.phi/dphi - .5*shift);
1263  i1 = (tmp<0) ? I(tmp)-1 : I(tmp);
1264  w1 = (ptg.phi-(i1+.5*shift)*dphi)/dphi;
1265  i2 = i1+1;
1266  if (i1<0) i1 +=nr;
1267  if (i2>=nr) i2 -=nr;
1268  pix[2] = sp+i1; pix[3] = sp+i2;
1269  wgt[2] = 1-w1; wgt[3] = w1;
1270  }
1271 
1272  if (ir1==0)
1273  {
1274  double wtheta = ptg.theta/theta2;
1275  wgt[2] *= wtheta; wgt[3] *= wtheta;
1276  double fac = (1-wtheta)*0.25;
1277  wgt[0] = fac; wgt[1] = fac; wgt[2] += fac; wgt[3] +=fac;
1278  pix[0] = (pix[2]+2)&3;
1279  pix[1] = (pix[3]+2)&3;
1280  }
1281  else if (ir2==4*nside_)
1282  {
1283  double wtheta = (ptg.theta-theta1)/(pi-theta1);
1284  wgt[0] *= (1-wtheta); wgt[1] *= (1-wtheta);
1285  double fac = wtheta*0.25;
1286  wgt[0] += fac; wgt[1] += fac; wgt[2] = fac; wgt[3] =fac;
1287  pix[2] = ((pix[0]+2)&3)+npix_-4;
1288  pix[3] = ((pix[1]+2)&3)+npix_-4;
1289  }
1290  else
1291  {
1292  double wtheta = (ptg.theta-theta1)/(theta2-theta1);
1293  wgt[0] *= (1-wtheta); wgt[1] *= (1-wtheta);
1294  wgt[2] *= wtheta; wgt[3] *= wtheta;
1295  }
1296 
1297  if (scheme_==NEST)
1298  for (tsize m=0; m<pix.size(); ++m)
1299  pix[m] = ring2nest(pix[m]);
1300  }
1301 
1302 template<typename I> void T_Healpix_Base<I>::swap (T_Healpix_Base &other)
1303  {
1304  std::swap(order_,other.order_);
1305  std::swap(nside_,other.nside_);
1306  std::swap(npface_,other.npface_);
1307  std::swap(ncap_,other.ncap_);
1308  std::swap(npix_,other.npix_);
1309  std::swap(fact1_,other.fact1_);
1310  std::swap(fact2_,other.fact2_);
1311  std::swap(scheme_,other.scheme_);
1312  }
1313 
1314 template<typename I> double T_Healpix_Base<I>::max_pixrad() const
1315  {
1316  vec3 va,vb;
1317  va.set_z_phi (2./3., pi/(4*nside_));
1318  double t1 = 1.-1./nside_;
1319  t1*=t1;
1320  vb.set_z_phi (1-t1/3, 0);
1321  return v_angle(va,vb);
1322  }
1323 
1324 template<typename I> double T_Healpix_Base<I>::max_pixrad(I ring) const
1325  {
1326  if (ring>=2*nside_) ring=4*nside_-ring;
1327  double z=ring2z(ring), z_up=ring2z(ring-1);
1328  vec3 mypos, uppos;
1329  uppos.set_z_phi(z_up,0);
1330  if (ring<=nside_)
1331  {
1332  mypos.set_z_phi(z,pi/(4*ring));
1333  double v1=v_angle(mypos,uppos);
1334  if (ring!=1) return v1;
1335  uppos.set_z_phi(ring2z(ring+1),pi/(4*(min(nside_,ring+1))));
1336  return max(v1,v_angle(mypos,uppos));
1337  }
1338  mypos.set_z_phi(z,0);
1339  double vdist=v_angle(mypos,uppos);
1340  double hdist=sqrt(1.-z*z)*pi/(4*nside_);
1341  return max(hdist,vdist);
1342  }
1343 
1344 template<typename I> void T_Healpix_Base<I>::xyf2loc (double x, double y,
1345  int face, double &z, double &phi, double &sth, bool &have_sth) const
1346  {
1347  have_sth = false;
1348  double jr = jrll[face] - x - y;
1349  double nr;
1350  if (jr<1)
1351  {
1352  nr = jr;
1353  double tmp = nr*nr/3.;
1354  z = 1 - tmp;
1355  if (z > 0.99)
1356  {
1357  sth = std::sqrt(tmp*(2.0-tmp));
1358  have_sth = true;
1359  }
1360  }
1361  else if (jr>3)
1362  {
1363  nr = 4-jr;
1364  double tmp = nr*nr/3.;
1365  z = tmp - 1;
1366  if (z<-0.99)
1367  {
1368  sth = std::sqrt(tmp*(2.-tmp));
1369  have_sth = true;
1370  }
1371  }
1372  else
1373  {
1374  nr = 1;
1375  z = (2-jr)*2./3.;
1376  }
1377 
1378  double tmp=jpll[face]*nr+x-y;
1379  if (tmp<0) tmp+=8;
1380  if (tmp>=8) tmp-=8;
1381  phi = (nr<1e-15) ? 0 : (0.5*halfpi*tmp)/nr;
1382  }
1383 
1384 namespace {
1385 
1386 vec3 locToVec3 (double z, double phi, double sth, bool have_sth)
1387  {
1388  if (have_sth)
1389  return vec3(sth*cos(phi),sth*sin(phi),z);
1390  else
1391  {
1392  vec3 res;
1393  res.set_z_phi (z, phi);
1394  return res;
1395  }
1396  }
1397 
1398 } // unnamed namespace
1399 
1400 template<typename I> void T_Healpix_Base<I>::boundaries(I pix, tsize step,
1401  vector<vec3> &out) const
1402  {
1403  out.resize(4*step);
1404  int ix, iy, face;
1405  pix2xyf(pix, ix, iy, face);
1406  double dc = 0.5 / nside_;
1407  double xc = (ix + 0.5)/nside_, yc = (iy + 0.5)/nside_;
1408  double d = 1.0/(step*nside_);
1409  for (tsize i=0; i<step; ++i)
1410  {
1411  double z, phi, sth;
1412  bool have_sth;
1413  xyf2loc(xc+dc-i*d, yc+dc, face, z, phi, sth, have_sth);
1414  out[i] = locToVec3(z, phi, sth, have_sth);
1415  xyf2loc(xc-dc, yc+dc-i*d, face, z, phi, sth, have_sth);
1416  out[i+step] = locToVec3(z, phi, sth, have_sth);
1417  xyf2loc(xc-dc+i*d, yc-dc, face, z, phi, sth, have_sth);
1418  out[i+2*step] = locToVec3(z, phi, sth, have_sth);
1419  xyf2loc(xc+dc, yc-dc+i*d, face, z, phi, sth, have_sth);
1420  out[i+3*step] = locToVec3(z, phi, sth, have_sth);
1421  }
1422  }
1423 
1424 template<typename I> arr<int> T_Healpix_Base<I>::swap_cycles() const
1425  {
1426  planck_assert(order_>=0, "need hierarchical map");
1427  planck_assert(order_<=13, "map too large");
1428  arr<int> result(swap_clen[order_]);
1429  tsize ofs=0;
1430  for (int m=0; m<order_;++m) ofs+=swap_clen[m];
1431  for (tsize m=0; m<result.size();++m) result[m]=swap_cycle[m+ofs];
1432  return result;
1433  }
1434 
1435 template class T_Healpix_Base<int>;
1436 template class T_Healpix_Base<int64>;
I nest2peano(I pix) const
void query_disc(pointing ptg, double radius, rangeset< I > &pixset) const
void get_ring_info2(I ring, I &startpix, I &ringpix, double &theta, bool &shifted) const
I nest2ring(I pix) const
Healpix_Ordering_Scheme
void query_polygon_inclusive(const std::vector< pointing > &vertex, rangeset< I > &pixset, int fact=1) const
void query_polygon(const std::vector< pointing > &vertex, rangeset< I > &pixset) const
static int nside2order(I nside)
Definition: healpix_base.cc:38
void get_interpol(const pointing &ptg, fix_arr< I, 4 > &pix, fix_arr< double, 4 > &wgt) const
void SetNside(I nside, Healpix_Ordering_Scheme scheme)
void swap(T_Healpix_Base &other)
I ring2nest(I pix) const
void Set(int order, Healpix_Ordering_Scheme scheme)
void query_strip(double theta1, double theta2, bool inclusive, rangeset< I > &pixset) const
void pix2zphi(I pix, double &z, double &phi) const
Definition: healpix_base.h:176
void boundaries(I pix, tsize step, std::vector< vec3 > &out) const
static I npix2nside(I npix)
Definition: healpix_base.cc:43
void get_ring_info(I ring, I &startpix, I &ringpix, double &costheta, double &sintheta, bool &shifted) const
double max_pixrad() const
I ring_above(double z) const
Definition: healpix_base.cc:50
void query_disc_inclusive(pointing ptg, double radius, rangeset< I > &pixset, int fact=1) const
void get_ring_info_small(I ring, I &startpix, I &ringpix, bool &shifted) const
void neighbors(I pix, fix_arr< I, 8 > &result) const
I peano2nest(I pix) const
double ring2z(I ring) const
I pix2ring(I pix) const
Healpix_Ordering_Scheme scheme_
Definition: healpix_base.h:56

Generated on Wed Nov 13 2024 12:18:30 for Healpix C++