Imported healpix tree

This commit is contained in:
Guilhem Lavaux 2012-10-30 13:56:48 -04:00
parent 4182c30485
commit 4bfb62f177
136 changed files with 26534 additions and 0 deletions

103
external/healpix/libpsht/libpsht.dox vendored Normal file
View file

@ -0,0 +1,103 @@
/*! \mainpage libpsht documentation
<ul>
<li>\ref introduction "Introduction"
<li><a href="modules.html">Programming interface</a>
</ul>
*/
/*! \page introduction Introduction to libpsht
"PSHT" is an acronym for <i>Performant Spherical Harmonic Transforms</i>.
All user-visible data types and functions in this library start with
the prefix "psht_", or with "pshts_" and "pshtd_" for single- and
double precision variants, respectively.
<i>libpsht</i>'s main functionality is the conversion between <i>maps</i>
on the sphere and <i>spherical harmonic coefficients</i> (or <i>a_lm</i>).
A map is defined as a set of <i>rings</i>, which in turn consist of
individual pixels that
<ul>
<li>all have the same colatitude and</li>
<li>are uniformly spaced in azimuthal direction.</li>
</ul>
Consequently, a ring is completely defined by
<ul>
<li>its colatitute (in radians)</li>
<li>the number of pixels it contains</li>
<li>the azimuth (in radians) of the first pixel in the ring</li>
<li>the weight that must be multiplied to every pixel during a map
analysis (typically the solid angle of a pixel in the ring) </li>
<li>the offset of the first ring pixel in the <i>map array</i></li>
<li>the stride between consecutive pixels in the ring.</li>
</ul>
The map array is a one-dimensional array of type <i>float</i> or
<i>double</i>, which contains the values of all map pixels. It is assumed
that the pixels of every ring are stored inside this array in order of
increasing azimuth and with the specified stride. Note however that the rings
themselves can be stored in any order inside the array.
The a_lm array is a one-dimensional array of type <i>pshts_cmplx</i> or
<i>pshtd_cmplx</i>, which contains all spherical harmonic coefficients
for 0<=m<=mmax and m<=l<=lmax. There is only one constraint on the
internal structure of the array, which is:
<code>Index[a_l+1,m] = Index[a_l,m] + stride</code>
That means that coefficients with identical <i>m</i> but different <i>l</i>
can be interpreted as a one-dimensional array in <i>l</i> with a unique
stride.
Several functions are provided for efficient index computation in this array;
they are documented \ref almgroup "here".
Information about a pixelisation of the sphere is stored in objects of
type psht_geom_info. It is possible to create such an object for any
supported pixelisation by using the function psht_make_geometry_info();
however, several easier-to-use functions are \ref geominfogroup "supplied"
for generating often-used pixelisations like ECP grids, Gaussian grids,
and Healpix grids.
A distinctive feature of PSHT is the ability to execute several transforms
simultaneously (as long as they have the same geometry information and
a_lm structure); this has the advantage that the spherical
harmonics only have to be evaluated once for all of the transforms, saving
a substantial amount of CPU time. The set of functions dealing with such
<i>job lists</i> is implemented twice, both for \ref sjoblistgroup "single"
and \ref djoblistgroup "double" precision transforms.
Currently, PSHT supports the following kinds of transforms:
<ul>
<li>scalar a_lm to map</li>
<li>scalar map to a_lm</li>
<li>polarised a_lm to map</li>
<li>polarised map to a_lm</li>
<li>spin(1-100) a_lm to map</li>
<li>spin(1-100) map to a_lm</li>
<li>scalar a_lm to maps of first derivatives</li>
</ul>
All these different kinds can be mixed freely within a job list; i.e., it is
possible to perform an a_lm->map and a map->a_lm transform simultaneously.
PSHT supports shared-memory parallelisation via OpenMP; this feature will
be automatically enabled if the compiler supports it.
PSHT will also make use of SSE2 instructions when compiled for a platform
known to support them (basically all Intel/AMD processors running a 64bit
operating system).
The spherical harmonic transforms can ce executed on double-precision and
single-precision maps and a_lm, but for accuracy reasons the computations
will always be performed in double precision. As a consequence,
single-precision transforms will most likely not be faster than their
double-precision counterparts, but they will require significantly less
memory.
Two example and benchmark programs are distributed with PSHT:
<ul>
<li>psht_test.c checks the accuracy of the (iterative) map analysis
algorithm</li>
<li>psht_perftest.c checks the performance of single or multiple
transforms</li>
</ul>
*/

27
external/healpix/libpsht/planck.make vendored Normal file
View file

@ -0,0 +1,27 @@
PKG:=libpsht
SD:=$(SRCROOT)/$(PKG)
OD:=$(BLDROOT)/$(PKG)
FULL_INCLUDE+= -I$(SD)
HDR_$(PKG):=$(SD)/*.h
LIB_$(PKG):=$(LIBDIR)/libpsht.a
BIN:=psht_test psht_perftest
LIBOBJ:=ylmgen_c.o psht.o psht_geomhelpers.o psht_almhelpers.o
ALLOBJ:=$(LIBOBJ) psht_test.o psht_perftest.o
LIBOBJ:=$(LIBOBJ:%=$(OD)/%)
ALLOBJ:=$(ALLOBJ:%=$(OD)/%)
ODEP:=$(HDR_$(PKG)) $(HDR_libfftpack) $(HDR_c_utils) $(SD)/psht_inc.c
BDEP:=$(LIB_$(PKG)) $(LIB_libfftpack) $(LIB_c_utils)
$(LIB_$(PKG)): $(LIBOBJ)
$(ALLOBJ): $(ODEP) | $(OD)_mkdir
BIN:=$(BIN:%=$(BINDIR)/%)
$(BIN): $(BINDIR)/% : $(OD)/%.o $(BDEP)
all_hdr+=$(HDR_$(PKG))
all_lib+=$(LIB_$(PKG))
all_cbin+=$(BIN)

216
external/healpix/libpsht/psht.c vendored Normal file
View file

@ -0,0 +1,216 @@
/*
* This file is part of libpsht.
*
* libpsht is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* libpsht is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libpsht; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* libpsht is being developed at the Max-Planck-Institut fuer Astrophysik
* and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
* (DLR).
*/
/*! \file psht.c
* Spherical transform library
*
* Copyright (C) 2006-2010 Max-Planck-Society
* \author Martin Reinecke
*/
#include <math.h>
#include "ls_fft.h"
#include "sse_utils.h"
#include "ylmgen_c.h"
#include "psht.h"
#include "c_utils.h"
const pshts_cmplx pshts_cmplx_null={0,0};
const pshtd_cmplx pshtd_cmplx_null={0,0};
static void get_chunk_info (int ndata, int *nchunks, int *chunksize)
{
static const int chunksize_min=100;
static const int nchunks_max=10;
*chunksize = IMAX(chunksize_min,(ndata+nchunks_max-1)/nchunks_max);
if ((*chunksize)&1) ++(*chunksize);
*nchunks = (ndata+*chunksize-1) / *chunksize;
}
typedef struct
{
double phi0_;
pshtd_cmplx *shiftarr, *work;
int s_shift, s_work;
real_plan plan;
int norot;
} ringhelper;
static void ringhelper_init (ringhelper *self)
{
static ringhelper rh_null = { 0, NULL, NULL, 0, 0, NULL, 0 };
*self = rh_null;
}
static void ringhelper_destroy (ringhelper *self)
{
if (self->plan) kill_real_plan(self->plan);
DEALLOC(self->shiftarr);
DEALLOC(self->work);
ringhelper_init(self);
}
static void ringhelper_update (ringhelper *self, int nph, int mmax, double phi0)
{
int m;
self->norot = (fabs(phi0)<1e-14);
if (!(self->norot))
if ((mmax!=self->s_shift-1) || (!FAPPROX(phi0,self->phi0_,1e-12)))
{
RESIZE (self->shiftarr,pshtd_cmplx,mmax+1);
self->s_shift = mmax+1;
self->phi0_ = phi0;
for (m=0; m<=mmax; ++m)
{
self->shiftarr[m].re = cos(m*phi0);
self->shiftarr[m].im = sin(m*phi0);
}
}
if (!self->plan) self->plan=make_real_plan(nph);
if (nph!=(int)self->plan->length)
{
kill_real_plan(self->plan);
self->plan=make_real_plan(nph);
}
GROW(self->work,pshtd_cmplx,self->s_work,nph);
}
static int ringinfo_compare (const void *xa, const void *xb)
{
const psht_ringinfo *a = xa, *b=xb;
if (a->sth < b->sth) return -1;
if (a->sth > b->sth) return 1;
return 0;
}
static int ringpair_compare (const void *xa, const void *xb)
{
const psht_ringpair *a = xa, *b=xb;
if (a->r1.nph==b->r1.nph)
{
if (a->r1.phi0<b->r1.phi0) return -1;
if (a->r1.phi0>b->r1.phi0) return 1;
return 0;
}
if (a->r1.nph<b->r1.nph) return -1;
if (a->r1.nph>b->r1.nph) return 1;
return 0;
}
static void assert_jobspace (int njobs_now)
{
UTIL_ASSERT (njobs_now<psht_maxjobs,
"Too many jobs added to a libpsht joblist. Exiting ...");
}
void psht_make_alm_info (int lmax, int mmax, int stride,
const ptrdiff_t *mstart, psht_alm_info **alm_info)
{
int m;
psht_alm_info *info = RALLOC(psht_alm_info,1);
info->lmax = lmax;
info->mmax = mmax;
info->mstart = RALLOC(ptrdiff_t,mmax+1);
info->stride = stride;
for (m=0; m<=mmax; ++m)
info->mstart[m] = mstart[m];
*alm_info = info;
}
ptrdiff_t psht_alm_index (const psht_alm_info *self, int l, int m)
{ return self->mstart[m]+self->stride*l; }
void psht_destroy_alm_info (psht_alm_info *info)
{
DEALLOC (info->mstart);
DEALLOC (info);
}
void psht_make_geom_info (int nrings, const int *nph, const ptrdiff_t *ofs,
const int *stride, const double *phi0, const double *theta,
const double *weight, psht_geom_info **geom_info)
{
psht_geom_info *info = RALLOC(psht_geom_info,1);
psht_ringinfo *infos = RALLOC(psht_ringinfo,nrings);
int pos=0;
int m;
info->pair=RALLOC(psht_ringpair,nrings);
info->npairs=0;
*geom_info = info;
for (m=0; m<nrings; ++m)
{
infos[m].theta = theta[m];
infos[m].cth = cos(theta[m]);
infos[m].sth = sin(theta[m]);
infos[m].weight = weight[m];
infos[m].phi0 = phi0[m];
infos[m].ofs = ofs[m];
infos[m].stride = stride[m];
infos[m].nph = nph[m];
}
qsort(infos,nrings,sizeof(psht_ringinfo),ringinfo_compare);
while (pos<nrings)
{
if ((pos<nrings-1) && FAPPROX(infos[pos].cth,-infos[pos+1].cth,1e-12))
{
info->pair[info->npairs].r1=infos[pos];
info->pair[info->npairs].r2=infos[pos+1];
pos+=2;
++info->npairs;
}
else
{
info->pair[info->npairs].r1=infos[pos];
info->pair[info->npairs].r2.nph=-1;
++pos;
++info->npairs;
}
}
DEALLOC(infos);
qsort(info->pair,info->npairs,sizeof(psht_ringpair),ringpair_compare);
}
void psht_destroy_geom_info (psht_geom_info *geom_info)
{
DEALLOC (geom_info->pair);
DEALLOC (geom_info);
}
#define CONCAT(a,b) a ## b
#define FLT double
#define X(arg) CONCAT(pshtd_,arg)
#include "psht_inc.c"
#undef FLT
#undef X
#define FLT float
#define X(arg) CONCAT(pshts_,arg)
#include "psht_inc.c"
#undef FLT
#undef X
#undef CONCAT

