├── Particles_gevolution.hpp ├── README.md ├── background.hpp ├── bcc_crystal.dat ├── fcc_crystal.dat ├── gevolution.hpp ├── ic_basic.hpp ├── main.cpp ├── makefile ├── manual.pdf ├── metadata.hpp ├── parser.hpp ├── pk-z100.dat ├── prng_engine.hpp ├── sc0_crystal.dat ├── sc1_crystal.dat ├── settings.ini └── tools.hpp /Particles_gevolution.hpp: -------------------------------------------------------------------------------- 1 | ////////////////////////// 2 | // Particles_gevolution.hpp 3 | ////////////////////////// 4 | // 5 | // Author: Julian Adamek (Université de Genève) 6 | // 7 | // Last modified: April 2016 8 | // 9 | ////////////////////////// 10 | 11 | #ifndef PARTICLES_GEVOLUTION_HEADER 12 | #define PARTICLES_GEVOLUTION_HEADER 13 | 14 | using namespace LATfield2; 15 | 16 | #ifndef GADGET2_HEADER 17 | #define GADGET2_HEADER 18 | struct gadget2_header 19 | { 20 | unsigned int npart[6]; 21 | double mass[6]; 22 | double time; 23 | double redshift; 24 | int flag_sfr; 25 | int flag_feedback; 26 | unsigned int npartTotal[6]; 27 | int flag_cooling; 28 | int num_files; 29 | double BoxSize; 30 | double Omega0; 31 | double OmegaLambda; 32 | double HubbleParam; 33 | char fill[256 - 6 * 4 - 6 * 8 - 2 * 8 - 2 * 4 - 6 * 4 - 2 * 4 - 4 * 8]; /* fills to 256 Bytes */ 34 | }; 35 | #endif 36 | 37 | template 38 | class Particles_gevolution: public Particles 39 | { 40 | public: 41 | void saveGadget2(string filename, gadget2_header & hdr, const int tracer_factor = 1); 42 | }; 43 | 44 | template 45 | void Particles_gevolution::saveGadget2(string filename, gadget2_header & hdr, const int tracer_factor) 46 | { 47 | #ifndef PCLBUFFER 48 | #define PCLBUFFER 1048576 49 | #endif 50 | 51 | float * posdata; 52 | float * veldata; 53 | long * IDs; 54 | MPI_File outfile; 55 | long count, npart; 56 | MPI_Offset offset_pos, offset_vel, offset_ID; 57 | MPI_Status status; 58 | unsigned int blocksize; 59 | unsigned int i; 60 | char fname[filename.length()+1]; 61 | double rescale_vel = 299792.458 / sqrt(hdr.time); 62 | 63 | filename.copy(fname, filename.length()); 64 | fname[filename.length()] = '\0'; 65 | 66 | LATfield2::Site xPart(this->lat_part_); 67 | typename std::list::iterator it; 68 | 69 | if (hdr.num_files != 1) 70 | { 71 | COUT << " warning: writing multiple Gadget2 files not currently supported!" << endl; 72 | return; 73 | } 74 | 75 | posdata = (float *) malloc(3 * sizeof(float) * PCLBUFFER); 76 | veldata = (float *) malloc(3 * sizeof(float) * PCLBUFFER); 77 | IDs = (long *) malloc(3 * sizeof(long) * PCLBUFFER); 78 | 79 | npart = 0; 80 | for(xPart.first(); xPart.test(); xPart.next()) 81 | { 82 | if(this->field_part_(xPart).size!=0) 83 | { 84 | for (it=(this->field_part_)(xPart).parts.begin(); it != (this->field_part_)(xPart).parts.end(); ++it) 85 | { 86 | if ((*it).ID % tracer_factor == 0) 87 | npart++; 88 | } 89 | } 90 | } 91 | 92 | if (parallel.rank() == 0) 93 | { 94 | parallel.send(npart, 1); 95 | parallel.receive(count, parallel.size()-1); 96 | if (count != hdr.npart[1]) cout << " error: number of particles in saveGadget2 does not match request!" << endl; 97 | count = 0; 98 | } 99 | else 100 | { 101 | parallel.receive(count, parallel.rank()-1); 102 | npart += count; 103 | parallel.send(npart, (parallel.rank()+1)%parallel.size()); 104 | } 105 | 106 | MPI_File_open(parallel.lat_world_comm(), fname, MPI_MODE_WRONLY | MPI_MODE_CREATE, MPI_INFO_NULL, &outfile); 107 | 108 | offset_pos = (MPI_Offset) hdr.npart[1]; 109 | offset_pos *= (MPI_Offset) (6 * sizeof(float) + sizeof(long)); 110 | offset_pos += (MPI_Offset) (8 * sizeof(unsigned int) + sizeof(hdr)); 111 | MPI_File_set_size(outfile, offset_pos); 112 | 113 | offset_pos = (MPI_Offset) (3 * sizeof(unsigned int) + sizeof(hdr)) + ((MPI_Offset) count) * ((MPI_Offset) (3 * sizeof(float))); 114 | offset_vel = offset_pos + (MPI_Offset) (2 * sizeof(unsigned int)) + ((MPI_Offset) hdr.npart[1]) * ((MPI_Offset) (3 * sizeof(float))); 115 | offset_ID = offset_vel + (MPI_Offset) (2 * sizeof(unsigned int)) + ((MPI_Offset) hdr.npart[1] - (MPI_Offset) count) * ((MPI_Offset) (3 * sizeof(float))) + ((MPI_Offset) count) * ((MPI_Offset) sizeof(long)); 116 | 117 | if (parallel.rank() == 0) 118 | { 119 | blocksize = sizeof(hdr); 120 | MPI_File_write_at(outfile, 0, &blocksize, 1, MPI_UNSIGNED, &status); 121 | MPI_File_write_at(outfile, sizeof(unsigned int), &hdr, sizeof(hdr), MPI_BYTE, &status); 122 | MPI_File_write_at(outfile, sizeof(hdr) + sizeof(unsigned int), &blocksize, 1, MPI_UNSIGNED, &status); 123 | blocksize = 3 * sizeof(float) * hdr.npart[1]; 124 | MPI_File_write_at(outfile, sizeof(hdr) + 2*sizeof(unsigned int), &blocksize, 1, MPI_UNSIGNED, &status); 125 | MPI_File_write_at(outfile, offset_vel - 2*sizeof(unsigned int), &blocksize, 1, MPI_UNSIGNED, &status); 126 | MPI_File_write_at(outfile, offset_vel - sizeof(unsigned int), &blocksize, 1, MPI_UNSIGNED, &status); 127 | MPI_File_write_at(outfile, offset_ID - 2*sizeof(unsigned int), &blocksize, 1, MPI_UNSIGNED, &status); 128 | blocksize = sizeof(long) * hdr.npart[1]; 129 | MPI_File_write_at(outfile, offset_ID - sizeof(unsigned int), &blocksize, 1, MPI_UNSIGNED, &status); 130 | MPI_File_write_at(outfile, offset_ID + blocksize, &blocksize, 1, MPI_UNSIGNED, &status); 131 | } 132 | 133 | count = 0; 134 | for(xPart.first(); xPart.test(); xPart.next()) 135 | { 136 | if(this->field_part_(xPart).size!=0) 137 | { 138 | for (it=(this->field_part_)(xPart).parts.begin(); it != (this->field_part_)(xPart).parts.end(); ++it) 139 | { 140 | if ((*it).ID % tracer_factor == 0) 141 | { 142 | for (i = 0; i < 3; i++) 143 | posdata[3*count+i] = (*it).pos[i] * hdr.BoxSize; 144 | 145 | for (i = 0; i < 3; i++) 146 | veldata[3*count+i] = (*it).vel[i] * rescale_vel / sqrt(hdr.time * hdr.time + (*it).vel[0] * (*it).vel[0] + (*it).vel[1] * (*it).vel[1] + (*it).vel[2] * (*it).vel[2]); 147 | 148 | IDs[count] = (*it).ID; 149 | 150 | count++; 151 | 152 | if (count == PCLBUFFER) 153 | { 154 | MPI_File_write_at(outfile, offset_pos, posdata, 3 * count, MPI_FLOAT, &status); 155 | offset_pos += 3 * PCLBUFFER * sizeof(float); 156 | MPI_File_write_at(outfile, offset_vel, veldata, 3 * count, MPI_FLOAT, &status); 157 | offset_vel += 3 * PCLBUFFER * sizeof(float); 158 | MPI_File_write_at(outfile, offset_ID, IDs, count, MPI_LONG, &status); 159 | offset_ID += PCLBUFFER * sizeof(long); 160 | count = 0; 161 | } 162 | } 163 | } 164 | } 165 | } 166 | 167 | if (count > 0) 168 | { 169 | MPI_File_write_at(outfile, offset_pos, posdata, 3 * count, MPI_FLOAT, &status); 170 | MPI_File_write_at(outfile, offset_vel, veldata, 3 * count, MPI_FLOAT, &status); 171 | MPI_File_write_at(outfile, offset_ID, IDs, count, MPI_LONG, &status); 172 | } 173 | 174 | MPI_File_close(&outfile); 175 | 176 | free(posdata); 177 | free(veldata); 178 | free(IDs); 179 | } 180 | 181 | #endif 182 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # gevolution-1.0 (archived) 2 | 3 | *This repository has been archived, please refer to the most recent code release* 4 | 5 | Copyright (c) 2015-2016 Julian Adamek 6 | (Université de Genève & Observatoire de Paris) 7 | 8 | Permission is hereby granted, free of charge, to any person obtaining a copy 9 | of this software and associated documentation files (the "Software"), to deal 10 | in the Software without restriction, including without limitation the rights 11 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 12 | copies of the Software, and to permit persons to whom the Software is 13 | furnished to do so, subject to the following conditions: 14 | 15 | The above copyright notice and this permission notice shall be included in 16 | all copies or substantial portions of the Software. 17 | 18 | **The Software is provided "as is", without warranty of any kind, expressed or 19 | implied, including but not limited to the warranties of merchantability, 20 | fitness for a particular purpose and noninfringement. In no event shall the 21 | authors or copyright holders be liable for any claim, damages or other 22 | liability, whether in an action of contact, tort or otherwise, arising from, 23 | out of or in connection with the Software or the use or other dealings in 24 | the Software.** 25 | 26 | ## Compilation and usage 27 | 28 | Before compilation, make sure that all required external libraries are 29 | installed: 30 | 31 | * LATfield2 [version 1.1](https://github.com/daverio/LATfield2.git) 32 | * FFTW version 3 33 | * GNU Scientific Library (GSL) including CBLAS 34 | * HDF5 35 | 36 | Make sure that the include paths are set properly, or add them to the 37 | makefile. Also check the compiler settings in the makefile. The code is 38 | compiled by typing: 39 | 40 | make 41 | 42 | A typical command to run a simulation looks like this: 43 | 44 | mpirun -np 16 ./gevolution -n 4 -m 4 -s settings.ini 45 | 46 | For further information, please refer to the User Manual (manual.pdf) 47 | 48 | ## Credits 49 | 50 | If you use gevolution for scientific work, we kindly ask you to cite 51 | *Adamek J., Daverio D., Durrer R., and Kunz M., Nature Phys. 12, 346 (2016)* 52 | in your publications. 53 | 54 | For bug reports and other important feedback you can contact the authors, 55 | julian.adamek@obspm.fr (for queries related to gevolution) 56 | developers@latfield.org (for queries related to the LATfield2 library) 57 | 58 | -------------------------------------------------------------------------------- /background.hpp: -------------------------------------------------------------------------------- 1 | ////////////////////////// 2 | // background.hpp 3 | ////////////////////////// 4 | // 5 | // code components related to background evolution 6 | // 7 | // Author: Julian Adamek (Université de Genève) 8 | // 9 | // Last modified: February 2016 10 | // 11 | ////////////////////////// 12 | 13 | #ifndef BACKGROUND_HEADER 14 | #define BACKGROUND_HEADER 15 | 16 | #include 17 | 18 | double FermiDiracIntegrand(double q, void * w) 19 | { 20 | return q * q * sqrt(q * q + *(double *)w) / (exp(q) + 1.0l); 21 | } 22 | 23 | double FermiDiracIntegral(double &w) 24 | { 25 | double result; 26 | gsl_function f; 27 | double err; 28 | size_t n; 29 | 30 | f.function = &FermiDiracIntegrand; 31 | f.params = &w; 32 | 33 | gsl_integration_qng(&f, 0.0l, 24.0l, 5.0e-7, 1.0e-7, &result, &err, &n); 34 | 35 | return result; 36 | } 37 | 38 | 39 | ////////////////////////// 40 | // bg_ncdm 41 | ////////////////////////// 42 | // Description: 43 | // computes the background model for ncdm species by integrating the relativistic 44 | // Fermi-Dirac distribution 45 | // 46 | // Arguments: 47 | // a scale factor at which to compute the background model 48 | // cosmo structure containing the cosmological parameters 49 | // 50 | // Note: 51 | // For optimization, the last value of a is stored in a static variable such that 52 | // multiple calls at the same value of a will not result in multiple integrations 53 | // being carried out. This assumes that the cosmological model should not change! 54 | // 55 | // Returns: value for the background model 56 | // 57 | ////////////////////////// 58 | 59 | double bg_ncdm(const double a, const cosmology cosmo) 60 | { 61 | double w; 62 | static double result = -1.0; 63 | static double a_prev = -1.0; 64 | 65 | if (a != a_prev) 66 | { 67 | result = 0.0; 68 | a_prev = a; 69 | 70 | for (int p = 0; p < cosmo.num_ncdm; p++) 71 | { 72 | w = a * cosmo.m_ncdm[p] / (pow(cosmo.Omega_g * cosmo.h * cosmo.h / 4.48147e-7, 0.25) * cosmo.T_ncdm[p] * 8.61733e-5); 73 | w *= w; 74 | 75 | result += FermiDiracIntegral(w) * cosmo.Omega_ncdm[p] * pow(cosmo.Omega_g * cosmo.h * cosmo.h / 4.48147e-7, 0.25) * cosmo.T_ncdm[p] * 4.77921357e-5 / cosmo.m_ncdm[p]; 76 | } 77 | } 78 | 79 | return result / a; 80 | } 81 | 82 | 83 | ////////////////////////// 84 | // Hconf 85 | ////////////////////////// 86 | // Description: 87 | // computes the conformal Hubble rate at given scale factor 88 | // 89 | // Arguments: 90 | // a scale factor 91 | // fourpiG "4 pi G" 92 | // cosmo structure containing the cosmological parameters 93 | // 94 | // Returns: conformal Hubble rate 95 | // 96 | ////////////////////////// 97 | 98 | double Hconf(const double a, const double fourpiG, const cosmology cosmo) 99 | { 100 | return sqrt((2. * fourpiG / 3.) * (((cosmo.Omega_cdm + cosmo.Omega_b + bg_ncdm(a, cosmo)) / a) + (cosmo.Omega_Lambda * a * a) + (cosmo.Omega_rad / a / a))); 101 | } 102 | 103 | 104 | double Omega_m(const double a, const cosmology cosmo) { return cosmo.Omega_m / (cosmo.Omega_cdm + cosmo.Omega_b + bg_ncdm(a, cosmo) + cosmo.Omega_Lambda * a * a * a + cosmo.Omega_rad / a); } 105 | 106 | double Omega_rad(const double a, const cosmology cosmo) { return (cosmo.Omega_rad + (bg_ncdm(a, cosmo) + cosmo.Omega_cdm + cosmo.Omega_b - cosmo.Omega_m) * a) / ((cosmo.Omega_cdm + cosmo.Omega_b + bg_ncdm(a, cosmo)) * a + cosmo.Omega_Lambda * a * a * a * a + cosmo.Omega_rad); } 107 | 108 | double Omega_Lambda(const double a, const cosmology cosmo) { return cosmo.Omega_Lambda / ((cosmo.Omega_cdm + cosmo.Omega_b + bg_ncdm(a, cosmo)) / a / a / a + cosmo.Omega_Lambda + cosmo.Omega_rad / a / a / a / a); } 109 | 110 | 111 | ////////////////////////// 112 | // rungekutta4bg 113 | ////////////////////////// 114 | // Description: 115 | // integrates the Friedmann equation for the background model using a fourth-order 116 | // Runge-Kutta method 117 | // 118 | // Arguments: 119 | // a scale factor (will be advanced by dtau) 120 | // fourpiG "4 pi G" 121 | // cosmo structure containing the cosmological parameters 122 | // dtau time step by which the scale factor should be advanced 123 | // 124 | // Returns: 125 | // 126 | ////////////////////////// 127 | 128 | void rungekutta4bg(double &a, const double fourpiG, const cosmology cosmo, const double dtau) 129 | { 130 | double k1a, k2a, k3a, k4a; 131 | 132 | k1a = a * Hconf(a, fourpiG, cosmo); 133 | k2a = (a + k1a * dtau / 2.) * Hconf(a + k1a * dtau / 2., fourpiG, cosmo); 134 | k3a = (a + k2a * dtau / 2.) * Hconf(a + k2a * dtau / 2., fourpiG, cosmo); 135 | k4a = (a + k3a * dtau) * Hconf(a + k3a * dtau, fourpiG, cosmo); 136 | 137 | a += dtau * (k1a + 2. * k2a + 2. * k3a + k4a) / 6.; 138 | } 139 | 140 | #endif 141 | 142 | -------------------------------------------------------------------------------- /bcc_crystal.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gevolution-code/gevolution-1.0/0906a1e1ec2c955470f10dd53ec03f1aa19021e4/bcc_crystal.dat -------------------------------------------------------------------------------- /fcc_crystal.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gevolution-code/gevolution-1.0/0906a1e1ec2c955470f10dd53ec03f1aa19021e4/fcc_crystal.dat -------------------------------------------------------------------------------- /gevolution.hpp: -------------------------------------------------------------------------------- 1 | ////////////////////////// 2 | // gevolution.hpp 3 | ////////////////////////// 4 | // 5 | // Geneva algorithms for evolution of metric perturbations 6 | // and relativistic free-streaming particles (gevolution) 7 | // 8 | // 1. Suite of Fourier-based methods for the computation of the 9 | // relativistic scalar (Phi, Phi-Psi) and vector modes [see J. Adamek, 10 | // R. Durrer, and M. Kunz, Class. Quant. Grav. 31, 234006 (2014)] 11 | // 12 | // 2. Collection of "update position" and "update velocity/momentum" 13 | // methods [see J. Adamek, D. Daverio, R. Durrer, and M. Kunz, in preparation] 14 | // 15 | // 3. Collection of projection methods for the construction of the 16 | // stress-energy-tensor 17 | // 18 | // Author: Julian Adamek (Université de Genève) 19 | // 20 | // Last modified: February 2016 21 | // 22 | ////////////////////////// 23 | 24 | #ifndef GEVOLUTION_HEADER 25 | #define GEVOLUTION_HEADER 26 | 27 | #ifndef Cplx 28 | #define Cplx Imag 29 | #endif 30 | 31 | using namespace std; 32 | using namespace LATfield2; 33 | 34 | 35 | ////////////////////////// 36 | // prepareFTsource (1) 37 | ////////////////////////// 38 | // Description: 39 | // construction of real-space source tensor for Fourier-based solvers 40 | // 41 | // Arguments: 42 | // phi reference to field configuration 43 | // Tij reference to symmetric tensor field containing the space-space 44 | // components of the stress-energy tensor (rescaled by a^3) 45 | // Sij reference to allocated symmetric tensor field which will contain 46 | // the source tensor (may be identical to Tji) 47 | // coeff scaling coefficient for Tij ("8 pi G dx^2 / a") 48 | // 49 | // Returns: 50 | // 51 | ////////////////////////// 52 | 53 | template 54 | void prepareFTsource(Field & phi, Field & Tij, Field & Sij, const double coeff) 55 | { 56 | Site x(phi.lattice()); 57 | 58 | for (x.first(); x.test(); x.next()) 59 | { 60 | // 0-0-component: 61 | Sij(x, 0, 0) = coeff * Tij(x, 0, 0); 62 | #ifdef PHINONLINEAR 63 | Sij(x, 0, 0) -= 4. * phi(x) * (phi(x-0) + phi(x+0) - 2. * phi(x)); 64 | Sij(x, 0, 0) -= 0.5 * (phi(x+0) - phi(x-0)) * (phi(x+0) - phi(x-0)); 65 | #endif 66 | 67 | // 1-1-component: 68 | Sij(x, 1, 1) = coeff * Tij(x, 1, 1); 69 | #ifdef PHINONLINEAR 70 | Sij(x, 1, 1) -= 4. * phi(x) * (phi(x-1) + phi(x+1) - 2. * phi(x)); 71 | Sij(x, 1, 1) -= 0.5 * (phi(x+1) - phi(x-1)) * (phi(x+1) - phi(x-1)); 72 | #endif 73 | 74 | // 2-2-component: 75 | Sij(x, 2, 2) = coeff * Tij(x, 2, 2); 76 | #ifdef PHINONLINEAR 77 | Sij(x, 2, 2) -= 4. * phi(x) * (phi(x-2) + phi(x+2) - 2. * phi(x)); 78 | Sij(x, 2, 2) -= 0.5 * (phi(x+2) - phi(x-2)) * (phi(x+2) - phi(x-2)); 79 | #endif 80 | 81 | // 0-1-component: 82 | Sij(x, 0, 1) = coeff * Tij(x, 0, 1); 83 | #ifdef PHINONLINEAR 84 | Sij(x, 0, 1) += phi(x+0) * phi(x+1) - phi(x) * phi(x+0+1); 85 | Sij(x, 0, 1) -= 1.5 * phi(x) * phi(x); 86 | Sij(x, 0, 1) += 1.5 * phi(x+0) * phi(x+0); 87 | Sij(x, 0, 1) += 1.5 * phi(x+1) * phi(x+1); 88 | Sij(x, 0, 1) -= 1.5 * phi(x+0+1) * phi(x+0+1); 89 | #endif 90 | 91 | // 0-2-component: 92 | Sij(x, 0, 2) = coeff * Tij(x, 0, 2); 93 | #ifdef PHINONLINEAR 94 | Sij(x, 0, 2) += phi(x+0) * phi(x+2) - phi(x) * phi(x+0+2); 95 | Sij(x, 0, 2) -= 1.5 * phi(x) * phi(x); 96 | Sij(x, 0, 2) += 1.5 * phi(x+0) * phi(x+0); 97 | Sij(x, 0, 2) += 1.5 * phi(x+2) * phi(x+2); 98 | Sij(x, 0, 2) -= 1.5 * phi(x+0+2) * phi(x+0+2); 99 | #endif 100 | 101 | // 1-2-component: 102 | Sij(x, 1, 2) = coeff * Tij(x, 1, 2); 103 | #ifdef PHINONLINEAR 104 | Sij(x, 1, 2) += phi(x+1) * phi(x+2) - phi(x) * phi(x+1+2); 105 | Sij(x, 1, 2) -= 1.5 * phi(x) * phi(x); 106 | Sij(x, 1, 2) += 1.5 * phi(x+1) * phi(x+1); 107 | Sij(x, 1, 2) += 1.5 * phi(x+2) * phi(x+2); 108 | Sij(x, 1, 2) -= 1.5 * phi(x+1+2) * phi(x+1+2); 109 | #endif 110 | } 111 | } 112 | 113 | ////////////////////////// 114 | // prepareFTsource (2) 115 | ////////////////////////// 116 | // Description: 117 | // construction of real-space source field for Fourier-based solvers 118 | // 119 | // Arguments: 120 | // phi reference to field configuration (first Bardeen potential) 121 | // psi reference to field configuration (second Bardeen potential) 122 | // source reference to fully dressed source field (rescaled by a^3) 123 | // bgmodel background model of the source (rescaled by a^3) to be subtracted 124 | // result reference to allocated field which will contain the result (may be identical to source) 125 | // coeff diffusion coefficient ("3 H_conformal dx^2 / dtau") 126 | // coeff2 scaling coefficient for the source ("4 pi G dx^2 / a") 127 | // coeff3 scaling coefficient for the psi-term ("3 H_conformal^2 dx^2") 128 | // 129 | // Returns: 130 | // 131 | ////////////////////////// 132 | 133 | template 134 | void prepareFTsource(Field & phi, Field & psi, Field & source, const FieldType bgmodel, Field & result, const double coeff, const double coeff2, const double coeff3) 135 | { 136 | Site x(phi.lattice()); 137 | 138 | for (x.first(); x.test(); x.next()) 139 | { 140 | result(x) = coeff2 * (source(x) - bgmodel); 141 | #ifdef PHINONLINEAR 142 | result(x) *= 1. - 4. * phi(x); 143 | result(x) -= 0.375 * (phi(x-0) - phi(x+0)) * (phi(x-0) - phi(x+0)); 144 | result(x) -= 0.375 * (phi(x-1) - phi(x+1)) * (phi(x-1) - phi(x+1)); 145 | result(x) -= 0.375 * (phi(x-2) - phi(x+2)) * (phi(x-2) - phi(x+2)); 146 | #endif 147 | result(x) += coeff3 * psi(x) - coeff * phi(x); 148 | } 149 | } 150 | 151 | 152 | #ifdef FFT3D 153 | ////////////////////////// 154 | // projectFTscalar 155 | ////////////////////////// 156 | // Description: 157 | // projection of the Fourier image of a tensor field on the trace-free 158 | // longitudinal (scalar) component 159 | // 160 | // Arguments: 161 | // SijFT reference to the Fourier image of the input tensor field 162 | // chiFT reference to allocated field which will contain the Fourier 163 | // image of the trace-free longitudinal (scalar) component 164 | // 165 | // Returns: 166 | // 167 | ////////////////////////// 168 | 169 | void projectFTscalar(Field & SijFT, Field & chiFT) 170 | { 171 | const int linesize = chiFT.lattice().size(1); 172 | int i; 173 | Real * gridk2; 174 | Cplx * kshift; 175 | rKSite k(chiFT.lattice()); 176 | 177 | gridk2 = (Real *) malloc(linesize * sizeof(Real)); 178 | kshift = (Cplx *) malloc(linesize * sizeof(Cplx)); 179 | 180 | for (i = 0; i < linesize; i++) 181 | { 182 | gridk2[i] = 2. * (Real) linesize * sin(M_PI * (Real) i / (Real) linesize); 183 | kshift[i] = gridk2[i] * Cplx(cos(M_PI * (Real) i / (Real) linesize), -sin(M_PI * (Real) i / (Real) linesize)); 184 | gridk2[i] *= gridk2[i]; 185 | } 186 | 187 | k.first(); 188 | if (k.coord(0) == 0 && k.coord(1) == 0 && k.coord(2) == 0) 189 | { 190 | chiFT(k) = Cplx(0.,0.); 191 | k.next(); 192 | } 193 | 194 | for (; k.test(); k.next()) 195 | { 196 | chiFT(k) = ((gridk2[k.coord(1)] + gridk2[k.coord(2)] - 2. * gridk2[k.coord(0)]) * SijFT(k, 0, 0) + 197 | (gridk2[k.coord(0)] + gridk2[k.coord(2)] - 2. * gridk2[k.coord(1)]) * SijFT(k, 1, 1) + 198 | (gridk2[k.coord(0)] + gridk2[k.coord(1)] - 2. * gridk2[k.coord(2)]) * SijFT(k, 2, 2) - 199 | 6. * kshift[k.coord(0)] * kshift[k.coord(1)] * SijFT(k, 0, 1) - 200 | 6. * kshift[k.coord(0)] * kshift[k.coord(2)] * SijFT(k, 0, 2) - 201 | 6. * kshift[k.coord(1)] * kshift[k.coord(2)] * SijFT(k, 1, 2)) / 202 | (2. * (gridk2[k.coord(0)] + gridk2[k.coord(1)] + gridk2[k.coord(2)]) * (gridk2[k.coord(0)] + gridk2[k.coord(1)] + gridk2[k.coord(2)]) * linesize); 203 | } 204 | 205 | free(gridk2); 206 | free(kshift); 207 | } 208 | 209 | 210 | ////////////////////////// 211 | // evolveFTvector 212 | ////////////////////////// 213 | // Description: 214 | // projects the Fourier image of a tensor field on the spin-1 component 215 | // used as a source for the evolution of the vector perturbation 216 | // 217 | // Arguments: 218 | // SijFT reference to the Fourier image of the input tensor field 219 | // BiFT reference to the Fourier image of the vector perturbation 220 | // a2dtau conformal time step times scale factor squared (a^2 * dtau) 221 | // 222 | // Returns: 223 | // 224 | ////////////////////////// 225 | 226 | void evolveFTvector(Field & SijFT, Field & BiFT, const Real a2dtau) 227 | { 228 | const int linesize = BiFT.lattice().size(1); 229 | int i; 230 | Real * gridk2; 231 | Cplx * kshift; 232 | rKSite k(BiFT.lattice()); 233 | Real k4; 234 | 235 | gridk2 = (Real *) malloc(linesize * sizeof(Real)); 236 | kshift = (Cplx *) malloc(linesize * sizeof(Cplx)); 237 | 238 | for (i = 0; i < linesize; i++) 239 | { 240 | gridk2[i] = 2. * (Real) linesize * sin(M_PI * (Real) i / (Real) linesize); 241 | kshift[i] = gridk2[i] * Cplx(cos(M_PI * (Real) i / (Real) linesize), -sin(M_PI * (Real) i / (Real) linesize)); 242 | gridk2[i] *= gridk2[i]; 243 | } 244 | 245 | k.first(); 246 | if (k.coord(0) == 0 && k.coord(1) == 0 && k.coord(2) == 0) 247 | { 248 | BiFT(k, 0) = Cplx(0.,0.); 249 | BiFT(k, 1) = Cplx(0.,0.); 250 | BiFT(k, 2) = Cplx(0.,0.); 251 | k.next(); 252 | } 253 | 254 | for (; k.test(); k.next()) 255 | { 256 | k4 = gridk2[k.coord(0)] + gridk2[k.coord(1)] + gridk2[k.coord(2)]; 257 | k4 *= k4; 258 | 259 | BiFT(k, 0) += Cplx(0.,-2.*a2dtau/k4) * (kshift[k.coord(0)].conj() * ((gridk2[k.coord(1)] + gridk2[k.coord(2)]) * SijFT(k, 0, 0) 260 | - gridk2[k.coord(1)] * SijFT(k, 1, 1) - gridk2[k.coord(2)] * SijFT(k, 2, 2) - 2. * kshift[k.coord(1)] * kshift[k.coord(2)] * SijFT(k, 1, 2)) 261 | + (gridk2[k.coord(1)] + gridk2[k.coord(2)] - gridk2[k.coord(0)]) * (kshift[k.coord(1)] * SijFT(k, 0, 1) + kshift[k.coord(2)] * SijFT(k, 0, 2))); 262 | BiFT(k, 1) += Cplx(0.,-2.*a2dtau/k4) * (kshift[k.coord(1)].conj() * ((gridk2[k.coord(0)] + gridk2[k.coord(2)]) * SijFT(k, 1, 1) 263 | - gridk2[k.coord(0)] * SijFT(k, 0, 0) - gridk2[k.coord(2)] * SijFT(k, 2, 2) - 2. * kshift[k.coord(0)] * kshift[k.coord(2)] * SijFT(k, 0, 2)) 264 | + (gridk2[k.coord(0)] + gridk2[k.coord(2)] - gridk2[k.coord(1)]) * (kshift[k.coord(0)] * SijFT(k, 0, 1) + kshift[k.coord(2)] * SijFT(k, 1, 2))); 265 | BiFT(k, 2) += Cplx(0.,-2.*a2dtau/k4) * (kshift[k.coord(2)].conj() * ((gridk2[k.coord(0)] + gridk2[k.coord(1)]) * SijFT(k, 2, 2) 266 | - gridk2[k.coord(0)] * SijFT(k, 0, 0) - gridk2[k.coord(1)] * SijFT(k, 1, 1) - 2. * kshift[k.coord(0)] * kshift[k.coord(1)] * SijFT(k, 0, 1)) 267 | + (gridk2[k.coord(0)] + gridk2[k.coord(1)] - gridk2[k.coord(2)]) * (kshift[k.coord(0)] * SijFT(k, 0, 2) + kshift[k.coord(1)] * SijFT(k, 1, 2))); 268 | } 269 | 270 | free(gridk2); 271 | free(kshift); 272 | } 273 | 274 | 275 | ////////////////////////// 276 | // projectFTvector 277 | ////////////////////////// 278 | // Description: 279 | // projects the Fourier image of a vector field on the transverse component 280 | // and solves the constraint equation for the vector perturbation 281 | // 282 | // Arguments: 283 | // SiFT reference to the Fourier image of the input vector field 284 | // BiFT reference to the Fourier image of the vector perturbation (can be identical to input) 285 | // coeff rescaling coefficient (default 1) 286 | // modif modification k^2 -> k^2 + modif (default 0) 287 | // 288 | // Returns: 289 | // 290 | ////////////////////////// 291 | 292 | void projectFTvector(Field & SiFT, Field & BiFT, const Real coeff = 1., const Real modif = 0.) 293 | { 294 | const int linesize = BiFT.lattice().size(1); 295 | int i; 296 | Real * gridk2; 297 | Cplx * kshift; 298 | rKSite k(BiFT.lattice()); 299 | Real k2; 300 | Cplx tmp(0., 0.); 301 | 302 | gridk2 = (Real *) malloc(linesize * sizeof(Real)); 303 | kshift = (Cplx *) malloc(linesize * sizeof(Cplx)); 304 | 305 | for (i = 0; i < linesize; i++) 306 | { 307 | gridk2[i] = 2. * (Real) linesize * sin(M_PI * (Real) i / (Real) linesize); 308 | kshift[i] = gridk2[i] * Cplx(cos(M_PI * (Real) i / (Real) linesize), -sin(M_PI * (Real) i / (Real) linesize)); 309 | gridk2[i] *= gridk2[i]; 310 | } 311 | 312 | k.first(); 313 | if (k.coord(0) == 0 && k.coord(1) == 0 && k.coord(2) == 0) 314 | { 315 | BiFT(k, 0) = Cplx(0.,0.); 316 | BiFT(k, 1) = Cplx(0.,0.); 317 | BiFT(k, 2) = Cplx(0.,0.); 318 | k.next(); 319 | } 320 | 321 | for (; k.test(); k.next()) 322 | { 323 | k2 = gridk2[k.coord(0)] + gridk2[k.coord(1)] + gridk2[k.coord(2)]; 324 | 325 | tmp = (kshift[k.coord(0)] * SiFT(k, 0) + kshift[k.coord(1)] * SiFT(k, 1) + kshift[k.coord(2)] * SiFT(k, 2)) / k2; 326 | 327 | BiFT(k, 0) = (SiFT(k, 0) - kshift[k.coord(0)].conj() * tmp) * 4. * coeff / (k2 + modif); 328 | BiFT(k, 1) = (SiFT(k, 1) - kshift[k.coord(1)].conj() * tmp) * 4. * coeff / (k2 + modif); 329 | BiFT(k, 2) = (SiFT(k, 2) - kshift[k.coord(2)].conj() * tmp) * 4. * coeff / (k2 + modif); 330 | } 331 | 332 | free(gridk2); 333 | free(kshift); 334 | } 335 | 336 | 337 | ////////////////////////// 338 | // projectFTtensor 339 | ////////////////////////// 340 | // Description: 341 | // projection of the Fourier image of a tensor field on the transverse 342 | // trace-free tensor component 343 | // 344 | // Arguments: 345 | // SijFT reference to the Fourier image of the input tensor field 346 | // hijFT reference to allocated field which will contain the Fourier 347 | // image of the transverse trace-free tensor component 348 | // 349 | // Returns: 350 | // 351 | ////////////////////////// 352 | 353 | void projectFTtensor(Field & SijFT, Field & hijFT) 354 | { 355 | const int linesize = hijFT.lattice().size(1); 356 | int i; 357 | Real * gridk2; 358 | Cplx * kshift; 359 | rKSite k(hijFT.lattice()); 360 | Cplx SxxFT, SxyFT, SxzFT, SyyFT, SyzFT, SzzFT; 361 | Real k2, k6; 362 | 363 | gridk2 = (Real *) malloc(linesize * sizeof(Real)); 364 | kshift = (Cplx *) malloc(linesize * sizeof(Cplx)); 365 | 366 | for (i = 0; i < linesize; i++) 367 | { 368 | gridk2[i] = 2. * (Real) linesize * sin(M_PI * (Real) i / (Real) linesize); 369 | kshift[i] = gridk2[i] * Cplx(cos(M_PI * (Real) i / (Real) linesize), -sin(M_PI * (Real) i / (Real) linesize)); 370 | gridk2[i] *= gridk2[i]; 371 | } 372 | 373 | k.first(); 374 | if (k.coord(0) == 0 && k.coord(1) == 0 && k.coord(2) == 0) 375 | { 376 | for (i = 0; i < hijFT.components(); i++) 377 | hijFT(k, i) = Cplx(0.,0.); 378 | 379 | k.next(); 380 | } 381 | 382 | for (; k.test(); k.next()) 383 | { 384 | SxxFT = SijFT(k, 0, 0); 385 | SxyFT = SijFT(k, 0, 1); 386 | SxzFT = SijFT(k, 0, 2); 387 | SyyFT = SijFT(k, 1, 1); 388 | SyzFT = SijFT(k, 1, 2); 389 | SzzFT = SijFT(k, 2, 2); 390 | 391 | k2 = gridk2[k.coord(0)] + gridk2[k.coord(1)] + gridk2[k.coord(2)]; 392 | k6 = k2 * k2 * k2 * linesize; 393 | 394 | hijFT(k, 0, 0) = ((gridk2[k.coord(0)] - k2) * ((gridk2[k.coord(0)] - k2) * SxxFT + 2. * kshift[k.coord(0)] * (kshift[k.coord(1)] * SxyFT + kshift[k.coord(2)] * SxzFT)) 395 | + ((gridk2[k.coord(0)] + k2) * (gridk2[k.coord(1)] + k2) - 2. * k2 * k2) * SyyFT 396 | + ((gridk2[k.coord(0)] + k2) * (gridk2[k.coord(2)] + k2) - 2. * k2 * k2) * SzzFT 397 | + 2. * (gridk2[k.coord(0)] + k2) * kshift[k.coord(1)] * kshift[k.coord(2)] * SyzFT) / k6; 398 | 399 | hijFT(k, 0, 1) = (2. * (gridk2[k.coord(0)] - k2) * (gridk2[k.coord(1)] - k2) * SxyFT + (gridk2[k.coord(2)] + k2) * kshift[k.coord(0)].conj() * kshift[k.coord(1)].conj() * SzzFT 400 | + (gridk2[k.coord(0)] - k2) * kshift[k.coord(1)].conj() * (kshift[k.coord(0)].conj() * SxxFT + 2. * kshift[k.coord(2)] * SxzFT) 401 | + (gridk2[k.coord(1)] - k2) * kshift[k.coord(0)].conj() * (kshift[k.coord(1)].conj() * SyyFT + 2. * kshift[k.coord(2)] * SyzFT)) / k6; 402 | 403 | hijFT(k, 0, 2) = (2. * (gridk2[k.coord(0)] - k2) * (gridk2[k.coord(2)] - k2) * SxzFT + (gridk2[k.coord(1)] + k2) * kshift[k.coord(0)].conj() * kshift[k.coord(2)].conj() * SyyFT 404 | + (gridk2[k.coord(0)] - k2) * kshift[k.coord(2)].conj() * (kshift[k.coord(0)].conj() * SxxFT + 2. * kshift[k.coord(1)] * SxyFT) 405 | + (gridk2[k.coord(2)] - k2) * kshift[k.coord(0)].conj() * (kshift[k.coord(2)].conj() * SzzFT + 2. * kshift[k.coord(1)] * SyzFT)) / k6; 406 | 407 | hijFT(k, 1, 1) = ((gridk2[k.coord(1)] - k2) * ((gridk2[k.coord(1)] - k2) * SyyFT + 2. * kshift[k.coord(1)] * (kshift[k.coord(0)] * SxyFT + kshift[k.coord(2)] * SyzFT)) 408 | + ((gridk2[k.coord(1)] + k2) * (gridk2[k.coord(0)] + k2) - 2. * k2 * k2) * SxxFT 409 | + ((gridk2[k.coord(1)] + k2) * (gridk2[k.coord(2)] + k2) - 2. * k2 * k2) * SzzFT 410 | + 2. * (gridk2[k.coord(1)] + k2) * kshift[k.coord(0)] * kshift[k.coord(2)] * SxzFT) / k6; 411 | 412 | hijFT(k, 1, 2) = (2. * (gridk2[k.coord(1)] - k2) * (gridk2[k.coord(2)] - k2) * SyzFT + (gridk2[k.coord(0)] + k2) * kshift[k.coord(1)].conj() * kshift[k.coord(2)].conj() * SxxFT 413 | + (gridk2[k.coord(1)] - k2) * kshift[k.coord(2)].conj() * (kshift[k.coord(1)].conj() * SyyFT + 2. * kshift[k.coord(0)] * SxyFT) 414 | + (gridk2[k.coord(2)] - k2) * kshift[k.coord(1)].conj() * (kshift[k.coord(2)].conj() * SzzFT + 2. * kshift[k.coord(0)] * SxzFT)) / k6; 415 | 416 | hijFT(k, 2, 2) = ((gridk2[k.coord(2)] - k2) * ((gridk2[k.coord(2)] - k2) * SzzFT + 2. * kshift[k.coord(2)] * (kshift[k.coord(0)] * SxzFT + kshift[k.coord(1)] * SyzFT)) 417 | + ((gridk2[k.coord(2)] + k2) * (gridk2[k.coord(0)] + k2) - 2. * k2 * k2) * SxxFT 418 | + ((gridk2[k.coord(2)] + k2) * (gridk2[k.coord(1)] + k2) - 2. * k2 * k2) * SyyFT 419 | + 2. * (gridk2[k.coord(2)] + k2) * kshift[k.coord(0)] * kshift[k.coord(1)] * SxyFT) / k6; 420 | } 421 | 422 | free(gridk2); 423 | free(kshift); 424 | } 425 | 426 | 427 | ////////////////////////// 428 | // solveModifiedPoissonFT 429 | ////////////////////////// 430 | // Description: 431 | // Modified Poisson solver using the standard Fourier method 432 | // 433 | // Arguments: 434 | // sourceFT reference to the Fourier image of the source field 435 | // potFT reference to the Fourier image of the potential 436 | // coeff coefficient applied to the source ("4 pi G / a") 437 | // modif modification k^2 -> k^2 + modif (default 0 gives standard Poisson equation) 438 | // 439 | // Returns: 440 | // 441 | ////////////////////////// 442 | 443 | void solveModifiedPoissonFT(Field & sourceFT, Field & potFT, Real coeff, const Real modif = 0.) 444 | { 445 | const int linesize = potFT.lattice().size(1); 446 | int i; 447 | Real * gridk2; 448 | Real * sinc; 449 | rKSite k(potFT.lattice()); 450 | 451 | gridk2 = (Real *) malloc(linesize * sizeof(Real)); 452 | 453 | coeff /= -((long) linesize * (long) linesize * (long) linesize); 454 | 455 | for (i = 0; i < linesize; i++) 456 | { 457 | gridk2[i] = 2. * (Real) linesize * sin(M_PI * (Real) i / (Real) linesize); 458 | gridk2[i] *= gridk2[i]; 459 | } 460 | 461 | k.first(); 462 | if (k.coord(0) == 0 && k.coord(1) == 0 && k.coord(2) == 0) 463 | { 464 | if (modif == 0.) 465 | potFT(k) = Cplx(0.,0.); 466 | else 467 | potFT(k) = sourceFT(k) * coeff / modif; 468 | k.next(); 469 | } 470 | 471 | for (; k.test(); k.next()) 472 | { 473 | potFT(k) = sourceFT(k) * coeff / (gridk2[k.coord(0)] + gridk2[k.coord(1)] + gridk2[k.coord(2)] + modif); 474 | } 475 | 476 | free(gridk2); 477 | } 478 | #endif 479 | 480 | 481 | ////////////////////////// 482 | // update_q 483 | ////////////////////////// 484 | // Description: 485 | // Update momentum method (arbitrary momentum) 486 | // Note that vel[3] in the particle structure is used to store q[3] in units 487 | // of the particle mass, such that as q^2 << m^2 a^2 the meaning of vel[3] 488 | // is ~ v*a. 489 | // 490 | // Arguments: 491 | // dtau time step 492 | // dx lattice unit 493 | // part pointer to particle structure 494 | // ref_dist distance vector to reference point 495 | // partInfo global particle properties (unused) 496 | // fields array of pointers to fields appearing in geodesic equation 497 | // fields[0] = psi 498 | // fields[1] = phi 499 | // fields[2] = Bi 500 | // sites array of sites on the respective lattices 501 | // nfield number of fields 502 | // params array of additional parameters 503 | // params[0] = a 504 | // params[1] = scaling coefficient for Bi 505 | // outputs array of reduction variables 506 | // noutputs number of reduction variables 507 | // 508 | // Returns: squared velocity of particle after update 509 | // 510 | ////////////////////////// 511 | 512 | Real update_q(double dtau, double dx, part_simple * part, double * ref_dist, part_simple_info partInfo, Field ** fields, Site * sites, int nfield, double * params, double * outputs, int noutputs) 513 | { 514 | #define psi (fields[0]) 515 | #define phi (fields[1]) 516 | #define Bi (fields[2]) 517 | #define xpsi (sites[0]) 518 | #define xphi (sites[1]) 519 | #define xB (sites[2]) 520 | 521 | Real gradpsi[3]={0,0,0}; 522 | Real gradphi[3]={0,0,0}; 523 | Real pgradB[3]={0,0,0}; 524 | Real v2 = (*part).vel[0] * (*part).vel[0] + (*part).vel[1] * (*part).vel[1] + (*part).vel[2] * (*part).vel[2]; 525 | Real e2 = v2 + params[0] * params[0]; 526 | 527 | gradpsi[0] = (1.-ref_dist[1]) * (1.-ref_dist[2]) * ((*psi)(xpsi+0) - (*psi)(xpsi)); 528 | gradpsi[1] = (1.-ref_dist[0]) * (1.-ref_dist[2]) * ((*psi)(xpsi+1) - (*psi)(xpsi)); 529 | gradpsi[2] = (1.-ref_dist[0]) * (1.-ref_dist[1]) * ((*psi)(xpsi+2) - (*psi)(xpsi)); 530 | gradpsi[0] += ref_dist[1] * (1.-ref_dist[2]) * ((*psi)(xpsi+1+0) - (*psi)(xpsi+1)); 531 | gradpsi[1] += ref_dist[0] * (1.-ref_dist[2]) * ((*psi)(xpsi+1+0) - (*psi)(xpsi+0)); 532 | gradpsi[2] += ref_dist[0] * (1.-ref_dist[1]) * ((*psi)(xpsi+2+0) - (*psi)(xpsi+0)); 533 | gradpsi[0] += (1.-ref_dist[1]) * ref_dist[2] * ((*psi)(xpsi+2+0) - (*psi)(xpsi+2)); 534 | gradpsi[1] += (1.-ref_dist[0]) * ref_dist[2] * ((*psi)(xpsi+2+1) - (*psi)(xpsi+2)); 535 | gradpsi[2] += (1.-ref_dist[0]) * ref_dist[1] * ((*psi)(xpsi+2+1) - (*psi)(xpsi+1)); 536 | gradpsi[0] += ref_dist[1] * ref_dist[2] * ((*psi)(xpsi+2+1+0) - (*psi)(xpsi+2+1)); 537 | gradpsi[1] += ref_dist[0] * ref_dist[2] * ((*psi)(xpsi+2+1+0) - (*psi)(xpsi+2+0)); 538 | gradpsi[2] += ref_dist[0] * ref_dist[1] * ((*psi)(xpsi+2+1+0) - (*psi)(xpsi+1+0)); 539 | 540 | if (nfield>=2 && phi != NULL) 541 | { 542 | gradphi[0] = (1.-ref_dist[1]) * (1.-ref_dist[2]) * ((*phi)(xphi+0) - (*phi)(xphi)); 543 | gradphi[1] = (1.-ref_dist[0]) * (1.-ref_dist[2]) * ((*phi)(xphi+1) - (*phi)(xphi)); 544 | gradphi[2] = (1.-ref_dist[0]) * (1.-ref_dist[1]) * ((*phi)(xphi+2) - (*phi)(xphi)); 545 | gradphi[0] += ref_dist[1] * (1.-ref_dist[2]) * ((*phi)(xphi+1+0) - (*phi)(xphi+1)); 546 | gradphi[1] += ref_dist[0] * (1.-ref_dist[2]) * ((*phi)(xphi+1+0) - (*phi)(xphi+0)); 547 | gradphi[2] += ref_dist[0] * (1.-ref_dist[1]) * ((*phi)(xphi+2+0) - (*phi)(xphi+0)); 548 | gradphi[0] += (1.-ref_dist[1]) * ref_dist[2] * ((*phi)(xphi+2+0) - (*phi)(xphi+2)); 549 | gradphi[1] += (1.-ref_dist[0]) * ref_dist[2] * ((*phi)(xphi+2+1) - (*phi)(xphi+2)); 550 | gradphi[2] += (1.-ref_dist[0]) * ref_dist[1] * ((*phi)(xphi+2+1) - (*phi)(xphi+1)); 551 | gradphi[0] += ref_dist[1] * ref_dist[2] * ((*phi)(xphi+2+1+0) - (*phi)(xphi+2+1)); 552 | gradphi[1] += ref_dist[0] * ref_dist[2] * ((*phi)(xphi+2+1+0) - (*phi)(xphi+2+0)); 553 | gradphi[2] += ref_dist[0] * ref_dist[1] * ((*phi)(xphi+2+1+0) - (*phi)(xphi+1+0)); 554 | 555 | gradpsi[0] += gradphi[0] * v2 / e2; 556 | gradpsi[1] += gradphi[1] * v2 / e2; 557 | gradpsi[2] += gradphi[2] * v2 / e2; 558 | } 559 | 560 | e2 = sqrt(e2); 561 | 562 | if (nfield>=3 && Bi != NULL) 563 | { 564 | pgradB[0] = ((1.-ref_dist[2]) * ((*Bi)(xB+0,1) - (*Bi)(xB,1)) + ref_dist[2] * ((*Bi)(xB+2+0,1) - (*Bi)(xB+2,1))) * (*part).vel[1]; 565 | pgradB[0] += ((1.-ref_dist[1]) * ((*Bi)(xB+0,2) - (*Bi)(xB,2)) + ref_dist[1] * ((*Bi)(xB+1+0,2) - (*Bi)(xB+1,2))) * (*part).vel[2]; 566 | pgradB[0] += (1.-ref_dist[1]) * (1.-ref_dist[2]) * ((ref_dist[0]-1.) * (*Bi)(xB-0,0) + (1.-2.*ref_dist[0]) * (*Bi)(xB,0) + ref_dist[0] * (*Bi)(xB+0,0)) * (*part).vel[0]; 567 | pgradB[0] += ref_dist[1] * (1.-ref_dist[2]) * ((ref_dist[0]-1.) * (*Bi)(xB+1-0,0) + (1.-2.*ref_dist[0]) * (*Bi)(xB+1,0) + ref_dist[0] * (*Bi)(xB+1+0,0)) * (*part).vel[0]; 568 | pgradB[0] += (1.-ref_dist[1]) * ref_dist[2] * ((ref_dist[0]-1.) * (*Bi)(xB+2-0,0) + (1.-2.*ref_dist[0]) * (*Bi)(xB+2,0) + ref_dist[0] * (*Bi)(xB+2+0,0)) * (*part).vel[0]; 569 | pgradB[0] += ref_dist[1] * ref_dist[2] * ((ref_dist[0]-1.) * (*Bi)(xB+2+1-0,0) + (1.-2.*ref_dist[0]) * (*Bi)(xB+2+1,0) + ref_dist[0] * (*Bi)(xB+2+1+0,0)) * (*part).vel[0]; 570 | 571 | pgradB[1] = ((1.-ref_dist[0]) * ((*Bi)(xB+1,2) - (*Bi)(xB,2)) + ref_dist[0] * ((*Bi)(xB+1+0,2) - (*Bi)(xB+0,2))) * (*part).vel[2]; 572 | pgradB[1] += ((1.-ref_dist[2]) * ((*Bi)(xB+1,0) - (*Bi)(xB,0)) + ref_dist[2] * ((*Bi)(xB+1+2,0) - (*Bi)(xB+2,0))) * (*part).vel[0]; 573 | pgradB[1] += (1.-ref_dist[0]) * (1.-ref_dist[2]) * ((ref_dist[1]-1.) * (*Bi)(xB-1,1) + (1.-2.*ref_dist[1]) * (*Bi)(xB,1) + ref_dist[1] * (*Bi)(xB+1,1)) * (*part).vel[1]; 574 | pgradB[1] += ref_dist[0] * (1.-ref_dist[2]) * ((ref_dist[1]-1.) * (*Bi)(xB+0-1,1) + (1.-2.*ref_dist[1]) * (*Bi)(xB+0,1) + ref_dist[1] * (*Bi)(xB+0+1,1)) * (*part).vel[1]; 575 | pgradB[1] += (1.-ref_dist[0]) * ref_dist[2] * ((ref_dist[1]-1.) * (*Bi)(xB+2-1,1) + (1.-2.*ref_dist[1]) * (*Bi)(xB+2,1) + ref_dist[1] * (*Bi)(xB+2+1,1)) * (*part).vel[1]; 576 | pgradB[1] += ref_dist[0] * ref_dist[2] * ((ref_dist[1]-1.) * (*Bi)(xB+2+0-1,1) + (1.-2.*ref_dist[1]) * (*Bi)(xB+2+0,1) + ref_dist[1] * (*Bi)(xB+2+0+1,1)) * (*part).vel[1]; 577 | 578 | pgradB[2] = ((1.-ref_dist[1]) * ((*Bi)(xB+2,0) - (*Bi)(xB,0)) + ref_dist[1] * ((*Bi)(xB+2+1,0) - (*Bi)(xB+1,0))) * (*part).vel[0]; 579 | pgradB[2] += ((1.-ref_dist[0]) * ((*Bi)(xB+2,1) - (*Bi)(xB,1)) + ref_dist[0] * ((*Bi)(xB+2+0,1) - (*Bi)(xB+0,1))) * (*part).vel[1]; 580 | pgradB[2] += (1.-ref_dist[0]) * (1.-ref_dist[1]) * ((ref_dist[2]-1.) * (*Bi)(xB-2,2) + (1.-2.*ref_dist[2]) * (*Bi)(xB,2) + ref_dist[2] * (*Bi)(xB+2,2)) * (*part).vel[2]; 581 | pgradB[2] += ref_dist[0] * (1.-ref_dist[1]) * ((ref_dist[2]-1.) * (*Bi)(xB+0-2,2) + (1.-2.*ref_dist[2]) * (*Bi)(xB+0,2) + ref_dist[2] * (*Bi)(xB+0+2,2)) * (*part).vel[2]; 582 | pgradB[2] += (1.-ref_dist[0]) * ref_dist[1] * ((ref_dist[2]-1.) * (*Bi)(xB+1-2,2) + (1.-2.*ref_dist[2]) * (*Bi)(xB+1,2) + ref_dist[2] * (*Bi)(xB+2+1,2)) * (*part).vel[2]; 583 | pgradB[2] += ref_dist[0] * ref_dist[1] * ((ref_dist[2]-1.) * (*Bi)(xB+1+0-2,2) + (1.-2.*ref_dist[2]) * (*Bi)(xB+1+0,2) + ref_dist[2] * (*Bi)(xB+1+0+2,2)) * (*part).vel[2]; 584 | 585 | gradpsi[0] += pgradB[0] / params[1] / e2; 586 | gradpsi[1] += pgradB[1] / params[1] / e2; 587 | gradpsi[2] += pgradB[2] / params[1] / e2; 588 | } 589 | 590 | v2 = 0.; 591 | for (int i=0;i<3;i++) 592 | { 593 | (*part).vel[i] -= dtau * e2 * gradpsi[i] / dx; 594 | v2 += (*part).vel[i] * (*part).vel[i]; 595 | } 596 | 597 | return v2 / params[0] / params[0]; 598 | 599 | #undef psi 600 | #undef phi 601 | #undef Bi 602 | #undef xpsi 603 | #undef xphi 604 | #undef xB 605 | } 606 | 607 | 608 | ////////////////////////// 609 | // update_q_Newton 610 | ////////////////////////// 611 | // Description: 612 | // Update momentum method (Newtonian version) 613 | // Note that vel[3] in the particle structure is used to store q[3] in units 614 | // of the particle mass, such that the meaning of vel[3] is v*a. 615 | // 616 | // Arguments: 617 | // dtau time step 618 | // dx lattice unit 619 | // part pointer to particle structure 620 | // ref_dist distance vector to reference point 621 | // partInfo global particle properties (unused) 622 | // fields array of pointers to fields appearing in geodesic equation 623 | // fields[0] = psi 624 | // sites array of sites on the respective lattices 625 | // nfield number of fields (should be 1) 626 | // params array of additional parameters 627 | // params[0] = a 628 | // outputs array of reduction variables 629 | // noutputs number of reduction variables 630 | // 631 | // Returns: squared velocity of particle after update 632 | // 633 | ////////////////////////// 634 | 635 | Real update_q_Newton(double dtau, double dx, part_simple * part, double * ref_dist, part_simple_info partInfo, Field ** fields, Site * sites, int nfield, double * params, double * outputs, int noutputs) 636 | { 637 | #define psi (fields[0]) 638 | #define xpsi (sites[0]) 639 | 640 | Real gradpsi[3]={0,0,0}; 641 | 642 | gradpsi[0] = (1.-ref_dist[1]) * (1.-ref_dist[2]) * ((*psi)(xpsi+0) - (*psi)(xpsi)); 643 | gradpsi[1] = (1.-ref_dist[0]) * (1.-ref_dist[2]) * ((*psi)(xpsi+1) - (*psi)(xpsi)); 644 | gradpsi[2] = (1.-ref_dist[0]) * (1.-ref_dist[1]) * ((*psi)(xpsi+2) - (*psi)(xpsi)); 645 | gradpsi[0] += ref_dist[1] * (1.-ref_dist[2]) * ((*psi)(xpsi+1+0) - (*psi)(xpsi+1)); 646 | gradpsi[1] += ref_dist[0] * (1.-ref_dist[2]) * ((*psi)(xpsi+1+0) - (*psi)(xpsi+0)); 647 | gradpsi[2] += ref_dist[0] * (1.-ref_dist[1]) * ((*psi)(xpsi+2+0) - (*psi)(xpsi+0)); 648 | gradpsi[0] += (1.-ref_dist[1]) * ref_dist[2] * ((*psi)(xpsi+2+0) - (*psi)(xpsi+2)); 649 | gradpsi[1] += (1.-ref_dist[0]) * ref_dist[2] * ((*psi)(xpsi+2+1) - (*psi)(xpsi+2)); 650 | gradpsi[2] += (1.-ref_dist[0]) * ref_dist[1] * ((*psi)(xpsi+2+1) - (*psi)(xpsi+1)); 651 | gradpsi[0] += ref_dist[1] * ref_dist[2] * ((*psi)(xpsi+2+1+0) - (*psi)(xpsi+2+1)); 652 | gradpsi[1] += ref_dist[0] * ref_dist[2] * ((*psi)(xpsi+2+1+0) - (*psi)(xpsi+2+0)); 653 | gradpsi[2] += ref_dist[0] * ref_dist[1] * ((*psi)(xpsi+2+1+0) - (*psi)(xpsi+1+0)); 654 | 655 | Real v2 = 0.; 656 | for (int i=0;i<3;i++) 657 | { 658 | (*part).vel[i] -= dtau * params[0] * gradpsi[i] / dx; 659 | v2 += (*part).vel[i] * (*part).vel[i]; 660 | } 661 | 662 | return v2 / params[0] / params[0]; 663 | 664 | #undef psi 665 | #undef xpsi 666 | } 667 | 668 | 669 | ////////////////////////// 670 | // update_pos 671 | ////////////////////////// 672 | // Description: 673 | // Update position method (arbitrary momentum) 674 | // Note that vel[3] in the particle structure is used to store q[3] in units 675 | // of the particle mass, such that as q^2 << m^2 a^2 the meaning of vel[3] 676 | // is ~ v*a. 677 | // 678 | // Arguments: 679 | // dtau time step 680 | // dx lattice unit 681 | // part pointer to particle structure 682 | // ref_dist distance vector to reference point 683 | // partInfo global particle properties (unused) 684 | // fields array of pointers to fields appearing in geodesic equation 685 | // fields[0] = psi 686 | // fields[1] = phi 687 | // fields[2] = Bi 688 | // sites array of sites on the respective lattices 689 | // nfield number of fields 690 | // params array of additional parameters 691 | // params[0] = a 692 | // params[1] = scaling coefficient for Bi 693 | // outputs array of reduction variables 694 | // noutputs number of reduction variables 695 | // 696 | // Returns: 697 | // 698 | ////////////////////////// 699 | 700 | void update_pos(double dtau, double dx, part_simple * part, double * ref_dist, part_simple_info partInfo, Field ** fields, Site * sites, int nfield, double * params, double * outputs, int noutputs) 701 | { 702 | Real v[3]; 703 | Real v2 = (*part).vel[0] * (*part).vel[0] + (*part).vel[1] * (*part).vel[1] + (*part).vel[2] * (*part).vel[2]; 704 | Real e2 = v2 + params[0] * params[0]; 705 | Real phi = 0; 706 | Real psi = 0; 707 | 708 | if (nfield >= 1) 709 | { 710 | psi = (*fields[0])(sites[0]) * (1.-ref_dist[0]) * (1.-ref_dist[1]) * (1.-ref_dist[2]); 711 | psi += (*fields[0])(sites[0]+0) * ref_dist[0] * (1.-ref_dist[1]) * (1.-ref_dist[2]); 712 | psi += (*fields[0])(sites[0]+1) * (1.-ref_dist[0]) * ref_dist[1] * (1.-ref_dist[2]); 713 | psi += (*fields[0])(sites[0]+0+1) * ref_dist[0] * ref_dist[1] * (1.-ref_dist[2]); 714 | psi += (*fields[0])(sites[0]+2) * (1.-ref_dist[0]) * (1.-ref_dist[1]) * ref_dist[2]; 715 | psi += (*fields[0])(sites[0]+0+2) * ref_dist[0] * (1.-ref_dist[1]) * ref_dist[2]; 716 | psi += (*fields[0])(sites[0]+1+2) * (1.-ref_dist[0]) * ref_dist[1] * ref_dist[2]; 717 | psi += (*fields[0])(sites[0]+0+1+2) * ref_dist[0] * ref_dist[1] * ref_dist[2]; 718 | } 719 | 720 | if (nfield >= 2) 721 | { 722 | phi = (*fields[1])(sites[1]) * (1.-ref_dist[0]) * (1.-ref_dist[1]) * (1.-ref_dist[2]); 723 | phi += (*fields[1])(sites[1]+0) * ref_dist[0] * (1.-ref_dist[1]) * (1.-ref_dist[2]); 724 | phi += (*fields[1])(sites[1]+1) * (1.-ref_dist[0]) * ref_dist[1] * (1.-ref_dist[2]); 725 | phi += (*fields[1])(sites[1]+0+1) * ref_dist[0] * ref_dist[1] * (1.-ref_dist[2]); 726 | phi += (*fields[1])(sites[1]+2) * (1.-ref_dist[0]) * (1.-ref_dist[1]) * ref_dist[2]; 727 | phi += (*fields[1])(sites[1]+0+2) * ref_dist[0] * (1.-ref_dist[1]) * ref_dist[2]; 728 | phi += (*fields[1])(sites[1]+1+2) * (1.-ref_dist[0]) * ref_dist[1] * ref_dist[2]; 729 | phi += (*fields[1])(sites[1]+0+1+2) * ref_dist[0] * ref_dist[1] * ref_dist[2]; 730 | } 731 | 732 | v2 = (1. + psi + (2. - v2 / e2) * phi) / sqrt(e2); 733 | 734 | v[0] = (*part).vel[0] * v2; 735 | v[1] = (*part).vel[1] * v2; 736 | v[2] = (*part).vel[2] * v2; 737 | 738 | if (nfield >= 3) 739 | { 740 | Real b[3]; 741 | 742 | b[0] = (*fields[2])(sites[2], 0) * (1.-ref_dist[1]) * (1.-ref_dist[2]); 743 | b[1] = (*fields[2])(sites[2], 1) * (1.-ref_dist[0]) * (1.-ref_dist[2]); 744 | b[2] = (*fields[2])(sites[2], 2) * (1.-ref_dist[0]) * (1.-ref_dist[1]); 745 | b[1] += (*fields[2])(sites[2]+0, 1) * ref_dist[0] * (1.-ref_dist[2]); 746 | b[2] += (*fields[2])(sites[2]+0, 2) * ref_dist[0] * (1.-ref_dist[1]); 747 | b[0] += (*fields[2])(sites[2]+1, 0) * ref_dist[1] * (1.-ref_dist[2]); 748 | b[2] += (*fields[2])(sites[2]+1, 2) * (1.-ref_dist[0]) * ref_dist[1]; 749 | b[0] += (*fields[2])(sites[2]+2, 0) * (1.-ref_dist[1]) * ref_dist[2]; 750 | b[1] += (*fields[2])(sites[2]+2, 1) * (1.-ref_dist[0]) * ref_dist[2]; 751 | b[1] += (*fields[2])(sites[2]+2+0, 1) * ref_dist[0] * ref_dist[2]; 752 | b[0] += (*fields[2])(sites[2]+2+1, 0) * ref_dist[1] * ref_dist[2]; 753 | b[2] += (*fields[2])(sites[2]+1+0, 2) * ref_dist[0] * ref_dist[1]; 754 | 755 | for (int l=0;l<3;l++) (*part).pos[l] += dtau*(v[l] + b[l] / params[1]); 756 | } 757 | else 758 | { 759 | for (int l=0;l<3;l++) (*part).pos[l] += dtau*v[l]; 760 | } 761 | } 762 | 763 | 764 | ////////////////////////// 765 | // update_pos_Newton 766 | ////////////////////////// 767 | // Description: 768 | // Update position method (Newtonian version) 769 | // Note that vel[3] in the particle structure is used to store q[3] in units 770 | // of the particle mass, such that the meaning of vel[3] is v*a. 771 | // 772 | // Arguments: 773 | // dtau time step 774 | // dx lattice unit (unused) 775 | // part pointer to particle structure 776 | // ref_dist distance vector to reference point (unused) 777 | // partInfo global particle properties (unused) 778 | // fields array of pointers to fields appearing in geodesic equation (unused) 779 | // sites array of sites on the respective lattices (unused) 780 | // nfield number of fields (unused) 781 | // params array of additional parameters 782 | // params[0] = a 783 | // outputs array of reduction variables (unused) 784 | // noutputs number of reduction variables (unused) 785 | // 786 | // Returns: 787 | // 788 | ////////////////////////// 789 | 790 | void update_pos_Newton(double dtau, double dx, part_simple * part, double * ref_dist, part_simple_info partInfo, Field ** fields, Site * sites, int nfield, double * params, double * outputs, int noutputs) 791 | { 792 | for (int l=0;l<3;l++) (*part).pos[l] += dtau * (*part).vel[l] / params[0]; 793 | } 794 | 795 | 796 | ////////////////////////// 797 | // projection_T00_project 798 | ////////////////////////// 799 | // Description: 800 | // Particle-mesh projection for T00, including geometric corrections 801 | // 802 | // Arguments: 803 | // pcls pointer to particle handler 804 | // T00 pointer to target field 805 | // a scale factor at projection (needed in order to convert 806 | // canonical momenta to energies) 807 | // phi pointer to Bardeen potential which characterizes the 808 | // geometric corrections (volume distortion); can be set to 809 | // NULL which will result in no corrections applied 810 | // 811 | // Returns: 812 | // 813 | ////////////////////////// 814 | 815 | template 816 | void projection_T00_project(Particles * pcls, Field * T00, double a = 1., Field * phi = NULL) 817 | { 818 | if (T00->lattice().halo() == 0) 819 | { 820 | cout<< "projection_T00_project: target field needs halo > 0" << endl; 821 | exit(-1); 822 | } 823 | 824 | Site xPart(pcls->lattice()); 825 | Site xField(T00->lattice()); 826 | 827 | typename std::list::iterator it; 828 | 829 | Real referPos[3]; 830 | Real weightScalarGridUp[3]; 831 | Real weightScalarGridDown[3]; 832 | Real dx = pcls->res(); 833 | 834 | double mass = 1. / (dx*dx*dx); 835 | mass *= *(double*)((char*)pcls->parts_info() + pcls->mass_offset()); 836 | mass /= a; 837 | 838 | Real e = a, f = 0.; 839 | Real * q; 840 | size_t offset_q = offsetof(part,vel); 841 | 842 | Real localCube[8]; // XYZ = 000 | 001 | 010 | 011 | 100 | 101 | 110 | 111 843 | Real localCubePhi[8]; 844 | 845 | for (int i=0; i<8; i++) localCubePhi[i] = 0.0; 846 | 847 | for (xPart.first(),xField.first(); xPart.test(); xPart.next(),xField.next()) 848 | { 849 | if (pcls->field()(xPart).size != 0) 850 | { 851 | for(int i=0; i<3; i++) referPos[i] = xPart.coord(i)*dx; 852 | for(int i=0; i<8; i++) localCube[i] = 0.0; 853 | 854 | if (phi != NULL) 855 | { 856 | localCubePhi[0] = (*phi)(xField); 857 | localCubePhi[1] = (*phi)(xField+2); 858 | localCubePhi[2] = (*phi)(xField+1); 859 | localCubePhi[3] = (*phi)(xField+1+2); 860 | localCubePhi[4] = (*phi)(xField+0); 861 | localCubePhi[5] = (*phi)(xField+0+2); 862 | localCubePhi[6] = (*phi)(xField+0+1); 863 | localCubePhi[7] = (*phi)(xField+0+1+2); 864 | } 865 | 866 | for (it=(pcls->field())(xPart).parts.begin(); it != (pcls->field())(xPart).parts.end(); ++it) 867 | { 868 | for (int i=0; i<3; i++) 869 | { 870 | weightScalarGridUp[i] = ((*it).pos[i] - referPos[i]) / dx; 871 | weightScalarGridDown[i] = 1.0l - weightScalarGridUp[i]; 872 | } 873 | 874 | if (phi != NULL) 875 | { 876 | q = (Real*)((char*)&(*it)+offset_q); 877 | 878 | f = q[0] * q[0] + q[1] * q[1] + q[2] * q[2]; 879 | e = sqrt(f + a * a); 880 | f = 3. * e + f / e; 881 | } 882 | 883 | //000 884 | localCube[0] += weightScalarGridDown[0]*weightScalarGridDown[1]*weightScalarGridDown[2]*(e+f*localCubePhi[0]); 885 | //001 886 | localCube[1] += weightScalarGridDown[0]*weightScalarGridDown[1]*weightScalarGridUp[2]*(e+f*localCubePhi[1]); 887 | //010 888 | localCube[2] += weightScalarGridDown[0]*weightScalarGridUp[1]*weightScalarGridDown[2]*(e+f*localCubePhi[2]); 889 | //011 890 | localCube[3] += weightScalarGridDown[0]*weightScalarGridUp[1]*weightScalarGridUp[2]*(e+f*localCubePhi[3]); 891 | //100 892 | localCube[4] += weightScalarGridUp[0]*weightScalarGridDown[1]*weightScalarGridDown[2]*(e+f*localCubePhi[4]); 893 | //101 894 | localCube[5] += weightScalarGridUp[0]*weightScalarGridDown[1]*weightScalarGridUp[2]*(e+f*localCubePhi[5]); 895 | //110 896 | localCube[6] += weightScalarGridUp[0]*weightScalarGridUp[1]*weightScalarGridDown[2]*(e+f*localCubePhi[6]); 897 | //111 898 | localCube[7] += weightScalarGridUp[0]*weightScalarGridUp[1]*weightScalarGridUp[2]*(e+f*localCubePhi[7]); 899 | } 900 | 901 | (*T00)(xField) += localCube[0] * mass; 902 | (*T00)(xField+2) += localCube[1] * mass; 903 | (*T00)(xField+1) += localCube[2] * mass; 904 | (*T00)(xField+1+2) += localCube[3] * mass; 905 | (*T00)(xField+0) += localCube[4] * mass; 906 | (*T00)(xField+0+2) += localCube[5] * mass; 907 | (*T00)(xField+0+1) += localCube[6] * mass; 908 | (*T00)(xField+0+1+2) += localCube[7] * mass; 909 | } 910 | } 911 | } 912 | 913 | #define projection_T00_comm scalarProjectionCIC_comm 914 | 915 | 916 | ////////////////////////// 917 | // projection_Tij_project 918 | ////////////////////////// 919 | // Description: 920 | // Particle-mesh projection for Tij, including geometric corrections 921 | // 922 | // Arguments: 923 | // pcls pointer to particle handler 924 | // Tij pointer to target field 925 | // a scale factor at projection (needed in order to convert 926 | // canonical momenta to energies) 927 | // phi pointer to Bardeen potential which characterizes the 928 | // geometric corrections (volume distortion); can be set to 929 | // NULL which will result in no corrections applied 930 | // 931 | // Returns: 932 | // 933 | ////////////////////////// 934 | 935 | template 936 | void projection_Tij_project(Particles * pcls, Field * Tij, double a = 1., Field * phi = NULL) 937 | { 938 | if (Tij->lattice().halo() == 0) 939 | { 940 | cout<< "projection_Tij_project: target field needs halo > 0" << endl; 941 | exit(-1); 942 | } 943 | 944 | Site xPart(pcls->lattice()); 945 | Site xTij(Tij->lattice()); 946 | 947 | typename std::list::iterator it; 948 | 949 | Real referPos[3]; 950 | Real weightScalarGridDown[3]; 951 | Real weightScalarGridUp[3]; 952 | Real dx = pcls->res(); 953 | 954 | double mass = 1. / (dx*dx*dx); 955 | mass *= *(double*)((char*)pcls->parts_info() + pcls->mass_offset()); 956 | mass /= a; 957 | 958 | Real e, f, w; 959 | Real * q; 960 | size_t offset_q = offsetof(part,vel); 961 | 962 | Real tij[6]; // local cube 963 | Real tii[24]; // local cube 964 | Real localCubePhi[8]; 965 | 966 | for (int i=0; i<8; i++) localCubePhi[i] = 0; 967 | 968 | for (xPart.first(),xTij.first(); xPart.test(); xPart.next(),xTij.next()) 969 | { 970 | if (pcls->field()(xPart).size != 0) 971 | { 972 | for (int i=0;i<3;i++) 973 | referPos[i] = (double)xPart.coord(i)*dx; 974 | 975 | for (int i=0; i<6; i++) tij[i]=0.0; 976 | for (int i=0; i<24; i++) tii[i]=0.0; 977 | 978 | if (phi != NULL) 979 | { 980 | localCubePhi[0] = (*phi)(xTij); 981 | localCubePhi[1] = (*phi)(xTij+2); 982 | localCubePhi[2] = (*phi)(xTij+1); 983 | localCubePhi[3] = (*phi)(xTij+1+2); 984 | localCubePhi[4] = (*phi)(xTij+0); 985 | localCubePhi[5] = (*phi)(xTij+0+2); 986 | localCubePhi[6] = (*phi)(xTij+0+1); 987 | localCubePhi[7] = (*phi)(xTij+0+1+2); 988 | } 989 | 990 | for (it=(pcls->field())(xPart).parts.begin(); it != (pcls->field())(xPart).parts.end(); ++it) 991 | { 992 | for (int i =0; i<3; i++) 993 | { 994 | weightScalarGridUp[i] = ((*it).pos[i] - referPos[i]) / dx; 995 | weightScalarGridDown[i] = 1.0l - weightScalarGridUp[i]; 996 | } 997 | 998 | q = (Real*)((char*)&(*it)+offset_q); 999 | f = q[0] * q[0] + q[1] * q[1] + q[2] * q[2]; 1000 | e = sqrt(f + a * a); 1001 | f = 4. + a * a / (f + a * a); 1002 | 1003 | // diagonal components 1004 | for (int i=0; i<3; i++) 1005 | { 1006 | w = mass * q[i] * q[i] / e; 1007 | //000 1008 | tii[0+i*8] += w * weightScalarGridDown[0] * weightScalarGridDown[1] * weightScalarGridDown[2] * (1. + f * localCubePhi[0]); 1009 | //001 1010 | tii[1+i*8] += w * weightScalarGridDown[0] * weightScalarGridDown[1] * weightScalarGridUp[2] * (1. + f * localCubePhi[1]); 1011 | //010 1012 | tii[2+i*8] += w * weightScalarGridDown[0] * weightScalarGridUp[1] * weightScalarGridDown[2] * (1. + f * localCubePhi[2]); 1013 | //011 1014 | tii[3+i*8] += w * weightScalarGridDown[0] * weightScalarGridUp[1] * weightScalarGridUp[2] * (1. + f * localCubePhi[3]); 1015 | //100 1016 | tii[4+i*8] += w * weightScalarGridUp[0] * weightScalarGridDown[1] * weightScalarGridDown[2] * (1. + f * localCubePhi[4]); 1017 | //101 1018 | tii[5+i*8] += w * weightScalarGridUp[0] * weightScalarGridDown[1] * weightScalarGridUp[2] * (1. + f * localCubePhi[5]); 1019 | //110 1020 | tii[6+i*8] += w * weightScalarGridUp[0] * weightScalarGridUp[1] * weightScalarGridDown[2] * (1. + f * localCubePhi[6]); 1021 | //111 1022 | tii[7+i*8] += w * weightScalarGridUp[0] * weightScalarGridUp[1] * weightScalarGridUp[2] * (1. + f * localCubePhi[7]); 1023 | } 1024 | 1025 | w = mass * q[0] * q[1] / e; 1026 | tij[0] += w * weightScalarGridDown[2] * (1. + f * 0.25 * (localCubePhi[0] + localCubePhi[2] + localCubePhi[4] + localCubePhi[6])); 1027 | tij[1] += w * weightScalarGridUp[2] * (1. + f * 0.25 * (localCubePhi[1] + localCubePhi[3] + localCubePhi[5] + localCubePhi[7])); 1028 | 1029 | w = mass * q[0] * q[2] / e; 1030 | tij[2] += w * weightScalarGridDown[1] * (1. + f * 0.25 * (localCubePhi[0] + localCubePhi[1] + localCubePhi[4] + localCubePhi[5])); 1031 | tij[3] += w * weightScalarGridUp[1] * (1. + f * 0.25 * (localCubePhi[2] + localCubePhi[3] + localCubePhi[6] + localCubePhi[7])); 1032 | 1033 | w = mass * q[1] * q[2] / e; 1034 | tij[4] += w * weightScalarGridDown[0] * (1. + f * 0.25 * (localCubePhi[0] + localCubePhi[1] + localCubePhi[2] + localCubePhi[3])); 1035 | tij[5] += w * weightScalarGridUp[0] * (1. + f * 0.25 * (localCubePhi[4] + localCubePhi[5] + localCubePhi[6] + localCubePhi[7])); 1036 | 1037 | } 1038 | 1039 | 1040 | for (int i=0; i<3; i++) (*Tij)(xTij,i,i) += tii[8*i]; 1041 | (*Tij)(xTij,0,1) += tij[0]; 1042 | (*Tij)(xTij,0,2) += tij[2]; 1043 | (*Tij)(xTij,1,2) += tij[4]; 1044 | 1045 | for (int i=0; i<3; i++) (*Tij)(xTij+0,i,i) += tii[4+8*i]; 1046 | (*Tij)(xTij+0,1,2) += tij[5]; 1047 | 1048 | for (int i=0; i<3; i++) (*Tij)(xTij+1,i,i) += tii[2+8*i]; 1049 | (*Tij)(xTij+1,0,2) += tij[3]; 1050 | 1051 | for (int i=0; i<3; i++) (*Tij)(xTij+2,i,i) += tii[1+8*i]; 1052 | (*Tij)(xTij+2,0,1) += tij[1]; 1053 | 1054 | for (int i=0; i<3; i++) (*Tij)(xTij+0+1,i,i) += tii[6+8*i]; 1055 | for (int i=0; i<3; i++) (*Tij)(xTij+0+2,i,i) += tii[5+8*i]; 1056 | for (int i=0; i<3; i++) (*Tij)(xTij+1+2,i,i) += tii[3+8*i]; 1057 | for (int i=0; i<3; i++) (*Tij)(xTij+0+1+2,i,i) += tii[7+8*i]; 1058 | } 1059 | } 1060 | } 1061 | 1062 | #ifndef projection_Tij_comm 1063 | #ifndef PARTICLES_TOOLS_HPP 1064 | #define projection_Tij_comm VecVecProjectionCICNGP_comm 1065 | #else 1066 | #define projection_Tij_comm symtensorProjectionCICNGP_comm 1067 | #endif 1068 | #endif 1069 | 1070 | #endif 1071 | 1072 | -------------------------------------------------------------------------------- /main.cpp: -------------------------------------------------------------------------------- 1 | ////////////////////////// 2 | // Copyright (c) 2015-2016 Julian Adamek (Université de Genève) 3 | // 4 | // Permission is hereby granted, free of charge, to any person obtaining a copy 5 | // of this software and associated documentation files (the "Software"), to deal 6 | // in the Software without restriction, including without limitation the rights 7 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 8 | // copies of the Software, and to permit persons to whom the Software is 9 | // furnished to do so, subject to the following conditions: 10 | // 11 | // The above copyright notice and this permission notice shall be included in 12 | // all copies or substantial portions of the Software. 13 | // 14 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESSED OR 15 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 16 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 17 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 18 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 19 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 20 | // THE SOFTWARE. 21 | ////////////////////////// 22 | 23 | ////////////////////////// 24 | // main.cpp 25 | ////////////////////////// 26 | // 27 | // main control sequence of Geneva N-body code with evolution of metric perturbations (gevolution) 28 | // 29 | // Author: Julian Adamek (Université de Genève) 30 | // 31 | // Last modified: March 2016 32 | // 33 | ////////////////////////// 34 | 35 | #include 36 | #include "LATfield2.hpp" 37 | #include "metadata.hpp" 38 | #include "background.hpp" 39 | #include "Particles_gevolution.hpp" 40 | #include "gevolution.hpp" 41 | #include "ic_basic.hpp" 42 | #ifdef ICGEN_PREVOLUTION 43 | #include "ic_prevolution.hpp" 44 | #endif 45 | #ifdef ICGEN_FALCONIC 46 | #include "fcn/togevolution.hpp" 47 | #endif 48 | #include "parser.hpp" 49 | #include "tools.hpp" 50 | 51 | #ifdef EXTERNAL_IO 52 | #ifndef NUMBER_OF_IO_FILES 53 | #define NUMBER_OF_IO_FILES 4 54 | #endif 55 | #endif 56 | 57 | using namespace std; 58 | 59 | using namespace LATfield2; 60 | 61 | int main(int argc, char **argv) 62 | { 63 | 64 | #ifdef BENCHMARK 65 | //benchmarking variables 66 | 67 | double start_time, ref_time, ref2_time, cycle_start_time; 68 | 69 | double initialization_time; 70 | double run_time; 71 | double cycle_time=0; 72 | double projection_time = 0; 73 | double snapshot_output_time = 0; 74 | double spectra_output_time = 0; 75 | double gravity_solver_time = 0; 76 | double fft_time = 0; 77 | int fft_count = 0; 78 | double update_q_time = 0; 79 | int update_q_count = 0; 80 | double moveParts_time = 0; 81 | int moveParts_count =0; 82 | 83 | #endif //BENCHMARK 84 | 85 | int n = 0, m = 0; 86 | int io_size = 0; 87 | int io_group_size = 0; 88 | 89 | int i, j, cycle = 0, snapcount = 0, pkcount = 0, usedparams, numparam = 0, doneTT, redo_psi = 0, numsteps; 90 | int numsteps_ncdm[MAX_PCL_SPECIES]; 91 | long numpts3d; 92 | int box[3]; 93 | double dtau, dtau_old, dx, tau, a, fourpiG, tau_Lambda, maxvel; 94 | double maxvel_ncdm[MAX_PCL_SPECIES]; 95 | FILE * outfile; 96 | char filename[2*PARAM_MAX_LENGTH+24]; 97 | char buffer[64]; 98 | string h5filename; 99 | char * settingsfile = NULL; 100 | parameter * params = NULL; 101 | metadata sim; 102 | cosmology cosmo; 103 | icsettings ic; 104 | gadget2_header hdr; 105 | Real * kbin; 106 | Real * power; 107 | Real * kscatter; 108 | Real * pscatter; 109 | int * occupation; 110 | int numbins; 111 | Real divB, curlB, divh, traceh, normh, T00hom; 112 | Cplx tempk; 113 | 114 | for (i=1 ; i < argc ; i++ ){ 115 | if ( argv[i][0] != '-' ) 116 | continue; 117 | switch(argv[i][1]) { 118 | case 's': 119 | settingsfile = argv[++i]; //settings file name 120 | break; 121 | case 'n': 122 | n = atoi(argv[++i]); //size of the dim 1 of the processor grid 123 | break; 124 | case 'm': 125 | m = atoi(argv[++i]); //size of the dim 2 of the processor grid 126 | break; 127 | case 'i': 128 | #ifndef EXTERNAL_IO 129 | cout << "EXTERNAL_IO needs to be set at compilation to use the I/O server"< pcls_cdm; 193 | Particles_gevolution pcls_ncdm[MAX_PCL_SPECIES]; 194 | Field * update_cdm_fields[3]; 195 | Field * update_ncdm_fields[3]; 196 | double f_params[5]; 197 | 198 | Field phi; 199 | Field psi; 200 | Field source; 201 | Field chi; 202 | Field Sij; 203 | Field Bi; 204 | Field scalarFT; 205 | Field SijFT; 206 | Field BiFT; 207 | source.initialize(lat,1); 208 | psi.initialize(lat,1); 209 | phi.initialize(lat,1); 210 | chi.initialize(lat,1); 211 | scalarFT.initialize(latFT,1); 212 | PlanFFT plan_source(&source, &scalarFT); 213 | PlanFFT plan_psi(&psi, &scalarFT); 214 | PlanFFT plan_phi(&phi, &scalarFT); 215 | PlanFFT plan_chi(&chi, &scalarFT); 216 | Sij.initialize(lat,3,3,symmetric); 217 | SijFT.initialize(latFT,3,3,symmetric); 218 | PlanFFT plan_Sij(&Sij, &SijFT); 219 | Bi.initialize(lat,3); 220 | BiFT.initialize(latFT,3); 221 | PlanFFT plan_Bi(&Bi, &BiFT); 222 | #ifdef CHECK_B 223 | Field Bi_check; 224 | Field BiFT_check; 225 | Bi_check.initialize(lat,3); 226 | BiFT_check.initialize(latFT,3); 227 | PlanFFT plan_Bi_check(&Bi_check, &BiFT_check); 228 | #endif 229 | 230 | update_cdm_fields[0] = ψ 231 | update_cdm_fields[1] = φ 232 | update_cdm_fields[2] = &Bi; 233 | 234 | update_ncdm_fields[0] = ψ 235 | update_ncdm_fields[1] = φ 236 | update_ncdm_fields[2] = &Bi; 237 | 238 | Site x(lat); 239 | rKSite kFT(latFT); 240 | 241 | dx = 1.0 / (double) sim.numpts; 242 | numpts3d = (long) sim.numpts * (long) sim.numpts * (long) sim.numpts; 243 | 244 | for (i = 0; i < 3; i++) // particles may never move farther than to the adjacent domain 245 | { 246 | if (lat.sizeLocal(i)-1 < sim.movelimit) 247 | sim.movelimit = lat.sizeLocal(i)-1; 248 | } 249 | parallel.min(sim.movelimit); 250 | 251 | fourpiG = 1.5 * sim.boxsize * sim.boxsize / 2997.92458 / 2997.92458; 252 | a = 1. / (1. + sim.z_in); 253 | tau = 2. / Hconf(a, fourpiG, cosmo); 254 | tau_Lambda = -1.0; 255 | 256 | if (sim.Cf * dx < sim.steplimit / Hconf(a, fourpiG, cosmo)) 257 | dtau = sim.Cf * dx; 258 | else 259 | dtau = sim.steplimit / Hconf(a, fourpiG, cosmo); 260 | 261 | dtau_old = dtau; 262 | 263 | if (ic.generator == ICGEN_BASIC) 264 | maxvel = generateIC_basic(sim, ic, cosmo, fourpiG, dtau, &pcls_cdm, pcls_ncdm, maxvel_ncdm, &phi, &psi, &chi, &Bi, &source, &Sij, &scalarFT, &BiFT, &SijFT, &plan_phi, &plan_psi, &plan_chi, &plan_Bi, &plan_source, &plan_Sij); // generates ICs on the fly 265 | #ifdef ICGEN_PREVOLUTION 266 | else if (ic.generator == ICGEN_PREVOLUTION) 267 | { 268 | maxvel = generateIC_prevolution(sim, ic, cosmo, fourpiG, a, &pcls_cdm, pcls_ncdm, maxvel_ncdm, &phi, &psi, &chi, &Bi, &source, &Sij, &scalarFT, &BiFT, &SijFT, &plan_phi, &plan_psi, &plan_chi, &plan_Bi, &plan_source, &plan_Sij); 269 | } 270 | #endif 271 | #ifdef ICGEN_FALCONIC 272 | else if (ic.generator == ICGEN_FALCONIC) 273 | { 274 | maxvel = generateIC_FalconIC(sim, ic, cosmo, fourpiG, dtau, &pcls_cdm, pcls_ncdm, maxvel_ncdm, &phi, &psi, &chi, &Bi, &source, &Sij, &scalarFT, &BiFT, &SijFT, &plan_phi, &plan_psi, &plan_chi, &plan_Bi, &plan_source, &plan_Sij); 275 | } 276 | #endif 277 | else 278 | { 279 | COUT << " error: IC generator not implemented!" << endl; 280 | parallel.abortForce(); 281 | } 282 | 283 | parallel.max(maxvel); 284 | if (cosmo.num_ncdm > 0) parallel.max(maxvel_ncdm, cosmo.num_ncdm); 285 | 286 | if (sim.gr_flag > 0) 287 | { 288 | maxvel /= sqrt(maxvel * maxvel + 1.0); 289 | for (i = 0; i < cosmo.num_ncdm; i++) 290 | maxvel_ncdm[i] /= sqrt(maxvel_ncdm[i] * maxvel_ncdm[i] + 1.0); 291 | } 292 | 293 | kbin = (Real *) malloc(sim.numbins * sizeof(Real)); 294 | power = (Real *) malloc(sim.numbins * sizeof(Real)); 295 | kscatter = (Real *) malloc(sim.numbins * sizeof(Real)); 296 | pscatter = (Real *) malloc(sim.numbins * sizeof(Real)); 297 | occupation = (int *) malloc(sim.numbins * sizeof(int)); 298 | 299 | for (i = 0; i < 6; i++) 300 | { 301 | hdr.npart[i] = 0; 302 | hdr.npartTotal[i] = 0; 303 | hdr.mass[i] = 0.; 304 | } 305 | hdr.num_files = 1; 306 | hdr.Omega0 = cosmo.Omega_m; 307 | hdr.OmegaLambda = 1. - cosmo.Omega_m; 308 | hdr.HubbleParam = cosmo.h; 309 | hdr.BoxSize = sim.boxsize * 1000.; 310 | hdr.flag_sfr = 0; 311 | hdr.flag_cooling = 0; 312 | hdr.flag_feedback = 0; 313 | for (i = 0; i < 256 - 6 * 4 - 6 * 8 - 2 * 8 - 2 * 4 - 6 * 4 - 2 * 4 - 4 * 8; i++) 314 | hdr.fill[i] = 0; 315 | 316 | #ifdef BENCHMARK 317 | initialization_time = MPI_Wtime() - start_time; 318 | parallel.sum(initialization_time); 319 | COUT << " initialization complete. BENCHMARK: " << hourMinSec(initialization_time) << endl << endl; 320 | #else 321 | COUT << " initialization complete." << endl << endl; 322 | #endif 323 | 324 | while (true) // main loop 325 | { 326 | #ifdef BENCHMARK 327 | cycle_start_time = MPI_Wtime(); 328 | #endif 329 | // construct stress-energy tensor 330 | projection_init(&source); 331 | if (sim.gr_flag > 0) 332 | { 333 | projection_T00_project(&pcls_cdm, &source, a, &phi); 334 | for (i = 0; i < cosmo.num_ncdm; i++) 335 | projection_T00_project(pcls_ncdm+i, &source, a, &phi); 336 | } 337 | else 338 | { 339 | scalarProjectionCIC_project(&pcls_cdm, &source); 340 | for (i = 0; i < cosmo.num_ncdm; i++) 341 | scalarProjectionCIC_project(pcls_ncdm+i, &source); 342 | } 343 | projection_T00_comm(&source); 344 | 345 | projection_init(&Sij); 346 | projection_Tij_project(&pcls_cdm, &Sij, a, &phi); 347 | for (i = 0; i < cosmo.num_ncdm; i++) 348 | projection_Tij_project(pcls_ncdm+i, &Sij, a, &phi); 349 | projection_Tij_comm(&Sij); 350 | 351 | doneTT = 0; 352 | 353 | #ifdef BENCHMARK 354 | projection_time += MPI_Wtime() - cycle_start_time; 355 | ref_time = MPI_Wtime(); 356 | #endif 357 | // snapshot output 358 | if (snapcount < sim.num_snapshot && 1. / a < sim.z_snapshot[snapcount] + 1.) 359 | { 360 | sprintf(filename, "%03d", snapcount); 361 | snapcount++; 362 | 363 | COUT << " writing snapshot at z = " << ((1./a) - 1.) << " (cycle " << cycle << "), tau/boxsize = " << tau << endl; 364 | 365 | #ifdef EXTERNAL_IO 366 | while (ioserver.openOstream()== OSTREAM_FAIL); 367 | 368 | if (sim.out_snapshot & MASK_PCLS) 369 | pcls_cdm.saveHDF5_server_open(h5filename + filename + "_part"); 370 | 371 | if (sim.out_snapshot & MASK_DBARE && sim.gr_flag > 0) 372 | psi.saveHDF5_server_open(h5filename + filename + "_deltaN"); 373 | 374 | if (sim.out_snapshot & MASK_T00) 375 | source.saveHDF5_server_open(h5filename + filename + "_T00"); 376 | 377 | if (sim.out_snapshot & MASK_B) 378 | Bi.saveHDF5_server_open(h5filename + filename + "_B"); 379 | 380 | if (sim.out_snapshot & MASK_PHI) 381 | phi.saveHDF5_server_open(h5filename + filename + "_phi"); 382 | 383 | if (sim.out_snapshot & MASK_CHI) 384 | chi.saveHDF5_server_open(h5filename + filename + "_chi"); 385 | 386 | if (sim.out_snapshot & MASK_HIJ) 387 | Sij.saveHDF5_server_open(h5filename + filename + "_hij"); 388 | 389 | #ifdef CHECK_B 390 | if (sim.out_snapshot & MASK_B) 391 | Bi_check.saveHDF5_server_open(h5filename + filename + "_B_check"); 392 | #endif 393 | #endif 394 | 395 | if (sim.out_snapshot & MASK_DBARE) 396 | { 397 | if (sim.gr_flag > 0) 398 | { 399 | projection_init(&psi); 400 | scalarProjectionCIC_project(&pcls_cdm, &psi); 401 | for (i = 0; i < cosmo.num_ncdm; i++) 402 | scalarProjectionCIC_project(pcls_ncdm+i, &psi); 403 | scalarProjectionCIC_comm(&psi); 404 | #ifdef EXTERNAL_IO 405 | psi.saveHDF5_server_write(NUMBER_OF_IO_FILES); 406 | #else 407 | psi.saveHDF5(h5filename + filename + "_deltaN.h5"); 408 | #endif 409 | redo_psi = 1; 410 | } 411 | else 412 | source.saveHDF5(h5filename + filename + "_deltaN.h5"); 413 | } 414 | 415 | if (sim.out_snapshot & MASK_POT) 416 | { 417 | if (!redo_psi) 418 | { 419 | projection_init(&psi); 420 | scalarProjectionCIC_project(&pcls_cdm, &psi); 421 | for (i = 0; i < cosmo.num_ncdm; i++) 422 | scalarProjectionCIC_project(pcls_ncdm+i, &psi); 423 | scalarProjectionCIC_comm(&psi); 424 | redo_psi = 1; 425 | } 426 | plan_psi.execute(FFT_FORWARD); 427 | solveModifiedPoissonFT(scalarFT, scalarFT, fourpiG / a); 428 | plan_psi.execute(FFT_BACKWARD); 429 | psi.saveHDF5(h5filename + filename + "_psiN.h5"); 430 | } 431 | 432 | if (sim.out_snapshot & MASK_T00) 433 | #ifdef EXTERNAL_IO 434 | source.saveHDF5_server_write(NUMBER_OF_IO_FILES); 435 | #else 436 | source.saveHDF5(h5filename + filename + "_T00.h5"); 437 | #endif 438 | 439 | if (sim.out_snapshot & MASK_B) 440 | { 441 | if (sim.gr_flag == 0) 442 | { 443 | plan_Bi.execute(FFT_BACKWARD); 444 | } 445 | for (x.first(); x.test(); x.next()) 446 | { 447 | Bi(x,0) /= a * a * sim.numpts; 448 | Bi(x,1) /= a * a * sim.numpts; 449 | Bi(x,2) /= a * a * sim.numpts; 450 | } 451 | Bi.updateHalo(); 452 | 453 | computeVectorDiagnostics(Bi, divB, curlB); 454 | COUT << " B diagnostics: max |divB| = " << divB << ", max |curlB| = " << curlB << endl; 455 | 456 | #ifdef EXTERNAL_IO 457 | Bi.saveHDF5_server_write(NUMBER_OF_IO_FILES); 458 | #else 459 | Bi.saveHDF5(h5filename + filename + "_B.h5"); 460 | #endif 461 | 462 | if (sim.gr_flag > 0) 463 | { 464 | plan_Bi.execute(FFT_BACKWARD); 465 | Bi.updateHalo(); 466 | } 467 | } 468 | 469 | if (sim.out_snapshot & MASK_PHI) 470 | #ifdef EXTERNAL_IO 471 | phi.saveHDF5_server_write(NUMBER_OF_IO_FILES); 472 | #else 473 | phi.saveHDF5(h5filename + filename + "_phi.h5"); 474 | #endif 475 | 476 | if (sim.out_snapshot & MASK_CHI) 477 | #ifdef EXTERNAL_IO 478 | chi.saveHDF5_server_write(NUMBER_OF_IO_FILES); 479 | #else 480 | chi.saveHDF5(h5filename + filename + "_chi.h5"); 481 | #endif 482 | 483 | if (sim.out_snapshot & MASK_TIJ) 484 | Sij.saveHDF5(h5filename + filename + "_Tij.h5"); 485 | 486 | if (sim.out_snapshot & MASK_HIJ) 487 | { 488 | projectFTtensor(SijFT, SijFT); 489 | doneTT = 1; 490 | plan_Sij.execute(FFT_BACKWARD); 491 | Sij.updateHalo(); 492 | 493 | computeTensorDiagnostics(Sij, divh, traceh, normh); 494 | COUT << " GW diagnostics: max |divh| = " << divh << ", max |traceh| = " << traceh << ", max |h| = " << normh << endl; 495 | 496 | #ifdef EXTERNAL_IO 497 | Sij.saveHDF5_server_write(NUMBER_OF_IO_FILES); 498 | #else 499 | Sij.saveHDF5(h5filename + filename + "_hij.h5"); 500 | #endif 501 | 502 | projection_init(&Sij); 503 | projection_Tij_project(&pcls_cdm, &Sij, a, &phi); 504 | for (i = 0; i < cosmo.num_ncdm; i++) 505 | projection_Tij_project(pcls_ncdm+i, &Sij, a, &phi); 506 | projection_Tij_comm(&Sij); 507 | } 508 | 509 | if (sim.out_snapshot & MASK_P) 510 | { 511 | #ifdef CHECK_B 512 | projection_init(&Bi_check); 513 | vectorProjectionCICNGP_project(&pcls_cdm, &Bi_check); 514 | for (i = 0; i < cosmo.num_ncdm; i++) 515 | vectorProjectionCICNGP_project(pcls_ncdm+i, &Bi_check); 516 | vectorProjectionCICNGP_comm(&Bi_check); 517 | Bi_check.saveHDF5(h5filename + filename + "_p.h5"); 518 | #else 519 | projection_init(&Bi); 520 | vectorProjectionCICNGP_project(&pcls_cdm, &Bi); 521 | for (i = 0; i < cosmo.num_ncdm; i++) 522 | vectorProjectionCICNGP_project(pcls_ncdm+i, &Bi); 523 | vectorProjectionCICNGP_comm(&Bi); 524 | Bi.saveHDF5(h5filename + filename + "_p.h5"); 525 | if (sim.gr_flag > 0) 526 | { 527 | plan_Bi.execute(FFT_BACKWARD); 528 | Bi.updateHalo(); 529 | } 530 | #endif 531 | } 532 | 533 | #ifdef CHECK_B 534 | if (sim.out_snapshot & MASK_B) 535 | { 536 | if (!(sim.out_snapshot & MASK_P)) 537 | { 538 | projection_init(&Bi_check); 539 | vectorProjectionCICNGP_project(&pcls_cdm, &Bi_check); 540 | for (i = 0; i < cosmo.num_ncdm; i++) 541 | vectorProjectionCICNGP_project(pcls_ncdm+i, &Bi_check); 542 | vectorProjectionCICNGP_comm(&Bi_check); 543 | } 544 | plan_Bi_check.execute(FFT_FORWARD); 545 | projectFTvector(BiFT_check, BiFT_check, fourpiG * dx * dx); 546 | plan_Bi_check.execute(FFT_BACKWARD); 547 | 548 | for (x.first(); x.test(); x.next()) 549 | { 550 | Bi_check(x,0) /= a * a * sim.numpts; 551 | Bi_check(x,1) /= a * a * sim.numpts; 552 | Bi_check(x,2) /= a * a * sim.numpts; 553 | } 554 | #ifdef EXTERNAL_IO 555 | Bi_check.saveHDF5_server_write(NUMBER_OF_IO_FILES); 556 | #else 557 | Bi_check.saveHDF5(h5filename + filename + "_B_check.h5"); 558 | #endif 559 | } 560 | #endif 561 | 562 | if (sim.out_snapshot & MASK_GADGET) 563 | { 564 | hdr.time = a; 565 | hdr.redshift = (1./a) - 1.; 566 | 567 | hdr.npart[1] = (unsigned int) (sim.numpcl[0] / sim.tracer_factor[0]); 568 | hdr.npartTotal[1] = hdr.npart[1]; 569 | hdr.mass[1] = (double) sim.tracer_factor[0] * 27.7459457 * (cosmo.Omega_cdm + cosmo.Omega_b) * sim.boxsize * sim.boxsize * sim.boxsize / sim.numpcl[0]; 570 | pcls_cdm.saveGadget2(h5filename + filename + "_part.dat", hdr, sim.tracer_factor[0]); 571 | for (i = 0; i < cosmo.num_ncdm; i++) 572 | { 573 | sprintf(buffer, "_ncdm%d.dat", i); 574 | hdr.npart[1] = (unsigned int) (sim.numpcl[i+1] / sim.tracer_factor[i+1]); 575 | hdr.npartTotal[1] = hdr.npart[1]; 576 | hdr.mass[1] = (double) sim.tracer_factor[i+1] * 27.7459457 * cosmo.Omega_ncdm[i] * sim.boxsize * sim.boxsize * sim.boxsize / sim.numpcl[i+1]; 577 | pcls_ncdm[i].saveGadget2(h5filename + filename + buffer, hdr, sim.tracer_factor[i+1]); 578 | } 579 | } 580 | 581 | if (sim.out_snapshot & MASK_PCLS) 582 | { 583 | #ifdef EXTERNAL_IO 584 | pcls_cdm.saveHDF5_server_write(); 585 | #else 586 | pcls_cdm.saveHDF5(h5filename + filename + "_part", 1); 587 | #endif 588 | } 589 | 590 | #ifdef EXTERNAL_IO 591 | ioserver.closeOstream(); 592 | #endif 593 | } // snapshot output done 594 | 595 | #ifdef BENCHMARK 596 | snapshot_output_time += MPI_Wtime() - ref_time; 597 | ref_time = MPI_Wtime(); 598 | #endif 599 | 600 | // power spectra 601 | if (pkcount < sim.num_pk && 1. / a < sim.z_pk[pkcount] + 1.) 602 | { 603 | pkcount++; 604 | 605 | COUT << " writing power spectra at z = " << ((1./a) - 1.) << " (cycle " << cycle << "), tau/boxsize = " << tau << endl; 606 | 607 | if (sim.out_pk & MASK_DBARE || sim.out_pk & MASK_POT || (sim.out_pk & MASK_T00 && sim.gr_flag == 0)) 608 | { 609 | if (!redo_psi && sim.gr_flag > 0) 610 | { 611 | projection_init(&psi); 612 | scalarProjectionCIC_project(&pcls_cdm, &psi); 613 | for (i = 0; i < cosmo.num_ncdm; i++) 614 | scalarProjectionCIC_project(pcls_ncdm+i, &psi); 615 | scalarProjectionCIC_comm(&psi); 616 | redo_psi = 1; 617 | plan_psi.execute(FFT_FORWARD); 618 | } 619 | else if (sim.gr_flag > 0) 620 | { 621 | plan_psi.execute(FFT_FORWARD); 622 | } 623 | else 624 | { 625 | plan_source.execute(FFT_FORWARD); 626 | } 627 | 628 | if (sim.out_pk & MASK_DBARE || (sim.out_pk & MASK_T00 && sim.gr_flag == 0)) 629 | extractPowerSpectrum(scalarFT, kbin, power, kscatter, pscatter, occupation, sim.numbins, true, KTYPE_LINEAR); 630 | 631 | if (sim.out_pk & MASK_DBARE) 632 | { 633 | sprintf(filename, "%s%s%03d_deltaN.dat", sim.output_path, sim.basename_pk, pkcount-1); 634 | writePowerSpectrum(kbin, power, kscatter, pscatter, occupation, sim.numbins, sim.boxsize, (Real) numpts3d * (Real) numpts3d * 2. * M_PI * M_PI, filename, "power spectrum of delta", a); 635 | } 636 | 637 | if (sim.out_pk & MASK_T00 && sim.gr_flag == 0) 638 | { 639 | sprintf(filename, "%s%s%03d_T00.dat", sim.output_path, sim.basename_pk, pkcount-1); 640 | writePowerSpectrum(kbin, power, kscatter, pscatter, occupation, sim.numbins, sim.boxsize, (Real) numpts3d * (Real) numpts3d * 2. * M_PI * M_PI, filename, "power spectrum of T00", a); 641 | } 642 | 643 | if (sim.out_pk & MASK_POT) 644 | { 645 | solveModifiedPoissonFT(scalarFT, scalarFT, fourpiG / a); 646 | extractPowerSpectrum(scalarFT, kbin, power, kscatter, pscatter, occupation, sim.numbins, false, KTYPE_LINEAR); 647 | sprintf(filename, "%s%s%03d_psiN.dat", sim.output_path, sim.basename_pk, pkcount-1); 648 | writePowerSpectrum(kbin, power, kscatter, pscatter, occupation, sim.numbins, sim.boxsize, (Real) numpts3d * (Real) numpts3d * 2. * M_PI * M_PI, filename, "power spectrum of psi_N", a); 649 | } 650 | 651 | if (cosmo.num_ncdm > 0 && (sim.out_pk & MASK_DBARE || (sim.out_pk & MASK_T00 && sim.gr_flag == 0))) 652 | { 653 | redo_psi = 1; 654 | projection_init(&psi); 655 | scalarProjectionCIC_project(&pcls_cdm, &psi); 656 | scalarProjectionCIC_comm(&psi); 657 | plan_psi.execute(FFT_FORWARD); 658 | extractPowerSpectrum(scalarFT, kbin, power, kscatter, pscatter, occupation, sim.numbins, false, KTYPE_LINEAR); 659 | sprintf(filename, "%s%s%03d_cdm.dat", sim.output_path, sim.basename_pk, pkcount-1); 660 | writePowerSpectrum(kbin, power, kscatter, pscatter, occupation, sim.numbins, sim.boxsize, (Real) numpts3d * (Real) numpts3d * 2. * M_PI * M_PI, filename, "power spectrum of delta for cdm", a); 661 | for (i = 0; i < cosmo.num_ncdm; i++) 662 | { 663 | projection_init(&psi); 664 | scalarProjectionCIC_project(pcls_ncdm+i, &psi); 665 | scalarProjectionCIC_comm(&psi); 666 | plan_psi.execute(FFT_FORWARD); 667 | extractPowerSpectrum(scalarFT, kbin, power, kscatter, pscatter, occupation, sim.numbins, false, KTYPE_LINEAR); 668 | sprintf(filename, "%s%s%03d_ncdm%d.dat", sim.output_path, sim.basename_pk, pkcount-1, i); 669 | sprintf(buffer, "power spectrum of delta for ncdm %d", i); 670 | writePowerSpectrum(kbin, power, kscatter, pscatter, occupation, sim.numbins, sim.boxsize, (Real) numpts3d * (Real) numpts3d * 2. * M_PI * M_PI, filename, buffer, a); 671 | #ifdef CHECK_B 672 | // store k-space information for cross-spectra using BiFT_check as temporary array 673 | if (cosmo.num_ncdm > 1 && i < cosmo.num_ncdm-1 && i < 3) 674 | { 675 | for (kFT.first(); kFT.test(); kFT.next()) 676 | BiFT_check(kFT, i) = scalarFT(kFT); 677 | } 678 | #endif 679 | } 680 | #ifdef CHECK_B 681 | for (i = 0; i < cosmo.num_ncdm-1 && i < 3; i++) 682 | { 683 | if (i > 0) 684 | { 685 | for (kFT.first(); kFT.test(); kFT.next()) 686 | scalarFT(kFT) = BiFT_check(kFT, i); 687 | } 688 | for (j = i+1; j < cosmo.num_ncdm && j <= 3; j++) 689 | { 690 | if (j > i+1) 691 | { 692 | for (kFT.first(); kFT.test(); kFT.next()) 693 | { 694 | tempk = BiFT_check(kFT, 0); 695 | BiFT_check(kFT, 0) = BiFT_check(kFT, j-1); 696 | BiFT_check(kFT, j-1) = tempk; 697 | } 698 | } 699 | 700 | extractCrossSpectrum(scalarFT, BiFT_check, kbin, power, kscatter, pscatter, occupation, sim.numbins, false, KTYPE_LINEAR); 701 | sprintf(filename, "%s%s%03d_ncdm%dx%d.dat", sim.output_path, sim.basename_pk, pkcount-1, i, j); 702 | if (cosmo.num_ncdm < 4) 703 | sprintf(buffer, "cross power spectrum of delta for ncdm %d x %d", (i+cosmo.num_ncdm-1)%cosmo.num_ncdm, (j+cosmo.num_ncdm-1)%cosmo.num_ncdm); 704 | else 705 | sprintf(buffer, "cross power spectrum of delta for ncdm %d x %d", (6-11*i+5*i*i)/2, i ? 4-j : (j+3)%4); 706 | writePowerSpectrum(kbin, power, kscatter, pscatter, occupation, sim.numbins, sim.boxsize, (Real) numpts3d * (Real) numpts3d * 2. * M_PI * M_PI, filename, buffer, a); 707 | } 708 | } 709 | #endif 710 | } 711 | } 712 | 713 | if (sim.out_pk & MASK_PHI) 714 | { 715 | plan_phi.execute(FFT_FORWARD); 716 | extractPowerSpectrum(scalarFT, kbin, power, kscatter, pscatter, occupation, sim.numbins, false, KTYPE_LINEAR); 717 | sprintf(filename, "%s%s%03d_phi.dat", sim.output_path, sim.basename_pk, pkcount-1); 718 | writePowerSpectrum(kbin, power, kscatter, pscatter, occupation, sim.numbins, sim.boxsize, (Real) numpts3d * (Real) numpts3d * 2. * M_PI * M_PI, filename, "power spectrum of phi", a); 719 | } 720 | 721 | if (sim.out_pk & MASK_CHI) 722 | { 723 | plan_chi.execute(FFT_FORWARD); 724 | extractPowerSpectrum(scalarFT, kbin, power, kscatter, pscatter, occupation, sim.numbins, false, KTYPE_LINEAR); 725 | sprintf(filename, "%s%s%03d_chi.dat", sim.output_path, sim.basename_pk, pkcount-1); 726 | writePowerSpectrum(kbin, power, kscatter, pscatter, occupation, sim.numbins, sim.boxsize, (Real) numpts3d * (Real) numpts3d * 2. * M_PI * M_PI, filename, "power spectrum of chi", a); 727 | } 728 | 729 | if (sim.out_pk & MASK_HIJ) 730 | { 731 | if (!doneTT) 732 | projectFTtensor(SijFT, SijFT); 733 | extractPowerSpectrum(SijFT, kbin, power, kscatter, pscatter, occupation, sim.numbins, false, KTYPE_LINEAR); 734 | sprintf(filename, "%s%s%03d_hij.dat", sim.output_path, sim.basename_pk, pkcount-1); 735 | writePowerSpectrum(kbin, power, kscatter, pscatter, occupation, sim.numbins, sim.boxsize, 2. * M_PI * M_PI, filename, "power spectrum of hij", a); 736 | } 737 | 738 | if (sim.out_pk & MASK_T00 && sim.gr_flag > 0) 739 | { 740 | plan_source.execute(FFT_FORWARD); 741 | extractPowerSpectrum(scalarFT, kbin, power, kscatter, pscatter, occupation, sim.numbins, true, KTYPE_LINEAR); 742 | sprintf(filename, "%s%s%03d_T00.dat", sim.output_path, sim.basename_pk, pkcount-1); 743 | writePowerSpectrum(kbin, power, kscatter, pscatter, occupation, sim.numbins, sim.boxsize, (Real) numpts3d * (Real) numpts3d * 2. * M_PI * M_PI, filename, "power spectrum of T00", a); 744 | 745 | if (cosmo.num_ncdm > 0) 746 | { 747 | redo_psi = 1; 748 | projection_init(&psi); 749 | projection_T00_project(&pcls_cdm, &psi, a, &phi); 750 | projection_T00_comm(&psi); 751 | plan_psi.execute(FFT_FORWARD); 752 | extractPowerSpectrum(scalarFT, kbin, power, kscatter, pscatter, occupation, sim.numbins, false, KTYPE_LINEAR); 753 | sprintf(filename, "%s%s%03d_T00cdm.dat", sim.output_path, sim.basename_pk, pkcount-1); 754 | writePowerSpectrum(kbin, power, kscatter, pscatter, occupation, sim.numbins, sim.boxsize, (Real) numpts3d * (Real) numpts3d * 2. * M_PI * M_PI, filename, "power spectrum of T00 for cdm", a); 755 | for (i = 0; i < cosmo.num_ncdm; i++) 756 | { 757 | projection_init(&psi); 758 | projection_T00_project(pcls_ncdm+i, &psi, a, &phi); 759 | projection_T00_comm(&psi); 760 | plan_psi.execute(FFT_FORWARD); 761 | extractPowerSpectrum(scalarFT, kbin, power, kscatter, pscatter, occupation, sim.numbins, false, KTYPE_LINEAR); 762 | sprintf(filename, "%s%s%03d_T00ncdm%d.dat", sim.output_path, sim.basename_pk, pkcount-1, i); 763 | sprintf(buffer, "power spectrum of T00 for ncdm %d", i); 764 | writePowerSpectrum(kbin, power, kscatter, pscatter, occupation, sim.numbins, sim.boxsize, (Real) numpts3d * (Real) numpts3d * 2. * M_PI * M_PI, filename, buffer, a); 765 | #ifdef CHECK_B 766 | // store k-space information for cross-spectra using BiFT_check as temporary array 767 | if (cosmo.num_ncdm > 1 && i < 3) 768 | { 769 | for (kFT.first(); kFT.test(); kFT.next()) 770 | BiFT_check(kFT, i) = scalarFT(kFT); 771 | } 772 | #endif 773 | } 774 | #ifdef CHECK_B 775 | for (i = 0; i < cosmo.num_ncdm-1 && i < 3; i++) 776 | { 777 | if (i > 0) 778 | { 779 | for (kFT.first(); kFT.test(); kFT.next()) 780 | scalarFT(kFT) = BiFT_check(kFT, i); 781 | } 782 | for (j = i+1; j < cosmo.num_ncdm && j <=3; j++) 783 | { 784 | if (j > i+1) 785 | { 786 | for (kFT.first(); kFT.test(); kFT.next()) 787 | { 788 | tempk = BiFT_check(kFT, 0); 789 | BiFT_check(kFT, 0) = BiFT_check(kFT, j-1); 790 | BiFT_check(kFT, j-1) = tempk; 791 | } 792 | } 793 | 794 | extractCrossSpectrum(scalarFT, BiFT_check, kbin, power, kscatter, pscatter, occupation, sim.numbins, false, KTYPE_LINEAR); 795 | sprintf(filename, "%s%s%03d_T00ncdm%dx%d.dat", sim.output_path, sim.basename_pk, pkcount-1, i, j); 796 | if (cosmo.num_ncdm < 4) 797 | sprintf(buffer, "cross power spectrum of T00 for ncdm %d x %d", (i+cosmo.num_ncdm-1)%cosmo.num_ncdm, (j+cosmo.num_ncdm-1)%cosmo.num_ncdm); 798 | else 799 | sprintf(buffer, "cross power spectrum of T00 for ncdm %d x %d", (6-11*i+5*i*i)/2, i ? 4-j : (j+3)%4); 800 | writePowerSpectrum(kbin, power, kscatter, pscatter, occupation, sim.numbins, sim.boxsize, (Real) numpts3d * (Real) numpts3d * 2. * M_PI * M_PI, filename, buffer, a); 801 | } 802 | } 803 | #endif 804 | } 805 | } 806 | 807 | if (sim.out_pk & MASK_B) 808 | { 809 | extractPowerSpectrum(BiFT, kbin, power, kscatter, pscatter, occupation, sim.numbins, false, KTYPE_LINEAR); 810 | sprintf(filename, "%s%s%03d_B.dat", sim.output_path, sim.basename_pk, pkcount-1); 811 | writePowerSpectrum(kbin, power, kscatter, pscatter, occupation, sim.numbins, sim.boxsize, a * a * a * a * sim.numpts * sim.numpts * 2. * M_PI * M_PI, filename, "power spectrum of B", a); 812 | 813 | #ifdef CHECK_B 814 | projection_init(&Bi_check); 815 | vectorProjectionCICNGP_project(&pcls_cdm,&Bi_check); 816 | for (i = 0; i < cosmo.num_ncdm; i++) 817 | vectorProjectionCICNGP_project(pcls_ncdm+i, &Bi_check); 818 | vectorProjectionCICNGP_comm(&Bi_check); 819 | plan_Bi_check.execute(FFT_FORWARD); 820 | projectFTvector(BiFT_check, BiFT_check, fourpiG * dx * dx); 821 | extractPowerSpectrum(BiFT_check, kbin, power, kscatter, pscatter, occupation, sim.numbins, false, KTYPE_LINEAR); 822 | sprintf(filename, "%s%s%03d_B_check.dat", sim.output_path, sim.basename_pk, pkcount-1); 823 | writePowerSpectrum(kbin, power, kscatter, pscatter, occupation, sim.numbins, sim.boxsize, a * a * a * a * sim.numpts * sim.numpts * 2. * M_PI * M_PI, filename, "power spectrum of B", a); 824 | #endif 825 | } 826 | } // power spectra done 827 | 828 | #ifdef BENCHMARK 829 | spectra_output_time += MPI_Wtime() - ref_time; 830 | ref_time = MPI_Wtime(); 831 | #endif 832 | 833 | if (sim.gr_flag > 0) 834 | { 835 | if (redo_psi) 836 | { 837 | for (x.first(); x.test(); x.next()) 838 | psi(x) = phi(x) - chi(x); 839 | redo_psi = 0; 840 | } 841 | 842 | T00hom = 0.; 843 | for (x.first(); x.test(); x.next()) 844 | T00hom += source(x); 845 | parallel.sum(T00hom); 846 | T00hom /= (Real) numpts3d; 847 | 848 | if (cycle % 10 == 0) 849 | { 850 | COUT << " cycle " << cycle << ", background information: z = " << (1./a) - 1. << ", average T00 = " << T00hom << ", background model = " << cosmo.Omega_cdm + cosmo.Omega_b + bg_ncdm(a, cosmo) << endl; 851 | } 852 | 853 | prepareFTsource(phi, psi, source, cosmo.Omega_cdm + cosmo.Omega_b + bg_ncdm(a, cosmo), source, 3. * Hconf(a, fourpiG, cosmo) * dx * dx / dtau_old, fourpiG * dx * dx / a, 3. * Hconf(a, fourpiG, cosmo) * Hconf(a, fourpiG, cosmo) * dx * dx); // prepare nonlinear source for phi update 854 | 855 | #ifdef BENCHMARK 856 | ref2_time= MPI_Wtime(); 857 | #endif 858 | plan_source.execute(FFT_FORWARD); // go to k-space 859 | #ifdef BENCHMARK 860 | fft_time += MPI_Wtime() - ref2_time; 861 | fft_count++; 862 | #endif 863 | 864 | solveModifiedPoissonFT(scalarFT, scalarFT, 1. / (dx * dx), 3. * Hconf(a, fourpiG, cosmo) / dtau_old); // phi update (k-space) 865 | } 866 | else 867 | { 868 | #ifdef BENCHMARK 869 | ref2_time= MPI_Wtime(); 870 | #endif 871 | plan_source.execute(FFT_FORWARD); // Newton: directly go to k-space 872 | #ifdef BENCHMARK 873 | fft_time += MPI_Wtime() - ref2_time; 874 | fft_count++; 875 | #endif 876 | 877 | solveModifiedPoissonFT(scalarFT, scalarFT, fourpiG / a); // Newton: phi update (k-space) 878 | } 879 | 880 | #ifdef BENCHMARK 881 | ref2_time= MPI_Wtime(); 882 | #endif 883 | plan_phi.execute(FFT_BACKWARD); // go back to position space 884 | #ifdef BENCHMARK 885 | fft_time += MPI_Wtime() - ref2_time; 886 | fft_count++; 887 | #endif 888 | phi.updateHalo(); // communicate halo values 889 | 890 | // record some background data 891 | if (kFT.setCoord(0, 0, 0)) 892 | { 893 | sprintf(filename, "%s%s_background.dat", sim.output_path, sim.basename_generic); 894 | outfile = fopen(filename, "a"); 895 | if (outfile == NULL) 896 | { 897 | cout << " error opening file for background output!" << endl; 898 | } 899 | else 900 | { 901 | if (cycle == 0) 902 | fprintf(outfile, "# background statistics\n# cycle tau/boxsize a conformal H/H0 phi(k=0) T00(k=0)\n"); 903 | fprintf(outfile, " %6d %e %e %e %e %e\n", cycle, tau, a, Hconf(a, fourpiG, cosmo) / Hconf(1., fourpiG, cosmo), scalarFT(kFT).real(), T00hom); 904 | fclose(outfile); 905 | } 906 | } 907 | // done recording background data 908 | 909 | if (pkcount >= sim.num_pk && snapcount >= sim.num_snapshot) break; // simulation complete 910 | 911 | prepareFTsource(phi, Sij, Sij, 2. * fourpiG * dx * dx / a); // prepare nonlinear source for additional equations 912 | 913 | #ifdef BENCHMARK 914 | ref2_time= MPI_Wtime(); 915 | #endif 916 | plan_Sij.execute(FFT_FORWARD); // go to k-space 917 | #ifdef BENCHMARK 918 | fft_time += MPI_Wtime() - ref2_time; 919 | fft_count += 6; 920 | #endif 921 | 922 | projectFTscalar(SijFT, scalarFT); // construct chi by scalar projection (k-space) 923 | 924 | evolveFTvector(SijFT, BiFT, a * a * dtau_old); // evlolve B using vector projection (k-space) 925 | 926 | #ifdef BENCHMARK 927 | ref2_time= MPI_Wtime(); 928 | #endif 929 | plan_chi.execute(FFT_BACKWARD); // go back to position space 930 | #ifdef BENCHMARK 931 | fft_time += MPI_Wtime() - ref2_time; 932 | fft_count++; 933 | #endif 934 | chi.updateHalo(); // communicale halo values 935 | 936 | if (sim.gr_flag > 0) 937 | { 938 | for (x.first(); x.test(); x.next()) // update psi 939 | psi(x) = phi(x) - chi(x); 940 | 941 | #ifdef BENCHMARK 942 | ref2_time= MPI_Wtime(); 943 | #endif 944 | plan_Bi.execute(FFT_BACKWARD); // go back to position space 945 | #ifdef BENCHMARK 946 | fft_time += MPI_Wtime() - ref2_time; 947 | fft_count += 3; 948 | #endif 949 | Bi.updateHalo(); // communicate halo values 950 | } 951 | else 952 | { 953 | for (x.first(); x.test(); x.next()) // Newton: update psi 954 | psi(x) = phi(x); 955 | } 956 | 957 | psi.updateHalo(); // communicate halo values 958 | 959 | // compute number of step subdivisions for particle updates 960 | numsteps = 1; 961 | for (i = 0; i < cosmo.num_ncdm; i++) 962 | { 963 | if (dtau * maxvel_ncdm[i] > dx * sim.movelimit) 964 | numsteps_ncdm[i] = (int) ceil(dtau * maxvel_ncdm[i] / dx / sim.movelimit); 965 | else numsteps_ncdm[i] = 1; 966 | 967 | if (numsteps < numsteps_ncdm[i]) numsteps = numsteps_ncdm[i]; 968 | } 969 | if (numsteps > 1 && numsteps % 2 > 0) numsteps++; // if >1, make it an even number 970 | 971 | for (i = 0; i < cosmo.num_ncdm; i++) 972 | { 973 | if (numsteps / numsteps_ncdm[i] <= 1) numsteps_ncdm[i] = numsteps; 974 | else if (numsteps_ncdm[i] > 1) numsteps_ncdm[i] = numsteps / 2; 975 | } 976 | 977 | if (cycle % 10 == 0) 978 | { 979 | COUT << " cycle " << cycle << ", time integration information: max |v| = " << maxvel << " (cdm Courant factor = " << maxvel * sim.Cf << "), time step / Hubble time = " << Hconf(a, fourpiG, cosmo) * dtau; 980 | 981 | for (i = 0; i < cosmo.num_ncdm; i++) 982 | { 983 | if (i == 0) 984 | { 985 | COUT << endl << " time step subdivision for ncdm species: "; 986 | } 987 | COUT << numsteps_ncdm[i] << " (max |v| = " << maxvel_ncdm[i] << ")"; 988 | if (i < cosmo.num_ncdm-1) 989 | { 990 | COUT << ", "; 991 | } 992 | } 993 | 994 | COUT << endl; 995 | } 996 | 997 | for (j = 0; j < numsteps; j++) // particle update 998 | { 999 | #ifdef BENCHMARK 1000 | ref2_time = MPI_Wtime(); 1001 | #endif 1002 | f_params[0] = a; 1003 | f_params[1] = a * a * sim.numpts; 1004 | if (j == 0) 1005 | { 1006 | if (sim.gr_flag > 0) 1007 | maxvel = pcls_cdm.updateVel(update_q, (dtau + dtau_old) / 2., update_cdm_fields, (1. / a < ic.z_relax + 1. ? 3 : 1), f_params); 1008 | else 1009 | maxvel = pcls_cdm.updateVel(update_q_Newton, (dtau + dtau_old) / 2., update_cdm_fields, 1, f_params); 1010 | 1011 | #ifdef BENCHMARK 1012 | update_q_count++; 1013 | #endif 1014 | } 1015 | 1016 | for (i = 0; i < cosmo.num_ncdm; i++) 1017 | { 1018 | if (j % (numsteps / numsteps_ncdm[i]) == 0) 1019 | { 1020 | if (sim.gr_flag > 0) 1021 | maxvel_ncdm[i] = pcls_ncdm[i].updateVel(update_q, (dtau + dtau_old) / 2. / numsteps_ncdm[i], update_ncdm_fields, (1. / a < ic.z_relax + 1. ? 3 : 2), f_params); 1022 | else 1023 | maxvel_ncdm[i] = pcls_ncdm[i].updateVel(update_q_Newton, (dtau + dtau_old) / 2. / numsteps_ncdm[i], update_ncdm_fields, 1, f_params); 1024 | 1025 | #ifdef BENCHMARK 1026 | update_q_count++; 1027 | #endif 1028 | } 1029 | } 1030 | #ifdef BENCHMARK 1031 | update_q_time += MPI_Wtime() - ref2_time; 1032 | ref2_time = MPI_Wtime(); 1033 | #endif 1034 | if (numsteps > 1 && j == numsteps / 2) 1035 | { 1036 | if (sim.gr_flag > 0) 1037 | pcls_cdm.moveParticles(update_pos, dtau, update_cdm_fields, (1. / a < ic.z_relax + 1. ? 3 : 0), f_params); 1038 | else 1039 | pcls_cdm.moveParticles(update_pos_Newton, dtau, NULL, 0, f_params); 1040 | 1041 | #ifdef BENCHMARK 1042 | moveParts_count++; 1043 | #endif 1044 | } 1045 | 1046 | for (i = 0; i < cosmo.num_ncdm; i++) 1047 | { 1048 | if (numsteps > 1 && ((numsteps_ncdm[i] == 1 && j == numsteps / 2) || (numsteps_ncdm[i] == numsteps / 2 && j % 2 > 0))) 1049 | { 1050 | if (sim.gr_flag > 0) 1051 | pcls_ncdm[i].moveParticles(update_pos, dtau / numsteps_ncdm[i], update_ncdm_fields, (1. / a < ic.z_relax + 1. ? 3 : 2), f_params); 1052 | else 1053 | pcls_ncdm[i].moveParticles(update_pos_Newton, dtau / numsteps_ncdm[i], NULL, 0, f_params); 1054 | 1055 | #ifdef BENCHMARK 1056 | moveParts_count++; 1057 | #endif 1058 | } 1059 | } 1060 | #ifdef BENCHMARK 1061 | moveParts_time += MPI_Wtime() - ref2_time; 1062 | #endif 1063 | rungekutta4bg(a, fourpiG, cosmo, 0.5 * dtau / numsteps); // evolve background by half a time step 1064 | #ifdef BENCHMARK 1065 | ref2_time = MPI_Wtime(); 1066 | #endif 1067 | f_params[0] = a; 1068 | f_params[1] = a * a * sim.numpts; 1069 | if (numsteps == 1) 1070 | { 1071 | if (sim.gr_flag > 0) 1072 | pcls_cdm.moveParticles(update_pos, dtau, update_cdm_fields, (1. / a < ic.z_relax + 1. ? 3 : 0), f_params); 1073 | else 1074 | pcls_cdm.moveParticles(update_pos_Newton, dtau, NULL, 0, f_params); 1075 | 1076 | #ifdef BENCHMARK 1077 | moveParts_count++; 1078 | #endif 1079 | } 1080 | 1081 | for (i = 0; i < cosmo.num_ncdm; i++) 1082 | { 1083 | if (numsteps_ncdm[i] == numsteps) 1084 | { 1085 | if (sim.gr_flag > 0) 1086 | pcls_ncdm[i].moveParticles(update_pos, dtau / numsteps_ncdm[i], update_ncdm_fields, (1. / a < ic.z_relax + 1. ? 3 : 2), f_params); 1087 | else 1088 | pcls_ncdm[i].moveParticles(update_pos_Newton, dtau / numsteps_ncdm[i], NULL, 0, f_params); 1089 | 1090 | #ifdef BENCHMARK 1091 | moveParts_count++; 1092 | #endif 1093 | } 1094 | } 1095 | #ifdef BENCHMARK 1096 | moveParts_time += MPI_Wtime() - ref2_time; 1097 | #endif 1098 | rungekutta4bg(a, fourpiG, cosmo, 0.5 * dtau / numsteps); // evolve background by half a time step 1099 | } // particle update done 1100 | 1101 | parallel.max(maxvel); 1102 | if (cosmo.num_ncdm > 0) parallel.max(maxvel_ncdm, cosmo.num_ncdm); 1103 | 1104 | if (sim.gr_flag > 0) 1105 | { 1106 | maxvel /= sqrt(maxvel * maxvel + 1.0); 1107 | for (i = 0; i < cosmo.num_ncdm; i++) 1108 | maxvel_ncdm[i] /= sqrt(maxvel_ncdm[i] * maxvel_ncdm[i] + 1.0); 1109 | } 1110 | 1111 | tau += dtau; 1112 | 1113 | if (tau_Lambda < 0. && (cosmo.Omega_m / a / a / a) < cosmo.Omega_Lambda) 1114 | { 1115 | tau_Lambda = tau; 1116 | COUT << "matter-dark energy equality at z=" << ((1./a) - 1.) << endl; 1117 | } 1118 | 1119 | dtau_old = dtau; 1120 | 1121 | if (sim.Cf * dx < sim.steplimit / Hconf(a, fourpiG, cosmo)) 1122 | dtau = sim.Cf * dx; 1123 | else 1124 | dtau = sim.steplimit / Hconf(a, fourpiG, cosmo); 1125 | 1126 | cycle++; 1127 | 1128 | #ifdef BENCHMARK 1129 | gravity_solver_time += MPI_Wtime() - ref_time; 1130 | cycle_time += MPI_Wtime()-cycle_start_time; 1131 | #endif 1132 | } 1133 | 1134 | COUT << " simulation complete." << endl; 1135 | 1136 | #ifdef BENCHMARK 1137 | run_time = MPI_Wtime() - start_time; 1138 | 1139 | parallel.sum(run_time); 1140 | parallel.sum(cycle_time); 1141 | parallel.sum(projection_time); 1142 | parallel.sum(snapshot_output_time); 1143 | parallel.sum(spectra_output_time); 1144 | parallel.sum(gravity_solver_time); 1145 | parallel.sum(fft_time); 1146 | parallel.sum(update_q_time); 1147 | parallel.sum(moveParts_time); 1148 | 1149 | COUT << endl << "BENCHMARK" << endl; 1150 | COUT << "total execution time : "< 17 | #include 18 | #include 19 | #include "metadata.hpp" 20 | 21 | #ifndef PARAM_MAX_LENGTH 22 | #define PARAM_MAX_LENGTH 64 23 | #endif 24 | #ifndef PARAM_MAX_LINESIZE 25 | #define PARAM_MAX_LINESIZE 256 26 | #endif 27 | 28 | using namespace std; 29 | 30 | struct parameter 31 | { 32 | char name[PARAM_MAX_LENGTH]; 33 | char value[PARAM_MAX_LENGTH]; 34 | bool used; 35 | }; 36 | 37 | 38 | int compare_redshifts (const void * z1, const void * z2) 39 | { 40 | if (* (double *) z1 > * (double *) z2) 41 | return -1; 42 | else if (* (double *) z1 < * (double *) z2) 43 | return 1; 44 | else 45 | return 0; 46 | } 47 | 48 | 49 | ////////////////////////// 50 | // readline 51 | ////////////////////////// 52 | // Description: 53 | // reads a line of characters and checks if it declares a parameter; if yes, 54 | // i.e. the line has the format " = " (with 55 | // an optional comment added, preceded by a hash-symbol, '#'), the parameter 56 | // name and value are copied to the corresponding arrays, and 'true' is returned. 57 | // If the format is not recognized (or the line is commented using the hash-symbol) 58 | // 'false' is returned instead. 59 | // 60 | // Arguments: 61 | // line string containing the line to be read 62 | // pname will contain the name of the declared parameter (if found) 63 | // pvalue will contain the value of the declared parameter (if found) 64 | // 65 | // Returns: 66 | // 'true' if a parameter is declared in the line, 'false' otherwise. 67 | // 68 | ////////////////////////// 69 | 70 | bool readline(char * line, char * pname, char * pvalue) 71 | { 72 | char * pequal; 73 | char * phash; 74 | char * l; 75 | char * r; 76 | 77 | pequal = strchr(line, '='); 78 | 79 | if (pequal == NULL || pequal == line) return false; 80 | 81 | phash = strchr(line, '#'); 82 | 83 | if (phash != NULL && phash < pequal) return false; 84 | 85 | l = line; 86 | while (*l == ' ' || *l == '\t') l++; 87 | 88 | r = pequal-1; 89 | while ((*r == ' ' || *r == '\t') && r > line) r--; 90 | 91 | if (r < l) return false; 92 | 93 | if (r-l+1 >= PARAM_MAX_LENGTH) return false; 94 | 95 | strncpy(pname, l, r-l+1); 96 | pname[r-l+1] = '\0'; 97 | 98 | l = pequal+1; 99 | while (*l == ' ' || *l == '\t') l++; 100 | 101 | if (phash == NULL) 102 | r = line+strlen(line)-1; 103 | else 104 | r = phash-1; 105 | 106 | while (*r == ' ' || *r == '\t' || *r == '\n' || *r == '\r') r--; 107 | 108 | if (r < l) return false; 109 | 110 | if (r-l+1 >= PARAM_MAX_LENGTH) return false; 111 | 112 | strncpy(pvalue, l, r-l+1); 113 | pvalue[r-l+1] = '\0'; 114 | 115 | return true; 116 | } 117 | 118 | 119 | ////////////////////////// 120 | // loadParameterFile 121 | ////////////////////////// 122 | // Description: 123 | // loads a parameter file and creates an array of parameters declared therein 124 | // 125 | // Arguments: 126 | // filename string containing the path to the parameter file 127 | // params will contain the array of parameters (memory will be allocated) 128 | // 129 | // Returns: 130 | // number of parameters defined in the parameter file (= length of parameter array) 131 | // 132 | ////////////////////////// 133 | 134 | int loadParameterFile(const char * filename, parameter * & params) 135 | { 136 | int numparam = 0; 137 | int i = 0; 138 | 139 | if (parallel.grid_rank()[0] == 0) // read file 140 | { 141 | FILE * paramfile; 142 | char line[PARAM_MAX_LINESIZE]; 143 | char pname[PARAM_MAX_LENGTH]; 144 | char pvalue[PARAM_MAX_LENGTH]; 145 | 146 | paramfile = fopen(filename, "r"); 147 | 148 | if (paramfile == NULL) 149 | { 150 | cerr << " proc#" << parallel.rank() << ": error in loadParameterFile! Unable to open parameter file " << filename << "." << endl; 151 | parallel.abortForce(); 152 | } 153 | 154 | while (!feof(paramfile) && !ferror(paramfile)) 155 | { 156 | fgets(line, PARAM_MAX_LINESIZE, paramfile); 157 | 158 | if (readline(line, pname, pvalue) == true) numparam++; 159 | } 160 | 161 | if (numparam == 0) 162 | { 163 | cerr << " proc#" << parallel.rank() << ": error in loadParameterFile! No valid data found in file " << filename << "." << endl; 164 | fclose(paramfile); 165 | parallel.abortForce(); 166 | } 167 | 168 | params = (parameter *) malloc(sizeof(parameter) * numparam); 169 | 170 | if (params == NULL) 171 | { 172 | cerr << " proc#" << parallel.rank() << ": error in loadParameterFile! Memory error." << endl; 173 | fclose(paramfile); 174 | parallel.abortForce(); 175 | } 176 | 177 | rewind(paramfile); 178 | 179 | while (!feof(paramfile) && !ferror(paramfile) && i < numparam) 180 | { 181 | fgets(line, PARAM_MAX_LINESIZE, paramfile); 182 | 183 | if (readline(line, params[i].name, params[i].value) == true) 184 | { 185 | params[i].used = false; 186 | i++; 187 | } 188 | } 189 | 190 | fclose(paramfile); 191 | 192 | if (i < numparam) 193 | { 194 | cerr << " proc#" << parallel.rank() << ": error in loadParameterFile! File may have changed or file pointer corrupted." << endl; 195 | free(params); 196 | parallel.abortForce(); 197 | } 198 | 199 | parallel.broadcast_dim0(numparam, 0); 200 | } 201 | else 202 | { 203 | parallel.broadcast_dim0(numparam, 0); 204 | 205 | params = (parameter *) malloc(sizeof(parameter) * numparam); 206 | 207 | if (params == NULL) 208 | { 209 | cerr << " proc#" << parallel.rank() << ": error in loadParameterFile! Memory error." << endl; 210 | parallel.abortForce(); 211 | } 212 | } 213 | 214 | parallel.broadcast_dim0(params, numparam, 0); 215 | 216 | return numparam; 217 | } 218 | 219 | 220 | ////////////////////////// 221 | // saveParameterFile 222 | ////////////////////////// 223 | // Description: 224 | // saves a parameter file 225 | // 226 | // Arguments: 227 | // filename string containing the path to the parameter file 228 | // params array of parameters 229 | // numparam length of parameter array 230 | // used_only if 'true', only the used parameters will be written (default) 231 | // 232 | // Returns: 233 | // 234 | ////////////////////////// 235 | 236 | void saveParameterFile(const char * filename, parameter * params, const int numparam, bool used_only = true) 237 | { 238 | if (parallel.isRoot()) 239 | { 240 | FILE * paramfile; 241 | 242 | paramfile = fopen(filename, "w"); 243 | 244 | if (paramfile == NULL) 245 | { 246 | cout << " error in saveParameterFile! Unable to open file " << filename << "." << endl; 247 | } 248 | else 249 | { 250 | for (int i = 0; i < numparam; i++) 251 | { 252 | if (!used_only || params[i].used) 253 | fprintf(paramfile, "%s = %s\n", params[i].name, params[i].value); 254 | } 255 | 256 | fclose(paramfile); 257 | } 258 | } 259 | } 260 | 261 | 262 | ////////////////////////// 263 | // parseParameter (int) 264 | ////////////////////////// 265 | // Description: 266 | // searches parameter array for specified parameter name and parses its value as integer 267 | // 268 | // Arguments: 269 | // params array of parameters 270 | // numparam length of parameter array 271 | // pname name of parameter to search for 272 | // pvalue reference to integer which will contain the parsed parameter value (if found) 273 | // 274 | // Returns: 275 | // 'true' if parameter is found and parsed successfully, 'false' otherwise 276 | // 277 | ////////////////////////// 278 | 279 | bool parseParameter(parameter * & params, const int numparam, const char * pname, int & pvalue) 280 | { 281 | for (int i = 0; i < numparam; i++) 282 | { 283 | if (strcmp(params[i].name, pname) == 0) 284 | { 285 | if (sscanf(params[i].value, "%d", &pvalue) == 1) 286 | { 287 | params[i].used = true; 288 | return true; 289 | } 290 | } 291 | } 292 | 293 | return false; 294 | } 295 | 296 | 297 | ////////////////////////// 298 | // parseParameter (long) 299 | ////////////////////////// 300 | // Description: 301 | // searches parameter array for specified parameter name and parses its value as integer 302 | // 303 | // Arguments: 304 | // params array of parameters 305 | // numparam length of parameter array 306 | // pname name of parameter to search for 307 | // pvalue reference to integer which will contain the parsed parameter value (if found) 308 | // 309 | // Returns: 310 | // 'true' if parameter is found and parsed successfully, 'false' otherwise 311 | // 312 | ////////////////////////// 313 | 314 | bool parseParameter(parameter * & params, const int numparam, const char * pname, long & pvalue) 315 | { 316 | for (int i = 0; i < numparam; i++) 317 | { 318 | if (strcmp(params[i].name, pname) == 0) 319 | { 320 | if (sscanf(params[i].value, "%ld", &pvalue) == 1) 321 | { 322 | params[i].used = true; 323 | return true; 324 | } 325 | } 326 | } 327 | 328 | return false; 329 | } 330 | 331 | 332 | ////////////////////////// 333 | // parseParameter (double) 334 | ////////////////////////// 335 | // Description: 336 | // searches parameter array for specified parameter name and parses its value as double 337 | // 338 | // Arguments: 339 | // params array of parameters 340 | // numparam length of parameter array 341 | // pname name of parameter to search for 342 | // pvalue reference to double which will contain the parsed parameter value (if found) 343 | // 344 | // Returns: 345 | // 'true' if parameter is found and parsed successfully, 'false' otherwise 346 | // 347 | ////////////////////////// 348 | 349 | bool parseParameter(parameter * & params, const int numparam, const char * pname, double & pvalue) 350 | { 351 | for (int i = 0; i < numparam; i++) 352 | { 353 | if (strcmp(params[i].name, pname) == 0) 354 | { 355 | if (sscanf(params[i].value, "%lf", &pvalue) == 1) 356 | { 357 | params[i].used = true; 358 | return true; 359 | } 360 | } 361 | } 362 | 363 | return false; 364 | } 365 | 366 | 367 | ////////////////////////// 368 | // parseParameter (char *) 369 | ////////////////////////// 370 | // Description: 371 | // searches parameter array for specified parameter name and retrieves its value as string 372 | // 373 | // Arguments: 374 | // params array of parameters 375 | // numparam length of parameter array 376 | // pname name of parameter to search for 377 | // pvalue character string which will contain a copy of the parameter value (if found) 378 | // 379 | // Returns: 380 | // 'true' if parameter is found, 'false' otherwise 381 | // 382 | ////////////////////////// 383 | 384 | bool parseParameter(parameter * & params, const int numparam, const char * pname, char * pvalue) 385 | { 386 | for (int i = 0; i < numparam; i++) 387 | { 388 | if (strcmp(params[i].name, pname) == 0) 389 | { 390 | strcpy(pvalue, params[i].value); 391 | params[i].used = true; 392 | return true; 393 | } 394 | } 395 | 396 | return false; 397 | } 398 | 399 | 400 | ////////////////////////// 401 | // parseParameter (double *) 402 | ////////////////////////// 403 | // Description: 404 | // searches parameter array for specified parameter name and parses it as a list of comma-separated double values 405 | // 406 | // Arguments: 407 | // params array of parameters 408 | // numparam length of parameter array 409 | // pname name of parameter to search for 410 | // pvalue array of double values which will contain the list of parsed parameters (if found) 411 | // nmax maximum size of array; will be set to the actual size at return 412 | // 413 | // Returns: 414 | // 'true' if parameter is found, 'false' otherwise 415 | // 416 | ////////////////////////// 417 | 418 | bool parseParameter(parameter * & params, const int numparam, const char * pname, double * pvalue, int & nmax) 419 | { 420 | char * start; 421 | char * comma; 422 | char item[PARAM_MAX_LENGTH]; 423 | int n = 0; 424 | 425 | for (int i = 0; i < numparam; i++) 426 | { 427 | if (strcmp(params[i].name, pname) == 0) 428 | { 429 | start = params[i].value; 430 | if (nmax > 1) 431 | { 432 | while ((comma = strchr(start, ',')) != NULL) 433 | { 434 | strncpy(item, start, comma-start); 435 | item[comma-start] = '\0'; 436 | if (sscanf(item, " %lf ", pvalue+n) != 1) 437 | { 438 | nmax = n; 439 | return false; 440 | } 441 | start = comma+1; 442 | if (++n > nmax-2) 443 | break; 444 | } 445 | } 446 | if (sscanf(start, " %lf ", pvalue+n) != 1) 447 | { 448 | nmax = n; 449 | return false; 450 | } 451 | nmax = ++n; 452 | params[i].used = true; 453 | return true; 454 | } 455 | } 456 | 457 | nmax = 0; 458 | return false; 459 | } 460 | 461 | 462 | ////////////////////////// 463 | // parseParameter (int *) 464 | ////////////////////////// 465 | // Description: 466 | // searches parameter array for specified parameter name and parses it as a list of comma-separated integer values 467 | // 468 | // Arguments: 469 | // params array of parameters 470 | // numparam length of parameter array 471 | // pname name of parameter to search for 472 | // pvalue array of integer values which will contain the list of parsed parameters (if found) 473 | // nmax maximum size of array; will be set to the actual size at return 474 | // 475 | // Returns: 476 | // 'true' if parameter is found, 'false' otherwise 477 | // 478 | ////////////////////////// 479 | 480 | bool parseParameter(parameter * & params, const int numparam, const char * pname, int * pvalue, int & nmax) 481 | { 482 | char * start; 483 | char * comma; 484 | char item[PARAM_MAX_LENGTH]; 485 | int n = 0; 486 | 487 | for (int i = 0; i < numparam; i++) 488 | { 489 | if (strcmp(params[i].name, pname) == 0) 490 | { 491 | start = params[i].value; 492 | if (nmax > 1) 493 | { 494 | while ((comma = strchr(start, ',')) != NULL) 495 | { 496 | strncpy(item, start, comma-start); 497 | item[comma-start] = '\0'; 498 | if (sscanf(item, " %d ", pvalue+n) != 1) 499 | { 500 | nmax = n; 501 | return false; 502 | } 503 | start = comma+1; 504 | if (++n > nmax-2) 505 | break; 506 | } 507 | } 508 | if (sscanf(start, " %d ", pvalue+n) != 1) 509 | { 510 | nmax = n; 511 | return false; 512 | } 513 | nmax = ++n; 514 | params[i].used = true; 515 | return true; 516 | } 517 | } 518 | 519 | nmax = 0; 520 | return false; 521 | } 522 | 523 | 524 | ////////////////////////// 525 | // parseFieldSpecifiers 526 | ////////////////////////// 527 | // Description: 528 | // searches parameter array for specified parameter name and parses it as a list of comma-separated field specifiers 529 | // 530 | // Arguments: 531 | // params array of parameters 532 | // numparam length of parameter array 533 | // pname name of parameter to search for 534 | // pvalue integer which will contain the binary-encoded list of parsed specifiers (if found) 535 | // 536 | // Returns: 537 | // 'true' if parameter is found, 'false' otherwise 538 | // 539 | ////////////////////////// 540 | 541 | bool parseFieldSpecifiers(parameter * & params, const int numparam, const char * pname, int & pvalue) 542 | { 543 | char * start; 544 | char * comma; 545 | int pos; 546 | char item[PARAM_MAX_LENGTH]; 547 | 548 | for (int i = 0; i < numparam; i++) 549 | { 550 | if (strcmp(params[i].name, pname) == 0) 551 | { 552 | pvalue = 0; 553 | start = params[i].value; 554 | while ((comma = strchr(start, ',')) != NULL) 555 | { 556 | strncpy(item, start, comma-start); 557 | for (pos = comma-start; pos > 0; pos--) 558 | { 559 | if (item[pos-1] != ' ' && item[pos-1] != '\t') break; 560 | } 561 | item[pos] = '\0'; 562 | 563 | if (strcmp(item, "Phi") == 0 || strcmp(item, "phi") == 0) 564 | pvalue |= MASK_PHI; 565 | else if (strcmp(item, "Chi") == 0 || strcmp(item, "chi") == 0) 566 | pvalue |= MASK_CHI; 567 | else if (strcmp(item, "Pot") == 0 || strcmp(item, "pot") == 0 || strcmp(item, "Psi_N") == 0 || strcmp(item, "psi_N") == 0 || strcmp(item, "PsiN") == 0 || strcmp(item, "psiN") == 0) 568 | pvalue |= MASK_POT; 569 | else if (strcmp(item, "B") == 0 || strcmp(item, "Bi") == 0) 570 | pvalue |= MASK_B; 571 | else if (strcmp(item, "P") == 0 || strcmp(item, "p") == 0 || strcmp(item, "v") == 0) 572 | pvalue |= MASK_P; 573 | else if (strcmp(item, "T00") == 0 || strcmp(item, "rho") == 0) 574 | pvalue |= MASK_T00; 575 | else if (strcmp(item, "Tij") == 0) 576 | pvalue |= MASK_TIJ; 577 | else if (strcmp(item, "delta_N") == 0 || strcmp(item, "deltaN") == 0) 578 | pvalue |= MASK_DBARE; 579 | else if (strcmp(item, "hij") == 0 || strcmp(item, "GW") == 0) 580 | pvalue |= MASK_HIJ; 581 | else if (strcmp(item, "Gadget") == 0 || strcmp(item, "Gadget2") == 0 || strcmp(item, "gadget") == 0 || strcmp(item, "gadget2") == 0) 582 | pvalue |= MASK_GADGET; 583 | else if (strcmp(item, "Particles") == 0 || strcmp(item, "particles") == 0 || strcmp(item, "pcls") == 0 || strcmp(item, "part") == 0) 584 | pvalue |= MASK_PCLS; 585 | 586 | start = comma+1; 587 | while (*start == ' ' || *start == '\t') start++; 588 | } 589 | 590 | if (strcmp(start, "Phi") == 0 || strcmp(start, "phi") == 0) 591 | pvalue |= MASK_PHI; 592 | else if (strcmp(start, "Chi") == 0 || strcmp(start, "chi") == 0) 593 | pvalue |= MASK_CHI; 594 | else if (strcmp(start, "Pot") == 0 || strcmp(start, "pot") == 0 || strcmp(start, "Psi_N") == 0 || strcmp(start, "psi_N") == 0 || strcmp(start, "PsiN") == 0 || strcmp(start, "psiN") == 0) 595 | pvalue |= MASK_POT; 596 | else if (strcmp(start, "B") == 0 || strcmp(start, "Bi") == 0) 597 | pvalue |= MASK_B; 598 | else if (strcmp(start, "P") == 0 || strcmp(start, "p") == 0 || strcmp(start, "v") == 0) 599 | pvalue |= MASK_P; 600 | else if (strcmp(start, "T00") == 0 || strcmp(start, "rho") == 0) 601 | pvalue |= MASK_T00; 602 | else if (strcmp(start, "Tij") == 0) 603 | pvalue |= MASK_TIJ; 604 | else if (strcmp(start, "delta_N") == 0 || strcmp(start, "deltaN") == 0) 605 | pvalue |= MASK_DBARE; 606 | else if (strcmp(start, "hij") == 0 || strcmp(start, "GW") == 0) 607 | pvalue |= MASK_HIJ; 608 | else if (strcmp(start, "Gadget") == 0 || strcmp(start, "Gadget2") == 0 || strcmp(start, "gadget") == 0 || strcmp(start, "gadget2") == 0) 609 | pvalue |= MASK_GADGET; 610 | else if (strcmp(start, "Particles") == 0 || strcmp(start, "particles") == 0 || strcmp(start, "pcls") == 0 || strcmp(start, "part") == 0) 611 | pvalue |= MASK_PCLS; 612 | 613 | params[i].used = true; 614 | return true; 615 | } 616 | } 617 | 618 | return false; 619 | } 620 | 621 | 622 | ////////////////////////// 623 | // parseMetadata 624 | ////////////////////////// 625 | // Description: 626 | // parses all metadata from the parameter array 627 | // 628 | // Arguments: 629 | // params array of parameters 630 | // numparam length of parameter array 631 | // sim reference to metadata stucture (holds simulation parameters) 632 | // cosmo reference to cosmology structure (holds cosmological parameters) 633 | // ic reference to icsettings structure (holds settings for IC generation) 634 | // 635 | // Returns: 636 | // number of parameters parsed 637 | // 638 | ////////////////////////// 639 | 640 | int parseMetadata(parameter * & params, const int numparam, metadata & sim, cosmology & cosmo, icsettings & ic) 641 | { 642 | char par_string[PARAM_MAX_LENGTH]; 643 | char * ptr; 644 | int usedparams = 0; 645 | int i; 646 | 647 | // parse settings for IC generator 648 | 649 | ic.seed = 0; 650 | ic.flags = 0; 651 | ic.z_relax = -2.; 652 | ic.steplimit = 0.2; 653 | ic.A_s = 2.215e-9; 654 | ic.n_s = 0.9619; 655 | 656 | parseParameter(params, numparam, "seed", ic.seed); 657 | 658 | if (parseParameter(params, numparam, "IC generator", par_string)) 659 | { 660 | if (par_string[0] == 'B' || par_string[0] == 'b') 661 | ic.generator = ICGEN_BASIC; 662 | else if (par_string[0] == 'R' || par_string[0] == 'r') 663 | ic.generator = ICGEN_READ_FROM_DISK; 664 | #ifdef ICGEN_PREVOLUTION 665 | else if (par_string[0] == 'P' || par_string[0] == 'p') 666 | ic.generator = ICGEN_PREVOLUTION; 667 | #endif 668 | #ifdef ICGEN_SONG 669 | else if (par_string[0] == 'S' || par_string[0] == 's') 670 | ic.generator = ICGEN_SONG; 671 | #endif 672 | #ifdef ICGEN_FALCONIC 673 | else if (par_string[0] == 'F' || par_string[0] == 'f') 674 | ic.generator = ICGEN_FALCONIC; 675 | #endif 676 | else 677 | { 678 | COUT << " error: IC generator not recognized!" << endl; 679 | parallel.abortForce(); 680 | } 681 | } 682 | else 683 | { 684 | COUT << " warning: IC generator not specified, selecting default (basic)" << endl; 685 | ic.generator = ICGEN_BASIC; 686 | } 687 | 688 | if (!parseParameter(params, numparam, "template file", ic.pclfile)) 689 | { 690 | COUT << " error: no template file specified!" << endl; 691 | parallel.abortForce(); 692 | } 693 | 694 | if (!parseParameter(params, numparam, "mPk file", ic.pkfile)) 695 | { 696 | COUT << " error: no power spectrum file specified!" << endl; 697 | parallel.abortForce(); 698 | } 699 | 700 | if (parseParameter(params, numparam, "correct displacement", par_string)) 701 | { 702 | if (par_string[0] == 'Y' || par_string[0] == 'y') 703 | ic.flags |= ICFLAG_CORRECT_DISPLACEMENT; 704 | else if (par_string[0] != 'N' && par_string[0] != 'n') 705 | COUT << " warning: setting chosen for deconvolve displacement option not recognized, using default (no)" << endl; 706 | } 707 | 708 | if (parseParameter(params, numparam, "k-domain", par_string)) 709 | { 710 | if (par_string[0] == 'S' || par_string[0] == 's') 711 | ic.flags |= ICFLAG_KSPHERE; 712 | else if (par_string[0] != 'C' && par_string[0] != 'c') 713 | COUT << " warning: setting chosen for k-domain option not recognized, using default (cube)" << endl; 714 | } 715 | 716 | parseParameter(params, numparam, "tiling factor", ic.numtile); 717 | if (ic.numtile <= 0) 718 | { 719 | COUT << " warning: tiling number for particle template not set properly; using default value (1)" << endl; 720 | ic.numtile = 1; 721 | } 722 | 723 | parseParameter(params, numparam, "relaxation redshift", ic.z_relax); 724 | 725 | cosmo.num_ncdm = MAX_PCL_SPECIES; 726 | parseParameter(params, numparam, "PSD samples", cosmo.m_ncdm, cosmo.num_ncdm); 727 | for (i = 0; i < cosmo.num_ncdm; i++) 728 | { 729 | ic.psd_samples[i] = (int) floor(cosmo.m_ncdm[i]); 730 | if (ic.psd_samples[i] < 1) ic.psd_samples[i] = 1; 731 | } 732 | for(; i < MAX_PCL_SPECIES; i++) ic.psd_samples[i] = 1; 733 | 734 | #ifdef ICGEN_PREVOLUTION 735 | if (ic.generator == ICGEN_PREVOLUTION) 736 | { 737 | if (parseParameter(params, numparam, "k-mode files", ic.kmodefiles)) 738 | { 739 | if ((ptr = strchr(ic.kmodefiles, '*')) == NULL) 740 | { 741 | COUT << " error: missing wildcard character (*) in k-mode files = " << ic.kmodefiles << endl; 742 | parallel.abortForce(); 743 | } 744 | 745 | if (strchr(++ptr, '*') != NULL) 746 | { 747 | COUT << " error: two or more wildcard characters (*) detected in k-mode files = " << ic.kmodefiles << endl; 748 | parallel.abortForce(); 749 | } 750 | } 751 | else 752 | { 753 | COUT << " error: no k-mode files specified for IC generator = prevolution" << endl; 754 | parallel.abortForce(); 755 | } 756 | 757 | if (!parseParameter(params, numparam, "background file", ic.bgfile)) 758 | { 759 | COUT << " error: no background file specified for IC generator = prevolution" << endl; 760 | parallel.abortForce(); 761 | } 762 | 763 | if (!parseParameter(params, numparam, "IC redshift", ic.z_ic)) 764 | { 765 | COUT << " error: no IC redshift specified for IC generator = prevolution" << endl; 766 | parallel.abortForce(); 767 | } 768 | 769 | if (!parseParameter(params, numparam, "IC Courant factor", ic.Cf)) 770 | { 771 | COUT << " warning: no IC Courant factor specified for IC generator = prevolution; using default value (1)" << endl; 772 | ic.Cf = 1.; 773 | } 774 | } 775 | #endif 776 | 777 | #ifdef ICGEN_FALCONIC 778 | if (ic.generator == ICGEN_FALCONIC) 779 | { 780 | parseParameter(params, numparam, "A_s", ic.A_s); 781 | 782 | parseParameter(params, numparam, "n_s", ic.n_s); 783 | } 784 | #endif 785 | 786 | // parse metadata 787 | 788 | sim.numpts = 0; 789 | for (i = 0; i <= MAX_PCL_SPECIES; i++) sim.numpcl[i] = 0; 790 | sim.gr_flag = 0; 791 | sim.out_pk = 0; 792 | sim.out_snapshot = 0; 793 | sim.num_pk = MAX_OUTPUTS; 794 | sim.numbins = 0; 795 | sim.num_snapshot = MAX_OUTPUTS; 796 | for (i = 0; i <= MAX_PCL_SPECIES; i++) sim.tracer_factor[i] = 1; 797 | sim.Cf = 1.; 798 | sim.steplimit = 1.; 799 | sim.boxsize = -1.; 800 | sim.z_in = 0.; 801 | 802 | if (!parseParameter(params, numparam, "generic file base", sim.basename_generic)) 803 | sim.basename_generic[0] = '\0'; 804 | 805 | if (!parseParameter(params, numparam, "snapshot file base", sim.basename_snapshot)) 806 | strcpy(sim.basename_snapshot, "snapshot"); 807 | 808 | if (!parseParameter(params, numparam, "Pk file base", sim.basename_pk)) 809 | strcpy(sim.basename_pk, "pk"); 810 | 811 | if (!parseParameter(params, numparam, "output path", sim.output_path)) 812 | sim.output_path[0] = '\0'; 813 | 814 | parseParameter(params, numparam, "boxsize", sim.boxsize); 815 | if (sim.boxsize <= 0. || !isfinite(sim.boxsize)) 816 | { 817 | COUT << " error: simulation box size not set properly!" << endl; 818 | parallel.abortForce(); 819 | } 820 | 821 | parseParameter(params, numparam, "Ngrid", sim.numpts); 822 | if (sim.numpts < 2 || !isfinite(sim.numpts)) 823 | { 824 | COUT << " error: number of grid points not set properly!" << endl; 825 | parallel.abortForce(); 826 | } 827 | 828 | if (!parseParameter(params, numparam, "move limit", sim.movelimit)) 829 | sim.movelimit = sim.numpts; 830 | 831 | if (!parseParameter(params, numparam, "initial redshift", sim.z_in)) 832 | { 833 | COUT << " error: initial redshift not specified!" << endl; 834 | parallel.abortForce(); 835 | } 836 | 837 | if (ic.z_relax < -1.) ic.z_relax = sim.z_in; 838 | 839 | parseParameter(params, numparam, "snapshot redshifts", sim.z_snapshot, sim.num_snapshot); 840 | if (sim.num_snapshot > 0) 841 | qsort((void *) sim.z_snapshot, (size_t) sim.num_snapshot, sizeof(double), compare_redshifts); 842 | 843 | parseParameter(params, numparam, "Pk redshifts", sim.z_pk, sim.num_pk); 844 | if (sim.num_pk > 0) 845 | qsort((void *) sim.z_pk, (size_t) sim.num_pk, sizeof(double), compare_redshifts); 846 | 847 | parseFieldSpecifiers(params, numparam, "snapshot outputs", sim.out_snapshot); 848 | parseFieldSpecifiers(params, numparam, "Pk outputs", sim.out_pk); 849 | 850 | i = MAX_PCL_SPECIES+1; 851 | parseParameter(params, numparam, "tracer factor", sim.tracer_factor, i); 852 | for (; i > 0; i--) 853 | { 854 | if (sim.tracer_factor[i-1] < 1) 855 | { 856 | COUT << " warning: tracer factor not set properly; using default value (1)" << endl; 857 | sim.tracer_factor[i-1] = 1; 858 | } 859 | } 860 | 861 | if ((sim.num_snapshot <= 0 || sim.out_snapshot == 0) && (sim.num_pk <= 0 || sim.out_pk == 0)) 862 | { 863 | COUT << " warning: no output specified!" << endl; 864 | } 865 | 866 | if (!parseParameter(params, numparam, "Pk bins", sim.numbins)) 867 | { 868 | COUT << " warning: number of Pk bins not set properly; using default value (64)" << endl; 869 | sim.numbins = 64; 870 | } 871 | 872 | parseParameter(params, numparam, "Courant factor", sim.Cf); 873 | 874 | parseParameter(params, numparam, "time step limit", sim.steplimit); 875 | 876 | if (parseParameter(params, numparam, "gravity theory", par_string)) 877 | { 878 | if (par_string[0] == 'N' || par_string[0] == 'n') 879 | { 880 | COUT << " gravity theory set to: Newtonian" << endl; 881 | sim.gr_flag = 0; 882 | } 883 | else if (par_string[0] == 'G' || par_string[0] == 'g') 884 | { 885 | COUT << " gravity theory set to: General Relativity" << endl; 886 | sim.gr_flag = 1; 887 | } 888 | else 889 | { 890 | COUT << " warning: gravity theory unknown, using default (General Relativity)" << endl; 891 | sim.gr_flag = 1; 892 | } 893 | } 894 | else 895 | { 896 | COUT << " warning: gravity theory not selected, using default (General Relativity)" << endl; 897 | sim.gr_flag = 1; 898 | } 899 | 900 | 901 | // parse cosmological parameters 902 | 903 | if (!parseParameter(params, numparam, "h", cosmo.h)) 904 | { 905 | cosmo.h = 0.67556; 906 | } 907 | 908 | cosmo.num_ncdm = MAX_PCL_SPECIES; 909 | if (!parseParameter(params, numparam, "m_ncdm", cosmo.m_ncdm, cosmo.num_ncdm)) 910 | { 911 | for (i = 0; i < MAX_PCL_SPECIES; i++) cosmo.m_ncdm[i] = 0.; 912 | cosmo.num_ncdm = 0; 913 | } 914 | 915 | if (parseParameter(params, numparam, "N_ncdm", i)) 916 | { 917 | if (i < 0 || !isfinite(i)) 918 | { 919 | COUT << " error: number of ncdm species not set properly!" << endl; 920 | parallel.abortForce(); 921 | } 922 | if (i > cosmo.num_ncdm) 923 | { 924 | COUT << " error: N_ncdm = " << i << " is larger than the number of mass parameters specified (" << cosmo.num_ncdm << ")!" << endl; 925 | parallel.abortForce(); 926 | } 927 | cosmo.num_ncdm = i; 928 | } 929 | else if (cosmo.num_ncdm > 0) 930 | { 931 | COUT << " warning: N_ncdm not specified, inferring from number of mass parameters in m_ncdm (" << cosmo.num_ncdm << ")!" << endl; 932 | } 933 | 934 | for (i = 0; i < MAX_PCL_SPECIES; i++) 935 | { 936 | cosmo.T_ncdm[i] = 0.71611; 937 | cosmo.deg_ncdm[i] = 1.0; 938 | } 939 | parseParameter(params, numparam, "T_ncdm", cosmo.T_ncdm, i); 940 | i = MAX_PCL_SPECIES; 941 | parseParameter(params, numparam, "deg_ncdm", cosmo.deg_ncdm, i); 942 | 943 | for (i = 0; i < cosmo.num_ncdm; i++) 944 | { 945 | cosmo.Omega_ncdm[i] = cosmo.m_ncdm[i] * cosmo.deg_ncdm[i] / 93.14 / cosmo.h / cosmo.h; 946 | } 947 | 948 | if (parseParameter(params, numparam, "T_cmb", cosmo.Omega_g)) 949 | { 950 | cosmo.Omega_g = cosmo.Omega_g * cosmo.Omega_g / cosmo.h; 951 | cosmo.Omega_g = cosmo.Omega_g * cosmo.Omega_g * 4.48147e-7; // Planck's law 952 | } 953 | else if (parseParameter(params, numparam, "omega_g", cosmo.Omega_g)) 954 | { 955 | cosmo.Omega_g /= cosmo.h * cosmo.h; 956 | } 957 | else if (!parseParameter(params, numparam, "Omega_g", cosmo.Omega_g)) 958 | { 959 | cosmo.Omega_g = 0.; 960 | } 961 | 962 | if (parseParameter(params, numparam, "N_ur", cosmo.Omega_ur)) 963 | { 964 | cosmo.Omega_ur *= (7./8.) * pow(4./11., 4./3.) * cosmo.Omega_g; 965 | } 966 | else if (parseParameter(params, numparam, "N_eff", cosmo.Omega_ur)) 967 | { 968 | cosmo.Omega_ur *= (7./8.) * pow(4./11., 4./3.) * cosmo.Omega_g; 969 | } 970 | else if (parseParameter(params, numparam, "omega_ur", cosmo.Omega_ur)) 971 | { 972 | cosmo.Omega_ur /= cosmo.h * cosmo.h; 973 | } 974 | else if (!parseParameter(params, numparam, "Omega_ur", cosmo.Omega_ur)) 975 | { 976 | cosmo.Omega_ur = 3.046 * (7./8.) * pow(4./11., 4./3.) * cosmo.Omega_g; 977 | } 978 | 979 | cosmo.Omega_rad = cosmo.Omega_g + cosmo.Omega_ur; 980 | 981 | if (parseParameter(params, numparam, "omega_b", cosmo.Omega_b)) 982 | { 983 | cosmo.Omega_b /= cosmo.h * cosmo.h; 984 | } 985 | else if (!parseParameter(params, numparam, "Omega_b", cosmo.Omega_b)) 986 | { 987 | COUT << " warning: Omega_b not found in settings file, setting to default (0)." << endl; 988 | cosmo.Omega_b = 0.; 989 | } 990 | 991 | if (parseParameter(params, numparam, "omega_cdm", cosmo.Omega_cdm)) 992 | { 993 | cosmo.Omega_cdm /= cosmo.h * cosmo.h; 994 | } 995 | else if (!parseParameter(params, numparam, "Omega_cdm", cosmo.Omega_cdm)) 996 | { 997 | COUT << " warning: Omega_cdm not found in settings file, setting to default (1)." << endl; 998 | cosmo.Omega_cdm = 1.; 999 | } 1000 | 1001 | cosmo.Omega_m = cosmo.Omega_cdm + cosmo.Omega_b; 1002 | for (i = 0; i < cosmo.num_ncdm; i++) cosmo.Omega_m += cosmo.Omega_ncdm[i]; 1003 | 1004 | if (cosmo.Omega_m <= 0. || cosmo.Omega_m > 1.) 1005 | { 1006 | COUT << " error: total matter density out of range!" << endl; 1007 | parallel.abortForce(); 1008 | } 1009 | else if (cosmo.Omega_rad < 0. || cosmo.Omega_rad > 1. - cosmo.Omega_m) 1010 | { 1011 | COUT << " error: total radiation energy density out of range!" << endl; 1012 | parallel.abortForce(); 1013 | } 1014 | else 1015 | { 1016 | COUT << " cosmological parameters are: Omega_m0 = " << cosmo.Omega_m << ", Omega_rad0 = " << cosmo.Omega_rad << ", h = " << cosmo.h << endl; 1017 | cosmo.Omega_Lambda = 1. - cosmo.Omega_m - cosmo.Omega_rad; 1018 | } 1019 | 1020 | for (i = 0; i < numparam; i++) 1021 | { 1022 | if (params[i].used) usedparams++; 1023 | } 1024 | 1025 | return usedparams; 1026 | } 1027 | 1028 | #endif 1029 | -------------------------------------------------------------------------------- /pk-z100.dat: -------------------------------------------------------------------------------- 1 | # Matter power spectrum P(k) at redshift z=100 2 | # for k=1.045e-05 to 106.861 h/Mpc, 3 | # number of wavenumbers equal to 623 4 | # 1:k (h/Mpc) 2:P (Mpc/h)^3 5 | 1.045004358465e-05 7.454560927911e-03 6 | 2.333095830364e-05 1.614157454337e-02 7 | 3.625717138197e-05 2.466669423036e-02 8 | 4.926346170446e-05 3.312587388992e-02 9 | 6.238518340033e-05 4.157319629697e-02 10 | 7.565858108432e-05 5.004889077810e-02 11 | 8.912111517766e-05 5.858716562749e-02 12 | 1.028118016360e-04 6.721942542402e-02 13 | 1.167715704439e-04 7.597590096854e-02 14 | 1.310436472695e-04 8.488663952874e-02 15 | 1.456739626796e-04 9.398219289039e-02 16 | 1.607115932535e-04 1.032941458288e-01 17 | 1.762092387588e-04 1.128555739920e-01 18 | 1.922237391794e-04 1.227014594007e-01 19 | 2.088166347274e-04 1.328690863775e-01 20 | 2.260547708937e-04 1.433984453060e-01 21 | 2.440109489228e-04 1.543326322632e-01 22 | 2.627646196243e-04 1.657182579088e-01 23 | 2.824026148746e-04 1.776058682158e-01 24 | 3.030199061975e-04 1.900503593479e-01 25 | 3.247203730558e-04 2.031113891671e-01 26 | 3.476175545344e-04 2.168537613830e-01 27 | 3.718353465747e-04 2.313477670600e-01 28 | 3.975085925723e-04 2.466694415614e-01 29 | 4.247834979996e-04 2.629007080562e-01 30 | 4.538177802962e-04 2.801293441203e-01 31 | 4.847804449377e-04 2.984487145648e-01 32 | 5.178510599038e-04 3.179571978154e-01 33 | 5.532183878397e-04 3.387572184153e-01 34 | 5.910782339040e-04 3.609538264342e-01 35 | 6.316303850249e-04 3.846527213928e-01 36 | 6.750745609842e-04 4.099577378220e-01 37 | 7.216053758472e-04 4.369677674242e-01 38 | 7.714064215132e-04 4.657732028594e-01 39 | 8.246437268604e-04 4.964520733977e-01 40 | 8.814589978991e-04 5.290661348106e-01 41 | 9.419631766203e-04 5.636572121461e-01 42 | 1.006230932013e-03 6.002441700873e-01 43 | 1.074296682416e-03 6.388208582254e-01 44 | 1.146152626855e-03 6.793552825395e-01 45 | 1.221749044348e-03 7.217901312369e-01 46 | 1.300996843579e-03 7.660446315595e-01 47 | 1.383772069420e-03 8.120154400304e-01 48 | 1.469921856686e-03 8.595824138553e-01 49 | 1.559271205765e-03 9.086186770403e-01 50 | 1.651629950109e-03 9.589854420987e-01 51 | 1.746799373907e-03 1.010539679901e+00 52 | 1.844578083652e-03 1.063137620990e+00 53 | 1.944766900246e-03 1.116637692431e+00 54 | 2.047172686846e-03 1.170902723676e+00 55 | 2.151611143041e-03 1.225801613922e+00 56 | 2.257908672078e-03 1.281210431127e+00 57 | 2.365903467808e-03 1.337013003710e+00 58 | 2.475445979787e-03 1.393101170551e+00 59 | 2.586398907712e-03 1.449374850627e+00 60 | 2.698636858273e-03 1.505741726112e+00 61 | 2.812045774843e-03 1.562117064014e+00 62 | 2.926522227346e-03 1.618423017351e+00 63 | 3.041972628545e-03 1.674588622294e+00 64 | 3.158312425015e-03 1.730548841227e+00 65 | 3.275465296538e-03 1.786244530544e+00 66 | 3.393362386273e-03 1.841621586969e+00 67 | 3.511941575581e-03 1.896631125418e+00 68 | 3.631146811106e-03 1.951228303962e+00 69 | 3.750927487357e-03 2.005372683275e+00 70 | 3.871237885001e-03 2.059027384203e+00 71 | 3.992036663108e-03 2.112159268415e+00 72 | 4.113286402413e-03 2.164738475172e+00 73 | 4.234953195938e-03 2.216737424779e+00 74 | 4.357006283050e-03 2.268132222385e+00 75 | 4.479417722957e-03 2.318900972656e+00 76 | 4.602162103782e-03 2.369024521295e+00 77 | 4.725216283514e-03 2.418485385026e+00 78 | 4.848559159457e-03 2.467268424263e+00 79 | 4.972171463027e-03 2.515360574728e+00 80 | 5.096035577095e-03 2.562750219215e+00 81 | 5.220135373297e-03 2.609427993445e+00 82 | 5.344456067073e-03 2.655385225190e+00 83 | 5.468984088379e-03 2.700614860915e+00 84 | 5.593706966284e-03 2.745112595912e+00 85 | 5.718613225869e-03 2.788872886898e+00 86 | 5.843692296004e-03 2.831893770536e+00 87 | 5.968934426788e-03 2.874173569294e+00 88 | 6.094330615523e-03 2.915710512218e+00 89 | 6.219872540296e-03 2.956505227812e+00 90 | 6.345552500285e-03 2.996558540643e+00 91 | 6.471363362067e-03 3.035871413169e+00 92 | 6.597298511245e-03 3.074447283980e+00 93 | 6.723351808830e-03 3.112290006580e+00 94 | 6.849517551848e-03 3.149402088502e+00 95 | 6.975790437733e-03 3.185787820288e+00 96 | 7.102165532088e-03 3.221453667271e+00 97 | 7.228638239472e-03 3.256402600796e+00 98 | 7.355204276894e-03 3.290641132461e+00 99 | 7.481859649729e-03 3.324177419933e+00 100 | 7.608600629819e-03 3.357016342417e+00 101 | 7.735423735527e-03 3.389164446342e+00 102 | 7.862325713566e-03 3.420628802193e+00 103 | 7.989303522403e-03 3.451417991759e+00 104 | 8.116354317107e-03 3.481537118073e+00 105 | 8.243475435493e-03 3.510996215179e+00 106 | 8.370664385429e-03 3.539799772373e+00 107 | 8.497918833216e-03 3.567960152361e+00 108 | 8.625236592919e-03 3.595481808397e+00 109 | 8.752615616576e-03 3.622373422608e+00 110 | 8.880053985201e-03 3.648642947014e+00 111 | 9.007549900508e-03 3.674298723617e+00 112 | 9.135101677287e-03 3.699346052699e+00 113 | 9.262707736385e-03 3.723800332491e+00 114 | 9.390366598231e-03 3.747661680522e+00 115 | 9.518076876859e-03 3.770940914959e+00 116 | 9.645837274391e-03 3.793645998405e+00 117 | 9.773646575931e-03 3.815784118053e+00 118 | 9.901503644852e-03 3.837362185556e+00 119 | 1.002940741843e-02 3.858386866385e+00 120 | 1.015735690378e-02 3.878868177853e+00 121 | 1.028535117414e-02 3.898812532047e+00 122 | 1.041338936539e-02 3.918226180707e+00 123 | 1.054147067279e-02 3.937116316192e+00 124 | 1.066959434803e-02 3.955489512579e+00 125 | 1.079775969644e-02 3.973354542784e+00 126 | 1.092596607441e-02 3.990714978931e+00 127 | 1.105421288699e-02 4.007579259706e+00 128 | 1.118249958563e-02 4.023954270761e+00 129 | 1.131082566619e-02 4.039845097402e+00 130 | 1.143919066690e-02 4.055259283900e+00 131 | 1.156759416668e-02 4.070201696606e+00 132 | 1.169603578339e-02 4.084677877516e+00 133 | 1.182451517231e-02 4.098695131489e+00 134 | 1.195303202469e-02 4.112257455695e+00 135 | 1.208158606643e-02 4.125371090974e+00 136 | 1.221017705681e-02 4.138043852871e+00 137 | 1.233880478730e-02 4.150278811592e+00 138 | 1.246746908058e-02 4.162080356686e+00 139 | 1.259616978942e-02 4.173456785071e+00 140 | 1.272490679583e-02 4.184411354024e+00 141 | 1.285368001017e-02 4.194949073222e+00 142 | 1.298248937038e-02 4.205076435101e+00 143 | 1.311133484117e-02 4.214796915615e+00 144 | 1.324021641342e-02 4.224115816159e+00 145 | 1.336913410352e-02 4.233038121197e+00 146 | 1.349808795276e-02 4.241569916436e+00 147 | 1.362707802683e-02 4.249714020972e+00 148 | 1.375610441532e-02 4.257474939493e+00 149 | 1.388516723129e-02 4.264859229798e+00 150 | 1.401426661081e-02 4.271870211476e+00 151 | 1.414340271265e-02 4.278513350944e+00 152 | 1.427257571792e-02 4.284792768737e+00 153 | 1.440178582977e-02 4.290712764590e+00 154 | 1.453103327311e-02 4.296277051327e+00 155 | 1.466031829438e-02 4.301492155364e+00 156 | 1.478964116137e-02 4.306359187237e+00 157 | 1.491900216301e-02 4.310888009111e+00 158 | 1.504840160920e-02 4.315076844504e+00 159 | 1.517783983073e-02 4.318934143048e+00 160 | 1.530731717916e-02 4.322462756627e+00 161 | 1.543683402673e-02 4.325666841229e+00 162 | 1.556639076630e-02 4.328550908517e+00 163 | 1.569598781137e-02 4.331118530003e+00 164 | 1.582562559600e-02 4.333374950561e+00 165 | 1.595530457486e-02 4.335324505816e+00 166 | 1.608502522327e-02 4.336969400199e+00 167 | 1.621478803722e-02 4.338316169997e+00 168 | 1.634459353345e-02 4.339365579040e+00 169 | 1.647444224958e-02 4.340126266054e+00 170 | 1.660433474414e-02 4.340599292058e+00 171 | 1.673427159678e-02 4.340788716588e+00 172 | 1.686425340835e-02 4.340699381553e+00 173 | 1.699428080111e-02 4.340336199527e+00 174 | 1.712435441886e-02 4.339701262462e+00 175 | 1.725447492718e-02 4.338797833667e+00 176 | 1.738464301363e-02 4.337635424981e+00 177 | 1.751485938798e-02 4.336206909678e+00 178 | 1.764512478243e-02 4.334525736212e+00 179 | 1.777543995193e-02 4.332591754538e+00 180 | 1.790580567440e-02 4.330410311545e+00 181 | 1.803622275109e-02 4.327987080071e+00 182 | 1.816669200684e-02 4.325318394835e+00 183 | 1.829721429042e-02 4.322415236167e+00 184 | 1.842779047491e-02 4.319279501231e+00 185 | 1.855842145803e-02 4.315911100240e+00 186 | 1.868910816253e-02 4.312319842993e+00 187 | 1.881985153660e-02 4.308503184176e+00 188 | 1.895065255427e-02 4.304465413354e+00 189 | 1.908151221584e-02 4.300216656003e+00 190 | 1.921243154835e-02 4.295751115785e+00 191 | 1.934341160602e-02 4.291076528818e+00 192 | 1.947445347077e-02 4.286201405896e+00 193 | 1.960555825268e-02 4.281121128186e+00 194 | 1.973672709056e-02 4.275841076611e+00 195 | 1.986796115246e-02 4.270367069710e+00 196 | 1.999926163623e-02 4.264699984016e+00 197 | 2.013062977012e-02 4.258841107525e+00 198 | 2.026206681336e-02 4.252794531173e+00 199 | 2.039357405681e-02 4.246569508999e+00 200 | 2.052515282356e-02 4.240162507886e+00 201 | 2.065680446963e-02 4.233580218329e+00 202 | 2.078853038464e-02 4.226827928914e+00 203 | 2.092033199250e-02 4.219894801327e+00 204 | 2.105221075219e-02 4.212803977766e+00 205 | 2.118416815845e-02 4.205544928715e+00 206 | 2.131620574262e-02 4.198125761230e+00 207 | 2.144832507339e-02 4.190542048281e+00 208 | 2.158052775766e-02 4.182810813016e+00 209 | 2.171281544138e-02 4.174920393120e+00 210 | 2.184518981047e-02 4.166885813715e+00 211 | 2.197765259164e-02 4.158694706364e+00 212 | 2.211020555343e-02 4.150365071486e+00 213 | 2.224285050711e-02 4.141892731274e+00 214 | 2.237558930770e-02 4.133283644190e+00 215 | 2.250842385501e-02 4.124537127142e+00 216 | 2.264135609466e-02 4.115655112897e+00 217 | 2.277438801924e-02 4.106644536915e+00 218 | 2.290752166936e-02 4.097508908947e+00 219 | 2.304075913486e-02 4.088241512203e+00 220 | 2.317410255604e-02 4.078850549872e+00 221 | 2.330755412480e-02 4.069345543760e+00 222 | 2.344111608601e-02 4.059722082542e+00 223 | 2.357479073879e-02 4.049978901882e+00 224 | 2.370858043787e-02 4.040120858681e+00 225 | 2.384248759499e-02 4.030157237117e+00 226 | 2.397651468034e-02 4.020085421515e+00 227 | 2.411066422407e-02 4.009909026657e+00 228 | 2.424493881783e-02 3.999624018046e+00 229 | 2.437934111633e-02 3.989246110308e+00 230 | 2.451387383901e-02 3.978759328601e+00 231 | 2.464853977174e-02 3.968187523901e+00 232 | 2.478334176854e-02 3.957517294050e+00 233 | 2.491828275342e-02 3.946756054892e+00 234 | 2.505336572221e-02 3.935905685613e+00 235 | 2.518859374453e-02 3.924977909896e+00 236 | 2.532396996575e-02 3.913952750296e+00 237 | 2.545949760907e-02 3.902852582341e+00 238 | 2.559517997761e-02 3.891665919383e+00 239 | 2.573102045669e-02 3.880403661461e+00 240 | 2.586702251600e-02 3.869060971894e+00 241 | 2.600318971206e-02 3.857649472462e+00 242 | 2.613952569055e-02 3.846162617511e+00 243 | 2.627603418892e-02 3.834613213839e+00 244 | 2.641271903892e-02 3.822988562377e+00 245 | 2.654958416936e-02 3.811312097298e+00 246 | 2.668663360886e-02 3.799547338088e+00 247 | 2.682387148875e-02 3.787732474366e+00 248 | 2.696130204606e-02 3.775868344789e+00 249 | 2.709892962664e-02 3.763927031852e+00 250 | 2.723675868836e-02 3.751937802957e+00 251 | 2.737479380444e-02 3.739894482595e+00 252 | 2.751303966691e-02 3.727804037981e+00 253 | 2.765150109016e-02 3.715648586651e+00 254 | 2.779018301472e-02 3.703462307982e+00 255 | 2.792909051104e-02 3.691213226571e+00 256 | 2.806822878351e-02 3.678922063661e+00 257 | 2.820760317466e-02 3.666582353728e+00 258 | 2.834721916939e-02 3.654209877967e+00 259 | 2.848708239949e-02 3.641799062649e+00 260 | 2.862719864828e-02 3.629334874123e+00 261 | 2.876757385545e-02 3.616839282554e+00 262 | 2.890821412206e-02 3.604306018082e+00 263 | 2.904912571580e-02 3.591736812717e+00 264 | 2.919031507636e-02 3.579138886142e+00 265 | 2.933178882113e-02 3.566503768955e+00 266 | 2.947355375108e-02 3.553837979646e+00 267 | 2.961561685685e-02 3.541147601797e+00 268 | 2.975798532515e-02 3.528419669262e+00 269 | 2.990066654540e-02 3.515678992409e+00 270 | 3.004366811665e-02 3.502905688963e+00 271 | 3.018699785478e-02 3.490102554822e+00 272 | 3.033066380005e-02 3.477293057045e+00 273 | 3.047467422493e-02 3.464446511019e+00 274 | 3.061903764232e-02 3.451589557664e+00 275 | 3.076376281406e-02 3.438712788682e+00 276 | 3.090885875989e-02 3.425805346625e+00 277 | 3.105433476679e-02 3.412898361612e+00 278 | 3.120020039870e-02 3.399969073243e+00 279 | 3.134646550675e-02 3.387024095299e+00 280 | 3.149314023990e-02 3.374070090476e+00 281 | 3.164023505612e-02 3.361099536605e+00 282 | 3.178776073406e-02 3.348116312289e+00 283 | 3.193572838529e-02 3.335118540199e+00 284 | 3.208414946714e-02 3.322118705052e+00 285 | 3.223303579609e-02 3.309108908492e+00 286 | 3.238239956191e-02 3.296087803657e+00 287 | 3.253225334243e-02 3.283067500448e+00 288 | 3.268261011904e-02 3.270027872748e+00 289 | 3.283348329301e-02 3.257000535629e+00 290 | 3.298488670259e-02 3.243951835370e+00 291 | 3.313683464103e-02 3.230907999542e+00 292 | 3.328934187547e-02 3.217859898979e+00 293 | 3.344242366689e-02 3.204811456418e+00 294 | 3.359609579103e-02 3.191754086328e+00 295 | 3.375037456053e-02 3.178695309428e+00 296 | 3.390527684814e-02 3.165652347583e+00 297 | 3.406082011128e-02 3.152591861648e+00 298 | 3.421702241793e-02 3.139535822438e+00 299 | 3.437390247395e-02 3.126492473621e+00 300 | 3.453147965192e-02 3.113438525373e+00 301 | 3.468977402169e-02 3.100392185315e+00 302 | 3.484880638259e-02 3.087347309573e+00 303 | 3.500859829758e-02 3.074303973810e+00 304 | 3.516917212940e-02 3.061267731083e+00 305 | 3.533055107886e-02 3.048233107154e+00 306 | 3.549275922540e-02 3.035200947754e+00 307 | 3.565582157023e-02 3.022167575270e+00 308 | 3.581976408199e-02 3.009147888879e+00 309 | 3.598461374536e-02 2.996127615692e+00 310 | 3.615039861271e-02 2.983119574215e+00 311 | 3.631714785906e-02 2.970107790126e+00 312 | 3.648489184058e-02 2.957099394849e+00 313 | 3.665366215692e-02 2.944110342706e+00 314 | 3.682349171774e-02 2.931117136272e+00 315 | 3.699441481367e-02 2.918129270921e+00 316 | 3.716646719210e-02 2.905148794690e+00 317 | 3.733968613823e-02 2.892173125372e+00 318 | 3.751411056177e-02 2.879197747361e+00 319 | 3.768978108986e-02 2.866239991932e+00 320 | 3.786674016657e-02 2.853273848849e+00 321 | 3.804503215979e-02 2.840307777948e+00 322 | 3.822470347586e-02 2.827363858212e+00 323 | 3.840580268301e-02 2.814417102598e+00 324 | 3.858838064404e-02 2.801457423701e+00 325 | 3.877249065931e-02 2.788517927600e+00 326 | 3.895818862096e-02 2.775578437448e+00 327 | 3.914553317940e-02 2.762639699819e+00 328 | 3.933458592328e-02 2.749698174871e+00 329 | 3.952541157417e-02 2.736753299710e+00 330 | 3.971807819759e-02 2.723820301007e+00 331 | 3.991265743180e-02 2.710888557336e+00 332 | 4.010922473646e-02 2.697938095906e+00 333 | 4.030785966288e-02 2.684999469799e+00 334 | 4.050864614847e-02 2.672050715354e+00 335 | 4.071167283779e-02 2.659098767175e+00 336 | 4.091703343321e-02 2.646138768570e+00 337 | 4.112482707841e-02 2.633184216057e+00 338 | 4.133515877846e-02 2.620199936187e+00 339 | 4.154813986079e-02 2.607219319019e+00 340 | 4.176388848168e-02 2.594221917652e+00 341 | 4.198253018382e-02 2.581215675713e+00 342 | 4.220419851120e-02 2.568190430458e+00 343 | 4.242903568833e-02 2.555158742782e+00 344 | 4.265719337197e-02 2.542105147704e+00 345 | 4.288883348483e-02 2.529019818649e+00 346 | 4.312412914181e-02 2.515936762154e+00 347 | 4.336326568147e-02 2.502801050918e+00 348 | 4.360644181685e-02 2.489645554398e+00 349 | 4.385387092265e-02 2.476468599964e+00 350 | 4.410578247799e-02 2.463244754110e+00 351 | 4.436242368764e-02 2.449999716948e+00 352 | 4.462406130828e-02 2.436705635839e+00 353 | 4.489098371107e-02 2.423376590675e+00 354 | 4.516350321751e-02 2.409995949093e+00 355 | 4.544195875207e-02 2.396558861214e+00 356 | 4.572671886360e-02 2.383065313780e+00 357 | 4.601818517708e-02 2.369518790307e+00 358 | 4.631679634960e-02 2.355885813145e+00 359 | 4.662303261929e-02 2.342210883086e+00 360 | 4.693742105388e-02 2.328440274541e+00 361 | 4.726054162823e-02 2.314583444038e+00 362 | 4.759303428806e-02 2.300638062516e+00 363 | 4.793560719149e-02 2.286587955535e+00 364 | 4.828904636352e-02 2.272424524810e+00 365 | 4.865422705274e-02 2.258141636107e+00 366 | 4.903212714816e-02 2.243730825985e+00 367 | 4.942384310017e-02 2.229166290795e+00 368 | 4.983060889990e-02 2.214436756232e+00 369 | 5.025381881014e-02 2.199563012276e+00 370 | 5.069505471927e-02 2.184481769117e+00 371 | 5.115611921608e-02 2.169177293356e+00 372 | 5.163907577182e-02 2.153622642396e+00 373 | 5.214629778177e-02 2.137792696893e+00 374 | 5.268052867832e-02 2.121660480332e+00 375 | 5.324495589638e-02 2.105175966110e+00 376 | 5.384330215613e-02 2.088291484335e+00 377 | 5.447993831049e-02 2.070944584651e+00 378 | 5.516002281028e-02 2.053062256832e+00 379 | 5.588967347556e-02 2.034561233480e+00 380 | 5.667617728526e-02 2.015306602645e+00 381 | 5.752824238763e-02 1.995157210412e+00 382 | 5.845629166292e-02 1.973913938433e+00 383 | 5.947278550584e-02 1.951323356981e+00 384 | 6.059253702404e-02 1.927042157298e+00 385 | 6.183293616966e-02 1.900612464217e+00 386 | 6.321391895944e-02 1.871429859916e+00 387 | 6.475739931141e-02 1.838708155100e+00 388 | 6.648575417647e-02 1.801438835945e+00 389 | 6.841893751845e-02 1.758439967162e+00 390 | 7.057014991713e-02 1.708468428142e+00 391 | 7.294096001121e-02 1.650507377503e+00 392 | 7.551806995251e-02 1.584164602970e+00 393 | 7.827420133877e-02 1.510064972997e+00 394 | 8.117356133227e-02 1.430000994610e+00 395 | 8.417927801560e-02 1.346723992195e+00 396 | 8.725923920168e-02 1.263457564839e+00 397 | 9.038865675803e-02 1.183359175272e+00 398 | 9.354994726216e-02 1.109075864628e+00 399 | 9.673132963228e-02 1.042492855483e+00 400 | 9.992519888886e-02 9.846461987288e-01 401 | 1.031267606933e-01 9.357573219526e-01 402 | 1.063330369207e-01 8.953492356928e-01 403 | 1.095421943607e-01 8.624012789010e-01 404 | 1.127531107498e-01 8.355088194241e-01 405 | 1.159651012776e-01 8.130415713800e-01 406 | 1.191777488189e-01 7.933056382379e-01 407 | 1.223907995083e-01 7.746870920655e-01 408 | 1.256040988568e-01 7.557943535825e-01 409 | 1.288175528007e-01 7.355680681704e-01 410 | 1.320311039975e-01 7.133608188379e-01 411 | 1.352447174182e-01 6.889609156495e-01 412 | 1.384583715953e-01 6.625629849537e-01 413 | 1.416720533079e-01 6.346924244769e-01 414 | 1.448857543556e-01 6.060977148568e-01 415 | 1.480994695979e-01 5.776284350424e-01 416 | 1.513131957646e-01 5.501237390964e-01 417 | 1.545269307318e-01 5.243142433895e-01 418 | 1.577406730825e-01 5.007672270594e-01 419 | 1.609544218378e-01 4.798343433454e-01 420 | 1.641681762942e-01 4.616434940898e-01 421 | 1.673819359230e-01 4.461303914420e-01 422 | 1.705957003091e-01 4.330456680114e-01 423 | 1.738094691134e-01 4.220086112153e-01 424 | 1.770232420486e-01 4.125452014949e-01 425 | 1.802370188648e-01 4.041459214588e-01 426 | 1.834507993398e-01 3.963269698132e-01 427 | 1.866645832730e-01 3.886728697387e-01 428 | 1.898783704814e-01 3.807186013737e-01 429 | 1.930921607962e-01 3.721835617417e-01 430 | 1.963059540615e-01 3.629171778029e-01 431 | 1.995197501323e-01 3.529065308744e-01 432 | 2.027335488731e-01 3.422651064503e-01 433 | 2.059473501575e-01 3.312028631252e-01 434 | 2.091611538671e-01 3.199822561581e-01 435 | 2.123749598908e-01 3.088830105230e-01 436 | 2.155887681241e-01 2.981578811925e-01 437 | 2.188025784691e-01 2.880098251190e-01 438 | 2.220163908331e-01 2.785971452933e-01 439 | 2.252302051293e-01 2.700148620169e-01 440 | 2.284440212754e-01 2.623024553677e-01 441 | 2.316578391940e-01 2.554505264125e-01 442 | 2.348716588117e-01 2.493831970570e-01 443 | 2.380854800593e-01 2.440021646450e-01 444 | 2.412993028713e-01 2.391621254122e-01 445 | 2.445131271855e-01 2.346975730993e-01 446 | 2.477269529431e-01 2.304457220399e-01 447 | 2.509407800883e-01 2.262608853097e-01 448 | 2.541546085682e-01 2.220201527174e-01 449 | 2.573684383324e-01 2.176449394594e-01 450 | 2.605822693330e-01 2.130917597620e-01 451 | 2.637961015247e-01 2.083521881789e-01 452 | 2.670099348642e-01 2.034482372161e-01 453 | 2.702237693103e-01 1.984259816922e-01 454 | 2.734376048237e-01 1.933543556772e-01 455 | 2.766514413671e-01 1.883129637090e-01 456 | 2.798652789047e-01 1.833836939218e-01 457 | 2.830791174024e-01 1.786445907290e-01 458 | 2.862929568279e-01 1.741585177255e-01 459 | 2.895067971499e-01 1.699664070222e-01 460 | 2.927206383389e-01 1.660853966603e-01 461 | 2.959344803664e-01 1.625095574906e-01 462 | 2.991483232052e-01 1.592144218915e-01 463 | 3.023621668294e-01 1.561631366384e-01 464 | 3.055760112140e-01 1.533120077116e-01 465 | 3.087898563352e-01 1.506137594435e-01 466 | 3.120037021700e-01 1.480218388658e-01 467 | 3.152175486966e-01 1.454914937058e-01 468 | 3.184313958939e-01 1.429830659183e-01 469 | 3.216452437417e-01 1.404645857499e-01 470 | 3.248590922206e-01 1.379158653692e-01 471 | 3.280729413120e-01 1.353290628319e-01 472 | 3.312867909978e-01 1.327090791189e-01 473 | 3.345006412610e-01 1.300707268496e-01 474 | 3.377144920850e-01 1.274360952202e-01 475 | 3.409283434538e-01 1.248289328079e-01 476 | 3.441421953521e-01 1.222722100401e-01 477 | 3.473560477652e-01 1.197859915223e-01 478 | 3.505699006787e-01 1.173876002032e-01 479 | 3.537837540791e-01 1.150891678379e-01 480 | 3.569976079530e-01 1.128996313201e-01 481 | 3.602114622879e-01 1.108224242990e-01 482 | 3.634253170713e-01 1.088554020116e-01 483 | 3.666391722915e-01 1.069893321078e-01 484 | 3.698530279369e-01 1.052108084172e-01 485 | 3.730668839967e-01 1.035029476307e-01 486 | 3.762807404600e-01 1.018483830358e-01 487 | 3.794945973167e-01 1.002314154659e-01 488 | 3.827084545567e-01 9.863976295955e-02 489 | 3.859223121705e-01 9.706479886896e-02 490 | 3.891361701487e-01 9.550123662461e-02 491 | 3.923500284823e-01 9.394615391299e-02 492 | 3.955638871627e-01 9.239869767340e-02 493 | 3.987777461815e-01 9.086025353549e-02 494 | 4.019916055304e-01 8.933387822148e-02 495 | 4.052054652017e-01 8.782504136346e-02 496 | 4.084193251876e-01 8.634039524038e-02 497 | 4.116331854808e-01 8.488708319334e-02 498 | 4.148470460740e-01 8.347140823008e-02 499 | 4.180609069605e-01 8.209746935517e-02 500 | 4.212747681333e-01 8.076722246508e-02 501 | 4.244886295860e-01 7.948074915146e-02 502 | 4.277024913123e-01 7.823646716934e-02 503 | 4.309163533060e-01 7.703243711715e-02 504 | 4.341302155611e-01 7.586628428728e-02 505 | 4.373440780719e-01 7.473553796722e-02 506 | 4.405579408327e-01 7.363697473363e-02 507 | 4.437718038381e-01 7.256661740250e-02 508 | 4.469856670828e-01 7.151982006058e-02 509 | 4.501995305617e-01 7.049190702859e-02 510 | 4.534133942698e-01 6.947899495465e-02 511 | 4.566272582021e-01 6.847850044962e-02 512 | 4.598411223540e-01 6.748937278339e-02 513 | 4.630549867210e-01 6.651180927833e-02 514 | 4.662688512984e-01 6.554659104698e-02 515 | 4.694827160821e-01 6.459471708460e-02 516 | 4.726965810677e-01 6.365712772227e-02 517 | 4.759104462512e-01 6.273480343000e-02 518 | 4.791243116286e-01 6.182878313491e-02 519 | 4.823381771960e-01 6.094078901299e-02 520 | 4.855520429496e-01 6.007254442018e-02 521 | 4.887659088857e-01 5.922564341407e-02 522 | 4.919797750007e-01 5.840084981415e-02 523 | 4.951936412912e-01 5.759819666019e-02 524 | 4.984075077536e-01 5.681642803008e-02 525 | 5.016213743848e-01 5.605374690334e-02 526 | 5.048352411815e-01 5.530812072844e-02 527 | 5.080491081405e-01 5.457777663221e-02 528 | 5.112629752588e-01 5.386136483323e-02 529 | 5.144768425333e-01 5.315789585924e-02 530 | 5.176907099612e-01 5.246646137484e-02 531 | 5.209045775396e-01 5.178609057235e-02 532 | 5.241184452657e-01 5.111568119674e-02 533 | 5.273323131368e-01 5.045440270971e-02 534 | 5.305461811503e-01 4.980181812445e-02 535 | 5.337600493036e-01 4.915808467645e-02 536 | 5.369739175941e-01 4.852386598254e-02 537 | 5.401877860195e-01 4.790013886954e-02 538 | 5.434016545772e-01 4.728760081986e-02 539 | 5.466155232651e-01 4.668663545954e-02 540 | 5.498293920807e-01 4.609703363077e-02 541 | 5.530432610219e-01 4.551876460398e-02 542 | 5.562571300865e-01 4.495128365223e-02 543 | 5.594709992723e-01 4.439443009181e-02 544 | 5.626848685772e-01 4.384837396357e-02 545 | 5.658987379993e-01 4.331290988829e-02 546 | 5.691126075365e-01 4.278795038676e-02 547 | 5.723264771868e-01 4.227307651574e-02 548 | 5.755403469485e-01 4.176752086896e-02 549 | 5.787542168196e-01 4.127041294282e-02 550 | 5.819680867983e-01 4.078107295467e-02 551 | 5.851819568828e-01 4.029907101988e-02 552 | 5.883958270714e-01 3.982435226818e-02 553 | 5.916096973624e-01 3.935698161641e-02 554 | 5.948235677541e-01 3.889699059715e-02 555 | 5.980374382449e-01 3.844414108403e-02 556 | 6.012513088332e-01 3.799817049478e-02 557 | 6.044651795175e-01 3.755869016132e-02 558 | 6.076790502961e-01 3.712553359918e-02 559 | 6.108929211677e-01 3.669871748538e-02 560 | 6.141067921308e-01 3.627858412281e-02 561 | 6.173206631839e-01 3.586544475218e-02 562 | 6.205345343256e-01 3.545945849198e-02 563 | 6.237484055545e-01 3.506054447406e-02 564 | 6.269622768694e-01 3.466843307622e-02 565 | 6.301761482688e-01 3.428261490388e-02 566 | 6.333900197516e-01 3.390290056941e-02 567 | 6.366038913164e-01 3.352907336538e-02 568 | 6.398177629619e-01 3.316111079787e-02 569 | 6.430316346871e-01 3.279906099286e-02 570 | 6.462455064906e-01 3.244289439194e-02 571 | 6.494593783714e-01 3.209232858575e-02 572 | 6.526732503282e-01 3.174702308988e-02 573 | 6.558871223600e-01 3.140655996610e-02 574 | 6.591009944657e-01 3.107071285767e-02 575 | 6.623148666441e-01 3.073939700748e-02 576 | 6.655287388943e-01 3.041278135356e-02 577 | 6.687426112152e-01 3.009095960367e-02 578 | 6.719564836057e-01 2.977403816636e-02 579 | 6.751703560649e-01 2.946190965348e-02 580 | 6.783842285918e-01 2.915436254382e-02 581 | 6.815981011854e-01 2.885112922146e-02 582 | 6.848119738448e-01 2.855206667943e-02 583 | 6.880258465691e-01 2.825717612660e-02 584 | 6.912397193574e-01 2.796657179327e-02 585 | 6.944535922087e-01 2.768038310013e-02 586 | 6.976674651222e-01 2.739861031656e-02 587 | 7.008813380971e-01 2.712113714382e-02 588 | 7.040952111324e-01 2.684779222057e-02 589 | 7.073090842275e-01 2.657812032473e-02 590 | 7.105229573814e-01 2.631204143286e-02 591 | 7.137368305933e-01 2.604951647945e-02 592 | 7.169507038626e-01 2.579059022495e-02 593 | 7.201645771883e-01 2.553536379399e-02 594 | 7.233784505698e-01 2.528382646859e-02 595 | 7.265923240064e-01 2.503583974258e-02 596 | 7.298061974972e-01 2.479120816824e-02 597 | 7.330200710416e-01 2.454973544581e-02 598 | 7.362339446388e-01 2.431127784663e-02 599 | 7.394478182883e-01 2.407586588042e-02 600 | 7.426616919892e-01 2.384358958913e-02 601 | 7.458755657410e-01 2.361455788271e-02 602 | 7.490894395429e-01 2.338878776377e-02 603 | 7.523033133944e-01 2.316618953905e-02 604 | 7.555171872948e-01 2.294657422000e-02 605 | 8.259205627815e-01 1.878180797959e-02 606 | 9.280150980228e-01 1.441180740392e-02 607 | 1.090552453521e+00 9.937786738704e-03 608 | 1.346943533441e+00 6.060808012771e-03 609 | 1.693655695988e+00 3.511009306898e-03 610 | 2.132152443295e+00 2.009944472000e-03 611 | 2.684220786091e+00 1.141207971264e-03 612 | 3.379233758430e+00 6.431755866533e-04 613 | 4.254203250880e+00 3.600604996036e-04 614 | 5.355724579470e+00 2.003367215091e-04 615 | 6.742457771666e+00 1.108433355439e-04 616 | 8.488251426699e+00 6.101482978973e-05 617 | 1.068607542277e+01 3.342864674319e-05 618 | 1.345297190207e+01 1.823556670247e-05 619 | 1.693628819167e+01 9.907842750839e-06 620 | 2.132152358597e+01 5.363254902921e-06 621 | 2.684220786054e+01 2.893167439123e-06 622 | 3.379233758430e+01 1.555628213940e-06 623 | 4.254203250880e+01 8.338891516511e-07 624 | 5.355724579470e+01 4.456841112696e-07 625 | 6.742457771666e+01 2.375173775734e-07 626 | 8.488251426699e+01 1.262136341440e-07 627 | 1.068607542277e+02 6.686557725224e-08 628 | -------------------------------------------------------------------------------- /prng_engine.hpp: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2012-2013 M.A. (Thijs) van den Berg, http://sitmo.com/ 2 | // 3 | // Use, modification and distribution are subject to the MIT Software License. 4 | // 5 | // The MIT License (MIT) 6 | // Permission is hereby granted, free of charge, to any person obtaining a copy 7 | // of this software and associated documentation files (the "Software"), to deal 8 | // in the Software without restriction, including without limitation the rights 9 | // to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 10 | // copies of the Software, and to permit persons to whom the Software is 11 | // furnished to do so, subject to the following conditions: 12 | // 13 | // The above copyright notice and this permission notice shall be included in 14 | // all copies or substantial portions of the Software. 15 | // 16 | // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 17 | // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 18 | // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 19 | // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 20 | // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 21 | // OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN 22 | // THE SOFTWARE. 23 | 24 | // version history: 25 | // version 1, 6 Sep 2012 26 | // version 2, 10 Dec 2013 27 | // bug fix in the discard() routine, it was discarding to many elements 28 | // added the version() method 29 | // version 3...5, 13 Dec 2013 30 | // fixed type-conversion earning 31 | // fixed potential issues with constructor template matching 32 | 33 | #ifndef SITMO_PRNG_ENGINE_HPP 34 | #define SITMO_PRNG_ENGINE_HPP 35 | #include 36 | 37 | #ifdef __GNUC__ 38 | #include // respecting the C99 standard. 39 | #endif 40 | #ifdef _MSC_VER 41 | typedef unsigned __int64 uint64_t; // Visual Studio 6.0(VC6) and newer.. 42 | typedef unsigned __int32 uint32_t; 43 | #endif 44 | 45 | // Double mixing function 46 | #define MIX2(x0,x1,rx,z0,z1,rz) \ 47 | x0 += x1; \ 48 | z0 += z1; \ 49 | x1 = (x1 << rx) | (x1 >> (64-rx)); \ 50 | z1 = (z1 << rz) | (z1 >> (64-rz)); \ 51 | x1 ^= x0; \ 52 | z1 ^= z0; 53 | 54 | 55 | // Double mixing function with key adition 56 | #define MIXK(x0,x1,rx,z0,z1,rz,k0,k1,l0,l1) \ 57 | x1 += k1; \ 58 | z1 += l1; \ 59 | x0 += x1+k0; \ 60 | z0 += z1+l0; \ 61 | x1 = (x1 << rx) | (x1 >> (64-rx)); \ 62 | z1 = (z1 << rz) | (z1 >> (64-rz)); \ 63 | x1 ^= x0; \ 64 | z1 ^= z0; \ 65 | 66 | 67 | namespace sitmo { 68 | 69 | // enable_if for C__98 compilers 70 | template 71 | struct sitmo_enable_if { typedef T type; }; 72 | 73 | template 74 | struct sitmo_enable_if { }; 75 | 76 | // SFINAE check for the existence of a "void generate(int*,int*)"member function 77 | template 78 | struct has_generate_template 79 | { 80 | typedef char (&Two)[2];; 81 | template struct helper {}; 82 | template static char test(helper >*); 83 | template static Two test(...); 84 | static bool const value = sizeof(test(0)) == sizeof(char); 85 | }; 86 | 87 | 88 | class prng_engine 89 | { 90 | public: 91 | // "req" are requirements as stated in the C++ 11 draft n3242=11-0012 92 | // 93 | // req: 26.5.1.3 Uniform random number generator requirements, p.906, table 116, row 1 94 | typedef uint32_t result_type; 95 | 96 | // req: 26.5.1.3 Uniform random number generator requirements, p.906, table 116, row 3 97 | static result_type (min)() { return 0; } 98 | 99 | // req: 26.5.1.3 Uniform random number generator requirements, p.906, table 116, row 4 100 | static result_type (max)() { return 0xFFFFFFFF; } 101 | 102 | // ------------------------------------------------- 103 | // Constructors 104 | // ------------------------------------------------- 105 | 106 | // req: 26.5.1.4 Random number engine requirements, p.907 table 117, row 1 107 | // Creates an engine with the same initial state as all other 108 | // default-constructed engines of type E. 109 | prng_engine() 110 | { 111 | seed(); 112 | } 113 | 114 | // req: 26.5.1.4 Random number engine requirements, p.907 table 117, row 2 115 | // Creates an engine that compares equal to x. 116 | prng_engine(const prng_engine& x) 117 | { 118 | for (unsigned short i=0; i<4; ++i) { 119 | _s[i] = x._s[i]; 120 | _k[i] = x._k[i]; 121 | _o[i] = x._o[i]; 122 | } 123 | _o_counter = x._o_counter; 124 | } 125 | 126 | 127 | // req: 26.5.1.4 Random number engine requirements, p.907 table 117, row 3 128 | // Creates an engine with initial O(size of state) state determined by s. 129 | prng_engine(uint32_t s) 130 | { 131 | seed(s); 132 | } 133 | 134 | // req: 26.5.1.4 Random number engine requirements, p.908 table 117, row 4 135 | // Creates an engine with an initial state that depends on a sequence 136 | // produced by one call to q.generate. 137 | template 138 | prng_engine(Seq& q, typename sitmo_enable_if< has_generate_template::value >::type* = 0 ) 139 | { 140 | seed(q); 141 | } 142 | 143 | // ------------------------------------------------- 144 | // Seeding 145 | // ------------------------------------------------- 146 | 147 | // req: 26.5.1.4 Random number engine requirements, p.908 table 117, row 5 148 | void seed() 149 | { 150 | for (unsigned short i=0; i<4; ++i) { 151 | _k[i] = 0; 152 | _s[i] = 0; 153 | } 154 | _o_counter = 0; 155 | 156 | _o[0] = 0x09218ebde6c85537; 157 | _o[1] = 0x55941f5266d86105; 158 | _o[2] = 0x4bd25e16282434dc; 159 | _o[3] = 0xee29ec846bd2e40b; 160 | } 161 | 162 | // req: 26.5.1.4 Random number engine requirements, p.908 table 117, row 6 163 | // s needs to be of return_type, which is uint32_t 164 | void seed(uint32_t s) 165 | { 166 | for (unsigned short i=0; i<4; ++i) { 167 | _k[i] = 0; 168 | _s[i] = 0; 169 | } 170 | _k[0] = s; 171 | _o_counter = 0; 172 | 173 | encrypt_counter(); 174 | } 175 | 176 | // req: 26.5.1.4 Random number engine requirements, p.908 table 117, row 7 177 | template 178 | void seed(Seq& q, typename sitmo_enable_if< has_generate_template::value >::type* = 0 ) 179 | { 180 | typename Seq::result_type w[8]; 181 | q.generate(&w[0], &w[8]); 182 | 183 | for (unsigned short i=0; i<4; ++i) { 184 | _k[i] = ( static_cast(w[2*i]) << 32) | w[2*i+1]; 185 | _s[i] = 0; 186 | } 187 | _o_counter = 0; 188 | 189 | encrypt_counter(); 190 | } 191 | 192 | // req: 26.5.1.4 Random number engine requirements, p.908 table 117, row 8 193 | // Advances e’s state ei to ei+1 = TA(ei) and returns GA(ei). 194 | uint32_t operator()() 195 | { 196 | // can we return a value from the current block? 197 | if (_o_counter < 8) { 198 | unsigned short _o_index = _o_counter >> 1; 199 | _o_counter++; 200 | if (_o_counter&1) 201 | return _o[_o_index] & 0xFFFFFFFF; 202 | else 203 | return _o[_o_index] >> 32; 204 | } 205 | 206 | // generate a new block and return the first 32 bits 207 | inc_counter(); 208 | encrypt_counter(); 209 | _o_counter = 1; // the next call 210 | return _o[0] & 0xFFFFFFFF; // this call 211 | } 212 | 213 | // ------------------------------------------------- 214 | // misc 215 | // ------------------------------------------------- 216 | 217 | // req: 26.5.1.4 Random number engine requirements, p.908 table 117, row 9 218 | // Advances e’s state ei to ei+z by any means equivalent to z 219 | // consecutive calls e(). 220 | void discard(uint64_t z) 221 | { 222 | // check if we stay in the current block 223 | if (z < 8 - _o_counter) { 224 | _o_counter += static_cast(z); 225 | return; 226 | } 227 | 228 | // we will have to generate a new block... 229 | z -= (8 - _o_counter); // discard the remainder of the current blok 230 | _o_counter = z % 8; // set the pointer in the correct element in the new block 231 | z -= _o_counter; // update z 232 | z >>= 3; // the number of buffers is elements/8 233 | ++z; // and one more because we crossed the buffer line 234 | inc_counter(z); 235 | encrypt_counter(); 236 | } 237 | 238 | // ------------------------------------------------- 239 | // IO 240 | // ------------------------------------------------- 241 | template 242 | friend std::basic_ostream& 243 | operator<<(std::basic_ostream& os, const prng_engine& s) { 244 | for (unsigned short i=0; i<4; ++i) 245 | os << s._k[i] << ' ' << s._s[i] << ' ' << s._o[i] << ' '; 246 | os << s._o_counter; 247 | return os; 248 | } 249 | 250 | template 251 | friend std::basic_istream& 252 | operator>>(std::basic_istream& is, prng_engine& s) { 253 | for (unsigned short i=0; i<4; ++i) 254 | is >> s._k[i] >> s._s[i] >> s._o[i]; 255 | is >> s._o_counter; 256 | return is; 257 | } 258 | // req: 26.5.1.4 Random number engine requirements, p.908 table 117, row 10 259 | // This operator is an equivalence relation. With Sx and Sy as the infinite 260 | // sequences of values that would be generated by repeated future calls to 261 | // x() and y(), respectively, returns true if Sx = Sy; else returns false. 262 | bool operator==(const prng_engine& y) 263 | { 264 | if (_o_counter != y._o_counter) return false; 265 | for (unsigned short i=0; i<4; ++i) { 266 | if (_s[i] != y._s[i]) return false; 267 | if (_k[i] != y._k[i]) return false; 268 | if (_o[i] != y._o[i]) return false; 269 | } 270 | return true; 271 | } 272 | 273 | // req: 26.5.1.4 Random number engine requirements, p.908 table 117, row 11 274 | bool operator!=(const prng_engine& y) 275 | { 276 | return !(*this == y); 277 | } 278 | 279 | // Extra function to set the key 280 | void set_key(uint64_t k0=0, uint64_t k1=0, uint64_t k2=0, uint64_t k3=0) 281 | { 282 | _k[0] = k0; _k[1] = k1; _k[2] = k2; _k[3] = k3; 283 | encrypt_counter(); 284 | } 285 | 286 | // set the counter 287 | void set_counter(uint64_t s0=0, uint64_t s1=0, uint64_t s2=0, uint64_t s3=0, unsigned short o_counter=0) 288 | { 289 | _s[0] = s0; 290 | _s[1] = s1; 291 | _s[2] = s2; 292 | _s[3] = s3; 293 | _o_counter = o_counter % 8; 294 | encrypt_counter(); 295 | } 296 | 297 | 298 | // versioning 299 | uint32_t version() 300 | { 301 | return 5; 302 | } 303 | 304 | private: 305 | void encrypt_counter() 306 | { 307 | uint64_t b[4]; 308 | uint64_t k[5]; 309 | 310 | for (unsigned short i=0; i<4; ++i) b[i] = _s[i]; 311 | for (unsigned short i=0; i<4; ++i) k[i] = _k[i]; 312 | 313 | k[4] = 0x1BD11BDAA9FC1A22 ^ k[0] ^ k[1] ^ k[2] ^ k[3]; 314 | 315 | MIXK(b[0], b[1], 14, b[2], b[3], 16, k[0], k[1], k[2], k[3]); 316 | MIX2(b[0], b[3], 52, b[2], b[1], 57); 317 | MIX2(b[0], b[1], 23, b[2], b[3], 40); 318 | MIX2(b[0], b[3], 5, b[2], b[1], 37); 319 | MIXK(b[0], b[1], 25, b[2], b[3], 33, k[1], k[2], k[3], k[4]+1); 320 | MIX2(b[0], b[3], 46, b[2], b[1], 12); 321 | MIX2(b[0], b[1], 58, b[2], b[3], 22); 322 | MIX2(b[0], b[3], 32, b[2], b[1], 32); 323 | 324 | MIXK(b[0], b[1], 14, b[2], b[3], 16, k[2], k[3], k[4], k[0]+2); 325 | MIX2(b[0], b[3], 52, b[2], b[1], 57); 326 | MIX2(b[0], b[1], 23, b[2], b[3], 40); 327 | MIX2(b[0], b[3], 5, b[2], b[1], 37); 328 | MIXK(b[0], b[1], 25, b[2], b[3], 33, k[3], k[4], k[0], k[1]+3); 329 | 330 | MIX2(b[0], b[3], 46, b[2], b[1], 12); 331 | MIX2(b[0], b[1], 58, b[2], b[3], 22); 332 | MIX2(b[0], b[3], 32, b[2], b[1], 32); 333 | 334 | MIXK(b[0], b[1], 14, b[2], b[3], 16, k[4], k[0], k[1], k[2]+4); 335 | MIX2(b[0], b[3], 52, b[2], b[1], 57); 336 | MIX2(b[0], b[1], 23, b[2], b[3], 40); 337 | MIX2(b[0], b[3], 5, b[2], b[1], 37); 338 | 339 | for (unsigned int i=0; i<4; ++i) _o[i] = b[i] + k[i]; 340 | _o[3] += 5; 341 | } 342 | 343 | void inc_counter() 344 | { 345 | ++_s[0]; 346 | if (_s[0] != 0) return; 347 | 348 | ++_s[1]; 349 | if (_s[1] != 0) return; 350 | 351 | ++_s[2]; 352 | if (_s[2] != 0) return; 353 | 354 | ++_s[3]; 355 | } 356 | 357 | void inc_counter(uint64_t z) 358 | { 359 | if (z > 0xFFFFFFFFFFFFFFFF - _s[0]) { // check if we will overflow the first 64 bit int 360 | ++_s[1]; 361 | if (_s[1] == 0) { 362 | ++_s[2]; 363 | if (_s[2] == 0) { 364 | ++_s[3]; 365 | } 366 | } 367 | } 368 | _s[0] += z; 369 | } 370 | 371 | private: 372 | uint64_t _k[4]; // key 373 | uint64_t _s[4]; // state (counter) 374 | uint64_t _o[4]; // cipher output 4 * 64 bit = 256 bit output 375 | unsigned short _o_counter; // output chunk counter, the 256 random bits in _o 376 | // are returned in eight 32 bit chunks 377 | }; 378 | 379 | 380 | } // namespace sitmo 381 | 382 | #undef MIXK 383 | #undef MIX2 384 | 385 | #endif -------------------------------------------------------------------------------- /sc0_crystal.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gevolution-code/gevolution-1.0/0906a1e1ec2c955470f10dd53ec03f1aa19021e4/sc0_crystal.dat -------------------------------------------------------------------------------- /sc1_crystal.dat: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/gevolution-code/gevolution-1.0/0906a1e1ec2c955470f10dd53ec03f1aa19021e4/sc1_crystal.dat -------------------------------------------------------------------------------- /settings.ini: -------------------------------------------------------------------------------- 1 | # info related to IC generation 2 | 3 | IC generator = basic # in this version of the code the only option is "basic" 4 | 5 | template file = sc1_crystal.dat # file (Gadget-2 format) containing homogeneous particle template 6 | tiling factor = 16 # number of times the template shall be repeated in each direction 7 | # total number of particles will be N_template * (tiling factor)^3 8 | 9 | mPk file = pk-z100.dat # file containing tabulated matter power spectrum (at initial redshift) 10 | 11 | seed = 12345 # initial seed for random number generator 12 | correct displacement = yes # if "yes" the IC generator will try to fold the template pattern 13 | # into the convolution kernel of the displacement field 14 | k-domain = sphere # possible choices are "sphere" or "cube" 15 | 16 | 17 | # cosmological parameters 18 | 19 | h = 0.67556 20 | omega_b = 0.022032 21 | omega_cdm = 0.12038 22 | T_cmb = 2.7255 # in units of K 23 | 24 | 25 | # simulation settings 26 | 27 | initial redshift = 100.0 28 | boxsize = 320.0 # in units of Mpc/h 29 | 30 | Ngrid = 64 31 | Courant factor = 48.0 32 | time step limit = 0.04 # in units of Hubble time 33 | 34 | gravity theory = GR # possible choices are "GR" or "Newton" 35 | 36 | 37 | # output 38 | 39 | output path = output/ 40 | generic file base = lcdm 41 | snapshot file base = lcdm_snap 42 | Pk file base = lcdm_pk 43 | Pk bins = 1024 44 | snapshot redshifts = 30, 10, 3, 0 45 | snapshot outputs = phi, B, chi, Gadget2 46 | Pk redshifts = 50, 30, 10, 3, 1, 0 47 | Pk outputs = phi, B, chi, hij 48 | 49 | -------------------------------------------------------------------------------- /tools.hpp: -------------------------------------------------------------------------------- 1 | ////////////////////////// 2 | // tools.hpp 3 | ////////////////////////// 4 | // 5 | // Collection of analysis tools for gevolution 6 | // 7 | // Author: Julian Adamek (Université de Genève) 8 | // 9 | // Last modified: January 2016 10 | // 11 | ////////////////////////// 12 | 13 | #ifndef TOOLS_HEADER 14 | #define TOOLS_HEADER 15 | 16 | #ifndef Cplx 17 | #define Cplx Imag 18 | #endif 19 | 20 | #define KTYPE_GRID 0 21 | #define KTYPE_LINEAR 1 22 | 23 | using namespace std; 24 | using namespace LATfield2; 25 | 26 | 27 | #ifdef FFT3D 28 | ////////////////////////// 29 | // extractCrossSpectrum 30 | ////////////////////////// 31 | // Description: 32 | // generates the cross spectrum for two Fourier images 33 | // 34 | // Arguments: 35 | // fld1FT reference to the first Fourier image for which the cross spectrum should be extracted 36 | // fld2FT reference to the first Fourier image for which the cross spectrum should be extracted 37 | // kbin allocated array that will contain the central k-value for the bins 38 | // power allocated array that will contain the average power in each bin 39 | // kscatter allocated array that will contain the k-scatter for each bin 40 | // pscatter allocated array that will contain the scatter in power for each bin 41 | // occupation allocated array that will count the number of grid points contributing to each bin 42 | // numbin number of bins (minimum size of all arrays) 43 | // ktype flag indicating which definition of momentum to be used 44 | // 0: grid momentum 45 | // 1: linear (default) 46 | // 47 | // Returns: 48 | // 49 | ////////////////////////// 50 | 51 | void extractCrossSpectrum(Field & fld1FT, Field & fld2FT, Real * kbin, Real * power, Real * kscatter, Real * pscatter, int * occupation, const int numbins, const bool deconvolve = true, const int ktype = KTYPE_LINEAR) 52 | { 53 | int i, weight; 54 | const int linesize = fld1FT.lattice().size(1); 55 | Real * typek2; 56 | Real * sinc; 57 | Real k2max, k2, s; 58 | rKSite k(fld1FT.lattice()); 59 | Cplx p; 60 | 61 | typek2 = (Real *) malloc(linesize * sizeof(Real)); 62 | sinc = (Real *) malloc(linesize * sizeof(Real)); 63 | 64 | if (ktype == KTYPE_GRID) 65 | { 66 | for (i = 0; i < linesize; i++) 67 | { 68 | typek2[i] = 2. * (Real) linesize * sin(M_PI * (Real) i / (Real) linesize); 69 | typek2[i] *= typek2[i]; 70 | } 71 | } 72 | else 73 | { 74 | for (i = 0; i <= linesize/2; i++) 75 | { 76 | typek2[i] = 2. * M_PI * (Real) i; 77 | typek2[i] *= typek2[i]; 78 | } 79 | for (; i < linesize; i++) 80 | { 81 | typek2[i] = 2. * M_PI * (Real) (linesize-i); 82 | typek2[i] *= typek2[i]; 83 | } 84 | } 85 | 86 | sinc[0] = 1.; 87 | if (deconvolve) 88 | { 89 | for (i = 1; i <= linesize / 2; i++) 90 | { 91 | sinc[i] = sin(M_PI * (float) i / (float) linesize) * (float) linesize / (M_PI * (float) i); 92 | } 93 | } 94 | else 95 | { 96 | for (i = 1; i <= linesize / 2; i++) 97 | { 98 | sinc[i] = 1.; 99 | } 100 | } 101 | for (; i < linesize; i++) 102 | { 103 | sinc[i] = sinc[linesize-i]; 104 | } 105 | 106 | k2max = 3. * typek2[linesize/2]; 107 | 108 | for (i = 0; i < numbins; i++) 109 | { 110 | kbin[i] = 0.; 111 | power[i] = 0.; 112 | kscatter[i] = 0.; 113 | pscatter[i] = 0.; 114 | occupation[i] = 0; 115 | } 116 | 117 | for (k.first(); k.test(); k.next()) 118 | { 119 | if (k.coord(0) == 0 && k.coord(1) == 0 && k.coord(2) == 0) 120 | continue; 121 | else if (k.coord(0) == 0) 122 | weight = 1; 123 | else if ((k.coord(0) == linesize/2) && (linesize % 2 == 0)) 124 | weight = 1; 125 | else 126 | weight = 2; 127 | 128 | k2 = typek2[k.coord(0)] + typek2[k.coord(1)] + typek2[k.coord(2)]; 129 | s = sinc[k.coord(0)] * sinc[k.coord(1)] * sinc[k.coord(2)]; 130 | s *= s; 131 | 132 | if (fld1FT.symmetry() == LATfield2::symmetric) 133 | { 134 | p = fld1FT(k, 0, 1) * fld2FT(k, 0, 1).conj(); 135 | p += fld1FT(k, 0, 2) * fld2FT(k, 0, 2).conj(); 136 | p += fld1FT(k, 1, 2) * fld2FT(k, 1, 2).conj(); 137 | p *= 2.; 138 | p += fld1FT(k, 0, 0) * fld2FT(k, 0, 0).conj(); 139 | p += fld1FT(k, 1, 1) * fld2FT(k, 1, 1).conj(); 140 | p += fld1FT(k, 2, 2) * fld2FT(k, 2, 2).conj(); 141 | } 142 | else 143 | { 144 | p = Cplx(0., 0.); 145 | for (i = 0; i < fld1FT.components(); i++) 146 | p += fld1FT(k, i) * fld2FT(k, i).conj(); 147 | } 148 | 149 | i = (int) floor((double) ((Real) numbins * sqrt(k2 / k2max))); 150 | if (i < numbins) 151 | { 152 | kbin[i] += weight * sqrt(k2); 153 | kscatter[i] += weight * k2; 154 | power[i] += weight * p.real() * k2 * sqrt(k2) / s; 155 | pscatter[i] += weight * p.real() * p.real() * k2 * k2 * k2 / s / s; 156 | occupation[i] += weight; 157 | } 158 | } 159 | 160 | free(typek2); 161 | free(sinc); 162 | 163 | parallel.sum(kbin, numbins); 164 | parallel.sum(kscatter, numbins); 165 | parallel.sum(power, numbins); 166 | parallel.sum(pscatter, numbins); 167 | parallel.sum(occupation, numbins); 168 | 169 | for (i = 0; i < numbins; i++) 170 | { 171 | if (occupation[i] > 0) 172 | { 173 | kscatter[i] = sqrt(kscatter[i] * occupation[i] - kbin[i] * kbin[i]) / occupation[i]; 174 | if (!isfinite(kscatter[i])) kscatter[i] = 0.; 175 | kbin[i] = kbin[i] / occupation[i]; 176 | power[i] /= occupation[i]; 177 | pscatter[i] = sqrt(pscatter[i] / occupation[i] - power[i] * power[i]); 178 | if (!isfinite(pscatter[i])) pscatter[i] = 0.; 179 | } 180 | } 181 | } 182 | 183 | 184 | ////////////////////////// 185 | // extractPowerSpectrum 186 | ////////////////////////// 187 | // Description: 188 | // generates the power spectrum for a Fourier image 189 | // 190 | // Arguments: 191 | // fldFT reference to the Fourier image for which the power spectrum should be extracted 192 | // kbin allocated array that will contain the central k-value for the bins 193 | // power allocated array that will contain the average power in each bin 194 | // kscatter allocated array that will contain the k-scatter for each bin 195 | // pscatter allocated array that will contain the scatter in power for each bin 196 | // occupation allocated array that will count the number of grid points contributing to each bin 197 | // numbin number of bins (minimum size of all arrays) 198 | // ktype flag indicating which definition of momentum to be used 199 | // 0: grid momentum 200 | // 1: linear (default) 201 | // 202 | // Returns: 203 | // 204 | ////////////////////////// 205 | 206 | void extractPowerSpectrum(Field & fldFT, Real * kbin, Real * power, Real * kscatter, Real * pscatter, int * occupation, const int numbins, const bool deconvolve = true, const int ktype = KTYPE_LINEAR) 207 | { 208 | extractCrossSpectrum(fldFT, fldFT, kbin, power, kscatter, pscatter, occupation, numbins, deconvolve, ktype); 209 | } 210 | #endif 211 | 212 | 213 | ////////////////////////// 214 | // writePowerSpectrum 215 | ////////////////////////// 216 | // Description: 217 | // writes power spectra as tabulated data into ASCII file 218 | // 219 | // Arguments: 220 | // kbin array containing the central values of k for each bin 221 | // power array containing the central values of P(k) for each bin 222 | // kscatter array containing the statistical error on k for each bin 223 | // pscatter array containing the statistical error on P(k) for each bin 224 | // occupation array containing the number of k-modes contributing to each bin 225 | // numbins total number of bins (length of the arrays) 226 | // rescalek unit conversion factor for k 227 | // rescalep unit conversion factor for P(k) 228 | // filename output file name 229 | // description descriptive header 230 | // a scale factor for this spectrum 231 | // 232 | // Returns: 233 | // 234 | ////////////////////////// 235 | 236 | void writePowerSpectrum(Real * kbin, Real * power, Real * kscatter, Real * pscatter, int * occupation, const int numbins, const Real rescalek, const Real rescalep, const char * filename, const char * description, const double a) 237 | { 238 | if (parallel.isRoot()) 239 | { 240 | FILE * outfile = fopen(filename, "w"); 241 | if (outfile == NULL) 242 | { 243 | cout << " error opening file for power spectrum output!" << endl; 244 | } 245 | else 246 | { 247 | fprintf(outfile, "# %s\n", description); 248 | fprintf(outfile, "# redshift z=%f\n", (1./a)-1.); 249 | fprintf(outfile, "# k Pk sigma(k) sigma(Pk) count\n"); 250 | for (int i = 0; i < numbins; i++) 251 | { 252 | if (occupation[i] > 0) 253 | fprintf(outfile, " %e %e %e %e %d\n", kbin[i]/rescalek, power[i]/rescalep, kscatter[i]/rescalek, pscatter[i]/rescalep/ sqrt(occupation[i]), occupation[i]); 254 | } 255 | fclose(outfile); 256 | } 257 | } 258 | } 259 | 260 | 261 | ////////////////////////// 262 | // computeVectorDiagnostics 263 | ////////////////////////// 264 | // Description: 265 | // computes some diagnostics for the spin-1 perturbation 266 | // 267 | // Arguments: 268 | // Bi reference to the real-space vector field to analyze 269 | // mdivB will contain the maximum value of the divergence of Bi 270 | // mcurlB will contain the maximum value of the curl of Bi 271 | // 272 | // Returns: 273 | // 274 | ////////////////////////// 275 | 276 | void computeVectorDiagnostics(Field & Bi, Real & mdivB, Real & mcurlB) 277 | { 278 | Real b1, b2, b3, b4; 279 | const Real linesize = (Real) Bi.lattice().sizeLocal(0); 280 | Site x(Bi.lattice()); 281 | 282 | mdivB = 0.; 283 | mcurlB = 0.; 284 | 285 | for (x.first(); x.test(); x.next()) 286 | { 287 | b1 = fabs((Bi(x,0)-Bi(x-0,0)) + (Bi(x,1)-Bi(x-1,1)) + (Bi(x,2)-Bi(x-2,2))) * linesize; 288 | if (b1 > mdivB) mdivB = b1; 289 | b1 = 0.5 * (Bi(x,0) + Bi(x+0,1) - Bi(x+1,0) - Bi(x,1) + Bi(x+2,0) + Bi(x+0+2,1) - Bi(x+1+2,0) - Bi(x+2,1)) * linesize; 290 | b2 = 0.5 * (Bi(x,0) + Bi(x+0,2) - Bi(x+2,0) - Bi(x,2) + Bi(x+1,0) + Bi(x+0+1,2) - Bi(x+2+1,0) - Bi(x+1,2)) * linesize; 291 | b3 = 0.5 * (Bi(x,2) + Bi(x+2,1) - Bi(x+1,2) - Bi(x,1) + Bi(x+0,2) + Bi(x+2+0,1) - Bi(x+1+0,2) - Bi(x+0,1)) * linesize; 292 | b4 = sqrt(b1 * b1 + b2 * b2 + b3 * b3); 293 | if (b4 > mcurlB) mcurlB = b4; 294 | } 295 | 296 | parallel.max(mdivB); 297 | parallel.max(mcurlB); 298 | } 299 | 300 | 301 | ////////////////////////// 302 | // computeTensorDiagnostics 303 | ////////////////////////// 304 | // Description: 305 | // computes some diagnostics for the spin-2 perturbation 306 | // 307 | // Arguments: 308 | // hij reference to the real-space tensor field to analyze 309 | // mdivh will contain the maximum value of the divergence of hij 310 | // mtraceh will contain the maximum value of the trace of hij 311 | // mnormh will contain the maximum value of the norm of hij 312 | // 313 | // Returns: 314 | // 315 | ////////////////////////// 316 | 317 | void computeTensorDiagnostics(Field & hij, Real & mdivh, Real & mtraceh, Real & mnormh) 318 | { 319 | Real d1, d2, d3; 320 | const Real linesize = (Real) hij.lattice().sizeLocal(0); 321 | Site x(hij.lattice()); 322 | 323 | mdivh = 0.; 324 | mtraceh = 0.; 325 | mnormh = 0.; 326 | 327 | for (x.first(); x.test(); x.next()) 328 | { 329 | d1 = (hij(x+0, 0, 0) - hij(x, 0, 0) + hij(x, 0, 1) - hij(x-1, 0, 1) + hij(x, 0, 2) - hij(x-2, 0, 2)) * linesize; 330 | d2 = (hij(x+1, 1, 1) - hij(x, 1, 1) + hij(x, 0, 1) - hij(x-0, 0, 1) + hij(x, 1, 2) - hij(x-2, 1, 2)) * linesize; 331 | d3 = (hij(x+2, 2, 2) - hij(x, 2, 2) + hij(x, 0, 2) - hij(x-0, 0, 2) + hij(x, 1, 2) - hij(x-1, 1, 2)) * linesize; 332 | d1 = sqrt(d1 * d1 + d2 * d2 + d3 * d3); 333 | if (d1 > mdivh) mdivh = d1; 334 | d1 = fabs(hij(x, 0, 0) + hij(x, 1, 1) + hij(x, 2, 2)); 335 | if (d1 > mtraceh) mtraceh = d1; 336 | d1 = sqrt(hij(x, 0, 0) * hij(x, 0, 0) + 2. * hij(x, 0, 1) * hij(x, 0, 1) + 2. * hij(x, 0, 2)* hij(x, 0, 2) + hij(x, 1, 1) * hij(x, 1, 1) + 2. * hij(x, 1, 2) * hij(x, 1, 2) + hij(x, 2, 2) * hij(x, 2, 2)); 337 | if (d1 > mnormh) mnormh = d1; 338 | } 339 | 340 | parallel.max(mdivh); 341 | parallel.max(mtraceh); 342 | parallel.max(mnormh); 343 | } 344 | 345 | 346 | ////////////////////////// 347 | // hourMinSec 348 | ////////////////////////// 349 | // Description: 350 | // generates formatted output for cpu-time: hh..h:mm:ss.s 351 | // 352 | // Arguments: 353 | // seconds number of seconds 354 | // 355 | // Returns: 356 | // formatted string 357 | // 358 | ////////////////////////// 359 | 360 | string hourMinSec(double seconds) 361 | { 362 | string output; 363 | char ptr[20]; 364 | int h, m, s, f; 365 | 366 | h = (int) floor(seconds / 3600.); 367 | seconds -= 3600. * h; 368 | m = (int) floor(seconds / 60.); 369 | seconds -= 60. * m; 370 | s = (int) floor(seconds); 371 | seconds -= s; 372 | f = (int) floor(10. * seconds); 373 | sprintf(ptr, "%d:%02d:%02d.%d", h, m, s, f); 374 | 375 | output.reserve(20); 376 | output.assign(ptr); 377 | 378 | return output; 379 | } 380 | 381 | #endif 382 | --------------------------------------------------------------------------------