#include "sopnamsp.h" #include "machdefs.h" #include #include #include "pexceptions.h" #include "fiondblock.h" #include "spherehealpix.h" #include "strutil.h" extern "C" { #include #include #include } using namespace SOPHYA; /*! \class SOPHYA::SphereHEALPix \ingroup SkyMap \brief Spherical maps in HEALPix pixelisation scheme. Class implementing spherical maps, in the HEALPix pixelisation scheme, with template data types (double, float, complex, ...) \verbatim Adapted from : ----------------------------------------------------------------------- version 0.8.2 Aug97 TAC Eric Hivon, Kris Gorski ----------------------------------------------------------------------- the sphere is split in 12 diamond-faces containing nside**2 pixels each the numbering of the pixels (in the nested scheme) is similar to quad-cube In each face the first pixel is in the lowest corner of the diamond the faces are (x,y) coordinate on each face . . . . <--- North Pole / \ / \ / \ / \ ^ ^ . 0 . 1 . 2 . 3 . <--- z = 2/3 \ / \ / \ / \ / \ / y \ / x 4 . 5 . 6 . 7 . 4 <--- equator \ / / \ / \ / \ / \ \/ . 8 . 9 .10 .11 . <--- z = -2/3 (0,0) : lowest corner \ / \ / \ / \ / . . . . <--- South Pole \endverbatim phi:0 2Pi in the ring scheme pixels are numbered along the parallels the first parallel is the one closest to the north pole and so on on each parallel, pixels are numbered starting from the one closest to phi = 0 nside MUST be a power of 2 (<= 8192) */ /* --Methode-- */ //! Default constructor - optional pixelisation scheme parameter template SphereHEALPix::SphereHEALPix(bool fgring) : fgring_(fgring), pixels_(), sliceBeginIndex_(), sliceLenght_() { InitNul(); } /*! \brief Constructor with specification of nside and optional pixelisation scheme \param : "nside" of the Healpix algorithm \param : if true -> RING pixelisation (default), if not NESTED The total number of pixels will be Npix = 12*nside**2 nside MUST be a power of 2 (<= 8192) */ template SphereHEALPix::SphereHEALPix(int_4 m, bool fgring) { fgring_ = fgring; InitNul(); Pixelize(m); SetThetaSlices(); } //! Copy constructor template SphereHEALPix::SphereHEALPix(const SphereHEALPix& s, bool share) : pixels_(s.pixels_, share), sliceBeginIndex_(s.sliceBeginIndex_, share), sliceLenght_(s.sliceLenght_, share) //-- { nSide_= s.nSide_; nPix_ = s.nPix_; omeg_ = s.omeg_; fgring_ = s.fgring_; if(s.mInfo_) this->mInfo_= new DVList(*s.mInfo_); } //++ template SphereHEALPix::SphereHEALPix(const SphereHEALPix& s) : pixels_(s.pixels_), sliceBeginIndex_(s.sliceBeginIndex_), sliceLenght_(s.sliceLenght_) // copy constructor //-- { nSide_= s.nSide_; nPix_ = s.nPix_; omeg_ = s.omeg_; fgring_ = s.fgring_; if(s.mInfo_) this->mInfo_= new DVList(*s.mInfo_); // CloneOrShare(s); } //! Clone if \b a is not temporary, share if temporary /*! \sa NDataBlock::CloneOrShare(const NDataBlock&) */ template void SphereHEALPix::CloneOrShare(const SphereHEALPix& a) { nSide_= a.nSide_; nPix_ = a.nPix_; omeg_ = a.omeg_; fgring_ = a.fgring_; pixels_.CloneOrShare(a.pixels_); sliceBeginIndex_.CloneOrShare(a.sliceBeginIndex_); sliceLenght_.CloneOrShare(a.sliceLenght_); if (this->mInfo_) {delete this->mInfo_; this->mInfo_ = NULL;} if (a.mInfo_) this->mInfo_ = new DVList(*(a.mInfo_)); } //! Share data with a template void SphereHEALPix::Share(const SphereHEALPix& a) { nSide_= a.nSide_; nPix_ = a.nPix_; omeg_ = a.omeg_; fgring_ = a.fgring_; pixels_.Share(a.pixels_); sliceBeginIndex_.Share(a.sliceBeginIndex_); sliceLenght_.Share(a.sliceLenght_); if (this->mInfo_) {delete this->mInfo_; this->mInfo_ = NULL;} if (a.mInfo_) this->mInfo_ = new DVList(*(a.mInfo_)); } ////////////////////////// methodes de copie/share template SphereHEALPix& SphereHEALPix::Set(const SphereHEALPix& a) { if (this != &a) { if (a.NbPixels() < 1) throw RangeCheckError("SphereHEALPix::Set(a ) - SphereHEALPix a not allocated ! "); if (NbPixels() < 1) CloneOrShare(a); else CopyElt(a); if (this->mInfo_) delete this->mInfo_; this->mInfo_ = NULL; if (a.mInfo_) this->mInfo_ = new DVList(*(a.mInfo_)); } return(*this); } template SphereHEALPix& SphereHEALPix::CopyElt(const SphereHEALPix& a) { if (NbPixels() < 1) throw RangeCheckError("SphereHEALPix::CopyElt(a) - Not Allocated SphereHEALPix ! "); if (NbPixels() != a.NbPixels()) throw(SzMismatchError("SphereHEALPix::CopyElt(a) SizeMismatch")) ; nSide_= a.nSide_; nPix_ = a.nPix_; omeg_ = a.omeg_; if (fgring_ == a.fgring_) for (int_4 k=0; k< nPix_; k++) pixels_(k) = a.pixels_(k); else { if (fgring_) for (int_4 k=0; k< nPix_; k++) pixels_(k) = a.pixels_(ring2nest(nSide_, k)); else for (int_4 k=0; k< nPix_; k++) pixels_(k) = a.pixels_(nest2ring(nSide_, k)); } for (size_t k=0; k< a.sliceBeginIndex_.Size(); k++) sliceBeginIndex_(k) = a.sliceBeginIndex_(k); for (size_t k=0; k< a.sliceLenght_.Size(); k++) sliceLenght_(k) = a.sliceLenght_(k); return(*this); } template SphereHEALPix::~SphereHEALPix() { } /*! \fn void SOPHYA::SphereHEALPix::Resize(int_4 m) \param "nside" of the HEALPix algorithm The total number of pixels will be Npix = 12*nside**2 nside MUST be a power of 2 (<= 8192) */ template void SphereHEALPix::Resize(int_4 m) { if ((m <= 0 && nSide_ > 0)) { cout << "SphereHEALPix::Resize(m) with m<=0, NOT resized" << endl; return; } InitNul(); Pixelize(m); SetThetaSlices(); } //! return type of the map pixelisation : RING or NESTED template string SphereHEALPix::TypeOfMap() const { if (fgring_) return string("RING"); else return string("NESTED"); } template void SphereHEALPix::Pixelize( int_4 m) // prépare la pixelisation Gorski (m a la même signification // que pour le constructeur) { if (m<=0 || m> 8192) { cout << "SphereHEALPix::Pixelize() m=" << m <<" out of range [0,8192]" << endl; throw ParmError("SphereHEALPix::Pixelize() m out of range"); } // verifier que m est une puissance de deux int x= m; while (x%2==0) x/=2; if(x != 1) { cout << "SphereHEALPix::Pixelize() m=" << m << " != 2^n " << endl; throw ParmError("SphereHEALPix::Pixelize() m!=2^n"); } // On memorise les arguments d'appel nSide_= m; // Nombre total de pixels sur la sphere entiere nPix_= 12*nSide_*nSide_; // pour le moment les tableaux qui suivent seront ranges dans l'ordre // de l'indexation GORSKY "RING" // on pourra ulterieurement changer de strategie et tirer profit // de la dualite d'indexation GORSKY (RING et NEST) : tout dependra // de pourquoi c'est faire // Creation et initialisation du vecteur des contenus des pixels pixels_.ReSize(nPix_); pixels_.Reset(); // solid angle per pixel omeg_= 4.0*Pi/nPix_; } template void SphereHEALPix::InitNul() // // initialise à zéro les variables de classe { nSide_= 0; nPix_ = 0; omeg_ = 0.; // pixels_.Reset(); - Il ne faut pas mettre les pixels a zero si share ! } /* --Methode-- */ /* Nombre de pixels du decoupage */ /*! \fn int_4 SOPHYA::SphereHEALPix::NbPixels() const Return number of pixels of the splitting */ template int_4 SphereHEALPix::NbPixels() const { return(nPix_); } /*! \fn uint_4 SOPHYA::SphereHEALPix::NbThetaSlices() const \return number of slices in theta direction on the sphere */ template uint_4 SphereHEALPix::NbThetaSlices() const { uint_4 nbslices = uint_4(4*nSide_-1); if (nSide_<=0) { nbslices = 0; throw PException(" sphere not pixelized, NbSlice=0 "); } return nbslices; } //! Return the theta angle for slice defined by \b index template r_8 SphereHEALPix::ThetaOfSlice(int_4 index) const { uint_4 nbslices = uint_4(4*nSide_-1); if (index<0 || index >= (int_4)nbslices) throw RangeCheckError(" SphereHEALPix::ThetaOfSlice() index out of range"); r_8 theta, phi0; PixThetaPhi(sliceBeginIndex_(index), theta, phi0); return theta; } //! Return true : All theta slices have a symmetric slice at Pi-Theta in SphereHEALPix template bool SphereHEALPix::HasSymThetaSlice() const { return true; } //! Return the slice index for the symmetric slice at theta=Pi-ThetaOfSlice(idx) template int_4 SphereHEALPix::GetSymThetaSliceIndex(int_4 idx) const { if(idx < 0 || idx >= (int_4)NbThetaSlices()) throw RangeCheckError("SphereHEALPix::GetSymThetaSliceIndex index out of range"); return (NbThetaSlices()-1-idx); } /*! \fn void SOPHYA::SphereHEALPix::GetThetaSlice(int_4 index,r_8& theta,TVector& phi,TVector& value) const For a theta-slice with index 'index', return : the corresponding "theta" a vector containing the phi's of the pixels of the slice a vector containing the corresponding values of pixels */ template void SphereHEALPix::GetThetaSlice(int_4 index,r_8& theta,TVector& phi,TVector& value) const { if (index<0 || index >= (int_4)NbThetaSlices()) throw RangeCheckError(" SphereHEALPix::GetThetaSlice() index out of range"); int_4 iring= sliceBeginIndex_(index); int_4 lring = sliceLenght_(index); phi.ReSize(lring); value.ReSize(lring); double TH= 0.; double FI= 0.; if (fgring_) { // RING pixelisation scheme for(int_4 kk = 0; kk < lring;kk++) { PixThetaPhi(kk+iring,TH,FI); phi(kk)= FI; value(kk)= pixels_(kk+iring); } PixThetaPhi(iring, theta, FI); } else { // NESTED pixelisation scheme for(int_4 kk = 0; kk < lring;kk++) { int kkn = ring2nest(nSide_, kk+iring); PixThetaPhi(kkn,TH,FI); phi(kk)= FI; value(kk)= pixels_(kkn); } PixThetaPhi(ring2nest(nSide_,iring), theta, FI); } // theta= TH; } /*! \fn void SOPHYA::SphereHEALPix::GetThetaSlice(int_4 sliceIndex,r_8& theta, r_8& phi0, TVector& pixelIndices,TVector& value) const For a theta-slice with index 'index', return : the corresponding "theta" the corresponding "phi" for first pixel of the slice a vector containing indices of the pixels of the slice (equally distributed in phi) a vector containing the corresponding values of pixels */ template void SphereHEALPix::GetThetaSlice(int_4 sliceIndex,r_8& theta, r_8& phi0, TVector& pixelIndices,TVector& value) const { if (sliceIndex<0 || sliceIndex >= (int_4)NbThetaSlices()) throw RangeCheckError(" SphereHEALPix::GetThetaSlice() index out of range"); int_4 iring= sliceBeginIndex_(sliceIndex); int_4 lring = sliceLenght_(sliceIndex); pixelIndices.ReSize(lring); value.ReSize(lring); if (fgring_) { // RING pixelisation scheme for(int_4 kk = 0; kk < lring;kk++) { pixelIndices(kk)= kk+iring; value(kk)= pixels_(kk+iring); } PixThetaPhi(iring, theta, phi0); } else { // NESTED pixelisation scheme for(int_4 kk = 0; kk < lring;kk++) { int_4 kkn = ring2nest(nSide_, kk+iring); pixelIndices(kk)= kkn; value(kk)= pixels_(kkn); } PixThetaPhi(ring2nest(nSide_,iring), theta, phi0); } } //! return a pointer to the specified slice pixel data in RING ordering, NULL in NESTED template T* SphereHEALPix::GetThetaSliceDataPtr(int_4 sliceIndex) { if (sliceIndex<0 || sliceIndex >= (int_4)NbThetaSlices()) throw RangeCheckError(" SphereHEALPix::GetThetaSliceDataPtr(): index out of range"); if (fgring_) return pixels_.Begin()+sliceBeginIndex_(sliceIndex); else return NULL; } template void SphereHEALPix::SetThetaSlices() { sliceBeginIndex_.ReSize(4*nSide_-1); sliceLenght_.ReSize(4*nSide_-1); int_4 sliceIndex; int_4 offp = 0; for (sliceIndex=0; sliceIndex< nSide_-1; sliceIndex++) { // sliceBeginIndex_(sliceIndex) = 2*sliceIndex*(sliceIndex+1); sliceBeginIndex_(sliceIndex) = offp; sliceLenght_(sliceIndex) = 4*(sliceIndex+1); offp += sliceLenght_(sliceIndex); } for (sliceIndex= nSide_-1; sliceIndex< 3*nSide_; sliceIndex++) { // sliceBeginIndex_(sliceIndex) = 2*nSide_*(2*sliceIndex-nSide_+1); sliceBeginIndex_(sliceIndex) = offp; sliceLenght_(sliceIndex) = 4*nSide_; offp += sliceLenght_(sliceIndex); } for (sliceIndex= 3*nSide_; sliceIndex< 4*nSide_-1; sliceIndex++) { int_4 nc= 4*nSide_-1-sliceIndex; // sliceBeginIndex_(sliceIndex) = nPix_-2*nc*(nc+1); sliceBeginIndex_(sliceIndex) = offp; sliceLenght_(sliceIndex) = 4*nc; offp += sliceLenght_(sliceIndex); } } //! \return value of the \b k th pixel template T& SphereHEALPix::PixVal(int_4 k) { if((k < 0) || (k >= nPix_)) throw RangeCheckError("SphereHEALPix::PixVal() Pixel index out of range"); return pixels_(k); } //! \return value of the \b k th pixel template T const& SphereHEALPix::PixVal(int_4 k) const { if((k < 0) || (k >= nPix_)) throw RangeCheckError("SphereHEALPix::PIxVal Pixel index out of range"); return *(pixels_.Data()+k); } /*! \fn bool SOPHYA::SphereHEALPix::ContainsSph(double theta, double phi) const \return true if teta,phi in map */ template bool SphereHEALPix::ContainsSph(double theta, double phi) const { return(true); } /*! \fn int_4 SOPHYA::SphereHEALPix::PixIndexSph(double theta,double phi) const \return "RING" index of the pixel corresponding to direction (theta, phi). */ template int_4 SphereHEALPix::PixIndexSph(double theta,double phi) const { if (fgring_) return ang2pix_ring(nSide_,theta,phi); else return ang2pix_nest(nSide_,theta,phi); } //! \return (theta,phi) coordinates of middle of pixel with "RING" index k template void SphereHEALPix::PixThetaPhi(int_4 k,double& theta,double& phi) const { if (fgring_) pix2ang_ring(nSide_,k,theta,phi); else pix2ang_nest(nSide_,k,theta,phi); } //! Set all pixels to value v template T SphereHEALPix::SetPixels(T v) { pixels_.Reset(v); return(v); } //! Conversion from NESTED index into RING index template int_4 SphereHEALPix::NestToRing(int_4 k) const { return nest2ring(nSide_,k); } //! Conversion from RING index into NESTED index template int_4 SphereHEALPix::RingToNest(int_4 k) const { return ring2nest(nSide_,k); } // ...... Operations de calcul ...... //! Fill a SphereHEALPix with a constant value \b a template SphereHEALPix& SphereHEALPix::SetT(T a) { if (NbPixels() < 1) throw RangeCheckError("SphereHEALPix::SetT(T ) - SphereHEALPix not dimensionned ! "); pixels_ = a; return (*this); } //! Add a constant value \b x to a SphereHEALPix template SphereHEALPix& SphereHEALPix::Add(T a) { cout << " c'est mon Add " << endl; if (NbPixels() < 1) throw RangeCheckError("SphereHEALPix::Add(T ) - SphereHEALPix not dimensionned ! "); // pixels_ += a; pixels_.Add(a); return (*this); } /*! Substract a constant value \b a to a SphereHEALPix */ template SphereHEALPix& SphereHEALPix::Sub(T a,bool fginv) { if (NbPixels() < 1) throw RangeCheckError("SphereHEALPix::Sub(T ) - SphereHEALPix not dimensionned ! "); pixels_.Sub(a,fginv); return (*this); } /*! multiply a SphereHEALPix by a constant value \b a */ template SphereHEALPix& SphereHEALPix::Mul(T a) { if (NbPixels() < 1) throw RangeCheckError("SphereHEALPix::Mul(T ) - SphereHEALPix not dimensionned ! "); pixels_ *= a; return (*this); } /*! divide a SphereHEALPix by a constant value \b a */ template SphereHEALPix& SphereHEALPix::Div(T a) { if (NbPixels() < 1) throw RangeCheckError("SphereHEALPix::Div(T ) - SphereHEALPix not dimensionned ! "); pixels_ /= a; return (*this); } // >>>> Operations avec 2nd membre de type SphereHEALPix //! Add two SphereHEALPix template SphereHEALPix& SphereHEALPix::AddElt(const SphereHEALPix& a) { if (NbPixels() != a.NbPixels() ) throw(SzMismatchError("SphereHEALPix::AddElt(a) SizeMismatch")) ; if (fgring_ != a.fgring_) throw(ParmError("SphereHEALPix::AddElt(a) different pixelisation RING<>NESTED")) ; pixels_ += a.pixels_; return (*this); } //! Substract two SphereHEALPix template SphereHEALPix& SphereHEALPix::SubElt(const SphereHEALPix& a) { if (NbPixels() != a.NbPixels() ) throw(SzMismatchError("SphereHEALPix::SubElt(a) SizeMismatch")) ; if (fgring_ != a.fgring_) throw(ParmError("SphereHEALPix::SubElt(a) different pixelisation RING<>NESTED")) ; pixels_ -= a.pixels_; return (*this); } //! Multiply two SphereHEALPix (elements by elements) template SphereHEALPix& SphereHEALPix::MulElt(const SphereHEALPix& a) { if (NbPixels() != a.NbPixels() ) throw(SzMismatchError("SphereHEALPix::MulElt(a) SizeMismatch")) ; if (fgring_ != a.fgring_) throw(ParmError("SphereHEALPix::MulElt(a) different pixelisation RING<>NESTED")) ; pixels_ *= a.pixels_; return (*this); } //! Divide two SphereHEALPix (elements by elements) - No protection for divide by 0 template SphereHEALPix& SphereHEALPix::DivElt(const SphereHEALPix& a) { if (NbPixels() != a.NbPixels() ) throw(SzMismatchError("SphereHEALPix::DivElt(a) SizeMismatch")) ; if (fgring_ != a.fgring_) throw(ParmError("SphereHEALPix::DivElt(a) different pixelisation RING<>NESTED")) ; pixels_ /= a.pixels_; return (*this); } template void SphereHEALPix::print(ostream& os) const { this->Show(os); os << "SphereHEALPix(" << TypeOfMap() << ") NSide= " << nSide_ << " nPix_ = " << nPix_ << " omeg_ = " << omeg_ << endl; if(this->mInfo_) os << " DVList Info= " << *(this->mInfo_) << endl; os << "... Pixel values : "; for(int i=0; i < nPix_; i++) { if(i%5 == 0) os << endl; os << pixels_(i) <<", "; } os << endl; } //******************************************************************* #ifdef __CXX_PRAGMA_TEMPLATES__ #pragma define_template SphereHEALPix #pragma define_template SphereHEALPix #pragma define_template SphereHEALPix #pragma define_template SphereHEALPix #pragma define_template SphereHEALPix< complex > #pragma define_template SphereHEALPix< complex > #endif #if defined(ANSI_TEMPLATES) || defined(GNU_TEMPLATES) namespace SOPHYA { template class SphereHEALPix; template class SphereHEALPix; template class SphereHEALPix; template class SphereHEALPix; template class SphereHEALPix< complex >; template class SphereHEALPix< complex >; } #endif