ROOT logo
// $Id: THealPix.h,v 1.36 2009/01/12 20:51:24 oxon Exp $
// Author: Akira Okumura 2008/06/20

/*****************************************************************************
   Copyright (C) 2008-, Akira Okumura
   All rights reserved.

   This is a port of HEALPix C++ package to ROOT system.
   Original code is available at <http://healpix.jpl.nasa.gov> under GPL.
******************************************************************************/

#ifndef T_HEAL_PIX
#define T_HEAL_PIX

//////////////////////////////////////////////////////////////////////////
//                                                                      //
// THealPix                                                             //
//                                                                      //
// HEALPix-like 2D histogram base class.                                //
//                                                                      //
//////////////////////////////////////////////////////////////////////////

#include <complex>
#include <float.h>
#include <string>
#include <vector>

#include "TArrayD.h"
#include "TArrayF.h"
#include "TAttFill.h"
#include "TAttLine.h"
#include "TAttMarker.h"
#include "TAxis.h"
#include "TNamed.h"

#include <fitsio.h>

#include "THealFFT.h"

class TDirectory;
template<typename T> class THealAlm;
class TList;
class TVirtualHealPainter;

class THealPix : public TNamed, public TAttLine, public TAttFill, public TAttMarker {
protected:
  class THealTable {
  private:
    Short_t fCtab[0x100];
    Short_t fUtab[0x100];
  public:
    THealTable();
    inline Short_t C(Int_t i) const {return fCtab[i];}
    inline Short_t U(Int_t i) const {return fUtab[i];}
  };

protected:
  TAxis         fXaxis;         //X axis descriptor
  TAxis         fYaxis;         //Y axis descriptor
  TAxis         fZaxis;         //Z axis descriptor
  TList*        fFunctions;     //->Pointer to list of functions (fits and user)
  Short_t       fBarOffset;     //(1000*offset) for bar charts or legos
  Short_t       fBarWidth;      //(1000*width) for bar charts or legos
  Int_t         fOrder;         //Order of resolution
  Int_t         fNside;         //!= 2^fOrder
  Int_t         fNpix;          //!= 12*fNside^2
  Int_t         fNside2;        //!= fNside*fNside (used for faster calculation)
  Int_t         fNcap;          //!= 2*fNside*(fNside-1) (used for faster calculation)
  Double_t      f3Nside2;       //!= 3*fNside*fNside (used for faster calculation)
  Double_t      f2over3Nside;   //!= 2/(3*fNside) (used for faster calculation)
  Int_t         f4Nside;        //!= 4*fNside
  Int_t         f2Nside;        //!= 2*fNside
  Bool_t        fIsDegree;      //deg = true, rad = false
  Bool_t        fIsNested;      //RING = false, NESTED = true
  std::string   fUnit;          //Unit of data (used in FITS header)
  Double_t      fEntries;       //Number of entries
  Double_t      fMaximum;       //Maximum value for plotting
  Double_t      fMinimum;       //Minimum value for plotting
  Double_t      fNormFactor;    //Normalization factor
  TArrayD       fContour;       //Array to display contour levels
  Double_t      fTsumw;         //Total Sum of weights
  Double_t      fTsumw2;        //Total Sum of squares of weights
  TArrayD       fSumw2;         //Total Sum of squares of weights
  TString       fOption;        //histogram options
  TDirectory*   fDirectory;     //!Pointer to directory holding this HEALPixxs
  TVirtualHealPainter* fPainter;//!pointer to HEALPix painter
  static Bool_t fgAddDirectory; //!flag to add HEALPixs to the directory
  static Bool_t fgDefaultSumw2; //!flag to call THealPix::Sumw2 automatically at histogram creation time
  static THealTable fgTable;    //!ctab and utab holder
  static const Int_t fgJrll[];  //!
  static const Int_t fgJpll[];  //!

private:
  void Build();
  void FillTable();

  THealPix& operator=(const THealPix&); // Not implemented

protected:
  THealPix();
  THealPix(const char* name, const char* title, Int_t order,
	   Bool_t isNested = kFALSE);
  virtual void  Copy(TObject& hpnew) const;

public:
  // THealPix status bits
  enum {
    kNoStats     = BIT(9),  // don't draw stats box
    kUserContour = BIT(10), // user specified contour levels
    kCanRebin    = BIT(11), // can rebin axis
    kLogX        = BIT(15), // X-axis in log scale
    kIsZoomed    = BIT(16), // bit set when zooming on Y axis
    kNoTitle     = BIT(17), // don't draw the histogram title
    kIsAverage   = BIT(18)  // Bin contents are average (used by Add)
  };

  struct HealHeader_t {
    Int_t order, colnum;
    Int_t nside, npix, nrows, repeat;
    Bool_t isNested;
    char tunit[FLEN_VALUE];
    char ttype[FLEN_VALUE];
  };

  THealPix(const THealPix&);
  virtual ~THealPix();
  
