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

Initial commit, beta version release candidate

This commit is contained in:
Oliver Hahn 2010-07-02 11:49:30 -07:00
commit c48c73488a
37 changed files with 18552 additions and 0 deletions

61
Makefile Normal file
View file

@ -0,0 +1,61 @@
##############################################################################
### compile time configuration options
MULTITHREADFFTW = yes
SINGLEPRECISION = no
HAVEHDF5 = yes
##############################################################################
### compiler and path settings
CC = g++
OPT = -O3
CFLAGS = -Wall -fopenmp
LFLAGS = -fopenmp -lgsl -lgslcblas
CPATHS = -I. -I$(HOME)/local/include -I/opt/local/include -I/usr/local/include
LPATHS = -L$(HOME)/local/lib -L/opt/local/lib -L/usr/local/lib
##############################################################################
# if you have FFTW 2.1.5 with multi-thread support, you can enable the option
ifeq ($(MULTITHREADFFTW), yes)
ifeq ($(SINGLEPRECISION), yes)
LFLAGS += -lsfftw_threads -lsrfftw_threads
else
LFLAGS += -ldfftw_threads -ldrfftw_threads
endif
else
CFLAGS += -DSINGLETHREAD_FFTW
endif
##############################################################################
# this section makes sure that the correct FFTW libraries are linked
ifeq ($(SINGLEPRECISION), yes)
CFLAGS += -DSINGLE_PRECISION
LFLAGS += -lsrfftw -lsfftw
else
LFLAGS += -ldrfftw -ldfftw
endif
##############################################################################
#if you have HDF5 installed, you can also enable the following options
ifeq ($(HAVEHDF5), yes)
OPT += -DH5_USE_16_API -DHAVE_HDF5
LFLAGS += -lhdf5
endif
##############################################################################
CFLAGS += $(OPT)
TARGET = MUSIC
OBJS = output.o transfer_function.o Numerics.o \
convolution_kernel.o densities.o cosmology.o main.o \
$(patsubst plugins/%.cc,plugins/%.o,$(wildcard plugins/*.cc))
##############################################################################
all: $(OBJS) $(TARGET)
$(TARGET): $(OBJS)
$(CC) $(LPATHS) -o $@ $^ $(LFLAGS)
%.o: %.cc *.hh Makefile
$(CC) $(CFLAGS) $(CPATHS) -c $< -o $@
clean:
rm -rf $(OBJS)

154
Numerics.cc Normal file
View file

@ -0,0 +1,154 @@
/*
numerics.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef WITH_MPI
#ifdef MANNO
#include <mpi.h>
#else
#include <mpi++.h>
#endif
#endif
#include <iostream>
#include "Numerics.hh"
#ifndef REL_PRECISION
#define REL_PRECISION 1.e-4
#endif
int Base_interp::locate(const double x)
{
int ju,jm,jl;
if (n < 2 || mm < 2 || mm > n) throw("locate size error");
bool ascnd=(xx[n-1] >= xx[0]);
jl=0;
ju=n-1;
while (ju-jl > 1) {
jm = (ju+jl) >> 1;
if ((x >= xx[jm]) == ascnd)
jl=jm;
else
ju=jm;
}
cor = abs(jl-jsav) > dj ? 0 : 1;
jsav = jl;
return std::max(0,std::min(n-mm,jl-((mm-2)>>1)));
}
int Base_interp::hunt(const double x)
{
int jl=jsav, jm, ju, inc=1;
if (n < 2 || mm < 2 || mm > n) throw("hunt size error");
bool ascnd=(xx[n-1] >= xx[0]);
if (jl < 0 || jl > n-1) {
jl=0;
ju=n-1;
} else {
if ((x >= xx[jl]) == ascnd) {
for (;;) {
ju = jl + inc;
if (ju >= n-1) {
ju = n-1;
break;
} else if ((x < xx[ju]) == ascnd) break;
else {
jl = ju;
inc += inc;
}
}
} else {
ju = jl;
for (;;) {
jl = jl - inc;
if (jl <= 0) { jl = 0; break;}
else if ((x >= xx[jl]) == ascnd) break;
else {
ju = jl;
inc += inc;
}
}
}
}
while (ju-jl > 1) {
jm = (ju+jl) >> 1;
if ((x >= xx[jm]) == ascnd)
jl=jm;
else
ju=jm;
}
cor = abs(jl-jsav) > dj ? 0 : 1;
jsav = jl;
return std::max(0,std::min(n-mm,jl-((mm-2)>>1)));
}
#if 1
real_t integrate( double (* func) (double x, void * params), double a, double b, void *params )
{
gsl_function F;
F.function = func;
F.params = params;//NULL;
double result;
double error;
//size_t neval;
gsl_integration_workspace *w = gsl_integration_workspace_alloc(100000);
gsl_integration_qag( &F, a, b, 0, REL_PRECISION, 100000, 6, w, &result, &error );
//gsl_integration_qng( &F, a, b, 0, REL_PRECISION, &result, &error, &neval );
//gsl_integration_qags( &F, a, b, 0, REL_PRECISION, 10000, w, &result, &error );
gsl_integration_workspace_free(w);
if( error > 10*REL_PRECISION )
std::cerr << " - Warning: no convergence in function 'integrate', rel. error=" << error/result << std::endl;
return (real_t)result;
}
#else
real_t integrate( double (* func) (double x, void * params), double a, double b, void *params )
{
unsigned nn = 1000;
double la = log10(a), lb = log10(b), dlk = (lb-la)/(nn-1);
double sum = 0.0;
for( unsigned i=1; i<nn; ++i )
{
double xr = pow(10.0, la+i*dlk );
double xl = pow(10.0, la+(i-1)*dlk );
sum += (xr-xl)*func(0.5*(xl+xr),params);
}
return sum;
}
#endif

204
Numerics.hh Normal file
View file

@ -0,0 +1,204 @@
/*
numerics.hh - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __NUMERICS_HH
#define __NUMERICS_HH
#ifdef WITH_MPI
#ifdef MANNO
#include <mpi.h>
#else
#include <mpi++.h>
#endif
#endif
#include <cmath>
#include <gsl/gsl_integration.h>
#include <vector>
#include <algorithm>
#include "general.hh"
real_t integrate( double (* func) (double x, void * params), double a, double b, void *params=NULL);
struct Base_interp
{
int n, mm, jsav, cor, dj;
const double *xx, *yy;
Base_interp(std::vector<double> &x, const double *y, int m)
: n(x.size()), mm(m), jsav(0), cor(0), dj(0), xx(&x[0]), yy(y)
{
dj = std::min(1,(int)pow((double)n,0.25));
}
double interp(double x) {
int jlo = cor ? hunt(x) : locate(x);
return rawinterp(jlo,x);
}
virtual ~Base_interp()
{ }
int locate(const double x);
int hunt(const double x);
double virtual rawinterp(int jlo, double x) = 0;
};
class Spline_interp : public Base_interp
{
protected:
std::vector<double> y2;
void sety2( const double *xv, const double *yv, double yp1, double ypn)
{
int i,k;
double p,qn,sig,un;
//int n=y2.size();
std::vector<double> u(n-1,0.0);
if (yp1 > 0.99e99)
y2[0]=u[0]=0.0;
else {
y2[0] = -0.5;
u[0]=(3.0/(xv[1]-xv[0]))*((yv[1]-yv[0])/(xv[1]-xv[0])-yp1);
}
for (i=1;i<n-1;i++) {
sig=(xv[i]-xv[i-1])/(xv[i+1]-xv[i-1]);
p=sig*y2[i-1]+2.0;
y2[i]=(sig-1.0)/p;
u[i]=(yv[i+1]-yv[i])/(xv[i+1]-xv[i]) - (yv[i]-yv[i-1])/(xv[i]-xv[i-1]);
u[i]=(6.0*u[i]/(xv[i+1]-xv[i-1])-sig*u[i-1])/p;
}
if (ypn > 0.99e99)
qn=un=0.0;
else {
qn=0.5;
un=(3.0/(xv[n-1]-xv[n-2]))*(ypn-(yv[n-1]-yv[n-2])/(xv[n-1]-xv[n-2]));
}
y2[n-1]=(un-qn*u[n-2])/(qn*y2[n-2]+1.0);
for (k=n-2;k>=0;k--)
y2[k]=y2[k]*y2[k+1]+u[k];
}
public:
Spline_interp( std::vector<double> &xv, std::vector<double> &yv, double yp1=1e99, double ypn=1.e99 )
: Base_interp( xv, &yv[0], xv.size() ), y2( xv.size(), 0.0 )
{
sety2( &xv[0], &yv[0], yp1, ypn );
}
virtual ~Spline_interp()
{ }
double rawinterp( int jl, double x )
{
int klo=jl,khi=jl+1;
double y,h,b,a;
h=xx[khi]-xx[klo];
if (h == 0.0) throw("Bad input to routine splint");
a=(xx[khi]-x)/h;
b=(x-xx[klo])/h;
y=a*yy[klo]+b*yy[khi]+((a*a*a-a)*y2[klo] +(b*b*b-b)*y2[khi])*(h*h)/6.0;
return y;
}
};
#if 1
inline unsigned locate( const double x, const std::vector<double> vx )
{
long unsigned ju,jm,jl;
bool ascnd=(vx[vx.size()-1]>=vx[0]);
jl = 0;
ju = vx.size()-1;
while( ju-jl > 1 ) {
jm = (ju+jl)>>1;
if( (x >= vx[jm]) == ascnd )
jl = jm;
else
ju = jm;
}
return std::max((long unsigned)0,std::min((long unsigned)(vx.size()-2),(long unsigned)jl));
}
#else
inline unsigned locate( const real_t x, const std::vector<double> vx )
{
unsigned i=0;
while( vx[i]<x && (unsigned)i< vx.size() ) ++i;
if(i>0)i=i-1;
return i;
}
#endif
inline real_t linint( const double x, const std::vector<double>& xx, const std::vector<double>& yy )
{
unsigned i = locate(x,xx);
/* if(i==xx.size()-1) //--i;
return 0.0;
if( x<xx[0] )
return 0.0;*/
if( x<xx[0] )
return yy[0];
if( x>=xx[xx.size()-1] )
return yy[yy.size()-1];
double a = 1.0/(xx[i+1]-xx[i]);
double dy = (yy[i+1]-yy[i])*a;
double y0 = (yy[i]*xx[i+1]-xx[i]*yy[i+1])*a;
return dy*x+y0;
}
/*
inline float linint( float x, const std::vector<float>& xx, const std::vector<float>& yy )
{
int i=0;
while( xx[i]<x && (unsigned)i< xx.size() ) ++i;
if(i>0)i=i-1;
float dy = (yy[i+1]-yy[i])/(xx[i+1]-xx[i]);
float y0 = (yy[i]*xx[i+1]-xx[i]*yy[i+1])/(xx[i+1]-xx[i]);
return dy*x+y0;
}
*/
#endif

1318
TransferFunction.hh Normal file

File diff suppressed because it is too large Load diff

327
config_file.hh Normal file
View file

@ -0,0 +1,327 @@
/*
config_file.hh - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CONFIG_FILE_HH
#define __CONFIG_FILE_HH
#include <string>
#include <sstream>
#include <map>
#include <fstream>
#include <iostream>
#include <iomanip>
#include <stdexcept>
#include <typeinfo>
/*!
* @class config_file
* @brief provides read/write access to configuration options
*
* This class provides access to the configuration file. The
* configuration is stored in hash-pairs and can be queried and
* validated by the responsible class/routine
*/
class config_file {
//! current line number
unsigned m_iLine;
//! hash table for key/value pairs, stored as strings
std::map<std::string, std::string> m_Items;
public:
//! removes all white space from string source
/*!
* @param source the string to be trimmed
* @param delims a string of delimiting characters
* @return trimmed string
*/
std::string trim(std::string const& source, char const* delims = " \t\r\n") const{
std::string result(source);
//... skip initial whitespace ...
std::string::size_type index = result.find_last_not_of(delims);
if(index != std::string::npos)
result.erase(++index);
//... find beginning of trailing whitespace ...
index = result.find_first_not_of(delims);
//... remove trailing whitespace ...
if(index != std::string::npos)
result.erase(0, index);
else
result.erase();
return result;
}
//! converts between different variable types
/*!
* The main purpose of this function is to parse and convert
* a string argument into numbers, booleans, etc...
* @param ival the input value (typically a std::string)
* @param oval the interpreted/converted value
*/
template <class in_value, class out_value>
void convert( const in_value & ival, out_value & oval) const
{
std::stringstream ss;
ss << ival; //.. insert value into stream
ss >> oval; //.. retrieve value from stream
if (! ss.eof()) {
//.. conversion error
std::cerr << "Error: conversion of \'" << ival << "\' failed." << std::endl;
throw ErrInvalidConversion(std::string("invalid conversion to ")+typeid(out_value).name()+'.');
}
}
//! constructor of class config_file
/*! @param FileName the path/name of the configuration file to be parsed
*/
config_file( std::string const& FileName )
: m_iLine(0), m_Items()
{
std::ifstream file(FileName.c_str());
if( !file.is_open() )
throw std::runtime_error(std::string("Error: Could not open config file \'")+FileName+std::string("\'"));
std::string line;
std::string name;
std::string value;
std::string inSection;
int posEqual;
m_iLine=0;
//.. walk through all lines ..
while (std::getline(file,line)) {
++m_iLine;
//.. encounterd EOL ?
if (! line.length()) continue;
//.. encountered comment ?
unsigned long idx;
if( (idx=line.find_first_of("#;%")) != std::string::npos )
line.erase(idx);
//.. encountered section tag ?
if (line[0] == '[') {
inSection=trim(line.substr(1,line.find(']')-1));
continue;
}
//.. seek end of entry name ..
posEqual=line.find('=');
name = trim(line.substr(0,posEqual));
value = trim(line.substr(posEqual+1));
//.. add key/value pair to hash table ..
m_Items[inSection+'/'+name] = value;
}
}
//! inserts a key/value pair in the hash map
/*! @param key the key value, usually "section/key"
* @param value the value of the key, also a string
*/
void insertValue( std::string const& key, std::string const& value )
{
m_Items[key] = value;
}
//! inserts a key/value pair in the hash map
/*! @param section section name. values are stored under "section/key"
* @param key the key value usually "section/key"
* @param value the value of the key, also a string
*/
void insertValue( std::string const& section, std::string const& key, std::string const& value )
{
m_Items[section+'/'+key] = value;
}
//! checks if a key is part of the hash map
/*! @param section the section name of the key
* @param key the key name to be checked
* @return true if the key is present, false otherwise
*/
bool containsKey( std::string const& section, std::string const& key )
{
std::map<std::string,std::string>::const_iterator i = m_Items.find(section+'/'+key);
if ( i == m_Items.end() )
return false;
return true;
}
//! checks if a key is part of the hash map
/*! @param key the key name to be checked
* @return true if the key is present, false otherwise
*/
bool containsKey( std::string const& key )
{
std::map<std::string,std::string>::const_iterator i = m_Items.find(key);
if ( i == m_Items.end() )
return false;
return true;
}
//! return value of a key
/*! returns the value of a given key, throws a ErrItemNotFound
* exception if the key is not available in the hash map.
* @param key the key name
* @return the value of the key
* @sa ErrItemNotFound
*/
template<class T> T getValue( std::string const& key ) const{
return getValue<T>( "", key );
}
//! return value of a key
/*! returns the value of a given key, throws a ErrItemNotFound
* exception if the key is not available in the hash map.
* @param section the section name for the key
* @param key the key name
* @return the value of the key
* @sa ErrItemNotFound
*/
template<class T> T getValue( std::string const& section, std::string const& key ) const
{
T r;
std::map<std::string,std::string>::const_iterator i = m_Items.find(section + '/' + key);
if ( i == m_Items.end() )
throw ErrItemNotFound('\'' + section + '/' + key + std::string("\' not found."));
convert(i->second,r);
return r;
}
//! exception safe version of getValue
/*! returns the value of a given key, returns a default value rather
* than a ErrItemNotFound exception if the key is not found.
* @param section the section name for the key
* @param key the key name
* @param default_value the value that is returned if the key is not found
* @return the key value (if key found) otherwise default_value
*/
template<class T> T getValueSafe( std::string const& section, std::string const& key, T default_value ) const
{
T r;
try{
r = getValue<T>( section, key );
} catch( ErrItemNotFound ) {
r = default_value;
}
return r;
}
//! exception safe version of getValue
/*! returns the value of a given key, returns a default value rather
* than a ErrItemNotFound exception if the key is not found.
* @param key the key name
* @param default_value the value that is returned if the key is not found
* @return the key value (if key found) otherwise default_value
*/
template<class T> T getValueSafe( std::string const& key, T default_value ) const
{
return getValueSafe( "", key, default_value );
}
//! dumps all key-value pairs to a std::ostream
void dump( std::ostream& out )
{
std::map<std::string,std::string>::const_iterator i = m_Items.begin();
while( i!=m_Items.end() )
{
if( i->second.length() > 0 )
out << std::setw(24) << std::left << i->first << " = " << i->second << std::endl;
++i;
}
}
//--- EXCEPTIONS ---
//! runtime error that is thrown if key is not found in getValue
class ErrItemNotFound : public std::runtime_error{
public:
ErrItemNotFound( std::string itemname )
: std::runtime_error( itemname.c_str() )
{}
};
//! runtime error that is thrown if type conversion fails
class ErrInvalidConversion : public std::runtime_error{
public:
ErrInvalidConversion( std::string errmsg )
: std::runtime_error( errmsg )
{}
};
class ErrIllegalIdentifier : public std::runtime_error{
public:
ErrIllegalIdentifier( std::string errmsg )
: std::runtime_error( errmsg )
{}
};
};
//==== below are template specialisations =======================================//
//... Function: getValue( strSection, strEntry ) ...
//... Descript: specialization of getValue for type boolean to interpret strings ...
//... like "true" and "false" etc.
//... converts the string to type bool, returns type bool ...
template<>
inline bool config_file::getValue<bool>( std::string const& strSection, std::string const& strEntry ) const{
std::string r1 = getValue<std::string>( strSection, strEntry );
if( r1=="true" || r1=="yes" || r1=="on" || r1=="1" )
return true;
if( r1=="false" || r1=="no" || r1=="off" || r1=="0" )
return false;
throw ErrIllegalIdentifier(std::string("Illegal identifier \'")+r1+std::string("\' in \'")+strEntry+std::string("\'."));
//return false;
}
template<>
inline bool config_file::getValueSafe<bool>( std::string const& strSection, std::string const& strEntry, bool defaultValue ) const{
std::string r1;
try{
r1 = getValue<std::string>( strSection, strEntry );
if( r1=="true" || r1=="yes" || r1=="on" || r1=="1" )
return true;
if( r1=="false" || r1=="no" || r1=="off" || r1=="0" )
return false;
} catch( ErrItemNotFound ) {
return defaultValue;
}
return defaultValue;
}
template<>
inline void config_file::convert<std::string,std::string>( const std::string & ival, std::string & oval) const
{
oval = ival;
}
#endif //__CONFIG_FILE_HH

583
convolution_kernel.cc Normal file
View file

@ -0,0 +1,583 @@
/*
convolution_kernel.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef SINGLE_PRECISION
#ifdef SINGLETHREAD_FFTW
#include <srfftw.h>
#else
#include <srfftw_threads.h>
#endif
#else
#ifdef SINGLETHREAD_FFTW
#include <drfftw.h>
#else
#include <drfftw_threads.h>
#endif
#endif
#include "densities.hh"
#include "convolution_kernel.hh"
namespace convolution{
std::map< std::string, kernel_creator *>&
get_kernel_map()
{
static std::map< std::string, kernel_creator* > kernel_map;
return kernel_map;
}
template< typename real_t >
void perform( kernel * pk, void *pd )
{
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));
fftw_complex *cdata,*ckernel;
fftw_real *data;
data = reinterpret_cast<fftw_real*>(pd);
cdata = reinterpret_cast<fftw_complex*>(data);
ckernel = reinterpret_cast<fftw_complex*>( pk->get_ptr() );
rfftwnd_plan iplan, plan;
plan = rfftw3d_create_plan( cparam_.nx, cparam_.ny, cparam_.nz,
FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE|FFTW_IN_PLACE);
iplan = rfftw3d_create_plan( cparam_.nx, cparam_.ny, cparam_.nz,
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
#pragma omp parallel for
for( int i=0; i<cparam_.nx; ++i )
for( int j=0; j<cparam_.ny; ++j )
for( int k=0; k<cparam_.nz/2+1; ++k )
{
unsigned ii = (i*cparam_.ny + j) * (cparam_.nz/2+1) + k;
complex 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();
}
#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);
}
template< typename real_t >
void perform_filtered( kernel * pk, void *pd )
{
parameters cparam_ = pk->cparam_;
double
kny, kmax,
fftnorm = pow(2.0*M_PI,1.5)/sqrt(cparam_.lx*cparam_.ly*cparam_.lz)/sqrt((double)(cparam_.nx*cparam_.ny*cparam_.nz));
fftw_complex *cdata,*ckernel;
fftw_real *data;
kny = cparam_.nx*M_PI/cparam_.lx;
kmax = M_PI/2.0;
data = reinterpret_cast<fftw_real*>(pd);
cdata = reinterpret_cast<fftw_complex*>(data);
ckernel = reinterpret_cast<fftw_complex*>( pk->get_ptr() );
rfftwnd_plan iplan, plan;
plan = rfftw3d_create_plan( cparam_.nx, cparam_.ny, cparam_.nz,
FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE|FFTW_IN_PLACE);
iplan = rfftw3d_create_plan( cparam_.nx, cparam_.ny, cparam_.nz,
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 kmax2 = kmax*kmax;
#pragma omp parallel for
for( int i=0; i<cparam_.nx; ++i )
for( int j=0; j<cparam_.ny; ++j )
for( int k=0; k<cparam_.nz/2+1; ++k )
{
unsigned ii = (i*cparam_.ny + j) * (cparam_.nz/2+1) + k;
complex ccdata(cdata[ii].re,cdata[ii].im), cckernel(ckernel[ii].re,ckernel[ii].im);
int ik(i), jk(j);
if( ik > cparam_.nx/2 )
ik -= cparam_.nx;
if( jk > cparam_.ny/2 )
jk -= cparam_.ny;
double
kx( M_PI*(double)ik/cparam_.nx ),
ky( M_PI*(double)jk/cparam_.ny ),
kz( M_PI*(double)k/cparam_.nz );//,
// kk( kx*kx+ky*ky+kz*kz );
//... cos(k) is the Hanning filter function (cf. Bertschinger 2001)
double filter = 0.0;
if( true ){//kk <= kmax2 ){
//filter = cos( kx )*cos( ky )*cos( kz );
filter = cos( 0.5*kx )*cos( 0.5*ky )*cos( 0.5*kz );
//filter = 1.0;
//filter *=filter;
}
//filter = 1.0;
ccdata = ccdata * cckernel *fftnorm * filter;
cdata[ii].re = ccdata.real();
cdata[ii].im = ccdata.imag();
}
#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);
}
template void perform<double>( kernel* pk, void *pd );
template void perform<float>( kernel* pk, void *pd );
template void perform_filtered<double>( kernel* pk, void *pd );
template void perform_filtered<float>( kernel* pk, void *pd );
void truncate( kernel* pk, double R, double alpha )
{
parameters cparam_ = pk->cparam_;
double
dx = cparam_.lx/cparam_.nx,
dy = cparam_.ly/cparam_.ny,
dz = cparam_.lz/cparam_.nz;
double fftnorm = 1.0/(cparam_.nx * cparam_.ny * cparam_.nz);
rfftwnd_plan iplan, plan;
plan = rfftw3d_create_plan( cparam_.nx, cparam_.ny, cparam_.nz,
FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE|FFTW_IN_PLACE);
iplan = rfftw3d_create_plan( cparam_.nx, cparam_.ny, cparam_.nz,
FFTW_COMPLEX_TO_REAL, FFTW_ESTIMATE|FFTW_IN_PLACE);
fftw_real *rkernel = reinterpret_cast<fftw_real*>( pk->get_ptr() );
fftw_complex *ckernel = reinterpret_cast<fftw_complex*>( pk->get_ptr() );
#ifndef SINGLETHREAD_FFTW
rfftwnd_threads_one_complex_to_real( omp_get_max_threads(), iplan, ckernel, NULL);
#else
rfftwnd_one_complex_to_real(iplan, ckernel, NULL);
#endif
#pragma omp parallel for
for( int i=0; i<cparam_.nx; ++i )
for( int j=0; j<cparam_.ny; ++j )
for( int k=0; k<cparam_.nz; ++k )
{
int iix(i), iiy(j), iiz(k);
double rr[3], rr2;
if( iix > (int)cparam_.nx/2 ) iix -= cparam_.nx;
if( iiy > (int)cparam_.ny/2 ) iiy -= cparam_.ny;
if( iiz > (int)cparam_.nz/2 ) iiz -= cparam_.nz;
rr[0] = (double)iix * dx;
rr[1] = (double)iiy * dy;
rr[2] = (double)iiz * dz;
rr2 = rr[0]*rr[0] + rr[1]*rr[1] + rr[2]*rr[2];
unsigned idx = (i*cparam_.ny + j) * 2*(cparam_.nz/2+1) + k;
rkernel[idx] *= 0.5*(erfc((sqrt(rr2)-R)*alpha))*fftnorm;
}
#ifndef SINGLETHREAD_FFTW
rfftwnd_threads_one_real_to_complex( omp_get_max_threads(), plan, rkernel, NULL );
#else
rfftwnd_one_real_to_complex( plan, rkernel, NULL );
#endif
}
void truncate_sharp( kernel* pk, double R )
{
parameters cparam_ = pk->cparam_;
double
dx = cparam_.lx/cparam_.nx,
dy = cparam_.ly/cparam_.ny,
dz = cparam_.lz/cparam_.nz,
R2 = R*R;
double fftnorm = 1.0/(cparam_.nx * cparam_.ny * cparam_.nz);
rfftwnd_plan iplan, plan;
plan = rfftw3d_create_plan( cparam_.nx, cparam_.ny, cparam_.nz,
FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE|FFTW_IN_PLACE);
iplan = rfftw3d_create_plan( cparam_.nx, cparam_.ny, cparam_.nz,
FFTW_COMPLEX_TO_REAL, FFTW_ESTIMATE|FFTW_IN_PLACE);
fftw_real *rkernel = reinterpret_cast<fftw_real*>( pk->get_ptr() );
fftw_complex *ckernel = reinterpret_cast<fftw_complex*>( pk->get_ptr() );
#ifndef SINGLETHREAD_FFTW
rfftwnd_threads_one_complex_to_real( omp_get_max_threads(), iplan, ckernel, NULL);
#else
rfftwnd_one_complex_to_real(iplan, ckernel, NULL);
#endif
#pragma omp parallel for
for( int i=0; i<cparam_.nx; ++i )
for( int j=0; j<cparam_.ny; ++j )
for( int k=0; k<cparam_.nz; ++k )
{
int iix(i), iiy(j), iiz(k);
double rr[3], rr2;
if( iix > (int)cparam_.nx/2 ) iix -= cparam_.nx;
if( iiy > (int)cparam_.ny/2 ) iiy -= cparam_.ny;
if( iiz > (int)cparam_.nz/2 ) iiz -= cparam_.nz;
rr[0] = (double)iix * dx;
rr[1] = (double)iiy * dy;
rr[2] = (double)iiz * dz;
rr2 = rr[0]*rr[0] + rr[1]*rr[1] + rr[2]*rr[2];
unsigned idx = (i*cparam_.ny + j) * 2*(cparam_.nz/2+1) + k;
if( rr2 > R2 )
{
rkernel[idx] = 0.0;
}else {
rkernel[idx] *= fftnorm;
}
}
#ifndef SINGLETHREAD_FFTW
rfftwnd_threads_one_real_to_complex( omp_get_max_threads(), plan, rkernel, NULL );
#else
rfftwnd_one_real_to_complex( plan, rkernel, NULL );
#endif
}
/*****************************************************************************************\
*** SPECIFIC KERNEL IMPLEMENTATIONS *********************************************
\*****************************************************************************************/
template< typename real_t >
class kernel_real : public kernel
{
protected:
std::vector<real_t> kdata_;
void compute_kernel( void );
public:
kernel_real( const parameters& cp )
: kernel( cp )
{
kdata_.assign( cparam_.nx*cparam_.ny*2*(cparam_.nz/2+1), 0.0 );
compute_kernel();
}
void *get_ptr()
{ return reinterpret_cast<void*> (&kdata_[0]); }
~kernel_real()
{ std::vector<real_t>().swap( kdata_ ); }
};
template< typename real_t >
void kernel_real<real_t>::compute_kernel( void )
{
double
kny = cparam_.nx*M_PI/cparam_.lx,
fac = cparam_.lx*cparam_.ly*cparam_.lz/pow(2.0*M_PI,3)/(cparam_.nx*cparam_.ny*cparam_.nz),
dx = cparam_.lx/cparam_.nx,
dy = cparam_.ly/cparam_.ny,
dz = cparam_.lz/cparam_.nz,
boxlength = cparam_.pcf->getValue<double>("setup","boxlength"),
nspec = cparam_.pcf->getValue<double>("cosmology","nspec"),//cosmo.nspect,
pnorm = cparam_.pcf->getValue<double>("cosmology","pnorm"),//cosmo.pnorm,
dplus = cparam_.pcf->getValue<double>("cosmology","dplus");//,//cosmo.dplus;
// t00f = cparam_.t0scale;
unsigned
levelmax = cparam_.pcf->getValue<unsigned>("setup","levelmax");
bool
bperiodic = cparam_.pcf->getValueSafe<bool>("setup","periodic_TF",true);
//if( cparam_.normalize )
// kny *= 2.0;
TransferFunction_real *tfr = new TransferFunction_real(cparam_.ptf,nspec,pnorm,dplus,0.25*cparam_.lx/(double)cparam_.nx,2.0*boxlength,kny, (int)pow(2,levelmax+2));
if( bperiodic )
{
#pragma omp parallel for
for( int i=0; i<cparam_.nx; ++i )
for( int j=0; j<cparam_.ny; ++j )
for( int k=0; k<cparam_.nz; ++k )
{
int iix(i), iiy(j), iiz(k);
double rr[3], rr2;
if( iix > (int)cparam_.nx/2 ) iix -= cparam_.nx;
if( iiy > (int)cparam_.ny/2 ) iiy -= cparam_.ny;
if( iiz > (int)cparam_.nz/2 ) iiz -= cparam_.nz;
unsigned idx = (i*cparam_.ny + j) * 2*(cparam_.nz/2+1) + k;
for( int ii=-1; ii<=1; ++ii )
for( int jj=-1; jj<=1; ++jj )
for( int kk=-1; kk<=1; ++kk )
{
rr[0] = ((double)iix ) * dx + ii*boxlength;
rr[1] = ((double)iiy ) * dy + jj*boxlength;
rr[2] = ((double)iiz ) * dz + kk*boxlength;
if( fabs(rr[0]) < boxlength
&& fabs(rr[1]) < boxlength
&& fabs(rr[2]) < boxlength )
{
rr2 = rr[0]*rr[0]+rr[1]*rr[1]+rr[2]*rr[2];
kdata_[idx] += tfr->compute_real(rr2);
}
}
kdata_[idx] *= fac;
}
}else{
#pragma omp parallel for
for( int i=0; i<cparam_.nx; ++i )
for( int j=0; j<cparam_.ny; ++j )
for( int k=0; k<cparam_.nz; ++k )
{
int iix(i), iiy(j), iiz(k);
double rr[3], rr2;
if( iix > (int)cparam_.nx/2 ) iix -= cparam_.nx;
if( iiy > (int)cparam_.ny/2 ) iiy -= cparam_.ny;
if( iiz > (int)cparam_.nz/2 ) iiz -= cparam_.nz;
unsigned idx = (i*cparam_.ny + j) * 2*(cparam_.nz/2+1) + k;
rr[0] = ((double)iix ) * dx;
rr[1] = ((double)iiy ) * dy;
rr[2] = ((double)iiz ) * dz;
rr2 = rr[0]*rr[0]+rr[1]*rr[1]+rr[2]*rr[2];
kdata_[idx] = tfr->compute_real(rr2)*fac;
}
}
//kdata_[0] = tfr->compute_real(dx*dx*0.25)*fac;
//std::cerr << "T(r=0) = " << kdata_[0]/fac << std::endl;
//if( cparam_.normalize )
// kdata_[0] *= 0.125;//= 0.0;//*= 0.125;
//... determine normalization
double sum = 0.0;
#pragma omp parallel for
for( int i=0; i<cparam_.nx; ++i )
for( int j=0; j<cparam_.ny; ++j )
for( int k=0; k<cparam_.nz; ++k )
{
unsigned idx = (i*cparam_.ny + j) * 2*(cparam_.nz/2+1) + k;
//if( idx > 0 )
sum += kdata_[idx];
}
//std::cerr << " - The convolution kernel has avg of " << (sum+kdata_[0])/(cparam_.nx*cparam_.ny*cparam_.nz) << std::endl;
sum /= cparam_.nx*cparam_.ny*cparam_.nz;//-1;
if( cparam_.normalize )
{
/*for( int i=0; i<cparam_.nx; ++i )
for( int j=0; j<cparam_.ny; ++j )
for( int k=0; k<cparam_.nz; ++k )
{
unsigned idx = (i*cparam_.ny + j) * 2*(cparam_.nz/2+1) + k;
//if( idx > 0 )
kdata_[idx] -= sum;
}*/
}
//if( t00f < 0.0 )
// kdata_[0] += (tfr->compute_real(0.125*dx*dx) - tfr->compute_real(0.0))*fac;
fftw_real *rkernel = reinterpret_cast<fftw_real*>( &kdata_[0] );
rfftwnd_plan plan = rfftw3d_create_plan( cparam_.nx, cparam_.ny, cparam_.nz,
FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE|FFTW_IN_PLACE);
#ifndef SINGLETHREAD_FFTW
rfftwnd_threads_one_real_to_complex( omp_get_max_threads(), plan, rkernel, NULL );
#else
rfftwnd_one_real_to_complex( plan, rkernel, NULL );
#endif
rfftwnd_destroy_plan(plan);
delete tfr;
}
template< typename real_t >
class kernel_k : public kernel
{
protected:
std::vector<real_t> kdata_;
void compute_kernel( void );
public:
kernel_k( const parameters& cp )
: kernel( cp )
{
kdata_.assign( cparam_.nx*cparam_.ny*2*(cparam_.nz/2+1), 0.0 );
compute_kernel();
}
void *get_ptr()
{ return reinterpret_cast<void*> (&kdata_[0]); }
~kernel_k()
{ std::vector<real_t>().swap( kdata_ ); }
};
template< typename real_t >
void kernel_k<real_t>::compute_kernel( void )
{
double
//kny = cparam_.nx*M_PI/cparam_.lx,
fac = cparam_.lx*cparam_.ly*cparam_.lz/pow(2.0*M_PI,3),// /(cparam_.nx*cparam_.ny*cparam_.nz),
// dx = cparam_.lx/cparam_.nx,
// dy = cparam_.ly/cparam_.ny,
// dz = cparam_.lz/cparam_.nz,
boxlength = cparam_.pcf->getValue<double>("setup","boxlength"),
nspec = cparam_.pcf->getValue<double>("cosmology","nspec"),
pnorm = cparam_.pcf->getValue<double>("cosmology","pnorm"),
dplus = cparam_.pcf->getValue<double>("cosmology","dplus");
TransferFunction_k *tfk = new TransferFunction_k(cparam_.ptf,nspec,pnorm,dplus);
fftw_complex *kdata = reinterpret_cast<fftw_complex*> ( this->get_ptr() );
unsigned nx = cparam_.nx, ny = cparam_.ny, nz = cparam_.nz, nzp = (nz/2+1);
fac =1.0;//*= 1.0/sqrt(nx*ny*nz);
double kfac = 2.0*M_PI/boxlength;
unsigned q=0;
for( int i=0; i<cparam_.nx; ++i )
for( int j=0; j<cparam_.ny; ++j )
for( int k=0; k<cparam_.nz/2+1; ++k )
{
double kx,ky,kz;
kx = (double)i;
ky = (double)j;
kz = (double)k;
if( kx > nx/2 ) kx -= nx;
if( ky > ny/2 ) ky -= ny;
q = (i*ny+j)*nzp+k;
kdata[q].re = fac*tfk->compute(kfac*sqrt(kx*kx+ky*ky+kz*kz));
kdata[q].im = 0.0;
}
delete tfk;
}
};
namespace{
convolution::kernel_creator_concrete< convolution::kernel_real<double> > creator_d("tf_kernel_real_double");
convolution::kernel_creator_concrete< convolution::kernel_real<float> > creator_f("tf_kernel_real_float");
convolution::kernel_creator_concrete< convolution::kernel_k<double> > creator_kd("tf_kernel_k_double");
convolution::kernel_creator_concrete< convolution::kernel_k<float> > creator_kf("tf_kernel_k_float");
}

