/*! \file gadgetio.cxx * \brief this file contains routines for gadget snapshot file io */ //-- GADGET SPECIFIC IO #include "stf.h" #include "gadgetitems.h" #include "endianutils.h" ///reads a gadget file. If cosmological simulation uses cosmology (generally assuming LCDM or small deviations from this) to estimate the mean interparticle spacing ///and scales physical linking length passed by this distance. Also reads header and over rides passed cosmological parameters with ones stored in header. void ReadGadget(Options &opt, vector &Part, const Int_t nbodies,Particle *&Pbaryons, Int_t nbaryons) { //counters Int_t i,k,n,temp,count,countsph,count2,bcount,bcount2,pc,pc_new,Ntotfile; Int_t ntot_withmasses; //used to read gadget data unsigned int dummy; GADGETIDTYPE idval; FLOAT ctemp[3]; REAL dtemp; char buf[2000]; char DATA[5]; //store cosmology double z,aadjust,Hubble,Hubbleflow; fstream *Fgad; struct gadget_header *header; Double_t mscale,lscale,lvscale; Double_t MP_DM=MAXVALUE,LN,N_DM,MP_B=MAXVALUE; int ifirstfile=0,*ireadtask,*readtaskID; std::vector ireadfile; Int_t ninputoffset = 0; #ifndef USEMPI Int_t Ntotal; int ThisTask=0,NProcs=1; ireadfile = std::vector(opt.num_files, 1); ireadtask=new int[NProcs]; ireadtask[0]=1; #endif //if MPI is used, Processor zero opens the file and loads the data into a particle buffer //this particle buffer is used to broadcast data to the appropriate processor #ifdef USEMPI //since positions, velocities, masses are all at different points in the file, //to correctly assign particle to proccessor with correct velocities and mass must have several file pointers fstream *Fgadvel, *Fgadid, *Fgadmass, *Fgadsph; fstream *Fgadstar, *Fgadbh; FLOAT vtemp[3]; MPI_Comm mpi_comm_read; Particle *Pbuf; vector *Preadbuf; Int_t chunksize=opt.inputbufsize,nchunk; Int_t BufSize=opt.mpiparticlebufsize; FLOAT *ctempchunk, *vtempchunk, *sphtempchunk; FLOAT *startempchunk, *bhtempchunk; REAL *dtempchunk; GADGETIDTYPE *idvalchunk; //for parallel io Int_t *Nbuf, *Nreadbuf,*nreadoffset; int ibuf=0; Int_t ibufindex; Int_t *Nlocalthreadbuf; int *irecv, *mpi_irecvflag; MPI_Request *mpi_request; Int_t *mpi_nsend_baryon; if (opt.iBaryonSearch && opt.partsearchtype!=PSTALL) mpi_nsend_baryon=new Int_t[NProcs*NProcs]; Int_t inreadsend,totreadsend; Int_t *mpi_nsend_readthread; Int_t *mpi_nsend_readthread_baryon; if (opt.iBaryonSearch) mpi_nsend_baryon=new Int_t[NProcs*NProcs]; if (opt.nsnapread>1) { mpi_nsend_readthread=new Int_t[opt.nsnapread*opt.nsnapread]; if (opt.iBaryonSearch) mpi_nsend_readthread_baryon=new Int_t[opt.nsnapread*opt.nsnapread]; } //altering io so that all tasks with task numbers less than the number of snapshots are used to read the data //this means that all ThisTask==0 need to be changed! //if (ThisTask==0) { Nbuf=new Int_t[NProcs]; nreadoffset=new Int_t[opt.nsnapread]; ireadtask=new int[NProcs]; readtaskID=new int[opt.nsnapread]; MPIDistributeReadTasks(opt,ireadtask,readtaskID); MPI_Comm_split(MPI_COMM_WORLD, (ireadtask[ThisTask]>=0), ThisTask, &mpi_comm_read); if (ireadtask[ThisTask]>=0) { //to temporarily store data from gadget file Pbuf=new Particle[BufSize*NProcs]; Nreadbuf=new Int_t[opt.nsnapread]; for (int j=0;j1){ Preadbuf=new vector[opt.nsnapread]; for (int j=0;j(opt.num_files); ifirstfile=MPISetFilesRead(opt,ireadfile,ireadtask); inreadsend=0; for (int j=0;j=0) { #endif //opening file #define SKIP2 Fgad[i].read((char*)&dummy, sizeof(dummy)); #define SKIPV2 Fgadvel[i].read((char*)&dummy, sizeof(dummy)); #define SKIPI2 Fgadid[i].read((char*)&dummy, sizeof(dummy)); #define SKIPM2 Fgadmass[i].read((char*)&dummy, sizeof(dummy)); Fgad=new fstream[opt.num_files]; header=new gadget_header[opt.num_files]; for(i=0; i1) sprintf(buf,"%s.%lld",opt.fname,i); else sprintf(buf,"%s",opt.fname); Fgad[i].open(buf,ios::in); if(!Fgad[i]) { cout<<"can't open file "<0) { SKIP2; if (dummy/ntot_withmasses!=sizeof(REAL)) {cout<<" mismatch in mass type size, file has "<0) MP_DM=dtemp; if(k==GGASTYPE && dtemp0) MP_B=dtemp; if (opt.partsearchtype==PSTALL) { Part[count2].SetMass(dtemp); count2++; } else if (opt.partsearchtype==PSTDARK) { if (!(k==GGASTYPE||k==GSTARTYPE||k==GBHTYPE)) { Part[count2].SetMass(dtemp); count2++; } else { if (opt.iBaryonSearch==1 && (k==GGASTYPE || k==GSTARTYPE)) { Pbaryons[bcount2].SetMass(dtemp); bcount2++; } } } else if (opt.partsearchtype==PSTSTAR) { if (k==GSTARTYPE) { Part[count2].SetMass(dtemp); count2++; } } else if (opt.partsearchtype==PSTGAS) { if (k==GGASTYPE) { Part[count2].SetMass(dtemp); count2++; } } pc_new++; } } if(ntot_withmasses>0) SKIP2; #endif //more information contained in sph particles and if there is sf feed back but for the moment, ignore //other quantities if (header[i].npartTotal[GGASTYPE]>0) { #ifdef GADGET2FORMAT SKIP2; Fgad[i].read((char*)&DATA[0],sizeof(char)*4);DATA[4] = '\0'; SKIP2; SKIP2; cout<<"reading "<0) { #ifdef GADGET2FORMAT SKIP2; Fgad[i].read((char*)&DATA[0],sizeof(char)*4);DATA[4] = '\0'; SKIP2; SKIP2; cout<<"reading "<0) { for (int nbhblocks=0;nbhblocks1) sprintf(buf,"%s.%d",opt.fname,int(i)); else sprintf(buf,"%s",opt.fname); count=0;for(k=0;k0) { //data loaded into memory in chunks if (header[i].npart[k]0)nchunk=header[i].npart[k]-n; Fgad[i].read((char*)ctempchunk, sizeof(FLOAT)*3*nchunk); Fgadvel[i].read((char*)vtempchunk, sizeof(FLOAT)*3*nchunk); Fgadid[i].read((char*)idvalchunk, sizeof(idval)*nchunk); #ifdef GASON for (int sphblocks=0;sphblocks0) MP_DM=dtemp; if(k==GGASTYPE && dtemp0) MP_B=dtemp; //determine processor this particle belongs on based on its spatial position ibuf=MPIGetParticlesProcessor(opt, ctemp[0],ctemp[1],ctemp[2]); ibufindex=ibuf*BufSize+Nbuf[ibuf]; //when running hydro runs, need to reset particle buffer quantities //related to hydro info to zero #ifdef GASON Pbuf[ibufindex].SetU(0); #ifdef STARON Pbuf[ibufindex].SetSFR(0); Pbuf[ibufindex].SetZmet(0); #endif #endif #ifdef STARON Pbuf[ibufindex].SetZmet(0); Pbuf[ibufindex].SetTage(0); #endif #ifdef BHON #endif //now depending on the type of particle and the type of search, //load the particle into a particle buffer. If the particle belongs on local thread, then just copy it over //to the Part array (or Pbaryons array if the iBaryonSearch is set). Otherwise, keep adding to the Pbuf array //till the array is full and then send messages. if (opt.partsearchtype==PSTALL) { Pbuf[ibufindex]=Particle(dtemp*mscale, ctemp[0]*lscale,ctemp[1]*lscale,ctemp[2]*lscale, vtemp[0]*opt.velocityinputconversion*sqrt(opt.a)+Hubbleflow*ctemp[0], vtemp[1]*opt.velocityinputconversion*sqrt(opt.a)+Hubbleflow*ctemp[1], vtemp[2]*opt.velocityinputconversion*sqrt(opt.a)+Hubbleflow*ctemp[2], count2,k); Pbuf[ibufindex].SetPID(idval); if (k==GGASTYPE) Pbuf[ibufindex].SetType(GASTYPE); else if (k==GSTARTYPE) Pbuf[ibufindex].SetType(STARTYPE); else if (k==GBHTYPE) Pbuf[ibufindex].SetType(BHTYPE); else Pbuf[ibufindex].SetType(DARKTYPE); //assume that first sphblock is internal energy #ifdef GASON if (k==GGASTYPE) Pbuf[ibufindex].SetU(sphtempchunk[0*nchunk+nn]); if (k==GGASTYPE) Pbuf[ibufindex].SetSPHDen(sphtempchunk[1*nchunk+nn]); #endif #ifdef STARON if (k==GSTARTYPE) Pbuf[ibufindex].SetTage(startempchunk[0*nchunk+nn]); #endif #ifdef EXTRAINPUTINFO if (opt.iextendedoutput) { Pbuf[ibufindex].SetInputFileID(i); Pbuf[ibufindex].SetInputIndexInFile(nn+ninputoffset); } #endif Nbuf[ibuf]++; MPIAddParticletoAppropriateBuffer(opt, ibuf, ibufindex, ireadtask, BufSize, Nbuf, Pbuf, Nlocal, Part.data(), Nreadbuf, Preadbuf); count2++; } else if (opt.partsearchtype==PSTDARK) { if (!(k==GGASTYPE||k==GSTARTYPE||k==GBHTYPE)) { Pbuf[ibufindex]=Particle(dtemp*mscale, ctemp[0]*lscale,ctemp[1]*lscale,ctemp[2]*lscale, vtemp[0]*opt.velocityinputconversion*sqrt(opt.a)+Hubbleflow*ctemp[0], vtemp[1]*opt.velocityinputconversion*sqrt(opt.a)+Hubbleflow*ctemp[1], vtemp[2]*opt.velocityinputconversion*sqrt(opt.a)+Hubbleflow*ctemp[2], count2,DARKTYPE); Pbuf[ibufindex].SetPID(idval); #ifdef EXTRAINPUTINFO if (opt.iextendedoutput) { Pbuf[ibufindex].SetInputFileID(i); Pbuf[ibufindex].SetInputIndexInFile(nn+ninputoffset); } #endif //when running hydro runs, need to reset particle buffer quantities //related to hydro info to zero Nbuf[ibuf]++; MPIAddParticletoAppropriateBuffer(opt, ibuf, ibufindex, ireadtask, BufSize, Nbuf, Pbuf, Nlocal, Part.data(), Nreadbuf, Preadbuf); count2++; } else if (opt.iBaryonSearch) { Pbuf[ibufindex]=Particle(dtemp*mscale, ctemp[0]*lscale,ctemp[1]*lscale,ctemp[2]*lscale, vtemp[0]*opt.velocityinputconversion*sqrt(opt.a)+Hubbleflow*ctemp[0], vtemp[1]*opt.velocityinputconversion*sqrt(opt.a)+Hubbleflow*ctemp[1], vtemp[2]*opt.velocityinputconversion*sqrt(opt.a)+Hubbleflow*ctemp[2], count2); Pbuf[ibufindex].SetPID(idval); if (k==GGASTYPE) { #ifdef GASON Pbuf[ibufindex].SetU(sphtempchunk[0*nchunk+nn]); Pbuf[ibufindex].SetSPHDen(sphtempchunk[1*nchunk+nn]); #endif Pbuf[ibufindex].SetType(GASTYPE); } else if (k==GSTARTYPE) { #ifdef STARON Pbuf[ibufindex].SetTage(startempchunk[0*nchunk+nn]); #endif Pbuf[ibufindex].SetType(STARTYPE); } else if (k==GBHTYPE) Pbuf[ibufindex].SetType(BHTYPE); #ifdef EXTRAINPUTINFO if (opt.iextendedoutput) { Pbuf[ibufindex].SetInputFileID(i); Pbuf[ibufindex].SetInputIndexInFile(nn+ninputoffset); } #endif Nbuf[ibuf]++; if (ibuf==ThisTask) { if (k==GGASTYPE) Nlocalbaryon[1]++; else if (k==GSTARTYPE) Nlocalbaryon[2]++; else if (k==GBHTYPE) Nlocalbaryon[3]++; } MPIAddParticletoAppropriateBuffer(opt, ibuf, ibufindex, ireadtask, BufSize, Nbuf, Pbuf, Nlocalbaryon[0], Pbaryons, Nreadbuf, Preadbuf); bcount2++; } } else if (opt.partsearchtype==PSTSTAR) { if (k==GSTARTYPE) { //if using MPI, determine proccessor and place in ibuf, store particle in particle buffer and if buffer full, broadcast data //unless ibuf is 0, then just store locally Pbuf[ibufindex]=Particle(dtemp*mscale, ctemp[0]*lscale,ctemp[1]*lscale,ctemp[2]*lscale, vtemp[0]*opt.velocityinputconversion*sqrt(opt.a)+Hubbleflow*ctemp[0], vtemp[1]*opt.velocityinputconversion*sqrt(opt.a)+Hubbleflow*ctemp[1], vtemp[2]*opt.velocityinputconversion*sqrt(opt.a)+Hubbleflow*ctemp[2], count2,STARTYPE); #ifdef STARON Pbuf[ibufindex].SetTage(startempchunk[0*nchunk+nn]); #endif Pbuf[ibufindex].SetPID(idval); #ifdef EXTRAINPUTINFO if (opt.iextendedoutput) { Pbuf[ibufindex].SetInputFileID(i); Pbuf[ibufindex].SetInputIndexInFile(nn+ninputoffset); } #endif Nbuf[ibuf]++; MPIAddParticletoAppropriateBuffer(opt, ibuf, ibufindex, ireadtask, BufSize, Nbuf, Pbuf, Nlocal, Part.data(), Nreadbuf, Preadbuf); count2++; } } else if (opt.partsearchtype==PSTGAS) { if (k==GGASTYPE) { Pbuf[ibufindex]=Particle(dtemp*mscale, ctemp[0]*lscale,ctemp[1]*lscale,ctemp[2]*lscale, vtemp[0]*opt.velocityinputconversion*sqrt(opt.a)+Hubbleflow*ctemp[0], vtemp[1]*opt.velocityinputconversion*sqrt(opt.a)+Hubbleflow*ctemp[1], vtemp[2]*opt.velocityinputconversion*sqrt(opt.a)+Hubbleflow*ctemp[2], count2,GASTYPE); //ensure that store number of particles to be sent to the reading threads Pbuf[ibufindex].SetPID(idval); #ifdef GASON Pbuf[ibufindex].SetU(sphtempchunk[0*nchunk+nn]); Pbuf[ibufindex].SetSPHDen(sphtempchunk[1*nchunk+nn]); #endif #ifdef EXTRAINPUTINFO if (opt.iextendedoutput) { Pbuf[ibufindex].SetInputFileID(i); Pbuf[ibufindex].SetInputIndexInFile(nn+ninputoffset); } #endif Nbuf[ibuf]++; MPIAddParticletoAppropriateBuffer(opt, ibuf, ibufindex, ireadtask, BufSize, Nbuf, Pbuf, Nlocal, Part.data(), Nreadbuf, Preadbuf); count2++; } } pc_new++; } ninputoffset += nchunk; } } //more information contained in sph particles and if there is sf feed back but for the moment, ignore Fgad[i].close(); Fgadvel[i].close(); Fgadid[i].close(); Fgadmass[i].close(); for (int sphblocks=0;sphblocks1&&inreadsend0) { MPI_Ssend(&Pbuf[ibuf*BufSize], sizeof(Particle)*Nbuf[ibuf], MPI_BYTE, ibuf, ibuf, MPI_COMM_WORLD); MPISendHydroInfoFromReadThreads(opt, Nbuf[ibuf], &Pbuf[ibuf*BufSize], ibuf); MPISendStarInfoFromReadThreads(opt, Nbuf[ibuf], &Pbuf[ibuf*BufSize], ibuf); MPISendBHInfoFromReadThreads(opt, Nbuf[ibuf], &Pbuf[ibuf*BufSize], ibuf); Nbuf[ibuf]=0; //last broadcast with Nbuf[ibuf]=0 so that receiver knows no more particles are to be broadcast MPI_Ssend(&Nbuf[ibuf],1,MPI_Int_t,ibuf,ibuf+NProcs,MPI_COMM_WORLD); } } if (opt.nsnapread>1){ MPI_Allgather(Nreadbuf, opt.nsnapread, MPI_Int_t, mpi_nsend_readthread, opt.nsnapread, MPI_Int_t, mpi_comm_read); MPISendParticlesBetweenReadThreads(opt, Preadbuf, Part.data(), ireadtask, readtaskID, Pbaryons, mpi_comm_read, mpi_nsend_readthread, mpi_nsend_readthread_baryon); } #endif #ifdef USEMPI }//end of read thread section else { MPIReceiveParticlesFromReadThreads(opt,Pbuf,Part.data(),readtaskID, irecv, mpi_irecvflag, Nlocalthreadbuf, mpi_request,Pbaryons); } #endif #ifdef USEMPI if (ThisTask==0) { #endif ///if gas found and Omega_b not set correctly (ie: ==0), assumes that ///lowest mass gas particle found corresponds to Omega_b ///Note that if there is mass evolution this WILL NOT WORK! if (opt.Omega_b==0 && MP_B1) { delete[] mpi_nsend_readthread; if (opt.iBaryonSearch) delete[] mpi_nsend_readthread_baryon; if (ireadtask[ThisTask]>=0) delete[] Preadbuf; } delete[] Nbuf; if (ireadtask[ThisTask]>=0) { delete[] Nreadbuf; delete[] Pbuf; } delete[] ireadtask; delete[] readtaskID; #endif }