  virtual void     Add(const THealPix *hp1, Double_t c1 = 1);
  virtual void     Add(const THealPix* hp1, const THealPix* hp2, Double_t c1 = 1, Double_t c2 = 1);
  virtual void     AddBinContent(Int_t bin);
  virtual void     AddBinContent(Int_t bin, Double_t w);
  static  void     AddDirectory(Bool_t add = kTRUE);
  static  Bool_t   AddDirectoryStatus();
  virtual void     Divide(const THealPix* hp1);
  virtual void     Draw(Option_t* option = "");
  virtual THealPix* DrawCopy(Option_t* option = "") const;
  virtual Int_t    Fill(Double_t theta, Double_t phi);
  virtual Int_t    Fill(Double_t theta, Double_t phi, Double_t w);
  virtual Int_t    Fill(const Double_t* x);
  virtual Int_t    Fill(const Double_t* x, Double_t w);
  virtual Int_t    Fill(const Float_t* x);
  virtual Int_t    Fill(const Float_t* x, Double_t w);
  virtual Int_t    FindBin(Double_t theta, Double_t phi) const;
  virtual Double_t GetAverage() const;
  virtual Float_t  GetBarOffset() const {return Float_t(0.001*Float_t(fBarOffset));}
  virtual Float_t  GetBarWidth() const  {return Float_t(0.001*Float_t(fBarWidth));}
  virtual Double_t GetBinArea(Bool_t degree2 = kFALSE) const;
  virtual void     GetBinCenter(Int_t bin, Double_t& theta, Double_t& phi) const;
  virtual void     GetBinCenter(Int_t bin, Double_t* theta, Double_t* phi) const;
  virtual Double_t GetBinContent(Int_t bin) const;
  virtual Double_t GetBinError(Int_t bin) const;
  virtual Int_t    GetBinVertices(Int_t bin, Double_t* x, Double_t* y) const;
  virtual Int_t    GetContour(Double_t* levels = 0);
  virtual Double_t GetContourLevel(Int_t level) const;
  virtual Double_t GetContourLevelPad(Int_t level) const;
  TDirectory*      GetDirectory() const {return fDirectory;}
  static  Bool_t   GetDefaultSumw2();
  virtual Double_t GetEntries() const;
  TList*           GetListOfFunctions() const {return fFunctions;}
  virtual Double_t GetMaximum(Double_t maxval = FLT_MAX) const;
  virtual Int_t    GetMaximumBin() const;
  virtual Double_t GetMaximumStored() const {return fMaximum;}
  virtual Double_t GetMinimum(Double_t minval = -FLT_MAX) const;
  virtual Int_t    GetMinimumBin() const;
  virtual Double_t GetMinimumStored() const {return fMinimum;}
  virtual Int_t    GetNside() const { return fNside;}
  virtual Double_t GetNormFactor() const {return fNormFactor;}
  virtual Int_t    GetNpix() const { return fNpix;}
  virtual Int_t    GetNrows() const;
  Option_t*        GetOption() const {return fOption.Data();}
  virtual Int_t    GetOrder() const { return fOrder;}
  TVirtualHealPainter* GetPainter(Option_t* option = "");
  virtual std::string GetSchemeString() const;
  virtual Double_t GetSumOfWeights() const;
  virtual TArrayD* GetSumw2() {return &fSumw2;}
          TAxis*   GetXaxis() const;
          TAxis*   GetYaxis() const;
          TAxis*   GetZaxis() const;
  virtual const TArrayD* GetSumw2() const {return &fSumw2;}
  virtual void     GetRingInfo(Int_t ring, Int_t& startpix, Int_t& ringpix, Double_t &costheta, Double_t& sintheta, Bool_t& shifted) const;
  virtual Int_t    GetSumw2N() const {return fSumw2.fN;}
  virtual Int_t    GetType() const = 0;
  virtual std::string GetTypeString() const = 0;
  virtual std::string GetUnit() const { return fUnit;}
  virtual Bool_t   IsDegree() const {return fIsDegree;}
  virtual Bool_t   IsNested() const {return fIsNested;}
  template<typename T>
          void     Map2Alm(THealAlm<T>& alm, Bool_t add = kFALSE) const;
  template<typename T>
          void     Map2Alm(THealAlm<T>& alm, const std::vector<double>& weight, Bool_t add = kFALSE) const;
  virtual void     Multiply(const THealPix* hp1);
  virtual void     Paint(Option_t* option = "");
  static  Bool_t   ReadFitsHeader(fitsfile** fptr, const char* fname,
				  const char* colname, HealHeader_t& head);
  virtual THealPix* Rebin(Int_t neworder, const char* newname = "");
  virtual void     Scale(Double_t c1 = 1, Option_t* option = "");
  virtual void     SetBarOffset(Float_t offset = 0.25) {fBarOffset = Short_t(1000*offset);}
  virtual void     SetBarWidth(Float_t width = 0.5) {fBarWidth = Short_t(1000*width);}
  virtual void     SetBinContent(Int_t bin, Double_t content);
  virtual void     SetBinError(Int_t bin, Double_t error);
  virtual void     SetBins(Int_t n);
  virtual void     SetBinsLength(Int_t = -1) {} // redefined in derived cplasses
  virtual void     SetContour(Int_t nlevels, const Double_t* levels = 0);
  virtual void     SetContourLevel(Int_t level, Double_t value);
  static  void     SetDefaultSumw2(Bool_t sumw2=kTRUE);
  virtual void     SetDegree(Bool_t isDegree = kTRUE) {fIsDegree = isDegree;}
  virtual void     SetDirectory(TDirectory *dir);
  virtual void     SetEntries(Double_t n) {fEntries = n;}
  virtual void     SetMaximum(Double_t maximum = -1111);
  virtual void     SetMinimum(Double_t minimum = -1111);
  virtual void     SetName(const char* name);
  virtual void     SetNameTitle(const char* name, const char* title);
  virtual void     SetNormFactor(Double_t factor = 1) {fNormFactor = factor;}
  virtual void     SetOption(Option_t* option = "") {fOption = option;}
  virtual void     SetOrder(Int_t order);
  virtual void     SetUnit(const char* unit);
  virtual void     SetXTitle(const char* title) {fXaxis.SetTitle(title);}
  virtual void     SetYTitle(const char* title) {fYaxis.SetTitle(title);}
  virtual void     SetZTitle(const char* title) {fZaxis.SetTitle(title);}
  virtual void     Sumw2();
  void             UseCurrentStyle();
  virtual void     Nest2XYF(Int_t pix, Int_t& x, Int_t& y, Int_t& face) const;
  virtual Int_t    XYF2Nest(Int_t x, Int_t y, Int_t face) const;
  virtual void     Ring2XYF(Int_t pix, Int_t& x, Int_t& y, Int_t& face) const;
  virtual Int_t    XYF2Ring(Int_t x, Int_t y, Int_t face) const;
  virtual Int_t    Nest2Ring(Int_t pix) const;
  virtual Int_t    Ring2Nest(Int_t pix) const;
  virtual void     Pix2XY(Int_t pix, Int_t& x, Int_t& y) const;
  virtual Int_t    XY2Pix(Int_t x, Int_t y) const;