116
convolution_kernel.hh Normal file
View file

@ -0,0 +1,116 @@
/*
convolution_kernel.hh - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __CONVOLUTION_KERNELS_HH
#define __CONVOLUTION_KERNELS_HH
#include <string>
#include <map>
#include "config_file.hh"
#include "densities.hh"
#include "transfer_function.hh"
namespace convolution{
//! encapsulates all parameters required for transfer function convolution
struct parameters
{
int nx,ny,nz;
double lx,ly,lz;//,boxlength;
config_file *pcf;
transfer_function* ptf;
bool normalize;
};
//! abstract base class for a transfer function convolution kernel
class kernel{
public:
//! all parameters (physical/numerical)
parameters cparam_;
//! constructor
kernel( const parameters& cp )
: cparam_( cp )
{ }
//! virtual destructor
virtual ~kernel(){ };
//! purely virtual method to obtain a pointer to the underlying data
virtual void* get_ptr() = 0;
};
//! abstract factory class to create convolution kernels
struct kernel_creator
{
//! creates a convolution kernel object
virtual kernel * create( const parameters& cp ) const = 0;
//! destructor
virtual ~kernel_creator() { }
};
//! access map to the various kernel classes through the factory
std::map< std::string, kernel_creator *>& get_kernel_map();
//! actual implementation of the factory class for kernel objects
template< class Derived >
struct kernel_creator_concrete : public kernel_creator
{
//! constructor inserts the kernel class in the map
kernel_creator_concrete( const std::string& kernel_name )
{ get_kernel_map()[ kernel_name ] = this; }
//! creates an instance of the kernel object
kernel * create( const parameters& cp ) const
{ return new Derived( cp ); }
};
//! actual implementation of the FFT convolution (independent of the actual kernel)
template< typename real_t >
void perform( kernel* pk, void *pd );
//! actual implementation of the FFT convolution (independent of the actual kernel)
//! with Hann (cf. Bertschinger 2001) window filter applied
template< typename real_t >
void perform_filtered( kernel* pk, void *pd );
//! truncate the kernel softly at R, used for boundary corrections
void truncate( kernel*pk, double R, double alpha );
//! truncate the kernel sharply at R, used for boundary corrections
void truncate_sharp( kernel*pk, double R );
}; //namespace convolution
#endif //__CONVOLUTION_KERNELS_HH

222
cosmology.cc Normal file
View file

@ -0,0 +1,222 @@
/*
cosmology.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "cosmology.hh"
#include "mesh.hh"
#include "mg_operators.hh"
#define ACC(i,j,k) ((*u.get_grid((ilevel)))((i),(j),(k)))
#define SQR(x) ((x)*(x))
void compute_LLA_density( const grid_hierarchy& u, grid_hierarchy& fnew, unsigned order )
{
fnew = u;
for( unsigned ilevel=u.levelmin(); ilevel<=u.levelmax(); ++ilevel )
{
double h = pow(2.0,ilevel), h2 = h*h, h2_4 = 0.25*h2;
meshvar_bnd *pvar = fnew.get_grid(ilevel);
if( order == 2 )
{
#pragma omp parallel for //reduction(+:sum_corr,sum,sum2)
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
{
double D[3][3];
D[0][0] = (ACC(ix-1,iy,iz)-2.0*ACC(ix,iy,iz)+ACC(ix+1,iy,iz)) * h2;
D[1][1] = (ACC(ix,iy-1,iz)-2.0*ACC(ix,iy,iz)+ACC(ix,iy+1,iz)) * h2;
D[2][2] = (ACC(ix,iy,iz-1)-2.0*ACC(ix,iy,iz)+ACC(ix,iy,iz+1)) * h2;
D[0][1] = D[1][0] = (ACC(ix-1,iy-1,iz)-ACC(ix-1,iy+1,iz)-ACC(ix+1,iy-1,iz)+ACC(ix+1,iy+1,iz))*h2_4;
D[0][2] = D[2][0] = (ACC(ix-1,iy,iz-1)-ACC(ix-1,iy,iz+1)-ACC(ix+1,iy,iz-1)+ACC(ix+1,iy,iz+1))*h2_4;
D[1][2] = D[2][1] = (ACC(ix,iy-1,iz-1)-ACC(ix,iy-1,iz+1)-ACC(ix,iy+1,iz-1)+ACC(ix,iy+1,iz+1))*h2_4;
(*pvar)(ix,iy,iz) = D[0][0]+D[1][1]+D[2][2] +
( D[0][0]*D[1][1] + D[0][0]*D[2][2] + D[1][1]*D[2][2] +
D[0][1]*D[1][0] + D[0][2]*D[2][0] + D[1][2]*D[2][1] +
D[0][0]*D[0][0] + D[1][1]*D[1][1] + D[2][2]*D[2][2] );
}
}
else if ( order == 4 )
{
#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
{
double D[3][3];
D[0][0] = (-ACC(ix-2,iy,iz)+16.*ACC(ix-1,iy,iz)-30.0*ACC(ix,iy,iz)+16.*ACC(ix+1,iy,iz)-ACC(ix+2,iy,iz)) * h2/12.0;
D[1][1] = (-ACC(ix,iy-2,iz)+16.*ACC(ix,iy-1,iz)-30.0*ACC(ix,iy,iz)+16.*ACC(ix,iy+1,iz)-ACC(ix,iy+2,iz)) * h2/12.0;
D[2][2] = (-ACC(ix,iy,iz-2)+16.*ACC(ix,iy,iz-1)-30.0*ACC(ix,iy,iz)+16.*ACC(ix,iy,iz+1)-ACC(ix,iy,iz+2)) * h2/12.0;
D[0][1] = D[1][0] = (ACC(ix-1,iy-1,iz)-ACC(ix-1,iy+1,iz)-ACC(ix+1,iy-1,iz)+ACC(ix+1,iy+1,iz))*h2_4;
D[0][2] = D[2][0] = (ACC(ix-1,iy,iz-1)-ACC(ix-1,iy,iz+1)-ACC(ix+1,iy,iz-1)+ACC(ix+1,iy,iz+1))*h2_4;
D[1][2] = D[2][1] = (ACC(ix,iy-1,iz-1)-ACC(ix,iy-1,iz+1)-ACC(ix,iy+1,iz-1)+ACC(ix,iy+1,iz+1))*h2_4;
(*pvar)(ix,iy,iz) = D[0][0]+D[1][1]+D[2][2] +
( D[0][0]*D[1][1] + D[0][0]*D[2][2] + D[1][1]*D[2][2] +
D[0][1]*D[1][0] + D[0][2]*D[2][0] + D[1][2]*D[2][1] +
D[0][0]*D[0][0] + D[1][1]*D[1][1] + D[2][2]*D[2][2] );
}
}else
throw std::runtime_error("compute_LLA_density : invalid operator order specified");
}
}
void compute_Lu_density( const grid_hierarchy& u, grid_hierarchy& fnew )
{
fnew = u;
for( unsigned ilevel=u.levelmin(); ilevel<=u.levelmax(); ++ilevel )
{
double h = pow(2.0,ilevel), h2 = h*h;
meshvar_bnd *pvar = fnew.get_grid(ilevel);
#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
{
double D[3][3];
D[0][0] = 1.0 + (ACC(ix-1,iy,iz)-2.0*ACC(ix,iy,iz)+ACC(ix+1,iy,iz)) * h2;
D[1][1] = 1.0 + (ACC(ix,iy-1,iz)-2.0*ACC(ix,iy,iz)+ACC(ix,iy+1,iz)) * h2;
D[2][2] = 1.0 + (ACC(ix,iy,iz-1)-2.0*ACC(ix,iy,iz)+ACC(ix,iy,iz+1)) * h2;
(*pvar)(ix,iy,iz) = D[0][0]+D[1][1]+D[2][2] - 3.0;
}
}
}
void compute_2LPT_source( const grid_hierarchy& u, grid_hierarchy& fnew, unsigned order )
{
fnew = u;
for( unsigned ilevel=u.levelmin(); ilevel<=u.levelmax(); ++ilevel )
{
double h = pow(2.0,ilevel), h2 = h*h, h2_4 = 0.25*h2;
meshvar_bnd *pvar = fnew.get_grid(ilevel);
if ( order == 2 )
{
#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
{
double D[3][3];
D[0][0] = (ACC(ix-1,iy,iz)-2.0*ACC(ix,iy,iz)+ACC(ix+1,iy,iz)) * h2;
D[1][1] = (ACC(ix,iy-1,iz)-2.0*ACC(ix,iy,iz)+ACC(ix,iy+1,iz)) * h2;
D[2][2] = (ACC(ix,iy,iz-1)-2.0*ACC(ix,iy,iz)+ACC(ix,iy,iz+1)) * h2;
D[0][1] = D[1][0] = (ACC(ix-1,iy-1,iz)-ACC(ix-1,iy+1,iz)-ACC(ix+1,iy-1,iz)+ACC(ix+1,iy+1,iz))*h2_4;
D[0][2] = D[2][0] = (ACC(ix-1,iy,iz-1)-ACC(ix-1,iy,iz+1)-ACC(ix+1,iy,iz-1)+ACC(ix+1,iy,iz+1))*h2_4;
D[1][2] = D[2][1] = (ACC(ix,iy-1,iz-1)-ACC(ix,iy-1,iz+1)-ACC(ix,iy+1,iz-1)+ACC(ix,iy+1,iz+1))*h2_4;
(*pvar)(ix,iy,iz) = D[0][0]*D[1][1] - SQR( D[0][1] )
+ D[0][0]*D[2][2] - SQR( D[0][2] )
+ D[1][1]*D[2][2] - SQR( D[1][2] );
}
}
else if ( order == 4 )
{
#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
{
double D[3][3];
D[0][0] = (-ACC(ix-2,iy,iz)+16.*ACC(ix-1,iy,iz)-30.0*ACC(ix,iy,iz)+16.*ACC(ix+1,iy,iz)-ACC(ix+2,iy,iz)) * h2/12.0;
D[1][1] = (-ACC(ix,iy-2,iz)+16.*ACC(ix,iy-1,iz)-30.0*ACC(ix,iy,iz)+16.*ACC(ix,iy+1,iz)-ACC(ix,iy+2,iz)) * h2/12.0;
D[2][2] = (-ACC(ix,iy,iz-2)+16.*ACC(ix,iy,iz-1)-30.0*ACC(ix,iy,iz)+16.*ACC(ix,iy,iz+1)-ACC(ix,iy,iz+2)) * h2/12.0;
D[0][1] = D[1][0] = (ACC(ix-1,iy-1,iz)-ACC(ix-1,iy+1,iz)-ACC(ix+1,iy-1,iz)+ACC(ix+1,iy+1,iz))*h2_4;
D[0][2] = D[2][0] = (ACC(ix-1,iy,iz-1)-ACC(ix-1,iy,iz+1)-ACC(ix+1,iy,iz-1)+ACC(ix+1,iy,iz+1))*h2_4;
D[1][2] = D[2][1] = (ACC(ix,iy-1,iz-1)-ACC(ix,iy-1,iz+1)-ACC(ix,iy+1,iz-1)+ACC(ix,iy+1,iz+1))*h2_4;
(*pvar)(ix,iy,iz) = D[0][0]*D[1][1] - SQR( D[0][1] )
+ D[0][0]*D[2][2] - SQR( D[0][2] )
+ D[1][1]*D[2][2] - SQR( D[1][2] );
}
}
else
throw std::runtime_error("compute_2LPT_source : invalid operator order specified");
}
//.. subtract global mean so the multi-grid poisson solver behaves well
for( int i=fnew.levelmax(); i>(int)fnew.levelmin(); --i )
mg_straight().restrict( (*fnew.get_grid(i)), (*fnew.get_grid(i-1)) );
double sum = 0.0;
int nx,ny,nz;
nx = fnew.get_grid(fnew.levelmin())->size(0);
ny = fnew.get_grid(fnew.levelmin())->size(1);
nz = fnew.get_grid(fnew.levelmin())->size(2);
for( int ix=0; ix<nx; ++ix )
for( int iy=0; iy<ny; ++iy )
for( int iz=0; iz<nz; ++iz )
sum += (*fnew.get_grid(fnew.levelmin()))(ix,iy,iz);
sum /= (nx*ny*nz);
for( unsigned i=fnew.levelmin(); i<=fnew.levelmax(); ++i )
{
nx = fnew.get_grid(i)->size(0);
ny = fnew.get_grid(i)->size(1);
nz = fnew.get_grid(i)->size(2);
for( int ix=0; ix<nx; ++ix )
for( int iy=0; iy<ny; ++iy )
for( int iz=0; iz<nz; ++iz )
(*fnew.get_grid(i))(ix,iy,iz) -= sum;
}
}
#undef SQR
#undef ACC

224
cosmology.hh Normal file
View file

@ -0,0 +1,224 @@
/*
cosmology.hh - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef _COSMOLOGY_HH
#define _COSMOLOGY_HH
#include "mesh.hh"
#include "general.hh"
#include "transfer_function.hh"
/*!
* @class CosmoCalc
* @brief provides functions to compute cosmological quantities
*
* This class provides member functions to compute cosmological quantities
* related to the Friedmann equations and linear perturbation theory
*/
class CosmoCalc
{
public:
//! data structure to store cosmological parameters
Cosmology m_Cosmology;
//! pointer to an instance of a transfer function plugin
transfer_function_plugin *m_pTransferFunction;
//! constructor for a cosmology calculator object
/*!
* @params acosmo a cosmological parameters structure
* @params pTransferFunction pointer to an instance of a transfer function object
*/
CosmoCalc( const Cosmology acosmo, transfer_function_plugin *pTransferFunction )
{
m_Cosmology = acosmo;
m_pTransferFunction = pTransferFunction;
}
//! 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
*/
inline real_t Power( real_t k, real_t a ){
real_t m_Dplus = CalcGrowthFactor( a );
real_t m_DplusOne = CalcGrowthFactor( 1.0 );
real_t m_pNorm = ComputePNorm( 1e4 );
m_Dplus /= m_DplusOne;
m_DplusOne = 1.0;
real_t scale = m_Dplus/m_DplusOne;
return m_pNorm*scale*scale*TransferSq(k)*pow((double)k,(double)m_Cosmology.nspect);
}
//! integrand function for Calc_fPeebles
/*!
* @sa Calc_fPeebles
*/
inline static double fy( double a, void *Params )
{
Cosmology *cosm = (Cosmology*)Params;
double y = cosm->Omega_m*(1.0/a-1.0) + cosm->Omega_L*(a*a-1.0) + 1.0;
return 1.0/pow(y,1.5);
}
//! calculates d log D+/d log a
/*! this version follows the Peebles (TBD: add citation)
* formula to compute Bertschinger's vfact
*/
inline real_t Calc_fPeebles( real_t a )
{
real_t y = m_Cosmology.Omega_m*(1.0/a-1.0) + m_Cosmology.Omega_L*(a*a-1.0) + 1.0;
real_t fact = integrate( &fy, 1e-6, a, (void*)&m_Cosmology );
return (m_Cosmology.Omega_L*a*a-0.5*m_Cosmology.Omega_m/a)/y - 1.0 + a*fy(a,(void*)&m_Cosmology)/fact;
}
//! Computes the linear theory growth factor D+
/*! Function integrates over member function GrowthIntegrand */
inline real_t CalcGrowthFactor( real_t a )
{
real_t eta = sqrt((double)(m_Cosmology.Omega_m/a+m_Cosmology.Omega_L*a*a
+1.0-m_Cosmology.Omega_m-m_Cosmology.Omega_L));
real_t integral = integrate( &GrowthIntegrand, 0.0, a, (void*)&m_Cosmology );
return eta/a*integral;
}
//! Integrand used by function CalcGrowthFactor to determine the linear growth factor D+
inline static double GrowthIntegrand( double a, void *Params )
{
Cosmology *cosm = (Cosmology*)Params;
double eta = sqrt((double)(cosm->Omega_m/a+cosm->Omega_L*a*a
+1.0-cosm->Omega_m-cosm->Omega_L));
return 2.5/(eta*eta*eta);
}
//! Compute the factor relating particle displacement and velocity
real_t ComputeVFact_old( real_t a ){
real_t fomega, dlogadt, eta;
real_t Omega_k = 1.0 - m_Cosmology.Omega_m - m_Cosmology.Omega_L;
real_t Dplus = CalcGrowthFactor( a );
eta = sqrt( (double)(m_Cosmology.Omega_m/a+ m_Cosmology.Omega_L*a*a + Omega_k ));
fomega = (2.5/Dplus-1.5*m_Cosmology.Omega_m/a-Omega_k)/eta/eta;
dlogadt = a*eta;
//... /100.0 since we would have to multiply by H0 to convert
//... the displacement to velocity units. But displacement is
//... in Mpc/h, and H0 in units of h is 100.
return fomega * dlogadt/a *100.0;
}
real_t ComputeVFact( real_t a ){
return Calc_fPeebles(a)*sqrt(m_Cosmology.Omega_m/a+m_Cosmology.Omega_L*a*a+1.0-m_Cosmology.Omega_m-m_Cosmology.Omega_L)*100.0;
}
real_t ComputedDdt( real_t a )
{
return Calc_fPeebles(a);
}
//! Integrand for the sigma_8 normalization of the power spectrum
/*! Returns the value of the primordial power spectrum multiplied with
the transfer function and the window function of 8 Mpc/h at wave number k */
static double dSigma8( double k, void *Params )
{
if( k<=0.0 )
return 0.0f;
transfer_function *ptf = (transfer_function *)Params;
double x = k*8.0;
double w = 3.0*(sin(x)-x*cos(x))/(x*x*x);
static double nspect = (double)ptf->cosmo_.nspect;
double tf = ptf->compute(k);
//... no growth factor since we compute at z=0 and normalize so that D+(z=0)=1
return k*k * w*w * pow((double)k,(double)nspect) * tf*tf;
}
//! 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
*/
inline real_t TransferSq( real_t k ){
//.. parameter supplied transfer function
real_t tf1 = m_pTransferFunction->compute(k);
return tf1*tf1;
}
//! Computes the normalization for the power spectrum
/*!
* integrates the power spectrum to fix the normalization to that given
* by the sigma_8 parameter
*/
real_t ComputePNorm( real_t kmax )
{
real_t sigma0, kmin;
kmax = m_pTransferFunction->get_kmax();//m_Cosmology.H0/8.0;
kmin = m_pTransferFunction->get_kmin();//0.0;
sigma0 = 4.0 * M_PI * integrate( &dSigma8, (double)kmin, (double)kmax, (void*)m_pTransferFunction );
return m_Cosmology.sigma8*m_Cosmology.sigma8/sigma0;
}
};
//! 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
*/
inline double jeans_sound_speed( double rho, double mass )
{
const double G = 6.67e-8;
return pow( 6.0*mass/M_PI*sqrt(rho)*pow(G,1.5), 1.0/3.0 );
}
//! computes the density from the potential using the Laplacian
void compute_Lu_density( const grid_hierarchy& u, grid_hierarchy& fnew );
//! computes the 2nd order density perturbations using also off-diagonal terms in the potential Hessian
void compute_LLA_density( const grid_hierarchy& u, grid_hierarchy& fnew, unsigned order=4 );
//! computes the source term for the 2nd order perturbations in the displacements
void compute_2LPT_source( const grid_hierarchy& u, grid_hierarchy& fnew, unsigned order=4 );
#endif // _COSMOLOGY_HH

837
densities.cc Normal file
View file