363
external/healpix/libpsht/psht.h vendored Normal file
View file

@ -0,0 +1,363 @@
/*
* This file is part of libpsht.
*
* libpsht is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* libpsht is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libpsht; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* libpsht is being developed at the Max-Planck-Institut fuer Astrophysik
* and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
* (DLR).
*/
/*! \file psht.h
* Interface for the spherical transform library.
*
* Copyright (C) 2006-2010 Max-Planck-Society
* \author Martin Reinecke
*/
#ifndef PLANCK_PSHT_H
#define PLANCK_PSHT_H
#include <stddef.h>
#include "sse_utils.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! PSHT type for storing single-precision complex values */
typedef struct
{
float re,im;
} pshts_cmplx;
/*! PSHT type for storing double-precision complex values */
typedef struct
{
double re,im;
} pshtd_cmplx;
extern const pshts_cmplx pshts_cmplx_null;
extern const pshtd_cmplx pshtd_cmplx_null;
/*! Helper type containing information about a single ring.
\note No user serviceable parts inside! */
typedef struct
{
double theta, phi0, weight, cth, sth;
ptrdiff_t ofs;
int nph, stride;
} psht_ringinfo;
/*! Helper type containing information about a pair of rings with colatitudes
symmetric around the equator.
\note No user serviceable parts inside! */
typedef struct
{
psht_ringinfo r1,r2;
} psht_ringpair;
/*! Enumeration of PSHT job types.
\note No user serviceable parts inside! */
typedef enum { MAP2ALM, ALM2MAP, ALM2MAP_DERIV1 } psht_jobtype;
/*! Type holding all required information about a map geometry.
\note No user serviceable parts inside! */
typedef struct
{
psht_ringpair *pair;
int npairs;
} psht_geom_info;
/*! Type holding all required information about a double precision SHT.
\note No user serviceable parts inside! */
typedef struct
{
psht_jobtype type;
int spin;
int add_output;
int nmaps, nalm;
double *map[3];
pshtd_cmplx *alm[3];
pshtd_cmplx *phas1[3], *phas2[3];
double *norm_l;
union {
#ifdef PLANCK_HAVE_SSE2
v2df *v[3];
v2df2 *v2[3];
#else
pshtd_cmplx *c[3];
#endif
} alm_tmp;
} pshtd_job;
enum { psht_maxjobs=10 };
/*! Type holding a list of simultaneous double precision SHT jobs.
\note No user serviceable parts inside! */
typedef struct
{
pshtd_job job[psht_maxjobs];
int njobs;
} pshtd_joblist;
/*! Type holding all required information about a single precision SHT.
\note No user serviceable parts inside! */
typedef struct
{
psht_jobtype type;
int spin;
int add_output;
int nmaps, nalm;
float *map[3];
pshts_cmplx *alm[3];
pshtd_cmplx *phas1[3], *phas2[3];
double *norm_l;
union {
#ifdef PLANCK_HAVE_SSE2
v2df *v[3];
v2df2 *v2[3];
#else
pshtd_cmplx *c[3];
#endif
} alm_tmp;
} pshts_job;
/*! Type holding a list of simultaneous single precision SHT jobs.
\note No user serviceable parts inside! */
typedef struct
{
pshts_job job[psht_maxjobs];
int njobs;
} pshts_joblist;
/*! \defgroup almgroup Helpers for calculation of a_lm indices */
/*! \{ */
/*! Helper type for index calculation in a_lm arrays. */
typedef struct
{
/*! Maximum \a l index of the array */
int lmax;
/*! Maximum \a m index of the array */
int mmax;
/*! Array containing the (hypothetical) indices of the coefficient
with quantum numbers 0,\a m */
ptrdiff_t *mstart;
/*! Stride between a_lm and a_(l+1),m */
ptrdiff_t stride;
} psht_alm_info;
/*! Creates an Alm data structure information from the following parameters:
\param lmax maximum \a l quantum number (>=0)
\param mmax maximum \a m quantum number (0<= \a mmax <= \a lmax)
\param stride the stride between consecutive a_lm entries
\param mstart the index of the (hypothetical) coefficient with the
quantum numbers 0,\a m. Must have \a mmax+1 entries.
\param alm_info will hold a pointer to the newly created data structure
*/
void psht_make_alm_info (int lmax, int mmax, int stride,
const ptrdiff_t *mstart, psht_alm_info **alm_info);
/*! Returns the index of the coefficient with quantum numbers \a l,\a m. */
ptrdiff_t psht_alm_index (const psht_alm_info *self, int l, int m);
/*! Deallocates the a_lm info object. */
void psht_destroy_alm_info (psht_alm_info *info);
/* \} */
/*! \defgroup geominfogroup Functions for dealing with geometry information */
/*! \{ */
/*! Creates a geometry information from a set of ring descriptions.
All arrays passed to this function must have \a nrings elements.
\param nrings the number of rings in the map
\param nph the number of pixels in each ring
\param ofs the index of the first pixel in each ring in the map array
\param stride the stride between consecutive pixels
\param phi0 the azimuth (in radians) of the first pixel in each ring
\param theta the colatitude (in radians) of each ring
\param weight the pixel weight to be used for the ring
\param geom_info will hold a pointer to the newly created data structure
*/
void psht_make_geom_info (int nrings, const int *nph, const ptrdiff_t *ofs,
const int *stride, const double *phi0, const double *theta,
const double *weight, psht_geom_info **geom_info);
/*! Deallocates the geometry information in \a info. */
void psht_destroy_geom_info (psht_geom_info *info);
/* \} */
/*! \defgroup sjoblistgroup Functions for dealing with single precision job lists
\note All pointers to maps or a_lm that are passed to the job-adding functions
must not be de-allocated until after the last call of execute_jobs() for
a particular job list! This is because PSHT does not copy the input data,
but only stores the pointers to the supplied maps and a_lm.
*/
/*! \{ */
/*! Creates a new joblist object. */
void pshts_make_joblist (pshts_joblist **joblist);
/*! Removes all jobs in \a joblist. */
void pshts_clear_joblist (pshts_joblist *joblist);
/*! Deallocates the given joblist object. */
void pshts_destroy_joblist (pshts_joblist *joblist);
/*! Adds a new scalar alm2map job to \a joblist, which reads data from \a alm
and writes data to \a map. If \a add_output is 0, \a map will be
overwritten, else the result will be added to \a map. */
void pshts_add_job_alm2map (pshts_joblist *joblist, const pshts_cmplx *alm,
float *map, int add_output);
/*! Adds a new scalar map2alm job to \a joblist, which reads data from \a map
and writes data to \a alm. If \a add_output is 0, \a alm will be
overwritten, else the result will be added to \a alm. */
void pshts_add_job_map2alm (pshts_joblist *joblist, const float *map,
pshts_cmplx *alm, int add_output);
/*! Adds a new polarised alm2map job to \a joblist, which reads data from
\a almT, \a almG and \a almC and writes data to \a mapT, \a mapQ and
\a mapU. If \a add_output is 0, the output maps will be
overwritten, else the result will be added to the output maps. */
void pshts_add_job_alm2map_pol (pshts_joblist *joblist,
const pshts_cmplx *almT, const pshts_cmplx *almG, const pshts_cmplx *almC,
float *mapT, float *mapQ, float *mapU, int add_output);
/*! Adds a new polarised map2alm job to \a joblist, which reads data from
\a mapT, \a mapQ and \a mapU and writes data to \a almT, \a almG and
\a almC. If \a add_output is 0, the output a_lm will be
overwritten, else the result will be added to the output a_lm. */
void pshts_add_job_map2alm_pol (pshts_joblist *joblist,
const float *mapT, const float *mapQ, const float *mapU,
pshts_cmplx *almT, pshts_cmplx *almG, pshts_cmplx *almC, int add_output);
/*! Adds a new spin alm2map job to \a joblist, which reads data from
\a alm1 and \a alm2 and writes data to \a map1 and map2.
\a spin must be 1, 2, or 3. If \a add_output is 0,
the output maps will be overwritten, else the result will be
added to the output maps. */
void pshts_add_job_alm2map_spin (pshts_joblist *joblist,
const pshts_cmplx *alm1, const pshts_cmplx *alm2, float *map1, float *map2,
int spin, int add_output);
/*! Adds a new spin map2alm job to \a joblist, which reads data from
\a map1 and \a map2 and writes data to \a alm1 and \a alm2.
\a spin must be 1, 2, or 3. If \a add_output is 0,
the output a_lm will be overwritten, else the result will be added
to the output a_lm. */
void pshts_add_job_map2alm_spin (pshts_joblist *joblist, const float *map1,
const float *map2, pshts_cmplx *alm1, pshts_cmplx *alm2, int spin,
int add_output);
/*! Adds a new job to \a joblist, which reads data from
\a alm and writes maps of the first derivatives to \a mapdtheta and
\a mapdphi, respectively. If \a add_output is 0,
the output maps will be overwritten, else the result will be added
to the output maps. */
void pshts_add_job_alm2map_deriv1 (pshts_joblist *joblist,
const pshts_cmplx *alm, float *mapdtheta, float *mapdphi, int add_output);
/*! Executes the jobs in \a joblist, using \a geom_info as map geometry
and \a alm_info as structure of the a_lm coefficients.
\note The map geometry and the a_lm structure have to be supplied to this
function only, since this information is not needed by PSHT anywhere else.
However, it is the user's responsibility to ensure that the input arrays
(specified by calls to the job-adding functions) are consistent with the
specified geometry and a_lm structure, and that the output arrays are
large enough to hold the produced results.
*/
void pshts_execute_jobs (pshts_joblist *joblist,
const psht_geom_info *geom_info, const psht_alm_info *alm_info);
/* \} */
/*! \defgroup djoblistgroup Functions for dealing with double precision job lists
\note All pointers to maps or a_lm that are passed to the job-adding functions
must not be de-allocated until after the last call of execute_jobs() for
a particular job list! This is because PSHT does not copy the input data,
but only stores the pointers to the supplied maps and a_lm.
*/
/*! \{ */
/*! Creates a new joblist object. */
void pshtd_make_joblist (pshtd_joblist **joblist);
/*! Removes all jobs in \a joblist. */
void pshtd_clear_joblist (pshtd_joblist *joblist);
/*! Deallocates the given joblist object. */
void pshtd_destroy_joblist (pshtd_joblist *joblist);
/*! Adds a new scalar alm2map job to \a joblist, which reads data from \a alm
and writes data to \a map. If \a add_output is 0, \a map will be
overwritten, else the result will be added to \a map. */
void pshtd_add_job_alm2map (pshtd_joblist *joblist, const pshtd_cmplx *alm,
double *map, int add_output);
/*! Adds a new scalar map2alm job to \a joblist, which reads data from \a map
and writes data to \a alm. If \a add_output is 0, \a alm will be
overwritten, else the result will be added to \a alm. */
void pshtd_add_job_map2alm (pshtd_joblist *joblist, const double *map,
pshtd_cmplx *alm, int add_output);
/*! Adds a new polarised alm2map job to \a joblist, which reads data from
\a almT, \a almG and \a almC and writes data to \a mapT, \a mapQ and
\a mapU. If \a add_output is 0, the output maps will be
overwritten, else the result will be added to the output maps. */
void pshtd_add_job_alm2map_pol (pshtd_joblist *joblist,
const pshtd_cmplx *almT, const pshtd_cmplx *almG, const pshtd_cmplx *almC,
double *mapT, double *mapQ, double *mapU, int add_output);
/*! Adds a new polarised map2alm job to \a joblist, which reads data from
\a mapT, \a mapQ and \a mapU and writes data to \a almT, \a almG and
\a almC. If \a add_output is 0, the output a_lm will be
overwritten, else the result will be added to the output a_lm. */
void pshtd_add_job_map2alm_pol (pshtd_joblist *joblist,
const double *mapT, const double *mapQ, const double *mapU,
pshtd_cmplx *almT, pshtd_cmplx *almG, pshtd_cmplx *almC, int add_output);
/*! Adds a new spin alm2map job to \a joblist, which reads data from
\a alm1 and \a alm2 and writes data to \a map1 and map2.
\a spin must be 1, 2, or 3. If \a add_output is 0,
the output maps will be overwritten, else the result will be
added to the output maps. */
void pshtd_add_job_alm2map_spin (pshtd_joblist *joblist,
const pshtd_cmplx *alm1, const pshtd_cmplx *alm2, double *map1, double *map2,
int spin, int add_output);
/*! Adds a new spin map2alm job to \a joblist, which reads data from
\a map1 and \a map2 and writes data to \a alm1 and \a alm2.
\a spin must be 1, 2, or 3. If \a add_output is 0,
the output a_lm will be overwritten, else the result will be added
to the output a_lm. */
void pshtd_add_job_map2alm_spin (pshtd_joblist *joblist, const double *map1,
const double *map2, pshtd_cmplx *alm1, pshtd_cmplx *alm2, int spin,
int add_output);
/*! Adds a new job to \a joblist, which reads data from
\a alm and writes maps of the first derivatives to \a mapdtheta and
\a mapdphi, respectively. If \a add_output is 0,
the output maps will be overwritten, else the result will be added
to the output maps. */
void pshtd_add_job_alm2map_deriv1 (pshtd_joblist *joblist,
const pshtd_cmplx *alm, double *mapdtheta, double *mapdphi, int add_output);
/*! Executes the jobs in \a joblist, using \a geom_info as map geometry
and \a alm_info as structure of the a_lm coefficients.
\note The map geometry and the a_lm structure have to be supplied to this
function only, since this information is not needed by PSHT anywhere else.
However, it is the user's responsibility to ensure that the input arrays
(specified by calls to the job-adding functions) are consistent with the
specified geometry and a_lm structure, and that the output arrays are
large enough to hold the produced results.
*/
void pshtd_execute_jobs (pshtd_joblist *joblist,
const psht_geom_info *geom_info, const psht_alm_info *alm_info);
/* \} */
#ifdef __cplusplus
}
#endif
#endif

