vide_public/c_tools/mock/generateMock.cpp

760 lines
20 KiB
C++

#include <cmath>
#include <cassert>
#include <iostream>
#include <fstream>
#include <string>
#include <algorithm>
#include <CosmoTool/loadSimu.hpp>
#include <CosmoTool/loadRamses.hpp>
#include <CosmoTool/loadGadget.hpp>
#include <CosmoTool/loadFlash.hpp>
#include <CosmoTool/interpolate.hpp>
#include <CosmoTool/fortran.hpp>
#include "generateMock_conf.h"
#include "gslIntegrate.hpp"
#include <netcdfcpp.h>
using namespace std;
using namespace CosmoTool;
#define LIGHT_SPEED 299792.458
static double gadgetUnit=1e-3;
template<typename T>
void delete_adaptor(void *ptr)
{
T *ptr_T = reinterpret_cast<T *>(ptr);
delete[] ptr_T;
}
SimuData *doLoadRamses(const char *basename, int baseid, int velAxis, bool goRedshift)
{
SimuData *d, *outd;
d = loadRamsesSimu(basename, baseid, -1, true, 0);
outd = new SimuData;
outd->NumPart = d->TotalNumPart;
outd->BoxSize = d->BoxSize;
outd->TotalNumPart = outd->NumPart;
outd->Hubble = d->Hubble;
outd->Omega_Lambda = d->Omega_Lambda;
outd->Omega_M = d->Omega_M;
outd->time = d->time;
for (int k = 0; k < 3; k++)
outd->Pos[k] = new float[outd->NumPart];
outd->Vel[2] = new float[outd->NumPart];
delete d;
int curCpu = 0;
cout << "loading cpu 0 " << endl;
while (d = loadRamsesSimu(basename, baseid, curCpu, true, NEED_POSITION|NEED_VELOCITY|NEED_GADGET_ID))
{
for (int k = 0; k < 3; k++)
for (int i = 0; i < d->NumPart; i++)
{
assert(d->Id[i] >= 1);
assert(d->Id[i] <= outd->TotalNumPart);
outd->Pos[k][d->Id[i]-1] = d->Pos[k][i];
outd->Vel[2][d->Id[i]-1] = d->Vel[velAxis][i];
}
if (goRedshift)
for (int i = 0; i < d->NumPart; i++)
outd->Pos[velAxis][d->Id[i]-1] += d->Vel[velAxis][i]/100.;
delete d;
curCpu++;
cout << "loading cpu " << curCpu << endl;
}
return outd;
}
SimuData *myLoadGadget(const char *fname, int id, int flags)
{
SimuData *sim = loadGadgetMulti(fname, id, flags);
sim->BoxSize *= gadgetUnit;
for (int j = 0; j < 3; j++)
{
if (sim->Pos[j] != 0) {
for (long i = 0; i < sim->NumPart; i++)
sim->Pos[j][i] *= gadgetUnit;
}
}
return sim;
}
SimuData *doLoadSimulation(const char *gadgetname, int velAxis, bool goRedshift, SimuData *(*loadFunction)(const char *fname, int id, int flags))
{
SimuData *d, *outd;
bool singleFile = false;
double redshift_gravity;
try
{
d = loadFunction(gadgetname, -1, 0);
singleFile = true;
}
catch (const NoSuchFileException& e)
{
try
{
d = loadFunction(gadgetname, 0, 0);
}
catch(const NoSuchFileException& e)
{
return 0;
}
}
outd = new SimuData;
outd->NumPart = d->TotalNumPart;
outd->BoxSize = d->BoxSize;
outd->TotalNumPart = outd->NumPart;
outd->Hubble = d->Hubble;
outd->Omega_Lambda = d->Omega_Lambda;
outd->Omega_M = d->Omega_M;
outd->time = d->time;
for (int k = 0; k < 3; k++)
outd->Pos[k] = new float[outd->NumPart];
outd->Vel[2] = new float[outd->NumPart];
outd->Id = new int[outd->NumPart];
delete d;
long *uniqueID = new long[outd->NumPart];
outd->new_attribute("uniqueID", uniqueID, delete_adaptor<long>);
redshift_gravity = goRedshift ? 1 : 0;
int curCpu = singleFile ? -1 : 0;
cout << "loading file 0 " << endl;
try
{
long loaded = 0;
while (1)
{
d = loadFunction(gadgetname, curCpu, NEED_POSITION|NEED_VELOCITY|NEED_GADGET_ID);
for (int i = 0; i < d->NumPart; i++)
{
for (int k = 0; k < 3; k++)
outd->Pos[k][loaded] = d->Pos[k][i];
outd->Vel[2][loaded] = d->Vel[velAxis][i];
outd->Id[loaded] = loaded;
uniqueID[loaded] = d->Id[i];
assert(loaded < outd->TotalNumPart);
outd->Pos[velAxis][loaded] +=
redshift_gravity*d->Vel[velAxis][i]/100.;
loaded++;
}
delete d;
if (singleFile)
break;
curCpu++;
cout << "loading file " << curCpu << endl;
}
}
catch (const NoSuchFileException& e)
{
}
return outd;
}
SimuData *doLoadMultidark(const char *multidarkname)
{
SimuData *outd;
FILE *fp;
int actualNumPart;
outd = new SimuData;
cout << "opening multidark file " << multidarkname << endl;
fp = fopen(multidarkname, "r");
if (fp == NULL) {
cout << "could not open file!" << endl;
return 0;
}
fscanf(fp, "%f\n", &outd->BoxSize);
fscanf(fp, "%f\n", &outd->Omega_M);
fscanf(fp, "%f\n", &outd->Hubble);
fscanf(fp, "%f\n", &outd->time);
fscanf(fp, "%ld\n", &outd->NumPart);
outd->time = 1./(1.+outd->time); // convert to scale factor
outd->TotalNumPart = outd->NumPart;
outd->Omega_Lambda = 1.0 - outd->Omega_M;
for (int k = 0; k < 3; k++)
outd->Pos[k] = new float[outd->NumPart];
outd->Vel[2] = new float[outd->NumPart];
outd->Id = new int[outd->NumPart];
long *uniqueID = new long[outd->NumPart];
outd->new_attribute("uniqueID", uniqueID, delete_adaptor<long>);
cout << "loading multidark particles" << endl;
actualNumPart = 0;
for (int i = 0; i < outd->NumPart; i++) {
fscanf(fp, "%d %f %f %f %f\n", &outd->Id[i],
&outd->Pos[0][i], &outd->Pos[1][i],
&outd->Pos[2][i], &outd->Vel[2][i]);
uniqueID[i] = 1;
//uniqueID[i] = 1 * outd->Id[i];
if (outd->Id[i] == -99 &&
outd->Pos[0][i] == -99 && outd->Pos[1][i] == -99 &&
outd->Pos[2][i] == -99 && outd->Vel[2][i] == -99) {
break;
} else {
actualNumPart++;
}
}
fclose(fp);
outd->NumPart = actualNumPart;
outd->TotalNumPart = actualNumPart;
return outd;
}
static double cubic(double a)
{
return a*a*a;
}
struct TotalExpansion
{
double Omega_M, Omega_L;
double operator()(double z)
{
return 1/sqrt(Omega_M*cubic(1+z) + Omega_L);
}
};
Interpolate make_cosmological_redshift(double OM, double OL, double z0, double z1, int N = 5000)
{
TotalExpansion e_computer;
double D_tilde, Q, Qprime;
InterpolatePairs pairs;
e_computer.Omega_M = OM;
e_computer.Omega_L = OL;
pairs.resize(N);
ofstream f("comoving_distance.txt");
for (int i = 0; i < N; i++)
{
double z = z0 + (z1-z0)/N*i;
pairs[i].second = z;
pairs[i].first = gslIntegrate(e_computer, 0, z, 1e-3);
f << z << " " << pairs[i].first << endl;
}
return buildFromVector(pairs);
}
void metricTransform(SimuData *data, int axis, bool reshift, bool pecvel, double*& expfact, bool cosmo_flag)
{
int x0, x1, x2;
switch (axis) {
case 0:
x0 = 1; x1 = 2; x2 = 0;
break;
case 1:
x0 = 0; x1 = 2; x2 = 1;
break;
case 2:
x0 = 0; x1 = 1; x2 = 2;
break;
default:
abort();
}
double z0 = 1/data->time - 1;
Interpolate z_vs_D =
make_cosmological_redshift(data->Omega_M, data->Omega_Lambda,
0., z0+8*data->BoxSize*100/LIGHT_SPEED);
// Redshift 2*z0 should be sufficient ? This is fragile.
//A proper solver is needed here.
double z_base = reshift ? z0 : 0;
TotalExpansion e_computer;
double baseComovingDistance;
expfact = new double[data->NumPart];
cout << "Using base redshift z=" << z0 << " " << z0+8*data->BoxSize*100/LIGHT_SPEED << endl;
e_computer.Omega_M = data->Omega_M;
e_computer.Omega_L = data->Omega_Lambda;
baseComovingDistance = LIGHT_SPEED/100.* gslIntegrate(e_computer, 0, z0, 1e-3);
cout << "Comoving distance = " << baseComovingDistance << " Mpc/h" << endl;
for (uint32_t i = 0; i < data->NumPart; i++)
{
float& x = data->Pos[x0][i];
float& y = data->Pos[x1][i];
float& z = data->Pos[x2][i];
float& v = data->Vel[2][i];
float z_old = z;
double reduced_red = (z + baseComovingDistance)*100./LIGHT_SPEED;
try
{
// Distorted redshift
if (reduced_red == 0)
z = 0;
else if (cosmo_flag)
z = (z_vs_D.compute(reduced_red)-z_base)*LIGHT_SPEED/100.;
else
z = reduced_red*LIGHT_SPEED/100.0;
expfact[i] = z / z_old;
// Add peculiar velocity
if (pecvel)
z += v/100;
}
catch(const InvalidRangeException& e) {
cout << "Trying to interpolate out of the tabulated range." << endl;
cout << "The offending value is z=" << reduced_red << endl;
abort();
}
}
}
void generateOutput(SimuData *data, int axis,
const std::string& fname)
{
UnformattedWrite f(fname);
cout << "Generating output particles to " << fname << endl;
int x0, x1, x2;
switch (axis) {
case 0:
x0 = 1; x1 = 2; x2 = 0;
break;
case 1:
x0 = 0; x1 = 2; x2 = 1;
break;
case 2:
x0 = 0; x1 = 1; x2 = 2;
break;
default:
abort();
}
f.beginCheckpoint();
f.writeInt32(data->NumPart);
f.endCheckpoint();
cout << "Writing X components..." << endl;
f.beginCheckpoint();
for (uint32_t i = 0; i < data->NumPart; i++)
{
f.writeReal32(data->Pos[x0][i]);
}
f.endCheckpoint();
cout << "Writing Y components..." << endl;
f.beginCheckpoint();
for (uint32_t i = 0; i < data->NumPart; i++)
{
f.writeReal32(data->Pos[x1][i]);
}
f.endCheckpoint();
cout << "Writing Z components..." << endl;
f.beginCheckpoint();
for (uint32_t i = 0; i < data->NumPart; i++)
{
f.writeReal32(data->Pos[x2][i]);
}
f.endCheckpoint();
cout << "Writing RA..." << endl;
f.beginCheckpoint();
for (uint32_t i = 0; i < data->NumPart; i++)
{
f.writeReal32(data->Pos[x0][i]);
}
f.endCheckpoint();
cout << "Writing Dec..." << endl;
f.beginCheckpoint();
for (uint32_t i = 0; i < data->NumPart; i++)
{
f.writeReal32(data->Pos[x1][i]);
}
f.endCheckpoint();
cout << "Writing redshift..." << endl;
f.beginCheckpoint();
for (uint32_t i = 0; i < data->NumPart; i++)
{
f.writeReal32(data->Pos[x2][i]);
}
f.endCheckpoint();
long *uniqueID = data->as<long>("uniqueID");
if (uniqueID != 0)
{
cout << "Writing unique ID..." << endl;
f.beginCheckpoint();
for (uint32_t i = 0; i < data->NumPart; i++)
{
//printf("HELLO %d %d\n", i, data->Id[i]);
//f.writeReal32(data->Id[i]);
f.writeInt64(uniqueID[i]);
}
f.endCheckpoint();
}
}
// This function prepares the list of targets for the specified snapshot. The target list is not
// cleared. That way new particles can be appended if this is a multi-file snapshot.
void selectBox(SimuData *simu, std::vector<long>& targets, generateMock_info& args_info)
{
float subsample = args_info.subsample_given ? args_info.subsample_arg : 1.0;
double ranges[3][2] = {
{ args_info.rangeX_min_arg, args_info.rangeX_max_arg },
{ args_info.rangeY_min_arg, args_info.rangeY_max_arg },
{ args_info.rangeZ_min_arg, args_info.rangeZ_max_arg }
};
for (uint32_t i = 0; i < simu->NumPart; i++)
{
bool acceptance = true;
for (int j = 0; j < 3; j++) {
acceptance =
acceptance &&
(simu->Pos[j][i] > ranges[j][0]) &&
(simu->Pos[j][i] < ranges[j][1]);
}
if (acceptance && (drand48() <= subsample))
targets.push_back(i);
}
cout << "Subsample fraction: " << subsample << endl;
}
void createBox(SimuData *simu, long num_targets, std::vector<long> snapshot_split, SimuData *& boxed, generateMock_info& args_info)
{
double *ranges = new double[6];
double *mul = new double[3];
ranges[0] = args_info.rangeX_min_arg;
ranges[1] = args_info.rangeX_max_arg;
ranges[2] = args_info.rangeY_min_arg;
ranges[3] = args_info.rangeY_max_arg;
ranges[4] = args_info.rangeZ_min_arg;
ranges[5] = args_info.rangeZ_max_arg;
boxed = new SimuData;
boxed->Hubble = simu->Hubble;
boxed->Omega_M = simu->Omega_M;
boxed->Omega_Lambda = simu->Omega_Lambda;
boxed->time = simu->time;
boxed->BoxSize = simu->BoxSize;
for (int j = 0; j < 3; j++)
{
boxed->Pos[j] = new float[num_targets];
boxed->Vel[j] = 0;
mul[j] = 1.0/(ranges[2*j+1] - ranges[2*j+0]);
}
cout << "Min range = " << ranges[0] << " " << ranges[2] << " " << ranges[4] << endl;
cout << "Max range = " << ranges[1] << " " << ranges[3] << " " << ranges[5] << endl;
cout << "Number of accepted particles: " << num_targets << endl;
cout << "Rescaling factors = " << mul[0] << " " << mul[1] << " " << mul[2] << endl;
long *uniqueID = new long[num_targets];
long *simu_uniqueID = simu->as<long>("uniqueID");
long *particle_id = new long[num_targets];
double *expansion_fac = new double[num_targets];
long *snap_split = new long[snapshot_split.size()];
int *numsnap_info = new int[1];
copy(snapshot_split.begin(), snapshot_split.end(), snap_split);
*numsnap_info = snapshot_split.size();
boxed->NumPart = num_targets;
boxed->new_attribute("particle_id", particle_id, delete_adaptor<long>);
boxed->new_attribute("expansion_fac", expansion_fac, delete_adaptor<double>);
boxed->new_attribute("uniqueID", uniqueID, delete_adaptor<long>);
boxed->new_attribute("mul", mul, delete_adaptor<double>);
boxed->new_attribute("ranges", ranges, delete_adaptor<double>);
boxed->new_attribute("snapshot_split", snap_split, delete_adaptor<long>);
boxed->new_attribute("num_snapshots", numsnap_info, delete_adaptor<int>);
}
void buildBox(SimuData *simu, const std::vector<long>& targets, long& loaded,
SimuData *boxed, double *efac)
{
uint32_t k = 0;
long *uniqueID = boxed->as<long>("uniqueID");
long *simu_uniqueID = simu->as<long>("uniqueID");
double *expansion_fac = boxed->as<double>("expansion_fac");
double *mul = boxed->as<double>("mul");
double *ranges = boxed->as<double>("ranges");
long *particle_id = boxed->as<long>("particle_id");
for (uint32_t i = 0; i < targets.size(); i++)
{
long pid = targets[i];
for (int j = 0; j < 3; j++)
{
boxed->Pos[j][loaded] = (simu->Pos[j][pid]-ranges[j*2])*mul[j];
assert(boxed->Pos[j][loaded] > 0);
assert(boxed->Pos[j][loaded] < 1);
}
particle_id[loaded] = pid;
uniqueID[loaded] = (simu_uniqueID != 0) ? simu_uniqueID[i] : 0;
expansion_fac[loaded] = efac[i];
loaded++;
k++;
}
}
void saveBox(SimuData *&boxed, generateMock_info& args_info)
{
double *ranges = boxed->as<double>("ranges");
NcFile f(args_info.outputParameter_arg, NcFile::Replace);
long *particle_id = boxed->as<long>("particle_id");
double *expansion_fac = boxed->as<double>("expansion_fac");
long *snapshot_split = boxed->as<long>("snapshot_split");
int num_snapshots = *boxed->as<int>("num_snapshots");
long *uniqueID = boxed->as<long>("uniqueID");
f.add_att("range_x_min", ranges[0]);
f.add_att("range_x_max", ranges[1]);
f.add_att("range_y_min", ranges[2]);
f.add_att("range_y_max", ranges[3]);
f.add_att("range_z_min", ranges[4]);
f.add_att("range_z_max", ranges[5]);
f.add_att("mask_index", -1);
NcDim *NumPart_dim = f.add_dim("numpart_dim", boxed->NumPart);
NcDim *NumSnap_dim = f.add_dim("numsnap_dim", num_snapshots);
NcVar *v = f.add_var("particle_ids", ncLong, NumPart_dim);
NcVar *v2 = f.add_var("expansion", ncDouble, NumPart_dim);
NcVar *v3 = f.add_var("snapshot_split", ncLong, NumSnap_dim);
v->put(particle_id, boxed->NumPart);
v2->put(expansion_fac, boxed->NumPart);
v3->put(snapshot_split, num_snapshots);
if (uniqueID != 0)
{
NcVar *v4 = f.add_var("unique_ids", ncLong, NumPart_dim);
v4->put(uniqueID, boxed->NumPart);
}
delete[] particle_id;
delete[] expansion_fac;
}
void makeBoxFromParameter(SimuData *simu, SimuData* &boxed, generateMock_info& args_info)
{
NcFile f(args_info.inputParameter_arg);
NcVar *v;
long *particle_id;
double *expansion_fac;
long *uniqueID;
long *snapshot_split;
int *num_snapshots = new int[1];
boxed = new SimuData;
boxed->Hubble = simu->Hubble;
boxed->Omega_M = simu->Omega_M;
boxed->Omega_Lambda = simu->Omega_Lambda;
boxed->time = simu->time;
boxed->BoxSize = simu->BoxSize;
NcVar *v_id = f.get_var("particle_ids");
NcVar *v_snap = f.get_var("snapshot_split");
long *edges1;
long *dim_snap;
double *ranges;
double *mul;
edges1 = v_id->edges();
dim_snap = v_snap->edges();
assert(v_id->num_dims()==1);
assert(v_snap->num_dims()==1);
boxed->NumPart = edges1[0];
*num_snapshots = dim_snap[0];
delete[] dim_snap;
delete[] edges1;
particle_id = new long[boxed->NumPart];
uniqueID = new long[boxed->NumPart];
mul = new double[3];
ranges = new double[6];
snapshot_split = new long[*num_snapshots];
boxed->new_attribute("uniqueID", uniqueID, delete_adaptor<long>);
boxed->new_attribute("mul", mul, delete_adaptor<double>);
boxed->new_attribute("ranges", ranges, delete_adaptor<double>);
boxed->new_attribute("particle_id", particle_id, delete_adaptor<long>);
boxed->new_attribute("num_snapshots", num_snapshots, delete_adaptor<int>);
boxed->new_attribute("snapshot_split", snapshot_split, delete_adaptor<long>);
v_id->get(particle_id, boxed->NumPart);
v_snap->get(snapshot_split, *num_snapshots);
ranges[0] = f.get_att("range_x_min")->as_double(0);
ranges[1] = f.get_att("range_x_max")->as_double(0);
ranges[2] = f.get_att("range_y_min")->as_double(0);
ranges[3] = f.get_att("range_y_max")->as_double(0);
ranges[4] = f.get_att("range_z_min")->as_double(0);
ranges[5] = f.get_att("range_z_max")->as_double(0);
for (int j = 0; j < 3; j++)
{
boxed->Pos[j] = new float[boxed->NumPart];
boxed->Vel[j] = 0;
mul[j] = 1.0/(ranges[2*j+1] - ranges[2*j+0]);
}
uint32_t k = 0;
NcVar *v_uniq = f.get_var("unique_ids");
v_uniq->get(uniqueID, boxed->NumPart);
}
int main(int argc, char **argv)
{
generateMock_info args_info;
generateMock_conf_params args_params;
SimuData *simu, *simuOut;
generateMock_conf_init(&args_info);
generateMock_conf_params_init(&args_params);
args_params.check_required = 0;
if (generateMock_conf_ext (argc, argv, &args_info, &args_params))
return 1;
if (!args_info.configFile_given)
{
if (generateMock_conf_required (&args_info, GENERATEMOCK_CONF_PACKAGE))
return 1;
}
else
{
args_params.check_required = 1;
args_params.initialize = 0;
if (generateMock_conf_config_file (args_info.configFile_arg,
&args_info,
&args_params))
return 1;
}
generateMock_conf_print_version();
gadgetUnit=args_info.gadgetUnit_arg;
if (args_info.ramsesBase_given || args_info.ramsesId_given)
{
if (args_info.ramsesBase_given && args_info.ramsesId_given) {
simu = doLoadRamses(args_info.ramsesBase_arg,
args_info.ramsesId_arg,
args_info.axis_arg, false);
}
else
{
cerr << "Both ramsesBase and ramsesId are required to be able to load snapshots" << endl;
return 1;
}
if (simu == 0)
{
cerr << "Error while loading" << endl;
return 1;
}
}
else if (args_info.gadget_given || args_info.flash_given || args_info.multidark_given)
{
if (args_info.gadget_given && args_info.flash_given)
{
cerr << "Do not know which file to use: Gadget or Flash ?" << endl;
return 1;
}
if (args_info.multidark_given) {
simu = doLoadMultidark(args_info.multidark_arg);
}
if (args_info.gadget_given) {
simu = doLoadSimulation(args_info.gadget_arg, args_info.axis_arg, false, myLoadGadget);
}
if (args_info.flash_given) {
simu = doLoadSimulation(args_info.flash_arg, args_info.axis_arg, false, loadFlashMulti);
}
if (simu == 0)
{
cerr << "Error while loading " << endl;
return 1;
}
}
else
{
cerr << "Either a ramses snapshot or a gadget snapshot is required." << endl;
return 1;
}
cout << "Hubble = " << simu->Hubble << endl;
cout << "Boxsize = " << simu->BoxSize << endl;
cout << "Omega_M = " << simu->Omega_M << endl;
cout << "Omega_Lambda = " << simu->Omega_Lambda << endl;
double *expfact;
metricTransform(simu, args_info.axis_arg, args_info.preReShift_flag,
args_info.peculiarVelocities_flag, expfact,
args_info.cosmo_flag);
vector<long> targets, split;
long loaded = 0;
if (args_info.inputParameter_given)
makeBoxFromParameter(simu, simuOut, args_info);
else
{
selectBox(simu, targets, args_info);
split.push_back(targets.size());
createBox(simu, targets.size(), split, simuOut, args_info);
}
buildBox(simu, targets, loaded, simuOut, expfact);
delete simu;
saveBox(simuOut, args_info);
generateOutput(simuOut, args_info.axis_arg, args_info.output_arg);
delete simuOut;
printf("Done!\n");
return 0;
}