@ -0,0 +1,837 @@
/*
densities.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "densities.hh"
#include "convolution_kernel.hh"
bool is_number(const std::string& s)
{
for (unsigned i = 0; i < s.length(); i++)
if (!std::isdigit(s[i])&&s[i]!='-' )
return false;
return true;
}
// TODO: use optimized convolution routine when in unigrid mode
void GenerateDensityUnigrid( config_file& cf, transfer_function *ptf, tf_type type, refinement_hierarchy& refh, grid_hierarchy& delta, bool kspace )
{
unsigned levelmin,levelmax,levelminPoisson;
real_t boxlength;
std::vector<long> rngseeds;
std::vector<std::string> rngfnames;
levelminPoisson = cf.getValue<unsigned>("setup","levelmin");
levelmin = cf.getValueSafe<unsigned>("setup","levelminTF",levelminPoisson);
levelmax = cf.getValue<unsigned>("setup","levelmax");
boxlength = cf.getValue<real_t>( "setup", "boxlength" );
//... parse random number options
for( int i=0; i<=100; ++i )
{
char seedstr[128];
std::string tempstr;
sprintf(seedstr,"seed[%d]",i);
if( cf.containsKey( "random", seedstr ) )
tempstr = cf.getValue<std::string>( "random", seedstr );
else
tempstr = std::string("-2");
if( is_number( tempstr ) )
{
long ltemp;
cf.convert( tempstr, ltemp );
rngfnames.push_back( "" );
rngseeds.push_back( ltemp );
}else{
rngfnames.push_back( tempstr );
rngseeds.push_back(-1);
std::cout << " - Random numbers for level " << std::setw(3) << i << " will be read from file.\n";
}
}
//... parse grid setup parameters
unsigned nbase = (unsigned)pow(2,levelmin);
float lxref[3];
std::string temp = cf.getValue<std::string>( "setup", "ref_extent" );
sscanf( temp.c_str(), "%g,%g,%g", &lxref[0],&lxref[1],&lxref[2] );
int shift[3];
shift[0] = cf.getValue<int>("setup","shift_x");
shift[1] = cf.getValue<int>("setup","shift_y");
shift[2] = cf.getValue<int>("setup","shift_z");
convolution::kernel_creator *the_kernel_creator;
if( kspace )
{
#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
{
#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;
conv_param.pcf = &cf;
//.. determine for which levels random seeds/random number files are given
int lmaxread = -1, lmingiven = -1;
for( unsigned ilevel = 0; ilevel < rngseeds.size(); ++ilevel )
{
if( rngfnames[ilevel].size() > 0 )
lmaxread = ilevel;
if( rngseeds[ilevel] > 0 && lmingiven == -1 )
lmingiven = ilevel;
}
if( (unsigned)lmingiven!=levelmin || levelmin!=levelminPoisson )
{
std::cerr <<" - Internal error: GenerateDensityUnigrid was called for a non-trivial\n"
<<" problem set-up. This should not happen, GenerateDensityHierarchy\n"
<<" should be called instead\n";
throw std::runtime_error("Internal error");
}
std::cout << " - Performing noise convolution on level " << std::setw(2) << levelmax << " ..." << std::endl;
DensityGrid<real_t> *top = new DensityGrid<real_t>( nbase, nbase, nbase );
double x0[3] = { refh.offset(levelmin,0), refh.offset(levelmin,1), refh.offset(levelmin,2) };
double lx[3] = { refh.size(levelmin,0), refh.size(levelmin,1), refh.size(levelmin,2) };
x0[0] /= pow(2,levelmin); x0[1] /= pow(2,levelmin); x0[2] /= pow(2,levelmin);
lx[0] /= pow(2,levelmin); lx[1] /= pow(2,levelmin); lx[2] /= pow(2,levelmin);
random_numbers<real_t> *rc = new random_numbers<real_t>( nbase, 32, rngseeds[levelmin], true );//, x0, lx );
if( shift[0]!=0||shift[1]!=0||shift[2]!=0 )
std::cout << " - WARNING: will ignore non-zero shift in unigrid mode!\n";
//top->fill_rand( rc, 1.0, 0, 0, 0, true );
rc->fill_all(*top);
delete rc;
conv_param.lx = boxlength;
conv_param.ly = boxlength;
conv_param.lz = boxlength;
conv_param.nx = top->nx_;
conv_param.ny = top->ny_;
conv_param.nz = top->nz_;
conv_param.normalize = false;
convolution::kernel *the_tf_kernel = the_kernel_creator->create( conv_param );
convolution::perform<real_t>( the_tf_kernel, reinterpret_cast<void*>( top->get_data_ptr() ) );
delete the_tf_kernel;
delta.create_base_hierarchy(levelmin);
top->copy( *delta.get_grid(levelmin) );
delete top;
for( int i=levelmax; i>0; --i )
mg_straight().restrict( (*delta.get_grid(i)), (*delta.get_grid(i-1)) );
double sum = 0.0;
{
int nx,ny,nz;
nx = delta.get_grid(levelmin)->size(0);
ny = delta.get_grid(levelmin)->size(1);
nz = delta.get_grid(levelmin)->size(2);
for( int ix=0; ix<nx; ++ix )
for( int iy=0; iy<ny; ++iy )
for( int iz=0; iz<nz; ++iz )
sum += (*delta.get_grid(levelmin))(ix,iy,iz);
sum /= (nx*ny*nz);
}
std::cout << " - Top grid mean density is off by " << sum << ", correcting..." << std::endl;
for( unsigned i=levelmin; i<=levelmax; ++i )
{
int nx,ny,nz;
nx = delta.get_grid(i)->size(0);
ny = delta.get_grid(i)->size(1);
nz = delta.get_grid(i)->size(2);
for( int ix=0; ix<nx; ++ix )
for( int iy=0; iy<ny; ++iy )
for( int iz=0; iz<nz; ++iz )
(*delta.get_grid(i))(ix,iy,iz) -= sum;
}
}
void GenerateDensityHierarchy( config_file& cf, transfer_function *ptf, tf_type type, refinement_hierarchy& refh, grid_hierarchy& delta )
{
unsigned levelmin,levelmax,levelminPoisson;
real_t boxlength;
std::vector<long> rngseeds;
std::vector<std::string> rngfnames;
levelminPoisson = cf.getValue<unsigned>("setup","levelmin");
levelmin = cf.getValueSafe<unsigned>("setup","levelminTF",levelminPoisson);
levelmax = cf.getValue<unsigned>("setup","levelmax");
boxlength = cf.getValue<real_t>( "setup", "boxlength" );
// TODO: need to make sure unigrid gets called whenever possible
if( levelmin == levelmax && levelmin==levelminPoisson )
{
GenerateDensityUnigrid(cf,ptf,type,refh,delta);
return;
}
//... parse random number options
for( int i=0; i<=100; ++i )
{
char seedstr[128];
std::string tempstr;
sprintf(seedstr,"seed[%d]",i);
if( cf.containsKey( "random", seedstr ) )
tempstr = cf.getValue<std::string>( "random", seedstr );
else
tempstr = std::string("-2");
if( is_number( tempstr ) )
{
long ltemp;
cf.convert( tempstr, ltemp );
rngfnames.push_back( "" );
rngseeds.push_back( ltemp );
}else{
rngfnames.push_back( tempstr );
rngseeds.push_back(-1);
std::cout << " - Random numbers for level " << std::setw(3) << i << " will be read from file.\n";
}
}
//... parse grid setup parameters
unsigned nbase = (unsigned)pow(2,levelmin);
float lxref[3];
std::string temp = cf.getValue<std::string>( "setup", "ref_extent" );
sscanf( temp.c_str(), "%g,%g,%g", &lxref[0],&lxref[1],&lxref[2] );
//double lextmin = std::min(lxref[0],std::min(lxref[1],lxref[2]));
real_t alpha = 0.1*(real_t)nbase/boxlength;//0.45*lextmin*(double)nbase;///boxlength;
real_t cutoff = 0.25;//lextmin*0.9;
int shift[3];
shift[0] = cf.getValue<int>("setup","shift_x");
shift[1] = cf.getValue<int>("setup","shift_y");
shift[2] = cf.getValue<int>("setup","shift_z");
#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::parameters conv_param;
//conv_param.boxlength = boxlength;
conv_param.ptf = ptf;
conv_param.pcf = &cf;
//conv_param.cosmo = cosmo;
//... compute absolute grid offsets
std::vector<int> offtotx(levelmax+1,0),offtoty(levelmax+1,0),offtotz(levelmax+1,0);
for( unsigned ilevel = levelmin+1; ilevel<=levelmax; ++ilevel )
{
//... build a partial sum to get absolute offsets
offtotx[ilevel] = 2*(offtotx[ilevel-1]+refh.offset(ilevel,0));
offtoty[ilevel] = 2*(offtoty[ilevel-1]+refh.offset(ilevel,1));
offtotz[ilevel] = 2*(offtotz[ilevel-1]+refh.offset(ilevel,2));
}
for( unsigned ilevel = levelmin+1; ilevel<=levelmax; ++ilevel )
{
//... the arrays are doubled in size for the isolated BCs
offtotx[ilevel] -= refh.size(ilevel,0)/2;
offtoty[ilevel] -= refh.size(ilevel,1)/2;
offtotz[ilevel] -= refh.size(ilevel,2)/2;
}
//.. determine for which levels random seeds/random number files are given
int lmaxread = -1, lmingiven = -1;
for( unsigned ilevel = 0; ilevel < rngseeds.size(); ++ilevel )
{
if( rngfnames[ilevel].size() > 0 )
lmaxread = ilevel;
if( rngseeds[ilevel] > 0 && lmingiven == -1 )
lmingiven = ilevel;
}
//... if random numbers are to be read from file, do this now
std::vector< random_numbers<real_t>* > randc;
randc.assign(std::max(lmaxread,std::max(lmingiven,(int)levelmax))+1,(random_numbers<real_t>*)NULL);
if( lmaxread >= (int)levelmin )
{
randc[lmaxread] = new random_numbers<real_t>( (unsigned)pow(2,lmaxread), rngfnames[lmaxread] );
for( int ilevel = lmaxread-1; ilevel >= (int)levelmin; --ilevel )
randc[ilevel] = new random_numbers<real_t>( *randc[ilevel+1] );
}
//... if random numbers are not given for lower levels, obtain them by averaging
if( lmingiven >= (int)levelmin )
{
//double x0[3] = { 0.0, 0.0, 0.0 };
//double lx[3] = { 1.0, 1.0, 1.0 };
randc[lmingiven] = new random_numbers<real_t>( (unsigned)pow(2,lmingiven), 32, rngseeds[lmingiven], true );//, x0, lx );
for( int ilevel = lmingiven-1; ilevel >= (int)levelmin; --ilevel ){
if( rngseeds[ilevel-levelmin] > 0 )
std::cerr << " - Warning: random seed for level " << ilevel << " will be ignored.\n"
<< " consistency requires that it is obtained by restriction from level " << lmingiven << std::endl;
randc[ilevel] = new random_numbers<real_t>( *randc[ilevel+1] );
}
}
//... if random seeds are given for levels coarser than levelmin, use them as constraints
if( lmingiven < (int)levelmin )
{
throw std::runtime_error("You provided a seed for a level below levelmin, this is not supported yet.");
//double x0[3] = { 0.0, 0.0, 0.0 };
//double lx[3] = { 1.0, 1.0, 1.0 };
randc[lmingiven] = new random_numbers<real_t>( (unsigned)pow(2,lmingiven), 32, rngseeds[lmingiven], true );//, x0, lx );
for( int ilevel = lmingiven+1; ilevel <= (int)levelmin; ++ilevel )
{
long seed = rngseeds[ilevel];
if( seed <= 0 )
seed = rngseeds[lmingiven+ilevel];
randc[ilevel] = new random_numbers<real_t>( *randc[ilevel-1] );
}
delete randc[lmingiven];
randc[lmingiven] = NULL;
}
//... create and initialize density grids with white noise
PaddedDensitySubGrid<real_t>* coarse(NULL), *fine(NULL);
DensityGrid<real_t>* top(NULL);
//... clean up ...//
for( unsigned i=0; i<randc.size(); ++i )
{
if( i<levelmin || i>levelmax )
if( randc[i] != NULL )
{
delete randc[i];
randc[i]=NULL;
}
}
//... perform convolutions ...//
if( levelmax == levelmin )
{
std::cout << " - Performing noise convolution on level " << std::setw(2) << levelmax << " ..." << std::endl;
top = new DensityGrid<real_t>( nbase, nbase, nbase );
real_t x0[3] = { refh.offset(levelmin,0), refh.offset(levelmin,1), refh.offset(levelmin,2) };
real_t lx[3] = { refh.size(levelmin,0), refh.size(levelmin,1), refh.size(levelmin,2) };
x0[0] /= pow(2,levelmin); x0[1] /= pow(2,levelmin); x0[2] /= pow(2,levelmin);
lx[0] /= pow(2,levelmin); lx[1] /= pow(2,levelmin); lx[2] /= pow(2,levelmin);
random_numbers<real_t> *rc;
if( randc[levelmin] == NULL )
rc = new random_numbers<real_t>( nbase, 32, rngseeds[levelmin], true );//, x0, lx );
else
rc = randc[levelmin];
#if 1
if( shift[0]!=0||shift[1]!=0||shift[2]!=0 )
std::cout << " - WARNING: will ignore non-zero shift in unigrid mode!\n";
top->fill_rand( rc, 1.0, 0, 0, 0, true );
#else
top->fill_rand( rc, 1.0, -shift[0], -shift[1], -shift[2], true );
#endif
delete rc;
conv_param.lx = boxlength;
conv_param.ly = boxlength;
conv_param.lz = boxlength;
conv_param.nx = top->nx_;
conv_param.ny = top->ny_;
conv_param.nz = top->nz_;
conv_param.normalize = false;
convolution::kernel *the_tf_kernel = the_kernel_creator->create( conv_param );
convolution::perform<real_t>( the_tf_kernel, reinterpret_cast<void*>( top->get_data_ptr() ) );
delete the_tf_kernel;
delta.create_base_hierarchy(levelmin);
top->copy( *delta.get_grid(levelmin) );
delete top;
}
//}
for( int i=0; i< (int)levelmax-(int)levelmin; ++i )
{
//.......................................................................................................//
//... GENERATE/FILL WITH RANDOM NUMBERS .................................................................//
//.......................................................................................................//
if( i==0 )
{
top = new DensityGrid<real_t>( nbase, nbase, nbase );
random_numbers<real_t> *rc;
int x0[3] = { refh.offset_abs(levelmin,0)-shift[0],
refh.offset_abs(levelmin,1)-shift[1],
refh.offset_abs(levelmin,2)-shift[2] };
int lx[3] = { refh.size(levelmin,0),
refh.size(levelmin,1),
refh.size(levelmin,2) };
if( randc[levelmin] == NULL )
rc = randc[levelmin] = new random_numbers<real_t>( nbase, 32, rngseeds[levelmin], x0, lx );
else
rc = randc[levelmin];
top->fill_rand( rc, 1.0, -shift[0], -shift[1], -shift[2], true );
delete rc;
randc[levelmin] = NULL;
}
fine = new PaddedDensitySubGrid<real_t>( refh.offset(levelmin+i+1,0),
refh.offset(levelmin+i+1,1),
refh.offset(levelmin+i+1,2),
refh.size(levelmin+i+1,0),
refh.size(levelmin+i+1,1),
refh.size(levelmin+i+1,2) );
{
random_numbers<real_t> *rc;
int x0[3],lx[3];
int lfac = (int)pow(2.0,i+1);
x0[0] = refh.offset_abs(levelmin+i+1,0)-lfac*shift[0]; //((real_t)(offtotx[levelmin+i+1]+lfac*shift[0]))/pow(2.0,levelmin+i+1);
x0[1] = refh.offset_abs(levelmin+i+1,1)-lfac*shift[1]; //((real_t)(offtoty[levelmin+i+1]+lfac*shift[1]))/pow(2.0,levelmin+i+1);
x0[2] = refh.offset_abs(levelmin+i+1,2)-lfac*shift[2]; //((real_t)(offtotz[levelmin+i+1]+lfac*shift[2]))/pow(2.0,levelmin+i+1);
lx[0] = refh.size(levelmin+i+1,0); // /pow(2.0,levelmin+i+1);
lx[1] = refh.size(levelmin+i+1,1); // /pow(2.0,levelmin+i+1);
lx[2] = refh.size(levelmin+i+1,2); // /pow(2.0,levelmin+i+1);
//x0[0] -= 0.5*lx[0]; lx[0] *= 2.0;
//x0[1] -= 0.5*lx[1]; lx[1] *= 2.0;
//x0[2] -= 0.5*lx[2]; lx[2] *= 2.0;
if( randc[levelmin+i+1] == NULL )
rc = randc[levelmin+i+1] = new random_numbers<real_t>((unsigned)pow(2,levelmin+i+1), 32, rngseeds[levelmin+i+1], x0, lx);
else
rc = randc[levelmin+i+1];
{
/*int llfac = (int)pow(2.0,i+1);
fine->fill_rand( rc, 1.0, offtotx[levelmin+i+1]-llfac*shift[0],
offtoty[levelmin+i+1]-llfac*shift[1],
offtotz[levelmin+i+1]-llfac*shift[2] );*/
fine->fill_rand( rc, 1.0, x0[0]-fine->nx_/4, x0[1]-fine->ny_/4, x0[2]-fine->nz_/4 );
if( i+levelmin+1 > (unsigned)lmingiven )
{
if(i==0)
fine->constrain( *top );
else
fine->constrain( *coarse );
}
}
delete rc;
rc = NULL;
}
//.......................................................................................................//
//... PERFORM CONVOLUTIONS ..............................................................................//
//.......................................................................................................//
if( i==0 )
{
/**********************************************************************************************************\
* multi-grid: top-level grid grids .....
\**********************************************************************************************************/
std::cout << " - Performing noise convolution on level " << std::setw(2) << levelmin+i << " ..." << std::endl;
delta.create_base_hierarchy(levelmin);
DensityGrid<real_t> top_save( *top );
conv_param.lx = boxlength;
conv_param.ly = boxlength;
conv_param.lz = boxlength;
conv_param.nx = top->nx_;
conv_param.ny = top->ny_;
conv_param.nz = top->nz_;
conv_param.normalize = true;
convolution::kernel *the_tf_kernel = the_kernel_creator->create( conv_param );
//... 1) compute standard convolution for levelmin
convolution::perform<real_t>( the_tf_kernel, reinterpret_cast<void*>( top->get_data_ptr() ) );
//convolution::perform_filtered<real_t>( the_tf_kernel, reinterpret_cast<void*>( top->get_data_ptr() ) );
top->copy( *delta.get_grid(levelmin) );
//... 2) compute contribution to finer grids from non-refined region
*top = top_save;
top_save.clear();
top->zero_subgrid(refh.offset(levelmin+i+1,0), refh.offset(levelmin+i+1,1), refh.offset(levelmin+i+1,2),
refh.size(levelmin+i+1,0)/2, refh.size(levelmin+i+1,1)/2, refh.size(levelmin+i+1,2)/2 );
convolution::perform<real_t>( the_tf_kernel, reinterpret_cast<void*>( top->get_data_ptr() ) );
//convolution::perform_filtered<real_t>( the_tf_kernel, reinterpret_cast<void*>( top->get_data_ptr() ) );
meshvar_bnd delta_longrange( *delta.get_grid(levelmin) );
top->copy( delta_longrange );
delete the_tf_kernel;
delete top;
//... restrict these contributions to the next level
delta.add_patch( refh.offset(levelmin+1,0), refh.offset(levelmin+1,1), refh.offset(levelmin+1,2),
refh.size(levelmin+1,0), refh.size(levelmin+1,1), refh.size(levelmin+1,2) );
//mg_linear().prolong( delta_longrange, *delta.get_grid(levelmin+1) );
mg_cubic().prolong( delta_longrange, *delta.get_grid(levelmin+1) );
}
else
{
/**********************************************************************************************************\
* multi-grid: intermediate sub-grids .....
\**********************************************************************************************************/
std::cout << " - Performing noise convolution on level " << std::setw(2) << levelmin+i << " ..." << std::endl;
delta.add_patch( refh.offset(levelmin+i+1,0), refh.offset(levelmin+i+1,1), refh.offset(levelmin+i+1,2),
refh.size(levelmin+i+1,0), refh.size(levelmin+i+1,1), refh.size(levelmin+i+1,2) );
//mg_linear().prolong( *delta.get_grid(levelmin+i), *delta.get_grid(levelmin+i+1) );
mg_cubic().prolong( *delta.get_grid(levelmin+i), *delta.get_grid(levelmin+i+1) );
real_t dx,lx,ly,lz;
dx = boxlength/pow(2.0,levelmin+i);
lx = dx * coarse->nx_;
ly = dx * coarse->ny_;
lz = dx * coarse->nz_;
real_t lmin = std::min( lx, std::min(ly,lz) );
conv_param.lx = lx;
conv_param.ly = ly;
conv_param.lz = lz;
conv_param.nx = coarse->nx_;
conv_param.ny = coarse->ny_;
conv_param.nz = coarse->nz_;
conv_param.normalize = false;
convolution::kernel *the_tf_kernel = the_kernel_creator->create( conv_param );
PaddedDensitySubGrid<real_t> coarse_save( *coarse );
//... 2) the inner region
coarse->zero_boundary();
convolution::perform<real_t>( the_tf_kernel, reinterpret_cast<void*> (coarse->get_data_ptr()) );
//convolution::perform_filtered<real_t>( the_tf_kernel, reinterpret_cast<void*> (coarse->get_data_ptr()) );
coarse->copy_add_unpad( *delta.get_grid(levelmin+i) );
//... 3) the 'BC' for the next finer grid
*coarse = coarse_save;
coarse->zero_subgrid(refh.offset(levelmin+i+1,0), refh.offset(levelmin+i+1,1), refh.offset(levelmin+i+1,2),
refh.size(levelmin+i+1,0)/2, refh.size(levelmin+i+1,1)/2, refh.size(levelmin+i+1,2)/2 );
coarse->zero_boundary();
convolution::perform<real_t>( the_tf_kernel, reinterpret_cast<void*> (coarse->get_data_ptr()) );
//convolution::perform_filtered<real_t>( the_tf_kernel, reinterpret_cast<void*> (coarse->get_data_ptr()) );
meshvar_bnd delta_longrange( *delta.get_grid(levelmin+i) );
coarse->copy_unpad( delta_longrange );
//mg_linear().prolong_add( delta_longrange, *delta.get_grid(levelmin+i+1) );
mg_cubic().prolong_add( delta_longrange, *delta.get_grid(levelmin+i+1) );
#if 1
//... FFT (isolated) boundary noise contribution
//convolution::truncate( the_tf_kernel, cutoff*lmin, 1e-8*alpha );
convolution::truncate_sharp( the_tf_kernel, cutoff*lmin );
*coarse = coarse_save;
//coarse_save.clear();
coarse->zero_subgrid(0,0,0,coarse->nx_/2,coarse->ny_/2,coarse->nz_/2);
coarse->subtract_oct_mean();
convolution::perform<real_t>( the_tf_kernel, reinterpret_cast<void*> (coarse->get_data_ptr()) );
//convolution::perform_filtered<real_t>( the_tf_kernel, reinterpret_cast<void*> (coarse->get_data_ptr()) );
coarse->copy_add_unpad( *delta.get_grid(levelmin+i) );
#endif
#if 0
*coarse = coarse_save;
coarse->zero_boundary();
coarse->subtract_oct_mean();
convolution::perform<real_t>( the_tf_kernel, reinterpret_cast<void*> (coarse->get_data_ptr()) );
//coarse->zero_subgrid(0,0,0,coarse->nx_/2,coarse->ny_/2,coarse->nz_/2);
coarse->upload_bnd_add( *delta.get_grid(levelmin+i-1) );
#endif
/**coarse = coarse_save;
coarse->zero_subgrid(0,0,0,coarse->nx_/2,coarse->ny_/2,coarse->nz_/2);
coarse->set_to_oct_mean();
convolution::perform<real_t>( the_tf_kernel, reinterpret_cast<void*> (coarse->get_data_ptr()) );
coarse->copy_subtract_unpad( *delta.get_grid(levelmin+i) );*/
delete the_tf_kernel;
delete coarse;
}
coarse = fine;
}
//... and convolution for finest grid (outside loop)
if( levelmax > levelmin )
{
/**********************************************************************************************************\
* multi-grid: finest sub-grid .....
\**********************************************************************************************************/
std::cout << " - Performing noise convolution on level " << std::setw(2) << levelmax << " ..." << std::endl;
real_t dx,lx,ly,lz;
dx = boxlength/pow(2.0,levelmax);
lx = dx * coarse->nx_;
ly = dx * coarse->ny_;
lz = dx * coarse->nz_;
real_t lmin = std::min( lx, std::min(ly,lz) );
conv_param.lx = lx;
conv_param.ly = ly;
conv_param.lz = lz;
conv_param.nx = coarse->nx_;
conv_param.ny = coarse->ny_;
conv_param.nz = coarse->nz_;
conv_param.normalize = false;
//... with LR/SR splitting and full subgrid
PaddedDensitySubGrid<real_t> coarse_save( *coarse );
convolution::kernel *the_tf_kernel = the_kernel_creator->create( conv_param );
//... 2) the inner region
coarse->zero_boundary();
convolution::perform<real_t>( the_tf_kernel, reinterpret_cast<void*> (coarse->get_data_ptr()) );
coarse->copy_add_unpad( *delta.get_grid(levelmax) );
//... compute convolution for isolated grid
//... 1) the padded boundary region
#if 1
convolution::truncate( the_tf_kernel, cutoff*lmin, alpha );
*coarse = coarse_save;
coarse->zero_subgrid(0,0,0,coarse->nx_/2,coarse->ny_/2,coarse->nz_/2);
coarse->subtract_oct_mean();
convolution::perform<real_t>( the_tf_kernel, reinterpret_cast<void*> (coarse->get_data_ptr()) );
coarse->copy_add_unpad( *delta.get_grid(levelmax) );
#endif
#if 0
// coarse correction
*coarse = coarse_save;
coarse->zero_boundary();
coarse->subtract_oct_mean();
convolution::perform<real_t>( the_tf_kernel, reinterpret_cast<void*> (coarse->get_data_ptr()) );
//coarse->zero_subgrid(0,0,0,coarse->nx_/2,coarse->ny_/2,coarse->nz_/2);
coarse->upload_bnd_add( *delta.get_grid(levelmax-1) );
// meshvar_bnd delta_longrange( *delta.get_grid(levelmax) );
//coarse->copy_unpad( delta_longrange );
//mg_straight().restrict_add( delta_longrange, *delta.get_grid(levelmax-1) );
#endif
/**coarse = coarse_save;
coarse->zero_subgrid(0,0,0,coarse->nx_/2,coarse->ny_/2,coarse->nz_/2);
coarse->set_to_oct_mean();
convolution::perform<real_t>( the_tf_kernel, reinterpret_cast<void*> (coarse->get_data_ptr()) );
coarse->copy_subtract_unpad( *delta.get_grid(levelmax) );*/
delete the_tf_kernel;
delete coarse;
}
//... clean up ...//
for( unsigned i=0; i<randc.size(); ++i )
{
if( i<levelmin || i>levelmax )
if( randc[i] != NULL )
{
delete randc[i];
randc[i]=NULL;
}
}
//... enforce mean condition
for( int i=levelmin; i<(int)levelmax; ++i )
enforce_mean( (*delta.get_grid(i+1)), (*delta.get_grid(i)) );
double sum;
#if 0
//... subtract the box mean.... this will otherwise add
//... a constant curvature term to the potential
sum = 0.0;
{
int nx,ny,nz;
nx = delta.get_grid(levelmin)->size(0);
ny = delta.get_grid(levelmin)->size(1);
nz = delta.get_grid(levelmin)->size(2);
for( int ix=0; ix<nx; ++ix )
for( int iy=0; iy<ny; ++iy )
for( int iz=0; iz<nz; ++iz )
sum += (*delta.get_grid(levelmin))(ix,iy,iz);
sum /= (nx*ny*nz);
}
std::cout << " - Top grid mean density is off by " << sum << ", correcting..." << std::endl;
for( unsigned i=levelmin; i<=levelmax; ++i )
{
int nx,ny,nz;
nx = delta.get_grid(i)->size(0);
ny = delta.get_grid(i)->size(1);
nz = delta.get_grid(i)->size(2);
for( int ix=0; ix<nx; ++ix )
for( int iy=0; iy<ny; ++iy )
for( int iz=0; iz<nz; ++iz )
(*delta.get_grid(i))(ix,iy,iz) -= sum;
}
#endif
//... fill coarser levels with data from finer ones...
// for( int i=levelmax; i>(int)levelmin; --i )
for( int i=levelmax; i>0; --i )
mg_straight().restrict( (*delta.get_grid(i)), (*delta.get_grid(i-1)) );
#if 1
sum = 0.0;
{
int nx,ny,nz;
nx = delta.get_grid(levelmin)->size(0);
ny = delta.get_grid(levelmin)->size(1);
nz = delta.get_grid(levelmin)->size(2);
for( int ix=0; ix<nx; ++ix )
for( int iy=0; iy<ny; ++iy )
for( int iz=0; iz<nz; ++iz )
sum += (*delta.get_grid(levelmin))(ix,iy,iz);
sum /= (nx*ny*nz);
}
std::cout << " - Top grid mean density is off by " << sum << ", correcting..." << std::endl;
for( unsigned i=levelmin; i<=levelmax; ++i )
{
int nx,ny,nz;
nx = delta.get_grid(i)->size(0);
ny = delta.get_grid(i)->size(1);
nz = delta.get_grid(i)->size(2);
for( int ix=0; ix<nx; ++ix )
for( int iy=0; iy<ny; ++iy )
for( int iz=0; iz<nz; ++iz )
(*delta.get_grid(i))(ix,iy,iz) -= sum;
}
#endif
}

827
densities.hh Normal file
View file