View file

@ -0,0 +1,63 @@
/*
* This file is part of libpsht.
*
* libpsht is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* libpsht is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libpsht; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* libpsht is being developed at the Max-Planck-Institut fuer Astrophysik
* and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
* (DLR).
*/
/*! \file psht_almhelpers.c
* Spherical transform library
*
* Copyright (C) 2008, 2009, 2010 Max-Planck-Society
* \author Martin Reinecke
*/
#include "psht_almhelpers.h"
#include "c_utils.h"
void psht_make_triangular_alm_info (int lmax, int mmax, int stride,
psht_alm_info **alm_info)
{
ptrdiff_t m;
int tval;
psht_alm_info *info = RALLOC(psht_alm_info,1);
info->lmax = lmax;
info->mmax = mmax;
info->mstart = RALLOC(ptrdiff_t,mmax+1);
info->stride = stride;
tval = 2*lmax+1;
for (m=0; m<=mmax; ++m)
info->mstart[m] = stride*((m*(tval-m))>>1);
*alm_info = info;
}
void psht_make_rectangular_alm_info (int lmax, int mmax, int stride,
psht_alm_info **alm_info)
{
ptrdiff_t m;
psht_alm_info *info = RALLOC(psht_alm_info,1);
info->lmax = lmax;
info->mmax = mmax;
info->mstart = RALLOC(ptrdiff_t,mmax+1);
info->stride = stride;
for (m=0; m<=mmax; ++m)
info->mstart[m] = stride*m*(lmax+1);
*alm_info = info;
}

