Commit 8169eaab authored by Martin Reinecke's avatar Martin Reinecke
Browse files

first import of libsharp

parent a0f9efc1
ACLOCAL_AMFLAGS = -I m4
lib_LTLIBRARIES = libmrutil.la
libmrutil_la_SOURCES = \
libsharp2/sharp_utils.h \
libsharp2/sharp_utils.cc \
libsharp2/sharp.cc \
libsharp2/sharp_almhelpers.cc \
libsharp2/sharp_core.cc \
libsharp2/sharp_geomhelpers.cc \
libsharp2/sharp_ylmgen_c.cc \
libsharp2/sharp_internal.h \
libsharp2/sharp_vecsupport.h \
libsharp2/sharp_ylmgen_c.h \
mr_util/cmplx.h \
mr_util/error_handling.cc \
mr_util/error_handling.h \
mr_util/fft.h \
mr_util/gl_integrator.h \
mr_util/mav.h \
mr_util/string_utils.cc \
mr_util/string_utils.h \
mr_util/system.cc \
mr_util/system.h \
mr_util/threading.h \
mr_util/timers.h \
mr_util/unity_roots.h \
mr_util/useful_macros.h
# format is "current:revision:age"
# any change: increase revision
# any interface change: increase current, revision=0
# any backward-compatible change: increase age
# any backward-incompatible change: age=0
# ==> age <= current
libmrutil_la_LDFLAGS = -version-info 0:0:0 -lpthread
AM_CXXFLAGS = @AM_CXXFLAGS@
if HAVE_MULTIARCH
libavx_la_SOURCES = libsharp2/sharp_core_inc.cc
libavx2_la_SOURCES = libsharp2/sharp_core_inc.cc
libfma_la_SOURCES = libsharp2/sharp_core_inc.cc
libfma4_la_SOURCES = libsharp2/sharp_core_inc.cc
libavx512f_la_SOURCES = libsharp2/sharp_core_inc.cc
noinst_LTLIBRARIES = libavx.la libavx2.la libfma.la libfma4.la libavx512f.la
libavx_la_CXXFLAGS = ${AM_CXXFLAGS} -mavx -DARCH=avx
libavx2_la_CXXFLAGS = ${AM_CXXFLAGS} -mavx2 -DARCH=avx2
libfma_la_CXXFLAGS = ${AM_CXXFLAGS} -mfma -DARCH=fma
libfma4_la_CXXFLAGS = ${AM_CXXFLAGS} -mfma4 -DARCH=fma4
libavx512f_la_CXXFLAGS = ${AM_CXXFLAGS} -mavx512f -DARCH=avx512f
libmrutil_la_LIBADD = libavx.la libavx2.la libfma.la libfma4.la libavx512f.la
endif
nobase_include_HEADERS = \
libsharp2/sharp.h \
libsharp2/sharp_mpi.h \
libsharp2/sharp_geomhelpers.h \
libsharp2/sharp_almhelpers.h \
libsharp2/sharp_cxx.h
EXTRA_DIST = \
runtest.sh fortran/sharp.f90 fortran/test_sharp.f90 libsharp2/sharp_mpi.cc
check_PROGRAMS = sharp2_testsuite
sharp2_testsuite_SOURCES = test/sharp2_testsuite.cc
sharp2_testsuite_LDADD = libmrutil.la
TESTS = runtest.sh
pkgconfigdir = $(libdir)/pkgconfig
nodist_pkgconfig_DATA = @PACKAGE_NAME@.pc
DISTCLEANFILES=@PACKAGE_NAME@.pc @PACKAGE_NAME@.pc.in @PACKAGE_NAME@-uninstalled.pc @PACKAGE_NAME@-uninstalled.sh
AC_INIT([libmrutil], [1.0.0])
AM_INIT_AUTOMAKE([foreign subdir-objects -Wall -Werror])
AM_MAINTAINER_MODE([enable])
dnl
dnl Needed for linking on Windows.
dnl Protect with m4_ifdef because AM_PROG_AR is required in
dnl autoconf >= 1.12 when using -Wall, but the macro is
dnl absent in old versions of autoconf.
dnl
m4_ifdef([AM_PROG_AR], [AM_PROG_AR])
LT_INIT
AC_CONFIG_MACRO_DIR([m4])
dnl
dnl Enable silent build rules if this version of Automake supports them
dnl
m4_ifdef([AM_SILENT_RULES], [AM_SILENT_RULES([yes])])
AC_PROG_CXX
AX_CXX_COMPILE_STDCXX([17])
AC_PROG_LIBTOOL
tmpval=`echo $CXXFLAGS | grep -c '\-DMULTIARCH'`
AM_CONDITIONAL([HAVE_MULTIARCH], [test $tmpval -gt 0])
PACKAGE_LIBS="-lmrutil"
dnl
dnl Create pkgconfig .pc file.
dnl
AX_CREATE_PKGCONFIG_INFO(,,,,[])
AC_SUBST([AM_CXXFLAGS])
AC_CONFIG_FILES([Makefile])
AC_OUTPUT
This diff is collapsed.
/*
* This file is part of libsharp2.
*
* libsharp2 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.
*
* libsharp2 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 libsharp2; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* libsharp2 is being developed at the Max-Planck-Institut fuer Astrophysik */
/*! \file sharp.h
* Portable interface for the spherical transform library.
*
* Copyright (C) 2012-2019 Max-Planck-Society
* \author Martin Reinecke \author Dag Sverre Seljebotn
*/
#ifndef SHARP_SHARP_H
#define SHARP_SHARP_H
#include <stddef.h>
#ifdef __cplusplus
extern "C" {
#endif
/*! \internal
Helper type containing information about a single ring. */
typedef struct
{
double theta, phi0, weight, cth, sth;
ptrdiff_t ofs;
int nph, stride;
} sharp_ringinfo;
/*! \internal
Helper type containing information about a pair of rings with colatitudes
symmetric around the equator. */
typedef struct
{
sharp_ringinfo r1,r2;
} sharp_ringpair;
/*! \internal
Type holding all required information about a map geometry. */
typedef struct
{
sharp_ringpair *pair;
int npairs, nphmax;
} sharp_geom_info;
/*! \defgroup almgroup Helpers for dealing with a_lm */
/*! \{ */
/*! \internal
Helper type for index calculation in a_lm arrays. */
typedef struct
{
/*! Maximum \a l index of the array */
int lmax;
/*! Number of different \a m values in this object */
int nm;
/*! Array with \a nm entries containing the individual m values */
int *mval;
/*! Combination of flags from sharp_almflags */
int flags;
/*! Array with \a nm entries containing the (hypothetical) indices of
the coefficients with quantum numbers 0,\a mval[i] */
ptrdiff_t *mvstart;
/*! Stride between a_lm and a_(l+1),m */
ptrdiff_t stride;
} sharp_alm_info;
/*! alm_info flags */
typedef enum { SHARP_PACKED = 1,
/*!< m=0-coefficients are packed so that the (zero) imaginary part is
not present. mvstart is in units of *real* float/double for all
m; stride is in units of reals for m=0 and complex for m!=0 */
SHARP_REAL_HARMONICS = 1<<6
/*!< Use the real spherical harmonic convention. For
m==0, the alm are treated exactly the same as in
the complex case. For m!=0, alm[i] represent a
pair (+abs(m), -abs(m)) instead of (real, imag),
and the coefficients are scaled by a factor of
sqrt(2) relative to the complex case. In other
words, (sqrt(.5) * alm[i]) recovers the
corresponding complex coefficient (when accessed
as complex).
*/
} sharp_almflags;
/*! Creates an a_lm data structure 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 entries with identical \a m, and \a l
differing by 1.
\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 sharp_make_alm_info (int lmax, int mmax, int stride,
const ptrdiff_t *mstart, sharp_alm_info **alm_info);
/*! Creates an a_lm data structure which from the following parameters:
\param lmax maximum \a l quantum number (\a >=0)
\param nm number of different \a m (\a 0<=nm<=lmax+1)
\param stride the stride between entries with identical \a m, and \a l
differing by 1.
\param mval array with \a nm entries containing the individual m values
\param mvstart array with \a nm entries containing the (hypothetical)
indices of the coefficients with the quantum numbers 0,\a mval[i]
\param flags a combination of sharp_almflags (pass 0 unless you know you need this)
\param alm_info will hold a pointer to the newly created data structure
*/
void sharp_make_general_alm_info (int lmax, int nm, int stride, const int *mval,
const ptrdiff_t *mvstart, int flags, sharp_alm_info **alm_info);
/*! Returns the index of the coefficient with quantum numbers \a l,
\a mval[mi].
\note for a \a sharp_alm_info generated by sharp_make_alm_info() this is
the index for the coefficient with the quantum numbers \a l, \a mi. */
ptrdiff_t sharp_alm_index (const sharp_alm_info *self, int l, int mi);
/*! Returns the number of alm coefficients described by \a self. If the SHARP_PACKED
flag is set, this is number of "real" coeffecients (for m < 0 and m >= 0),
otherwise it is the number of complex coefficients (with m>=0). */
ptrdiff_t sharp_alm_count(const sharp_alm_info *self);
/*! Deallocates the a_lm info object. */
void sharp_destroy_alm_info (sharp_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 wgt the pixel weight to be used for the ring in map2alm
and adjoint map2alm transforms.
Pass NULL to use 1.0 as weight for all rings.
\param geom_info will hold a pointer to the newly created data structure
*/
void sharp_make_geom_info (int nrings, const int *nph, const ptrdiff_t *ofs,
const int *stride, const double *phi0, const double *theta,
const double *wgt, sharp_geom_info **geom_info);
/*! Counts the number of grid points needed for (the local part of) a map described
by \a info.
*/
ptrdiff_t sharp_map_size(const sharp_geom_info *info);
/*! Deallocates the geometry information in \a info. */
void sharp_destroy_geom_info (sharp_geom_info *info);
/*! \} */
/*! \defgroup lowlevelgroup Low-level libsharp2 SHT interface */
/*! \{ */
/*! Enumeration of SHARP job types. */
typedef enum { SHARP_YtW=0, /*!< analysis */
SHARP_MAP2ALM=SHARP_YtW, /*!< analysis */
SHARP_Y=1, /*!< synthesis */
SHARP_ALM2MAP=SHARP_Y, /*!< synthesis */
SHARP_Yt=2, /*!< adjoint synthesis */
SHARP_WY=3, /*!< adjoint analysis */
SHARP_ALM2MAP_DERIV1=4 /*!< synthesis of first derivatives */
} sharp_jobtype;
/*! Job flags */
typedef enum { SHARP_DP = 1<<4,
/*!< map and a_lm are in double precision */
SHARP_ADD = 1<<5,
/*!< results are added to the output arrays, instead of
overwriting them */
/* NOTE: SHARP_REAL_HARMONICS, 1<<6, is also available in sharp_jobflags,
but its use here is deprecated in favor of having it in the sharp_alm_info */
SHARP_NO_FFT = 1<<7,
SHARP_USE_WEIGHTS = 1<<20, /* internal use only */
} sharp_jobflags;
/*! Performs a libsharp2 SHT job. The interface deliberately does not use
the C99 "complex" data type, in order to be callable from C89 and C++.
\param type the type of SHT
\param spin the spin of the quantities to be transformed
\param alm contains pointers to the a_lm coefficients. If \a spin==0,
alm[0] points to the a_lm of the SHT. If \a spin>0, alm[0] and alm[1]
point to the two a_lm sets of the SHT. The exact data type of \a alm
depends on whether the SHARP_DP flag is set.
\param map contains pointers to the maps. If \a spin==0,
map[0] points to the map of the SHT. If \a spin>0, or \a type is
SHARP_ALM2MAP_DERIV1, map[0] and map[1] point to the two maps of the SHT.
The exact data type of \a map depends on whether the SHARP_DP flag is set.
\param geom_info A \c sharp_geom_info object compatible with the provided
\a map arrays.
\param alm_info A \c sharp_alm_info object compatible with the provided
\a alm arrays. All \c m values from 0 to some \c mmax<=lmax must be present
exactly once.
\param flags See sharp_jobflags. In particular, if SHARP_DP is set, then
\a alm is expected to have the type "complex double **" and \a map is
expected to have the type "double **"; otherwise, the expected
types are "complex float **" and "float **", respectively.
\param time If not NULL, the wall clock time required for this SHT
(in seconds) will be written here.
\param opcnt If not NULL, a conservative estimate of the total floating point
operation count for this SHT will be written here. */
void sharp_execute (sharp_jobtype type, int spin, void *alm, void *map,
const sharp_geom_info *geom_info, const sharp_alm_info *alm_info,
int flags, double *time, unsigned long long *opcnt);
void sharp_set_chunksize_min(int new_chunksize_min);
void sharp_set_nchunks_max(int new_nchunks_max);
typedef enum { SHARP_ERROR_NO_MPI = 1,
/*!< libsharp2 not compiled with MPI support */
} sharp_errors;
/*! Works like sharp_execute_mpi, but is always present whether or not libsharp2
is compiled with USE_MPI. This is primarily useful for wrapper code etc.
Note that \a pcomm has the type MPI_Comm*, except we declare void* to avoid
pulling in MPI headers. I.e., the comm argument of sharp_execute_mpi
is *(MPI_Comm*)pcomm.
Other parameters are the same as sharp_execute_mpi.
Returns 0 if successful, or SHARP_ERROR_NO_MPI if MPI is not available
(in which case nothing is done).
*/
int sharp_execute_mpi_maybe (void *pcomm, sharp_jobtype type, int spin,
void *alm, void *map, const sharp_geom_info *geom_info,
const sharp_alm_info *alm_info, int flags, double *time,
unsigned long long *opcnt);
/*! \} */
int sharp_get_mlim (int lmax, int spin, double sth, double cth);
int sharp_veclen(void);
const char *sharp_architecture(void);
#ifdef __cplusplus
}
#endif
#endif
/*
* This file is part of libsharp2.
*
* libsharp2 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.
*
* libsharp2 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 libsharp2; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* libsharp2 is being developed at the Max-Planck-Institut fuer Astrophysik */
/*! \file sharp_almhelpers.c
* Spherical transform library
*
* Copyright (C) 2008-2019 Max-Planck-Society
* \author Martin Reinecke
*/
#include "libsharp2/sharp_almhelpers.h"
#include "libsharp2/sharp_utils.h"
void sharp_make_triangular_alm_info (int lmax, int mmax, int stride,
sharp_alm_info **alm_info)
{
sharp_alm_info *info = RALLOC(sharp_alm_info,1);
info->lmax = lmax;
info->nm = mmax+1;
info->mval = RALLOC(int,mmax+1);
info->mvstart = RALLOC(ptrdiff_t,mmax+1);
info->stride = stride;
info->flags = 0;
ptrdiff_t tval = 2*lmax+1;
for (ptrdiff_t m=0; m<=mmax; ++m)
{
info->mval[m] = m;
info->mvstart[m] = stride*((m*(tval-m))>>1);
}
*alm_info = info;
}
void sharp_make_rectangular_alm_info (int lmax, int mmax, int stride,
sharp_alm_info **alm_info)
{
sharp_alm_info *info = RALLOC(sharp_alm_info,1);
info->lmax = lmax;
info->nm = mmax+1;
info->mval = RALLOC(int,mmax+1);
info->mvstart = RALLOC(ptrdiff_t,mmax+1);
info->stride = stride;
info->flags = 0;
for (ptrdiff_t m=0; m<=mmax; ++m)
{
info->mval[m] = m;
info->mvstart[m] = stride*m*(lmax+1);
}
*alm_info = info;
}
void sharp_make_mmajor_real_packed_alm_info (int lmax, int stride,
int nm, const int *ms, sharp_alm_info **alm_info)
{
ptrdiff_t idx;
int f;
sharp_alm_info *info = RALLOC(sharp_alm_info,1);
info->lmax = lmax;
info->nm = nm;
info->mval = RALLOC(int,nm);
info->mvstart = RALLOC(ptrdiff_t,nm);
info->stride = stride;
info->flags = SHARP_PACKED | SHARP_REAL_HARMONICS;
idx = 0; /* tracks the number of 'consumed' elements so far; need to correct by m */
for (int im=0; im!=nm; ++im)
{
int m=(ms==NULL)?im:ms[im];
f = (m==0) ? 1 : 2;
info->mval[im] = m;
info->mvstart[im] = stride * (idx - f * m);
idx += f * (lmax + 1 - m);
}
*alm_info = info;
}
/*
* This file is part of libsharp2.
*
* libsharp2 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.
*
* libsharp2 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 libsharp2; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* libsharp2 is being developed at the Max-Planck-Institut fuer Astrophysik */
/*! \file sharp_almhelpers.h
* SHARP helper function for the creation of a_lm data structures
*
* Copyright (C) 2008-2019 Max-Planck-Society
* \author Martin Reinecke
*/
#ifndef SHARP2_ALMHELPERS_H
#define SHARP2_ALMHELPERS_H
#include "libsharp2/sharp.h"
#ifdef __cplusplus
extern "C" {
#endif
/*! Initialises an a_lm data structure according to the scheme used by
Healpix_cxx.
\ingroup almgroup */
void sharp_make_triangular_alm_info (int lmax, int mmax, int stride,
sharp_alm_info **alm_info);
/*! Initialises an a_lm data structure according to the scheme used by
Fortran Healpix
\ingroup almgroup */
void sharp_make_rectangular_alm_info (int lmax, int mmax, int stride,
sharp_alm_info **alm_info);
/*! Initialises alm_info for mmajor, real, packed spherical harmonics.
Pass \a mmax + 1 to nm and NULL to \a ms in order to use everything;
otherwise you can pick a subset of m to process (should only be used
for MPI parallelization).
\ingroup almgroup */
void sharp_make_mmajor_real_packed_alm_info (int lmax, int stride,
int nm, const int *ms, sharp_alm_info **alm_info);
#ifdef __cplusplus
}
#endif
#endif
/*
* This file is part of libsharp2.
*
* libsharp2 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.
*
* libsharp2 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 libsharp2; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/
/* libsharp2 is being developed at the Max-Planck-Institut fuer Astrophysik */
/*! \file sharp_core.c
* Spherical transform library
*
* Copyright (C) 2019 Max-Planck-Society
* \author Martin Reinecke
*/
#define ARCH default
#define GENERIC_ARCH
#include "libsharp2/sharp_core_inc.cc"
#undef GENERIC_ARCH
#undef ARCH
typedef void (*t_inner_loop) (sharp_job *job, const int *ispair,
const double *cth_, const double *sth_, int llim, int ulim,
sharp_Ylmgen_C *gen, int mi, const int *mlim);
typedef int (*t_veclen) (void);
typedef int (*t_max_nvec) (int spin);
typedef const char *(*t_architecture) (void);
static t_inner_loop inner_loop_ = NULL;
static t_veclen veclen_ = NULL;
static t_max_nvec max_nvec_ = NULL;
static t_architecture architecture_ = NULL;
#ifdef MULTIARCH
#if (defined(___AVX512F__) || defined(__FMA4__) || defined(__FMA__) || \
defined(__AVX2__) || defined(__AVX__))
#error MULTIARCH specified but platform-specific flags detected
#endif
#define DECL(arch) \
static int XCONCATX2(have,arch)(void) \
{ \
static int res=-1; \
if (res<0) \
{ \
__builtin_cpu_init(); \
res = __builtin_cpu_supports(#arch); \
} \
return res; \
} \
\
void XCONCATX2(inner_loop,arch) (sharp_job *job, const int *ispair, \
const double *cth_, const double *sth_, int llim, int ulim, \
sharp_Ylmgen_C *gen, int mi, const int *mlim); \
int XCONCATX2(sharp_veclen,arch) (void); \
int XCONCATX2(sharp_max_nvec,arch) (int spin); \
const char *XCONCATX2(sharp_architecture,arch) (void);
#if (!defined(__APPLE__))
DECL(avx512f)
#endif
DECL(fma4)
DECL(fma)
DECL(avx2)
DECL(avx)
#endif
static void assign_funcs(void)
{
#ifdef MULTIARCH
#define DECL2(arch) \
if (XCONCATX2(have,arch)()) \
{ \
inner_loop_ = XCONCATX2(inner_loop,arch); \
veclen_ = XCONCATX2(sharp_veclen,arch); \
max_nvec_ = XCONCATX2(sharp_max_nvec,arch); \
architecture_ = XCONCATX2(sharp_architecture,arch); \
return; \
}
#if (!defined(__APPLE__))
DECL2(avx512f)
#endif