@ -0,0 +1,827 @@
/*
densities.hh - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __DENSITIES_HH
#define __DENSITIES_HH
#ifdef SINGLE_PRECISION
#ifdef SINGLETHREAD_FFTW
#include <srfftw.h>
#else
#include <srfftw_threads.h>
#endif
#else
#ifdef SINGLETHREAD_FFTW
#include <drfftw.h>
#else
#include <drfftw_threads.h>
#endif
#endif
#include "config_file.hh"
#include "random.hh"
#include "cosmology.hh"
#include "transfer_function.hh"
void GenerateDensityHierarchy( config_file& cf, transfer_function *ptf, tf_type type,
refinement_hierarchy& refh, grid_hierarchy& delta );
void GenerateDensityUnigrid( config_file& cf, transfer_function *ptf, tf_type type,
refinement_hierarchy& refh, grid_hierarchy& delta, bool kspace=false );
/*!
* @class DensityGrid
* @brief provides infrastructure for computing the initial density field
*
* This class provides access and data management member functions that
* are used when computing the initial density field by convolution with
* transfer functions.
*/
template< typename real_t >
class DensityGrid
{
public:
int nx_; //!< number of grid cells in x-direction
int ny_; //!< number of grid cells in y-direction
int nz_; //!< number of grid cells in z-direction
int nzp_; //!< number of cells in memory (z-dir), used for Nyquist padding
//! the actual data container in the form of a 1D array
std::vector< real_t > data_;
//! 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
*/
DensityGrid( unsigned nx, unsigned ny, unsigned nz )
: nx_(nx), ny_(ny), nz_(nz)
{
data_.assign(nx_*ny_*2*(nz_/2+1),0.0);
nzp_ = 2*(nz_/2+1);
}
//! copy constructor
explicit DensityGrid( const DensityGrid<real_t> & g )
: nx_(g.nx_), ny_(g.ny_), nz_(g.nz_), nzp_(g.nzp_)
{
data_ = g.data_;
}
//!destructor
~DensityGrid()
{ }
//! clears the density object
/*! sets all dimensions to zero and frees the memory
*/
void clear( void )
{
nx_ = ny_ = nz_ = nzp_ = 0;
data_.clear();
std::vector<real_t>().swap(data_);
}
//! assigns the contents of another DensityGrid to this
DensityGrid& operator=( const DensityGrid<real_t>& g )
{
nx_ = g.nx_;
ny_ = g.ny_;
nz_ = g.nz_;
nzp_= g.nzp_;
data_ = g.data_;
return *this;
}
//! 3D index based data access operator
inline real_t& operator()( int i, int j, int k )
{ return data_[(i*ny_+j)*nzp_+k]; }
//! 3D index based const data access operator
inline const real_t& operator()( int i, int j, int k ) const
{ return data_[(i*ny_+j)*nzp_+k]; }
//! recover the pointer to the 1D data array
inline real_t * get_data_ptr( void )
{ return &data_[0]; }
//! 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 zero 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 zero=false )
{
double sum = 0.0;
#pragma omp parallel for reduction(+:sum)
for( int i=0; i<nx_; ++i )
for( int j=0; j<ny_; ++j )
for( int k=0; k<nz_; ++k )
{
(*this)(i,j,k) = (*prc)(i0+i,j0+j,k0+k) * variance;
sum += (*this)(i,j,k);
}
sum /= nx_*ny_*nz_;
if( zero )
{
#pragma omp parallel for
for( int i=0; i<nx_; ++i )
for( int j=0; j<ny_; ++j )
for( int k=0; k<nz_; ++k )
(*this)(i,j,k) -= sum;
}
}
//! copies the data from another field with 3D index-based access operator
template< class array3 >
void copy( array3& v )
{
for( int ix=0; ix<(int)nx_; ++ix )
for( int iy=0; iy<(int)ny_; ++iy )
for( int iz=0; iz<(int)nz_; ++iz )
v(ix,iy,iz) = (*this)(ix,iy,iz);
}
//! adds the data from another field with 3D index-based access operator
template< class array3 >
void copy_add( array3& v )
{
for( int ix=0; ix<(int)nx_; ++ix )
for( int iy=0; iy<(int)ny_; ++iy )
for( int iz=0; iz<(int)nz_; ++iz )
v(ix,iy,iz) += (*this)(ix,iy,iz);
}
//! subtract the mean of each oct of the field
/*! subtracting the mean of each oct implies that a restriction of the field to the coarser level
* is zero everywhere (needed for Hoffman-Ribak constraints)
*/
void subtract_oct_mean( void )
{
for( int i=0; i<nx_; i+=2 )
for( int j=0; j<ny_; j+=2 )
for( int k=0; k<nz_; k+=2 )
{
real_t avg =
0.125*((*this)(i,j,k)+(*this)(i+1,j,k)+(*this)(i,j+1,k)+(*this)(i,j,k+1)+
(*this)(i+1,j+1,k)+(*this)(i+1,j,k+1)+(*this)(i,j+1,k+1)+(*this)(i+1,j+1,k+1));
(*this)(i,j,k) -= avg;
(*this)(i+1,j,k) -= avg;
(*this)(i,j+1,k) -= avg;
(*this)(i,j,k+1) -= avg;
(*this)(i+1,j+1,k) -= avg;
(*this)(i+1,j,k+1) -= avg;
(*this)(i,j+1,k+1) -= avg;
(*this)(i+1,j+1,k+1) -= avg;
}
}
//! replaces the value of all cells in an oct with the average value of the oct
void set_to_oct_mean( void )
{
for( int i=0; i<nx_; i+=2 )
for( int j=0; j<ny_; j+=2 )
for( int k=0; k<nz_; k+=2 )
{
real_t avg =
0.125*((*this)(i,j,k)+(*this)(i+1,j,k)+(*this)(i,j+1,k)+(*this)(i,j,k+1)+
(*this)(i+1,j+1,k)+(*this)(i+1,j,k+1)+(*this)(i,j+1,k+1)+(*this)(i+1,j+1,k+1));
(*this)(i,j,k) = avg;
(*this)(i+1,j,k) = avg;
(*this)(i,j+1,k) = avg;
(*this)(i,j,k+1) = avg;
(*this)(i+1,j+1,k) = avg;
(*this)(i+1,j,k+1) = avg;
(*this)(i,j+1,k+1) = avg;
(*this)(i+1,j+1,k+1) = avg;
}
}
//! sets the field to zero inside of a rectangular box
void zero_subgrid( unsigned oxsub, unsigned oysub, unsigned ozsub, unsigned lxsub, unsigned lysub, unsigned lzsub )
{
//... correct offsets for padding (not needed for top grid)
for( int ix=oxsub; ix<(int)(oxsub+lxsub); ++ix )
for( int iy=oysub; iy<(int)(oysub+lysub); ++iy )
for( int iz=ozsub; iz<(int)(ozsub+lzsub); ++iz )
(*this)(ix,iy,iz) = 0.0;
}
//! sets the field to zero inside of a rectangular box including the boundary of the box (used for isolated FFT)
void zero_padded_subgrid( unsigned oxsub, unsigned oysub, unsigned ozsub, unsigned lxsub, unsigned lysub, unsigned lzsub )
{
//... correct offsets for padding (not needed for top grid)
oxsub -= lxsub/2;
oysub -= lysub/2;
ozsub -= lzsub/2;
lxsub *= 2;
lysub *= 2;
lzsub *= 2;
for( int ix=oxsub; ix<(int)(oxsub+lxsub); ++ix )
for( int iy=oysub; iy<(int)(oysub+lysub); ++iy )
for( int iz=ozsub; iz<(int)(ozsub+lzsub); ++iz )
(*this)(ix,iy,iz) = 0.0;
}
//! sets the field to zero outside of a rectangular box including the boundary of the box (used for isolated FFT)
void zero_but_padded_subgrid( int oxsub, int oysub, int ozsub, int lxsub, int lysub, int lzsub )
{
//... correct offsets for padding (not needed for top grid)
oxsub -= lxsub/2;
oysub -= lysub/2;
ozsub -= lzsub/2;
lxsub *= 2;
lysub *= 2;
lzsub *= 2;
for( int ix=0; ix<nx_; ++ix )
for( int iy=0; iy<ny_; ++iy )
for( int iz=0; iz<nz_; ++iz )
{
if( (ix<oxsub||ix>=oxsub+lxsub)
|| (iy<oysub||iy>=oysub+lysub)
|| (iz<ozsub||iz>=ozsub+lzsub) )
(*this)(ix,iy,iz) = 0.0;
}
}
//! sets the field to zero outside of a rectangular box
void zero_but_subgrid( int oxsub, int oysub, int ozsub, int lxsub, int lysub, int lzsub )
{
for( int ix=0; ix<nx_; ++ix )
for( int iy=0; iy<ny_; ++iy )
for( int iz=0; iz<nz_; ++iz )
{
if( (ix<oxsub||ix>=oxsub+lxsub)
|| (iy<oysub||iy>=oysub+lysub)
|| (iz<ozsub||iz>=ozsub+lzsub) )
(*this)(ix,iy,iz) = 0.0;
}
}
//! sets the field to zero except on the boundary of a rectangular box
void zero_but_subgrid_bnd( unsigned oxsub, unsigned oysub, unsigned ozsub, unsigned lxsub, unsigned lysub, unsigned lzsub )
{
//... correct offsets for padding (not needed for top grid)
// zero the subgrid
for( int ix=oxsub; ix<(int)(oxsub+lxsub); ++ix )
for( int iy=oysub; iy<(int)(oysub+lysub); ++iy )
for( int iz=ozsub; iz<(int)(ozsub+lzsub); ++iz )
(*this)(ix,iy,iz) = 0.0;
oxsub -= lxsub/2;
oysub -= lysub/2;
ozsub -= lzsub/2;
lxsub *= 2;
lysub *= 2;
lzsub *= 2;
// zero the outside, except the boundary
//#pragma parallel nowait
{
for( int ix=0; ix<oxsub; ++ix )
for( int iy=0; iy<ny_; ++iy )
for( int iz=0; iz<nz_; ++iz )
(*this)(ix,iy,iz) = 0.0;
for( int ix=oxsub+lxsub; ix<nx_; ++ix )
for( int iy=0; iy<ny_; ++iy )
for( int iz=0; iz<nz_; ++iz )
(*this)(ix,iy,iz) = 0.0;
for( int ix=0; ix<nx_; ++ix )
for( int iy=0; iy<oysub; ++iy )
for( int iz=0; iz<nz_; ++iz )
(*this)(ix,iy,iz) = 0.0;
for( int ix=0; ix<nx_; ++ix )
for( int iy=oysub+lysub; iy<ny_; ++iy )
for( int iz=0; iz<nz_; ++iz )
(*this)(ix,iy,iz) = 0.0;
for( int ix=0; ix<nx_; ++ix )
for( int iy=0; iy<ny_; ++iy )
for( int iz=0; iz<ozsub; ++iz )
(*this)(ix,iy,iz) = 0.0;
for( int ix=0; ix<nx_; ++ix )
for( int iy=0; iy<ny_; ++iy )
for( int iz=ozsub+lzsub; iz<nz_; ++iz )
(*this)(ix,iy,iz) = 0.0;
}
}
};
template< typename real_t >
class PaddedDensitySubGrid : public DensityGrid<real_t>
{
public:
using DensityGrid<real_t>::nx_;
using DensityGrid<real_t>::ny_;
using DensityGrid<real_t>::nz_;
using DensityGrid<real_t>::data_;
using DensityGrid<real_t>::fill_rand;
using DensityGrid<real_t>::get_data_ptr;
int ox_, oy_, oz_;
public:
PaddedDensitySubGrid( int ox, int oy, int oz, unsigned nx, unsigned ny, unsigned nz)
: DensityGrid<real_t>(2*nx,2*ny,2*nz), ox_(ox), oy_(oy), oz_(oz)
{
if( ox-nx/4 < 0 || oy-ny/4 < 0 || oz-nz/4 < 0 )
throw std::runtime_error("subgrid extends across top grid");
//.. the size in top grid cells is nx/2,ny/2,nz/2, so padding starts at ox-nx/4...
//.. loop over relevant part of top grid and copy down grid values
/*for( int ix=ox-nx/4,ixs=0; ix<ox+3*nx/4; ix++,ixs+=2 )
for( int iy=oy-ny/4,iys=0; iy<oy+3*ny/4; iy++,iys+=2 )
for( int iz=oz-nz/4,izs=0; iz<oz+3*nz/4; iz++,izs+=2 )
{
(*this)(ixs,iys,izs) =
(*this)(ixs+1,iys,izs) =
(*this)(ixs,iys+1,izs) =
(*this)(ixs,iys,izs+1) =
(*this)(ixs+1,iys+1,izs) =
(*this)(ixs+1,iys,izs+1) =
(*this)(ixs,iys+1,izs+1) =
(*this)(ixs+1,iys+1,izs+1) = top(ix,iy,iz);
}*/
}
PaddedDensitySubGrid( const PaddedDensitySubGrid<real_t>& o )
: DensityGrid<real_t>( o ), ox_(o.ox_), oy_(o.oy_), oz_(o.oz_)
{ }
void zero_padded_subgrid( unsigned oxsub, unsigned oysub, unsigned ozsub, unsigned lxsub, unsigned lysub, unsigned lzsub )
{
//... correct offsets for padding (not needed for top grid)
oxsub += nx_/4;
oysub += ny_/4;
ozsub += nz_/4;
//... correct offsets for padding (not needed for top grid)
for( int ix=oxsub; ix<(int)(oxsub+lxsub); ++ix )
for( int iy=oysub; iy<(int)(oysub+lysub); ++iy )
for( int iz=ozsub; iz<(int)(ozsub+lzsub); ++iz )
(*this)(ix,iy,iz) = 0.0;
}
void zero_subgrid( unsigned oxsub, unsigned oysub, unsigned ozsub, unsigned lxsub, unsigned lysub, unsigned lzsub )
{
//... correct offsets for padding (not needed for top grid)
oxsub += nx_/4;
oysub += ny_/4;
ozsub += nz_/4;
for( int ix=oxsub; ix<(int)(oxsub+lxsub); ++ix )
for( int iy=oysub; iy<(int)(oysub+lysub); ++iy )
for( int iz=ozsub; iz<(int)(ozsub+lzsub); ++iz )
(*this)(ix,iy,iz) = 0.0;
}
void zero_but_subgrid_bnd( unsigned oxsub, unsigned oysub, unsigned ozsub, unsigned lxsub, unsigned lysub, unsigned lzsub )
{
//... correct offsets for padding (not needed for top grid)
oxsub += nx_/4;
oysub += ny_/4;
ozsub += nz_/4;
//lxsub += nx_/4;
//lysub += nx_/4;
//lzsub += nx_/4;
// zero the subgrid
for( int ix=oxsub; ix<(int)(oxsub+lxsub); ++ix )
for( int iy=oysub; iy<(int)(oysub+lysub); ++iy )
for( int iz=ozsub; iz<(int)(ozsub+lzsub); ++iz )
(*this)(ix,iy,iz) = 0.0;
oxsub -= lxsub/2;
oysub -= lysub/2;
ozsub -= lzsub/2;
lxsub *= 2;
lysub *= 2;
lzsub *= 2;
// zero the outside, except the boundary
//#pragma parallel block nowait
{
for( int ix=0; ix<oxsub; ++ix )
for( int iy=0; iy<ny_; ++iy )
for( int iz=0; iz<nz_; ++iz )
(*this)(ix,iy,iz) = 0.0;
std::cerr << oxsub+lxsub << " -> " << nx_ << std::endl;
for( int ix=oxsub+lxsub; ix<nx_; ++ix )
for( int iy=0; iy<ny_; ++iy )
for( int iz=0; iz<nz_; ++iz )
(*this)(ix,iy,iz) = 0.0;
for( int ix=0; ix<nx_; ++ix )
for( int iy=0; iy<oysub; ++iy )
for( int iz=0; iz<nz_; ++iz )
(*this)(ix,iy,iz) = 0.0;
for( int ix=0; ix<nx_; ++ix )
for( int iy=oysub+lysub; iy<ny_; ++iy )
for( int iz=0; iz<nz_; ++iz )
(*this)(ix,iy,iz) = 0.0;
for( int ix=0; ix<nx_; ++ix )
for( int iy=0; iy<ny_; ++iy )
for( int iz=0; iz<ozsub; ++iz )
(*this)(ix,iy,iz) = 0.0;
for( int ix=0; ix<nx_; ++ix )
for( int iy=0; iy<ny_; ++iy )
for( int iz=ozsub+lzsub; iz<nz_; ++iz )
(*this)(ix,iy,iz) = 0.0;
}
}
template< class array3 >
void upload_bnd_add( array3& top )
{
int ox=ox_-nx_/8, oy=oy_-ny_/8, oz=oz_-nz_/8;
int lx=ox+nx_/2, ly=oy+ny_/2, lz=oz+nz_/2;
ox = std::max(ox,0);
oy = std::max(oy,0);
oz = std::max(oz,0);
lx = std::min(lx,(int)top.size(0));
ly = std::min(ly,(int)top.size(1));
lz = std::min(lz,(int)top.size(2));
if( ox < 0 || oy < 0 || oz < 0 ){
std::cerr << "offset = " << ox << ", " << oy << ", " << oz << std::endl;
std::cerr << "nx = " << nx_ << ", " << ny_ << ", " << nz_ << std::endl;
throw std::runtime_error("Subgrid extends beyond top grid. Increase levelmin or reduce size of refinement region!");
}
for( int ix=0,ixu=ox;ix<nx_&&ixu<lx;ix+=2,++ixu )
for( int iy=0,iyu=oy;iy<ny_&&iyu<ly;iy+=2,++iyu )
for( int iz=0,izu=oz;iz<nz_&&izu<lz;iz+=2,++izu )
{
if( (ix<nx_/4||ix>=3*nx_/4)
|| (iy<ny_/4||iy>=3*ny_/4)
|| (iz<nz_/4||iz>=3*nz_/4) )
{
top(ixu,iyu,izu) += 0.125* ((*this)(ix,iy,iz)+(*this)(ix+1,iy,iz)+(*this)(ix,iy+1,iz)+(*this)(ix,iy,iz+1)
+(*this)(ix+1,iy+1,iz)+(*this)(ix+1,iy,iz+1)+(*this)(ix,iy+1,iz+1)+(*this)(ix+1,iy+1,iz+1) );
// std::cerr << "*";
}
}
}
void constrain( const DensityGrid<real_t>& top )
{
int ox=ox_-nx_/8, oy=oy_-ny_/8, oz=oz_-nz_/8;
if( ox < 0 || oy < 0 || oz < 0 ){
std::cerr << "offset = " << ox << ", " << oy << ", " << oz << std::endl;
std::cerr << "nx = " << nx_ << ", " << ny_ << ", " << nz_ << std::endl;
throw std::runtime_error("Subgrid extends beyond top grid. Increase levelmin or reduce size of refinement region!");
}
//...top grid is not padded
//.. fine grid will be multiplied by sqrt(8) later to account for increase in variance
//.. so, we need to divide the coarse grid value by it
real_t fac = 1.0/sqrt(8);
for( int ixs=0,ix=ox;ixs<nx_;ixs+=2,++ix )
for( int iys=0,iy=oy;iys<ny_;iys+=2,++iy )
for( int izs=0,iz=oz;izs<nz_;izs+=2,++iz )
{
real_t mean = 0.125 *
((*this)(ixs,iys,izs)+
(*this)(ixs+1,iys,izs)+
(*this)(ixs,iys+1,izs)+
(*this)(ixs,iys,izs+1)+
(*this)(ixs+1,iys+1,izs)+
(*this)(ixs+1,iys,izs+1)+
(*this)(ixs,iys+1,izs+1)+
(*this)(ixs+1,iys+1,izs+1));
double aa = top(ix,iy,iz)*fac - mean;
(*this)(ixs,iys,izs) += aa;
(*this)(ixs+1,iys,izs) += aa;
(*this)(ixs,iys+1,izs) += aa;
(*this)(ixs,iys,izs+1) += aa;
(*this)(ixs+1,iys+1,izs) += aa;
(*this)(ixs+1,iys,izs+1) += aa;
(*this)(ixs,iys+1,izs+1) += aa;
(*this)(ixs+1,iys+1,izs+1) += aa;
}
#if 0
unsigned nx=nx_/2, ny=ny_/2, nz=nz_/2;
int ox=ox_, oy=oy_, oz=oz_;
if( ox-nx/4 < 0 || oy-ny/4 < 0 || oz-nz/4 < 0 )
throw("subgrid extends across top grid");
//.. the size in top grid cells is nx/2,ny/2,nz/2, so padding starts at ox-nx/4...
//.. loop over relevant part of top grid and copy down grid values
for( int ix=ox-nx/4,ixs=0; ix<ox+3*nx/4; ix++,ixs+=2 )
for( int iy=oy-ny/4,iys=0; iy<oy+3*ny/4; iy++,iys+=2 )
for( int iz=oz-nz/4,izs=0; iz<oz+3*nz/4; iz++,izs+=2 )
{
//... removed -r, as the mean will be taken out right at the beginning
(*this)(ixs,iys,izs) += top(ix,iy,iz);
(*this)(ixs+1,iys,izs) += top(ix,iy,iz);
(*this)(ixs,iys+1,izs) += top(ix,iy,iz);
(*this)(ixs,iys,izs+1) += top(ix,iy,iz);
(*this)(ixs+1,iys+1,izs) += top(ix,iy,iz);
(*this)(ixs+1,iys,izs+1) += top(ix,iy,iz);
(*this)(ixs,iys+1,izs+1) += top(ix,iy,iz);
(*this)(ixs+1,iys+1,izs+1) += top(ix,iy,iz);
}
#endif
}
void constrain( const PaddedDensitySubGrid<real_t>& top )
{
///... top grid is padded too...
//.. ox is shifted by nx_/4, padded overlap starts at -nx_/8
int ox=ox_+top.nx_/4-nx_/8, oy=oy_+top.ny_/4-ny_/8, oz=oz_+top.nz_/4-nz_/8;
if( ox < 0 || oy < 0 || oz < 0 )
throw std::runtime_error("subgrid extends beyond top grid");
double fac = 1.0/sqrt(8.0);
for( int ixs=0,ix=ox;ixs<nx_;ixs+=2,++ix )
for( int iys=0,iy=oy;iys<ny_;iys+=2,++iy )
for( int izs=0,iz=oz;izs<nz_;izs+=2,++iz )
{
double mean = 0.125 *
((*this)(ixs,iys,izs)+
(*this)(ixs+1,iys,izs)+
(*this)(ixs,iys+1,izs)+
(*this)(ixs,iys,izs+1)+
(*this)(ixs+1,iys+1,izs)+
(*this)(ixs+1,iys,izs+1)+
(*this)(ixs,iys+1,izs+1)+
(*this)(ixs+1,iys+1,izs+1));
double aa = top(ix,iy,iz)*fac - mean;
(*this)(ixs,iys,izs) += aa;
(*this)(ixs+1,iys,izs) += aa;
(*this)(ixs,iys+1,izs) += aa;
(*this)(ixs,iys,izs+1) += aa;
(*this)(ixs+1,iys+1,izs) += aa;
(*this)(ixs+1,iys,izs+1) += aa;
(*this)(ixs,iys+1,izs+1) += aa;
(*this)(ixs+1,iys+1,izs+1) += aa;
}
}
template< class array3 >
void upload_bnd( unsigned nbnd, array3& v )
{
for( int ix=nx_/4-2*nbnd,ixu=-nbnd; ix<3*nx_/4+2*nbnd; ix+=2,++ixu)
for( int iy=ny_/4-2*nbnd,iyu=-nbnd; iy<3*ny_/4+2*nbnd; iy+=2,++iyu )
for( int iz=nz_/4-2*nbnd,izu=-nbnd; iz<3*nz_/4+2*nbnd; iz+=2,++izu )
{
if( (ix<nx_/4||ix>=3*nx_/4)
|| (iy<ny_/4||iy>=3*ny_/4)
|| (iz<nz_/4||iz>=3*nz_/4) )
{
v(ixu+ox_,iyu+oy_,izu+oz_)
= 1.0;
}
}
}
template< class array3 >
void copy_unpad( array3& v )
{
for( int ix=nx_/4,ixu=0; ix<3*nx_/4; ++ix,++ixu )
for( int iy=ny_/4,iyu=0; iy<3*ny_/4; ++iy,++iyu )
for( int iz=nz_/4,izu=0; iz<3*nz_/4; ++iz,++izu )
v(ixu,iyu,izu) = (*this)(ix,iy,iz);
}
template< class array3 >
void copy_add_unpad( array3& v )
{
for( int ix=nx_/4,ixu=0; ix<3*nx_/4; ++ix,++ixu )
for( int iy=ny_/4,iyu=0; iy<3*ny_/4; ++iy,++iyu )
for( int iz=nz_/4,izu=0; iz<3*nz_/4; ++iz,++izu )
v(ixu,iyu,izu) += (*this)(ix,iy,iz);
}
template< class array3 >
void copy_subtract_unpad( array3& v )
{
for( int ix=nx_/4,ixu=0; ix<3*nx_/4; ++ix,++ixu )
for( int iy=ny_/4,iyu=0; iy<3*ny_/4; ++iy,++iyu )
for( int iz=nz_/4,izu=0; iz<3*nz_/4; ++iz,++izu )
v(ixu,iyu,izu) -= (*this)(ix,iy,iz);
}
void zero_boundary( void )
{
for( int ix=0; ix<nx_/4; ++ix )
for( int iy=0; iy<ny_; ++iy )
for( int iz=0; iz<nz_; ++iz )
{
(*this)(ix,iy,iz) = 0.0;
(*this)(ix+3*nx_/4,iy,iz) = 0.0;
}
for( int ix=0; ix<nx_; ++ix )
for( int iy=0; iy<ny_/4; ++iy )
for( int iz=0; iz<nz_; ++iz )
{
(*this)(ix,iy,iz) = 0.0;
(*this)(ix,iy+3*ny_/4,iz) = 0.0;
}
for( int ix=0; ix<nx_; ++ix )
for( int iy=0; iy<ny_; ++iy )
for( int iz=0; iz<nz_/4; ++iz )
{
(*this)(ix,iy,iz) = 0.0;
(*this)(ix,iy,iz+3*nz_/4) = 0.0;
}
}
};
template< typename M >
inline void enforce_coarse_mean( M& v, M& V )
{
double outersum =0.0, innersum = 0.0;
int
nx = v.size(0)/2,
ny = v.size(1)/2,
nz = v.size(2)/2,
ox = v.offset(0),
oy = v.offset(1),
oz = v.offset(2);
unsigned innercount = 0, outercount = 0;
for( int i=0; i<V.size(0); ++i )
for( int j=0; j<V.size(1); ++j )
for( int k=0; k<V.size(2); ++k )
{
if( (i > ox && i < ox+nx) &&
(j > oy && j < oy+ny) &&
(k > oz && k < oz+nz ))
{
innersum += V(i,j,k);
++innercount;
}
else
{
outersum += V(i,j,k);
++outercount;
}
}
innersum /= innercount;
outersum /= outercount;
double dcorr = innersum * innercount / outercount;
for( int i=0; i<V.size(0); ++i )
for( int j=0; j<V.size(1); ++j )
for( int k=0; k<V.size(2); ++k )
{
if( !((i > ox && i < ox+nx) &&
(j > oy && j < oy+ny) &&
(k > oz && k < oz+nz )))
V(i,j,k) -= outersum + dcorr;//innersum;
}
}
template< typename M >
inline void enforce_mean( M& v, M& V )
{
int
nx = v.size(0)/2,
ny = v.size(1)/2,
nz = v.size(2)/2,
ox = v.offset(0),
oy = v.offset(1),
oz = v.offset(2);
double coarsemean = 0.0, finemean = 0.0;
unsigned count = 0;
#pragma omp parallel for reduction(+:coarsemean,finemean,count)
for( int i=0; i<nx; ++i )
{
int i2 = 2*i;
for( int j=0,j2=0; j<ny; ++j,j2+=2 )
for( int k=0,k2=0; k<nz; ++k,k2+=2 )
{
finemean += 0.125 * ( v(i2+1,j2,k2) + v(i2,j2+1,k2) + v(i2,j2,k2+1) + v(i2+1,j2+1,k2) +
v(i2+1,j2,k2+1) + v(i2+1,j2+1,k2+1) + v(i2,j2+1,k2+1) + v(i2,j2,k2) );
coarsemean += V(i+ox,j+oy,k+oz);
++count;
}
}
coarsemean /= count;
finemean /= count;
double dmean = coarsemean-finemean;
#pragma omp parallel for reduction(+:coarsemean,finemean)
for( int i=0; i<nx; ++i )
{
int i2 = 2*i;
for( int j=0,j2=0; j<ny; ++j,j2+=2 )
for( int k=0,k2=0; k<nz; ++k,k2+=2 )
{
v(i2+1,j2,k2) += dmean;
v(i2,j2+1,k2) += dmean;
v(i2,j2,k2+1) += dmean;
v(i2+1,j2+1,k2) += dmean;
v(i2+1,j2,k2+1) += dmean;
v(i2+1,j2+1,k2+1) += dmean;
v(i2,j2+1,k2+1) += dmean;
v(i2,j2,k2) += dmean;
}
}
}
#endif

408
fd_schemes.hh Normal file
View file

@ -0,0 +1,408 @@
/*
fd_schemes.hh - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __FD_SCHEMES_HH
#define __FD_SCHEMES_HH
#include <vector>
#include <stdexcept>
//... abstract implementation of the Poisson/Force scheme
template< class L, class G, typename real_t=double >
class scheme
{
public:
typedef L laplacian;
typedef G gradient;
laplacian m_laplacian;
gradient m_gradient;
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 ); }
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 ); }
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 ); }
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 ); }
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 ); }
inline real_t ccoeff( void )
{ return m_laplacian.ccoeff(); }
};
template< int nextent, typename T >
class gradient
{
typedef T real_t;
std::vector<real_t> m_stencil;
const unsigned nl;
public:
gradient()
: nl( 2*nextent+1 )
{
m_stencil.assign(nl*nl*nl,(real_t)0.0);
}
real_t& operator()(int i)
{ return m_stencil[i+nextent]; }
const real_t& operator()(int i) const
{ return m_stencil[i+nextent]; }
template< class C >
inline void apply( const C& c, C& f, int dir )
{
f = c;
int nx=c.size(0), ny=c.size(1), nz=c.size(2);
double hx = 1.0/(nx+1.0), hy = 1.0/(ny+1.0), hz = 1.0/(nz+1.0);
f.zero();
if( dir == 0 )
for( int i=0; i<nx; ++i )
for( int j=0; j<ny; ++j )
for( int k=0; k<nz; ++k )
for( int ii = -nextent; ii<=nextent; ++ii )
f(i,j,k) += (*this)(ii) * c(i+ii,j,k)/hx;
else if( dir == 1 )
for( int i=0; i<nx; ++i )
for( int j=0; j<ny; ++j )
for( int k=0; k<nz; ++k )
for( int jj = -nextent; jj<=nextent; ++jj )
f(i,j,k) += (*this)(jj) * c(i,j+jj,k)/hy;
else if( dir == 2 )
for( int i=0; i<nx; ++i )
for( int j=0; j<ny; ++j )
for( int k=0; k<nz; ++k )
for( int kk = -nextent; kk<=nextent; ++kk )
f(i,j,k) += (*this)(kk) * c(i,j,k+kk)/hz;
}
};
template< int nextent, typename real_t >
class base_stencil
{
protected:
std::vector<real_t> m_stencil;
const unsigned nl;
public:
bool m_modsource;
public:
base_stencil( bool amodsource = false )
: nl( 2*nextent+1 ), m_modsource( amodsource )
{
m_stencil.assign(nl*nl*nl,(real_t)0.0);
}
real_t& operator()(int i, int j, int k)
{ return m_stencil[((i+nextent)*nl+(j+nextent))*nl+(k+nextent)]; }
const real_t& operator()(unsigned i, unsigned j, unsigned k) const
{ return m_stencil[((i+nextent)*nl+(j+nextent))*nl+(k+nextent)]; }
template< class C >
inline real_t rhs( const C& c, const int i, const int j, const int k )
{
real_t sum = this->apply( c, i, j, k );
sum -= (*this)(0,0,0) * c(i,j,k);
return sum;
}
inline real_t ccoeff( void )
{
return (*this)(0,0,0);
}
template< class C >
inline real_t apply( const C& c, const int i, const int j, const int k )
{
real_t sum = 0.0;
for( int ii=-nextent; ii<=nextent; ++ii )
for( int jj=-nextent; jj<=nextent; ++jj )
for( int kk=-nextent; kk<=nextent; ++kk )
sum += (*this)(ii,jj,kk) * c(i+ii,j+jj,k+kk);
return sum;
}
template< class C >
inline real_t modsource( const C& c, const int i, const int j, const int k )
{
return 0.0;
}
};
/***************************************************************************************/
/***************************************************************************************/
/***************************************************************************************/
//... Implementation of the Gradient schemes............................................
template< typename real_t >
class deriv_2P : public gradient<1,real_t>
{
public:
deriv_2P( void )
{
(*this)( 0 ) = 0.0;
(*this)(-1 ) = -0.5;
(*this)(+1 ) = +0.5;
}
};
//... Implementation of the Laplacian schemes..........................................
template< typename real_t >
class stencil_7P : public base_stencil<1,real_t>
{
public:
stencil_7P( void )
{
(*this)( 0, 0, 0) = -6.0;
(*this)(-1, 0, 0) = +1.0;
(*this)(+1, 0, 0) = +1.0;
(*this)( 0,-1, 0) = +1.0;
(*this)( 0,+1, 0) = +1.0;
(*this)( 0, 0,-1) = +1.0;
(*this)( 0, 0,+1) = +1.0;
}
template< class C >
inline real_t apply( const C& c, const int i, const int j, const int k ) const
{
return c(i-1,j,k)+c(i+1,j,k)+c(i,j-1,k)+c(i,j+1,k)+c(i,j,k-1)+c(i,j,k+1)-6.0*c(i,j,k);
}
template< class C >
inline real_t rhs( const C& c, const int i, const int j, const int k ) const
{
return c(i-1,j,k)+c(i+1,j,k)+c(i,j-1,k)+c(i,j+1,k)+c(i,j,k-1)+c(i,j,k+1);
}
inline real_t ccoeff( void )
{
return -6.0;
}
};
template< typename real_t >
class stencil_13P : public base_stencil<2,real_t>
{
public:
stencil_13P( void )
{
(*this)( 0, 0, 0) = -90.0/12.;
(*this)(-1, 0, 0) =
(*this)(+1, 0, 0) =
(*this)( 0,-1, 0) =
(*this)( 0,+1, 0) =
(*this)( 0, 0,-1) =
(*this)( 0, 0,+1) = 16./12.;
(*this)(-2, 0, 0) =
(*this)(+2, 0, 0) =
(*this)( 0,-2, 0) =
(*this)( 0,+2, 0) =
(*this)( 0, 0,-2) =
(*this)( 0, 0,+2) = -1./12.;
}
template< class C >
inline real_t apply( const C& c, const int i, const int j, const int k )
{
return
(-1.0*(c(i-2,j,k)+c(i+2,j,k)+c(i,j-2,k)+c(i,j+2,k)+c(i,j,k-2)+c(i,j,k+2))
+16.0*(c(i-1,j,k)+c(i+1,j,k)+c(i,j-1,k)+c(i,j+1,k)+c(i,j,k-1)+c(i,j,k+1))
-90.0*c(i,j,k))/12.0;
}
template< class C >
inline real_t rhs( const C& c, const int i, const int j, const int k )
{
return
(-1.0*(c(i-2,j,k)+c(i+2,j,k)+c(i,j-2,k)+c(i,j+2,k)+c(i,j,k-2)+c(i,j,k+2))
+16.0*(c(i-1,j,k)+c(i+1,j,k)+c(i,j-1,k)+c(i,j+1,k)+c(i,j,k-1)+c(i,j,k+1)))/12.0;
}
inline real_t ccoeff( void )
{
return -90.0/12.0;
}
};
template< typename real_t >
class stencil_19P : public base_stencil<3,real_t>
{
public:
stencil_19P( void )
{
(*this)( 0, 0, 0) = -1470./180.;
(*this)(-1, 0, 0) =
(*this)(+1, 0, 0) =
(*this)( 0,-1, 0) =
(*this)( 0,+1, 0) =
(*this)( 0, 0,-1) =
(*this)( 0, 0,+1) = 270./180.;
(*this)(-2, 0, 0) =
(*this)(+2, 0, 0) =
(*this)( 0,-2, 0) =
(*this)( 0,+2, 0) =
(*this)( 0, 0,-2) =
(*this)( 0, 0,+2) = -27./180.;
(*this)(-3, 0, 0) =
(*this)(+3, 0, 0) =
(*this)( 0,-3, 0) =
(*this)( 0,+3, 0) =
(*this)( 0, 0,-3) =
(*this)( 0, 0,+3) = 2./180.;
}
template< class C >
inline real_t apply( const C& c, const int i, const int j, const int k )
{
return
(2.0*(c(i-3,j,k)+c(i+3,j,k)+c(i,j-3,k)+c(i,j+3,k)+c(i,j,k-3)+c(i,j,k+3))
-27.0*(c(i-2,j,k)+c(i+2,j,k)+c(i,j-2,k)+c(i,j+2,k)+c(i,j,k-2)+c(i,j,k+2))
+270.0*(c(i-1,j,k)+c(i+1,j,k)+c(i,j-1,k)+c(i,j+1,k)+c(i,j,k-1)+c(i,j,k+1))
-1470.0*c(i,j,k))/180.0;
}
template< class C >
inline real_t rhs( const C& c, const int i, const int j, const int k )
{
return
(2.0*(c(i-3,j,k)+c(i+3,j,k)+c(i,j-3,k)+c(i,j+3,k)+c(i,j,k-3)+c(i,j,k+3))
-27.0*(c(i-2,j,k)+c(i+2,j,k)+c(i,j-2,k)+c(i,j+2,k)+c(i,j,k-2)+c(i,j,k+2))
+270.0*(c(i-1,j,k)+c(i+1,j,k)+c(i,j-1,k)+c(i,j+1,k)+c(i,j,k-1)+c(i,j,k+1)))/180.0;
}
inline real_t ccoeff( void )
{
return -1470.0/180.0;
}
};
template< typename real_t >
class Laplace_flux_O4
{
public:
//.. idir is -1 for left boundary, +1 for right boundary
template< class C >
inline double apply_x( int idir, const C& c, const int i, const int j, const int k )
{
double fac = -((double)idir)/12.0;
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));
}
template< class C >
inline double apply_y( int idir, const C& c, const int i, const int j, const int k )
{
double fac = -((double)idir)/12.0;
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));
}
template< class C >
inline double apply_z( int idir, const C& c, const int i, const int j, const int k )
{
double fac = -((double)idir)/12.0;
return fac*(-c(i,j,k-2)+15.0*c(i,j,k-1)-15.0*c(i,j,k)+c(i,j,k+1));
}
};
template< typename real_t >
class Laplace_flux_O6
{
public:
//.. idir is -1 for left boundary, +1 for right boundary
template< class C >
inline double apply_x( int idir, const C& c, const int i, const int j, const int k )
{
double fac = -((double)idir)/180.0;
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));
}
template< class C >
inline double apply_y( int idir, const C& c, const int i, const int j, const int k )
{
double fac = -((double)idir)/180.0;
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));
}
template< class C >
inline double apply_z( int idir, const C& c, const int i, const int j, const int k )
{
double fac = -((double)idir)/180.0;
return fac*(2.*c(i,j,k-3)-25.*c(i,j,k-2)+245.*c(i,j,k-1)-245.0*c(i,j,k)+25.*c(i,j,k+1)-2.*c(i,j,k+2));
}
};
#endif

121
general.hh Normal file
View file

@ -0,0 +1,121 @@
/*
general.hh - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __GENERAL_HH
#define __GENERAL_HH
#include <omp.h>
#ifdef WITH_MPI
#ifdef MANNO
#include <mpi.h>
#else
#include <mpi++.h>
#endif
#else
#include <time.h>
#endif
#ifdef SINGLE_PRECISION
#ifdef WITH_MPI
#include "srfftw_mpi.h"
#define MPI_TREAL MPI_FLOAT
#else
#include "srfftw.h"
#endif
typedef float real_t;
#else
#ifdef WITH_MPI
#include "drfftw_mpi.h"
#define MPI_TREAL MPI_DOUBLE
#else
#include "drfftw.h"
#endif
typedef double real_t;
#endif
#include <vector>
#include "mesh.hh"
typedef GridHierarchy<real_t> grid_hierarchy;
typedef MeshvarBnd<real_t> meshvar_bnd;
typedef Meshvar<real_t> meshvar;
/* Convenience from Numerical Recipes in C, 2nd edition */
template< typename T >
inline T SQR( T a ){
return a*a;
}
template< typename T >
inline T CUBE( T a ){
return a*a*a;
}
template< typename T >
inline T POW4( T a ){
return a*a*a*a;
}
// --- 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
}Cosmology;
typedef struct {
unsigned levelmin, levelmax;
double boxlength;
std::vector<unsigned> offx,offy,offz,llx,lly,llz;
}Parameters;
inline double time_seconds( void )
{
#ifdef WITH_MPI
return MPI_Wtime();
#else
return ((double) clock()) / CLOCKS_PER_SEC;
#endif
}
#endif

605
main.cc Normal file
View file