View file

@ -0,0 +1,57 @@
/*
* This file is part of libpsht.
*
* libpsht is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* libpsht is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libpsht; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* libpsht is being developed at the Max-Planck-Institut fuer Astrophysik
* and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
* (DLR).
*/
/*! \file psht_almhelpers.h
* PSHT helper function for the creation of a_lm data structures
*
* Copyright (C) 2008 Max-Planck-Society
* \author Martin Reinecke
*/
#ifndef PLANCK_PSHT_ALMHELPERS_H
#define PLANCK_PSHT_ALMHELPERS_H
#include "psht.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! Initialises an a_lm data structure according to the scheme used by
Healpix_cxx.
\ingroup almgroup */
void psht_make_triangular_alm_info (int lmax, int mmax, int stride,
psht_alm_info **alm_info);
/*! Initialises an a_lm data structure according to the scheme used by
Fortran Healpix
\ingroup almgroup */
void psht_make_rectangular_alm_info (int lmax, int mmax, int stride,
psht_alm_info **alm_info);
#ifdef __cplusplus
}
#endif
#endif

198
external/healpix/libpsht/psht_cxx.h vendored Normal file
View file

@ -0,0 +1,198 @@
/*
* This file is part of libpsht.
*
* libpsht is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* libpsht is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libpsht; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* libpsht is being developed at the Max-Planck-Institut fuer Astrophysik
* and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
* (DLR).
*/
/*! \file psht_cxx.h
* Spherical transform library
*
* Copyright (C) 2008, 2009 Max-Planck-Society
* \author Martin Reinecke
*/
#ifndef PLANCK_PSHT_CXX_H
#define PLANCK_PSHT_CXX_H
#include "psht.h"
#include "psht_geomhelpers.h"
#include "psht_almhelpers.h"
#include "xcomplex.h"
class psht_base
{
protected:
psht_geom_info *ginfo;
psht_alm_info *ainfo;
public:
psht_base()
: ginfo(0), ainfo(0) {}
~psht_base()
{
psht_destroy_geom_info(ginfo);
psht_destroy_alm_info(ainfo);
}
void set_general_geometry (int nrings, const int *nph, const ptrdiff_t *ofs,
const int *stride, const double *phi0, const double *theta,
const double *weight)
{
psht_make_geom_info (nrings, nph, ofs, stride, phi0, theta, weight,
&ginfo);
}
void set_ECP_geometry (int nrings, int nphi)
{ psht_make_ecp_geom_info (nrings, nphi, 0., 1, &ginfo); }
void set_Healpix_geometry (int nside)
{ psht_make_healpix_geom_info (nside, 1, &ginfo); }
void set_weighted_Healpix_geometry (int nside, const double *weight)
{ psht_make_weighted_healpix_geom_info (nside, 1, weight, &ginfo); }
void set_triangular_alm_info (int lmax, int mmax)
{ psht_make_triangular_alm_info (lmax, mmax, 1, &ainfo); }
};
template<typename T> class psht_joblist
{};
template<> class psht_joblist<float>: public psht_base
{
private:
pshts_joblist *jobs;
static pshts_cmplx *conv (xcomplex<float> *ptr)
{ return reinterpret_cast<pshts_cmplx *>(ptr); }
static const pshts_cmplx *conv (const xcomplex<float> *ptr)
{ return reinterpret_cast<const pshts_cmplx *>(ptr); }
public:
psht_joblist()
{ pshts_make_joblist (&jobs); }
~psht_joblist()
{ pshts_destroy_joblist (jobs); }
void clear_jobs()
{ pshts_clear_joblist (jobs); }
void add_alm2map (const xcomplex<float> *alm, float *map, bool add)
{ pshts_add_job_alm2map (jobs, conv(alm), map, add); }
void add_map2alm (const float *map, xcomplex<float> *alm, bool add)
{ pshts_add_job_map2alm (jobs, map, conv(alm), add); }
void add_alm2map_pol (const xcomplex<float> *almT,
const xcomplex<float> *almG, const xcomplex<float> *almC,
float *mapT, float *mapQ, float *mapU, bool add)
{
pshts_add_job_alm2map_pol (jobs, conv(almT), conv(almG), conv(almC),
mapT, mapQ, mapU, add);
}
void add_map2alm_pol (const float *mapT, const float *mapQ,
const float *mapU, xcomplex<float> *almT, xcomplex<float> *almG,
xcomplex<float> *almC, bool add)
{
pshts_add_job_map2alm_pol (jobs, mapT, mapQ, mapU, conv(almT),
conv(almG), conv(almC), add);
}
void add_alm2map_spin (const xcomplex<float> *alm1,
const xcomplex<float> *alm2, float *map1, float *map2, int spin, bool add)
{
pshts_add_job_alm2map_spin (jobs, conv(alm1), conv(alm2), map1, map2,
spin, add);
}
void add_map2alm_spin (const float *map1, const float *map2,
xcomplex<float> *alm1, xcomplex<float> *alm2, int spin, bool add)
{
pshts_add_job_map2alm_spin (jobs, map1, map2, conv(alm1), conv(alm2),
spin, add);
}
void add_alm2map_der1 (const xcomplex<float> *alm, float *mapdth,
float *mapdph, bool add)
{
pshts_add_job_alm2map_deriv1 (jobs, conv(alm), mapdth, mapdph, add);
}
void execute()
{ pshts_execute_jobs (jobs,ginfo,ainfo); }
};
template<> class psht_joblist<double>: public psht_base
{
private:
pshtd_joblist *jobs;
static pshtd_cmplx *conv (xcomplex<double> *ptr)
{ return reinterpret_cast<pshtd_cmplx *>(ptr); }
static const pshtd_cmplx *conv (const xcomplex<double> *ptr)
{ return reinterpret_cast<const pshtd_cmplx *>(ptr); }
public:
psht_joblist()
{ pshtd_make_joblist (&jobs); }
~psht_joblist()
{ pshtd_destroy_joblist (jobs); }
void clear_jobs()
{ pshtd_clear_joblist (jobs); }
void add_alm2map (const xcomplex<double> *alm, double *map, bool add)
{ pshtd_add_job_alm2map (jobs, conv(alm), map, add); }
void add_map2alm (const double *map, xcomplex<double> *alm, bool add)
{ pshtd_add_job_map2alm (jobs, map, conv(alm), add); }
void add_alm2map_pol (const xcomplex<double> *almT,
const xcomplex<double> *almG, const xcomplex<double> *almC,
double *mapT, double *mapQ, double *mapU, bool add)
{
pshtd_add_job_alm2map_pol (jobs, conv(almT), conv(almG), conv(almC),
mapT, mapQ, mapU, add);
}
void add_map2alm_pol (const double *mapT, const double *mapQ,
const double *mapU, xcomplex<double> *almT, xcomplex<double> *almG,
xcomplex<double> *almC, bool add)
{
pshtd_add_job_map2alm_pol (jobs, mapT, mapQ, mapU, conv(almT),
conv(almG), conv(almC), add);
}
void add_alm2map_spin (const xcomplex<double> *alm1,
const xcomplex<double> *alm2, double *map1, double *map2, int spin,
bool add)
{
pshtd_add_job_alm2map_spin (jobs, conv(alm1), conv(alm2), map1, map2,
spin, add);
}
void add_map2alm_spin (const double *map1, const double *map2,
xcomplex<double> *alm1, xcomplex<double> *alm2, int spin, bool add)
{
pshtd_add_job_map2alm_spin (jobs, map1, map2, conv(alm1), conv(alm2),
spin, add);
}
void add_alm2map_der1 (const xcomplex<double> *alm, double *mapdth,
double *mapdph, bool add)
{
pshtd_add_job_alm2map_deriv1 (jobs, conv(alm), mapdth, mapdph, add);
}
void execute()
{ pshtd_execute_jobs (jobs,ginfo,ainfo); }
};
#endif

