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