@ -0,0 +1,605 @@
/*
main.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdio.h>
#include <iostream>
#include <iomanip>
#include <math.h>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include <gsl/gsl_integration.h>
#include "general.hh"
#include "output.hh"
#include "config_file.hh"
#include "poisson.hh"
#include "mg_solver.hh"
#include "fd_schemes.hh"
#include "random.hh"
#include "densities.hh"
#include "cosmology.hh"
#include "transfer_function.hh"
#define THE_CODE_NAME "music!"
#define THE_CODE_VERSION "0.2a"
namespace music
{
struct framework
{
transfer_function *the_transfer_function;
//poisson_solver *the_poisson_solver;
config_file *the_config_file;
refinement_hierarchy *the_refinement_hierarchy;
};
}
transfer_function *TransferFunction_real::ptf_ = NULL;
transfer_function *TransferFunction_k::ptf_ = NULL;
real_t TransferFunction_real::nspec_ = -1.0;
real_t TransferFunction_k::nspec_ = -1.0;
void splash(void)
{
std::cout
<< "\n __ __ __ __ ______ __ ______ \n"
<< " /\\ \"-./ \\ /\\ \\/\\ \\ /\\ ___\\ /\\ \\ /\\ ___\\ \n"
<< " \\ \\ \\-./\\ \\ \\ \\ \\_\\ \\ \\ \\___ \\ \\ \\ \\ \\ \\ \\____ \n"
<< " \\ \\_\\ \\ \\_\\ \\ \\_____\\ \\/\\_____\\ \\ \\_\\ \\ \\_____\\ \n"
<< " \\/_/ \\/_/ \\/_____/ \\/_____/ \\/_/ \\/_____/ \n\n"
<< " this is " << THE_CODE_NAME << " version " << THE_CODE_VERSION << "\n\n\n";
}
void modify_grid_for_TF( const refinement_hierarchy& rh_full, refinement_hierarchy& rh_TF, config_file& cf )
{
unsigned lbase, lbaseTF, lmax;
lbase = cf.getValue<unsigned>( "setup", "levelmin" );
lbaseTF = cf.getValueSafe<unsigned>( "setup", "levelminTF", lbase );
lmax = cf.getValue<unsigned>( "setup", "levelmax" );
rh_TF = rh_full;
unsigned pad = 4;
for( unsigned i=lbase+1; i<=lmax; ++i )
{
rh_TF.adjust_level(i, rh_TF.size(i,0)+2*pad, rh_TF.size(i,1)+2*pad, rh_TF.size(i,2)+2*pad,
rh_TF.offset_abs(i,0)-pad, rh_TF.offset_abs(i,1)-pad, rh_TF.offset_abs(i,2)-pad);
}
if( lbaseTF > lbase )
{
std::cout << " - Will use levelmin = " << lbaseTF << " to compute density field...\n";
for( unsigned i=lbase; i<=lbaseTF; ++i )
{
unsigned nfull = (unsigned)pow(2,i);
rh_TF.adjust_level(i, nfull, nfull, nfull, 0, 0, 0);
}
}
}
void coarsen_density( const refinement_hierarchy& rh, grid_hierarchy& u )
{
for( unsigned i=1; i<=rh.levelmax(); ++i )
{
if( rh.offset(i,0) != u.get_grid(i)->offset(0)
|| rh.offset(i,1) != u.get_grid(i)->offset(1)
|| rh.offset(i,2) != u.get_grid(i)->offset(2)
|| rh.size(i,0) != u.get_grid(i)->size(0)
|| rh.size(i,1) != u.get_grid(i)->size(1)
|| rh.size(i,2) != u.get_grid(i)->size(2) )
{
u.cut_patch(i, rh.offset_abs(i,0), rh.offset_abs(i,1), rh.offset_abs(i,2),
rh.size(i,0), rh.size(i,1), rh.size(i,2) );
}
}
}
void store_grid_structure( config_file& cf, const refinement_hierarchy& rh )
{
char str1[128], str2[128];
for( unsigned i=rh.levelmin(); i<=rh.levelmax(); ++i )
{
for( int j=0; j<3; ++j )
{
sprintf(str1,"offset(%d,%d)",i,j);
sprintf(str2,"%d",rh.offset(i,j));
cf.insertValue("setup",str1,str2);
sprintf(str1,"size(%d,%d)",i,j);
sprintf(str2,"%d",rh.size(i,j));
cf.insertValue("setup",str1,str2);
}
}
}
//... this is just for testing purposes ...
void compute_Lu( const grid_hierarchy& u, grid_hierarchy& Du )
{
Du = u;
for( unsigned ilevel=u.levelmin(); ilevel<=u.levelmax(); ++ilevel )
{
double h = pow(2.0,ilevel);
h = h*h;
meshvar_bnd *pvar = Du.get_grid(ilevel);
/*#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
(*pvar)(ix,iy,iz) = -((*u.get_grid(ilevel))(ix+1,iy,iz)+(*u.get_grid(ilevel))(ix-1,iy,iz)+
(*u.get_grid(ilevel))(ix,iy+1,iz)+(*u.get_grid(ilevel))(ix,iy-1,iz)+
(*u.get_grid(ilevel))(ix,iy,iz+1)+(*u.get_grid(ilevel))(ix,iy,iz-1)-
6.0*(*u.get_grid(ilevel))(ix,iy,iz))*h;
*/
/*#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
(*pvar)(ix,iy,iz) = -stencil_13P<double>().apply(*u.get_grid(ilevel),ix,iy,iz)*h;
*/
#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
(*pvar)(ix,iy,iz) = -stencil_19P<double>().apply(*u.get_grid(ilevel),ix,iy,iz)*h;
}
}
void subtract_finest_mean( grid_hierarchy& u )
{
std::cout << " - Subtracting component mean...\n";
double sum = 0.0;
for( int ix = 0; ix < (int)(*u.get_grid(u.levelmax())).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(u.levelmax())).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(u.levelmax())).size(2); ++iz )
sum += 0.5*(*u.get_grid(u.levelmax()))(ix,iy,iz);
sum /= (*u.get_grid(u.levelmax())).size(0)
* (*u.get_grid(u.levelmax())).size(1)
* (*u.get_grid(u.levelmax())).size(2);
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 )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
(*u.get_grid(ilevel))(ix,iy,iz) -= sum;
}
/*****************************************************************************************************/
/*****************************************************************************************************/
/*****************************************************************************************************/
int main (int argc, const char * argv[])
{
const unsigned nbnd = 4;
unsigned lbase, lmax, lbaseTF;
double err;
cosmology cosmo;
double boxlength, zstart;
std::vector<long> rngseeds;
std::vector<std::string> rngfnames;
double x0[3], lx[3];
unsigned npad = 8;
splash();
if( argc != 2 ){
std::cout << " This version is compiled with the following plug-ins:\n";
print_transfer_function_plugins();
print_output_plugins();
std::cerr << "\n In order to run, you need to specify a parameter file!\n\n";
exit(0);
}
/******************************************************************************************************/
/* read and interpret config file *********************************************************************/
/******************************************************************************************************/
config_file cf(argv[1]);
std::string tfname,randfname,temp, outformat, outfname, poisson_solver_name;;
bool shift_back(false), align_top(false), kspace(false);
float tf0,tf1,tf2;
boxlength = cf.getValue<double>( "setup", "boxlength" );
lbase = cf.getValue<unsigned>( "setup", "levelmin" );
lmax = cf.getValue<unsigned>( "setup", "levelmax" );
lbaseTF = cf.getValueSafe<unsigned>( "setup", "levelminTF", lbase );
temp = cf.getValue<std::string>( "setup", "ref_offset" );
sscanf( temp.c_str(), "%g,%g,%g", &tf0, &tf1, &tf2 ); x0[0] = tf0; x0[1] = tf1; x0[2] = tf2;
temp = cf.getValue<std::string>( "setup", "ref_extent" );
sscanf( temp.c_str(), "%g,%g,%g", &tf0, &tf1, &tf2 ); lx[0] = tf0; lx[1] = tf1; lx[2] = tf2;
npad = cf.getValue<unsigned>( "setup", "padding" );
align_top = cf.getValueSafe<bool>( "setup", "align_top", false );
kspace = cf.getValueSafe<bool>( "setup", "kspace", false );
if( kspace )
poisson_solver_name = std::string("fft_poisson");
else
poisson_solver_name = std::string("mg_poisson");
// TODO: move cosmology parameters reading to cosmo_calc
zstart = cf.getValue<double>( "setup", "zstart" );
cosmo.astart = 1.0/(1.0+zstart);
cosmo.Omega_b = cf.getValue<double>( "cosmology", "Omega_b" );
cosmo.Omega_m = cf.getValue<double>( "cosmology", "Omega_m" );
cosmo.Omega_L = cf.getValue<double>( "cosmology", "Omega_L" );
cosmo.H0 = cf.getValue<double>( "cosmology", "H0" );
cosmo.sigma8 = cf.getValue<double>( "cosmology", "sigma_8" );
cosmo.nspect = cf.getValue<double>( "cosmology", "nspec" );
cosmo.WDMg_x = cf.getValueSafe<double>( "cosmology", "WDMg_x", 1.5 );
cosmo.WDMmass = cf.getValueSafe<double>( "cosmology", "WDMmass", 0.0 );
//cosmo.Gamma = cf.getValueSafe<double>( "cosmology", "Gamma", -1.0 );
/******************************************************************************************************/
/******************************************************************************************************/
shift_back = cf.getValueSafe<bool>( "output", "shift_back", shift_back );
outformat = cf.getValue<std::string>( "output", "format" );
outfname = cf.getValue<std::string>( "output", "filename" );
/******************************************************************************************************/
/******************************************************************************************************/
/******************************************************************************************************/
#ifndef SINGLETHREAD_FFTW
fftw_threads_init();
#endif
transfer_function_plugin *the_transfer_function_plugin
= select_transfer_function_plugin( cf );
CosmoCalc ccalc(cosmo,the_transfer_function_plugin);
cosmo.pnorm = ccalc.ComputePNorm( 2.0*M_PI/boxlength );
cosmo.dplus = ccalc.CalcGrowthFactor( cosmo.astart )/ccalc.CalcGrowthFactor( 1.0 );
cosmo.vfact = ccalc.ComputeVFact( cosmo.astart );
{
char tmpstr[128];
sprintf(tmpstr,"%.12g",cosmo.pnorm);
cf.insertValue("cosmology","pnorm",tmpstr);
sprintf(tmpstr,"%.12g",cosmo.dplus);
cf.insertValue("cosmology","dplus",tmpstr);
sprintf(tmpstr,"%.12g",cosmo.vfact);
cf.insertValue("cosmology","vfact",tmpstr);
}
/******************************************************************************************************/
/******************************************************************************************************/
bool
do_baryons = cf.getValue<bool>("setup","baryons"),
do_2LPT = cf.getValue<bool>("setup","use_2LPT"),
do_LLA = cf.getValue<bool>("setup","use_LLA"),
do_CVM = cf.getValueSafe<bool>("setup","center_velocities",false),
do_UVA = false;//FIXME: cf.getValue<bool>("setup","use_UVA");
refinement_hierarchy rh_Poisson( cf );
store_grid_structure(cf, rh_Poisson);
rh_Poisson.output();
refinement_hierarchy rh_TF( rh_Poisson );
modify_grid_for_TF( rh_Poisson, rh_TF, cf );
//rh_TF.output();
if( !the_transfer_function_plugin->tf_is_distinct() && do_baryons )
std::cout << " - WARNING: The selected transfer function does not support\n"
<< " distinct amplitudes for baryon and DM fields!\n"
<< " Perturbation amplitudes will be identical!" << std::endl;
output_plugin *the_output_plugin = select_output_plugin( cf );
poisson_plugin_creator *the_poisson_plugin_creator = get_poisson_plugin_map()[ poisson_solver_name ];
poisson_plugin *the_poisson_solver = the_poisson_plugin_creator->create( cf );
//... THIS IS THE MAIN DRIVER BRANCHING TREE RUNNING THE VARIOUS PARTS OF THE CODE
bool bfatal = false;
try{
if( ! do_2LPT )
{
//.. don't use 2LPT ...
if( !the_transfer_function_plugin->tf_is_distinct() || !do_baryons )
{
std::cerr << " - Computing ICs from the total matter power spectrum..." << std::endl;
grid_hierarchy f( nbnd ), u(nbnd);
GenerateDensityHierarchy( cf, the_transfer_function_plugin, total , rh_TF, f );
coarsen_density(rh_Poisson, f);
u = f; u.zero();
err = the_poisson_solver->solve(f, u);
#if 0
grid_hierarchy u2( nbnd );
compute_Lu( u, u2 );
u=u2;
#endif
the_output_plugin->write_dm_density(f);
the_output_plugin->write_dm_mass(f);
if( do_baryons )
{
if( do_LLA )
compute_LLA_density( u, f );
the_output_plugin->write_gas_density(f);
}
f.deallocate();
the_output_plugin->write_dm_potential(u);
grid_hierarchy data_forIO(u);
for( int icoord = 0; icoord < 3; ++icoord )
{
//... displacement
the_poisson_solver->gradient(icoord, u, data_forIO );
if( do_CVM)
subtract_finest_mean( data_forIO );
the_output_plugin->write_dm_position(icoord, data_forIO );
//... velocity
if( do_UVA )
{
//FIXME: this still needs to be added
throw std::runtime_error("Updated Velocity Approximation not yet supported!");
}
else
{
data_forIO *= cosmo.vfact;
the_output_plugin->write_dm_velocity(icoord, data_forIO);
}
if( do_baryons )
the_output_plugin->write_gas_velocity(icoord, data_forIO);
}
}else{
//... cdm density and displacements
grid_hierarchy f( nbnd ), u(nbnd);
GenerateDensityHierarchy( cf, the_transfer_function_plugin, cdm , rh_TF, f );
u = f; u.zero();
err = the_poisson_solver->solve(f, u);
the_output_plugin->write_dm_density(f);
the_output_plugin->write_dm_mass(f);
f.deallocate();
the_output_plugin->write_dm_potential(u);
//... DM displacements
{
grid_hierarchy data_forIO(u);
for( int icoord = 0; icoord < 3; ++icoord )
{
//... displacement
the_poisson_solver->gradient(icoord, u, data_forIO );
the_output_plugin->write_dm_position(icoord, data_forIO );
}
}
//... gas density
GenerateDensityHierarchy( cf, the_transfer_function_plugin, baryon , rh_TF, f );
if( do_LLA )
{
u = f; u.zero();
err = the_poisson_solver->solve(f, u);
compute_LLA_density( u, f );
}
the_output_plugin->write_gas_density(f);
//... velocities
if( do_UVA )
{
//... need to co-add potentials...
throw std::runtime_error("Updated Velocity Approximation not yet supported!");
}
else
{
GenerateDensityHierarchy( cf, the_transfer_function_plugin, total , rh_TF, f );
u = f; u.zero();
err = the_poisson_solver->solve(f, u);
grid_hierarchy data_forIO(u);
for( int icoord = 0; icoord < 3; ++icoord )
{
//... displacement
the_poisson_solver->gradient(icoord, u, data_forIO );
data_forIO *= cosmo.vfact;
the_output_plugin->write_dm_velocity(icoord, data_forIO);
the_output_plugin->write_gas_velocity(icoord, data_forIO);
}
}
}
}else {
//.. use 2LPT ...
if( !the_transfer_function_plugin->tf_is_distinct() || !do_baryons )
{
grid_hierarchy f( nbnd ), u1(nbnd), u2(nbnd);
GenerateDensityHierarchy( cf, the_transfer_function_plugin, total , rh_TF, f );
u1 = f; u1.zero();
the_output_plugin->write_dm_density(f);
the_output_plugin->write_dm_mass(f);
//... compute 1LPT term
err = the_poisson_solver->solve(f, u1);
the_output_plugin->write_dm_potential(u1);
//... compute 2LPT term
u2 = f; u2.zero();
compute_2LPT_source(u1, f);
err = the_poisson_solver->solve(f, u2);
u2 *= 3.0/7.0;
grid_hierarchy data_forIO(u1);
for( int icoord = 0; icoord < 3; ++icoord )
{
//... displacement
the_poisson_solver->gradient(icoord, u1, data_forIO );
the_poisson_solver->gradient(icoord, u2, f );
//... co-add for the displacement
data_forIO += f;
the_output_plugin->write_dm_position(icoord, data_forIO );
//... velocity
if( do_UVA )
{
throw std::runtime_error("Updated Velocity Approximation not yet supported!");
}
else
{
//... for velocities, the 2LPT term has a factor of 2, so add a second time
data_forIO += f;
data_forIO *= cosmo.vfact;
the_output_plugin->write_dm_velocity(icoord, data_forIO);
}
if( do_baryons )
the_output_plugin->write_gas_velocity(icoord, data_forIO);
}
//...
u1 += u2;
if( do_baryons )
{
if( do_LLA )
compute_LLA_density( u1, f );
else
compute_Lu_density( u1, f );
the_output_plugin->write_gas_density(f);
}
}
else
{
throw std::runtime_error("2LPT for distinct baryon/CDM not implemented yet.");
}
}
the_output_plugin->finalize();
}catch(...)
{
std::cerr << " - A fatal error occured. We need to exit...\n";
bfatal;
}
//... clean up
delete the_output_plugin;
std::cout << "-------------------------------------------------------------\n";
if( !bfatal )
std::cout << " - Wrote output file \'" << outfname << "\'\n using plugin \'" << outformat << "\'...\n";
delete the_transfer_function_plugin;
delete the_poisson_solver;
/** we are done ! **/
std::cout << " - Done!" << std::endl << std::endl;
///*****************************************///
std::string save_fname(std::string(argv[1])+std::string("_stats"));
std::ofstream ofs(save_fname.c_str());
time_t ltime=time(NULL);
ofs << "Parameter dump for the run on " << asctime( localtime(&ltime) );
ofs << "You ran " << THE_CODE_NAME << " version " << THE_CODE_VERSION << std::endl << std::endl;
cf.dump( ofs );
return 0;
}

1181
mesh.hh Normal file

File diff suppressed because it is too large Load diff

1267
mg_interp.hh Normal file

File diff suppressed because it is too large Load diff

1362
mg_operators.hh Normal file

File diff suppressed because it is too large Load diff

1051
mg_solver.hh Normal file

File diff suppressed because it is too large Load diff

73
output.cc Normal file
View file

@ -0,0 +1,73 @@
/*
output.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "output.hh"
std::map< std::string, output_plugin_creator *>&
get_output_plugin_map()
{
static std::map< std::string, output_plugin_creator* > output_plugin_map;
return output_plugin_map;
}
void print_output_plugins()
{
std::map< std::string, output_plugin_creator *>& m = get_output_plugin_map();
std::map< std::string, output_plugin_creator *>::iterator it;
it = m.begin();
std::cout << " - Available output plug-ins:\n";
while( it!=m.end() )
{
if( (*it).second )
std::cout << "\t\'" << (*it).first << "\'\n";
++it;
}
}
output_plugin *select_output_plugin( config_file& cf )
{
std::string formatname = cf.getValue<std::string>( "output", "format" );
output_plugin_creator *the_output_plugin_creator
= get_output_plugin_map()[ formatname ];
if( !the_output_plugin_creator )
{
std::cerr << " - Error: output plug-in \'" << formatname << "\' not found." << std::endl;
print_output_plugins();
throw std::runtime_error("Unknown output plug-in");
}else
std::cout << " - Selecting output plug-in \'" << formatname << "\'..." << std::endl;
output_plugin *the_output_plugin
= the_output_plugin_creator->create( cf );
return the_output_plugin;
}

176
output.hh Normal file
View file

@ -0,0 +1,176 @@
/*
output.hh - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __OUTPUT_HH
#define __OUTPUT_HH
#include <string>
#include <map>
#include "general.hh"
/*!
* @class output_plugin
* @brief abstract base class for output plug-ins
*
* This class provides the abstract base class for all output plug-ins.
* All output plug-ins need to derive from it and implement the purely
* virtual member functions.
*/
class output_plugin
{
protected:
//! reference to the config_file object that holds all configuration options
config_file& cf_;
//! output file or directory name
std::string fname_;
//! minimum refinement level
unsigned levelmin_;
//! maximum refinement level
unsigned levelmax_;
std::vector<unsigned>
offx_, //!< vector describing the x-offset of each level
offy_, //!< vector describing the y-offset of each level
offz_, //!< vector describing the z-offset of each level
sizex_, //!< vector describing the extent in x of each level
sizey_, //!< vector describing the extent in y of each level
sizez_; //!< vector describing the extent in z of each level
//! quick access function to query properties of the refinement grid from the configuration options
/*! @param name name of the config property
* @param icomp component index (0=x, 1=y, 2=z)
* @param oit output iterator (e.g. std::back_inserter for vectors)
*/
template< typename output_iterator >
void query_grid_prop( std::string name, int icomp, output_iterator oit )
{
char str[128];
for( unsigned i=levelmin_; i<=levelmax_; ++i )
{
sprintf( str, "%s(%d,%d)", name.c_str(), i, icomp );
*oit = cf_.getValue<unsigned>( "setup", str );
++oit;
}
}
public:
//! constructor
explicit output_plugin( config_file& cf )
: cf_(cf)
{
fname_ = cf.getValue<std::string>("output","filename");
levelmin_ = cf.getValue<unsigned>( "setup", "levelmin" );
levelmax_ = cf.getValue<unsigned>( "setup", "levelmax" );
query_grid_prop( "offset", 0, std::back_inserter(offx_) );
query_grid_prop( "offset", 1, std::back_inserter(offy_) );
query_grid_prop( "offset", 2, std::back_inserter(offz_) );
query_grid_prop( "size", 0, std::back_inserter(sizex_) );
query_grid_prop( "size", 1, std::back_inserter(sizey_) );
query_grid_prop( "size", 2, std::back_inserter(sizez_) );
}
//! destructor
virtual ~output_plugin()
{ }
//! purely virtual prototype to write the masses for each dark matter particle
virtual void write_dm_mass( const grid_hierarchy& gh ) = 0;
//! purely virtual prototype to write the dark matter density field
virtual void write_dm_density( const grid_hierarchy& gh ) = 0;
//! purely virtual prototype to write the dark matter gravitational potential (from which displacements are computed in 1LPT)
virtual void write_dm_potential( const grid_hierarchy& gh ) = 0;
//! purely virtual prototype to write dark matter particle velocities
virtual void write_dm_velocity( int coord, const grid_hierarchy& gh ) = 0;
//! purely virtual prototype to write dark matter particle positions
virtual void write_dm_position( int coord, const grid_hierarchy& gh ) = 0;
//! purely virtual prototype to write the baryon velocities
virtual void write_gas_velocity( int coord, const grid_hierarchy& gh ) = 0;
//! purely virtual prototype to write the baryon coordinates
virtual void write_gas_position( int coord, const grid_hierarchy& gh ) = 0;
//! purely virtual prototype to write the baryon density field
virtual void write_gas_density( const grid_hierarchy& gh ) = 0;
//! purely virtual prototype to write the baryon gravitational potential (from which displacements are computed in 1LPT)
virtual void write_gas_potential( const grid_hierarchy& gh ) = 0;
//! purely virtual prototype for all things to be done at the very end
virtual void finalize( void ) = 0;
};
/*!
* @brief implements abstract factory design pattern for output plug-ins
*/
struct output_plugin_creator
{
//! create an instance of a plug-in
virtual output_plugin * create( config_file& cf ) const = 0;
//! destroy an instance of a plug-in
virtual ~output_plugin_creator() { }
};
//! maps the name of a plug-in to a pointer of the factory pattern
std::map< std::string, output_plugin_creator *>& get_output_plugin_map();
//! print a list of all registered output plug-ins
void print_output_plugins();
/*!
* @brief concrete factory pattern for output plug-ins
*/
template< class Derived >
struct output_plugin_creator_concrete : public output_plugin_creator
{
//! register the plug-in by its name
output_plugin_creator_concrete( const std::string& plugin_name )
{
get_output_plugin_map()[ plugin_name ] = this;
}
//! create an instance of the plug-in
output_plugin * create( config_file& cf ) const
{
return new Derived( cf );
}
};
//! failsafe version to select the output plug-in
output_plugin *select_output_plugin( config_file& cf );
#endif // __OUTPUT_HH

1024
plugins/HDF_IO.hh Executable file

File diff suppressed because it is too large Load diff

396
plugins/output_enzo.cc Normal file
View file

@ -0,0 +1,396 @@
/*
output_enzo.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_HDF5
#include <sys/types.h>
#include <sys/stat.h>
#include "output.hh"
#include "HDF_IO.hh"
class enzo_output_plugin : public output_plugin
{
protected:
struct patch_header{
int component_rank;
int component_size;
std::vector<int> dimensions;
int rank;
std::vector<int> top_grid_dims;
std::vector<int> top_grid_end;
std::vector<int> top_grid_start;
};
struct sim_header{
std::vector<int> dimensions;
std::vector<int> offset;
float a_start;
float dx;
float h0;
float omega_b;
float omega_m;
float omega_v;
float vfact;
};
sim_header the_sim_header;
void write_sim_header( std::string fname, const sim_header& h )
{
HDFWriteGroupAttribute( fname, "/", "Dimensions", h.dimensions );
HDFWriteGroupAttribute( fname, "/", "Offset", h.offset );
HDFWriteGroupAttribute( fname, "/", "a_start", h.a_start );
HDFWriteGroupAttribute( fname, "/", "dx", h.dx );
HDFWriteGroupAttribute( fname, "/", "h0", h.h0 );
HDFWriteGroupAttribute( fname, "/", "omega_b", h.omega_b );
HDFWriteGroupAttribute( fname, "/", "omega_m", h.omega_m );
HDFWriteGroupAttribute( fname, "/", "omega_v", h.omega_v );
HDFWriteGroupAttribute( fname, "/", "vfact", h.vfact );
}
void write_patch_header( std::string fname, std::string dsetname, const patch_header& h )
{
HDFWriteDatasetAttribute( fname, dsetname, "Component_Rank", h.component_rank );
HDFWriteDatasetAttribute( fname, dsetname, "Component_Size", h.component_size );
HDFWriteDatasetAttribute( fname, dsetname, "Dimensions", h.dimensions );
HDFWriteDatasetAttribute( fname, dsetname, "Rank", h.rank );
HDFWriteDatasetAttribute( fname, dsetname, "TopGridDims", h.top_grid_dims );
HDFWriteDatasetAttribute( fname, dsetname, "TopGridEnd", h.top_grid_end );
HDFWriteDatasetAttribute( fname, dsetname, "TopGridStart", h.top_grid_start );
}
void dump_grid_data( std::string fieldname, const grid_hierarchy& gh, double factor = 1.0, double add = 0.0 )
{
char enzoname[256], filename[256];
for(unsigned ilevel=levelmin_; ilevel<=levelmax_; ++ilevel )
{
std::vector<int> ng;
ng.push_back( gh.get_grid(ilevel)->size(0) );
ng.push_back( gh.get_grid(ilevel)->size(1) );
ng.push_back( gh.get_grid(ilevel)->size(2) );
//... need to copy data because we need to get rid of the ghost zones
std::vector<double> data;
data.reserve( ng[0]*ng[1]*ng[2] );
for( int k=0; k<ng[2]; ++k )
for( int j=0; j<ng[1]; ++j )
for( int i=0; i<ng[0]; ++i )
data.push_back( (add+(*gh.get_grid(ilevel))(i,j,k))*factor );
sprintf( enzoname, "%s.%d", fieldname.c_str(), ilevel-levelmin_ );
sprintf( filename, "%s/%s", fname_.c_str(), enzoname );
HDFCreateFile( filename );
write_sim_header( filename, the_sim_header );
HDFWriteDataset3Ds( filename, enzoname, reinterpret_cast<unsigned*>(&ng[0]), data );
//... header data for the patch
patch_header ph;
ph.component_rank = 1;
ph.component_size = ng[0]*ng[1]*ng[2];
ph.dimensions = ng;
ph.rank = 3;
ph.top_grid_dims.assign(3,(int)pow(2,levelmin_));
//... offset_abs is in units of the current level cell size
double rfac = 1.0/pow(2,ilevel-levelmin_);
ph.top_grid_start.push_back( (int)(gh.offset_abs(ilevel, 0)*rfac) );
ph.top_grid_start.push_back( (int)(gh.offset_abs(ilevel, 1)*rfac) );
ph.top_grid_start.push_back( (int)(gh.offset_abs(ilevel, 2)*rfac) );
ph.top_grid_end.push_back( ph.top_grid_start[0] + (int)(ng[0]*rfac) );
ph.top_grid_end.push_back( ph.top_grid_start[1] + (int)(ng[1]*rfac) );
ph.top_grid_end.push_back( ph.top_grid_start[2] + (int)(ng[2]*rfac) );
write_patch_header( filename, enzoname, ph );
}
}
public:
enzo_output_plugin( config_file& cf )
: output_plugin( cf )
{
if( mkdir( fname_.c_str(), 0777 ) )
{
perror( fname_.c_str() );
throw std::runtime_error("Error in enzo_output_plugin!");
}
bool bhave_hydro = cf_.getValue<bool>("setup","baryons");
the_sim_header.dimensions.push_back( (int)pow(2,levelmin_) );
the_sim_header.dimensions.push_back( (int)pow(2,levelmin_) );
the_sim_header.dimensions.push_back( (int)pow(2,levelmin_) );
the_sim_header.offset.push_back( 0 );
the_sim_header.offset.push_back( 0 );
the_sim_header.offset.push_back( 0 );
the_sim_header.a_start = 1.0/(1.0+cf.getValue<double>("setup","zstart"));
the_sim_header.dx = cf.getValue<double>("setup","boxlength")/the_sim_header.dimensions[0]/(cf.getValue<double>("cosmology","H0")*0.01); // not sure?!?
the_sim_header.h0 = cf.getValue<double>("cosmology","H0")*0.01;
if( bhave_hydro )
the_sim_header.omega_b = cf.getValue<double>("cosmology","Omega_b");
else
the_sim_header.omega_b = 0.0;
the_sim_header.omega_m = cf.getValue<double>("cosmology","Omega_m");
the_sim_header.omega_v = cf.getValue<double>("cosmology","Omega_L");
the_sim_header.vfact = cf.getValue<double>("cosmology","vfact")*the_sim_header.h0; //.. need to multiply by h, ENZO wants this factor for non h-1 units
}
~enzo_output_plugin()
{ }
void write_dm_mass( const grid_hierarchy& gh )
{ /* do nothing, not needed */ }
void write_dm_density( const grid_hierarchy& gh )
{ /* do nothing, not needed */
bool bhave_hydro = cf_.getValue<bool>("setup","baryons");
char filename[256];
unsigned nbase = (unsigned)pow(2,levelmin_);
sprintf( filename, "%s/parameter_file.txt", fname_.c_str() );
std::ofstream ofs( filename, std::ios::trunc );
ofs
<< "#\n"
<< "ProblemType = 30 // cosmology simulation\n"
<< "TopGridRank = 3\n"
<< "TopGridDimensions = " << nbase << " " << nbase << " " << nbase << "\n"
<< "SelfGravity = 1 // gravity on\n"
<< "TopGridGravityBoundary = 0 // Periodic BC for gravity\n"
<< "LeftFaceBoundaryCondition = 3 3 3 // same for fluid\n"
<< "RightFaceBoundaryCondition = 3 3 3\n"
<< "\n"
<< "#\n";
if( bhave_hydro )
ofs
<< "CosmologySimulationOmegaBaryonNow = " << the_sim_header.omega_b << "\n"
<< "CosmologySimulationOmegaCDMNow = " << the_sim_header.omega_m-the_sim_header.omega_b << "\n";
else
ofs
<< "CosmologySimulationOmegaBaryonNow = " << 0.0 << "\n"
<< "CosmologySimulationOmegaCDMNow = " << the_sim_header.omega_m << "\n";
if( bhave_hydro )
ofs
<< "CosmologySimulationDensityName = GridDensity\n"
<< "CosmologySimulationVelocity1Name = GridVelocities_x\n"
<< "CosmologySimulationVelocity2Name = GridVelocities_y\n"
<< "CosmologySimulationVelocity3Name = GridVelocities_z\n";
ofs
<< "CosmologySimulationCalculatePositions = 1\n"
<< "CosmologySimulationParticleVelocity1Name = ParticleVelocities_x\n"
<< "CosmologySimulationParticleVelocity2Name = ParticleVelocities_y\n"
<< "CosmologySimulationParticleVelocity3Name = ParticleVelocities_z\n"
<< "\n"
<< "#\n"
<< "# define cosmology parameters\n"
<< "#\n"
<< "ComovingCoordinates = 1 // Expansion ON\n"
<< "CosmologyOmegaMatterNow = " << the_sim_header.omega_m << "\n"
<< "CosmologyOmegaLambdaNow = " << the_sim_header.omega_v << "\n"
<< "CosmologyHubbleConstantNow = " << the_sim_header.h0 << " // in 100 km/s/Mpc\n"
<< "CosmologyComovingBoxSize = " << cf_.getValue<double>("setup","boxlength") << " // in Mpc/h\n"
<< "CosmologyMaxExpansionRate = 0.015 // maximum allowed delta(a)/a\n"
<< "CosmologyInitialRedshift = " << cf_.getValue<double>("setup","zstart") << " //\n"
<< "CosmologyFinalRedshift = 0 //\n"
<< "GravitationalConstant = 1 // this must be true for cosmology\n"
<< "#\n"
<< "#\n"
<< "CosmologySimulationNumberOfInitialGrids = " << 1+levelmax_-levelmin_ << "\n";
//... only for additionally refined grids
for( unsigned ilevel = 0; ilevel< levelmax_-levelmin_; ++ilevel )
{
double h = 1.0/pow(2,levelmin_+1+ilevel);
ofs
<< "CosmologySimulationGridDimension[" << 1+ilevel << "] = "
<< gh.size( levelmin_+ilevel+1, 0 ) << " "
<< gh.size( levelmin_+ilevel+1, 1 ) << " "
<< gh.size( levelmin_+ilevel+1, 2 ) << "\n"
<< "CosmologySimulationGridLeftEdge[" << 1+ilevel << "] = "
<< h*gh.offset_abs(levelmin_+ilevel+1, 0) << " "
<< h*gh.offset_abs(levelmin_+ilevel+1, 1) << " "
<< h*gh.offset_abs(levelmin_+ilevel+1, 2) << "\n"
<< "CosmologySimulationGridRightEdge[" << 1+ilevel << "] = "
<< h*(gh.offset_abs(levelmin_+ilevel+1, 0)+gh.size( levelmin_+ilevel+1, 0 )) << " "
<< h*(gh.offset_abs(levelmin_+ilevel+1, 1)+gh.size( levelmin_+ilevel+1, 1 )) << " "
<< h*(gh.offset_abs(levelmin_+ilevel+1, 2)+gh.size( levelmin_+ilevel+1, 2 )) << "\n"
<< "CosmologySimulationGridLevel[" << 1+ilevel << "] = " << 1+ilevel << "\n";
}
}
void write_dm_velocity( int coord, const grid_hierarchy& gh )
{
char enzoname[256];
sprintf( enzoname, "ParticleVelocities_%c", (char)('x'+coord) );
double vunit = 1.0/(1.225e2*sqrt(the_sim_header.omega_m/the_sim_header.a_start));// /the_sim_header.h0;
dump_grid_data( enzoname, gh, vunit );
}
void write_dm_position( int coord, const grid_hierarchy& gh )
{
char fieldname[256];
sprintf( fieldname, "ParticlePositions_%c", (char)('x'+coord) );
char enzoname[256], filename[256];
for(unsigned ilevel=levelmin_; ilevel<=levelmax_; ++ilevel )
{
std::vector<int> ng;
ng.push_back( gh.get_grid(ilevel)->size(0) );
ng.push_back( gh.get_grid(ilevel)->size(1) );
ng.push_back( gh.get_grid(ilevel)->size(2) );
//... need to copy data because we need to get rid of the ghost zones
std::vector<double> data;
data.reserve( ng[0]*ng[1]*ng[2] );
for( int k=0; k<ng[2]; ++k )
for( int j=0; j<ng[1]; ++j )
for( int i=0; i<ng[0]; ++i )
{
double xx[3];
gh.cell_pos(ilevel, i, j, k, xx);
data.push_back( fmod( 1.0 + xx[coord] + (*gh.get_grid(ilevel))(k,j,i), 1.0 ) );
}
//--------------------------------------------------------------------------
sprintf( enzoname, "%s.%d", fieldname, ilevel-levelmin_ );
sprintf( filename, "%s/%s", fname_.c_str(), enzoname );
HDFCreateFile( filename );
write_sim_header( filename, the_sim_header );
HDFWriteDataset3Ds( filename, enzoname, reinterpret_cast<unsigned*>(&ng[0]), data );
//--------------------------------------------------------------------------
//... header data for the patch
patch_header ph;
ph.component_rank = 1;
ph.component_size = ng[0]*ng[1]*ng[2];
ph.dimensions = ng;
ph.rank = 3;
ph.top_grid_dims.assign(3,(int)pow(2,levelmin_));
//... offset_abs is in units of the current level cell size
double rfac = 1.0/pow(2,ilevel-levelmin_);
ph.top_grid_start.push_back( (int)(gh.offset_abs(ilevel, 0)*rfac) );
ph.top_grid_start.push_back( (int)(gh.offset_abs(ilevel, 1)*rfac) );
ph.top_grid_start.push_back( (int)(gh.offset_abs(ilevel, 2)*rfac) );
ph.top_grid_end.push_back( ph.top_grid_start[0] + (int)(ng[0]*rfac) );
ph.top_grid_end.push_back( ph.top_grid_start[1] + (int)(ng[1]*rfac) );
ph.top_grid_end.push_back( ph.top_grid_start[2] + (int)(ng[2]*rfac) );
write_patch_header( filename, enzoname, ph );
//--------------------------------------------------------------------------
}
}
void write_dm_potential( const grid_hierarchy& gh )
{ }
void write_gas_potential( const grid_hierarchy& gh )
{ }
void write_gas_velocity( int coord, const grid_hierarchy& gh )
{
double vunit = 1.0/(1.225e2*sqrt(the_sim_header.omega_m/the_sim_header.a_start));
char enzoname[256];
sprintf( enzoname, "GridVelocities_%c", (char)('x'+coord) );
dump_grid_data( enzoname, gh, vunit );
}
void write_gas_position( int coord, const grid_hierarchy& gh )
{
/* do nothing, not needed */
}
void write_gas_density( const grid_hierarchy& gh )
{
char enzoname[256];
sprintf( enzoname, "GridDensity" );
dump_grid_data( enzoname, gh, the_sim_header.omega_b/the_sim_header.omega_m, 1.0 );
}
void finalize( void )
{ }
};
namespace{
output_plugin_creator_concrete<enzo_output_plugin> creator("enzo");
}
#endif