View file

@ -0,0 +1,229 @@
/*
* This file is part of libpsht.
*
* libpsht is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* libpsht is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libpsht; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* libpsht is being developed at the Max-Planck-Institut fuer Astrophysik
* and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
* (DLR).
*/
/*! \file psht_geomhelpers.c
* Spherical transform library
*
* Copyright (C) 2006-2010 Max-Planck-Society
* \author Martin Reinecke
*/
#include <math.h>
#include "psht_geomhelpers.h"
#include "c_utils.h"
void psht_make_healpix_geom_info (int nside, int stride,
psht_geom_info **geom_info)
{
double *weight=RALLOC(double,2*nside);
SET_ARRAY(weight,0,2*nside,1);
psht_make_weighted_healpix_geom_info (nside, stride, weight, geom_info);
DEALLOC(weight);
}
void psht_make_weighted_healpix_geom_info (int nside, int stride,
const double *weight, psht_geom_info **geom_info)
{
const double pi=3.141592653589793238462643383279502884197;
ptrdiff_t npix=(ptrdiff_t)nside*nside*12;
ptrdiff_t ncap=2*(ptrdiff_t)nside*(nside-1);
int nrings=4*nside-1;
double *theta=RALLOC(double,nrings);
double *weight_=RALLOC(double,nrings);
int *nph=RALLOC(int,nrings);
double *phi0=RALLOC(double,nrings);
ptrdiff_t *ofs=RALLOC(ptrdiff_t,nrings);
int *stride_=RALLOC(int,nrings);
int m;
for (m=0; m<nrings; ++m)
{
int ring=m+1;
ptrdiff_t northring = (ring>2*nside) ? 4*nside-ring : ring;
stride_[m] = stride;
if (northring < nside)
{
theta[m] = 2*asin(northring/(sqrt(6.)*nside));
nph[m] = 4*northring;
phi0[m] = pi/nph[m];
ofs[m] = 2*northring*(northring-1);
}
else
{
double fact1 = (8.*nside)/npix;
double costheta = (2*nside-northring)*fact1;
theta[m] = acos(costheta);
nph[m] = 4*nside;
if ((northring-nside) & 1)
phi0[m] = 0;
else
phi0[m] = pi/nph[m];
ofs[m] = ncap + (northring-nside)*nph[m];
}
if (northring != ring) /* southern hemisphere */
{
theta[m] = pi-theta[m];
ofs[m] = npix - nph[m] - ofs[m];
}
weight_[m]=4.*pi/npix*weight[northring-1];
}
psht_make_geom_info (nrings, nph, ofs, stride_, phi0, theta, weight_,
geom_info);
DEALLOC(theta);
DEALLOC(weight_);
DEALLOC(nph);
DEALLOC(phi0);
DEALLOC(ofs);
DEALLOC(stride_);
}
static void gauleg (double x1, double x2, double *x, double *w, int n)
{
const double pi = 3.141592653589793238462643383279502884197;
const double eps = 3.0E-14;
int m = (n+1)/2;
double xm = 0.5*(x2+x1);
double xl = 0.5*(x2-x1);
int i;
for(i=1; i<=m; ++i)
{
double z = cos(pi*(i-0.25)/(n+0.5));
double pp;
int dobreak=0;
while(1)
{
double p1 = 1.0, p2 = 0.0;
double z1 = z;
int j;
for(j=1; j<=n; ++j)
{
double p3 = p2;
p2 = p1;
p1 = ((2*j-1)*z*p2-(j-1)*p3)/j;
}
pp = n*(z*p1-p2)/(z*z-1);
z = z1 - p1/pp;
if (dobreak) break;
if (fabs(z-z1) <= eps) dobreak=1;
}
x[i-1] = xm - xl*z;
x[n-i] = xm + xl*z;
w[i-1] = w[n-i] = 2*xl/((1-z*z)*pp*pp);
}
}
static void makeweights (int bw, double *weights)
{
const double pi = 3.141592653589793238462643383279502884197;
const double fudge = pi/(4*bw);
int j;
for (j=0; j<2*bw; ++j)
{
double tmpsum = 0;
int k;
for (k=0; k<bw; ++k)
tmpsum += 1./(2*k+1) * sin((2*j+1)*(2*k+1)*fudge);
tmpsum *= sin((2*j+1)*fudge);
tmpsum *= 2./bw;
weights[j] = tmpsum ;
/* weights[j + 2*bw] = tmpsum * sin((2*j+1)*fudge); */
}
}
void psht_make_gauss_geom_info (int nrings, int nphi, int stride,
psht_geom_info **geom_info)
{
const double pi=3.141592653589793238462643383279502884197;
double *theta=RALLOC(double,nrings);
double *weight=RALLOC(double,nrings);
int *nph=RALLOC(int,nrings);
double *phi0=RALLOC(double,nrings);
ptrdiff_t *ofs=RALLOC(ptrdiff_t,nrings);
int *stride_=RALLOC(int,nrings);
int m;
gauleg(-1,1,theta,weight,nrings);
for (m=0; m<nrings; ++m)
{
theta[m] = acos(theta[m]);
nph[m]=nphi;
phi0[m]=0;
ofs[m]=(ptrdiff_t)m*nphi;
stride_[m]=stride;
weight[m]*=2*pi/nphi;
}
psht_make_geom_info (nrings, nph, ofs, stride_, phi0, theta, weight,
geom_info);
DEALLOC(theta);
DEALLOC(weight);
DEALLOC(nph);
DEALLOC(phi0);
DEALLOC(ofs);
DEALLOC(stride_);
}
void psht_make_ecp_geom_info (int nrings, int nphi, double phi0, int stride,
psht_geom_info **geom_info)
{
const double pi=3.141592653589793238462643383279502884197;
double *theta=RALLOC(double,nrings);
double *weight=RALLOC(double,nrings);
int *nph=RALLOC(int,nrings);
double *phi0_=RALLOC(double,nrings);
ptrdiff_t *ofs=RALLOC(ptrdiff_t,nrings);
int *stride_=RALLOC(int,nrings);
int m;
UTIL_ASSERT((nrings&1)==0,
"Even number of rings needed for equidistant grid!");
makeweights(nrings/2,weight);
for (m=0; m<nrings; ++m)
{
theta[m] = (m+0.5)*pi/nrings;
nph[m]=nphi;
phi0_[m]=phi0;
ofs[m]=(ptrdiff_t)m*nphi;
stride_[m]=stride;
weight[m]*=2*pi/nphi;
}
psht_make_geom_info (nrings, nph, ofs, stride_, phi0_, theta, weight,
geom_info);
DEALLOC(theta);
DEALLOC(weight);
DEALLOC(nph);
DEALLOC(phi0_);
DEALLOC(ofs);
DEALLOC(stride_);
}

