1
0
Fork 0
mirror of https://github.com/cosmo-sims/MUSIC.git synced 2024-09-19 17:03:46 +02:00

Many minor changes

* Moved hybrid poisson solver from convolution_kernel.cc to poisson.cc
* Fine-tuned deconvolution schemes for various running modes
* Added lots of doxygen documentation
This commit is contained in:
Oliver Hahn 2010-08-31 21:59:31 -07:00
parent af02e4ef4e
commit 275753ede2
21 changed files with 779 additions and 443 deletions

View file

@ -31,6 +31,7 @@
#include <iostream>
#include "Numerics.hh"
#ifndef REL_PRECISION
#define REL_PRECISION 1.e-4
#endif

View file

@ -38,7 +38,6 @@
#include <algorithm>
#include "general.hh"
real_t integrate( double (* func) (double x, void * params), double a, double b, void *params=NULL);
typedef __attribute__((__may_alias__)) int aint;

View file

@ -276,7 +276,8 @@ public:
{}
};
//! runtime error that is thrown if identifier is not found in keys
class ErrIllegalIdentifier : public std::runtime_error{
public:
ErrIllegalIdentifier( std::string errmsg )

View file

@ -53,6 +53,7 @@ namespace convolution{
template< typename real_t >
void perform( kernel * pk, void *pd )
{
// return;
parameters cparam_ = pk->cparam_;
double fftnorm = pow(2.0*M_PI,1.5)/sqrt(cparam_.lx*cparam_.ly*cparam_.lz)/sqrt((double)(cparam_.nx*cparam_.ny*cparam_.nz));
@ -88,10 +89,10 @@ namespace convolution{
for( int k=0; k<cparam_.nz/2+1; ++k )
{
unsigned ii = (i*cparam_.ny + j) * (cparam_.nz/2+1) + k;
std::complex<double> ccdata(cdata[ii].re,cdata[ii].im), cckernel(ckernel[ii].re,ckernel[ii].im);
ccdata = ccdata * cckernel *fftnorm;
cdata[ii].re = ccdata.real();
cdata[ii].im = ccdata.imag();
}
@ -149,28 +150,30 @@ namespace convolution{
dy = cparam_.ly/cparam_.ny,
dz = cparam_.lz/cparam_.nz,
boxlength = cparam_.pcf->getValue<double>("setup","boxlength"),
boxlength2 = 0.5*boxlength,
nspec = cparam_.pcf->getValue<double>("cosmology","nspec"),
pnorm = cparam_.pcf->getValue<double>("cosmology","pnorm"),
dplus = cparam_.pcf->getValue<double>("cosmology","dplus");
bool
bavgfine = cparam_.pcf->getValueSafe<bool>("setup","avg_fine",false),
bdefd = cparam_.pcf->getValueSafe<bool> ( "poisson" , "deconvolve", false ),
bperiodic = cparam_.pcf->getValueSafe<bool>("setup","periodic_TF",true);
bperiodic = cparam_.pcf->getValueSafe<bool>("setup","periodic_TF",true),
kspacepoisson = (cparam_.pcf->getValueSafe<bool>("poisson","fft_fine",true)|
cparam_.pcf->getValueSafe<bool>("poisson","kspace",false));
unsigned
levelmax = cparam_.pcf->getValue<unsigned>("setup","levelmax");
if( bavgfine )
cparam_.coarse_fact++;
const int ref_fac = (int)(pow(2,cparam_.coarse_fact)+0.5), ql = -ref_fac/2+1, qr=ql+ref_fac, rf8=(int)pow(ref_fac,3);
std::cout << " - Computing transfer function kernel...\n";
if(! cparam_.is_finest )
kny *= pow(2,cparam_.coarse_fact);
kny *= pow(2,cparam_.coarse_fact);
TransferFunction_real *tfr =
new TransferFunction_real(type, cparam_.ptf,nspec,pnorm,dplus,
@ -187,6 +190,11 @@ namespace convolution{
T0 = tfr->compute_real(0.0);
if(bavgfine)
cparam_.coarse_fact--;
//... obtain a grid-version of the real space transfer function
if( bperiodic )
{
@ -306,26 +314,32 @@ namespace convolution{
rrr[2] = rr[2]+(double)kkk*0.5*dx - 0.25*dx;
rrr2[2]= rrr[2]*rrr[2];
rr2 = rrr2[0]+rrr2[1]+rrr2[2];
kdata_[idx] += (fftw_real)(tfr->compute_real(rr2)/rf8);
if( fabs(rr[0])<=boxlength2||fabs(rr[1])<=boxlength2||fabs(rr[2])<=boxlength2 )
kdata_[idx] += (fftw_real)(tfr->compute_real(rr2)/rf8)*fac;
}
}
}
}else{
rr2 = rr[0]*rr[0]+rr[1]*rr[1]+rr[2]*rr[2];
kdata_[idx] += (fftw_real)tfr->compute_real(rr2);
if( fabs(rr[0])<=boxlength2||fabs(rr[1])<=boxlength2||fabs(rr[2])<=boxlength2 )
kdata_[idx] += (fftw_real)tfr->compute_real(rr2)*fac;
}
}
}
if( cparam_.is_finest )
{
kdata_[0] = tfr->compute_real(0.0)*fac;
//std::cerr << "T(0) = " << kdata_[0] << std::endl;
//kdata_[0] = sqrt(8.0)*tfr->compute_real(0.5*sqrt(3.0)*dx/4)*fac;
//std::cerr << "T(0) = " << kdata_[0] << std::endl;
}
T0 = kdata_[0];
delete tfr;
double k0 = kdata_[0];
//... subtract white noise component before deconvolution
if( cparam_.deconvolve )//&& cparam_.is_finest)
kdata_[0] = 0.0;
@ -336,6 +350,7 @@ namespace convolution{
rfftwnd_one_real_to_complex( plan, rkernel, NULL );
#endif
//... do some k-space filter correction stuff
if( cparam_.deconvolve || cparam_.smooth )
{
@ -359,15 +374,6 @@ namespace convolution{
double ipix = 1.0;
//... perform k-space 'averaging' for coarser grids
/*if( !cparam_.is_finest )
{
for( unsigned c=1; c<= cparam_.coarse_fact; ++c )
{
double kkmax = 0.5*kmax/pow(2,c-1);
ipix *= (cos(kx*kkmax)*cos(ky*kkmax)*cos(kz*kkmax));
}
}*/
double kkmax = kmax;// / pow(2,cparam_.coarse_fact);
@ -387,17 +393,30 @@ namespace convolution{
if( !cparam_.smooth )
{
if(!(bdefd&&cparam_.is_finest))
if( cparam_.is_finest )
{
kkernel[q].re *= ipix;
kkernel[q].im *= ipix;
if( kspacepoisson )
{
kkernel[q].re /= cos(kx*kkmax)*cos(ky*kkmax)*cos(kz*kkmax);
kkernel[q].im /= cos(kx*kkmax)*cos(ky*kkmax)*cos(kz*kkmax);
///////kkernel[q].re *= ipix;
///////kkernel[q].im *= ipix;
}else{
////////kkernel[q].re /= cos(kx*kkmax)*cos(ky*kkmax)*cos(kz*kkmax);
////////kkernel[q].im /= cos(kx*kkmax)*cos(ky*kkmax)*cos(kz*kkmax);
kkernel[q].re *= ipix;
kkernel[q].im *= ipix;
}
}else{
kkmax /= pow(2,cparam_.coarse_fact);
kkernel[q].re /= cos(kx*kkmax)*cos(ky*kkmax)*cos(kz*kkmax);
kkernel[q].im /= cos(kx*kkmax)*cos(ky*kkmax)*cos(kz*kkmax);
////////kkernel[q].re *= ipix;
////////kkernel[q].im *= ipix;
}
}else{
//... if smooth==true, convolve with
//... NGP kernel to get CIC smoothness
@ -427,7 +446,7 @@ namespace convolution{
//... set white noise component to zero if smoothing is enabled
if( cparam_.smooth )
dk = 0.0;
//... enforce the r=0 component by adjusting the k-space mean
#pragma omp parallel for reduction(+:ksum,kcount)
for( int i=0; i<cparam_.nx; ++i )
@ -441,8 +460,7 @@ namespace convolution{
rfftwnd_destroy_plan(plan);
if(bavgfine)
cparam_.coarse_fact--;
}
@ -525,305 +543,9 @@ namespace convolution{
}
}
/**************************************************************************************/
/**************************************************************************************/
#pragma mark -
template<int order>
double deconv_kernel( int idir, int i, int j, int k, int n )
{
return 1.0;
}
template<>
inline double deconv_kernel<2>(int idir, int i, int j, int k, int n )
{
double
ki(M_PI*(double)i/(double)n),
kj(M_PI*(double)j/(double)n),
kk(M_PI*(double)k/(double)n),
kr(sqrt(ki*ki+kj*kj+kk*kk));
double grad = 1.0, laplace = 1.0;
if( idir==0&&i!=0 )
grad = sin(ki)/ki;
else if( idir==1&&j!=0 )
grad = sin(kj)/kj;
else if( idir==2&&k!=0 )
grad = sin(kk)/kk;
laplace = 2.0*((-cos(ki)+1.0)+(-cos(kj)+1.0)+(-cos(kk)+1.0));
if(i!=0&&j!=0&&k!=0)
laplace /= (kr*kr);
else
laplace=1.0;
return laplace/grad;
}
template<>
inline double deconv_kernel<4>(int idir, int i, int j, int k, int n )
{
double
ki(M_PI*(double)i/(double)n),
kj(M_PI*(double)j/(double)n),
kk(M_PI*(double)k/(double)n),
kr(sqrt(ki*ki+kj*kj+kk*kk));
double grad = 1.0, laplace = 1.0;
if( idir==0&&i!=0 )
grad = 0.166666666667*(-sin(2.*ki)+8.*sin(ki))/ki;
else if( idir==1&&j!=0 )
grad = 0.166666666667*(-sin(2.*kj)+8.*sin(kj))/kj;
else if( idir==2&&k!=0 )
grad = 0.166666666667*(-sin(2.*kk)+8.*sin(kk))/kk;
laplace = 0.1666666667*((cos(2*ki)-16.*cos(ki)+15.)
+(cos(2*kj)-16.*cos(kj)+15.)
+(cos(2*kk)-16.*cos(kk)+15.));
if(i!=0&&j!=0&&k!=0)
laplace /= (kr*kr);
else
laplace=1.0;
return laplace/grad;
}
template<>
inline double deconv_kernel<6>(int idir, int i, int j, int k, int n )
{
double
ki(M_PI*(double)i/(double)n),
kj(M_PI*(double)j/(double)n),
kk(M_PI*(double)k/(double)n),
//ki(M_PI*(1.0-(double)(n-i)/(double)n)),
//kj(M_PI*(1.0-(double)(n-j)/(double)n)),
//kk(M_PI*(1.0-(double)(n-k)/(double)n)),
kr(sqrt(ki*ki+kj*kj+kk*kk));
if(i==0&&j==0&&k==0)
return 0.0;
double grad = 1.0, laplace = 1.0;
if( idir==0 )//&&i!=0&&i!=n )
grad = 0.0333333333333*(sin(3.*ki)-9.*sin(2.*ki)+45.*sin(ki));
else if( idir==1 )//&&j!=0&&j!=n )
grad = 0.0333333333333*(sin(3.*kj)-9.*sin(2.*kj)+45.*sin(kj));
else if( idir==2 ) //&&k!=0&&k!=n )
grad = 0.0333333333333*(sin(3.*kk)-9.*sin(2.*kk)+45.*sin(kk));
laplace = 0.01111111111111*(
(-2.*cos(3.0*ki)+27.*cos(2.*ki)-270.*cos(ki)+245.)
+(-2.*cos(3.0*kj)+27.*cos(2.*kj)-270.*cos(kj)+245.)
+(-2.*cos(3.0*kk)+27.*cos(2.*kk)-270.*cos(kk)+245.));
//if(i!=0&&j!=0&&k!=0)
/* if(i==0&&j==0&&k==0)
laplace=1.0;
else*/
//laplace -= (kr*kr);
double kgrad = 1.0;
if( idir==0 )
kgrad = ki;
else if( idir ==1)
kgrad = kj;
else if( idir ==2)
kgrad = kk;
return (kgrad/kr/kr-grad/laplace)*M_PI/n*M_PI/n;//laplace/grad;
//return kgrad/kr/kr*M_PI/n*M_PI/n;
//return grad/laplace*M_PI/n*M_PI/n;
//return (kgrad/kr/kr-grad/laplace);
}
template<int order>
void do_deconvolve( fftw_real* data, int idir, int nxp, int nyp, int nzp, bool periodic )
{
double fftnorm = 1.0/(nxp*nyp*nzp);
if(periodic)
fftnorm *= nxp/(4.0*M_PI*M_PI);//sqrt(8.0);
/*if(periodic)
fftnorm *= M_PI*M_PI/nxp/nyp/nzp;
else
fftnorm *= M_PI*M_PI/nxp/nyp/nzp;
if( idir == 0 )
fftnorm *= nxp;
else if( idir == 1 )
fftnorm *= nyp;
else
fftnorm *= nzp;*/
fftw_complex *cdata = reinterpret_cast<fftw_complex*>(data);
rfftwnd_plan iplan, plan;
plan = rfftw3d_create_plan( nxp, nyp, nzp,
FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE|FFTW_IN_PLACE);
iplan = rfftw3d_create_plan( nxp, nyp, nzp,
FFTW_COMPLEX_TO_REAL, FFTW_ESTIMATE|FFTW_IN_PLACE);
#ifndef SINGLETHREAD_FFTW
rfftwnd_threads_one_real_to_complex( omp_get_max_threads(), plan, data, NULL );
#else
rfftwnd_one_real_to_complex( plan, data, NULL );
#endif
double ksum = 0.0;
unsigned kcount = 0;
for( int i=0; i<nxp; ++i )
for( int j=0; j<nyp; ++j )
for( int k=0; k<nzp/2+1; ++k )
{
unsigned ii = (i*nyp + j) * (nzp/2+1) + k;
if( k==0 || k==nzp/2 )
{
ksum += cdata[ii].re;
kcount++;
}else{
ksum += 2.0*(cdata[ii].re);
kcount+=2;
}
}
ksum /= kcount;
kcount = 0;
cdata[0].re = 0.0;
cdata[0].im = 0.0;
#pragma omp parallel for
for( int i=0; i<nxp; ++i )
for( int j=0; j<nyp; ++j )
for( int k=0; k<nzp/2+1; ++k )
{
unsigned ii = (i*nyp + j) * (nzp/2+1) + k;
int ki(i), kj(j);
if( ki > nxp/2 ) ki-=nxp;
if( kj > nyp/2 ) kj-=nyp;
double dk = deconv_kernel<order>(idir, ki, kj, k, nxp/2 );
//cdata[ii].re -= ksum;
double re = cdata[ii].re, im = cdata[ii].im;
cdata[ii].re = -im*dk*fftnorm;
cdata[ii].im = re*dk*fftnorm;
//cdata[ii].re += ksum*fftnorm;
}
cdata[0].re = 0.0;
cdata[0].im = 0.0;
#ifndef SINGLETHREAD_FFTW
rfftwnd_threads_one_complex_to_real( omp_get_max_threads(), iplan, cdata, NULL);
#else
rfftwnd_one_complex_to_real(iplan, cdata, NULL);
#endif
rfftwnd_destroy_plan(plan);
rfftwnd_destroy_plan(iplan);
}
void deconvolve( MeshvarBnd<double>& f, int idir, int order, bool periodic )
{
int nx=f.size(0), ny=f.size(1), nz=f.size(2), nxp, nyp, nzp;
fftw_real *data;
int xo=0,yo=0,zo=0;
int nmax = std::max(nx,std::max(ny,nz));
if(!periodic)
{
nxp = 2*nmax;
nyp = 2*nmax;
nzp = 2*nmax;
xo = nmax/2;
yo = nmax/2;
zo = nmax/2;
}
else
{
nxp = nmax;
nyp = nmax;
nzp = nmax;
}
data = new fftw_real[nxp*nyp*2*(nzp/2+1)];
if(idir==0)
std::cout << " - Performing de-convolution... (" << nxp << ", " << nyp << ", " << nzp << ")\n";
for( int i=0; i<nxp*nyp*2*(nzp/2+1); ++i )
data[i]=0.0;
for( int i=0; i<nx; ++i )
for( int j=0; j<ny; ++j )
for( int k=0; k<nz; ++k )
{
int idx = ((i+xo)*nyp + j+yo) * 2*(nzp/2+1) + k+zo;
data[idx] = f(i,j,k);
}
switch (order) {
case 2:
do_deconvolve<2>(data, idir, nxp, nyp, nzp, periodic);
break;
case 4:
do_deconvolve<4>(data, idir, nxp, nyp, nzp, periodic);
break;
case 6:
do_deconvolve<6>(data, idir, nxp, nyp, nzp, periodic);
break;
default:
std::cerr << " - ERROR: invalid operator order specified in deconvolution.";
break;
}
for( int i=0; i<nx; ++i )
for( int j=0; j<ny; ++j )
for( int k=0; k<nz; ++k )
{
//int idx = (i*nyp + j) * 2*(nzp/2+1) + k;
int idx = ((i+xo)*nyp + j+yo) * 2*(nzp/2+1) + k+zo;
f(i,j,k) = data[idx];
}
delete[] data;
}
namespace{

View file

@ -102,8 +102,5 @@ namespace convolution{
} //namespace convolution
void deconvolve( MeshvarBnd<double>& f, int idir, int order, bool periodic );
#endif //__CONVOLUTION_KERNELS_HH

View file

@ -291,15 +291,37 @@ void compute_2LPT_source_FFT( config_file& cf_, const grid_hierarchy& u, grid_hi
cdata_33[idx].re = -k[2]*k[2] * cdata[idx].re * norm;
cdata_33[idx].im = -k[2]*k[2] * cdata[idx].im * norm;
if( i==nx/2||j==ny/2||l==nz/2)
{
cdata_11[idx].re = 0.0;
cdata_11[idx].im = 0.0;
cdata_12[idx].re = 0.0;
cdata_12[idx].im = 0.0;
cdata_13[idx].re = 0.0;
cdata_13[idx].im = 0.0;
cdata_22[idx].re = 0.0;
cdata_22[idx].im = 0.0;
cdata_23[idx].re = 0.0;
cdata_23[idx].im = 0.0;
cdata_33[idx].re = 0.0;
cdata_33[idx].im = 0.0;
}
}
delete[] data;
cdata_11[0].re = 0.0; cdata_11[0].im = 0.0;
/*cdata_11[0].re = 0.0; cdata_11[0].im = 0.0;
cdata_12[0].re = 0.0; cdata_12[0].im = 0.0;
cdata_13[0].re = 0.0; cdata_13[0].im = 0.0;
cdata_22[0].re = 0.0; cdata_22[0].im = 0.0;
cdata_23[0].re = 0.0; cdata_23[0].im = 0.0;
cdata_33[0].re = 0.0; cdata_33[0].im = 0.0;
cdata_33[0].re = 0.0; cdata_33[0].im = 0.0;*/
#ifndef SINGLETHREAD_FFTW
@ -335,6 +357,9 @@ void compute_2LPT_source_FFT( config_file& cf_, const grid_hierarchy& u, grid_hi
(*fnew.get_grid(u.levelmax()))(i,j,k) = (( data_11[ii]*data_22[ii]-data_12[ii]*data_12[ii] ) +
( data_11[ii]*data_33[ii]-data_13[ii]*data_13[ii] ) +
( data_22[ii]*data_33[ii]-data_23[ii]*data_23[ii] ) );
//(*fnew.get_grid(u.levelmax()))(i,j,k) =
}
//delete[] data;

View file

@ -47,8 +47,8 @@ public:
//! constructor for a cosmology calculator object
/*!
* @params acosmo a cosmological parameters structure
* @params pTransferFunction pointer to an instance of a transfer function object
* @param acosmo a cosmological parameters structure
* @param pTransferFunction pointer to an instance of a transfer function object
*/
CosmoCalc( const Cosmology acosmo, transfer_function_plugin *pTransferFunction )
@ -59,9 +59,9 @@ public:
//! returns the amplitude of amplitude of the power spectrum
/*!
* @params k the wave number in h/Mpc
* @params a the expansion factor of the universe
* @return power spectrum amplitude for wave number k at time a
* @param k the wave number in h/Mpc
* @param a the expansion factor of the universe
* @returns power spectrum amplitude for wave number k at time a
*/
inline real_t Power( real_t k, real_t a ){
real_t m_Dplus = CalcGrowthFactor( a );
@ -166,8 +166,8 @@ public:
//! Computes the square of the transfer function
/*! Function evaluates the supplied transfer function m_pTransferFunction
and returns the square of its value at wave number k
\param k wave number at which to evaluate the transfer function
* and returns the square of its value at wave number k
* @param k wave number at which to evaluate the transfer function
*/
inline real_t TransferSq( real_t k ){
//.. parameter supplied transfer function
@ -199,9 +199,9 @@ public:
//! compute the jeans sound speed
/*! given a density in g/cm^-3 and a mass in g it gives back the sound
* speed in cm/s for which the input mass is equal to the jeans mass
* @params rho density
* @params mass mass scale
* @return jeans sound speed
* @param rho density
* @param mass mass scale
* @returns jeans sound speed
*/
inline double jeans_sound_speed( double rho, double mass )
{

View file

@ -292,11 +292,37 @@ void GenerateDensityHierarchy( config_file& cf, transfer_function *ptf, tf_type
shift[1] = cf.getValue<int>("setup","shift_y");
shift[2] = cf.getValue<int>("setup","shift_z");
#ifdef SINGLE_PRECISION
/*#ifdef SINGLE_PRECISION
convolution::kernel_creator *the_kernel_creator = convolution::get_kernel_map()[ "tf_kernel_real_float" ];
#else
convolution::kernel_creator *the_kernel_creator = convolution::get_kernel_map()[ "tf_kernel_real_double" ];
#endif*/
convolution::kernel_creator *the_kernel_creator;
if( kspaceTF )
{
if( levelmin!=levelmax )
throw std::runtime_error("k-space transfer function can only be used in unigrid density mode");
std::cout << " - Using k-space transfer function kernel.\n";
#ifdef SINGLE_PRECISION
the_kernel_creator = convolution::get_kernel_map()[ "tf_kernel_k_float" ];
#else
the_kernel_creator = convolution::get_kernel_map()[ "tf_kernel_k_double" ];
#endif
}
else
{
std::cout << " - Using real-space transfer function kernel.\n";
#ifdef SINGLE_PRECISION
the_kernel_creator = convolution::get_kernel_map()[ "tf_kernel_real_float" ];
#else
the_kernel_creator = convolution::get_kernel_map()[ "tf_kernel_real_double" ];
#endif
}
convolution::parameters conv_param;
conv_param.ptf = ptf;
@ -886,7 +912,7 @@ void GenerateDensityHierarchy( config_file& cf, transfer_function *ptf, tf_type
}
//std::cout << " - Top grid mean density is off by " << sum << ", correcting..." << std::endl;
std::cout << " - Top grid mean density is off by " << sum << ", correcting..." << std::endl;
for( unsigned i=levelmin; i<=levelmax; ++i )
{

View file

@ -79,9 +79,9 @@ public:
//! constructor
/*! constructs an instance given the dimensions of the density field
* @params nx the number of cells in x
* @params ny the number of cells in y
* @params nz the number of cells in z
* @param nx the number of cells in x
* @param ny the number of cells in y
* @param nz the number of cells in z
*/
DensityGrid( unsigned nx, unsigned ny, unsigned nz )
: nx_(nx), ny_(ny), nz_(nz)
@ -113,7 +113,7 @@ public:
//! query the 3D array sizes of the density object
/*! returns the size of the 3D density object along a specified dimension
* @params i the dimension for which size is to be returned
* @param i the dimension for which size is to be returned
* @returns array size along dimension i
*/
int size( int i )
@ -158,12 +158,12 @@ public:
//! fills the density field with random number values
/*! given a pointer to a random_numbers object, fills the field with random values
* @params prc pointer to a random_numbers object
* @params variance the variance of the random numbers (the values returned by prc are multiplied by this)
* @params i0 x-offset (shift) in cells of the density field with respect to the random number field
* @params j0 y-offset (shift) in cells of the density field with respect to the random number field
* @params k0 z-offset (shift) in cells of the density field with respect to the random number field
* @params setzero boolean, if true, the global mean will be subtracted
* @param prc pointer to a random_numbers object
* @param variance the variance of the random numbers (the values returned by prc are multiplied by this)
* @param i0 x-offset (shift) in cells of the density field with respect to the random number field
* @param j0 y-offset (shift) in cells of the density field with respect to the random number field
* @param k0 z-offset (shift) in cells of the density field with respect to the random number field
* @param setzero boolean, if true, the global mean will be subtracted
*/
void fill_rand( /*const*/ random_numbers<real_t>* prc, real_t variance, int i0, int j0, int k0, bool setzero=false )
{

View file

@ -28,7 +28,7 @@
#include <stdexcept>
//... abstract implementation of the Poisson/Force scheme
//! abstract implementation of the Poisson/Force scheme
template< class L, class G, typename real_t=double >
class scheme
{
@ -39,22 +39,27 @@ public:
laplacian m_laplacian;
gradient m_gradient;
//! gradient along x-direction
template< class C >
inline real_t grad_x( const C&c, const int i, const int j, const int k )
{ return m_gradient.apply_x( c,i,j,k ); }
//! gradient along y-direction
template< class C >
inline real_t grad_y( const C&c, const int i, const int j, const int k )
{ return m_gradient.apply_y( c,i,j,k ); }
//! gradient along z-direction
template< class C >
inline real_t grad_z( const C&c, const int i, const int j, const int k )
{ return m_gradient.apply_z( c,i,j,k ); }
//! apply Laplace operator
template< class C >
inline real_t L_apply( const C&c, const int i, const int j, const int k )
{ return m_laplacian.apply( c,i,j,k ); }
//! compute an explicit solution for the central component of the discrete Poisson's equation
template< class C >
inline real_t L_rhs( const C&c, const int i, const int j, const int k )
{ return m_laplacian.rhs( c,i,j,k ); }
@ -64,7 +69,7 @@ public:
};
//! base class for finite difference gradients
template< int nextent, typename T >
class gradient
{
@ -117,6 +122,7 @@ public:
}
};
//! base class for finite difference stencils
template< int nextent, typename real_t >
class base_stencil
{
@ -200,7 +206,7 @@ public:
//... Implementation of the Laplacian schemes..........................................
//! 7-point, 2nd order finite difference Laplacian
template< typename real_t >
class stencil_7P : public base_stencil<1,real_t>
{
@ -235,7 +241,7 @@ public:
}
};
//! 13-point, 4th order finite difference Laplacian
template< typename real_t >
class stencil_13P : public base_stencil<2,real_t>
{
@ -283,6 +289,8 @@ public:
}
};
//! 19-point, 6th order finite difference Laplacian
template< typename real_t >
class stencil_19P : public base_stencil<3,real_t>
{
@ -342,12 +350,19 @@ public:
};
//! flux operator for the 4th order FD Laplacian
template< typename real_t >
class Laplace_flux_O4
{
public:
//.. idir is -1 for left boundary, +1 for right boundary
/*! computes flux across a surface normal to x-direction
* @param idir idir is -1 for left boundary, +1 for right boundary
* @param c array on which to apply the operator
* @param i grid x-index
* @param j grid y-index
* @param k grid z-index
* @returns flux value
*/
template< class C >
inline double apply_x( int idir, const C& c, const int i, const int j, const int k )
{
@ -355,6 +370,14 @@ public:
return fac*(-c(i-2,j,k)+15.0*c(i-1,j,k)-15.0*c(i,j,k)+c(i+1,j,k));
}
/*! computes flux across a surface normal to y-direction
* @param idir idir is -1 for left boundary, +1 for right boundary
* @param c array on which to apply the operator
* @param i grid x-index
* @param j grid y-index
* @param k grid z-index
* @returns flux value
*/
template< class C >
inline double apply_y( int idir, const C& c, const int i, const int j, const int k )
{
@ -362,6 +385,14 @@ public:
return fac*(-c(i,j-2,k)+15.0*c(i,j-1,k)-15.0*c(i,j,k)+c(i,j+1,k));
}
/*! computes flux across a surface normal to z-direction
* @param idir idir is -1 for left boundary, +1 for right boundary
* @param c array on which to apply the operator
* @param i grid x-index
* @param j grid y-index
* @param k grid z-index
* @returns flux value
*/
template< class C >
inline double apply_z( int idir, const C& c, const int i, const int j, const int k )
{
@ -372,12 +403,20 @@ public:
};
//! flux operator for the 6th order FD Laplacian
template< typename real_t >
class Laplace_flux_O6
{
public:
//.. idir is -1 for left boundary, +1 for right boundary
/*! computes flux across a surface normal to x-direction
* @param idir idir is -1 for left boundary, +1 for right boundary
* @param c array on which to apply the operator
* @param i grid x-index
* @param j grid y-index
* @param k grid z-index
* @returns flux value
*/
template< class C >
inline double apply_x( int idir, const C& c, const int i, const int j, const int k )
{
@ -385,6 +424,14 @@ public:
return fac*(2.*c(i-3,j,k)-25.*c(i-2,j,k)+245.*c(i-1,j,k)-245.0*c(i,j,k)+25.*c(i+1,j,k)-2.*c(i+2,j,k));
}
/*! computes flux across a surface normal to y-direction
* @param idir idir is -1 for left boundary, +1 for right boundary
* @param c array on which to apply the operator
* @param i grid x-index
* @param j grid y-index
* @param k grid z-index
* @returns flux value
*/
template< class C >
inline double apply_y( int idir, const C& c, const int i, const int j, const int k )
{
@ -392,6 +439,14 @@ public:
return fac*(2.*c(i,j-3,k)-25.*c(i,j-2,k)+245.*c(i,j-1,k)-245.0*c(i,j,k)+25.*c(i,j+1,k)-2.*c(i,j+2,k));
}
/*! computes flux across a surface normal to z-direction
* @param idir idir is -1 for left boundary, +1 for right boundary
* @param c array on which to apply the operator
* @param i grid x-index
* @param j grid y-index
* @param k grid z-index
* @returns flux value
*/
template< class C >
inline double apply_z( int idir, const C& c, const int i, const int j, const int k )
{

View file

@ -65,51 +65,55 @@ typedef MeshvarBnd<real_t> meshvar_bnd;
typedef Meshvar<real_t> meshvar;
/* Convenience from Numerical Recipes in C, 2nd edition */
//! compute square of argument
template< typename T >
inline T SQR( T a ){
return a*a;
}
//! compute cube of argument
template< typename T >
inline T CUBE( T a ){
return a*a*a;
}
//! compute 4th power of argument
template< typename T >
inline T POW4( T a ){
return a*a*a*a;
return SQR(SQR(a));
//return a*a*a*a;
}
// --- structure for cosmological parameters --- //
//! structure for cosmological parameters
typedef struct cosmology{
double
Omega_m, // baryon+dark matter density
Omega_b, // baryon matter density
Omega_L, // dark energy density
H0, // Hubble constant
nspect, // long-wave spectral index (scale free is nspect=1)
sigma8, // power spectrum normalization
//Gamma, // shape parameter (of historical interest, as a free parameter)
//fnl, // non-gaussian contribution parameter
//w0, // dark energy equation of state parameter (not implemented, i.e. =1 at the moment)
//wa, // dark energy equation of state parameter (not implemented, i.e. =1 at the moment)
dplus,
pnorm,
vfact,
WDMmass,
WDMg_x,
astart; // expansion factor a for which to generate initial conditions
Omega_m, //!< baryon+dark matter density
Omega_b, //!< baryon matter density
Omega_L, //!< dark energy density
H0, //!< Hubble constant
nspect, //!< long-wave spectral index (scale free is nspect=1)
sigma8, //!< power spectrum normalization
//Gamma, //!< shape parameter (of historical interest, as a free parameter)
//fnl, //!< non-gaussian contribution parameter
//w0, //!< dark energy equation of state parameter (not implemented, i.e. =1 at the moment)
//wa, //!< dark energy equation of state parameter (not implemented, i.e. =1 at the moment)
dplus, //!< linear perturbation growth factor
pnorm, //!< actual power spectrum normalisation factor
vfact, //!< velocity<->displacement conversion factor in Zel'dovich approx.
WDMmass, //!< Warm DM particle mass
WDMg_x, //!< Warm DM particle degrees of freedom
astart; //!< expansion factor a for which to generate initial conditions
}Cosmology;
//! basic box/grid/refinement structure parameters
typedef struct {
unsigned levelmin, levelmax;
double boxlength;
std::vector<unsigned> offx,offy,offz,llx,lly,llz;
}Parameters;
//! measure elapsed wallclock time
inline double time_seconds( void )
{
#ifdef WITH_MPI

15
main.cc
View file

@ -237,6 +237,8 @@ void subtract_finest_mean( grid_hierarchy& u )
* (*u.get_grid(u.levelmax())).size(1)
* (*u.get_grid(u.levelmax())).size(2);
std::cout << " component mean is " << sum << std::endl;
for( unsigned ilevel=u.levelmin(); ilevel<=u.levelmax(); ++ilevel )
#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
@ -411,7 +413,7 @@ int main (int argc, const char * argv[])
refinement_hierarchy rh_TF( rh_Poisson );
modify_grid_for_TF( rh_Poisson, rh_TF, cf );
//rh_TF.output();
rh_TF.output();
if( !the_transfer_function_plugin->tf_is_distinct() && do_baryons )
@ -468,7 +470,7 @@ int main (int argc, const char * argv[])
if( bdefd )
{
data_forIO = f;
deconvolve(*data_forIO.get_grid(data_forIO.levelmax()), icoord, grad_order, data_forIO.levelmin()==data_forIO.levelmax());
poisson_hybrid(*data_forIO.get_grid(data_forIO.levelmax()), icoord, grad_order, data_forIO.levelmin()==data_forIO.levelmax());
the_poisson_solver->gradient_add(icoord, u, data_forIO );
}
else
@ -529,7 +531,7 @@ int main (int argc, const char * argv[])
{
data_forIO.zero();
*data_forIO.get_grid(data_forIO.levelmax()) = *f.get_grid(f.levelmax());
deconvolve(*data_forIO.get_grid(data_forIO.levelmax()), icoord, grad_order, data_forIO.levelmin()==data_forIO.levelmax());
poisson_hybrid(*data_forIO.get_grid(data_forIO.levelmax()), icoord, grad_order, data_forIO.levelmin()==data_forIO.levelmax());
the_poisson_solver->gradient_add(icoord, u, data_forIO );
}
else
@ -590,6 +592,7 @@ int main (int argc, const char * argv[])
u2 *= 6.0/7.0;
u1 += u2;
//u1 = u2;
u2.deallocate();
grid_hierarchy data_forIO(u1);
@ -599,13 +602,13 @@ int main (int argc, const char * argv[])
//... displacement
//the_poisson_solver->gradient(icoord, u1, data_forIO );
//if(bdefd)
// deconvolve(*data_forIO.get_grid(data_forIO.levelmax()), icoord, grad_order, data_forIO.levelmin()==data_forIO.levelmax());
// poisson_hybrid(*data_forIO.get_grid(data_forIO.levelmax()), icoord, grad_order, data_forIO.levelmin()==data_forIO.levelmax());
if(bdefd)
{
data_forIO.zero();
*data_forIO.get_grid(data_forIO.levelmax()) = *f.get_grid(f.levelmax());
deconvolve(*data_forIO.get_grid(data_forIO.levelmax()), icoord, grad_order, data_forIO.levelmin()==data_forIO.levelmax());
poisson_hybrid(*data_forIO.get_grid(data_forIO.levelmax()), icoord, grad_order, data_forIO.levelmin()==data_forIO.levelmax());
the_poisson_solver->gradient_add(icoord, u1, data_forIO );
}
else
@ -677,7 +680,7 @@ int main (int argc, const char * argv[])
{
data_forIO.zero();
*data_forIO.get_grid(data_forIO.levelmax()) = *f.get_grid(f.levelmax());
deconvolve(*data_forIO.get_grid(data_forIO.levelmax()), icoord, grad_order, data_forIO.levelmin()==data_forIO.levelmax());
poisson_hybrid(*data_forIO.get_grid(data_forIO.levelmax()), icoord, grad_order, data_forIO.levelmin()==data_forIO.levelmax());
the_poisson_solver->gradient_add(icoord, u1, data_forIO );
}
else

99
mesh.hh
View file

@ -287,7 +287,9 @@ class MeshvarBnd : public Meshvar< T >{
public:
typedef T real_t;
unsigned m_nbnd;
//! number of boundary (ghost) cells
unsigned m_nbnd;
//! most general constructor
MeshvarBnd( unsigned nbnd, unsigned nx, unsigned ny, unsigned nz, unsigned xoff, unsigned yoff, unsigned zoff )
@ -693,6 +695,7 @@ public:
m_levelmin = lmax;
}
//! multiply entire grid hierarchy by a constant
GridHierarchy<T>& operator*=( T x )
{
for( unsigned i=0; i<m_pgrids.size(); ++i )
@ -700,6 +703,7 @@ public:
return *this;
}
//! divide entire grid hierarchy by a constant
GridHierarchy<T>& operator/=( T x )
{
for( unsigned i=0; i<m_pgrids.size(); ++i )
@ -707,6 +711,7 @@ public:
return *this;
}
//! add a constant to the entire grid hierarchy
GridHierarchy<T>& operator+=( T x )
{
for( unsigned i=0; i<m_pgrids.size(); ++i )
@ -714,6 +719,7 @@ public:
return *this;
}
//! subtract a constant from the entire grid hierarchy
GridHierarchy<T>& operator-=( T x )
{
for( unsigned i=0; i<m_pgrids.size(); ++i )
@ -721,6 +727,7 @@ public:
return *this;
}
//! multiply (element-wise) two grid hierarchies
GridHierarchy<T>& operator*=( const GridHierarchy& gh )
{
if( !is_consistent(gh) )
@ -731,6 +738,7 @@ public:
return *this;
}
//! divide (element-wise) two grid hierarchies
GridHierarchy<T>& operator/=( const GridHierarchy& gh )
{
if( !is_consistent(gh) )
@ -741,6 +749,7 @@ public:
return *this;
}
//! add (element-wise) two grid hierarchies
GridHierarchy<T>& operator+=( const GridHierarchy& gh )
{
if( !is_consistent(gh) )
@ -751,6 +760,7 @@ public:
return *this;
}
//! subtract (element-wise) two grid hierarchies
GridHierarchy<T>& operator-=( const GridHierarchy& gh )
{
if( !is_consistent(gh) )
@ -763,8 +773,14 @@ public:
//... Xoff is in units of the coarser grid,
//... nX is the extent in fine grid cells
/*! add a new refinement patch to the so-far finest level
* @param xoff x-offset in units of the coarser grid (finest grid before adding new patch)
* @param yoff y-offset in units of the coarser grid (finest grid before adding new patch)
* @param zoff z-offset in units of the coarser grid (finest grid before adding new patch)
* @param nx x-extent in fine grid cells
* @param ny y-extent in fine grid cells
* @param nz z-extent in fine grid cells
*/
void add_patch( unsigned xoff, unsigned yoff, unsigned zoff, unsigned nx, unsigned ny, unsigned nz )
{
m_pgrids.push_back( new MeshvarBnd<T>( m_nbnd, nx, ny, nz, xoff, yoff, zoff ) );
@ -776,6 +792,15 @@ public:
m_zoffabs.push_back( 2*(m_zoffabs.back() + zoff) );
}
/*! cut a refinement patch to the specified size
* @param ilevel grid level on which to perform the size adjustment
* @param xoff new x-offset in units of the coarser grid (finest grid before adding new patch)
* @param yoff new y-offset in units of the coarser grid (finest grid before adding new patch)
* @param zoff new z-offset in units of the coarser grid (finest grid before adding new patch)
* @param nx new x-extent in fine grid cells
* @param ny new y-extent in fine grid cells
* @param nz new z-extent in fine grid cells
*/
void cut_patch( unsigned ilevel, unsigned xoff, unsigned yoff, unsigned zoff, unsigned nx, unsigned ny, unsigned nz)
{
unsigned dx,dy,dz,dxtop,dytop,dztop;
@ -815,6 +840,7 @@ public:
find_new_levelmin();
}
/*! determine level for which grid extends over entire domain */
void find_new_levelmin( void )
{
for( unsigned i=0; i<=levelmax(); ++i )
@ -829,16 +855,19 @@ public:
}
}
//! return maximum level in refinement hierarchy
unsigned levelmax( void ) const
{
return m_pgrids.size()-1;
}
//! return minimum level in refinement hierarchy (the level which extends over the entire domain)
unsigned levelmin( void ) const
{
return m_levelmin;
}
//! assignment operator
GridHierarchy& operator=( const GridHierarchy<T>& gh )
{
for( unsigned i=0; i<m_pgrids.size(); ++i )
@ -862,23 +891,52 @@ public:
//! class that computes the refinement structure given parameters
class refinement_hierarchy
{
std::vector<double> x0_,y0_,z0_,xl_,yl_,zl_;
std::vector<unsigned> ox_,oy_,oz_,oax_,oay_,oaz_;
std::vector<unsigned> nx_,ny_,nz_;
unsigned levelmin_, levelmax_, levelmin_tf_, padding_;
config_file& cf_;
bool align_top_;
double x0ref_[3], lxref_[3];
int xshift_[3];
std::vector<double>
x0_, //!< x-coordinates of grid origins (in [0..1[)
y0_, //!< y-coordinates of grid origins (in [0..1[)
z0_, //!< z-coordinates of grid origins (in [0..1[)
xl_, //!< x-extent of grids (in [0..1[)
yl_, //!< y-extent of grids (in [0..1[)
zl_; //!< z-extent of grids (in [0..1[)
std::vector<unsigned>
ox_, //!< relative x-coordinates of grid origins (in coarser grid cells)
oy_, //!< relative y-coordinates of grid origins (in coarser grid cells)
oz_, //!< relative z-coordinates of grid origins (in coarser grid cells)
oax_, //!< absolute x-coordinates of grid origins (in fine grid cells)
oay_, //!< absolute y-coordinates of grid origins (in fine grid cells)
oaz_, //!< absolute z-coordinates of grid origins (in fine grid cells)
nx_, //!< x-extent of grids (in fine grid cells)
ny_, //!< y-extent of grids (in fine grid cells)
nz_; //!< z-extent of grids (in fine grid cells)
unsigned
levelmin_, //!< minimum grid level for Poisson solver
levelmax_, //!< maximum grid level for all operations
levelmin_tf_, //!< minimum grid level for density calculation
padding_; //!< padding in number of coarse cells between refinement levels
config_file& cf_; //!< reference to config_file
bool align_top_; //!< bool whether to align all grids with coarsest grid cells
double
x0ref_[3], //!< coordinates of refinement region origin (in [0..1[)
lxref_[3]; //!< extent of refinement region (int [0..1[)
int xshift_[3]; //!< shift of refinement region in coarse cells (in order to center it in the domain)
public:
//! copy constructor
refinement_hierarchy( const refinement_hierarchy& rh )
: cf_( rh.cf_ )
{
*this = rh;
}
//! constructor from a config_file holding information about the desired refinement geometry
explicit refinement_hierarchy( config_file& cf )
: cf_( cf )
{
@ -1058,6 +1116,7 @@ public:
}
}
//! asignment operator
refinement_hierarchy& operator=( const refinement_hierarchy& o )
{
levelmin_ = o.levelmin_;
@ -1081,6 +1140,16 @@ public:
return *this;
}
/*! cut a grid level to the specified size
* @param ilevel grid level on which to perform the size adjustment
* @param nx new x-extent in fine grid cells
* @param ny new y-extent in fine grid cells
* @param nz new z-extent in fine grid cells
* @param oax new x-offset in units fine grid units
* @param oay new y-offset in units fine grid units
* @param oaz new z-offset in units fine grid units
*/
void adjust_level( unsigned ilevel, int nx, int ny, int nz, int oax, int oay, int oaz )
{
double h = 1.0/pow(2,ilevel);
@ -1122,6 +1191,7 @@ public:
}
/*! determine level for which grid extends over entire domain */
void find_new_levelmin( bool print=false )
{
unsigned old_levelmin( levelmin_ );
@ -1140,6 +1210,7 @@ public:
std::cerr << " - refinement_hierarchy: set new levelmin to " << levelmin_ << std::endl;
}
//! get absolute grid offset for a specified level along a specified dimension (in fine grid units)
unsigned offset_abs( unsigned ilevel, int dim ) const
{
if( dim==0 )
@ -1149,6 +1220,7 @@ public:
return oaz_.at(ilevel);
}
//! get relative grid offset for a specified level along a specified dimension (in coarser grid units)
unsigned offset( unsigned ilevel, int dim ) const
{
if( dim==0 )
@ -1158,6 +1230,7 @@ public:
return oz_.at(ilevel);
}
//! get grid size for a specified level along a specified dimension
unsigned size( unsigned ilevel, int dim ) const
{
if( dim==0 )
@ -1167,14 +1240,16 @@ public:
return nz_.at(ilevel);
}
//! get minimum grid level (the level for which the grid covers the entire domain)
unsigned levelmin( void ) const
{ return levelmin_; }
//! get maximum grid level
unsigned levelmax( void ) const
{ return levelmax_; }
//! write refinement hierarchy to stdout
void output( void )
{
std::cout << "-------------------------------------------------------------\n";

View file

@ -21,6 +21,7 @@ struct coarse_fine_interpolation
};
//! general 2nd order polynomial interpolation
inline double interp2( double x1, double x2, double x3, double f1, double f2, double f3, double x )
{
double a,b,c;
@ -32,28 +33,33 @@ inline double interp2( double x1, double x2, double x3, double f1, double f2, do
}
//! optimized 4th order polynomial interpolation across a left boundary for i-1 values
inline double interp4left( double f0, double f1, double f2, double f3, double f4 )
{
//return -4.0/231.0*f0+4.0/7.0*f1+5.0/7.0*f2-1.0/3.0*f3+5./77.0*f4;
return 1.0/13.0*f0-21./55.*f1+7.0/9.0*f2+8./15.*f3-8./1287*f4;
}
//! optimized 4th order polynomial interpolation across a right boundary for i+1 values
inline double interp4right( double f0, double f1, double f2, double f3, double f4 )
{
return interp4left(f4,f3,f2,f1,f0);
}
//! optimized 4th order polynomial interpolation across a left boundary for i-2 values
inline double interp4lleft( double f0, double f1, double f2, double f3, double f4 )
{
//return 16./231.*f0+48.0/35.0*f1-6.0/7.0*f2-8.0/15.0*f3-9./77.*f4;
return -15./91.*f0+8./11.*f1+-10./9.*f2+32./21.*f3+32./1287.*f4;
}
//! optimized 4th order polynomial interpolation across a right boundary for i+2 values
inline double interp4rright( double f0, double f1, double f2, double f3, double f4 )
{
return interp4lleft(f4,f3,f2,f1,f0);
}
//! general 4th order polynomial interpolation
inline double interp4( double fm2, double fm1, double f0, double fp1, double fp2, double x )
{
double x2 = x*x, x3=x2*x, x4=x3*x;
@ -68,6 +74,7 @@ inline double interp4( double fm2, double fm1, double f0, double fp1, double fp2
return a*x4+b*x3+c*x2+d*x+e;
}
//! general 4th order polynomial interpolation
inline double interp4( double* f, double x )
{
double x2 = x*x, x3=x2*x, x4=x3*x;
@ -82,7 +89,7 @@ inline double interp4( double* f, double x )
return a*x4+b*x3+c*x2+d*x+e;
}
//! general 6th order polynomial interpolation
inline double interp6( double *f, double x )
{
double x2 = x*x, x3=x2*x, x4=x3*x, x5=x4*x, x6=x5*x;
@ -100,6 +107,7 @@ inline double interp6( double *f, double x )
}
//! general 6th order polynomial interpolation
inline double interp6( double f0, double f1, double f2, double f3, double f4, double f5, double f6, double x )
{
double x2 = x*x, x3=x2*x, x4=x3*x, x5=x4*x, x6=x5*x;
@ -120,6 +128,7 @@ inline double interp6( double f0, double f1, double f2, double f3, double f4, do
}
//! general 2nd order polynomial interpolation
inline double interp2( double fleft, double fcenter, double fright, double x )
{
double a,b,c;
@ -130,7 +139,7 @@ inline double interp2( double fleft, double fcenter, double fright, double x )
return a*x*x+b*x+c;
}
//! optimized 2nd order polynomial interpolation for i-1 values
inline double interp2left( double fleft, double fcenter, double fright )
{
double a,b,c;
@ -141,6 +150,7 @@ inline double interp2left( double fleft, double fcenter, double fright )
return a-b+c;
}
//! optimized 2nd order polynomial interpolation for i+1 values
inline double interp2right( double fleft, double fcenter, double fright )
{
double a,b,c;
@ -151,6 +161,7 @@ inline double interp2right( double fleft, double fcenter, double fright )
return a+b+c;
}
//! optimized 2nd order polynomial interpolation for i-2 values
inline double interp2lleft( double fleft, double fcenter, double fright )
{
double a,b,c;
@ -161,6 +172,7 @@ inline double interp2lleft( double fleft, double fcenter, double fright )
return a-b+c;
}
//! optimized 2nd order polynomial interpolation for i+2 values
inline double interp2rright( double fleft, double fcenter, double fright )
{
double a,b,c;
@ -171,33 +183,37 @@ inline double interp2rright( double fleft, double fcenter, double fright )
return a-b+c;
}
//! optimized 6th order polynomial interpolation for i-1 values
inline double interp6left( double f0, double f1, double f2, double f3, double f4, double f5, double f6 )
{
//return -77./2565.*f6+44./221.*f5-14./25.*f4+308./351.*f3+352./675.*f2-16./1755.*f1+112./104975.*f0;
return 4./2431.*f0-24./1001.*f1+4./7.*f2+60./77.*f3-6./13.*f4+12./77.*f5-5./221.*f6;
}
//! optimized 6th order polynomial interpolation for i-2 values
inline double interp6lleft( double f0, double f1, double f2, double f3, double f4, double f5, double f6 )
{
//return -16./4199.*f0+16./429.*f1+32./21.*f2-675./1547.*f5-50./39.*f3+12./11.*f4+4./57.*f6;
return -12./2431.*f0+40./429.*f1+4./3.*f2-10./11.*f3+28./39.*f4-3./11.*f5+28./663.*f6;
}
//! optimized 6th order polynomial interpolation for i-3 values
inline double interp6llleft( double f0, double f1, double f2, double f3, double f4, double f5, double f6 )
{
//return -432./20995.*f0+112./429.*f1+32./15.*f2-324./221.*f5-140./39.*f3+189./55.*f4+14./57.*f6;
return -36./2431.*f0+600./1001.*f1+20./21.*f2-100./77.*f3+15./13.*f4-36./77.*f5+50./663.*f6;
}
//! optimized 6th order polynomial interpolation for i+1 values
inline double interp6right( double f0, double f1, double f2, double f3, double f4, double f5, double f6 )
{
return interp6left(f6,f5,f4,f3,f2,f1,f0);
}
//! optimized 6th order polynomial interpolation for i+2 values
inline double interp6rright( double f0, double f1, double f2, double f3, double f4, double f5, double f6 )
{
return interp6lleft(f6,f5,f4,f3,f2,f1,f0);
}
//! optimized 6th order polynomial interpolation for i+3 values
inline double interp6rrright( double f0, double f1, double f2, double f3, double f4, double f5, double f6 )
{
return interp6llleft(f6,f5,f4,f3,f2,f1,f0);
@ -208,6 +224,7 @@ inline double interp6rrright( double f0, double f1, double f2, double f3, double
#include "fd_schemes.hh"
//! tri-cubic interpolation for non-conservative injection
struct cubic_interp
: public coarse_fine_interpolation
{
@ -413,7 +430,7 @@ struct cubic_interp
};
//! 3rd order flux-corrected coarse-fine interpolation
struct interp_O3_fluxcorr
: public coarse_fine_interpolation
{
@ -617,6 +634,7 @@ struct interp_O3_fluxcorr
}
};
//! 5th order flux-corrected coarse-fine interpolation
struct interp_O5_fluxcorr
: public coarse_fine_interpolation
{
@ -923,7 +941,7 @@ struct interp_O5_fluxcorr
}
};
//! 7th order flux-corrected coarse-fine interpolation
struct interp_O7_fluxcorr
: public coarse_fine_interpolation
{

View file

@ -24,7 +24,7 @@
#ifndef __MG_OPERATORS_HH
#define __MG_OPERATORS_HH
//! injection operator based Catmull-Rom splines with arbitrary refinement factor
//! injection operator based on Catmull-Rom splines with arbitrary refinement factor
class mg_cubic_mult
{
protected:
@ -598,7 +598,7 @@ public:
};
/*
class mg_lin
{
public:
@ -739,9 +739,9 @@ public:
}
};
*/
//! linear grid injection/restriction operator
//template< typename T >
class mg_linear
{
@ -1004,14 +1004,11 @@ public:
};
//template< typename T >
//! zero order grid injection/restriction operator
class mg_straight
{
public:
//typedef T real_t;
template< typename m1, typename m2 >
inline void restrict_bnd( const m1& v, m2& V ) const
{
@ -1164,7 +1161,7 @@ public:
}
//... prolongs V to v
//... prolongs V to v on grid boundary cells
template< typename m1, typename m2 >
inline void prolong_bnd( const m1& V, m2& v ) const
{
@ -1285,6 +1282,7 @@ public:
}
//! prolongs V and adds it to v
template< typename m1, typename m2 >
inline void prolong_add( const m1& V, m2& v ) const
{

View file

@ -37,12 +37,13 @@
BEGIN_MULTIGRID_NAMESPACE
//! options for multigrid smoothing operation
namespace opt {
enum smtype { sm_jacobi, sm_gauss_seidel, sm_sor };
}
//! actual implementation of FAS adaptive multigrid solver
template< class S, class I, class O, typename T=double >
class solver
{
@ -52,51 +53,68 @@ public:
typedef I interp;
protected:
scheme m_scheme;
mgop m_gridop;
unsigned m_npresmooth, m_npostsmooth;
opt::smtype m_smoother;
unsigned m_ilevelmin;
scheme m_scheme; //!< finite difference scheme
mgop m_gridop; //!< grid prolongation and restriction operator
unsigned m_npresmooth, //!< number of pre sweeps
m_npostsmooth; //!< number of post sweeps
opt::smtype m_smoother; //!< smoothing method to be applied
unsigned m_ilevelmin; //!< index of the top grid level
const static bool m_bperiodic = true;
const static bool m_bperiodic = true; //!< flag whether top grid is periodic
std::vector<double> m_residu_ini;
bool m_is_ini;
std::vector<double> m_residu_ini; //!< vector of initial residuals for each level
bool m_is_ini; //!< bool that is true for first iteration
GridHierarchy<T> *m_pu, *m_pf, *m_pfsave;
GridHierarchy<T> *m_pu, //!< pointer to GridHierarchy for solution u
*m_pf, //!< pointer to GridHierarchy for right-hand-side
*m_pfsave; //!< pointer to saved state of right-hand-side (unused)
const MeshvarBnd<T> *m_pubnd;
//! compute residual for a level
double compute_error( const MeshvarBnd<T>& u, const MeshvarBnd<T>& unew );
//! compute residuals for entire grid hierarchy
double compute_error( const GridHierarchy<T>& uh, const GridHierarchy<T>& uhnew, bool verbose );
//! compute residuals for entire grid hierarchy
double compute_RMS_resid( const GridHierarchy<T>& uh, const GridHierarchy<T>& fh, bool verbose );
protected:
//! Jacobi smoothing
void Jacobi( T h, MeshvarBnd<T>* u, const MeshvarBnd<T>* f );
//! Gauss-Seidel smoothing
void GaussSeidel( T h, MeshvarBnd<T>* u, const MeshvarBnd<T>* f );
//! Successive-Overrelaxation smoothing
void SOR( T h, MeshvarBnd<T>* u, const MeshvarBnd<T>* f );
//! main two-grid (V-cycle) for multi-grid iterations
void twoGrid( unsigned ilevel );
//! apply boundary conditions
void setBC( unsigned ilevel );
//! make top grid periodic boundary conditions
void make_periodic( MeshvarBnd<T> *u );
//void interp_coarse_fine_cubic( unsigned ilevel, MeshvarBnd<T>& coarse, MeshvarBnd<T>& fine );
public:
//! constructor
solver( GridHierarchy<T>& f, opt::smtype smoother, unsigned npresmooth, unsigned npostsmooth );
//! destructor
~solver()
{ }
//! solve Poisson's equation
double solve( GridHierarchy<T>& u, double accuracy, double h=-1.0, bool verbose=false );
//! solve Poisson's equation
double solve( GridHierarchy<T>& u, double accuracy, bool verbose=false )
{
return this->solve ( u, accuracy, -1.0, verbose );

View file

@ -528,6 +528,22 @@ public:
shift[2] = -(double)cf_.getValue<int>( "setup", "shift_z" )*h;
}
if( !cf_.getValueSafe<bool>("output","stagger_particles",false ) )
{
double h = 1.0/pow(2,levelmax_);
if( shift==NULL )
{
shift = new double[3];
shift[0] = -0.5*h;
shift[1] = -0.5*h;
shift[2] = -0.5*h;
}else{
shift[0] -= 0.5*h;
shift[1] -= 0.5*h;
shift[2] -= 0.5*h;
}
}
//...
header_.npart[1] = npfine;

View file

@ -24,6 +24,8 @@
/****** ABSTRACT FACTORY PATTERN IMPLEMENTATION *******/
#include "poisson.hh"
#include "Numerics.hh"
std::map< std::string, poisson_plugin_creator *>&
get_poisson_plugin_map()
{
@ -512,11 +514,10 @@ double fft_poisson_plugin::solve( grid_hierarchy& f, grid_hierarchy& u )
double kk2 = kfac*kfac*(ki*ki+kj*kj+kk*kk);
unsigned idx = (i*ny+j)*nzp/2+k;
double re = cdata[idx].re;
double im = cdata[idx].im;
cdata[idx].re = -re/kk2*fac;
cdata[idx].im = -im/kk2*fac;
cdata[idx].re *= -1.0/kk2*fac;
cdata[idx].im *= -1.0/kk2*fac;
}
cdata[0].re = 0.0;
@ -592,6 +593,7 @@ double fft_poisson_plugin::gradient( int dir, grid_hierarchy& u, grid_hierarchy&
for( int j=0; j<ny; ++j )
for( int k=0; k<nz/2+1; ++k )
{
unsigned idx = (i*ny+j)*nzp/2+k;
int ii = i; if(ii>nx/2) ii-=nx;
int jj = j; if(jj>ny/2) jj-=ny;
double ki = (double)ii;
@ -606,12 +608,19 @@ double fft_poisson_plugin::gradient( int dir, grid_hierarchy& u, grid_hierarchy&
else //if( dir == 2 )
kdir = kfac*kk;
unsigned idx = (i*ny+j)*nzp/2+k;
double re = cdata[idx].re;
double im = cdata[idx].im;
if( i==nx/2||j==ny/2||k==nz/2 )
{
cdata[idx].re = 0.0;
cdata[idx].im = 0.0;
}
cdata[idx].re = fac*im*kdir;
cdata[idx].im = -fac*re*kdir;
cdata[idx].im = -fac*re*kdir;
}
cdata[0].re = 0.0;
@ -627,24 +636,318 @@ double fft_poisson_plugin::gradient( int dir, grid_hierarchy& u, grid_hierarchy&
rfftwnd_destroy_plan(iplan);
//... copy data ..........................................
double dmax = 0.0;
for( int i=0; i<nx; ++i )
for( int j=0; j<ny; ++j )
for( int k=0; k<nz; ++k )
{
unsigned idx = (i*ny+j)*nzp+k;
(*Du.get_grid(u.levelmax()))(i,j,k) = data[idx];
if(fabs(data[idx])>dmax)
dmax = fabs(data[idx]);
}
std::cerr << " - component max. is " << dmax*nx << std::endl;
delete[] data;
return 0.0;
}
/**************************************************************************************/
/**************************************************************************************/
#pragma mark -
template<int order>
double poisson_hybrid_kernel( int idir, int i, int j, int k, int n )
{
return 1.0;
}
template<>
inline double poisson_hybrid_kernel<2>(int idir, int i, int j, int k, int n )
{
double
ki(M_PI*(double)i/(double)n),
kj(M_PI*(double)j/(double)n),
kk(M_PI*(double)k/(double)n),
kr(sqrt(ki*ki+kj*kj+kk*kk));
double grad = 1.0, laplace = 1.0;
if( idir==0&&i!=0 )
grad = sin(ki);
else if( idir==1&&j!=0 )
grad = sin(kj);
else if( idir==2&&k!=0 )
grad = sin(kk);
laplace = 2.0*((-cos(ki)+1.0)+(-cos(kj)+1.0)+(-cos(kk)+1.0));
double kgrad = 1.0;
if( idir==0 )
kgrad = ki;
else if( idir ==1)
kgrad = kj;
else if( idir ==2)
kgrad = kk;
return (kgrad/kr/kr-grad/laplace)*M_PI/n*M_PI/n;
}
template<>
inline double poisson_hybrid_kernel<4>(int idir, int i, int j, int k, int n )
{
if(i==0&&j==0&&k==0)
return 0.0;
double
ki(M_PI*(double)i/(double)n),
kj(M_PI*(double)j/(double)n),
kk(M_PI*(double)k/(double)n),
kr(sqrt(ki*ki+kj*kj+kk*kk));
double grad = 1.0, laplace = 1.0;
if( idir==0 )
grad = 0.166666666667*(-sin(2.*ki)+8.*sin(ki));
else if( idir==1 )
grad = 0.166666666667*(-sin(2.*kj)+8.*sin(kj));
else if( idir==2 )
grad = 0.166666666667*(-sin(2.*kk)+8.*sin(kk));
laplace = 0.1666666667*((cos(2*ki)-16.*cos(ki)+15.)
+(cos(2*kj)-16.*cos(kj)+15.)
+(cos(2*kk)-16.*cos(kk)+15.));
double kgrad = 1.0;
if( idir==0 )
kgrad = ki;
else if( idir ==1)
kgrad = kj;
else if( idir ==2)
kgrad = kk;
return (kgrad/kr/kr-grad/laplace)*M_PI/n*M_PI/n;
}
template<>
inline double poisson_hybrid_kernel<6>(int idir, int i, int j, int k, int n )
{
double
ki(M_PI*(double)i/(double)n),
kj(M_PI*(double)j/(double)n),
kk(M_PI*(double)k/(double)n),
kr(sqrt(ki*ki+kj*kj+kk*kk));
if(i==0&&j==0&&k==0)
return 0.0;
double grad = 1.0, laplace = 1.0;
if( idir==0 )
grad = 0.0333333333333*(sin(3.*ki)-9.*sin(2.*ki)+45.*sin(ki));
else if( idir==1 )
grad = 0.0333333333333*(sin(3.*kj)-9.*sin(2.*kj)+45.*sin(kj));
else if( idir==2 )
grad = 0.0333333333333*(sin(3.*kk)-9.*sin(2.*kk)+45.*sin(kk));
laplace = 0.01111111111111*(
(-2.*cos(3.0*ki)+27.*cos(2.*ki)-270.*cos(ki)+245.)
+(-2.*cos(3.0*kj)+27.*cos(2.*kj)-270.*cos(kj)+245.)
+(-2.*cos(3.0*kk)+27.*cos(2.*kk)-270.*cos(kk)+245.));
double kgrad = 1.0;
if( idir==0 )
kgrad = ki;
else if( idir ==1)
kgrad = kj;
else if( idir ==2)
kgrad = kk;
return (kgrad/kr/kr-grad/laplace)*M_PI/n*M_PI/n;//laplace/grad;
//return kgrad/kr/kr*M_PI/n*M_PI/n;
//return grad/laplace*M_PI/n*M_PI/n;
//return (kgrad/kr/kr-grad/laplace);
}
template<int order>
void do_poisson_hybrid( fftw_real* data, int idir, int nxp, int nyp, int nzp, bool periodic )
{
double fftnorm = 1.0/(nxp*nyp*nzp);
if(periodic)
fftnorm *= nxp/(4.0*M_PI*M_PI);//sqrt(8.0);
/*if(periodic)
fftnorm *= M_PI*M_PI/nxp/nyp/nzp;
else
fftnorm *= M_PI*M_PI/nxp/nyp/nzp;
if( idir == 0 )
fftnorm *= nxp;
else if( idir == 1 )
fftnorm *= nyp;
else
fftnorm *= nzp;*/
fftw_complex *cdata = reinterpret_cast<fftw_complex*>(data);
rfftwnd_plan iplan, plan;
plan = rfftw3d_create_plan( nxp, nyp, nzp,
FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE|FFTW_IN_PLACE);
iplan = rfftw3d_create_plan( nxp, nyp, nzp,
FFTW_COMPLEX_TO_REAL, FFTW_ESTIMATE|FFTW_IN_PLACE);
#ifndef SINGLETHREAD_FFTW
rfftwnd_threads_one_real_to_complex( omp_get_max_threads(), plan, data, NULL );
#else
rfftwnd_one_real_to_complex( plan, data, NULL );
#endif
double ksum = 0.0;
unsigned kcount = 0;
for( int i=0; i<nxp; ++i )
for( int j=0; j<nyp; ++j )
for( int k=0; k<nzp/2+1; ++k )
{
unsigned ii = (i*nyp + j) * (nzp/2+1) + k;
if( k==0 || k==nzp/2 )
{
ksum += cdata[ii].re;
kcount++;
}else{
ksum += 2.0*(cdata[ii].re);
kcount+=2;
}
}
ksum /= kcount;
kcount = 0;
cdata[0].re = 0.0;
cdata[0].im = 0.0;
#pragma omp parallel for
for( int i=0; i<nxp; ++i )
for( int j=0; j<nyp; ++j )
for( int k=0; k<nzp/2+1; ++k )
{
unsigned ii = (i*nyp + j) * (nzp/2+1) + k;
int ki(i), kj(j);
if( ki > nxp/2 ) ki-=nxp;
if( kj > nyp/2 ) kj-=nyp;
//... apply hybrid correction
double dk = poisson_hybrid_kernel<order>(idir, ki, kj, k, nxp/2 );
cdata[ii].re -= ksum;
double re = cdata[ii].re, im = cdata[ii].im;
cdata[ii].re = -im*dk*fftnorm;
cdata[ii].im = re*dk*fftnorm;
cdata[ii].re += ksum*fftnorm;
}
cdata[0].re = 0.0;
cdata[0].im = 0.0;
#ifndef SINGLETHREAD_FFTW
rfftwnd_threads_one_complex_to_real( omp_get_max_threads(), iplan, cdata, NULL);
#else
rfftwnd_one_complex_to_real(iplan, cdata, NULL);
#endif
rfftwnd_destroy_plan(plan);
rfftwnd_destroy_plan(iplan);
}
void poisson_hybrid( MeshvarBnd<double>& f, int idir, int order, bool periodic )
{
int nx=f.size(0), ny=f.size(1), nz=f.size(2), nxp, nyp, nzp;
fftw_real *data;
int xo=0,yo=0,zo=0;
int nmax = std::max(nx,std::max(ny,nz));
if(!periodic)
{
nxp = 2*nmax;
nyp = 2*nmax;
nzp = 2*nmax;
xo = nmax/2;
yo = nmax/2;
zo = nmax/2;
}
else
{
nxp = nmax;
nyp = nmax;
nzp = nmax;
}
data = new fftw_real[nxp*nyp*2*(nzp/2+1)];
if(idir==0)
std::cout << " - Performing hybrid Poisson step... (" << nxp << ", " << nyp << ", " << nzp << ")\n";
for( int i=0; i<nxp*nyp*2*(nzp/2+1); ++i )
data[i]=0.0;
for( int i=0; i<nx; ++i )
for( int j=0; j<ny; ++j )
for( int k=0; k<nz; ++k )
{
int idx = ((i+xo)*nyp + j+yo) * 2*(nzp/2+1) + k+zo;
data[idx] = f(i,j,k);
}
switch (order) {
case 2:
do_poisson_hybrid<2>(data, idir, nxp, nyp, nzp, periodic);
break;
case 4:
do_poisson_hybrid<4>(data, idir, nxp, nyp, nzp, periodic);
break;
case 6:
do_poisson_hybrid<6>(data, idir, nxp, nyp, nzp, periodic);
break;
default:
std::cerr << " - ERROR: invalid operator order specified in deconvolution.";
break;
}
for( int i=0; i<nx; ++i )
for( int j=0; j<ny; ++j )
for( int k=0; k<nz; ++k )
{
int idx = ((i+xo)*nyp + j+yo) * 2*(nzp/2+1) + k+zo;
f(i,j,k) = data[idx];
}
delete[] data;
}
/**************************************************************************************/
/**************************************************************************************/
#pragma mark -
namespace{
poisson_plugin_creator_concrete<multigrid_poisson_plugin> multigrid_poisson_creator("mg_poisson");

View file

@ -29,6 +29,7 @@
#include "general.hh"
//! abstract base class for Poisson solvers and gradient calculations
class poisson_plugin
{
protected:
@ -47,8 +48,13 @@ public:
virtual ~poisson_plugin()
{ }
//! solve Poisson's equation Du=f
virtual double solve( grid_hierarchy& f, grid_hierarchy& u ) = 0;
//! compute the gradient of u
virtual double gradient( int dir, grid_hierarchy& u, grid_hierarchy& Du ) = 0;
//! compute the gradient and add
virtual double gradient_add( int dir, grid_hierarchy& u, grid_hierarchy& Du ) = 0;
};
@ -97,30 +103,55 @@ struct poisson_plugin_creator_concrete : public poisson_plugin_creator
/**************************************************************************************/
#pragma mark -
//! adaptive FAS multigrid implementation of abstract base class poisson_plugin
class multigrid_poisson_plugin : public poisson_plugin
{
public:
//! constructor
explicit multigrid_poisson_plugin( config_file& cf )
: poisson_plugin( cf )
{ }
//! solve Poisson's equation Du=f
double solve( grid_hierarchy& f, grid_hierarchy& u );
//! compute the gradient of u
double gradient( int dir, grid_hierarchy& u, grid_hierarchy& Du );
//! compute the gradient and add
double gradient_add( int dir, grid_hierarchy& u, grid_hierarchy& Du );
protected:
//! various FD approximation implementations
struct implementation
{
//! solve 2nd order FD approximation to Poisson's equation
double solve_O2( grid_hierarchy& f, grid_hierarchy& u );
//! solve 4th order FD approximation to Poisson's equation
double solve_O4( grid_hierarchy& f, grid_hierarchy& u );
//! solve 6th order FD approximation to Poisson's equation
double solve_O6( grid_hierarchy& f, grid_hierarchy& u );
//! compute 2nd order FD gradient
void gradient_O2( int dir, grid_hierarchy& u, grid_hierarchy& Du );
//! compute and add 2nd order FD gradient
void gradient_add_O2( int dir, grid_hierarchy& u, grid_hierarchy& Du );
//! compute 4th order FD gradient
void gradient_O4( int dir, grid_hierarchy& u, grid_hierarchy& Du );
//! compute and add 4th order FD gradient
void gradient_add_O4( int dir, grid_hierarchy& u, grid_hierarchy& Du );
//! compute 6th order FD gradient
void gradient_O6( int dir, grid_hierarchy& u, grid_hierarchy& Du );
//! compute and add 6th order FD gradient
void gradient_add_O6( int dir, grid_hierarchy& u, grid_hierarchy& Du );
};
};
@ -129,23 +160,33 @@ protected:
/**************************************************************************************/
#pragma mark -
//! FFT based implementation of abstract base class poisson_plugin
class fft_poisson_plugin : public poisson_plugin
{
public:
//! constructor
explicit fft_poisson_plugin( config_file& cf )
: poisson_plugin( cf )
{ }
//! solve Poisson's equation Du=f
double solve( grid_hierarchy& f, grid_hierarchy& u );
//! compute the gradient of u
double gradient( int dir, grid_hierarchy& u, grid_hierarchy& Du );
//! compute the gradient and add
double gradient_add( int dir, grid_hierarchy& u, grid_hierarchy& Du ){ return 0.0; }
};
/**************************************************************************************/
/**************************************************************************************/
#pragma mark -
void poisson_hybrid( MeshvarBnd<double>& f, int idir, int order, bool periodic );

View file

@ -226,10 +226,10 @@ protected:
{
std::cerr << " - degrading field for 1 level...(" << res_ << ")\n";
//unsigned ixoff=51,iyoff=51,izoff=51;
//unsigned nx=52, ny=52, nz=52;
unsigned ixoff=102, iyoff=102, izoff=102;
unsigned nx=104, ny=104, nz=104;
unsigned ixoff=51,iyoff=51,izoff=51;
unsigned nx=52, ny=52, nz=52;
//unsigned ixoff=102, iyoff=102, izoff=102;
//unsigned nx=104, ny=104, nz=104;
#pragma omp parallel for
for( unsigned ix=0; ix<res_; ix+=2 )

View file

@ -55,12 +55,13 @@ enum tf_type{
*/
class transfer_function_plugin{
public:
Cosmology cosmo_;
config_file *pcf_;
bool tf_distinct_;
Cosmology cosmo_; //!< cosmological parameter, read from config_file
config_file *pcf_; //!< pointer to config_file from which to read parameters
bool tf_distinct_; //!< bool if transfer function is distinct for baryons and DM
public:
//! constructor
transfer_function_plugin( config_file& cf )
: pcf_( &cf )
{
@ -74,34 +75,50 @@ public:
cosmo_.sigma8 = pcf_->getValue<real_t>( "cosmology", "sigma_8" );
cosmo_.nspect = pcf_->getValue<real_t>( "cosmology", "nspec" );
}
//! destructor
virtual ~transfer_function_plugin(){ };
//! compute value of transfer function at waven umber
virtual double compute( double k, tf_type type) = 0;
//! return maximum wave number allowed
virtual double get_kmax( void ) = 0;
//! return minimum wave number allowed
virtual double get_kmin( void ) = 0;
//! return if transfer function is distinct for baryons and DM
bool tf_is_distinct( void )
{ return tf_distinct_; }
};
//! Implements abstract factory design pattern for transfer function plug-ins
struct transfer_function_plugin_creator
{
//! create an instance of a transfer function plug-in
virtual transfer_function_plugin * create( config_file& cf ) const = 0;
//! destroy an instance of a plug-in
virtual ~transfer_function_plugin_creator() { }
};
//! Write names of registered transfer function plug-ins to stdout
std::map< std::string, transfer_function_plugin_creator *>& get_transfer_function_plugin_map();
void print_transfer_function_plugins( void );
//! Concrete factory pattern for transfer function plug-ins
template< class Derived >
struct transfer_function_plugin_creator_concrete : public transfer_function_plugin_creator
{
//! register the plug-in by its name
transfer_function_plugin_creator_concrete( const std::string& plugin_name )
{
get_transfer_function_plugin_map()[ plugin_name ] = this;
}
//! create an instance of the plug-in
transfer_function_plugin * create( config_file& cf ) const
{
return new Derived( cf );
@ -117,6 +134,7 @@ transfer_function_plugin *select_transfer_function_plugin( config_file& cf );
/**********************************************************************/
/**********************************************************************/
//! k-space transfer function
class TransferFunction_k
{
public:
@ -132,6 +150,19 @@ public:
nspec_ = nspec;
sqrtpnorm_ = sqrt( pnorm_ );
type_ = type;
std::ofstream ofs("input_powerspec.txt");
double kmin=-3, kmax=3, dk=(kmax-kmin)/100.;
for( int i=0; i<100; ++i )
{
double k = pow(10.0,kmin+i*dk);
ofs << std::setw(16) << k
<< std::setw(16) << pow(dplus_*sqrtpnorm_*pow(k,0.5*nspec_)*ptf_->compute(k,type_),2)
<< std::endl;
}
}
inline real_t compute( real_t k ) const
@ -400,9 +431,12 @@ public:
//.. need a factor sqrt( 2*kny^2_x + 2*kny^2_y + 2*kny^2_z )/2 = sqrt(3/2)kny (in equilateral case)
//#warning Need to integrate from Boxsize (see below)?
gsl_integration_qag (&F, 0.0, sqrt(1.5)*knymax, 0, 1e-8, 20000, GSL_INTEG_GAUSS21, wp, &Tr0_, &error);
//gsl_integration_qag (&F, 0.0, 1.24070098*knymax, 0, 1e-8, 20000, GSL_INTEG_GAUSS21, wp, &Tr0_, &error);
//gsl_integration_qag (&F, 0.0, 1.280788*knymax, 0, 1e-8, 20000, GSL_INTEG_GAUSS21, wp, &Tr0_, &error);
//gsl_integration_qag (&F, 0.0, knymax, 0, 1e-8, 20000, GSL_INTEG_GAUSS21, wp, &Tr0_, &error);
//gsl_integration_qag (&F, 0.0, 1.116*knymax, 0, 1e-8, 20000, GSL_INTEG_GAUSS21, wp, &Tr0_, &error);
//gsl_integration_qag (&F, 0.0, sqrt(3)*knymax, 0, 1e-8, 20000, GSL_INTEG_GAUSS21, wp, &Tr0_, &error);
//gsl_integration_qag (&F, 0.0, knymax, 0, 1e-8, 20000, GSL_INTEG_GAUSS21, wp, &Tr0_, &error);
//gsl_integration_qag (&F, 0.0, 0.5*knymax, 0, 1e-8, 20000, GSL_INTEG_GAUSS21, wp, &Tr0_, &error);
gsl_integration_workspace_free(wp);