670
plugins/output_gadget2.cc Normal file
View file

@ -0,0 +1,670 @@
/*
output_gadget2.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <fstream>
#include "output.hh"
template< typename T_store=float >
class gadget2_output_plugin : public output_plugin
{
protected:
std::ofstream ofs_;
bool bmultimass_;
typedef struct io_header
{
int npart[6];
double mass[6];
double time;
double redshift;
int flag_sfr;
int flag_feedback;
unsigned int npartTotal[6];
int flag_cooling;
int num_files;
double BoxSize;
double Omega0;
double OmegaLambda;
double HubbleParam;
int flag_stellarage;
int flag_metals;
unsigned int npartTotalHighWord[6];
int flag_entropy_instead_u;
char fill[60];
}header;
header header_;
std::string fname;
enum iofields {
id_dm_mass, id_dm_vel, id_dm_pos, id_gas_vel, id_gas_rho, id_gas_temp
};
unsigned block_buf_size_;
//bool bbndparticles_;
bool bmorethan2bnd_;
void assemble_scalar( unsigned nptot, std::string ifname )
{
T_store *tmp;
std::ifstream
ifs( ifname.c_str(), std::ios::binary );
int
npleft = nptot,
n2read = std::min((int)block_buf_size_,npleft);
tmp = new T_store[block_buf_size_];
std::vector<T_store> adata;
adata.reserve( block_buf_size_ );
unsigned blk;
ifs.read( (char *)&blk, sizeof(int) );
if( blk != nptot*sizeof(T_store) ){
delete[] tmp;
throw std::runtime_error("Internal consistency error in gadget2 output plug-in");
}
npleft = nptot;
n2read = std::min((int)block_buf_size_,npleft);
int blksize = nptot*sizeof(T_store);
ofs_.write( reinterpret_cast<char*>(&blksize), sizeof(int) );
while( n2read > 0 )
{
ifs.read( reinterpret_cast<char*>(&tmp[0]), n2read*sizeof(T_store) );
ofs_.write( reinterpret_cast<char*>(&tmp[0]), n2read*sizeof(T_store) );
npleft -= n2read;
n2read = std::min( (int)block_buf_size_,npleft );
}
ofs_.write( reinterpret_cast<char*>(&blksize), sizeof(int) );
remove( fname.c_str() );
}
void assemble_vector( unsigned nptot, std::string fname1, std::string fname2,std::string fname3 )
{
T_store *tmp1, *tmp2, *tmp3;
std::ifstream
ifs1( fname1.c_str(), std::ios::binary ),
ifs2( fname2.c_str(), std::ios::binary ),
ifs3( fname3.c_str(), std::ios::binary );
int
npleft = nptot,
n2read = std::min((int)block_buf_size_,npleft);
tmp1 = new T_store[block_buf_size_];
tmp2 = new T_store[block_buf_size_];
tmp3 = new T_store[block_buf_size_];
std::vector<T_store> adata3;
adata3.reserve( 3*block_buf_size_ );
unsigned blk;
ifs1.read( (char *)&blk, sizeof(int) );
if( blk != nptot*sizeof(T_store) ){
delete[] tmp1;
delete[] tmp2;
delete[] tmp3;
throw std::runtime_error("Internal consistency error in gadget2 output plug-in");
}
ifs2.read( (char *)&blk, sizeof(int) );
if( blk != nptot*sizeof(T_store) )
{
delete[] tmp1;
delete[] tmp2;
delete[] tmp3;
throw std::runtime_error("Internal consistency error in gadget2 output plug-in");
}
ifs3.read( (char *)&blk, sizeof(int) );
if( blk != nptot*sizeof(T_store) )
{
delete[] tmp1;
delete[] tmp2;
delete[] tmp3;
throw std::runtime_error("Internal consistency error in gadget2 output plug-in");
}
//int blksize = 3*nptot*sizeof(T_store);
//ofs_.write( (char *)&blksize, sizeof(int) );
while( n2read > 0 )
{
//ifs1.read( (char*)&tmp1[0], n2read*sizeof(T_store) );
ifs1.read( reinterpret_cast<char*>(&tmp1[0]), n2read*sizeof(T_store) );
ifs2.read( reinterpret_cast<char*>(&tmp2[0]), n2read*sizeof(T_store) );
ifs3.read( reinterpret_cast<char*>(&tmp3[0]), n2read*sizeof(T_store) );
for( int i=0; i<n2read; ++i )
{
adata3.push_back( tmp1[i] );
adata3.push_back( tmp2[i] );
adata3.push_back( tmp3[i] );
}
ofs_.write( reinterpret_cast<char*>(&adata3[0]), 3*n2read*sizeof(T_store) );
adata3.clear();
npleft -= n2read;
n2read = std::min( (int)block_buf_size_,npleft );
}
//ofs_.write( reinterpret_cast<char*>(&blksize), sizeof(int) );
remove( fname1.c_str() );
remove( fname2.c_str() );
remove( fname3.c_str() );
delete[] tmp1;
delete[] tmp2;
delete[] tmp3;
}
void assemble_gadget_file( void )
{
int blksize = sizeof(header);
//... write the header .......................................................
ofs_.write( (char *)&blksize, sizeof(int) );
ofs_.write( (char *)&header_, sizeof(header) );
ofs_.write( (char *)&blksize, sizeof(int) );
//............................................................................
//... copy from the temporary files, interleave the data and save ............
char fnx[256],fny[256],fnz[256],fnvx[256],fnvy[256],fnvz[256],fnm[256];
sprintf( fnx, "___ic_temp_%05d.bin", 100*id_dm_pos+0 );
sprintf( fny, "___ic_temp_%05d.bin", 100*id_dm_pos+1 );
sprintf( fnz, "___ic_temp_%05d.bin", 100*id_dm_pos+2 );
sprintf( fnvx, "___ic_temp_%05d.bin", 100*id_dm_vel+0 );
sprintf( fnvy, "___ic_temp_%05d.bin", 100*id_dm_vel+1 );
sprintf( fnvz, "___ic_temp_%05d.bin", 100*id_dm_vel+2 );
sprintf( fnm, "___ic_temp_%05d.bin", 100*id_dm_mass );
std::ifstream
ifs1( fnx, std::ios::binary ),
ifs2( fny, std::ios::binary ),
ifs3( fnz, std::ios::binary );
const int
nptot = header_.npart[1]+header_.npart[5];
int
npleft = nptot,
n2read = std::min((int)block_buf_size_,npleft);
//... particle coordinates ..................................................
unsigned blk;
ifs1.read( (char *)&blk, sizeof(int) );
if( blk != nptot*sizeof(T_store) )
throw std::runtime_error("Internal consistency error in gadget2 output plug-in");
ifs2.read( (char *)&blk, sizeof(int) );
if( blk != nptot*sizeof(T_store) )
throw std::runtime_error("Internal consistency error in gadget2 output plug-in");
ifs3.read( (char *)&blk, sizeof(int) );
if( blk != nptot*sizeof(T_store) )
throw std::runtime_error("Internal consistency error in gadget2 output plug-in");
std::vector<T_store> adata3;
adata3.reserve( 3*block_buf_size_ );
T_store *tmp1, *tmp2, *tmp3;
tmp1 = new T_store[block_buf_size_];
tmp2 = new T_store[block_buf_size_];
tmp3 = new T_store[block_buf_size_];
blksize = 3*nptot*sizeof(T_store);
ofs_.write( (char *)&blksize, sizeof(int) );
while( n2read > 0 )
{
//ifs1.read( (char*)&tmp1[0], n2read*sizeof(T_store) );
ifs1.read( reinterpret_cast<char*>(&tmp1[0]), n2read*sizeof(T_store) );
ifs2.read( reinterpret_cast<char*>(&tmp2[0]), n2read*sizeof(T_store) );
ifs3.read( reinterpret_cast<char*>(&tmp3[0]), n2read*sizeof(T_store) );
for( int i=0; i<n2read; ++i )
{
adata3.push_back( tmp1[i] );
adata3.push_back( tmp2[i] );
adata3.push_back( tmp3[i] );
}
ofs_.write( reinterpret_cast<char*>(&adata3[0]), 3*n2read*sizeof(T_store) );
adata3.clear();
npleft -= n2read;
n2read = std::min( (int)block_buf_size_,npleft );
}
ofs_.write( reinterpret_cast<char*>(&blksize), sizeof(int) );
remove( fnx );
remove( fny );
remove( fnz );
//... particle velocities ..................................................
ifs1.close(); ifs1.open( fnvx, std::ios::binary );
ifs2.close(); ifs2.open( fnvy, std::ios::binary );
ifs3.close(); ifs3.open( fnvz, std::ios::binary );
ifs1.read( (char *)&blk, sizeof(int) );
if( blk != nptot*sizeof(T_store)){
delete[] tmp1;
delete[] tmp2;
delete[] tmp3;
throw std::runtime_error("Internal consistency error in gadget2 output plug-in");
}
ifs2.read( (char *)&blk, sizeof(int) );
if( blk != nptot*sizeof(T_store)){
delete[] tmp1;
delete[] tmp2;
delete[] tmp3;
throw std::runtime_error("Internal consistency error in gadget2 output plug-in");
}
ifs3.read( (char *)&blk, sizeof(int) );
if( blk != nptot*sizeof(T_store)){
delete[] tmp1;
delete[] tmp2;
delete[] tmp3;
throw std::runtime_error("Internal consistency error in gadget2 output plug-in");
}
npleft = nptot;
n2read = std::min((int)block_buf_size_,npleft);
ofs_.write( reinterpret_cast<char*>(&blksize), sizeof(int) );
while( n2read > 0 )
{
ifs1.read( reinterpret_cast<char*>(&tmp1[0]), n2read*sizeof(T_store) );
ifs2.read( reinterpret_cast<char*>(&tmp2[0]), n2read*sizeof(T_store) );
ifs3.read( reinterpret_cast<char*>(&tmp3[0]), n2read*sizeof(T_store) );
for( int i=0; i<n2read; ++i )
{
adata3.push_back( tmp1[i] );
adata3.push_back( tmp2[i] );
adata3.push_back( tmp3[i] );
}
ofs_.write( reinterpret_cast<char*>(&adata3[0]), 3*n2read*sizeof(T_store) );
adata3.clear();
npleft -= n2read;
n2read = std::min( (int)block_buf_size_,npleft );
}
ofs_.write( reinterpret_cast<char*>(&blksize), sizeof(int) );
remove( fnvx );
remove( fnvy );
remove( fnvz );
delete[] tmp2;
delete[] tmp3;
//... particle IDs ..........................................................
std::vector<unsigned> ids(block_buf_size_,0);
unsigned idcount = 0;
npleft = nptot;
n2read = std::min((int)block_buf_size_,npleft);
blksize = sizeof(unsigned)*nptot;
//... generate contiguous IDs and store in file .......................//
ofs_.write( reinterpret_cast<char*>(&blksize), sizeof(int) );
while( n2read > 0 )
{
for( int i=0; i<n2read; ++i )
ids[i] = idcount++;
ofs_.write( reinterpret_cast<char*>(&ids[0]), n2read*sizeof(unsigned) );
ids.clear();
npleft -= n2read;
n2read = std::min( (int)block_buf_size_,npleft );
}
ofs_.write( reinterpret_cast<char*>(&blksize), sizeof(int) );
//... particle masses .......................................................
if( bmultimass_ && bmorethan2bnd_ )
{
unsigned npcoarse = header_.npart[5];
ifs1.close();
ifs1.open( fnm, std::ios::binary );
if( !ifs1.good() )
throw std::runtime_error("Could not open buffer file in gadget2 output plug-in");
ifs1.read( (char *)&blk, sizeof(int) );
if( blk != npcoarse*sizeof(T_store)){
delete[] tmp1;
throw std::runtime_error("Internal consistency error in gadget2 output plug-in");
}
npleft = npcoarse;
n2read = std::min((int)block_buf_size_,npleft);
blksize = npcoarse*sizeof(T_store);
ofs_.write( reinterpret_cast<char*>(&blksize), sizeof(int) );
while( n2read > 0 )
{
ifs1.read( reinterpret_cast<char*>(&tmp1[0]), n2read*sizeof(T_store) );
ofs_.write( reinterpret_cast<char*>(&tmp1[0]), n2read*sizeof(T_store) );
npleft -= n2read;
n2read = std::min( (int)block_buf_size_,npleft );
}
ofs_.write( reinterpret_cast<char*>(&blksize), sizeof(int) );
remove( fnm );
}
delete[] tmp1;
ofs_.flush();
}
public:
gadget2_output_plugin( config_file& cf )//std::string afname, Cosmology cosm, Parameters param, unsigned block_buf_size = 100000 )
: output_plugin( cf ), ofs_( fname_.c_str(), std::ios::binary|std::ios::trunc )
{
block_buf_size_ = cf_.getValueSafe<unsigned>("output","gadget_blksize",100000);
//bbndparticles_ = !cf_.getValueSafe<bool>("output","gadget_nobndpart",false);
bmorethan2bnd_ = false;
if( levelmax_ > levelmin_ +1)
bmorethan2bnd_ = true;
bmultimass_ = true;
if( levelmax_ == levelmin_ )
bmultimass_ = false;
for( int i=0; i<6; ++i )
{
header_.npart[i] = 0;
header_.npartTotal[i] = 0;
header_.npartTotalHighWord[i] = 0;
header_.mass[i] = 0.0;
}
//... set time ......................................................
header_.redshift = cf.getValue<double>("setup","zstart");
header_.time = 1.0/(1.0+header_.redshift);
//... SF flags
header_.flag_sfr = 0;
header_.flag_feedback = 0;
header_.flag_cooling = 0;
//...
header_.num_files = 1;
header_.BoxSize = cf.getValue<double>("setup","boxlength");
header_.Omega0 = cf.getValue<double>("cosmology","Omega_m");
header_.OmegaLambda = cf.getValue<double>("cosmology","Omega_L");
header_.HubbleParam = cf.getValue<double>("cosmology","H0");
header_.flag_stellarage = 0;
header_.flag_metals = 0;
header_.flag_entropy_instead_u = 0;
}
void write_dm_mass( const grid_hierarchy& gh )
{
double rhoc = 27.7519737; // h^2 1e10 M_sol / Mpc^3
header_.mass[1] = header_.Omega0 * rhoc * pow(header_.BoxSize,3.)/pow(2,3*levelmax_);
if( bmorethan2bnd_ )
{
std::vector<T_store> temp_dat;
temp_dat.clear();
for( int ilevel=gh.levelmax()-1; ilevel>=(int)gh.levelmin(); --ilevel )
{
double pmass = header_.Omega0 * rhoc * pow(header_.BoxSize,3.)/pow(2,3*ilevel);
for( unsigned i=0; i<gh.get_grid(ilevel)->size(0); ++i )
for( unsigned j=0; j<gh.get_grid(ilevel)->size(1); ++j )
for( unsigned k=0; k<gh.get_grid(ilevel)->size(2); ++k )
if( ! gh.is_refined(ilevel,i,j,k) )
temp_dat.push_back( pmass );
}
char temp_fname[256];
sprintf( temp_fname, "___ic_temp_%05d.bin", 100*id_dm_mass );
std::ofstream ofs_temp( temp_fname, std::ios::binary|std::ios::trunc );
int blksize = sizeof(T_store)*temp_dat.size();
ofs_temp.write( (char *)&blksize, sizeof(int) );
ofs_temp.write( (char*)&temp_dat[0], blksize );
ofs_temp.write( (char *)&blksize, sizeof(int) );
}
else
{
header_.mass[5] = header_.Omega0 * rhoc * pow(header_.BoxSize,3.)/pow(2,3*levelmin_);
}
}
void write_dm_position( int coord, const grid_hierarchy& gh )
{
//... count number of leaf cells ...//
unsigned npcoarse = 0, npfine = 0;
npfine = gh.count_leaf_cells(gh.levelmax(), gh.levelmax());
if( bmultimass_ )
npcoarse = gh.count_leaf_cells(gh.levelmin(), gh.levelmax()-1);
//... determine if we need to shift the coordinates back
double *shift = NULL;
if( cf_.getValueSafe<bool>("output","shift_back",false ) )
{
if( coord == 0 )
std::cout << " - gadget2 output plug-in will shift particle positions back...\n";
double h = 1.0/pow(2,levelmin_);
shift = new double[3];
shift[0] = -(double)cf_.getValue<int>( "setup", "shift_x" )*h;
shift[1] = -(double)cf_.getValue<int>( "setup", "shift_y" )*h;
shift[2] = -(double)cf_.getValue<int>( "setup", "shift_z" )*h;
}
//...
header_.npart[1] = npfine;
header_.npart[5] = npcoarse;
header_.npartTotal[1] = npfine;
header_.npartTotal[5] = npcoarse;
header_.npartTotalHighWord[1] = 0;
header_.npartTotalHighWord[5] = 0;
//... collect displacements and convert to absolute coordinates with correct
//... units
std::vector<T_store> temp_data;
temp_data.reserve( npfine );
double xfac = header_.BoxSize;
for( int ilevel=gh.levelmax(); ilevel>=(int)gh.levelmin(); --ilevel )
for( unsigned i=0; i<gh.get_grid(ilevel)->size(0); ++i )
for( unsigned j=0; j<gh.get_grid(ilevel)->size(1); ++j )
for( unsigned k=0; k<gh.get_grid(ilevel)->size(2); ++k )
if( ! gh.is_refined(ilevel,i,j,k) )
{
double xx[3];
gh.cell_pos(ilevel, i, j, k, xx);
if( shift != NULL )
xx[coord] += shift[coord];
xx[coord] = fmod( (xx[coord]+(*gh.get_grid(ilevel))(i,j,k))*xfac + header_.BoxSize, header_.BoxSize );
temp_data.push_back( xx[coord] );
}
//... dump to temporary file
char temp_fname[256];
sprintf( temp_fname, "___ic_temp_%05d.bin", 100*id_dm_pos+coord );
std::ofstream ofs_temp( temp_fname, std::ios::binary|std::ios::trunc );
int blksize = sizeof(T_store)*temp_data.size();
ofs_temp.write( (char *)&blksize, sizeof(int) );
ofs_temp.write( (char*)&temp_data[0], blksize );
ofs_temp.write( (char *)&blksize, sizeof(int) );
ofs_temp.close();
if( shift != NULL )
delete[] shift;
}
void write_dm_velocity( int coord, const grid_hierarchy& gh )
{
//... count number of leaf cells ...//
unsigned npcoarse = 0, npfine = 0;
npfine = gh.count_leaf_cells(gh.levelmax(), gh.levelmax());
if( bmultimass_ )
npcoarse = gh.count_leaf_cells(gh.levelmin(), gh.levelmax()-1);
header_.npart[1] = npfine;
header_.npart[5] = npcoarse;
header_.npartTotal[1] = npfine;
header_.npartTotal[5] = npcoarse;
header_.npartTotalHighWord[1] = 0;
header_.npartTotalHighWord[5] = 0;
//... collect displacements and convert to absolute coordinates with correct
//... units
std::vector<T_store> temp_data;
temp_data.reserve( npfine+npcoarse );
float isqrta = 1.0f/sqrt(header_.time);
//float vfac = cosm_.astart/100.0*isqrta*param_.boxlength;
float vfac = isqrta*header_.BoxSize;
for( int ilevel=levelmax_; ilevel>=(int)levelmin_; --ilevel )
for( unsigned i=0; i<gh.get_grid(ilevel)->size(0); ++i )
for( unsigned j=0; j<gh.get_grid(ilevel)->size(1); ++j )
for( unsigned k=0; k<gh.get_grid(ilevel)->size(2); ++k )
if( ! gh.is_refined(ilevel,i,j,k) )
temp_data.push_back( (*gh.get_grid(ilevel))(i,j,k) * vfac );
//... dump to temporary file
char temp_fname[256];
sprintf( temp_fname, "___ic_temp_%05d.bin", 100*id_dm_vel+coord );
std::ofstream ofs_temp( temp_fname, std::ios::binary|std::ios::trunc );
int blksize = sizeof(T_store)*temp_data.size();
ofs_temp.write( (char *)&blksize, sizeof(int) );
ofs_temp.write( (char*)&temp_data[0], blksize );
ofs_temp.write( (char *)&blksize, sizeof(int) );
ofs_temp.close();
}
void write_dm_density( const grid_hierarchy& gh )
{
//... we don't care about DM density for Gadget
}
void write_dm_potential( const grid_hierarchy& gh )
{ }
void write_gas_potential( const grid_hierarchy& gh )
{ }
//... write data for gas -- don't do this
void write_gas_velocity( int coord, const grid_hierarchy& gh )
{
std::cout << " - WARNING: Gadget-2 output plug-in does not support baryons yet!\n"
<< " Baryon data is not written to file!" << std::endl;
}
void write_gas_position( int coord, const grid_hierarchy& gh )
{
std::cout << " - WARNING: Gadget-2 output plug-in does not support baryons yet!\n"
<< " Baryon data is not written to file!" << std::endl;
}
void write_gas_density( const grid_hierarchy& gh )
{
std::cout << " - WARNING: Gadget-2 output plug-in does not support baryons yet!\n"
<< " Baryon data is not written to file!" << std::endl;
}
void finalize( void )
{
this->assemble_gadget_file();
}
};
namespace{
output_plugin_creator_concrete< gadget2_output_plugin<float> > creator1("gadget2");
#ifndef SINGLE_PRECISION
output_plugin_creator_concrete< gadget2_output_plugin<double> > creator2("gadget2_double");
#endif
}

192
plugins/output_generic.cc Normal file
View file

@ -0,0 +1,192 @@
/*
output_generic.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifdef HAVE_HDF5
#include "output.hh"
#include "HDF_IO.hh"
class generic_output_plugin : public output_plugin
{
protected:
using output_plugin::cf_;
template< typename Tt >
void write2HDF5( std::string fname, std::string dname, const MeshvarBnd<Tt>& data )
{
int nres = data.size(0), nb = data.m_nbnd;
std::vector<Tt> vdata;
vdata.reserve((unsigned)pow(nres+2*nb,3));
for(int i=-nb; i<nres+nb; ++i )
for(int j=-nb; j<nres+nb; ++j )
for(int k=-nb; k<nres+nb; ++k )
vdata.push_back( data(i,j,k) );
unsigned nd[3] = { nres+2*nb,nres+2*nb,nres+2*nb };
HDFWriteDataset3D( fname, dname, nd, vdata);
}
public:
generic_output_plugin( config_file& cf )//std::string fname, Cosmology cosm, Parameters param )
: output_plugin( cf )//fname, cosm, param )
{
HDFCreateFile(fname_);
HDFCreateGroup(fname_, "header");
HDFWriteDataset(fname_,"/header/grid_off_x",offx_);
HDFWriteDataset(fname_,"/header/grid_off_y",offy_);
HDFWriteDataset(fname_,"/header/grid_off_z",offz_);
HDFWriteDataset(fname_,"/header/grid_len_x",sizex_);
HDFWriteDataset(fname_,"/header/grid_len_y",sizey_);
HDFWriteDataset(fname_,"/header/grid_len_z",sizez_);
HDFWriteGroupAttribute(fname_, "header", "levelmin", levelmin_ );
HDFWriteGroupAttribute(fname_, "header", "levelmax", levelmax_ );
}
~generic_output_plugin()
{ }
void write_dm_mass( const grid_hierarchy& gh )
{ }
void write_dm_velocity( int coord, const grid_hierarchy& gh )
{
char sstr[128];
for( unsigned ilevel=0; ilevel<=levelmax_; ++ilevel )
{
if( coord == 0 )
sprintf(sstr,"level_%03d_DM_vx",ilevel);
else if( coord == 1 )
sprintf(sstr,"level_%03d_DM_vy",ilevel);
else if( coord == 2 )
sprintf(sstr,"level_%03d_DM_vz",ilevel);
write2HDF5( fname_, sstr, *gh.get_grid(ilevel) );
}
}
void write_dm_position( int coord, const grid_hierarchy& gh )
{
char sstr[128];
for( unsigned ilevel=0; ilevel<=levelmax_; ++ilevel )
{
if( coord == 0 )
sprintf(sstr,"level_%03d_DM_dx",ilevel);
else if( coord == 1 )
sprintf(sstr,"level_%03d_DM_dy",ilevel);
else if( coord == 2 )
sprintf(sstr,"level_%03d_DM_dz",ilevel);
write2HDF5( fname_, sstr, *gh.get_grid(ilevel) );
}
}
void write_dm_density( const grid_hierarchy& gh )
{
char sstr[128];
for( unsigned ilevel=0; ilevel<=levelmax_; ++ilevel )
{
sprintf(sstr,"level_%03d_DM_rho",ilevel);
write2HDF5( fname_, sstr, *gh.get_grid(ilevel) );
}
}
void write_dm_potential( const grid_hierarchy& gh )
{
char sstr[128];
for( unsigned ilevel=0; ilevel<=levelmax_; ++ilevel )
{
sprintf(sstr,"level_%03d_DM_potential",ilevel);
write2HDF5( fname_, sstr, *gh.get_grid(ilevel) );
}
}
void write_gas_potential( const grid_hierarchy& gh )
{
char sstr[128];
for( unsigned ilevel=0; ilevel<=levelmax_; ++ilevel )
{
sprintf(sstr,"level_%03d_BA_potential",ilevel);
write2HDF5( fname_, sstr, *gh.get_grid(ilevel) );
}
}
void write_gas_velocity( int coord, const grid_hierarchy& gh )
{
char sstr[128];
for( unsigned ilevel=0; ilevel<=levelmax_; ++ilevel )
{
if( coord == 0 )
sprintf(sstr,"level_%03d_BA_vx",ilevel);
else if( coord == 1 )
sprintf(sstr,"level_%03d_BA_vy",ilevel);
else if( coord == 2 )
sprintf(sstr,"level_%03d_BA_vz",ilevel);
write2HDF5( fname_, sstr, *gh.get_grid(ilevel) );
}
}
void write_gas_position( int coord, const grid_hierarchy& gh )
{ }
void write_gas_density( const grid_hierarchy& gh )
{
char sstr[128];
for( unsigned ilevel=0; ilevel<=levelmax_; ++ilevel )
{
sprintf(sstr,"level_%03d_BA_rho",ilevel);
write2HDF5( fname_, sstr, *gh.get_grid(ilevel) );
}
}
void finalize( void )
{ }
};
namespace{
output_plugin_creator_concrete< generic_output_plugin > creator("generic");
}
#endif

325
plugins/output_grafic2.cc Normal file
View file

@ -0,0 +1,325 @@
/*
output_grafic2.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include <sys/types.h>
#include <sys/stat.h>
#include <fstream>
#include "output.hh"
//! Implementation of class grafic2_output_plugin
/*!
This class implements a grafic-2 (cf. Bertschinger 2001) compatible
output format. With some RAMSES extras.
*/
class grafic2_output_plugin : public output_plugin
{
protected:
typedef struct{
int n1, n2, n3;
float dxini0;
float xoff10,xoff20,xoff30;
float astart0,omega_m0,omega_l0,h00;
}header;
bool bhavehydro_;
void write_file_header( std::ofstream& ofs, unsigned ilevel, const grid_hierarchy& gh )
{
header loc_head;
double
boxlength = cf_.getValue<double>("setup","boxlength"),
H0 = cf_.getValue<double>("cosmology","H0"),
zstart = cf_.getValue<double>("setup","zstart"),
astart = 1.0/(1.0+zstart),
omegam = cf_.getValue<double>("cosmology","Omega_m"),
omegaL = cf_.getValue<double>("cosmology","Omega_L");
loc_head.n1 = gh.get_grid(ilevel)->size(0);
loc_head.n2 = gh.get_grid(ilevel)->size(1);
loc_head.n3 = gh.get_grid(ilevel)->size(2);
loc_head.dxini0 = boxlength / (H0*0.01) / pow(2.0,ilevel);
loc_head.xoff10 = gh.offset_abs(ilevel,0) * loc_head.dxini0;
loc_head.xoff20 = gh.offset_abs(ilevel,1) * loc_head.dxini0;
loc_head.xoff30 = gh.offset_abs(ilevel,2) * loc_head.dxini0;
loc_head.astart0 = astart;
loc_head.omega_m0 = omegam;
loc_head.omega_l0 = omegaL;
loc_head.h00 = H0;
int blksz = sizeof(header);
ofs.write( reinterpret_cast<char*> (&blksz), sizeof(int) );
ofs.write( reinterpret_cast<char*> (&loc_head), blksz );
ofs.write( reinterpret_cast<char*> (&blksz), sizeof(int) );
}
void write_sliced_array( std::ofstream& ofs, unsigned ilevel, const grid_hierarchy& gh, float fac = 1.0f )
{
unsigned n1,n2,n3;
n1 = gh.get_grid(ilevel)->size(0);
n2 = gh.get_grid(ilevel)->size(1);
n3 = gh.get_grid(ilevel)->size(2);
std::vector<float> data(n1*n2,0.0f);
for( unsigned i=0; i<n1; ++i )
{
data.clear();
for( unsigned j=0; j<n2; ++j )
for( unsigned k=0; k<n3; ++k )
data[j*n3+k] = (*gh.get_grid(ilevel))(k,j,i) * fac;
unsigned blksize = n2*n3*sizeof(float);
ofs.write( reinterpret_cast<char*> (&blksize), sizeof(unsigned) );
ofs.write( reinterpret_cast<char*> (&data[0]), blksize );
ofs.write( reinterpret_cast<char*> (&blksize), sizeof(unsigned) );
}
}
void write_ramses_namelist( const grid_hierarchy& gh )
{
//... also write the refinement options to a dummy namelist file
char ff[256];
sprintf(ff,"%s/ramses.nml",fname_.c_str() );
std::ofstream ofst(ff,std::ios::trunc);
ofst
<< "&INIT_PARAMS\n"
<< "filetype=\'grafic\'\n";
for( unsigned i=gh.levelmin();i<=gh.levelmax(); ++i)
{
sprintf(ff,"initfile(%d)=\'%s/level_%03d\'\n",i-gh.levelmin()+1,fname_.c_str(), i );
ofst << std::string(ff);
}
ofst << "/\n\n";
double xc,yc,zc,l;
ofst
<< "&AMR_PARAMS\n"
<< "levelmin=" << gh.levelmin() << "\n"
<< "levelmax=" << gh.levelmax() << "\n"
<< "ngridtot=2000000\n"
<< "nparttot=3000000\n"
<< "nexpand=1\n/\n\n";
if( gh.levelmax() > gh.levelmin() )
{
l = pow(2.0,gh.levelmin()+1);
xc = ((double)gh.offset_abs(gh.levelmin()+1,0)+0.5*(double)gh.size(gh.levelmin()+1,0))/l;
yc = ((double)gh.offset_abs(gh.levelmin()+1,1)+0.5*(double)gh.size(gh.levelmin()+1,1))/l;
zc = ((double)gh.offset_abs(gh.levelmin()+1,2)+0.5*(double)gh.size(gh.levelmin()+1,2))/l;
ofst << "&REFINE_PARAMS\n"
<< "m_refine=0.";
for( unsigned i=gh.levelmin()+1;i<gh.levelmax(); ++i)
ofst << ",0.";
ofst << "\nx_refine="<< std::setw(12) << xc;
for( unsigned i=gh.levelmin()+1;i<gh.levelmax(); ++i)
{
l = pow(2.0,i+1);
xc = ((double)gh.offset_abs(i+1,0)+0.5*(double)gh.size(i+1,0))/l;
ofst << ","<< std::setw(12) << xc;
}
ofst << "\ny_refine="<< std::setw(12)<< yc;
for( unsigned i=gh.levelmin()+1;i<gh.levelmax(); ++i)
{
l = pow(2.0,i+1);
yc = ((double)gh.offset_abs(i+1,1)+0.5*(double)gh.size(i+1,1))/l;
ofst << ","<< std::setw(12) << yc;
}
ofst << "\nz_refine="<< std::setw(12) << zc;
for( unsigned i=gh.levelmin()+1;i<gh.levelmax(); ++i)
{
l = pow(2.0,i+1);
zc = ((double)gh.offset_abs(i+1,2)+0.5*(double)gh.size(i+1,2))/l;
ofst << ","<< std::setw(12) << zc;
}
ofst << "\nr_refine=";
for(unsigned i=gh.levelmin();i<gh.levelmax(); ++i )
{
double r = (gh.size(i+1,0)-4.0)/pow(2.0,i+1);
if( i==gh.levelmin() )
ofst << std::setw(12) << r;
else
ofst << "," << std::setw(12) << r;
}
ofst << "\nexp_refine=10.0";
for( unsigned i=gh.levelmin()+1;i<gh.levelmax(); ++i)
ofst << ",10.0";
ofst << "\n/\n";
}
sprintf(ff,"%s/ramses.nml",fname_.c_str() );
std::cout << " - The grafic2 output plug-in wrote the grid data to a partial\n"
<< " RAMSES namelist file \'" << ff << "\'\n";
}
public:
grafic2_output_plugin( config_file& cf )
: output_plugin( cf )
{
// create directory structure
remove( fname_.c_str() );
mkdir( fname_.c_str(), 0777 );
for(unsigned ilevel=levelmin_; ilevel<=levelmax_; ++ilevel )
{
char fp[256];
sprintf(fp,"%s/level_%03d",fname_.c_str(), ilevel );
mkdir( fp, 0777 );
}
bhavehydro_ = cf.getValue<bool>("setup","baryons");
}
/*~grafic2_output_plugin()
{ }*/
void write_dm_position( int coord, const grid_hierarchy& gh )
{
double
boxlength = cf_.getValue<double>("setup","boxlength");
// H0 = cf_.getValue<double>("cosmology","H0");
for(unsigned ilevel=levelmin_; ilevel<=levelmax_; ++ilevel )
{
char ff[256];
sprintf(ff,"%s/level_%03d/ic_posc%c",fname_.c_str(), ilevel, (char)('x'+coord) );
std::ofstream ofs(ff,std::ios::binary|std::ios::trunc);
write_file_header( ofs, ilevel, gh );
write_sliced_array( ofs, ilevel, gh, boxlength );
}
}
void write_dm_velocity( int coord, const grid_hierarchy& gh )
{
double
boxlength = cf_.getValue<double>("setup","boxlength");
for(unsigned ilevel=levelmin_; ilevel<=levelmax_; ++ilevel )
{
char ff[256];
sprintf(ff,"%s/level_%03d/ic_velc%c",fname_.c_str(), ilevel, (char)('x'+coord) );
std::ofstream ofs(ff,std::ios::binary|std::ios::trunc);
write_file_header( ofs, ilevel, gh );
write_sliced_array( ofs, ilevel, gh, boxlength );
}
}
void write_gas_velocity( int coord, const grid_hierarchy& gh )
{
double
boxlength = cf_.getValue<double>("setup","boxlength");
for(unsigned ilevel=levelmin_; ilevel<=levelmax_; ++ilevel )
{
char ff[256];
sprintf(ff,"%s/level_%03d/ic_velb%c",fname_.c_str(), ilevel, (char)('x'+coord) );
std::ofstream ofs(ff,std::ios::binary|std::ios::trunc);
write_file_header( ofs, ilevel, gh );
write_sliced_array( ofs, ilevel, gh, boxlength );
}
}
void write_gas_density( const grid_hierarchy& gh )
{
for(unsigned ilevel=levelmin_; ilevel<=levelmax_; ++ilevel )
{
char ff[256];
sprintf(ff,"%s/level_%03d/ic_deltab",fname_.c_str(), ilevel );
std::ofstream ofs(ff,std::ios::binary|std::ios::trunc);
write_file_header( ofs, ilevel, gh );
write_sliced_array( ofs, ilevel, gh );
}
}
void write_dm_density( const grid_hierarchy& gh )
{
if(! bhavehydro_ )
write_gas_density(gh);
if( cf_.getValueSafe<bool>("output","ramses_nml",true) )
write_ramses_namelist(gh);
}
void write_dm_mass( const grid_hierarchy& gh )
{ /* do nothing, not used... */ }
void write_dm_potential( const grid_hierarchy& gh )
{ /* do nothing, not used... */ }
void write_gas_potential( const grid_hierarchy& gh )
{ /* do nothing, not used... */ }
void write_gas_position( int coord, const grid_hierarchy& gh )
{ /* do nothing, not used... */ }
void finalize( void )
{ }
};
namespace{
output_plugin_creator_concrete<grafic2_output_plugin> creator("grafic2");
}