View file

@ -0,0 +1,72 @@
/*
* This file is part of libpsht.
*
* libpsht is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* libpsht is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libpsht; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* libpsht is being developed at the Max-Planck-Institut fuer Astrophysik
* and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
* (DLR).
*/
/*! \file psht_geomhelpers.h
* PSHT helper function for the creation of grid geometries
*
* Copyright (C) 2006, 2007, 2008 Max-Planck-Society
* \author Martin Reinecke
*/
#ifndef PLANCK_PSHT_GEOMHELPERS_H
#define PLANCK_PSHT_GEOMHELPERS_H
#include "psht.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! Creates a geometry information describing a HEALPix map with an
Nside parameter \a nside.
\ingroup geominfogroup */
void psht_make_healpix_geom_info (int nside, int stride,
psht_geom_info **geom_info);
/*! Creates a geometry information describing a HEALPix map with an
Nside parameter \a nside. \a weight contains the relative ring
weights and must have \a 2*nside entries.
\ingroup geominfogroup */
void psht_make_weighted_healpix_geom_info (int nside, int stride,
const double *weight, psht_geom_info **geom_info);
/*! Creates a geometry information describing a Gaussian map with \a nrings
iso-latitude rings and \a nphi pixels per ring. The azimuth of the first
pixel in each ring is 0.
\ingroup geominfogroup */
void psht_make_gauss_geom_info (int nrings, int nphi, int stride,
psht_geom_info **geom_info);
/*! Creates a geometry information describing an ECP map with \a nrings
iso-latitude rings and \a nphi pixels per ring. The azimuth of the first
pixel in each ring is \a phi0 (in radians).
\ingroup geominfogroup */
void psht_make_ecp_geom_info (int nrings, int nphi, double phi0, int stride,
psht_geom_info **geom_info);
#ifdef __cplusplus
}
#endif
#endif

1081
external/healpix/libpsht/psht_inc.c vendored Normal file

File diff suppressed because it is too large Load diff

223
external/healpix/libpsht/psht_perftest.c vendored Normal file
View file