  static  Int_t    Nside2Npix(Int_t nside) {return 12*nside*nside;}
  static  Int_t    Order2Nside(Int_t order) {return 1<<order;}

  ClassDef(THealPix, 1); // 2D HEALPix histogram
};

//______________________________________________________________________________
namespace {
  inline UInt_t Isqrt(UInt_t v);
  inline Double_t Modulo(Double_t v1, Double_t v2);
  inline Int_t Modulo(Int_t v1, Int_t v2);
  inline Long_t Modulo(Long_t v1, Long_t v2);
  void get_chunk_info (int nrings, int &nchunks, int &chunksize);
  void fill_work (const std::complex<double> *datain, int nph, int mmax,
		  bool shifted, const std::vector<std::complex<double> > &shiftarr,
		  std::vector<std::complex<double> > &work);
  void read_work (const std::vector<std::complex<double> >& work, int nph,
		  int mmax, bool shifted,
		  const std::vector<std::complex<double> > &shiftarr,
		  std::complex<double> *dataout);
  template<typename T>
  void fft_map2alm (int nph, int mmax, bool shifted, double weight,
		    THealFFT::rfft &plan, const T *mapN, const T *mapS,
		    std::complex<double> *phas_n, std::complex<double> *phas_s,
		    const std::vector<std::complex<double> > &shiftarr,
		    std::vector<std::complex<double> > &work);
  void recalc_map2alm (int nph, int mmax, THealFFT::rfft &plan,
		       std::vector<std::complex<double> > &shiftarr);
  void recalc_alm2map (int nph, int mmax, THealFFT::rfft &plan,
		       std::vector<std::complex<double> > &shiftarr);
  template<typename T>
  void fft_alm2map (int nph, int mmax, bool shifted, THealFFT::rfft &plan,
		    T *mapN, T *mapS, std::complex<double> *b_north,
		    const std::complex<double> *b_south,
		    const std::vector<std::complex<double> > &shiftarr,
		    std::vector<std::complex<double> > &work);
} // namespace

//______________________________________________________________________________
template<typename T>
void THealPix::Map2Alm(THealAlm<T>& alm, Bool_t add) const
{
  std::vector<Double_t> weight(2*fNside, 1);
  Map2Alm(alm, weight, add);
}

//______________________________________________________________________________
inline void THealPix::Nest2XYF(Int_t pix, Int_t& x, Int_t& y, Int_t& face) const
{
  // Original code is Healpix_Base::nest2xyf of HEALPix C++
  face = pix>>(2*fOrder);
  Pix2XY(pix & (fNside2 - 1), x, y);
}

//______________________________________________________________________________
inline Int_t THealPix::XYF2Nest(Int_t x, Int_t y, Int_t face) const
{
  // Original code is Healpix_Base::xyf2nest of HEALPix C++
  return (face<<(2*fOrder)) + XY2Pix(x, y);
}

//______________________________________________________________________________
inline Int_t THealPix::Nest2Ring(Int_t pix) const
{
  // Original code is Healpix_Base::nest2ring of HEALPix C++
  Int_t x, y, face;
  Nest2XYF(pix, x, y, face);
  return XYF2Ring(x, y, face);
}

//______________________________________________________________________________
inline Int_t THealPix::Ring2Nest(Int_t pix) const
{
  // Original code is Healpix_Base::ring2nest of HEALPix C++
  Int_t x, y, face;
  Ring2XYF(pix, x, y, face);
  return XYF2Nest(x, y, face);
}

//______________________________________________________________________________
inline void THealPix::Pix2XY(Int_t pix, Int_t& x, Int_t& y) const
{
  // Original code is Healpix_Base::pix2xy of HEALPix C++
  Int_t raw = (pix&0x5555) | ((pix&0x55550000)>>15);
  x = fgTable.C(raw&0xff) | (fgTable.C(raw>>8)<<4);
  raw = ((pix&0xaaaa)>>1) | ((pix&0xaaaa0000)>>16);
  y = fgTable.C(raw&0xff) | (fgTable.C(raw>>8)<<4);
}

//______________________________________________________________________________
inline Int_t THealPix::XY2Pix(Int_t x, Int_t y) const
{
  // Original code is Healpix_Base::xy2pix of HEALPix C++
  return fgTable.U(x&0xff) | (fgTable.U(x>>8)<<16) | (fgTable.U(y&0xff)<<1)
    | (fgTable.U(y>>8)<<17);
}

//______________________________________________________________________________
class THealPixF : public THealPix, public TArrayF {
public:
  THealPixF();
  THealPixF(const char* name, const char* title, Int_t order,
	    Bool_t isNested = kFALSE);
  THealPixF(const THealPixF& hpd);
  virtual ~THealPixF();
  
  virtual void       AddBinContent(Int_t bin) {++fArray[bin];}
  virtual void       AddBinContent(Int_t bin, Double_t w)
                                  {fArray[bin] += Float_t(w);}
  virtual void       Copy(TObject& newhp) const;
  virtual THealPix*  DrawCopy(Option_t* option = "") const;
  virtual Double_t   GetBinContent(Int_t bin) const;
  virtual Int_t      GetType() const;
  virtual std::string GetTypeString() const;
  static  THealPixF* ReadFits(const char* fname, const char* colname);
  virtual void       SetBinContent(Int_t bin, Double_t content);
  virtual void       SetBinsLength(Int_t n=-1);
          THealPixF& operator=(const THealPixF &hp1);
  friend  THealPixF  operator*(Double_t c1, const THealPixF &hp1);
  friend  THealPixF  operator*(const THealPixF &hp1, Double_t c1);
  friend  THealPixF  operator+(const THealPixF &hp1, const THealPixF &hp2);
  friend  THealPixF  operator-(const THealPixF &hp1, const THealPixF &hp2);
  friend  THealPixF  operator*(const THealPixF &hp1, const THealPixF &hp2);
  friend  THealPixF  operator/(const THealPixF &hp1, const THealPixF &hp2);