95
plugins/transfer_bbks.cc Normal file
View file

@ -0,0 +1,95 @@
/*
transfer_bbks.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "transfer_function.hh"
//! Implementation of class TransferFunction_BBKS for the BBKS transfer function
/*!
This class implements the analytical fit to the matter transfer
function by Bardeen, Bond, Kaiser & Szalay (BBKS).
( see Bardeen et al. (1986) )
*/
class transfer_bbks_plugin : public transfer_function_plugin{
private:
double m_Gamma;
public:
//! Constructor
/*!
\param aCosm Structure of type Cosmology carrying the cosmological parameters
\param bSugiyama flag whether the Sugiyama (1995) correction shall be applied (default=true)
*/
transfer_bbks_plugin( config_file& cf )
: transfer_function_plugin( cf )
{
double Omega0 = cosmo_.Omega_m;
double FreeGamma = -1.0;
bool bSugiyama(true);
try{
bSugiyama= pcf_->getValue<bool>( "cosmology", "sugiyama_corr" );
}catch(...){
throw std::runtime_error("Error in \'tranfer_bbks_plugin\': need to specify \'[cosmology]/sugiyama_corr = [true/false]");
}
FreeGamma = pcf_->getValueSafe<double>( "cosmology", "gamma", FreeGamma );
if( FreeGamma <= 0.0 ){
m_Gamma = Omega0*0.01*cosmo_.H0;
if( bSugiyama )
m_Gamma *= exp(-cosmo_.Omega_b*(1.0+sqrt(2.0*0.01*cosmo_.H0)/Omega0));
}else
m_Gamma = FreeGamma;
tf_distinct_ = false;
}
//! computes the value of the BBKS transfer function for mode k (in h/Mpc)
inline double compute( double k, tf_type type ){
double q, f1, f2;
q = k/(m_Gamma);
f1 = log(1.0 + 2.34*q)/(2.34*q);
f2 = 1.0 + q*(3.89 + q*(259.21 + q*(162.771336 + q*2027.16958081)));
return f1/sqrt(sqrt(f2));
}
inline double get_kmin( void ){
return 1e-4;
}
inline double get_kmax( void ){
return 1.e4;
}
};
namespace{
transfer_function_plugin_creator_concrete< transfer_bbks_plugin > creator("bbks");
}

167
plugins/transfer_camb.cc Normal file
View file

@ -0,0 +1,167 @@
/*
transfer_camb.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "transfer_function.hh"
class transfer_CAMB_plugin : public transfer_function_plugin
{
private:
//Cosmology m_Cosmology;
std::string m_filename_Pk, m_filename_Tk;
std::vector<double> m_tab_k, m_tab_Tk_tot, m_tab_Tk_cdm, m_tab_Tk_baryon;
Spline_interp *m_psinterp;
gsl_interp_accel *acc_tot, *acc_cdm, *acc_baryon;
gsl_spline *spline_tot, *spline_cdm, *spline_baryon;
void read_table( void ){
#ifdef WITH_MPI
if( MPI::COMM_WORLD.Get_rank() == 0 ){
#endif
std::cerr
<< " - reading tabulated transfer function data from file \n"
<< " \'" << m_filename_Tk << "\'\n";
std::string line;
std::ifstream ifs( m_filename_Tk.c_str() );
m_tab_k.clear();
m_tab_Tk_tot.clear();
m_tab_Tk_cdm.clear();
m_tab_Tk_baryon.clear();
while( !ifs.eof() ){
getline(ifs,line);
if(ifs.eof()) break;
std::stringstream ss(line);
double k, Tkc, Tkb, Tkg, Tkr, Tknu, Tktot;
ss >> k;
ss >> Tkc;
ss >> Tkb;
ss >> Tkg;
ss >> Tkr;
ss >> Tknu;
ss >> Tktot;
m_tab_k.push_back( log10(k) );
m_tab_Tk_tot.push_back( log10(Tktot) );
m_tab_Tk_baryon.push_back( log10(Tkb) );
m_tab_Tk_cdm.push_back( log10(Tkc) );
}
ifs.close();
#ifdef WITH_MPI
}
unsigned n=m_tab_k.size();
MPI::COMM_WORLD.Bcast( &n, 1, MPI_UNSIGNED, 0 );
if( MPI::COMM_WORLD.Get_rank() > 0 ){
m_tab_k.assign(n,0);
m_tab_Tk_tot.assign(n,0);
m_tab_Tk_cdm.assign(n,0);
m_tab_Tk_baryon.assign(n,0);
}
MPI::COMM_WORLD.Bcast( &m_tab_k[0], n, MPI_DOUBLE, 0 );
MPI::COMM_WORLD.Bcast( &m_tab_Tk_tot[0], n, MPI_DOUBLE, 0 );
MPI::COMM_WORLD.Bcast( &m_tab_Tk_cdm[0], n, MPI_DOUBLE, 0 );
MPI::COMM_WORLD.Bcast( &m_tab_Tk_baryon[0], n, MPI_DOUBLE, 0 );
#endif
}
public:
transfer_CAMB_plugin( config_file& cf )//Cosmology aCosm, std::string filename_Tk, TFtype iwhich )
: transfer_function_plugin( cf )//, m_filename_Tk( filename_Tk ), m_psinterp( NULL )
{
m_filename_Tk = pcf_->getValue<std::string>("cosmology","transfer_file");
read_table( );
acc_tot = gsl_interp_accel_alloc();
acc_cdm = gsl_interp_accel_alloc();
acc_baryon = gsl_interp_accel_alloc();
spline_tot = gsl_spline_alloc( gsl_interp_akima, m_tab_k.size() );
spline_cdm = gsl_spline_alloc( gsl_interp_akima, m_tab_k.size() );
spline_baryon = gsl_spline_alloc( gsl_interp_akima, m_tab_k.size() );
gsl_spline_init (spline_tot, &m_tab_k[0], &m_tab_Tk_tot[0], m_tab_k.size() );
gsl_spline_init (spline_cdm, &m_tab_k[0], &m_tab_Tk_cdm[0], m_tab_k.size() );
gsl_spline_init (spline_baryon, &m_tab_k[0], &m_tab_Tk_baryon[0], m_tab_k.size() );
tf_distinct_ = true;
}
~transfer_CAMB_plugin()
{
gsl_spline_free (spline_tot);
gsl_spline_free (spline_cdm);
gsl_spline_free (spline_baryon);
gsl_interp_accel_free (acc_tot);
gsl_interp_accel_free (acc_cdm);
gsl_interp_accel_free (acc_baryon);
}
inline double compute( double k, tf_type type ){
if( type == total )
return pow(10.0, gsl_spline_eval (spline_tot, log10(k), acc_tot) );
if( type == cdm )
return pow(10.0, gsl_spline_eval (spline_cdm, log10(k), acc_cdm) );
return pow(10.0, gsl_spline_eval (spline_baryon, log10(k), acc_baryon) );
}
inline double get_kmin( void ){
return pow(10.0,m_tab_k[1]);
}
inline double get_kmax( void ){
return pow(10.0,m_tab_k[m_tab_k.size()-2]);
}
};
namespace{
transfer_function_plugin_creator_concrete< transfer_CAMB_plugin > creator("camb_file");
}

View file

@ -0,0 +1,218 @@
/*
transfer_eisenstein.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "transfer_function.hh"
//! Implementation of abstract base class TransferFunction for the Eisenstein & Hu transfer function
/*!
This class implements the analytical fit to the matter transfer
function by Eisenstein & Hu (1999). In fact it is their code.
*/
class transfer_eisenstein_plugin : public transfer_function_plugin
{
protected:
using transfer_function_plugin::cosmo_;
//Cosmology m_Cosmology;
double m_h0;
double 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 */
//! private member function: sets internal quantities for Eisenstein & Hu fitting
void TFset_parameters(double omega0hh, double f_baryon, double 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. */
{
double z_drag_b1, z_drag_b2;
double 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((double)omhh,-0.419)*(1+0.607*pow((double)omhh,0.674));
z_drag_b2 = 0.238*pow((double)omhh,0.223);
z_drag = 1291*pow(omhh,0.251)/(1+0.659*pow((double)omhh,0.828))*
(1+z_drag_b1*pow((double)obhh,(double)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((double)obhh,0.52)*pow((double)omhh,0.73)*(1+pow((double)10.4*omhh,-0.95));
alpha_c_a1 = pow((double)46.9*omhh,0.670)*(1+pow(32.1*omhh,-0.532));
alpha_c_a2 = pow((double)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;
}
//! private member function: computes transfer function for mode k (k in Mpc)
inline double TFfit_onek(double k, double *tf_baryon, double *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. */
{
double T_c_ln_beta, T_c_ln_nobeta, T_c_C_alpha, T_c_C_noalpha;
double q, xx, xx_tilde;//, q_eff;
double T_c_f, T_c, s_tilde, T_b_T0, T_b, f_baryon, T_full;
//double T_0_L0, T_0_C0, T_0, gamma_eff;
//double 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;
}
public:
//! Constructor for Eisenstein & Hu fitting for transfer function
/*!
\param aCosm structure of type Cosmology carrying the cosmological parameters
\param Tcmb mean temperature of the CMB fluctuations (defaults to
Tcmb = 2.726 if not specified)
*/
transfer_eisenstein_plugin( config_file &cf )//Cosmology aCosm, double Tcmb = 2.726 )
: transfer_function_plugin(cf), m_h0( cosmo_.H0*0.01 )
{
double Tcmb = pcf_->getValueSafe("cosmology","Tcmb",2.726);
TFset_parameters( (cosmo_.Omega_m)*cosmo_.H0*cosmo_.H0*(0.01*0.01),
cosmo_.Omega_b/(cosmo_.Omega_m-cosmo_.Omega_b),//-aCosm.Omega_b),
Tcmb);
tf_distinct_ = false;
}
//! Computes the transfer function for k in Mpc/h by calling TFfit_onek
inline double compute( double k, tf_type type ){
double tfb, tfcdm, fb, fc; //, tfull
TFfit_onek( k*m_h0, &tfb, &tfcdm );
fb = cosmo_.Omega_b/(cosmo_.Omega_m);
fc = (cosmo_.Omega_m-cosmo_.Omega_b)/(cosmo_.Omega_m) ;
return fb*tfb+fc*tfcdm;
//return 1.0;
}
inline double get_kmin( void ){
return 1e-4;
}
inline double get_kmax( void ){
return 1.e4;
}
};
namespace{
transfer_function_plugin_creator_concrete< transfer_eisenstein_plugin > creator("eisenstein");
}

View file

@ -0,0 +1,64 @@
/*
tranfer_inflation.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "transfer_function.hh"
class transfer_inflation_plugin : public transfer_function_plugin
{
protected:
double ns2_;
public:
transfer_inflation_plugin( config_file& cf )
: transfer_function_plugin( cf )
{
ns2_ = 0.5*cf.getValue<double>("cosmology","nspec");
tf_distinct_ = true;
}
~transfer_inflation_plugin(){ };
double compute( double k, tf_type type=baryon)
{
return pow(k,ns2_);
}
double get_kmax( void )
{
return 1e10;
}
double get_kmin( void )
{
return 1e-30;
}
};
namespace{
transfer_function_plugin_creator_concrete< transfer_inflation_plugin > creator("inflation");
}

499
poisson.cc Normal file
View file

@ -0,0 +1,499 @@
/*
poisson.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/****** ABSTRACT FACTORY PATTERN IMPLEMENTATION *******/
#include "poisson.hh"
std::map< std::string, poisson_plugin_creator *>&
get_poisson_plugin_map()
{
static std::map< std::string, poisson_plugin_creator* > poisson_plugin_map;
return poisson_plugin_map;
}
void print_poisson_plugins()
{
std::map< std::string, poisson_plugin_creator *>& m = get_poisson_plugin_map();
std::map< std::string, poisson_plugin_creator *>::iterator it;
it = m.begin();
std::cout << " - Available poisson solver plug-ins:\n";
while( it!=m.end() )
{
if( (*it).second )
std::cout << "\t\'" << (*it).first << "\'\n";
++it;
}
}
/****** CALL IMPLEMENTATIONS OF POISSON SOLVER CLASSES ******/
#include "mg_solver.hh"
#include "fd_schemes.hh"
#ifdef SINGLE_PRECISION
typedef multigrid::solver< stencil_7P<float>, interp_O3_fluxcorr, mg_straight, float > poisson_solver_O2;
typedef multigrid::solver< stencil_13P<float>, interp_O5_fluxcorr, mg_straight, float > poisson_solver_O4;
typedef multigrid::solver< stencil_19P<float>, interp_O7_fluxcorr, mg_straight, float > poisson_solver_O6;
#else
typedef multigrid::solver< stencil_7P<double>, interp_O3_fluxcorr, mg_straight, double > poisson_solver_O2;
typedef multigrid::solver< stencil_13P<double>, interp_O5_fluxcorr, mg_straight, double > poisson_solver_O4;
typedef multigrid::solver< stencil_19P<double>, interp_O7_fluxcorr, mg_straight, double > poisson_solver_O6;
#endif
/**************************************************************************************/
/**************************************************************************************/
#pragma mark -
double multigrid_poisson_plugin::solve( grid_hierarchy& f, grid_hierarchy& u )
{
unsigned verbosity = cf_.getValueSafe<unsigned>("setup","verbosity",2);
if( verbosity > 0 )
std::cout << " - Invoking multi-grid Poisson solver..." << std::endl;
double acc = 1e-5, err;
std::string ps_smoother_name;
unsigned ps_presmooth, ps_postsmooth, order;
acc = cf_.getValueSafe<double>("poisson","accuracy",acc);
ps_presmooth = cf_.getValueSafe<unsigned>("poisson","pre_smooth",3);
ps_postsmooth = cf_.getValueSafe<unsigned>("poisson","post_smooth",3);
ps_smoother_name = cf_.getValueSafe<std::string>("poisson","smoother","gs");
order = cf_.getValueSafe<unsigned>( "setup", "laplace_order", 4 );
multigrid::opt::smtype ps_smtype = multigrid::opt::sm_gauss_seidel;
if ( ps_smoother_name == std::string("gs") )
ps_smtype = multigrid::opt::sm_gauss_seidel;
else if ( ps_smoother_name == std::string("jacobi") )
ps_smtype = multigrid::opt::sm_jacobi;
else if ( ps_smoother_name == std::string("sor") )
ps_smtype = multigrid::opt::sm_sor;
else
std::cerr << " - Warning: unknown smoother \'" << ps_smoother_name << "\' for multigrid solver!\n"
<< " reverting to \'gs\' (Gauss-Seidel)" << std::endl;
double tstart, tend;
tstart = omp_get_wtime();
//----- run Poisson solver -----//
if( order == 2 )
{
poisson_solver_O2 ps( f, ps_smtype, ps_presmooth, ps_postsmooth );
err = ps.solve( u, acc, true );
}
else if( order == 4 )
{
poisson_solver_O4 ps( f, ps_smtype, ps_presmooth, ps_postsmooth );
err = ps.solve( u, acc, true );
}
else if( order == 6 )
{
poisson_solver_O6 ps( f, ps_smtype, ps_presmooth, ps_postsmooth );
err = ps.solve( u, acc, true );
}
else
{
throw std::runtime_error("Invalid order specified for Laplace operator");
}
//------------------------------//
tend = omp_get_wtime();
if( verbosity > 1 )
std::cout << " - Poisson solver took " << tend-tstart << "s with " << omp_get_max_threads() << " threads." << std::endl;
return err;
}
double multigrid_poisson_plugin::gradient( int dir, grid_hierarchy& u, grid_hierarchy& Du )
{
Du = u;
unsigned order = cf_.getValueSafe<unsigned>( "setup", "grad_order", 4 );
switch( order )
{
case 2:
implementation().gradient_O2( dir, u, Du );
break;
case 4:
implementation().gradient_O4( dir, u, Du );
break;
case 6:
implementation().gradient_O6( dir, u, Du );
break;
default:
throw std::runtime_error("Invalid order specified for gradient operator!");
}
return 0.0;
}
void multigrid_poisson_plugin::implementation::gradient_O2( int dir, grid_hierarchy& u, grid_hierarchy& Du )
{
for( unsigned ilevel=u.levelmin(); ilevel<=u.levelmax(); ++ilevel )
{
double h = pow(2.0,ilevel);
meshvar_bnd *pvar = Du.get_grid(ilevel);
if( dir == 0 )
#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
(*pvar)(ix,iy,iz) = 0.5*((*u.get_grid(ilevel))(ix+1,iy,iz)-(*u.get_grid(ilevel))(ix-1,iy,iz))*h;
else if( dir == 1 )
#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
(*pvar)(ix,iy,iz) = 0.5*((*u.get_grid(ilevel))(ix,iy+1,iz)-(*u.get_grid(ilevel))(ix,iy-1,iz))*h;
else if( dir == 2 )
#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
(*pvar)(ix,iy,iz) = 0.5*((*u.get_grid(ilevel))(ix,iy,iz+1)-(*u.get_grid(ilevel))(ix,iy,iz-1))*h;
}
}
void multigrid_poisson_plugin::implementation::gradient_O4( int dir, grid_hierarchy& u, grid_hierarchy& Du )
{
for( unsigned ilevel=u.levelmin(); ilevel<=u.levelmax(); ++ilevel )
{
double h = pow(2.0,ilevel);
meshvar_bnd *pvar = Du.get_grid(ilevel);
h /= 12.0;
if( dir == 0 )
#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
(*pvar)(ix,iy,iz) = ((*u.get_grid(ilevel))(ix-2,iy,iz)
-8.0*(*u.get_grid(ilevel))(ix-1,iy,iz)
+8.0*(*u.get_grid(ilevel))(ix+1,iy,iz)
-(*u.get_grid(ilevel))(ix+2,iy,iz))*h;
else if( dir == 1 )
#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
(*pvar)(ix,iy,iz) = ((*u.get_grid(ilevel))(ix,iy-2,iz)
-8.0*(*u.get_grid(ilevel))(ix,iy-1,iz)
+8.0*(*u.get_grid(ilevel))(ix,iy+1,iz)
-(*u.get_grid(ilevel))(ix,iy+2,iz))*h;
else if( dir == 2 )
#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
(*pvar)(ix,iy,iz) = ((*u.get_grid(ilevel))(ix,iy,iz-2)
-8.0*(*u.get_grid(ilevel))(ix,iy,iz-1)
+8.0*(*u.get_grid(ilevel))(ix,iy,iz+1)
-(*u.get_grid(ilevel))(ix,iy,iz+2))*h;
}
}
void multigrid_poisson_plugin::implementation::gradient_O6( int dir, grid_hierarchy& u, grid_hierarchy& Du )
{
for( unsigned ilevel=u.levelmin(); ilevel<=u.levelmax(); ++ilevel )
{
double h = pow(2.0,ilevel);
meshvar_bnd *pvar = Du.get_grid(ilevel);
h /= 60.;
if( dir == 0 )
#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
(*pvar)(ix,iy,iz) =
(-(*u.get_grid(ilevel))(ix-3,iy,iz)
+9.0*(*u.get_grid(ilevel))(ix-2,iy,iz)
-45.0*(*u.get_grid(ilevel))(ix-1,iy,iz)
+45.0*(*u.get_grid(ilevel))(ix+1,iy,iz)
-9.0*(*u.get_grid(ilevel))(ix+2,iy,iz)
+(*u.get_grid(ilevel))(ix+3,iy,iz))*h;
else if( dir == 1 )
#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
(*pvar)(ix,iy,iz) =
(-(*u.get_grid(ilevel))(ix,iy-3,iz)
+9.0*(*u.get_grid(ilevel))(ix,iy-2,iz)
-45.0*(*u.get_grid(ilevel))(ix,iy-1,iz)
+45.0*(*u.get_grid(ilevel))(ix,iy+1,iz)
-9.0*(*u.get_grid(ilevel))(ix,iy+2,iz)
+(*u.get_grid(ilevel))(ix,iy+3,iz))*h;
else if( dir == 2 )
#pragma omp parallel for
for( int ix = 0; ix < (int)(*u.get_grid(ilevel)).size(0); ++ix )
for( int iy = 0; iy < (int)(*u.get_grid(ilevel)).size(1); ++iy )
for( int iz = 0; iz < (int)(*u.get_grid(ilevel)).size(2); ++iz )
(*pvar)(ix,iy,iz) =
(-(*u.get_grid(ilevel))(ix,iy,iz-3)
+9.0*(*u.get_grid(ilevel))(ix,iy,iz-2)
-45.0*(*u.get_grid(ilevel))(ix,iy,iz-1)
+45.0*(*u.get_grid(ilevel))(ix,iy,iz+1)
-9.0*(*u.get_grid(ilevel))(ix,iy,iz+2)
+(*u.get_grid(ilevel))(ix,iy,iz+3))*h;
}
}
/**************************************************************************************/
/**************************************************************************************/
#pragma mark -
#ifdef SINGLE_PRECISION
#ifdef SINGLETHREAD_FFTW
#include <srfftw.h>
#else
#include <srfftw_threads.h>
#endif
#else
#ifdef SINGLETHREAD_FFTW
#include <drfftw.h>
#else
#include <drfftw_threads.h>
#endif
#endif
double fft_poisson_plugin::solve( grid_hierarchy& f, grid_hierarchy& u )
{
unsigned verbosity = cf_.getValueSafe<unsigned>("setup","verbosity",2);
if( f.levelmin() != f.levelmax() )
throw std::runtime_error("fft_poisson_plugin::solve : k-space method can only be used in unigrid mode (levelmin=levelmax)");
if( verbosity > 0 )
std::cout << " - Invoking unigrid FFT Poisson solver..." << std::endl;
int nx,ny,nz,nzp;
nx = f.get_grid(f.levelmax())->size(0);
ny = f.get_grid(f.levelmax())->size(1);
nz = f.get_grid(f.levelmax())->size(2);
nzp = 2*(nz/2+1);
//... copy data ..................................................
fftw_real *data = new fftw_real[nx*ny*nzp];
fftw_complex *cdata = reinterpret_cast<fftw_complex*> (data);
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;
data[idx] = (*f.get_grid(f.levelmax()))(i,j,k);
}
//... perform FFT and Poisson solve................................
rfftwnd_plan
plan = rfftw3d_create_plan( nx,ny,nz,
FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE|FFTW_IN_PLACE),
iplan = rfftw3d_create_plan( nx,ny,nz,
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 boxlength = cf_.getValue<double>("setup","boxlength");
double kfac = 2.0*M_PI/boxlength;
double fac = -1.0/(nx*ny*nz)/boxlength;
for( int i=0; i<nx; ++i )
for( int j=0; j<ny; ++j )
for( int k=0; k<nz/2+1; ++k )
{
int ii = i; if(ii>nx/2) ii-=nx;
int jj = j; if(jj>ny/2) jj-=ny;
double ki = (double)ii;
double kj = (double)jj;
double kk = (double)k;
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[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);
//... copy data ..........................................
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;
(*u.get_grid(u.levelmax()))(i,j,k) = data[idx];
}
delete[] data;
return 0.0;
}
double fft_poisson_plugin::gradient( int dir, grid_hierarchy& u, grid_hierarchy& Du )
{
if( u.levelmin() != u.levelmax() )
throw std::runtime_error("fft_poisson_plugin::gradient : k-space method can only be used in unigrid mode (levelmin=levelmax)");
Du = u;
int nx,ny,nz,nzp;
nx = u.get_grid(u.levelmax())->size(0);
ny = u.get_grid(u.levelmax())->size(1);
nz = u.get_grid(u.levelmax())->size(2);
nzp = 2*(nz/2+1);
//... copy data ..................................................
fftw_real *data = new fftw_real[nx*ny*nzp];
fftw_complex *cdata = reinterpret_cast<fftw_complex*> (data);
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;
data[idx] = (*u.get_grid(u.levelmax()))(i,j,k);
}
//... perform FFT and Poisson solve................................
rfftwnd_plan
plan = rfftw3d_create_plan( nx,ny,nz,
FFTW_REAL_TO_COMPLEX, FFTW_ESTIMATE|FFTW_IN_PLACE),
iplan = rfftw3d_create_plan( nx,ny,nz,
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 fac = -1.0/(nx*ny*nz);
double boxlength = cf_.getValue<double>("setup","boxlength");
double kfac = 2.0*M_PI/boxlength;
for( int i=0; i<nx; ++i )
for( int j=0; j<ny; ++j )
for( int k=0; k<nz/2+1; ++k )
{
int ii = i; if(ii>nx/2) ii-=nx;
int jj = j; if(jj>ny/2) jj-=ny;
double ki = (double)ii;
double kj = (double)jj;
double kk = (double)k;
double kdir;
if( dir == 0 )
kdir = kfac*ki;
else if( dir == 1 )
kdir = kfac*kj;
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;
cdata[idx].re = fac*im*kdir;
cdata[idx].im = -fac*re*kdir;
}
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);
//... copy data ..........................................
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];
}
delete[] data;
return 0.0;
}
/**************************************************************************************/
/**************************************************************************************/
#pragma mark -
namespace{
poisson_plugin_creator_concrete<multigrid_poisson_plugin> multigrid_poisson_creator("mg_poisson");
poisson_plugin_creator_concrete<fft_poisson_plugin> fft_poisson_creator("fft_poisson");
}

140
poisson.hh Normal file
View file

@ -0,0 +1,140 @@
/*
poisson.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __POISSON_HH
#define __POISSON_HH
#include <string>
#include <map>
#include "general.hh"
class poisson_plugin
{
protected:
//! reference to the config_file object that holds all configuration options
config_file& cf_;
public:
//! constructor
explicit poisson_plugin( config_file& cf )
: cf_(cf)
{ }
//! destructor
virtual ~poisson_plugin()
{ }
virtual double solve( grid_hierarchy& f, grid_hierarchy& u ) = 0;
virtual double gradient( int dir, grid_hierarchy& u, grid_hierarchy& Du ) = 0;
};
#pragma mark -
/*!
* @brief implements abstract factory design pattern for poisson solver plug-ins
*/
struct poisson_plugin_creator
{
//! create an instance of a plug-in
virtual poisson_plugin * create( config_file& cf ) const = 0;
//! destroy an instance of a plug-in
virtual ~poisson_plugin_creator() { }
};
//! maps the name of a plug-in to a pointer of the factory pattern
std::map< std::string, poisson_plugin_creator *>& get_poisson_plugin_map();
//! print a list of all registered output plug-ins
void print_poisson_plugins();
/*!
* @brief concrete factory pattern for output plug-ins
*/
template< class Derived >
struct poisson_plugin_creator_concrete : public poisson_plugin_creator
{
//! register the plug-in by its name
poisson_plugin_creator_concrete( const std::string& plugin_name )
{
get_poisson_plugin_map()[ plugin_name ] = this;
}
//! create an instance of the plug-in
poisson_plugin * create( config_file& cf ) const
{
return new Derived( cf );
}
};
/**************************************************************************************/
/**************************************************************************************/
#pragma mark -
class multigrid_poisson_plugin : public poisson_plugin
{
public:
explicit multigrid_poisson_plugin( config_file& cf )
: poisson_plugin( cf )
{ }
double solve( grid_hierarchy& f, grid_hierarchy& u );
double gradient( int dir, grid_hierarchy& u, grid_hierarchy& Du );
protected:
struct implementation
{
double solve_O2( grid_hierarchy& f, grid_hierarchy& u );
double solve_O4( grid_hierarchy& f, grid_hierarchy& u );
void gradient_O2( int dir, grid_hierarchy& u, grid_hierarchy& Du );
void gradient_O4( int dir, grid_hierarchy& u, grid_hierarchy& Du );
void gradient_O6( int dir, grid_hierarchy& u, grid_hierarchy& Du );
};
};
/**************************************************************************************/
/**************************************************************************************/
#pragma mark -
class fft_poisson_plugin : public poisson_plugin
{
public:
explicit fft_poisson_plugin( config_file& cf )
: poisson_plugin( cf )
{ }
double solve( grid_hierarchy& f, grid_hierarchy& u );
double gradient( int dir, grid_hierarchy& u, grid_hierarchy& Du );
};
#endif // __POISSON_HH

459
random.hh Normal file
View file

@ -0,0 +1,459 @@
/*
random.hh - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __RANDOM_HH
#define __RANDOM_HH
#include <fstream>
#include <algorithm>
#include <gsl/gsl_rng.h>
#include <gsl/gsl_randist.h>
#include "mesh.hh"
#include "mg_operators.hh"
/*!
* @brief encapsulates all things random number generator related
*/
template< typename T >
class random_numbers
{
public:
unsigned
res_, //!< resolution of the full mesh
cubesize_, //!< size of one independent random number cube
ncubes_; //!< number of random number cubes to cover the full mesh
long baseseed_; //!< base seed from which cube seeds are computed
//! vector of 3D meshes (the random number cbues) with random numbers
std::vector< Meshvar<T>* > rnums_;
protected:
//! fills a subcube with random numbers
double fill_cube( int i, int j, int k)
{
gsl_rng *RNG = gsl_rng_alloc( gsl_rng_mt19937 );
i = (i+ncubes_)%ncubes_;
j = (j+ncubes_)%ncubes_;
k = (k+ncubes_)%ncubes_;
long icube = (i*ncubes_+j)*ncubes_+k;
long cubeseed = baseseed_+icube; //... each cube gets its unique seed
gsl_rng_set( RNG, cubeseed );
if( rnums_[icube] == NULL )
rnums_[icube] = new Meshvar<T>( cubesize_, 0, 0, 0 );
double mean = 0.0;
for( int ii=0; ii<(int)cubesize_; ++ii )
for( int jj=0; jj<(int)cubesize_; ++jj )
for( int kk=0; kk<(int)cubesize_; ++kk )
{
(*rnums_[icube])(ii,jj,kk) = gsl_ran_ugaussian_ratio_method( RNG );
mean += (*rnums_[icube])(ii,jj,kk);
}
gsl_rng_free( RNG );
return mean/(cubesize_*cubesize_*cubesize_);
}
//! copy random numbers from a cube to a full grid array
template< class C >
void copy_cube( int i, int j, int k, C& dat )
{
int offi, offj, offk;
offi = i*cubesize_;
offj = j*cubesize_;
offk = k*cubesize_;
i = (i+ncubes_)%ncubes_;
j = (j+ncubes_)%ncubes_;
k = (k+ncubes_)%ncubes_;
long icube = (i*ncubes_+j)*ncubes_+k;
for( int ii=0; ii<(int)cubesize_; ++ii )
for( int jj=0; jj<(int)cubesize_; ++jj )
for( int kk=0; kk<(int)cubesize_; ++kk )
dat(offi+ii,offj+jj,offk+kk) = (*rnums_[icube])(ii,jj,kk);
}
//! free the memory associated with a subcube
void free_cube( int i, int j, int k )
{
i = (i+ncubes_)%ncubes_;
j = (j+ncubes_)%ncubes_;
k = (k+ncubes_)%ncubes_;
long icube = (i*ncubes_+j)*ncubes_+k;
if( rnums_[icube] != NULL )
{
delete rnums_[icube];
rnums_[icube] = NULL;
}
}
//! initialize member variables and allocate memory
void initialize( void )
{
ncubes_ = std::max((int)((double)res_/cubesize_),1);
if( res_ < cubesize_ )
{
ncubes_ = 1;
cubesize_ = res_;
}
rnums_.assign( ncubes_*ncubes_*ncubes_, NULL );
}
//! fill a cubic subvolume of the full grid with random numbers
double fill_subvolume( int *i0, int *n )
{
unsigned i0cube[3], ncube[3];
i0cube[0] = (int)((double)i0[0]/cubesize_);
i0cube[1] = (int)((double)i0[1]/cubesize_);
i0cube[2] = (int)((double)i0[2]/cubesize_);
ncube[0] = (int)((double)(i0[0]+n[0])/cubesize_+1.0)-i0cube[0];
ncube[1] = (int)((double)(i0[1]+n[1])/cubesize_+1.0)-i0cube[1];
ncube[2] = (int)((double)(i0[2]+n[2])/cubesize_+1.0)-i0cube[2];
double mean = 0.0;
#pragma omp parallel for reduction(+:mean)
for( int i=i0cube[0]; i<(int)ncube[0]; ++i )
for( int j=i0cube[1]; j<(int)ncube[1]; ++j )
for( int k=i0cube[2]; k<(int)ncube[2]; ++k )
{
int ii(i),jj(j),kk(k);
ii = (ii+ncubes_)%ncubes_;
jj = (jj+ncubes_)%ncubes_;
kk = (kk+ncubes_)%ncubes_;
mean += fill_cube(ii, jj, kk);
}
return mean/(ncube[0]*ncube[1]*ncube[2]);
}
//! fill an entire grid with random numbers
double fill_all( void )
{
double sum = 0.0;
#pragma omp parallel for reduction(+:sum)
for( int i=0; i<(int)ncubes_; ++i )
for( int j=0; j<(int)ncubes_; ++j )
for( int k=0; k<(int)ncubes_; ++k )
{
int ii(i),jj(j),kk(k);
ii = (ii+ncubes_)%ncubes_;
jj = (jj+ncubes_)%ncubes_;
kk = (kk+ncubes_)%ncubes_;
sum+=fill_cube(ii, jj, kk);
}
return sum/(ncubes_*ncubes_*ncubes_);
}
public:
template< class C >
double fill_all( C& dat )
{
double sum = 0.0;
#pragma omp parallel for reduction(+:sum)
for( int i=0; i<(int)ncubes_; ++i )
for( int j=0; j<(int)ncubes_; ++j )
for( int k=0; k<(int)ncubes_; ++k )
{
int ii(i),jj(j),kk(k);
ii = (ii+ncubes_)%ncubes_;
jj = (jj+ncubes_)%ncubes_;
kk = (kk+ncubes_)%ncubes_;
sum+=fill_cube(ii, jj, kk);
copy_cube(ii,jj,kk,dat);
free_cube(ii, jj, kk);
}
return sum/(ncubes_*ncubes_*ncubes_);
}
public:
//! constructor
random_numbers( unsigned res, unsigned cubesize, long baseseed, int *x0, int *lx )
: res_( res ), cubesize_( cubesize ), ncubes_( 1 ), baseseed_( baseseed )
{
initialize();
fill_subvolume( x0, lx );
}
//! constructor
random_numbers( unsigned res, unsigned cubesize, long baseseed, bool zeromean=true )
: res_( res ), cubesize_( cubesize ), ncubes_( 1 ), baseseed_( baseseed )
{
double mean = 0.0;
initialize();
mean = fill_all();
if( zeromean )
{
for(unsigned i=0; i<res_; ++i )
for( unsigned j=0; j<res_; ++j )
for( unsigned k=0; k<res_; ++k )
(*this)(i,j,k) -= mean;
}
}
//! constructor
random_numbers( unsigned res, std::string randfname )
: res_( res ), cubesize_( res ), ncubes_(1)
{
rnums_.push_back( new Meshvar<T>( res, 0, 0, 0 ) );
std::ifstream ifs(randfname.c_str(), std::ios::binary);
if( !ifs )
throw std::runtime_error(std::string("Could not open random number file \'")+randfname+std::string("\'!"));
unsigned vartype;
unsigned nx,ny,nz,blksz;
int iseed;
long seed;
//ifs.read( (char*)&vartype, sizeof(unsigned) );
//... read header .../
ifs.read( reinterpret_cast<char*> (&blksz), sizeof(int) );
if( blksz != 4*sizeof(int) )
throw std::runtime_error("corrupt random number file");
ifs.read( reinterpret_cast<char*> (&nx), sizeof(unsigned) );
ifs.read( reinterpret_cast<char*> (&ny), sizeof(unsigned) );
ifs.read( reinterpret_cast<char*> (&nz), sizeof(unsigned) );
ifs.read( reinterpret_cast<char*> (&iseed), sizeof(int) );
seed = (long)iseed;
ifs.read( reinterpret_cast<char*> (&blksz), sizeof(int) );
//... read data ...//
ifs.read( reinterpret_cast<char*> (&blksz), sizeof(int) );
if( blksz == nx*ny*sizeof(float) )
vartype = 4;
else if( blksz == nx*ny*sizeof(double) )
vartype = 8;
else
throw std::runtime_error("corrupt random number file");
std::vector<float> in_float;
std::vector<double> in_double;
std::cout << " - Random number file \'" << randfname << "\'\n"
<< " contains " << nx*ny*nz << " numbers. Reading..." << std::endl;
double sum = 0.0, sum2 = 0.0;
unsigned count = 0;
if( vartype == 4 )
{
for( int ii=0; ii<(int)nz; ++ii )
{
in_float.assign(nx*ny,0.0f);
ifs.read( (char*)&in_float[0], nx*ny*sizeof(float) );
for( int jj=0,q=0; jj<(int)ny; ++jj )
for( int kk=0; kk<(int)nx; ++kk ){
sum += in_float[q];
sum2 += in_float[q]*in_float[q];
++count;
#ifdef RAND_DEBUG
(*rnums_[0])(ii,jj,kk) = 0.0;
#else
(*rnums_[0])(ii,jj,kk) = in_float[q++];
#endif
}
}
}
else if( vartype == 8 )
{
for( int ii=0; ii<(int)nz; ++ii )
{
in_double.assign(nx*ny,0.0f);
ifs.read( (char*)&in_double[0], nx*ny*sizeof(double) );
for( int jj=0,q=0; jj<(int)ny; ++jj )
for( int kk=0; kk<(int)nx; ++kk )
{
sum += in_double[q];
sum2 += in_double[q]*in_double[q];
++count;
#ifdef RAND_DEBUG
(*rnums_[0])(ii,jj,kk) = 0.0;
#else
(*rnums_[0])(ii,jj,kk) = in_double[q++];
#endif
}
}
}
double mean, var;
mean = sum/count;
var = sum2/count-mean*mean;
#ifdef RAND_DEBUG
(*rnums_[0])(cubesize_/2-1,cubesize_/2-1,cubesize_/2-1) = 1.0;
#endif
std::cout << " - Random numbers in file have \n"
<< " mean = " << mean << " and var = " << var << std::endl;
}
//... copy construct by averaging down
explicit random_numbers( /*const*/ random_numbers <T>& rc )
{
//if( res > rc.m_res || (res/rc.m_res)%2 != 0 )
// throw std::runtime_error("Invalid restriction in random number container copy constructor.");
double sum = 0.0, sum2 = 0.0;
unsigned count = 0;
//... initialize properties of container
if( rc.rnums_.size() == 1 )
{
res_ = rc.res_/2;
cubesize_ = res_;
ncubes_ = 1;
baseseed_ = -2;
//... use restriction to get consistent random numbers on coarser grid
mg_straight gop;
rnums_.push_back( new Meshvar<T>( res_, 0, 0, 0 ) );
gop.restrict( *rc.rnums_[0], *rnums_[0] );
for( unsigned i=0; i< rnums_[0]->size(0); ++i )
for( unsigned j=0; j< rnums_[0]->size(1); ++j )
for( unsigned k=0; k< rnums_[0]->size(2); ++k )
{
(*rnums_[0])(i,j,k) *= sqrt(8); //.. maintain that var(delta)=1
sum += (*rnums_[0])(i,j,k);
sum2+= (*rnums_[0])(i,j,k) * (*rnums_[0])(i,j,k);
++count;
}
}
else
{
res_ = rc.res_/2;
cubesize_ = res_;
ncubes_ = 1;
baseseed_ = -2;
rnums_.push_back( new Meshvar<T>( res_, 0, 0, 0 ) );
double fac = 1.0/sqrt(8);
for( unsigned i=0,ii=0; i<rc.res_; i+=2,++ii )
for( unsigned j=0,jj=0; j<rc.res_; j+=2,++jj )
for( unsigned k=0,kk=0; k<rc.res_; k+=2,++kk )
{
(*rnums_[0])(ii,jj,kk) = fac *
( rc(i,j,k)+rc(i+1,j,k)+rc(i,j+1,k)+rc(i,j,k+1)+
rc(i+1,j+1,k)+rc(i+1,j,k+1)+rc(i,j+1,k+1)+rc(i+1,j+1,k+1));
sum += (*rnums_[0])(ii,jj,kk);
sum2+= (*rnums_[0])(ii,jj,kk) * (*rnums_[0])(ii,jj,kk);
++count;
}
}
double rmean, rvar;
rmean = sum/count;
rvar = sum2/count-rmean*rmean;
std::cout << " - Restricted random numbers have mean = " << rmean << " and var = " << rvar << std::endl;
}
~random_numbers()
{
for( unsigned i=0; i<rnums_.size(); ++i )
if( rnums_[i] != NULL )
delete rnums_[i];
rnums_.clear();
}
T& operator()( int i, int j, int k )
{
int ic, jc, kc, is, js, ks;
if( ncubes_ == 0 )
throw std::runtime_error("random_numbers: internal error, not properly initialized");
//... determine cube
ic = (int)((double)i/cubesize_ + ncubes_) % ncubes_;
jc = (int)((double)j/cubesize_ + ncubes_) % ncubes_;
kc = (int)((double)k/cubesize_ + ncubes_) % ncubes_;
long icube = (ic*ncubes_+jc)*ncubes_+kc;
if( rnums_[ icube ] == NULL )
{
rnums_[ icube ] = new Meshvar<T>( cubesize_, 0, 0, 0 );
fill_cube(ic, jc, kc);
}
//... determine cell in cube
is = (i - ic * cubesize_ + cubesize_) % cubesize_;
js = (j - jc * cubesize_ + cubesize_) % cubesize_;
ks = (k - kc * cubesize_ + cubesize_) % cubesize_;
return (*rnums_[ icube ])(is,js,ks);
}
};
#endif //__RANDOM_HH

275
schemes.hh Normal file
View file

@ -0,0 +1,275 @@
/*
* schemes.hh
* GravitySolver
*
* Created by Oliver Hahn on 2/1/10.
* Copyright 2010 KIPAC/Stanford University. All rights reserved.
*
*/
#ifndef __SCHEME_HH
#define __SCHEME_HH
#include <vector>
#include <stdexcept>
#include "solver.hh"
//... abstract implementation of the Poisson/Force scheme
template< class L, class G, typename real_t=double >
class scheme
{
public:
typedef L laplacian;
typedef G gradient;
laplacian m_laplacian;
gradient m_gradient;
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 ); }
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 ); }
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 ); }
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 ); }
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 ); }
inline real_t ccoeff( void )
{ return m_laplacian.ccoeff(); }
};
template< int nextent, typename T >
class gradient
{
typedef T real_t;
std::vector<real_t> m_stencil;
const unsigned nl;
public:
gradient()
: nl( 2*nextent+1 )
{
m_stencil.assign(nl*nl*nl,(real_t)0.0);
}
real_t& operator()(int i)
{ return m_stencil[i+nextent]; }
const real_t& operator()(int i) const
{ return m_stencil[i+nextent]; }
template< class C >
inline void apply( const C& c, C& f, int dir )
{
f = c;
int nx=c.size(0), ny=c.size(1), nz=c.size(2);
double hx = 1.0/(nx+1.0), hy = 1.0/(ny+1.0), hz = 1.0/(nz+1.0);
f.zero();
if( dir == 0 )
for( int i=0; i<nx; ++i )
for( int j=0; j<ny; ++j )
for( int k=0; k<nz; ++k )
for( int ii = -nextent; ii<=nextent; ++ii )
f(i,j,k) += (*this)(ii) * c(i+ii,j,k)/hx;
else if( dir == 1 )
for( int i=0; i<nx; ++i )
for( int j=0; j<ny; ++j )
for( int k=0; k<nz; ++k )
for( int jj = -nextent; jj<=nextent; ++jj )
f(i,j,k) += (*this)(jj) * c(i,j+jj,k)/hy;
else if( dir == 2 )
for( int i=0; i<nx; ++i )
for( int j=0; j<ny; ++j )
for( int k=0; k<nz; ++k )
for( int kk = -nextent; kk<=nextent; ++kk )
f(i,j,k) += (*this)(kk) * c(i,j,k+kk)/hz;
}
};
template< int nextent, typename real_t >
class base_stencil
{
protected:
std::vector<real_t> m_stencil;
const unsigned nl;
public:
bool m_modsource;
public:
base_stencil( bool amodsource = false )
: nl( 2*nextent+1 ), m_modsource( amodsource )
{
m_stencil.assign(nl*nl*nl,(real_t)0.0);
}
real_t& operator()(int i, int j, int k)
{ return m_stencil[((i+nextent)*nl+(j+nextent))*nl+(k+nextent)]; }
const real_t& operator()(unsigned i, unsigned j, unsigned k) const
{ return m_stencil[((i+nextent)*nl+(j+nextent))*nl+(k+nextent)]; }
template< class C >
inline real_t rhs( const C& c, const int i, const int j, const int k )
{
real_t sum = this->apply( c, i, j, k );
sum -= (*this)(0,0,0) * c(i,j,k);
return sum;
}
inline real_t ccoeff( void )
{
return (*this)(0,0,0);
}
template< class C >
inline real_t apply( const C& c, const int i, const int j, const int k )
{
real_t sum = 0.0;
for( int ii=-nextent; ii<=nextent; ++ii )
for( int jj=-nextent; jj<=nextent; ++jj )
for( int kk=-nextent; kk<=nextent; ++kk )
sum += (*this)(ii,jj,kk) * c(i+ii,j+jj,k+kk);
return sum;
}
template< class C >
inline real_t modsource( const C& c, const int i, const int j, const int k )
{
return 0.0;
}
};
/***************************************************************************************/
/***************************************************************************************/
/***************************************************************************************/
//... Implementation of the Gradient schemes............................................
template< typename real_t >
class deriv_2P : public gradient<1,real_t>
{
public:
deriv_2P( void )
{
(*this)( 0 ) = 0.0;
(*this)(-1 ) = -0.5;
(*this)(+1 ) = +0.5;
}
};
//... Implementation of the Laplacian schemes..........................................
template< typename real_t >
class stencil_7P : public base_stencil<1,real_t>
{
public:
stencil_7P( void )
{
(*this)( 0, 0, 0) = -6.0;
(*this)(-1, 0, 0) = +1.0;
(*this)(+1, 0, 0) = +1.0;
(*this)( 0,-1, 0) = +1.0;
(*this)( 0,+1, 0) = +1.0;
(*this)( 0, 0,-1) = +1.0;
(*this)( 0, 0,+1) = +1.0;
}
template< class C >
inline real_t apply( const C& c, const int i, const int j, const int k ) const
{
return c(i-1,j,k)+c(i+1,j,k)+c(i,j-1,k)+c(i,j+1,k)+c(i,j,k-1)+c(i,j,k+1)-6.0*c(i,j,k);
}
template< class C >
inline real_t rhs( const C& c, const int i, const int j, const int k ) const
{
return c(i-1,j,k)+c(i+1,j,k)+c(i,j-1,k)+c(i,j+1,k)+c(i,j,k-1)+c(i,j,k+1);
}
inline real_t ccoeff( void )
{
return -6.0;
}
};
template< typename real_t >
class stencil_13P : public base_stencil<2,real_t>
{
public:
stencil_13P( void )
{
(*this)( 0, 0, 0) = -90.0/12.;
(*this)(-1, 0, 0) =
(*this)(+1, 0, 0) =
(*this)( 0,-1, 0) =
(*this)( 0,+1, 0) =
(*this)( 0, 0,-1) =
(*this)( 0, 0,+1) = 16./12.;
(*this)(-2, 0, 0) =
(*this)(+2, 0, 0) =
(*this)( 0,-2, 0) =
(*this)( 0,+2, 0) =
(*this)( 0, 0,-2) =
(*this)( 0, 0,+2) = -1./12.;
}
template< class C >
inline real_t apply( const C& c, const int i, const int j, const int k )
{
return
(-1.0*(c(i-2,j,k)+c(i+2,j,k)+c(i,j-2,k)+c(i,j+2,k)+c(i,j,k-2)+c(i,j,k+2))
+16.0*(c(i-1,j,k)+c(i+1,j,k)+c(i,j-1,k)+c(i,j+1,k)+c(i,j,k-1)+c(i,j,k+1))
-90.0*c(i,j,k))/12.0;
}
template< class C >
inline real_t rhs( const C& c, const int i, const int j, const int k )
{
return
(-1.0*(c(i-2,j,k)+c(i+2,j,k)+c(i,j-2,k)+c(i,j+2,k)+c(i,j,k-2)+c(i,j,k+2))
+16.0*(c(i-1,j,k)+c(i+1,j,k)+c(i,j-1,k)+c(i,j+1,k)+c(i,j,k-1)+c(i,j,k+1)))/12.0;
}
inline real_t ccoeff( void )
{
return -90.0/12.0;
}
};
#endif