@ -0,0 +1,223 @@
/*
* This file is part of libpsht.
*
* libpsht is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* libpsht is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libpsht; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* libpsht is being developed at the Max-Planck-Institut fuer Astrophysik
* and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
* (DLR).
*/
/*! \file psht_perftest.c
Performance test of libpsht's map synthesis and analysis algorithms.
This program creates a list of transform jobs with a user-specified
maximum multipole lmax that operate on a HEALPix, ECP or Gaussian grid.
Depending on the geometry type, the user has to specify the Nside parameter
(for HEALPix) or the number of pixels per ring.
The individual job types are also given by the user
and can be "alm2map", "map2alm", "alm2map_pol", "map2alm_pol",
"alm2map_spin[1-3]", "map2alm_spin[1-3]", and "alm2map_deriv1".
Any combination of job types is allowed.
All requested jobs are executed simultaneously.
Copyright (C) 2006-2010 Max-Planck-Society
\author Martin Reinecke
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "psht.h"
#include "psht_geomhelpers.h"
#include "psht_almhelpers.h"
#include "c_utils.h"
#include "walltime_c.h"
static void get_map(float **map, ptrdiff_t npix)
{
*map=RALLOC(float,npix);
SET_ARRAY(*map,0,npix,1);
}
static void get_alm(pshts_cmplx **alm, ptrdiff_t nalm)
{
static const pshts_cmplx pshts_cmplx_one={1,1};
*alm=RALLOC(pshts_cmplx,nalm);
SET_ARRAY(*alm,0,nalm,pshts_cmplx_one);
}
static void prepare_job (const char *jobname, float **map,
pshts_cmplx **alm, ptrdiff_t npix, ptrdiff_t nalm, int ofs_m, int ofs_a,
int num_m, int num_a)
{
int m;
printf("adding job: %s\n", jobname);
for (m=0; m<num_m; ++m)
get_map (&map[ofs_m+m],npix);
for (m=0; m<num_a; ++m)
get_alm (&alm[ofs_a+m],nalm);
}
int main(int argc, char **argv)
{
ptrdiff_t npix=0,lmax,nalm;
float *map[100];
pshts_cmplx *alm[100];
psht_alm_info *alms;
psht_geom_info *tinfo;
pshts_joblist *joblist;
int ofs_m, ofs_a, m;
double wtimer;
UTIL_ASSERT (argc>=5,
"usage: psht_perftest <healpix|ecp|gauss> <lmax> <nside|nphi> <type>+\n"
" where <type> can be 'alm2map', 'map2alm', 'alm2map_pol',\n"
" 'map2alm_pol', 'alm2map_spin[1-3]', 'map2alm_spin[1-3]',\n"
" or 'alm2map_deriv1'");
lmax=atoi(argv[2]);
if (strcmp(argv[1],"gauss")==0)
{
int nrings=lmax+1;
int ppring=atoi(argv[3]);
npix=(ptrdiff_t)nrings*ppring;
printf("\nTesting Gaussian grid (%d rings, %d pixels/ring, %ld pixels)\n",
nrings,ppring,(long)npix);
psht_make_gauss_geom_info (nrings, ppring, 1, &tinfo);
}
else if (strcmp(argv[1],"ecp")==0)
{
int nrings=2*lmax+2;
int ppring=atoi(argv[3]);
npix=(ptrdiff_t)nrings*ppring;
printf("\nTesting ECP grid (%d rings, %d pixels/ring, %ld pixels)\n",
nrings,ppring,(long)npix);
psht_make_ecp_geom_info (nrings, ppring, 0., 1, &tinfo);
}
else if (strcmp(argv[1],"healpix")==0)
{
int nside=atoi(argv[3]);
if (nside<1) nside=1;
npix=12*(ptrdiff_t)nside*nside;
printf("\nTesting Healpix grid (nside=%d, %ld pixels)\n",
nside,(long)npix);
psht_make_healpix_geom_info (nside, 1, &tinfo);
}
else
UTIL_FAIL("unknown command");
psht_make_triangular_alm_info(lmax,lmax,1,&alms);
nalm = ((ptrdiff_t)(lmax+1)*(lmax+2))/2;
pshts_make_joblist (&joblist);
ofs_m=ofs_a=0;
for (m=4; m<argc; ++m)
{
if (strcmp(argv[m],"alm2map")==0)
{
prepare_job ("alm2map",map,alm,npix,nalm,ofs_m,ofs_a,1,1);
pshts_add_job_alm2map(joblist,alm[ofs_a],map[ofs_m],0);
++ofs_m; ++ofs_a;
}
else if (strcmp(argv[m],"map2alm")==0)
{
prepare_job ("map2alm",map,alm,npix,nalm,ofs_m,ofs_a,1,1);
pshts_add_job_map2alm(joblist,map[ofs_m],alm[ofs_a],0);
++ofs_m; ++ofs_a;
}
else if (strcmp(argv[m],"alm2map_pol")==0)
{
prepare_job ("alm2map_pol",map,alm,npix,nalm,ofs_m,ofs_a,3,3);
pshts_add_job_alm2map_pol(joblist,alm[ofs_a],alm[ofs_a+1],alm[ofs_a+2],
map[ofs_m],map[ofs_m+1],map[ofs_m+2],0);
ofs_m+=3; ofs_a+=3;
}
else if (strcmp(argv[m],"map2alm_pol")==0)
{
prepare_job ("map2alm_pol",map,alm,npix,nalm,ofs_m,ofs_a,3,3);
pshts_add_job_map2alm_pol(joblist,map[ofs_m],map[ofs_m+1],map[ofs_m+2],
alm[ofs_a],alm[ofs_a+1],alm[ofs_a+2],0);
ofs_m+=3; ofs_a+=3;
}
else if (strcmp(argv[m],"alm2map_spin1")==0)
{
prepare_job ("alm2map_spin1",map,alm,npix,nalm,ofs_m,ofs_a,2,2);
pshts_add_job_alm2map_spin(joblist,alm[ofs_a],alm[ofs_a+1],
map[ofs_m],map[ofs_m+1],1,0);
ofs_m+=2; ofs_a+=2;
}
else if (strcmp(argv[m],"map2alm_spin1")==0)
{
prepare_job ("map2alm_spin1",map,alm,npix,nalm,ofs_m,ofs_a,2,2);
pshts_add_job_map2alm_spin(joblist,map[ofs_m],map[ofs_m+1],
alm[ofs_a],alm[ofs_a+1],1,0);
ofs_m+=2; ofs_a+=2;
}
else if (strcmp(argv[m],"alm2map_spin2")==0)
{
prepare_job ("alm2map_spin2",map,alm,npix,nalm,ofs_m,ofs_a,2,2);
pshts_add_job_alm2map_spin(joblist,alm[ofs_a],alm[ofs_a+1],
map[ofs_m],map[ofs_m+1],2,0);
ofs_m+=2; ofs_a+=2;
}
else if (strcmp(argv[m],"map2alm_spin2")==0)
{
prepare_job ("map2alm_spin2",map,alm,npix,nalm,ofs_m,ofs_a,2,2);
pshts_add_job_map2alm_spin(joblist,map[ofs_m],map[ofs_m+1],
alm[ofs_a],alm[ofs_a+1],2,0);
ofs_m+=2; ofs_a+=2;
}
else if (strcmp(argv[m],"alm2map_spin3")==0)
{
prepare_job ("alm2map_spin3",map,alm,npix,nalm,ofs_m,ofs_a,2,2);
pshts_add_job_map2alm_spin(joblist,map[ofs_m],map[ofs_m+1],
alm[ofs_a],alm[ofs_a+1],3,0);
ofs_m+=2; ofs_a+=2;
}
else if (strcmp(argv[m],"map2alm_spin3")==0)
{
prepare_job ("map2alm_spin3",map,alm,npix,nalm,ofs_m,ofs_a,2,2);
pshts_add_job_map2alm_spin(joblist,map[ofs_m],map[ofs_m+1],
alm[ofs_a],alm[ofs_a+1],3,0);
ofs_m+=2; ofs_a+=2;
}
else if (strcmp(argv[m],"alm2map_deriv1")==0)
{
prepare_job ("alm2map_deriv1",map,alm,npix,nalm,ofs_m,ofs_a,2,1);
pshts_add_job_alm2map_deriv1(joblist,alm[ofs_a], map[ofs_m],
map[ofs_m+1],0);
ofs_m+=2; ofs_a+=1;
}
else
UTIL_FAIL("unknown transform type");
}
wtimer=wallTime();
pshts_execute_jobs (joblist, tinfo, alms);
printf("wall time for transform: %fs\n",wallTime()-wtimer);
pshts_destroy_joblist(joblist);
psht_destroy_geom_info(tinfo);
psht_destroy_alm_info(alms);
for (m=0; m<ofs_m; ++m)
DEALLOC(map[m]);
for (m=0; m<ofs_a; ++m)
DEALLOC(alm[m]);
return 0;
}

260
external/healpix/libpsht/psht_test.c vendored Normal file
View file

@ -0,0 +1,260 @@
/*
* This file is part of libpsht.
*
* libpsht is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* libpsht is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libpsht; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* libpsht is being developed at the Max-Planck-Institut fuer Astrophysik
* and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
* (DLR).
*/
/*! \file psht_test.c
Accuracy test for libpsht's map analysis.
This program first generates a_lm coefficients up to
a user-specified lmax (with mmax=lmax); where applicable, the
real and imaginary parts of the coefficients are uniform
random numbers of the interval [-1;1[.
Afterwards, the random a_lm are converted to a map.
This map is analyzed (optionally using an iterative scheme
with a user-supplied number of steps).
After every iteration, the code then outputs the RMS of the residual a_lm
(i.e. the difference between the current and original a_lm), divided by
the RMS of the original a_lm, as well as the maximum absolute change of any
real or imaginary part between the current and original a_lm.
This operation can be performed for several different pixelisations:
- a Gaussian with the minimal number of rings for exact analysis
and a user-defined ring resolution
- an ECP grid with the minimal number of rings for exact analysis
and a user-defined ring resolution
- a Healpix grid with a user-defined Nside parameter.
The user can specify the spin of the desired transform.
Copyright (C) 2006-2010 Max-Planck-Society
\author Martin Reinecke
*/
#include <stdio.h>
#include <string.h>
#include "psht.h"
#include "psht_geomhelpers.h"
#include "psht_almhelpers.h"
#include "c_utils.h"
#include "walltime_c.h"
static double drand (double min, double max)
{
return min + (max-min)*rand()/(RAND_MAX+1.0);
}
static void random_alm (pshtd_cmplx *alm, psht_alm_info *helper, int spin)
{
int l,m;
for (m=0;m<=helper->mmax; ++m)
for (l=m;l<=helper->lmax; ++l)
{
if ((l<spin)&&(m<spin))
alm[psht_alm_index(helper,l,m)] = pshtd_cmplx_null;
else
{
alm[psht_alm_index(helper,l,m)].re = drand(-1,1);
alm[psht_alm_index(helper,l,m)].im = (m==0) ? 0 : drand(-1,1);
}
}
}
static void measure_errors (pshtd_cmplx **alm, pshtd_cmplx **alm2,
ptrdiff_t nalms, int ncomp)
{
int i;
ptrdiff_t m;
for (i=0; i<ncomp; ++i)
{
double sum=0, sum2=0, maxdiff=0;
for (m=0; m<nalms; ++m)
{
double x=alm[i][m].re-alm2[i][m].re, y=alm[i][m].im-alm2[i][m].im;
sum+=x*x+y*y;
sum2+=alm[i][m].re*alm[i][m].re+alm[i][m].im*alm[i][m].im;
if (fabs(x)>maxdiff) maxdiff=fabs(x);
if (fabs(y)>maxdiff) maxdiff=fabs(y);
}
sum=sqrt(sum/nalms);
sum2=sqrt(sum2/nalms);
printf("component %i: rms %e, maxerr %e\n",i, sum/sum2, maxdiff);
}
}
static void map2alm_iter (psht_geom_info *tinfo, double **map,
pshtd_cmplx **alm_orig, pshtd_cmplx **alm, int lmax, int mmax,
ptrdiff_t npix, ptrdiff_t nalms, int spin, int niter)
{
psht_alm_info *alms;
pshtd_joblist *joblist;
int ncomp = (spin==0) ? 1 : 2;
int iter,i;
ptrdiff_t m;
double timer;
psht_make_triangular_alm_info(lmax,mmax,1,&alms);
pshtd_make_joblist (&joblist);
if (spin==0)
pshtd_add_job_map2alm(joblist,map[0],alm[0],0);
else
pshtd_add_job_map2alm_spin(joblist,map[0],map[1],alm[0],alm[1],spin,0);
timer=wallTime();
pshtd_execute_jobs (joblist, tinfo, alms);
printf("wall time for map2alm: %fs\n",wallTime()-timer);
pshtd_clear_joblist (joblist);
measure_errors(alm_orig,alm,nalms,ncomp);
for (iter=0; iter<niter; ++iter)
{
double **map2;
ALLOC2D(map2,double,ncomp,npix);
printf ("\niteration %i:\n", iter+1);
if (spin==0)
pshtd_add_job_alm2map(joblist,alm[0],map2[0],0);
else
pshtd_add_job_alm2map_spin(joblist,alm[0],alm[1],map2[0],map2[1],spin,0);
timer=wallTime();
pshtd_execute_jobs (joblist, tinfo, alms);
printf("wall time for alm2map: %fs\n",wallTime()-timer);
pshtd_clear_joblist (joblist);
for (i=0; i<ncomp; ++i)
for (m=0; m<npix; ++m)
map2[i][m] = map[i][m]-map2[i][m];
if (spin==0)
pshtd_add_job_map2alm(joblist,map2[0],alm[0],1);
else
pshtd_add_job_map2alm_spin(joblist,map2[0],map2[1],alm[0],alm[1],spin,1);
timer=wallTime();
pshtd_execute_jobs (joblist, tinfo, alms);
printf("wall time for map2alm: %fs\n",wallTime()-timer);
pshtd_clear_joblist (joblist);
DEALLOC2D(map2);
measure_errors(alm_orig,alm,nalms,ncomp);
}
psht_destroy_alm_info(alms);
pshtd_destroy_joblist(joblist);
}
static void check_accuracy (psht_geom_info *tinfo, ptrdiff_t lmax,
ptrdiff_t mmax, ptrdiff_t npix, int spin, int niter)
{
psht_alm_info *alms;
pshtd_joblist *joblist;
double **map;
pshtd_cmplx **alm, **alm2;
ptrdiff_t nalms = ((mmax+1)*(mmax+2))/2 + (mmax+1)*(lmax-mmax);
int ncomp = (spin==0) ? 1 : 2;
double timer;
ALLOC2D(map,double,ncomp,npix);
psht_make_triangular_alm_info(lmax,mmax,1,&alms);
pshtd_make_joblist (&joblist);
srand(4);
ALLOC2D(alm,pshtd_cmplx,ncomp,nalms);
random_alm(alm[0],alms,spin);
if (spin>0)
random_alm(alm[1],alms,spin);
ALLOC2D(alm2,pshtd_cmplx,ncomp,nalms);
printf ("\niteration 0:\n");
if (spin==0)
pshtd_add_job_alm2map(joblist,alm[0],map[0],0);
else
pshtd_add_job_alm2map_spin(joblist,alm[0],alm[1],map[0],map[1],spin,0);
timer=wallTime();
pshtd_execute_jobs (joblist, tinfo, alms);
printf("wall time for alm2map: %fs\n",wallTime()-timer);
pshtd_clear_joblist (joblist);
map2alm_iter(tinfo, map, alm, alm2, lmax, mmax, npix, nalms, spin, niter);
DEALLOC2D(map);
DEALLOC2D(alm);
DEALLOC2D(alm2);
psht_destroy_alm_info(alms);
pshtd_destroy_joblist(joblist);
}
int main(int argc, char **argv)
{
int lmax;
int spin;
int niter;
psht_geom_info *tinfo;
UTIL_ASSERT (argc==6,
"usage: psht_test <healpix|ecp|gauss> <lmax> <nside|nphi> <niter> <spin>");
lmax=atoi(argv[2]);
niter=atoi(argv[4]);
spin=atoi(argv[5]);
printf("Testing map analysis accuracy.\n");
printf("lmax=%d, %d iterations, spin=%d\n", lmax, niter, spin);
if (strcmp(argv[1],"gauss")==0)
{
int nrings=lmax+1;
int ppring=atoi(argv[3]);
ptrdiff_t npix=(ptrdiff_t)nrings*ppring;
printf("\nTesting Gaussian grid (%d rings, %d pixels/ring, %ld pixels)\n",
nrings,ppring,(long)npix);
psht_make_gauss_geom_info (nrings, ppring, 1, &tinfo);
check_accuracy(tinfo,lmax,lmax,npix,spin,niter);
psht_destroy_geom_info(tinfo);
}
else if (strcmp(argv[1],"ecp")==0)
{
int nrings=2*lmax+2;
int ppring=atoi(argv[3]);
ptrdiff_t npix=(ptrdiff_t)nrings*ppring;
printf("\nTesting ECP grid (%d rings, %d pixels/ring, %ld pixels)\n",
nrings,ppring,(long)npix);
psht_make_ecp_geom_info (nrings, ppring, 0., 1, &tinfo);
check_accuracy(tinfo,lmax,lmax,npix,spin,niter);
psht_destroy_geom_info(tinfo);
}
else if (strcmp(argv[1],"healpix")==0)
{
int nside=atoi(argv[3]);
ptrdiff_t npix;
if (nside<1) nside=1;
npix=12*(ptrdiff_t)nside*nside;
printf("\nTesting Healpix grid (nside=%d, %ld pixels)\n",
nside,(long)npix);
psht_make_healpix_geom_info (nside, 1, &tinfo);
check_accuracy(tinfo,lmax,lmax,npix,spin,niter);
psht_destroy_geom_info(tinfo);
}
else
UTIL_FAIL("unknown grid geometry");
return 0;
}

