Update cosmotool 2nd part

This commit is contained in:
Guilhem Lavaux 2018-07-19 15:11:23 +03:00
parent 64e05fc180
commit 003bc39d4a
70 changed files with 8708 additions and 0 deletions

View file

@ -0,0 +1,101 @@
#ifndef __MPI_FFTW_UNIFIED_CALLS_HPP
#define __MPI_FFTW_UNIFIED_CALLS_HPP
#include <complex>
#include <mpi.h>
#include <fftw3-mpi.h>
namespace CosmoTool
{
static inline void init_fftw_mpi()
{
fftw_mpi_init();
}
static inline void done_fftw_mpi()
{
fftw_mpi_cleanup();
}
template<typename T> class FFTW_MPI_Calls {};
#define FFTW_MPI_CALLS_BASE(rtype, prefix) \
template<> \
class FFTW_MPI_Calls<rtype> { \
public: \
typedef rtype real_type; \
typedef prefix ## _complex complex_type; \
typedef prefix ## _plan plan_type; \
\
static complex_type *alloc_complex(size_t N) { return prefix ## _alloc_complex(N); } \
static real_type *alloc_real(size_t N) { return prefix ## _alloc_real(N); } \
static void free(void *p) { fftw_free(p); } \
\
static ptrdiff_t local_size_2d(ptrdiff_t N0, ptrdiff_t N1, MPI_Comm comm, \
ptrdiff_t *local_n0, ptrdiff_t *local_0_start) { \
return prefix ## _mpi_local_size_2d(N0, N1, comm, local_n0, local_0_start); \
} \
\
static ptrdiff_t local_size_3d(ptrdiff_t N0, ptrdiff_t N1, ptrdiff_t N2, MPI_Comm comm, \
ptrdiff_t *local_n0, ptrdiff_t *local_0_start) { \
return prefix ## _mpi_local_size_3d(N0, N1, N2, comm, local_n0, local_0_start); \
} \
\
static void execute(plan_type p) { prefix ## _execute(p); } \
static void execute_r2c(plan_type p, real_type *in, complex_type *out) { prefix ## _mpi_execute_dft_r2c(p, in, out); } \
static void execute_c2r(plan_type p, std::complex<real_type> *in, real_type *out) { prefix ## _mpi_execute_dft_c2r(p, (complex_type*)in, out); } \
static void execute_c2r(plan_type p, complex_type *in, real_type *out) { prefix ## _mpi_execute_dft_c2r(p, in, out); } \
static void execute_r2c(plan_type p, real_type *in, std::complex<real_type> *out) { prefix ## _mpi_execute_dft_r2c(p, in, (complex_type*)out); } \
\
static plan_type plan_dft_r2c_2d(int Nx, int Ny, \
real_type *in, complex_type *out, \
MPI_Comm comm, unsigned flags) \
{ \
return prefix ## _mpi_plan_dft_r2c_2d(Nx, Ny, in, out, \
comm, flags); \
} \
static plan_type plan_dft_c2r_2d(int Nx, int Ny, \
complex_type *in, real_type *out, \
MPI_Comm comm, unsigned flags) \
{ \
return prefix ## _mpi_plan_dft_c2r_2d(Nx, Ny, in, out, \
comm, flags); \
} \
static plan_type plan_dft_r2c_3d(int Nx, int Ny, int Nz, \
real_type *in, complex_type *out, \
MPI_Comm comm, unsigned flags) \
{ \
return prefix ## _mpi_plan_dft_r2c_3d(Nx, Ny, Nz, in, out, comm, flags); \
} \
static plan_type plan_dft_c2r_3d(int Nx, int Ny, int Nz, \
complex_type *in, real_type *out, \
MPI_Comm comm, \
unsigned flags) \
{ \
return prefix ## _mpi_plan_dft_c2r_3d(Nx, Ny, Nz, in, out, comm, flags); \
} \
\
static plan_type plan_dft_r2c(int rank, const ptrdiff_t *n, real_type *in, \
complex_type *out, MPI_Comm comm, unsigned flags) \
{ \
return prefix ## _mpi_plan_dft_r2c(rank, n, in, out, comm, flags); \
} \
static plan_type plan_dft_c2r(int rank, const ptrdiff_t *n, complex_type *in, \
real_type *out, MPI_Comm comm, unsigned flags) \
{ \
return prefix ## _mpi_plan_dft_c2r(rank, n, in, out, comm, flags); \
} \
static void destroy_plan(plan_type plan) { prefix ## _destroy_plan(plan); } \
}
FFTW_MPI_CALLS_BASE(double, fftw);
FFTW_MPI_CALLS_BASE(float, fftwf);
#undef FFTW_MPI_CALLS_BASE
};
#endif

View file

@ -0,0 +1,42 @@
#ifndef __COSMOTOOL_FFT_COMPLEX_HPP
#define __COSMOTOOL_FFT_COMPLEX_HPP
#include <complex>
#include <fftw3.h>
namespace CosmoTool
{
template<typename T>
struct adapt_complex {
};
template<> struct adapt_complex<fftw_complex> {
typedef fftw_complex f_type;
typedef std::complex<double> cpp_complex;
static inline cpp_complex *adapt(f_type *a) {
return reinterpret_cast<cpp_complex *>(a);
}
};
template<> struct adapt_complex<fftwf_complex> {
typedef fftwf_complex f_type;
typedef std::complex<float> cpp_complex;
static inline cpp_complex *adapt(f_type *a) {
return reinterpret_cast<cpp_complex *>(a);
}
};
template<> struct adapt_complex<fftwl_complex> {
typedef fftwl_complex f_type;
typedef std::complex<long double> cpp_complex;
static inline cpp_complex *adapt(f_type *a) {
return reinterpret_cast<cpp_complex *>(a);
}
};
}
#endif

487
external/cosmotool/src/hdf5_array.hpp vendored Normal file
View file

@ -0,0 +1,487 @@
/*+
This is CosmoTool (./src/hdf5_array.hpp) -- Copyright (C) Guilhem Lavaux (2007-2014)
guilhem.lavaux@gmail.com
This software is a computer program whose purpose is to provide a toolbox for cosmological
data analysis (e.g. filters, generalized Fourier transforms, power spectra, ...)
This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info".
As a counterpart to the access to the source code and rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors have only limited
liability.
In this respect, the user's attention is drawn to the risks associated
with loading, using, modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
sthat may mean that it is complicated to manipulate, and that also
therefore means that it is reserved for developers and experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or
data to be ensured and, more generally, to use and operate it in the
same conditions as regards security.
The fact that you are presently reading this means that you have had
knowledge of the CeCILL license and that you accept its terms.
+*/
#ifndef __COSMO_HDF5_ARRAY_HPP
#define __COSMO_HDF5_ARRAY_HPP
#include <string>
#include <stdint.h>
#include <boost/static_assert.hpp>
#include <boost/utility.hpp>
#include <boost/mpl/assert.hpp>
#include <boost/multi_array.hpp>
#include <boost/type_traits/is_same.hpp>
#include <boost/type_traits/is_floating_point.hpp>
#include <boost/preprocessor/cat.hpp>
#include <boost/preprocessor/stringize.hpp>
#include <boost/preprocessor/seq/for_each.hpp>
#include <vector>
#include <H5Cpp.h>
namespace CosmoTool {
#if (H5_VERS_MAJOR == 1) && (H5_VERS_MINOR <= 8)
typedef H5::CommonFG H5_CommonFileGroup;
#else
typedef H5::Group H5_CommonFileGroup;
#endif
//!_______________________________________________________________________________________
//!
//! map types to HDF5 types
//!
//!
//! Leo Goodstadt (04 March 2013), improved with enable_if by Guilhem Lavaux (May 2014)
//!_______________________________________________________________________________________
template<typename T, class Enable = void> struct get_hdf5_data_type
{
static H5::DataType type()
{
BOOST_MPL_ASSERT_MSG(0, Unknown_HDF5_data_type, ());
return H5::PredType::NATIVE_DOUBLE;
}
};
//, typename boost::enable_if<boost::is_same<T, tl> >::type> \
//
#define HDF5_TYPE(tl, thdf5) \
template<typename T> struct get_hdf5_data_type<T, typename boost::enable_if<boost::is_same<T,tl> >::type > \
{ static H5::DataType type() { return H5::PredType::thdf5; }; }
#define HDF5_SAFE_TYPE(tl, othertl, thdf5) \
template<typename T> struct get_hdf5_data_type<T, \
typename boost::enable_if< \
boost::integral_constant<bool, \
boost::is_same<T, tl>::value \
&& !boost::is_same<T,othertl>::value > \
>::type \
> \
{ static H5::DataType type() { return H5::PredType::thdf5; }; }
HDF5_SAFE_TYPE(long, int , NATIVE_LONG);
HDF5_SAFE_TYPE(unsigned long, unsigned int , NATIVE_ULONG);
HDF5_SAFE_TYPE(long long, long , NATIVE_LLONG);
HDF5_SAFE_TYPE(unsigned long long, unsigned long, NATIVE_ULLONG);
HDF5_TYPE(char , NATIVE_CHAR);
HDF5_TYPE(unsigned char , NATIVE_UCHAR);
HDF5_TYPE(int , NATIVE_INT);
HDF5_TYPE(unsigned int , NATIVE_UINT);
HDF5_TYPE(float , NATIVE_FLOAT);
HDF5_TYPE(double , NATIVE_DOUBLE);
#undef HDF5_TYPE
#undef HDF5_SAFE_TYPE
// Extent generator
template<std::size_t r>
struct hdf5_extent_gen {
typedef typename boost::detail::multi_array::extent_gen<r> type;
static inline type build(hsize_t *d)
{
return (hdf5_extent_gen<r-1>::build(d))[d[r-1]];
}
};
template<>
struct hdf5_extent_gen<0> {
static inline boost::multi_array_types::extent_gen build(hsize_t *d)
{
return boost::extents;
}
};
//!_______________________________________________________________________________________
//!
//! write_hdf5 multi_array
//!
//! \author Guilhem Lavaux (2014-2015)
//! \author leo Goodstadt (04 March 2013)
//!
//!_______________________________________________________________________________________
template<typename ArrayType, typename hdf5_data_type>
void hdf5_write_array(H5_CommonFileGroup& fg, const std::string& data_set_name,
const ArrayType& data,
const hdf5_data_type& datatype,
const std::vector<hsize_t>& dimensions,
bool doCreate = true,
bool useBases = false)
{
std::vector<hsize_t> memdims(data.shape(), data.shape() + data.num_dimensions());
H5::DataSpace dataspace(dimensions.size(), dimensions.data());
H5::DataSpace memspace(memdims.size(), memdims.data());
if (useBases) {
std::vector<hsize_t> offsets(data.index_bases(), data.index_bases() + data.num_dimensions());
dataspace.selectHyperslab(H5S_SELECT_SET, memdims.data(), offsets.data());
}
H5::DataSet dataset;
if (doCreate)
dataset = fg.createDataSet(data_set_name, datatype, dataspace);
else
dataset = fg.openDataSet(data_set_name);
dataset.write(data.data(), datatype, memspace, dataspace);
}
template<typename ArrayType, typename hdf5_data_type>
void hdf5_write_array(H5_CommonFileGroup& fg, const std::string& data_set_name,
const ArrayType& data,
const hdf5_data_type& datatype,
bool doCreate = true,
bool useBases = false)
{
std::vector<hsize_t> dimensions(data.shape(), data.shape() + data.num_dimensions());
hdf5_write_array(fg, data_set_name, data, datatype, dimensions, doCreate, useBases);
}
/* HDF5 complex type */
template<typename T>
class hdf5_ComplexType
{
public:
H5::CompType type;
hdf5_ComplexType()
: type(sizeof(std::complex<T>))
{
get_hdf5_data_type<T> hdf_data_type;
type.insertMember("r", 0, hdf_data_type.type());
type.insertMember("i", sizeof(T), hdf_data_type.type());
type.pack();
}
static const hdf5_ComplexType<T> *ctype()
{
static hdf5_ComplexType<T> singleton;
return &singleton;
}
};
template<> struct get_hdf5_data_type<std::complex<float> > {
static H5::DataType type() {
return hdf5_ComplexType<float>::ctype()->type;
}
};
template<> struct get_hdf5_data_type<std::complex<double> > {
static H5::DataType type() {
return hdf5_ComplexType<double>::ctype()->type;
}
};
class hdf5_StringType
{
public:
H5::StrType type;
hdf5_StringType()
: type(0, H5T_VARIABLE)
{
}
static const hdf5_StringType *ctype()
{
static hdf5_StringType singleton;
return &singleton;
}
};
template<> struct get_hdf5_data_type<std::string> {
static H5::DataType type() {
return hdf5_StringType::ctype()->type;
}
};
class hdf5_BoolType
{
public:
H5::EnumType type;
hdf5_BoolType()
: type(sizeof(bool))
{
bool v;
v = true;
type.insert("TRUE", &v);
v = false;
type.insert("FALSE", &v);
}
static const hdf5_BoolType *ctype()
{
static hdf5_BoolType singleton;
return &singleton;
}
};
template<> struct get_hdf5_data_type<bool> {
static H5::DataType type() {
return hdf5_BoolType::ctype()->type;
}
};
template<typename ArrayType>
void hdf5_write_array(H5_CommonFileGroup& fg, const std::string& data_set_name, const ArrayType& data )
{
typedef typename ArrayType::element T;
get_hdf5_data_type<T> hdf_data_type;
hdf5_write_array(fg, data_set_name, data, hdf_data_type.type());
}
// HDF5 array reader
//
// Author Guilhem Lavaux (May 2014)
class InvalidDimensions: virtual std::exception {
};
// ----------------------------------------------------------------------
// Conditional resize support
// If the Array type support resize then it is called. Otherwise
// the dimensions are checked and lead to a failure if they are different
template<typename Array> class array_has_resize {
struct Fallback { int resize; };
struct Derived: Array, Fallback {};
typedef char yes[1];
typedef char no[2];
template<typename U, U> struct Check;
template<typename U>
static yes& func(Check<int Fallback::*, &U::resize> *);
template<typename U>
static no& func(...);
public:
typedef array_has_resize type;
enum { value = sizeof(func<Derived>(0)) == sizeof(no) };
};
template<typename ArrayType>
typename boost::enable_if<
array_has_resize<ArrayType>
>::type
hdf5_resize_array(ArrayType& data, std::vector<hsize_t>& dims) {
data.resize(
hdf5_extent_gen<ArrayType::dimensionality>::build(dims.data())
);
}
template<typename ArrayType>
void hdf5_check_array(ArrayType& data, std::vector<hsize_t>& dims) {
for (size_t i = 0; i < data.num_dimensions(); i++) {
if (data.shape()[i] != dims[i]) {
throw InvalidDimensions();
}
}
}
template<typename ArrayType>
void hdf5_weak_check_array(ArrayType& data, std::vector<hsize_t>& dims) {
for (size_t i = 0; i < data.num_dimensions(); i++) {
if (data.index_bases()[i] < 0) {
// Negative indexes are not supported right now.
throw InvalidDimensions();
}
if (data.index_bases()[i]+data.shape()[i] > dims[i]) {
throw InvalidDimensions();
}
}
}
template<typename ArrayType>
typename boost::disable_if<
array_has_resize<ArrayType>
>::type
hdf5_resize_array(ArrayType& data, std::vector<hsize_t>& dims) {
hdf5_check_array(data, dims);
}
// ----------------------------------------------------------------------
template<typename ArrayType, typename hdf5_data_type>
void hdf5_read_array_typed(H5_CommonFileGroup& fg, const std::string& data_set_name,
ArrayType& data,
const hdf5_data_type& datatype, bool auto_resize = true, bool useBases = false)
{
H5::DataSet dataset = fg.openDataSet(data_set_name);
H5::DataSpace dataspace = dataset.getSpace();
std::vector<hsize_t> dimensions(data.num_dimensions());
if ((size_t)dataspace.getSimpleExtentNdims() != (size_t)data.num_dimensions())
{
throw InvalidDimensions();
}
dataspace.getSimpleExtentDims(dimensions.data());
if (auto_resize)
hdf5_resize_array(data, dimensions);
else {
if (useBases) {
hdf5_weak_check_array(data, dimensions);
std::vector<hsize_t> memdims(data.shape(), data.shape() + data.num_dimensions());
H5::DataSpace memspace(memdims.size(), memdims.data());
std::vector<hsize_t> offsets(data.index_bases(), data.index_bases() + data.num_dimensions());
dataspace.selectHyperslab(H5S_SELECT_SET, memdims.data(), offsets.data());
dataset.read(data.data(), datatype, memspace, dataspace);
return;
} else {
hdf5_check_array(data, dimensions);
}
}
dataset.read(data.data(), datatype);
}
template<typename ArrayType>
void hdf5_read_array(H5_CommonFileGroup& fg, const std::string& data_set_name, ArrayType& data, bool auto_resize = true,
bool useBases = false )
{
typedef typename ArrayType::element T;
hdf5_read_array_typed(fg, data_set_name, data, get_hdf5_data_type<T>::type(), auto_resize, useBases);
}
#define CTOOL_HDF5_NAME(STRUCT) BOOST_PP_CAT(hdf5_,STRUCT)
#define CTOOL_HDF5_INSERT_ELEMENT(r, STRUCT, element) \
{ \
::CosmoTool::get_hdf5_data_type<BOOST_PP_TUPLE_ELEM(2, 0, element)> t; \
position = HOFFSET(STRUCT, BOOST_PP_TUPLE_ELEM(2, 1, element)); \
const char *field_name = BOOST_PP_STRINGIZE(BOOST_PP_TUPLE_ELEM(2, 1, element)); \
type.insertMember(field_name, position, t.type()); \
}
#define CTOOL_STRUCT_TYPE(STRUCT, TNAME, ATTRIBUTES) \
namespace CosmoTool { \
class TNAME { \
public: \
H5::CompType type; \
\
TNAME() : type(sizeof(STRUCT)) \
{ \
long position; \
BOOST_PP_SEQ_FOR_EACH(CTOOL_HDF5_INSERT_ELEMENT, STRUCT, ATTRIBUTES) \
} \
\
static const TNAME *ctype() \
{ \
static TNAME singleton; \
return &singleton; \
} \
}; \
template<> struct get_hdf5_data_type<STRUCT> { \
static H5::DataType type() { return TNAME::ctype()->type; }; \
}; \
};
#define CTOOL_HDF5_INSERT_ENUM_ELEMENT(r, STRUCT, element) \
{ \
const char *field_name = BOOST_PP_STRINGIZE(element); \
STRUCT a = element; \
type.insert(field_name, &a); \
}
#define CTOOL_ENUM_TYPE(STRUCT, TNAME, ATTRIBUTES) \
namespace CosmoTool { \
class TNAME { \
public: \
H5::EnumType type; \
\
TNAME() : type(sizeof(STRUCT)) \
{ \
long position; \
BOOST_PP_SEQ_FOR_EACH(CTOOL_HDF5_INSERT_ENUM_ELEMENT, STRUCT, ATTRIBUTES) \
} \
\
static const TNAME *ctype() \
{ \
static TNAME singleton; \
return &singleton; \
} \
}; \
template<> struct get_hdf5_data_type<STRUCT> { \
static H5::DataType type() { return TNAME::ctype()->type; }; \
}; \
};
#define CTOOL_ARRAY_TYPE(ARRAY_TYPE, DIM, TNAME) \
namespace CosmoTool { \
class TNAME { \
public: \
H5::ArrayType *type; \
\
TNAME() \
{ \
hsize_t dims[1] = { DIM }; \
type = new H5::ArrayType(get_hdf5_data_type<ARRAY_TYPE>::type(), 1, dims); \
} \
~TNAME() { delete type; } \
\
static const TNAME *ctype() \
{ \
static TNAME singleton; \
return &singleton; \
} \
}; \
\
template<> struct get_hdf5_data_type< ARRAY_TYPE[DIM] > { \
static H5::DataType type() { return *(TNAME::ctype()->type); }; \
}; \
};
};
#endif

217
external/cosmotool/src/octTree.tcc vendored Normal file
View file

@ -0,0 +1,217 @@
/*+
This is CosmoTool (./src/octTree.cpp) -- Copyright (C) Guilhem Lavaux (2007-2014)
guilhem.lavaux@gmail.com
This software is a computer program whose purpose is to provide a toolbox for cosmological
data analysis (e.g. filters, generalized Fourier transforms, power spectra, ...)
This software is governed by the CeCILL license under French law and
abiding by the rules of distribution of free software. You can use,
modify and/ or redistribute the software under the terms of the CeCILL
license as circulated by CEA, CNRS and INRIA at the following URL
"http://www.cecill.info".
As a counterpart to the access to the source code and rights to copy,
modify and redistribute granted by the license, users are provided only
with a limited warranty and the software's author, the holder of the
economic rights, and the successive licensors have only limited
liability.
In this respect, the user's attention is drawn to the risks associated
with loading, using, modifying and/or developing or reproducing the
software by the user in light of its specific status of free software,
that may mean that it is complicated to manipulate, and that also
therefore means that it is reserved for developers and experienced
professionals having in-depth computer knowledge. Users are therefore
encouraged to load and test the software's suitability as regards their
requirements in conditions enabling the security of their systems and/or
data to be ensured and, more generally, to use and operate it in the
same conditions as regards security.
The fact that you are presently reading this means that you have had
knowledge of the CeCILL license and that you accept its terms.
+*/
#include <iostream>
#include <cmath>
#include <cassert>
#include "config.hpp"
#include "octTree.hpp"
namespace CosmoTool {
using namespace std;
//#define VERBOSE
static uint32_t mypow(uint32_t i, uint32_t p)
{
if (p == 0)
return 1;
else if (p == 1)
return i;
uint32_t k = p/2;
uint32_t j = mypow(i, k);
if (2*k==p)
return j*j;
else
return j*j*i;
}
template<typename Updater, typename T>
OctTree<Updater,T>::OctTree(const FCoordinates *particles, octPtr numParticles,
uint32_t maxMeanTreeDepth, uint32_t maxAbsoluteDepth,
uint32_t threshold)
{
cout << "MeanTree=" << maxMeanTreeDepth << endl;
numCells = mypow(8, maxMeanTreeDepth);
assert(numCells < invalidOctCell);
//#ifdef VERBOSE
cerr << "Allocating " << numCells << " octtree cells" << endl;
//#endif
for (int j = 0; j < 3; j++)
xMin[j] = particles[0][j];
for (octPtr i = 1; i < numParticles; i++)
{
for (int j = 0; j < 3; j++)
{
if (particles[i][j] < xMin[j])
xMin[j] = particles[i][j];
}
}
lenNorm = 0;
for (octPtr i = 0; i < numParticles; i++)
{
for (int j = 0; j < 3; j++)
{
float delta = particles[i][j]-xMin[j];
if (delta > lenNorm)
lenNorm = delta;
}
}
cout << xMin[0] << " " << xMin[1] << " " << xMin[2] << " lNorm=" << lenNorm << endl;
cells = new OctCell<T>[numCells];
Lbox = (float)(octCoordTypeNorm+1);
cells[0].numberLeaves = 0;
for (int i = 0; i < 8; i++)
cells[0].children[i] = emptyOctCell;
lastNode = 1;
this->particles = particles;
this->numParticles = numParticles;
buildTree(maxAbsoluteDepth);
//#ifdef VERBOSE
cerr << "Used " << lastNode << " cells" << endl;
//#endif
}
template<typename Updater, typename T>
OctTree<Updater,T>::~OctTree()
{
delete cells;
}
template<typename Updater, typename T>
void OctTree<Updater,T>::buildTree(uint32_t maxAbsoluteDepth)
{
for (octPtr i = 0; i < numParticles; i++)
{
OctCoords rootCenter = { octCoordCenter, octCoordCenter, octCoordCenter };
insertParticle(0, // root node
rootCenter,
octCoordCenter,
i,
maxAbsoluteDepth);
}
}
template<typename Updater, typename T>
void OctTree<Updater,T>::insertParticle(octPtr node,
const OctCoords& icoord,
octCoordType halfNodeLength,
octPtr particleId,
uint32_t maxAbsoluteDepth)
{
#ifdef VERBOSE
cout << "Entering " << node << " (" << icoord[0] << "," << icoord[1] << "," << icoord[2] << ")" << endl;
#endif
int octPos = 0;
int ipos[3] = { 0,0,0};
octPtr newNode;
OctCoords newCoord;
cells[node].numberLeaves++;
if (maxAbsoluteDepth == 0)
{
// All children must be invalid.
for (int i = 0 ; i < 8; i++)
cells[node].children[i] = invalidOctCell;
return;
}
for (int j = 0; j < 3; j++)
{
float treePos = (particles[particleId][j]-xMin[j])*Lbox/lenNorm;
if ((octPtr)(treePos) > icoord[j])
{
octPos |= (1 << j);
ipos[j] = 1;
}
}
if (cells[node].children[octPos] == emptyOctCell)
{
// Put the particle there.
cells[node].children[octPos] = particleId | octParticleMarker;
return;
}
// If it is a node, explores it.
if (!(cells[node].children[octPos] & octParticleMarker))
{
assert(halfNodeLength >= 2);
// Compute coordinates
for (int j = 0; j < 3; j++)
newCoord[j] = icoord[j]+(2*ipos[j]-1)*halfNodeLength/2;
insertParticle(cells[node].children[octPos], newCoord, halfNodeLength/2,
particleId, maxAbsoluteDepth-1);
return;
}
// We have a particle there.
// Make a new node and insert the old particle into this node.
// Insert the new particle into the node also
// Finally put the node in place
newNode = lastNode++;
assert(lastNode != numCells);
for (int j = 0; j < 8; j++)
cells[newNode].children[j] = emptyOctCell;
cells[newNode].numberLeaves = 0;
// Compute coordinates
for (int j = 0; j < 3; j++)
newCoord[j] = icoord[j]+(2*ipos[j]-1)*halfNodeLength/2;
octPtr oldPartId = cells[node].children[octPos] & octParticleMask;
insertParticle(newNode, newCoord, halfNodeLength/2,
oldPartId, maxAbsoluteDepth-1);
insertParticle(newNode, newCoord, halfNodeLength/2,
particleId, maxAbsoluteDepth-1);
cells[node].children[octPos] = newNode;
}
};

44
external/cosmotool/src/openmp.hpp vendored Normal file
View file

@ -0,0 +1,44 @@
#ifndef __CTOOL_OPENMP_HPP
#define __CTOOL_OPENMP_HPP
#ifdef _OPENMP
#include <omp.h>
#endif
namespace CosmoTool {
static int smp_get_max_threads() {
#ifdef _OPENMP
return omp_get_max_threads();
#else
return 1;
#endif
}
static int smp_get_thread_id() {
#ifdef _OPENMP
return omp_get_thread_num();
#else
return 0;
#endif
}
static int smp_get_num_threads() {
#ifdef _OPENMP
return omp_get_num_threads();
#else
return 1;
#endif
}
static void smp_set_nested(bool n) {
#ifdef _OPENMP
omp_set_nested(n ? 1 : 0);
#endif
}
};
#endif

View file

@ -0,0 +1,32 @@
#ifndef __COSMOTOOL_SYMBOL_VISIBLE_HPP
#define __COSMOTOOL_SYMBOL_VISIBLE_HPP
#if defined _WIN32 || defined __CYGWIN__
#ifdef BUILDING_DLL
#ifdef __GNUC__
#define CTOOL_DLL_PUBLIC __attribute__ ((dllexport))
#else
#define CTOOL_DLL_PUBLIC __declspec(dllexport) // Note: actually gcc seems to also supports this syntax.
#endif
#else
#ifdef __GNUC__
#define CTOOL_DLL_PUBLIC __attribute__ ((dllimport))
#else
#define CTOOL_DLL_PUBLIC __declspec(dllimport) // Note: actually gcc seems to also supports this syntax.
#endif
#endif
#define CTOOL_DLL_LOCAL
#else
#if __GNUC__ >= 4
#define CTOOL_DLL_PUBLIC __attribute__ ((visibility ("default")))
#define CTOOL_DLL_LOCAL __attribute__ ((visibility ("hidden")))
#else
#define CTOOL_DLL_PUBLIC
#define CTOOL_DLL_LOCAL
#endif
#endif
#endif

313
external/cosmotool/src/tf_fit.hpp vendored Normal file
View file

@ -0,0 +1,313 @@
/* The following routines implement all of the fitting formulae in
Eisenstein \& Hu (1997) */
/* There are two sets of routines here. The first set,
TFfit_hmpc(), TFset_parameters(), and TFfit_onek(),
calculate the transfer function for an arbitrary CDM+baryon universe using
the fitting formula in Section 3 of the paper. The second set,
TFsound_horizon_fit(), TFk_peak(), TFnowiggles(), and TFzerobaryon(),
calculate other quantities given in Section 4 of the paper. */
#include <math.h>
#include <stdio.h>
/* ------------------------ DRIVER ROUTINE --------------------------- */
/* The following is an example of a driver routine you might use. */
/* Basically, the driver routine needs to call TFset_parameters() to
set all the scalar parameters, and then call TFfit_onek() for each
wavenumber k you desire. */
/* While the routines use Mpc^-1 units internally, this driver has been
written to take an array of wavenumbers in units of h Mpc^-1. On the
other hand, if you want to use Mpc^-1 externally, you can do this by
altering the variables you pass to the driver:
omega0 -> omega0*hubble*hubble, hubble -> 1.0 */
/* INPUT: omega0 -- the matter density (baryons+CDM) in units of critical
f_baryon -- the ratio of baryon density to matter density
hubble -- the Hubble constant, in units of 100 km/s/Mpc
Tcmb -- the CMB temperature in Kelvin. T<=0 uses the COBE value 2.728.
numk -- the length of the following zero-offset array
k[] -- the array of wavevectors k[0..numk-1] */
/* INPUT/OUTPUT: There are three output arrays of transfer functions.
All are zero-offset and, if used, must have storage [0..numk-1] declared
in the calling program. However, if you substitute the NULL pointer for
one or more of the arrays, then that particular transfer function won't
be outputted. The transfer functions are:
tf_full[] -- The full fitting formula, eq. (16), for the matter
transfer function.
tf_baryon[] -- The baryonic piece of the full fitting formula, eq. 21.
tf_cdm[] -- The CDM piece of the full fitting formula, eq. 17. */
/* Again, you can set these pointers to NULL in the function call if
you don't want a particular output. */
/* Various intermediate scalar quantities are stored in global variables,
so that you might more easily access them. However, this also means that
you would be better off not simply #include'ing this file in your programs,
but rather compiling it separately, calling only the driver, and using
extern declarations to access the intermediate quantities. */
/* ------------------------ FITTING FORMULAE ROUTINES ----------------- */
/* There are two routines here. TFset_parameters() sets all the scalar
parameters, while TFfit_onek() calculates the transfer function for a
given wavenumber k. TFfit_onek() may be called many times after a single
call to TFset_parameters() */
/* Global variables -- We've left many of the intermediate results as
global variables in case you wish to access them, e.g. by declaring
them as extern variables in your main program. */
/* Note that all internal scales are in Mpc, without any Hubble constants! */
namespace CosmoTool {
struct TF_Transfer {
float omhh, /* Omega_matter*h^2 */
obhh, /* Omega_baryon*h^2 */
theta_cmb, /* Tcmb in units of 2.7 K */
z_equality, /* Redshift of matter-radiation equality, really 1+z */
k_equality, /* Scale of equality, in Mpc^-1 */
z_drag, /* Redshift of drag epoch */
R_drag, /* Photon-baryon ratio at drag epoch */
R_equality, /* Photon-baryon ratio at equality epoch */
sound_horizon, /* Sound horizon at drag epoch, in Mpc */
k_silk, /* Silk damping scale, in Mpc^-1 */
alpha_c, /* CDM suppression */
beta_c, /* CDM log shift */
alpha_b, /* Baryon suppression */
beta_b, /* Baryon envelope shift */
beta_node, /* Sound horizon shift */
k_peak, /* Fit to wavenumber of first peak, in Mpc^-1 */
sound_horizon_fit, /* Fit to sound horizon, in Mpc */
alpha_gamma; /* Gamma suppression in approximate TF */
/* Convenience from Numerical Recipes in C, 2nd edition */
float sqrarg;
#define SQR(a) ((sqrarg=(a)) == 0.0 ? 0.0 : sqrarg*sqrarg)
float cubearg;
#define CUBE(a) ((cubearg=(a)) == 0.0 ? 0.0 : cubearg*cubearg*cubearg)
float pow4arg;
#define POW4(a) ((pow4arg=(a)) == 0.0 ? 0.0 : pow4arg*pow4arg*pow4arg*pow4arg)
/* Yes, I know the last one isn't optimal; it doesn't appear much */
void TFset_parameters(float omega0hh, float f_baryon, float Tcmb)
/* Set all the scalars quantities for Eisenstein & Hu 1997 fitting formula */
/* Input: omega0hh -- The density of CDM and baryons, in units of critical dens,
multiplied by the square of the Hubble constant, in units
of 100 km/s/Mpc */
/* f_baryon -- The fraction of baryons to CDM */
/* Tcmb -- The temperature of the CMB in Kelvin. Tcmb<=0 forces use
of the COBE value of 2.728 K. */
/* Output: Nothing, but set many global variables used in TFfit_onek().
You can access them yourself, if you want. */
/* Note: Units are always Mpc, never h^-1 Mpc. */
{
float z_drag_b1, z_drag_b2;
float alpha_c_a1, alpha_c_a2, beta_c_b1, beta_c_b2, alpha_b_G, y;
if (f_baryon<=0.0 || omega0hh<=0.0) {
fprintf(stderr, "TFset_parameters(): Illegal input.\n");
exit(1);
}
omhh = omega0hh;
obhh = omhh*f_baryon;
if (Tcmb<=0.0) Tcmb=2.728; /* COBE FIRAS */
theta_cmb = Tcmb/2.7;
z_equality = 2.50e4*omhh/POW4(theta_cmb); /* Really 1+z */
k_equality = 0.0746*omhh/SQR(theta_cmb);
z_drag_b1 = 0.313*pow(omhh,-0.419)*(1+0.607*pow(omhh,0.674));
z_drag_b2 = 0.238*pow(omhh,0.223);
z_drag = 1291*pow(omhh,0.251)/(1+0.659*pow(omhh,0.828))*
(1+z_drag_b1*pow(obhh,z_drag_b2));
R_drag = 31.5*obhh/POW4(theta_cmb)*(1000/(1+z_drag));
R_equality = 31.5*obhh/POW4(theta_cmb)*(1000/z_equality);
sound_horizon = 2./3./k_equality*sqrt(6./R_equality)*
log((sqrt(1+R_drag)+sqrt(R_drag+R_equality))/(1+sqrt(R_equality)));
k_silk = 1.6*pow(obhh,0.52)*pow(omhh,0.73)*(1+pow(10.4*omhh,-0.95));
alpha_c_a1 = pow(46.9*omhh,0.670)*(1+pow(32.1*omhh,-0.532));
alpha_c_a2 = pow(12.0*omhh,0.424)*(1+pow(45.0*omhh,-0.582));
alpha_c = pow(alpha_c_a1,-f_baryon)*
pow(alpha_c_a2,-CUBE(f_baryon));
beta_c_b1 = 0.944/(1+pow(458*omhh,-0.708));
beta_c_b2 = pow(0.395*omhh, -0.0266);
beta_c = 1.0/(1+beta_c_b1*(pow(1-f_baryon, beta_c_b2)-1));
y = z_equality/(1+z_drag);
alpha_b_G = y*(-6.*sqrt(1+y)+(2.+3.*y)*log((sqrt(1+y)+1)/(sqrt(1+y)-1)));
alpha_b = 2.07*k_equality*sound_horizon*pow(1+R_drag,-0.75)*alpha_b_G;
beta_node = 8.41*pow(omhh, 0.435);
beta_b = 0.5+f_baryon+(3.-2.*f_baryon)*sqrt(pow(17.2*omhh,2.0)+1);
k_peak = 2.5*3.14159*(1+0.217*omhh)/sound_horizon;
sound_horizon_fit = 44.5*log(9.83/omhh)/sqrt(1+10.0*pow(obhh,0.75));
alpha_gamma = 1-0.328*log(431.0*omhh)*f_baryon + 0.38*log(22.3*omhh)*
SQR(f_baryon);
return;
}
float TFfit_onek(float k, float *tf_baryon, float *tf_cdm)
/* Input: k -- Wavenumber at which to calculate transfer function, in Mpc^-1.
*tf_baryon, *tf_cdm -- Input value not used; replaced on output if
the input was not NULL. */
/* Output: Returns the value of the full transfer function fitting formula.
This is the form given in Section 3 of Eisenstein & Hu (1997).
*tf_baryon -- The baryonic contribution to the full fit.
*tf_cdm -- The CDM contribution to the full fit. */
/* Notes: Units are Mpc, not h^-1 Mpc. */
{
float T_c_ln_beta, T_c_ln_nobeta, T_c_C_alpha, T_c_C_noalpha;
float q, xx, xx_tilde, q_eff;
float T_c_f, T_c, s_tilde, T_b_T0, T_b, f_baryon, T_full;
float T_0_L0, T_0_C0, T_0, gamma_eff;
float T_nowiggles_L0, T_nowiggles_C0, T_nowiggles;
k = fabs(k); /* Just define negative k as positive */
if (k==0.0) {
if (tf_baryon!=NULL) *tf_baryon = 1.0;
if (tf_cdm!=NULL) *tf_cdm = 1.0;
return 1.0;
}
q = k/13.41/k_equality;
xx = k*sound_horizon;
T_c_ln_beta = log(2.718282+1.8*beta_c*q);
T_c_ln_nobeta = log(2.718282+1.8*q);
T_c_C_alpha = 14.2/alpha_c + 386.0/(1+69.9*pow(q,1.08));
T_c_C_noalpha = 14.2 + 386.0/(1+69.9*pow(q,1.08));
T_c_f = 1.0/(1.0+POW4(xx/5.4));
T_c = T_c_f*T_c_ln_beta/(T_c_ln_beta+T_c_C_noalpha*SQR(q)) +
(1-T_c_f)*T_c_ln_beta/(T_c_ln_beta+T_c_C_alpha*SQR(q));
s_tilde = sound_horizon*pow(1+CUBE(beta_node/xx),-1./3.);
xx_tilde = k*s_tilde;
T_b_T0 = T_c_ln_nobeta/(T_c_ln_nobeta+T_c_C_noalpha*SQR(q));
T_b = sin(xx_tilde)/(xx_tilde)*(T_b_T0/(1+SQR(xx/5.2))+
alpha_b/(1+CUBE(beta_b/xx))*exp(-pow(k/k_silk,1.4)));
f_baryon = obhh/omhh;
T_full = f_baryon*T_b + (1-f_baryon)*T_c;
/* Now to store these transfer functions */
if (tf_baryon!=NULL) *tf_baryon = T_b;
if (tf_cdm!=NULL) *tf_cdm = T_c;
return T_full;
}
/* ======================= Approximate forms =========================== */
float TFsound_horizon_fit(float omega0, float f_baryon, float hubble)
/* Input: omega0 -- CDM density, in units of critical density
f_baryon -- Baryon fraction, the ratio of baryon to CDM density.
hubble -- Hubble constant, in units of 100 km/s/Mpc
/* Output: The approximate value of the sound horizon, in h^-1 Mpc. */
/* Note: If you prefer to have the answer in units of Mpc, use hubble -> 1
and omega0 -> omega0*hubble^2. */
{
float omhh, sound_horizon_fit_mpc;
omhh = omega0*hubble*hubble;
sound_horizon_fit_mpc =
44.5*log(9.83/omhh)/sqrt(1+10.0*pow(omhh*f_baryon,0.75));
return sound_horizon_fit_mpc*hubble;
}
float TFk_peak(float omega0, float f_baryon, float hubble)
/* Input: omega0 -- CDM density, in units of critical density
f_baryon -- Baryon fraction, the ratio of baryon to CDM density.
hubble -- Hubble constant, in units of 100 km/s/Mpc
/* Output: The approximate location of the first baryonic peak, in h Mpc^-1 */
/* Note: If you prefer to have the answer in units of Mpc^-1, use hubble -> 1
and omega0 -> omega0*hubble^2. */
{
float omhh, k_peak_mpc;
omhh = omega0*hubble*hubble;
k_peak_mpc = 2.5*3.14159*(1+0.217*omhh)/TFsound_horizon_fit(omhh,f_baryon,1.0);
return k_peak_mpc/hubble;
}
float TFnowiggles(float omega0, float f_baryon, float hubble,
float Tcmb, float k_hmpc)
/* Input: omega0 -- CDM density, in units of critical density
f_baryon -- Baryon fraction, the ratio of baryon to CDM density.
hubble -- Hubble constant, in units of 100 km/s/Mpc
Tcmb -- Temperature of the CMB in Kelvin; Tcmb<=0 forces use of
COBE FIRAS value of 2.728 K
k_hmpc -- Wavenumber in units of (h Mpc^-1). */
/* Output: The value of an approximate transfer function that captures the
non-oscillatory part of a partial baryon transfer function. In other words,
the baryon oscillations are left out, but the suppression of power below
the sound horizon is included. See equations (30) and (31). */
/* Note: If you prefer to use wavenumbers in units of Mpc^-1, use hubble -> 1
and omega0 -> omega0*hubble^2. */
{
float k, omhh, theta_cmb, k_equality, q, xx, alpha_gamma, gamma_eff;
float q_eff, T_nowiggles_L0, T_nowiggles_C0;
k = k_hmpc*hubble; /* Convert to Mpc^-1 */
omhh = omega0*hubble*hubble;
if (Tcmb<=0.0) Tcmb=2.728; /* COBE FIRAS */
theta_cmb = Tcmb/2.7;
k_equality = 0.0746*omhh/SQR(theta_cmb);
q = k/13.41/k_equality;
xx = k*TFsound_horizon_fit(omhh, f_baryon, 1.0);
alpha_gamma = 1-0.328*log(431.0*omhh)*f_baryon + 0.38*log(22.3*omhh)*
SQR(f_baryon);
gamma_eff = omhh*(alpha_gamma+(1-alpha_gamma)/(1+POW4(0.43*xx)));
q_eff = q*omhh/gamma_eff;
T_nowiggles_L0 = log(2.0*2.718282+1.8*q_eff);
T_nowiggles_C0 = 14.2 + 731.0/(1+62.5*q_eff);
return T_nowiggles_L0/(T_nowiggles_L0+T_nowiggles_C0*SQR(q_eff));
}
/* ======================= Zero Baryon Formula =========================== */
float TFzerobaryon(float omega0, float hubble, float Tcmb, float k_hmpc)
/* Input: omega0 -- CDM density, in units of critical density
hubble -- Hubble constant, in units of 100 km/s/Mpc
Tcmb -- Temperature of the CMB in Kelvin; Tcmb<=0 forces use of
COBE FIRAS value of 2.728 K
k_hmpc -- Wavenumber in units of (h Mpc^-1). */
/* Output: The value of the transfer function for a zero-baryon universe. */
/* Note: If you prefer to use wavenumbers in units of Mpc^-1, use hubble -> 1
and omega0 -> omega0*hubble^2. */
{
float k, omhh, theta_cmb, k_equality, q, T_0_L0, T_0_C0;
k = k_hmpc*hubble; /* Convert to Mpc^-1 */
omhh = omega0*hubble*hubble;
if (Tcmb<=0.0) Tcmb=2.728; /* COBE FIRAS */
theta_cmb = Tcmb/2.7;
k_equality = 0.0746*omhh/SQR(theta_cmb);
q = k/13.41/k_equality;
T_0_L0 = log(2.0*2.718282+1.8*q);
T_0_C0 = 14.2 + 731.0/(1+62.5*q);
return T_0_L0/(T_0_L0+T_0_C0*q*q);
}
};
};