1110
solver.hh Normal file

File diff suppressed because it is too large Load diff

309
tests.hh Normal file
View file

@ -0,0 +1,309 @@
/*
tests.hh - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#ifndef __TESTS_HH
#define __TESTS_HH
#include <math.h>
inline double CIC_interp_back( const MeshvarBnd<double>& A, double x, double y, double z )
{
int
ix = (int)x,
iy = (int)y,
iz = (int)z,
ix1 = (ix+1),
iy1 = (iy+1),
iz1 = (iz+1);
double
dx = (double)(x - (double)ix),
dy = (double)(y - (double)iy),
dz = (double)(z - (double)iz),
tx = 1.0-dx,
ty = 1.0-dy,
tz = 1.0-dz;
double
f_xyz = A(ix,iy,iz)*tx*ty*tz,
f_Xyz = A(ix1,iy,iz)*dx*ty*tz,
f_xYz = A(ix,iy1,iz)*tx*dy*tz,
f_xyZ = A(ix,iy,iz1)*tx*ty*dz,
f_XYz = A(ix1,iy1,iz)*dx*dy*tz,
f_XyZ = A(ix1,iy,iz1)*dx*ty*dz,
f_xYZ = A(ix,iy1,iz1)*tx*dy*dz,
f_XYZ = A(ix1,iy1,iz1)*dx*dy*dz;
return f_xyz + f_Xyz + f_xYz + f_xyZ + f_XYz + f_XyZ + f_xYZ + f_XYZ;
}
inline double TSC_interp_back( const MeshvarBnd<double>& A, double x, double y, double z )
{
double val = 0.0;
int xngp = (int)x, yngp = (int)y, zngp = (int)z;
for( int xx = xngp-1; xx <= xngp+1; ++xx )
{
double weightx = 1.0;
double dx = fabs(x-(double)xx);
int axx(xx);
if( xx==xngp )
weightx *= 0.75-dx*dx;
else{
weightx *= 1.125 - 1.5*dx + 0.5*dx*dx;
}
for( int yy = yngp-1; yy <= yngp+1; ++yy )
{
double weighty = weightx;
double dy = fabs(y-(double)yy);
int ayy(yy);
if( yy==yngp )
weighty *= 0.75-dy*dy;
else{
weighty *= 1.125 - 1.5*dy + 0.5*dy*dy;
}
for( int zz = zngp-1; zz <= zngp+1; ++zz )
{
double weightz = weighty;
double dz = fabs(z-(double)zz);
int azz(zz);
if( zz==zngp )
weightz *= 0.75-dz*dz;
else{
weightz *= 1.125 - 1.5*dz + 0.5*dz*dz;
}
val += A(axx,ayy,azz) * weightz;
}
}
}
return val;
}
class TestProblem{
public:
MeshvarBnd<double> m_rho, m_uana, m_ubnd, m_xgrad, m_ygrad, m_zgrad;
int m_nb, m_nres;
double m_h;
TestProblem( int nb, int nres )
: m_rho( nb, nres ), m_uana( nb, nres ), m_ubnd( nb, nres ),
m_xgrad( nb, nres ), m_ygrad( nb, nres ), m_zgrad( nb, nres ),
m_nb( nb ), m_nres( nres ), m_h( 1.0/((double)nres ) )//m_h( 1.0/((double)nres+1.0 ) )
{ }
};
class TSC_Test : public TestProblem{
public:
double m_q;
class TSCcube{
public:
std::vector<double> m_data;
TSCcube()
{
m_data.assign(27,0.0);
//.. center
(*this)( 0, 0, 0) = 27./64.;
//.. faces
(*this)(-1, 0, 0) =
(*this)(+1, 0, 0) =
(*this)( 0,-1, 0) =
(*this)( 0,+1, 0) =
(*this)( 0, 0,-1) =
(*this)( 0, 0,+1) = 9./128.;
//.. edges
(*this)(-1,-1, 0) =
(*this)(-1,+1, 0) =
(*this)(+1,-1, 0) =
(*this)(+1,+1, 0) =
(*this)(-1, 0,-1) =
(*this)(-1, 0,+1) =
(*this)(+1, 0,-1) =
(*this)(+1, 0,+1) =
(*this)( 0,-1,-1) =
(*this)( 0,-1,+1) =
(*this)( 0,+1,-1) =
(*this)( 0,+1,+1) = 3./256.;
//.. corners
(*this)(-1,-1,-1) =
(*this)(-1,+1,-1) =
(*this)(-1,-1,+1) =
(*this)(-1,+1,+1) =
(*this)(+1,-1,-1) =
(*this)(+1,+1,-1) =
(*this)(+1,-1,+1) =
(*this)(+1,+1,+1) = 1./512.;
}
double& operator()(int i, int j, int k)
{ return m_data[ ((i+1)*3+(j+1))*3 +(k+1)]; }
const double& operator()(int i, int j, int k) const
{ return m_data[ ((i+1)*3+(j+1))*3 +(k+1)]; }
};
TSC_Test( int nb, int nres, double q=-1.0 )
: TestProblem(nb, nres), m_q(q)
{
TSCcube c;
int xm(nres/2-1), ym(nres/2-1), zm(nres/2-1);
double xxm((double)xm*m_h), yym((double)ym*m_h), zzm((double)zm*m_h);
double fourpi = 4.0*M_PI;
m_uana.zero();
m_ubnd.zero();
m_xgrad.zero();
m_ygrad.zero();
m_zgrad.zero();
for( int i=-nb; i<nres+nb; ++i )
for( int j=-nb; j<nres+nb; ++j )
for( int k=-nb; k<nres+nb; ++k )
{
//double xxm((double)xm), yym((double)ym), zzm((double)zm);
double xx((double)i*m_h), yy((double)j*m_h), zz((double)k*m_h);
for( int ix=-1; ix<=1; ++ix )
for( int iy=-1; iy<=1; ++iy )
for( int iz=-1; iz<=1; ++iz )
{
double dx(xx-(xxm+ix*m_h)), dy(yy-(yym+iy*m_h)), dz(zz-(zzm+iz*m_h));
double d3 = pow(dx*dx+dy*dy+dz*dz,1.5);
double dphi = m_q*c(ix,iy,iz)/sqrt(dx*dx+dy*dy+dz*dz);
if( i==xm && j==ym && k==zm )
m_rho(i+ix,j+iy,k+iz) = m_q*c(ix,iy,iz)/(m_h*m_h*m_h);
if( d3 < 1e-10 )
continue;
m_uana(i,j,k) += dphi/fourpi;
m_ubnd(i,j,k) += dphi/fourpi;
m_xgrad(i,j,k) -= m_q*c(ix,iy,iz)*dx/d3/fourpi;
m_ygrad(i,j,k) -= m_q*c(ix,iy,iz)*dy/d3/fourpi;
m_zgrad(i,j,k) -= m_q*c(ix,iy,iz)*dz/d3/fourpi;
}
}
//m_rho(xm,ym,zm) = 4.0*M_PI*m_q/(m_h*m_h*m_h);
}
};
class PointMassTest : public TestProblem{
public:
double m_q;
PointMassTest( int nb, int nres, double q=-1.0 )
: TestProblem(nb, nres), m_q( q )
{
//int xm(nres/2-1), ym(nres/2-1), zm(nres/2-1);
int xm(nres/2), ym(nres/2), zm(nres/2);
double xxm((double)xm*m_h), yym((double)ym*m_h), zzm((double)zm*m_h);
m_rho.zero();
double fourpi = 4.0*M_PI;
for( int i=-nb; i<nres+nb; ++i )
for( int j=-nb; j<nres+nb; ++j )
for( int k=-nb; k<nres+nb; ++k )
{
//double xxm((double)xm), yym((double)ym), zzm((double)zm);
double xx((double)i*m_h), yy((double)j*m_h), zz((double)k*m_h);
double dx(xx-xxm), dy(yy-yym), dz(zz-zzm);
m_uana(i,j,k) = m_q/sqrt(dx*dx+dy*dy+dz*dz)/fourpi;///2.0/M_PI;
m_ubnd(i,j,k) = 0.0;//m_uana(i,j,k);
double d3 = pow(dx*dx+dy*dy+dz*dz,1.5);
m_xgrad(i,j,k) = -m_q*dx/d3/fourpi;
m_ygrad(i,j,k) = -m_q*dy/d3/fourpi;
m_zgrad(i,j,k) = -m_q*dz/d3/fourpi;
}
for( int iy=0; iy<nres; ++iy )
for( int iz=0; iz<nres; ++iz )
{
double dx=0.5+0.5*m_h, dy=((double)iy+0.5)*m_h-0.5, dz=((double)iz+0.5)*m_h-0.5, d=sqrt(dx*dx+dy*dy+dz*dz);
m_ubnd(-1,iy,iz) = m_q/d/fourpi;
dx = 0.5-0.5*m_h;
d = sqrt(dx*dx+dy*dy+dz*dz);
m_ubnd(nres,iy,iz) = m_q/d/fourpi;
}
for( int ix=0; ix<nres; ++ix )
for( int iz=0; iz<nres; ++iz )
{
double dx=((double)ix+0.5)*m_h-0.5, dy=0.5+0.5*m_h, dz=((double)iz+0.5)*m_h-0.5, d=sqrt(dx*dx+dy*dy+dz*dz);
m_ubnd(ix,-1,iz) = m_q/d/fourpi;
dy=0.5-0.5*m_h;
d = sqrt(dx*dx+dy*dy+dz*dz);
m_ubnd(ix,nres,iz) = m_q/d/fourpi;
}
for( int ix=0; ix<nres; ++ix )
for( int iy=0; iy<nres; ++iy )
{
double dx=((double)ix+0.5)*m_h-0.5, dy=((double)iy+0.5)*m_h-0.5, dz=0.5+0.5*m_h, d=sqrt(dx*dx+dy*dy+dz*dz);
m_ubnd(ix,iy,-1) = m_q/d/fourpi;
dz=0.5-0.5*m_h;
d = sqrt(dx*dx+dy*dy+dz*dz);
m_ubnd(ix,iy,nres) = m_q/d/fourpi;
}
m_rho(xm,ym,zm) = m_q/(m_h*m_h*m_h);
}
};
#endif

72
transfer_function.cc Normal file
View file

@ -0,0 +1,72 @@
/*
transfer_function.cc - This file is part of MUSIC -
a code to generate multi-scale initial conditions
for cosmological simulations
Copyright (C) 2010 Oliver Hahn
This program is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#include "transfer_function.hh"
std::map< std::string, transfer_function_plugin_creator *>&
get_transfer_function_plugin_map()
{
static std::map< std::string, transfer_function_plugin_creator* > transfer_function_plugin_map;
return transfer_function_plugin_map;
}
void print_transfer_function_plugins()
{
std::map< std::string, transfer_function_plugin_creator *>& m = get_transfer_function_plugin_map();
std::map< std::string, transfer_function_plugin_creator *>::iterator it;
it = m.begin();
std::cout << " - Available transfer function plug-ins:\n";
while( it!=m.end() )
{
if( (*it).second )
std::cout << "\t\'" << (*it).first << "\'\n";
++it;
}
}
transfer_function_plugin *select_transfer_function_plugin( config_file& cf )
{
std::string tfname = cf.getValue<std::string>( "cosmology", "transfer" );
transfer_function_plugin_creator *the_transfer_function_plugin_creator
= get_transfer_function_plugin_map()[ tfname ];
if( !the_transfer_function_plugin_creator )
{
std::cerr << " - Error: transfer function plug-in \'" << tfname << "\' not found." << std::endl;
print_transfer_function_plugins();
throw std::runtime_error("Unknown transfer function plug-in");
}else
std::cout << " - Selecting transfer function plug-in \'" << tfname << "\'..." << std::endl;
transfer_function_plugin *the_transfer_function_plugin
= the_transfer_function_plugin_creator->create( cf );
return the_transfer_function_plugin;
}

1420
transfer_function.hh Normal file

File diff suppressed because it is too large Load diff