  // Operators for PyROOT
  virtual THealPixF  __add__(const THealPixF& hp1) const;
  virtual THealPixF  __div__(const THealPixF& hp1) const;
  virtual THealPixF  __mul__(Double_t c1) const;
  virtual THealPixF  __mul__(const THealPixF& hp1) const;
  virtual THealPixF  __rmul__(Double_t c1) const;
  virtual THealPixF  __sub__(const THealPixF& hp1) const;

  ClassDef(THealPixF, 1); // 2D HEALPix histogram (one float per channel)
};

THealPixF operator*(Double_t c1, const THealPixF &hp1);
inline
THealPixF operator*(const THealPixF &hp1, Double_t c1) {return operator*(c1, hp1);}
THealPixF operator+(const THealPixF &hp1, const THealPixF &hp2);
THealPixF operator-(const THealPixF &hp1, const THealPixF &hp2);
THealPixF operator*(const THealPixF &hp1, const THealPixF &hp2);
THealPixF operator/(const THealPixF &hp1, const THealPixF &hp2);

//______________________________________________________________________________
class THealPixD : public THealPix, public TArrayD {
public:
  THealPixD();
  THealPixD(const char* name, const char* title, Int_t order,
	    Bool_t isNested = kFALSE);
  THealPixD(const THealPixD& hpd);
  virtual ~THealPixD();
  
  virtual void       AddBinContent(Int_t bin) {++fArray[bin];}
  virtual void       AddBinContent(Int_t bin, Double_t w)
                                  {fArray[bin] += Double_t(w);}
  virtual void       Copy(TObject& newhp) const;
  virtual THealPix*  DrawCopy(Option_t* option = "") const;
  virtual Double_t   GetBinContent(Int_t bin) const;
  virtual Int_t      GetType() const;
  virtual std::string GetTypeString() const;
  static  THealPixD* ReadFits(const char* fname, const char* colname);
  virtual void       SetBinContent(Int_t bin, Double_t content);
  virtual void       SetBinsLength(Int_t n=-1);
          THealPixD& operator=(const THealPixD& hp1);
  friend  THealPixD  operator*(Double_t c1, const THealPixD& hp1);
  friend  THealPixD  operator*(const THealPixD& hp1, Double_t c1);
  friend  THealPixD  operator+(const THealPixD& hp1, const THealPixD& hp2);
  friend  THealPixD  operator-(const THealPixD& hp1, const THealPixD& hp2);
  friend  THealPixD  operator*(const THealPixD& hp1, const THealPixD& hp2);
  friend  THealPixD  operator/(const THealPixD& hp1, const THealPixD& hp2);

  // Operators for PyROOT
  virtual THealPixD  __add__(const THealPixD& hp1) const;
  virtual THealPixD  __div__(const THealPixD& hp1) const;
  virtual THealPixD  __mul__(Double_t c1) const;
  virtual THealPixD  __mul__(const THealPixD& hp1) const;
  virtual THealPixD  __rmul__(Double_t c1) const;
  virtual THealPixD  __sub__(const THealPixD& hp1) const;

  ClassDef(THealPixD, 1); // 2D HEALPix histogram (one double per channel)
};

THealPixD operator*(Double_t c1, const THealPixD& hp1);
inline
THealPixD operator*(const THealPixD& hp1, Double_t c1) {return operator*(c1, hp1);}
THealPixD operator+(const THealPixD& hp1, const THealPixD& hp2);
THealPixD operator-(const THealPixD& hp1, const THealPixD& hp2);
THealPixD operator*(const THealPixD& hp1, const THealPixD& hp2);
THealPixD operator/(const THealPixD& hp1, const THealPixD& hp2);