1151
external/healpix/libpsht/ylmgen_c.c vendored Normal file

File diff suppressed because it is too large Load diff

141
external/healpix/libpsht/ylmgen_c.h vendored Normal file
View file

@ -0,0 +1,141 @@
/*
* This file is part of libpsht.
*
* libpsht is free software; you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation; either version 2 of the License, or
* (at your option) any later version.
*
* libpsht is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with libpsht; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/*
* libpsht is being developed at the Max-Planck-Institut fuer Astrophysik
* and financially supported by the Deutsches Zentrum fuer Luft- und Raumfahrt
* (DLR).
*/
/*! \file ylmgen_c.h
* Code for efficient calculation of Y_lm(phi=0,theta)
*
* Copyright (C) 2005-2011 Max-Planck-Society
* \author Martin Reinecke
*/
#ifndef PLANCK_YLMGEN_C_H
#define PLANCK_YLMGEN_C_H
#include "sse_utils.h"
#ifdef __cplusplus
extern "C" {
#endif
typedef double ylmgen_dbl2[2];
typedef double ylmgen_dbl3[3];
typedef struct
{
double cth_crit;
int mdist_crit;
/* members depending on m and m' */
int s, m, mlo, mhi, cosPow, sinPow;
long double prefactor;
ylmgen_dbl3 *fx;
int preMinus_p, preMinus_m;
} sylmgen_d;
typedef struct
{
double fsmall, fbig, eps, cth_crit;
int lmax, mmax, m_cur, ith, nth, m_crit, spinrec;
/*! The index of the first non-negligible Y_lm value. */
int *firstl;
double *cf, *mfac, *t1fac, *t2fac, *th, *cth, *sth, *logsth;
ylmgen_dbl2 *recfac;
double *lamfact;
/*! Points to an array of size [0..lmax] containing the Y_lm values. */
double *ylm;
/*! Points to an array of size [0..lmax] containing the lambda_w
and lambda_x values for spin>0 transforms. */
ylmgen_dbl2 **lambda_wx;
long double *logsum, *lc05, *ls05;
double *flm1, *flm2, *xl;
sylmgen_d **sylm;
int *lwx_uptodate;
int ylm_uptodate;
#ifdef PLANCK_HAVE_SSE2
int ith1, ith2;
/*! Points to an array of size [0..lmax] containing the Y_lm values. */
v2df *ylm_sse2;
/*! Points to an array of size [0..lmax] containing the lambda_w
and lambda_x values for spin>0 transforms. */
v2df2 **lambda_wx_sse2;
int *lwx_uptodate_sse2;
int ylm_uptodate_sse2;
#endif
int recfac_uptodate, lamfact_uptodate;
} Ylmgen_C;
/*! Creates a generator which will calculate Y_lm(theta,phi=0)
up to \a l=l_max and \a m=m_max. It may regard Y_lm whose absolute
magnitude is smaller than \a epsilon as zero. If \a spinrec is nonzero,
the spin-1 and spin-2 Y_lm will be calculated by recursion from the spin-0
ones, otherwise Wigner d matrix elements will be used. */
void Ylmgen_init (Ylmgen_C *gen, int l_max, int m_max, int spinrec,
double epsilon);
/*! Passes am array \a theta of \a nth colatitudes that will be used in
subsequent calls. The individual angles will be referenced by their
index in the array, starting with 0.
\note The array can be freed or reused after the call. */
void Ylmgen_set_theta (Ylmgen_C *gen, const double *theta, int nth);
/*! Deallocates a generator previously initialised by Ylmgen_init(). */
void Ylmgen_destroy (Ylmgen_C *gen);
/*! Prepares the object for the calculation at \a theta and \a m. */
void Ylmgen_prepare (Ylmgen_C *gen, int ith, int m);
/*! Recalculates (if necessary) the Y_lm values. */
void Ylmgen_recalc_Ylm (Ylmgen_C *gen);
/*! Recalculates (if necessary) the lambda_w and lambda_x values for spin >0
transforms. */
void Ylmgen_recalc_lambda_wx (Ylmgen_C *gen, int spin);
#ifdef PLANCK_HAVE_SSE2
/*! Prepares the object for the calculation at \a theta, \a theta2 and \a m. */
void Ylmgen_prepare_sse2 (Ylmgen_C *gen, int ith1, int ith2, int m);
/*! Recalculates (if necessary) the Y_lm values. */
void Ylmgen_recalc_Ylm_sse2 (Ylmgen_C *gen);
/*! Recalculates (if necessary) the lambda_w and lambda_x values for spin >0
transforms. */
void Ylmgen_recalc_lambda_wx_sse2 (Ylmgen_C *gen, int spin);
#endif
/*! Returns a pointer to an array with lmax+1 entries containing normalisation
factors that must be applied to Y_lm values computed for \a spin with the
given \a spinrec flag. The array must be deallocated (using free()) by the
user. */
double *Ylmgen_get_norm (int lmax, int spin, int spinrec);
/*! Returns the maximum spin quantum number supported by the Ylmgen code. */
int Ylmgen_maxspin(void);
#ifdef __cplusplus
}
#endif
#endif