//______________________________________________________________________________
template<typename T>
void THealPix::Map2Alm(THealAlm<T>& alm, const std::vector<double>& weight,
		       Bool_t add) const
{
  if(fIsNested){
    // to be modified
    return;
  } // if

  if((Int_t)weight.size() < f2Nside){
    // to be modified
    return;
  } // if

  int lmax = alm.GetLmax(), mmax = alm.GetMmax();

  int nchunks, chunksize;
  get_chunk_info(f2Nside,nchunks,chunksize);

  std::complex<double> *phas_n[chunksize], *phas_s[chunksize];
  for(Int_t i = 0; i < chunksize; i++){
    phas_n[i] = new std::complex<double>[mmax+1];
    phas_s[i] = new std::complex<double>[mmax+1];
  } // i

  std::vector<double> cth(chunksize), sth(chunksize);
  double normfact = TMath::Pi()/(3*fNside2);

  if (!add) alm.SetToZero();

  for(int chunk=0; chunk<nchunks; ++chunk){
    int llim=chunk*chunksize, ulim=TMath::Min(llim+chunksize,f2Nside);
    std::vector<std::complex<double> > shiftarr(mmax+1), work(f4Nside);
    THealFFT::rfft plan;

    for (int ith=llim; ith<ulim; ++ith){
      int istart_north, istart_south, nph;
      bool shifted;
      GetRingInfo (ith+1,istart_north,nph,cth[ith-llim],sth[ith-llim],shifted);
      istart_south = fNpix - istart_north - nph;
      recalc_map2alm (nph, mmax, plan, shiftarr);
      if(GetTypeString() == "D"){
	const THealPixD* tmp = dynamic_cast<const THealPixD*>(this);
	const Double_t* p1 = &(tmp->GetArray()[istart_north]);
	const Double_t* p2 = &(tmp->GetArray()[istart_south]);
	fft_map2alm (nph, mmax, shifted, weight[ith]*normfact, plan,
		     p1, p2,	phas_n[ith-llim], phas_s[ith-llim], shiftarr, work);
      } else if(GetTypeString() == "E"){
	const THealPixF* tmp = dynamic_cast<const THealPixF*>(this);
	const Float_t* p1 = &(tmp->GetArray()[istart_north]);
	const Float_t* p2 = &(tmp->GetArray()[istart_south]);
	fft_map2alm (nph, mmax, shifted, weight[ith]*normfact, plan,
		     p1, p2,	phas_n[ith-llim], phas_s[ith-llim], shiftarr, work);
      } // if
    } // ith
    
    THealFFT::Ylmgen generator(lmax,mmax,1e-30);
    std::vector<double> Ylm;
    std::vector<std::complex<double> > alm_tmp(lmax+1);
    for (int m=0; m<=mmax; ++m)
      {
      for (int l=m; l<=lmax; ++l) alm_tmp[l] = std::complex<double>(0.,0.);
      for (int ith=0; ith<ulim-llim; ++ith)
        {
        int l;
        generator.get_Ylm(cth[ith],sth[ith],m,Ylm,l);
        if (l<=lmax)
          {
	   std::complex<double> p1 = phas_n[ith][m]+phas_s[ith][m],
                                p2 = phas_n[ith][m]-phas_s[ith][m];
          if ((l-m)&1) goto middle;
start:
          alm_tmp[l] += p1*Ylm[l];
          if (++l>lmax) goto end;
middle:
          alm_tmp[l] += p2*Ylm[l];
          if (++l<=lmax) goto start;
end:      ;
          }
        }
      std::complex<T> *palm = alm.GetMstart(m);
      for (int l=m; l<=lmax; ++l)
        { palm[l] += alm_tmp[l]; }
      }
    }

  for(Int_t i = 0; i < chunksize; i++){
    delete phas_n[i];
    delete phas_s[i];
  } // i
}

//______________________________________________________________________________
namespace {
  UInt_t Isqrt(UInt_t v)
  {
    // Calculate square root of an integer
    // Original code is isqrt of HEALPix C++
    return UInt_t(TMath::Sqrt(v + .5));
  }
  
//______________________________________________________________________________
  Double_t Modulo(Double_t v1, Double_t v2)
  {
    // Calculate modulo of two doubles
    // Original code is modulo of HEALPix C++
    return (v1 >= 0) ? ((v1 < v2) ? v1 : fmod(v1, v2)) : (fmod(v1, v2) + v2);
  }
  
//______________________________________________________________________________
  Int_t Modulo(Int_t v1, Int_t v2)
  {
    // Calculate modulo of two integers
    // Original code is modulo of HEALPix C++
    return (v1 >= 0) ? ((v1 < v2) ? v1 : (v1%v2)) : ((v1%v2) + v2);
  }
  
//______________________________________________________________________________
  Long_t Modulo(Long_t v1, Long_t v2)
  {
    // Calculate modulo of two long integers
    // Original code is modulo of HEALPix C++
    return (v1 >= 0) ? ((v1 < v2) ? v1 : (v1%v2)) : ((v1%v2) + v2);
  }

//______________________________________________________________________________
  void get_chunk_info (int nrings, int &nchunks, int &chunksize)
  {
    nchunks = nrings/TMath::Max(100,nrings/10) + 1;
    chunksize = (nrings+nchunks-1)/nchunks;
  }

//______________________________________________________________________________
  void fill_work (const std::complex<double> *datain, int nph, int mmax,
		  bool shifted, const std::vector<std::complex<double> > &shiftarr,
		  std::vector<std::complex<double> > &work)
  {
    for (int m=1; m<nph; ++m) work[m]=0;
    work[0]=datain[0];
    
    int cnt1=0, cnt2=nph;
    for(int m=1; m<=mmax; ++m){
      if (++cnt1==nph) cnt1=0;
      if (--cnt2==-1) cnt2=nph-1;
      std::complex<double> tmp = shifted ? (datain[m]*shiftarr[m]) : datain[m];
      work[cnt1] += tmp;
      work[cnt2] += conj(tmp);
    }
  }

//______________________________________________________________________________
  void read_work (const std::vector<std::complex<double> >& work, int nph,
		  int mmax, bool shifted,
		  const std::vector<std::complex<double> > &shiftarr,
		  std::complex<double> *dataout)
  {
    int cnt2=0;
    for(int m=0; m<=mmax; ++m){
      dataout[m] = work[cnt2];
      if (++cnt2==nph) cnt2=0;
    }
    if (shifted)
      for (int m=0; m<=mmax; ++m) dataout[m] *= shiftarr[m];
  }

//______________________________________________________________________________
  template<typename T>
  void fft_map2alm (int nph, int mmax, bool shifted, double weight,
		    THealFFT::rfft &plan, const T *mapN, const T *mapS,
		    std::complex<double> *phas_n, std::complex<double> *phas_s,
		    const std::vector<std::complex<double> > &shiftarr,
		    std::vector<std::complex<double> > &work)
  {
    for (int m=0; m<nph; ++m) work[m] = mapN[m]*weight;
    plan.forward_c(work);
    read_work (work, nph, mmax, shifted, shiftarr, phas_n);
    if (mapN!=mapS){
      for (int m=0; m<nph; ++m) work[m] = mapS[m]*weight;
      plan.forward_c(work);
      read_work (work, nph, mmax, shifted, shiftarr, phas_s);
    } else {
      for (int m=0; m<=mmax; ++m) phas_s[m]=0;
    } // if
  }
  
//______________________________________________________________________________
  void recalc_map2alm (int nph, int mmax, THealFFT::rfft &plan,
		       std::vector<std::complex<double> > &shiftarr)
  {
    if (plan.size() == nph) return;
    plan.Set (nph);
    double f1 = TMath::Pi()/nph;
    for (int m=0; m<=mmax; ++m){
      if (m<nph)
	shiftarr[m] = std::complex<double>(cos(m*f1),-sin(m*f1));
      else
	shiftarr[m]=-shiftarr[m-nph];
    } // m
  }

//______________________________________________________________________________
  template<typename T>
  void fft_alm2map (int nph, int mmax, bool shifted, THealFFT::rfft &plan,
		    T *mapN, T *mapS, std::complex<double> *b_north,
		    const std::complex<double> *b_south,
		    const std::vector<std::complex<double> > &shiftarr,
		    std::vector<std::complex<double> > &work)
  {
    fill_work (b_north, nph, mmax, shifted, shiftarr, work);
    plan.backward_c(work);
    for (int m=0; m<nph; ++m) mapN[m] = work[m].real();
    if (mapN==mapS) return;
    fill_work (b_south, nph, mmax, shifted, shiftarr, work);
    plan.backward_c(work);
    for (int m=0; m<nph; ++m) mapS[m] = work[m].real();
  }
}


#endif // T_HEAL_PIX
 THealPix.h:1
 THealPix.h:2
 THealPix.h:3
 THealPix.h:4
 THealPix.h:5
 THealPix.h:6
 THealPix.h:7
 THealPix.h:8
 THealPix.h:9
 THealPix.h:10
 THealPix.h:11
 THealPix.h:12
 THealPix.h:13
 THealPix.h:14
 THealPix.h:15
 THealPix.h:16
 THealPix.h:17
 THealPix.h:18
 THealPix.h:19
 THealPix.h:20
 THealPix.h:21
 THealPix.h:22
 THealPix.h:23
 THealPix.h:24
 THealPix.h:25
 THealPix.h:26
 THealPix.h:27
 THealPix.h:28
 THealPix.h:29
 THealPix.h:30
 THealPix.h:31
 THealPix.h:32
 THealPix.h:33
 THealPix.h:34
 THealPix.h:35
 THealPix.h:36
 THealPix.h:37
 THealPix.h:38
 THealPix.h:39
 THealPix.h:40
 THealPix.h:41
 THealPix.h:42
 THealPix.h:43
 THealPix.h:44
 THealPix.h:45
 THealPix.h:46
 THealPix.h:47
 THealPix.h:48
 THealPix.h:49
 THealPix.h:50
 THealPix.h:51
 THealPix.h:52
 THealPix.h:53
 THealPix.h:54
 THealPix.h:55
 THealPix.h:56
 THealPix.h:57
 THealPix.h:58
 THealPix.h:59
 THealPix.h:60
 THealPix.h:61
 THealPix.h:62
 THealPix.h:63
 THealPix.h:64
 THealPix.h:65
 THealPix.h:66
 THealPix.h:67
 THealPix.h:68
 THealPix.h:69
 THealPix.h:70
 THealPix.h:71
 THealPix.h:72
 THealPix.h:73
 THealPix.h:74
 THealPix.h:75
 THealPix.h:76
 THealPix.h:77
 THealPix.h:78
 THealPix.h:79
 THealPix.h:80
 THealPix.h:81
 THealPix.h:82
 THealPix.h:83
 THealPix.h:84
 THealPix.h:85
 THealPix.h:86
 THealPix.h:87
 THealPix.h:88
 THealPix.h:89
 THealPix.h:90
 THealPix.h:91
 THealPix.h:92
 THealPix.h:93
 THealPix.h:94
 THealPix.h:95
 THealPix.h:96
 THealPix.h:97
 THealPix.h:98
 THealPix.h:99
 THealPix.h:100
 THealPix.h:101
 THealPix.h:102
 THealPix.h:103
 THealPix.h:104
 THealPix.h:105
 THealPix.h:106
 THealPix.h:107
 THealPix.h:108
 THealPix.h:109
 THealPix.h:110
 THealPix.h:111
 THealPix.h:112
 THealPix.h:113
 THealPix.h:114
 THealPix.h:115
 THealPix.h:116
 THealPix.h:117
 THealPix.h:118
 THealPix.h:119
 THealPix.h:120
 THealPix.h:121
 THealPix.h:122
 THealPix.h:123
 THealPix.h:124
 THealPix.h:125
 THealPix.h:126
 THealPix.h:127
 THealPix.h:128
 THealPix.h:129
 THealPix.h:130
 THealPix.h:131
 THealPix.h:132
 THealPix.h:133
 THealPix.h:134
 THealPix.h:135
 THealPix.h:136
 THealPix.h:137
 THealPix.h:138
 THealPix.h:139
 THealPix.h:140
 THealPix.h:141
 THealPix.h:142
 THealPix.h:143
 THealPix.h:144
 THealPix.h:145
 THealPix.h:146
 THealPix.h:147
 THealPix.h:148
 THealPix.h:149
 THealPix.h:150
 THealPix.h:151
 THealPix.h:152
 THealPix.h:153
 THealPix.h:154
 THealPix.h:155
 THealPix.h:156
 THealPix.h:157
 THealPix.h:158
 THealPix.h:159
 THealPix.h:160
 THealPix.h:161
 THealPix.h:162
 THealPix.h:163
 THealPix.h:164
 THealPix.h:165
 THealPix.h:166
 THealPix.h:167
 THealPix.h:168
 THealPix.h:169
 THealPix.h:170
 THealPix.h:171
 THealPix.h:172
 THealPix.h:173
 THealPix.h:174
 THealPix.h:175
 THealPix.h:176
 THealPix.h:177
 THealPix.h:178
 THealPix.h:179
 THealPix.h:180
 THealPix.h:181
 THealPix.h:182
 THealPix.h:183
 THealPix.h:184
 THealPix.h:185
 THealPix.h:186
 THealPix.h:187
 THealPix.h:188
 THealPix.h:189
 THealPix.h:190
 THealPix.h:191
 THealPix.h:192
 THealPix.h:193
 THealPix.h:194
 THealPix.h:195
 THealPix.h:196
 THealPix.h:197
 THealPix.h:198
 THealPix.h:199
 THealPix.h:200
 THealPix.h:201
 THealPix.h:202
 THealPix.h:203
 THealPix.h:204
 THealPix.h:205
 THealPix.h:206
 THealPix.h:207
 THealPix.h:208
 THealPix.h:209
 THealPix.h:210
 THealPix.h:211
 THealPix.h:212
 THealPix.h:213
 THealPix.h:214
 THealPix.h:215
 THealPix.h:216
 THealPix.h:217
 THealPix.h:218
 THealPix.h:219
 THealPix.h:220
 THealPix.h:221
 THealPix.h:222
 THealPix.h:223
 THealPix.h:224
 THealPix.h:225
 THealPix.h:226
 THealPix.h:227
 THealPix.h:228
 THealPix.h:229
 THealPix.h:230
 THealPix.h:231
 THealPix.h:232
 THealPix.h:233
 THealPix.h:234
 THealPix.h:235
 THealPix.h:236
 THealPix.h:237
 THealPix.h:238
 THealPix.h:239
 THealPix.h:240
 THealPix.h:241
 THealPix.h:242
 THealPix.h:243
 THealPix.h:244
 THealPix.h:245
 THealPix.h:246
 THealPix.h:247
 THealPix.h:248
 THealPix.h:249
 THealPix.h:250
 THealPix.h:251
 THealPix.h:252
 THealPix.h:253
 THealPix.h:254
 THealPix.h:255
 THealPix.h:256
 THealPix.h:257
 THealPix.h:258
 THealPix.h:259
 THealPix.h:260
 THealPix.h:261
 THealPix.h:262
 THealPix.h:263
 THealPix.h:264
 THealPix.h:265
 THealPix.h:266
 THealPix.h:267
 THealPix.h:268
 THealPix.h:269
 THealPix.h:270
 THealPix.h:271
 THealPix.h:272
 THealPix.h:273
 THealPix.h:274
 THealPix.h:275
 THealPix.h:276
 THealPix.h:277
 THealPix.h:278
 THealPix.h:279
 THealPix.h:280
 THealPix.h:281
 THealPix.h:282
 THealPix.h:283
 THealPix.h:284
 THealPix.h:285
 THealPix.h:286
 THealPix.h:287
 THealPix.h:288
 THealPix.h:289
 THealPix.h:290
 THealPix.h:291
 THealPix.h:292
 THealPix.h:293
 THealPix.h:294
 THealPix.h:295
 THealPix.h:296
 THealPix.h:297
 THealPix.h:298
 THealPix.h:299
 THealPix.h:300
 THealPix.h:301
 THealPix.h:302
 THealPix.h:303
 THealPix.h:304
 THealPix.h:305
 THealPix.h:306
 THealPix.h:307
 THealPix.h:308
 THealPix.h:309
 THealPix.h:310
 THealPix.h:311
 THealPix.h:312
 THealPix.h:313
 THealPix.h:314
 THealPix.h:315
 THealPix.h:316
 THealPix.h:317
 THealPix.h:318
 THealPix.h:319
 THealPix.h:320
 THealPix.h:321
 THealPix.h:322
 THealPix.h:323
 THealPix.h:324
 THealPix.h:325
 THealPix.h:326
 THealPix.h:327
 THealPix.h:328
 THealPix.h:329
 THealPix.h:330
 THealPix.h:331
 THealPix.h:332
 THealPix.h:333
 THealPix.h:334
 THealPix.h:335
 THealPix.h:336
 THealPix.h:337
 THealPix.h:338
 THealPix.h:339
 THealPix.h:340
 THealPix.h:341
 THealPix.h:342
 THealPix.h:343
 THealPix.h:344
 THealPix.h:345
 THealPix.h:346
 THealPix.h:347
 THealPix.h:348
 THealPix.h:349
 THealPix.h:350
 THealPix.h:351
 THealPix.h:352
 THealPix.h:353
 THealPix.h:354
 THealPix.h:355
 THealPix.h:356
 THealPix.h:357
 THealPix.h:358
 THealPix.h:359
 THealPix.h:360
 THealPix.h:361
 THealPix.h:362
 THealPix.h:363
 THealPix.h:364
 THealPix.h:365
 THealPix.h:366
 THealPix.h:367
 THealPix.h:368
 THealPix.h:369
 THealPix.h:370
 THealPix.h:371
 THealPix.h:372
 THealPix.h:373
 THealPix.h:374
 THealPix.h:375
 THealPix.h:376
 THealPix.h:377
 THealPix.h:378
 THealPix.h:379
 THealPix.h:380
 THealPix.h:381
 THealPix.h:382
 THealPix.h:383
 THealPix.h:384
 THealPix.h:385
 THealPix.h:386
 THealPix.h:387
 THealPix.h:388
 THealPix.h:389
 THealPix.h:390
 THealPix.h:391
 THealPix.h:392
 THealPix.h:393
 THealPix.h:394
 THealPix.h:395
 THealPix.h:396
 THealPix.h:397
 THealPix.h:398
 THealPix.h:399
 THealPix.h:400
 THealPix.h:401
 THealPix.h:402
 THealPix.h:403
 THealPix.h:404
 THealPix.h:405
 THealPix.h:406
 THealPix.h:407
 THealPix.h:408
 THealPix.h:409
 THealPix.h:410
 THealPix.h:411
 THealPix.h:412
 THealPix.h:413
 THealPix.h:414
 THealPix.h:415
 THealPix.h:416
 THealPix.h:417
 THealPix.h:418
 THealPix.h:419
 THealPix.h:420
 THealPix.h:421
 THealPix.h:422
 THealPix.h:423
 THealPix.h:424
 THealPix.h:425
 THealPix.h:426
 THealPix.h:427
 THealPix.h:428
 THealPix.h:429
 THealPix.h:430
 THealPix.h:431
 THealPix.h:432
 THealPix.h:433
 THealPix.h:434
 THealPix.h:435
 THealPix.h:436
 THealPix.h:437
 THealPix.h:438
 THealPix.h:439
 THealPix.h:440
 THealPix.h:441
 THealPix.h:442
 THealPix.h:443
 THealPix.h:444
 THealPix.h:445
 THealPix.h:446
 THealPix.h:447
 THealPix.h:448
 THealPix.h:449
 THealPix.h:450
 THealPix.h:451
 THealPix.h:452
 THealPix.h:453
 THealPix.h:454
 THealPix.h:455
 THealPix.h:456
 THealPix.h:457
 THealPix.h:458
 THealPix.h:459
 THealPix.h:460
 THealPix.h:461
 THealPix.h:462
 THealPix.h:463
 THealPix.h:464
 THealPix.h:465
 THealPix.h:466
 THealPix.h:467
 THealPix.h:468
 THealPix.h:469
 THealPix.h:470
 THealPix.h:471
 THealPix.h:472
 THealPix.h:473
 THealPix.h:474
 THealPix.h:475
 THealPix.h:476
 THealPix.h:477
 THealPix.h:478
 THealPix.h:479
 THealPix.h:480
 THealPix.h:481
 THealPix.h:482
 THealPix.h:483
 THealPix.h:484
 THealPix.h:485
 THealPix.h:486
 THealPix.h:487
 THealPix.h:488
 THealPix.h:489
 THealPix.h:490
 THealPix.h:491
 THealPix.h:492
 THealPix.h:493
 THealPix.h:494
 THealPix.h:495
 THealPix.h:496
 THealPix.h:497
 THealPix.h:498
 THealPix.h:499
 THealPix.h:500
 THealPix.h:501
 THealPix.h:502
 THealPix.h:503
 THealPix.h:504
 THealPix.h:505
 THealPix.h:506
 THealPix.h:507
 THealPix.h:508
 THealPix.h:509
 THealPix.h:510
 THealPix.h:511
 THealPix.h:512
 THealPix.h:513
 THealPix.h:514
 THealPix.h:515
 THealPix.h:516
 THealPix.h:517
 THealPix.h:518
 THealPix.h:519
 THealPix.h:520
 THealPix.h:521
 THealPix.h:522
 THealPix.h:523
 THealPix.h:524
 THealPix.h:525
 THealPix.h:526
 THealPix.h:527
 THealPix.h:528
 THealPix.h:529
 THealPix.h:530
 THealPix.h:531
 THealPix.h:532
 THealPix.h:533
 THealPix.h:534
 THealPix.h:535
 THealPix.h:536
 THealPix.h:537
 THealPix.h:538
 THealPix.h:539
 THealPix.h:540
 THealPix.h:541
 THealPix.h:542
 THealPix.h:543
 THealPix.h:544
 THealPix.h:545
 THealPix.h:546
 THealPix.h:547
 THealPix.h:548
 THealPix.h:549
 THealPix.h:550
 THealPix.h:551
 THealPix.h:552
 THealPix.h:553
 THealPix.h:554
 THealPix.h:555
 THealPix.h:556
 THealPix.h:557
 THealPix.h:558
 THealPix.h:559
 THealPix.h:560
 THealPix.h:561
 THealPix.h:562
 THealPix.h:563
 THealPix.h:564
 THealPix.h:565
 THealPix.h:566
 THealPix.h:567
 THealPix.h:568
 THealPix.h:569
 THealPix.h:570
 THealPix.h:571
 THealPix.h:572
 THealPix.h:573
 THealPix.h:574
 THealPix.h:575
 THealPix.h:576
 THealPix.h:577
 THealPix.h:578
 THealPix.h:579
 THealPix.h:580
 THealPix.h:581
 THealPix.h:582
 THealPix.h:583
 THealPix.h:584
 THealPix.h:585
 THealPix.h:586
 THealPix.h:587
 THealPix.h:588
 THealPix.h:589
 THealPix.h:590
 THealPix.h:591
 THealPix.h:592
 THealPix.h:593
 THealPix.h:594
 THealPix.h:595
 THealPix.h:596
 THealPix.h:597
 THealPix.h:598
 THealPix.h:599
 THealPix.h:600
 THealPix.h:601
 THealPix.h:602
 THealPix.h:603
 THealPix.h:604
 THealPix.h:605
 THealPix.h:606
 THealPix.h:607
 THealPix.h:608
 THealPix.h:609
 THealPix.h:610
 THealPix.h:611
 THealPix.h:612
 THealPix.h:613
 THealPix.h:614
 THealPix.h:615
 THealPix.h:616
 THealPix.h:617
 THealPix.h:618
 THealPix.h:619
 THealPix.h:620
 THealPix.h:621
 THealPix.h:622
 THealPix.h:623
 THealPix.h:624
 THealPix.h:625
 THealPix.h:626
 THealPix.h:627
 THealPix.h:628
 THealPix.h:629
 THealPix.h:630
 THealPix.h:631
 THealPix.h:632
 THealPix.h:633
 THealPix.h:634
 THealPix.h:635
 THealPix.h:636
 THealPix.h:637
 THealPix.h:638
 THealPix.h:639
 THealPix.h:640
 THealPix.h:641
 THealPix.h:642