diff --git a/src/dump.h b/src/dump.h index 17d4554cc3..ce2f0dc4e7 100644 --- a/src/dump.h +++ b/src/dump.h @@ -57,12 +57,12 @@ class Dump : protected Pointers { int binary; // 1 if dump file is written binary, 0 no int multifile; // 0 = one big file, 1 = one file per timestep - int multiproc; // 0 = proc 0 writes for all, + int multiproc; // 0 = proc 0 writes for all // else # of procs writing files int nclusterprocs; // # of procs in my cluster that write to one file int filewriter; // 1 if this proc writes a file, else 0 int fileproc; // ID of proc in my cluster who writes to file - char *multiname; // dump filename with % converted to cluster ID + char *multiname; // filename with % converted to cluster ID MPI_Comm clustercomm; // MPI communicator within my cluster of procs int header_flag; // 0 = item, 2 = xyz diff --git a/src/output.cpp b/src/output.cpp index 251a66fc87..7c97b85b1a 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -706,9 +706,13 @@ void Output::create_restart(int narg, char **arg) return; } - if (narg != 2 && narg != 3) error->all(FLERR,"Illegal restart command"); + if (narg < 2) error->all(FLERR,"Illegal restart command"); - if (narg == 2) { + int nfile = 0; + if (narg % 2 == 0) nfile = 1; + else nfile = 2; + + if (nfile = 1) { restart_flag = restart_flag_single = 1; if (varflag) { @@ -725,7 +729,7 @@ void Output::create_restart(int narg, char **arg) if (strchr(restart1,'*') == NULL) strcat(restart1,".*"); } - if (narg == 3) { + if (nfile == 2) { restart_flag = restart_flag_double = 1; if (varflag) { @@ -745,7 +749,35 @@ void Output::create_restart(int narg, char **arg) strcpy(restart2b,arg[2]); } - if (restart == NULL) restart = new WriteRestart(lmp); + // check for multiproc output and an MPI-IO filename + // if 2 filenames, must be consistent + + int multiproc; + if (strchr(arg[1],'%')) multiproc = comm->nprocs; + else multiproc = 0; + if (nfile == 2) { + if (multiproc && !strchr(arg[2],'%')) + error->all(FLERR,"Both restart files must have '%' or neither"); + if (!multiproc && strchr(arg[2],'%')) + error->all(FLERR,"Both restart files must have '%' or neither"); + } + + int mpiio; + if (strstr(arg[1],".mpi")) mpiio = 1; + else mpiio = 0; + if (nfile == 2) { + if (mpiio && !strstr(arg[2],".mpi")) + error->all(FLERR,"Both restart files must use MPI-IO or neither"); + if (!mpiio && strstr(arg[2],".mpi")) + error->all(FLERR,"Both restart files must use MPI-IO or neither"); + } + + // setup output style and process optional args + + delete restart; + restart = new WriteRestart(lmp); + int iarg = nfile+1; + restart->multiproc_options(multiproc,mpiio,narg-iarg,&arg[iarg]); } /* ---------------------------------------------------------------------- diff --git a/src/read_restart.cpp b/src/read_restart.cpp index 08d346c4ba..0167911b5b 100644 --- a/src/read_restart.cpp +++ b/src/read_restart.cpp @@ -15,7 +15,6 @@ #include "mpi.h" #include "string.h" #include "stdlib.h" -//#include "sys/types.h" #include "dirent.h" #include "read_restart.h" #include "atom.h" @@ -43,21 +42,24 @@ using namespace LAMMPS_NS; // same as write_restart.cpp +#define MAGIC_STRING "LammpS RestartT" +#define ENDIAN 0x0001 +#define ENDIANSWAP 0x1000 +#define VERSION_NUMERIC 0 + enum{VERSION,SMALLINT,TAGINT,BIGINT, - UNITS,NTIMESTEP,DIMENSION,NPROCS,PROCGRID_0,PROCGRID_1,PROCGRID_2, - NEWTON_PAIR,NEWTON_BOND,XPERIODIC,YPERIODIC,ZPERIODIC, - BOUNDARY_00,BOUNDARY_01,BOUNDARY_10,BOUNDARY_11,BOUNDARY_20,BOUNDARY_21, - ATOM_STYLE,NATOMS,NTYPES, - NBONDS,NBONDTYPES,BOND_PER_ATOM, - NANGLES,NANGLETYPES,ANGLE_PER_ATOM, - NDIHEDRALS,NDIHEDRALTYPES,DIHEDRAL_PER_ATOM, - NIMPROPERS,NIMPROPERTYPES,IMPROPER_PER_ATOM, - BOXLO_0,BOXHI_0,BOXLO_1,BOXHI_1,BOXLO_2,BOXHI_2, - SPECIAL_LJ_1,SPECIAL_LJ_2,SPECIAL_LJ_3, - SPECIAL_COUL_1,SPECIAL_COUL_2,SPECIAL_COUL_3, - XY,XZ,YZ}; -enum{MASS}; -enum{PAIR,BOND,ANGLE,DIHEDRAL,IMPROPER}; + UNITS,NTIMESTEP,DIMENSION,NPROCS,PROCGRID, + NEWTON_PAIR,NEWTON_BOND, + XPERIODIC,YPERIODIC,ZPERIODIC,BOUNDARY, + ATOM_STYLE,NATOMS,NTYPES, + NBONDS,NBONDTYPES,BOND_PER_ATOM, + NANGLES,NANGLETYPES,ANGLE_PER_ATOM, + NDIHEDRALS,NDIHEDRALTYPES,DIHEDRAL_PER_ATOM, + NIMPROPERS,NIMPROPERTYPES,IMPROPER_PER_ATOM, + TRICLINIC,BOXLO,BOXHI,XY,XZ,YZ, + SPECIAL_LJ,SPECIAL_COUL, + MASS,PAIR,BOND,ANGLE,DIHEDRAL,IMPROPER, + MULTIPROC,MPIIO,PROCSPERFILE,PERPROC}; #define LB_FACTOR 1.1 @@ -90,14 +92,18 @@ void ReadRestart::command(int narg, char **arg) MPI_Bcast(file,n,MPI_CHAR,0,world); } else strcpy(file,arg[0]); - // check if filename contains "%" + // check for multiproc files and an MPI-IO filename - int multiproc; - if (strchr(file,'%')) multiproc = 1; + if (strchr(arg[0],'%')) multiproc = 1; else multiproc = 0; + if (strstr(arg[0],".mpi")) mpiio = 1; + else mpiio = 0; + + if (multiproc && mpiio) + error->all(FLERR, + "Read restart MPI-IO output not allowed with '%' in filename"); // open single restart file or base file for multiproc case - // auto-detect whether byte swapping needs to be done as file is read if (me == 0) { if (screen) fprintf(screen,"Reading restart file ...\n"); @@ -115,15 +121,18 @@ void ReadRestart::command(int narg, char **arg) sprintf(str,"Cannot open restart file %s",hfile); error->one(FLERR,str); } - swapflag = autodetect(&fp,hfile); if (multiproc) delete [] hfile; } - MPI_Bcast(&swapflag,1,MPI_INT,0,world); + // read magic string, endian flag, numeric version - // read header info and create atom style and simulation box + magic_string(); + endian(); + int outofdate = version_numeric(); - header(); + // read header info which creates simulation box + + header(outofdate); domain->box_exist = 1; // problem setup using info from header @@ -153,12 +162,19 @@ void ReadRestart::command(int narg, char **arg) atom->nextra_store = nextra; memory->create(atom->extra,n,nextra,"atom:extra"); + // read file layout info + + file_layout(); + + // all done with reading header info + + if (me == 0) fclose(fp); + // single file: // nprocs_file = # of chunks in file - // proc 0 reads chunks one at a time and bcasts it to other procs + // proc 0 reads a chunk and bcasts it to other procs // each proc unpacks the atoms, saving ones in it's sub-domain // check for atom in sub-domain differs for orthogonal vs triclinic box - // close restart file when done AtomVec *avec = atom->avec; @@ -167,6 +183,7 @@ void ReadRestart::command(int narg, char **arg) int m; if (multiproc == 0) { + int triclinic = domain->triclinic; double *x,lamda[3]; double *coord,*sublo,*subhi; @@ -179,17 +196,16 @@ void ReadRestart::command(int narg, char **arg) } for (int iproc = 0; iproc < nprocs_file; iproc++) { + if (read_int() != PERPROC) + error->all(FLERR,"Invalid flag in peratom section of restart file"); + n = read_int(); if (n > maxbuf) { maxbuf = n; memory->destroy(buf); memory->create(buf,maxbuf,"read_restart:buf"); } - - if (n > 0) { - if (me == 0) nread_double(buf,n,fp); - MPI_Bcast(buf,n,MPI_DOUBLE,0,world); - } + read_double_vec(n,buf); m = 0; while (m < n) { @@ -210,42 +226,166 @@ void ReadRestart::command(int narg, char **arg) if (me == 0) fclose(fp); - // one file per proc: - // nprocs_file = # of files - // each proc reads 1/P fraction of files, keeping all atoms in the files - // perform irregular comm to migrate atoms to correct procs - // close restart file when done + // multiple files with procs <= files + // # of files = multiproc_file + // each proc reads a subset of files, striding by nprocs + // each proc keeps all atoms in all perproc chunks in its files - } else { - if (me == 0) fclose(fp); - char *perproc = new char[strlen(file) + 16]; + } else if (nprocs <= multiproc_file) { + + char *procfile = new char[strlen(file) + 16]; char *ptr = strchr(file,'%'); - for (int iproc = me; iproc < nprocs_file; iproc += nprocs) { + for (int iproc = me; iproc < multiproc_file; iproc += nprocs) { *ptr = '\0'; - sprintf(perproc,"%s%d%s",file,iproc,ptr+1); + sprintf(procfile,"%s%d%s",file,iproc,ptr+1); *ptr = '%'; - fp = fopen(perproc,"rb"); + fp = fopen(procfile,"rb"); if (fp == NULL) { char str[128]; - sprintf(str,"Cannot open restart file %s",perproc); + sprintf(str,"Cannot open restart file %s",procfile); error->one(FLERR,str); } - nread_int(&n,1,fp); - if (n > maxbuf) { - maxbuf = n; - memory->destroy(buf); - memory->create(buf,maxbuf,"read_restart:buf"); - } - if (n > 0) nread_double(buf,n,fp); + int flag; + fread(&flag,sizeof(int),1,fp); + if (flag != PROCSPERFILE) + error->one(FLERR,"Invalid flag in peratom section of restart file"); + int procsperfile; + fread(&procsperfile,sizeof(int),1,fp); + + for (int i = 0; i < procsperfile; i++) { + fread(&flag,sizeof(int),1,fp); + if (flag != PERPROC) + error->one(FLERR,"Invalid flag in peratom section of restart file"); + + fread(&n,sizeof(int),1,fp); + if (n > maxbuf) { + maxbuf = n; + memory->destroy(buf); + memory->create(buf,maxbuf,"read_restart:buf"); + } + fread(buf,sizeof(double),n,fp); + + m = 0; + while (m < n) m += avec->unpack_restart(&buf[m]); + } - m = 0; - while (m < n) m += avec->unpack_restart(&buf[m]); fclose(fp); } - delete [] perproc; + delete [] procfile; + + // multiple files with procs > files + // # of files = multiproc_file + // cluster procs based on # of files + // 1st proc in each cluster reads per-proc chunks from file + // sends chunks round-robin to other procs in its cluster + // each proc keeps all atoms in its perproc chunks in file + + } else { + + // nclusterprocs = # of procs in my cluster that read from one file + // filewriter = 1 if this proc reads file, else 0 + // fileproc = ID of proc in my cluster who reads from file + // clustercomm = MPI communicator within my cluster of procs + + int nfile = multiproc_file; + int icluster = static_cast ((bigint) me * nfile/nprocs); + int fileproc = static_cast ((bigint) icluster * nprocs/nfile); + int fcluster = static_cast ((bigint) fileproc * nfile/nprocs); + if (fcluster < icluster) fileproc++; + int fileprocnext = + static_cast ((bigint) (icluster+1) * nprocs/nfile); + fcluster = static_cast ((bigint) fileprocnext * nfile/nprocs); + if (fcluster < icluster+1) fileprocnext++; + int nclusterprocs = fileprocnext - fileproc; + int filereader = 0; + if (me == fileproc) filereader = 1; + MPI_Comm clustercomm; + MPI_Comm_split(world,icluster,0,&clustercomm); + + if (filereader) { + char *procfile = new char[strlen(file) + 16]; + char *ptr = strchr(file,'%'); + *ptr = '\0'; + sprintf(procfile,"%s%d%s",file,icluster,ptr+1); + *ptr = '%'; + fp = fopen(procfile,"rb"); + if (fp == NULL) { + char str[128]; + sprintf(str,"Cannot open restart file %s",procfile); + error->one(FLERR,str); + } + delete [] procfile; + } + + int flag,procsperfile; + + if (filereader) { + fread(&flag,sizeof(int),1,fp); + if (flag != PROCSPERFILE) + error->one(FLERR,"Invalid flag in peratom section of restart file"); + fread(&procsperfile,sizeof(int),1,fp); + } + MPI_Bcast(&procsperfile,1,MPI_INT,0,clustercomm); + + int tmp,iproc; + MPI_Status status; + MPI_Request request; + + for (int i = 0; i < procsperfile; i++) { + if (filereader) { + fread(&flag,sizeof(int),1,fp); + if (flag != PERPROC) + error->one(FLERR,"Invalid flag in peratom section of restart file"); + + fread(&n,sizeof(int),1,fp); + if (n > maxbuf) { + maxbuf = n; + memory->destroy(buf); + memory->create(buf,maxbuf,"read_restart:buf"); + } + fread(buf,sizeof(double),n,fp); + + if (i % nclusterprocs) { + iproc = me + (i % nclusterprocs); + MPI_Send(&n,1,MPI_INT,iproc,0,world); + MPI_Recv(&tmp,0,MPI_INT,iproc,0,world,&status); + MPI_Rsend(buf,n,MPI_DOUBLE,iproc,0,world); + } + + } else if (i % nclusterprocs == me - fileproc) { + MPI_Recv(&n,1,MPI_INT,fileproc,0,world,&status); + if (n > maxbuf) { + maxbuf = n; + memory->destroy(buf); + memory->create(buf,maxbuf,"read_restart:buf"); + } + MPI_Irecv(buf,n,MPI_DOUBLE,fileproc,0,world,&request); + MPI_Send(&tmp,0,MPI_INT,fileproc,0,world); + MPI_Wait(&request,&status); + } + + if (i % nclusterprocs == me - fileproc) { + m = 0; + while (m < n) m += avec->unpack_restart(&buf[m]); + } + } + + if (filereader) fclose(fp); + MPI_Comm_free(&clustercomm); + } + + // clean-up memory + + delete [] file; + memory->destroy(buf); + + // for multiproc files: + // perform irregular comm to migrate atoms to correct procs + + if (multiproc) { // create a temporary fix to hold and migrate extra atom info // necessary b/c irregular will migrate atoms @@ -294,11 +434,6 @@ void ReadRestart::command(int narg, char **arg) } } - // clean-up memory - - delete [] file; - memory->destroy(buf); - // check that all atoms were assigned to procs bigint natoms; @@ -451,13 +586,13 @@ void ReadRestart::file_search(char *infile, char *outfile) read header of restart file ------------------------------------------------------------------------- */ -void ReadRestart::header() +void ReadRestart::header(int outofdate) { int px,py,pz; int xperiodic,yperiodic,zperiodic; int boundary[3][2]; - // read flags and values until flag = -1 + // read flags and fields until flag = -1 int flag = read_int(); while (flag >= 0) { @@ -465,16 +600,16 @@ void ReadRestart::header() // check restart file version, warn if different if (flag == VERSION) { - char *version = read_char(); - if (strcmp(version,universe->version) != 0 && me == 0) { - error->warning(FLERR, - "Restart file version does not match LAMMPS version"); + char *version = read_string(); + if (me == 0) { if (screen) fprintf(screen," restart file = %s, LAMMPS = %s\n", version,universe->version); } + if (outofdate) + error->all(FLERR,"Restart file too old for current version to read"); delete [] version; - // check lmptype.h sizes, error if different + // check lmptype.h sizes, error if different } else if (flag == SMALLINT) { int size = read_int(); @@ -489,18 +624,18 @@ void ReadRestart::header() if (size != sizeof(bigint)) error->all(FLERR,"Bigint setting in lmptype.h is not compatible"); - // reset unit_style only if different - // so that timestep,neighbor-skin are not changed + // reset unit_style only if different + // so that timestep,neighbor-skin are not changed } else if (flag == UNITS) { - char *style = read_char(); + char *style = read_string(); if (strcmp(style,update->unit_style) != 0) update->set_units(style); delete [] style; } else if (flag == NTIMESTEP) { update->ntimestep = read_bigint(); - // set dimension from restart file + // set dimension from restart file } else if (flag == DIMENSION) { int dimension = read_int(); @@ -509,24 +644,23 @@ void ReadRestart::header() error->all(FLERR, "Cannot run 2d simulation with nonperiodic Z dimension"); - // read nprocs from restart file, warn if different + // read nprocs from restart file, warn if different } else if (flag == NPROCS) { nprocs_file = read_int(); if (nprocs_file != comm->nprocs && me == 0) error->warning(FLERR,"Restart file used different # of processors"); - // don't set procgrid, warn if different + // don't set procgrid, warn if different - } else if (flag == PROCGRID_0) { - px = read_int(); - } else if (flag == PROCGRID_1) { - py = read_int(); - } else if (flag == PROCGRID_2) { - pz = read_int(); + } else if (flag == PROCGRID) { + int procgrid[3]; + read_int(); + read_int_vec(3,procgrid); if (comm->user_procgrid[0] != 0 && - (px != comm->user_procgrid[0] || py != comm->user_procgrid[1] || - pz != comm->user_procgrid[2]) && me == 0) + (procgrid[0] != comm->user_procgrid[0] || + procgrid[1] != comm->user_procgrid[1] || + procgrid[2] != comm->user_procgrid[2]) && me == 0) error->warning(FLERR,"Restart file used different 3d processor grid"); // don't set newton_pair, leave input script value unchanged @@ -562,18 +696,10 @@ void ReadRestart::header() yperiodic = read_int(); } else if (flag == ZPERIODIC) { zperiodic = read_int(); - } else if (flag == BOUNDARY_00) { - boundary[0][0] = read_int(); - } else if (flag == BOUNDARY_01) { - boundary[0][1] = read_int(); - } else if (flag == BOUNDARY_10) { - boundary[1][0] = read_int(); - } else if (flag == BOUNDARY_11) { - boundary[1][1] = read_int(); - } else if (flag == BOUNDARY_20) { - boundary[2][0] = read_int(); - } else if (flag == BOUNDARY_21) { - boundary[2][1] = read_int(); + } else if (flag == BOUNDARY) { + int boundary[3][2]; + read_int(); + read_int_vec(6,&boundary[0][0]); if (domain->boundary[0][0] || domain->boundary[0][1] || domain->boundary[1][0] || domain->boundary[1][1] || @@ -611,11 +737,11 @@ void ReadRestart::header() domain->nonperiodic = 2; } - // create new AtomVec class - // if style = hybrid, read additional sub-class arguments + // create new AtomVec class + // if style = hybrid, read additional sub-class arguments } else if (flag == ATOM_STYLE) { - char *style = read_char(); + char *style = read_string(); int nwords = 0; char **words = NULL; @@ -623,7 +749,7 @@ void ReadRestart::header() if (strcmp(style,"hybrid") == 0) { nwords = read_int(); words = new char*[nwords]; - for (int i = 0; i < nwords; i++) words[i] = read_char(); + for (int i = 0; i < nwords; i++) words[i] = read_string(); } atom->create_avec(style,nwords,words); @@ -662,42 +788,28 @@ void ReadRestart::header() } else if (flag == IMPROPER_PER_ATOM) { atom->improper_per_atom = read_int(); - } else if (flag == BOXLO_0) { - domain->boxlo[0] = read_double(); - } else if (flag == BOXHI_0) { - domain->boxhi[0] = read_double(); - } else if (flag == BOXLO_1) { - domain->boxlo[1] = read_double(); - } else if (flag == BOXHI_1) { - domain->boxhi[1] = read_double(); - } else if (flag == BOXLO_2) { - domain->boxlo[2] = read_double(); - } else if (flag == BOXHI_2) { - domain->boxhi[2] = read_double(); - - } else if (flag == SPECIAL_LJ_1) { - force->special_lj[1] = read_double(); - } else if (flag == SPECIAL_LJ_2) { - force->special_lj[2] = read_double(); - } else if (flag == SPECIAL_LJ_3) { - force->special_lj[3] = read_double(); - } else if (flag == SPECIAL_COUL_1) { - force->special_coul[1] = read_double(); - } else if (flag == SPECIAL_COUL_2) { - force->special_coul[2] = read_double(); - } else if (flag == SPECIAL_COUL_3) { - force->special_coul[3] = read_double(); - + } else if (flag == TRICLINIC) { + domain->triclinic = read_int(); + } else if (flag == BOXLO) { + read_int(); + read_double_vec(3,domain->boxlo); + } else if (flag == BOXHI) { + read_int(); + read_double_vec(3,domain->boxhi); } else if (flag == XY) { - domain->triclinic = 1; domain->xy = read_double(); } else if (flag == XZ) { - domain->triclinic = 1; domain->xz = read_double(); } else if (flag == YZ) { - domain->triclinic = 1; domain->yz = read_double(); + } else if (flag == SPECIAL_LJ) { + read_int(); + read_double_vec(3,&force->special_lj[1]); + } else if (flag == SPECIAL_COUL) { + read_int(); + read_double_vec(3,&force->special_coul[1]); + } else error->all(FLERR,"Invalid flag in header section of restart file"); flag = read_int(); @@ -712,9 +824,9 @@ void ReadRestart::type_arrays() while (flag >= 0) { if (flag == MASS) { + read_int(); double *mass = new double[atom->ntypes+1]; - if (me == 0) nread_double(&mass[1],atom->ntypes,fp); - MPI_Bcast(&mass[1],atom->ntypes,MPI_DOUBLE,0,world); + read_double_vec(atom->ntypes,&mass[1]); atom->set_mass(mass); delete [] mass; @@ -736,55 +848,31 @@ void ReadRestart::force_fields() while (flag >= 0) { if (flag == PAIR) { - n = read_int(); - style = new char[n]; - if (me == 0) nread_char(style,n,fp); - MPI_Bcast(style,n,MPI_CHAR,0,world); - + style = read_string(); force->create_pair(style); delete [] style; - if (force->pair->restartinfo) force->pair->read_restart(fp); - else { - delete force->pair; - force->pair = NULL; - } + force->pair->read_restart(fp); } else if (flag == BOND) { - n = read_int(); - style = new char[n]; - if (me == 0) nread_char(style,n,fp); - MPI_Bcast(style,n,MPI_CHAR,0,world); - + style = read_string(); force->create_bond(style); delete [] style; force->bond->read_restart(fp); } else if (flag == ANGLE) { - n = read_int(); - style = new char[n]; - if (me == 0) nread_char(style,n,fp); - MPI_Bcast(style,n,MPI_CHAR,0,world); - + style = read_string(); force->create_angle(style); delete [] style; force->angle->read_restart(fp); } else if (flag == DIHEDRAL) { - n = read_int(); - style = new char[n]; - if (me == 0) nread_char(style,n,fp); - MPI_Bcast(style,n,MPI_CHAR,0,world); - + style = read_string(); force->create_dihedral(style); delete [] style; force->dihedral->read_restart(fp); } else if (flag == IMPROPER) { - n = read_int(); - style = new char[n]; - if (me == 0) nread_char(style,n,fp); - MPI_Bcast(style,n,MPI_CHAR,0,world); - + style = read_string(); force->create_improper(style); delete [] style; force->improper->read_restart(fp); @@ -796,36 +884,81 @@ void ReadRestart::force_fields() } } +/* ---------------------------------------------------------------------- */ + +void ReadRestart::file_layout() +{ + int flag = read_int(); + while (flag >= 0) { + + if (flag == MULTIPROC) { + multiproc_file = read_int(); + if (multiproc == 0 && multiproc_file) + error->all(FLERR,"Restart file is not a multi-proc file"); + if (multiproc && multiproc_file == 0) + error->all(FLERR,"Restart file is a multi-proc file"); + + } else if (flag = MPIIO) { + int mpiio_file = read_int(); + if (mpiio == 0 && mpiio_file) + error->all(FLERR,"Restart file is a MPI-IO file"); + if (mpiio && mpiio_file == 0) + error->all(FLERR,"Restart file is not a MPI-IO file"); + } + + flag = read_int(); + } +} + +// ---------------------------------------------------------------------- +// ---------------------------------------------------------------------- +// low-level fread methods +// ---------------------------------------------------------------------- +// ---------------------------------------------------------------------- + /* ---------------------------------------------------------------------- - read N ints from restart file - do not bcast them, caller does that if required ------------------------------------------------------------------------- */ -void ReadRestart::nread_int(int *buf, int n, FILE *fp) +void ReadRestart::magic_string() { - fread(buf,sizeof(int),n,fp); - if (swapflag) {} + int n = strlen(MAGIC_STRING) + 1; + char *str = new char[n]; + + int count; + if (me == 0) count = fread(str,sizeof(char),n,fp); + MPI_Bcast(&count,1,MPI_INT,0,world); + if (count < n) + error->all(FLERR,"Invalid LAMMPS restart file"); + MPI_Bcast(str,n,MPI_CHAR,0,world); + if (strcmp(str,MAGIC_STRING) != 0) + error->all(FLERR,"Invalid LAMMPS restart file"); + delete [] str; } /* ---------------------------------------------------------------------- - read N doubles from restart file - do not bcast them, caller does that if required ------------------------------------------------------------------------- */ -void ReadRestart::nread_double(double *buf, int n, FILE *fp) +void ReadRestart::endian() { - fread(buf,sizeof(double),n,fp); - if (swapflag) {} + int endian; + if (me == 0) fread(&endian,sizeof(int),1,fp); + MPI_Bcast(&endian,1,MPI_INT,0,world); + if (endian == ENDIAN) return; + if (endian == ENDIANSWAP) + error->all(FLERR,"Restart file byte ordering is swapped"); + else error->all(FLERR,"Restart file byte ordering is not recognized"); } /* ---------------------------------------------------------------------- - read N chars from restart file - do not bcast them, caller does that if required ------------------------------------------------------------------------- */ -void ReadRestart::nread_char(char *buf, int n, FILE *fp) +int ReadRestart::version_numeric() { - fread(buf,sizeof(char),n,fp); + int vn; + if (me == 0) fread(&vn,sizeof(int),1,fp); + MPI_Bcast(&vn,1,MPI_INT,0,world); + if (vn < VERSION_NUMERIC) return 1; + return 0; } /* ---------------------------------------------------------------------- @@ -835,51 +968,11 @@ void ReadRestart::nread_char(char *buf, int n, FILE *fp) int ReadRestart::read_int() { int value; - if (me == 0) { - fread(&value,sizeof(int),1,fp); - if (swapflag) {} - } + if (me == 0) fread(&value,sizeof(int),1,fp); MPI_Bcast(&value,1,MPI_INT,0,world); return value; } -/* ---------------------------------------------------------------------- - read a double from restart file and bcast it -------------------------------------------------------------------------- */ - -double ReadRestart::read_double() -{ - double value; - if (me == 0) { - fread(&value,sizeof(double),1,fp); - if (swapflag) {} - } - MPI_Bcast(&value,1,MPI_DOUBLE,0,world); - return value; -} - -/* ---------------------------------------------------------------------- - read a char str from restart file and bcast it - str is allocated here, ptr is returned, caller must deallocate -------------------------------------------------------------------------- */ - -char *ReadRestart::read_char() -{ - int n; - if (me == 0) { - fread(&n,sizeof(int),1,fp); - if (swapflag) {} - } - MPI_Bcast(&n,1,MPI_INT,0,world); - char *value = new char[n]; - if (me == 0) { - fread(value,sizeof(char),n,fp); - if (swapflag) {} - } - MPI_Bcast(value,n,MPI_CHAR,0,world); - return value; -} - /* ---------------------------------------------------------------------- read a bigint from restart file and bcast it ------------------------------------------------------------------------- */ @@ -887,35 +980,57 @@ char *ReadRestart::read_char() bigint ReadRestart::read_bigint() { bigint value; - if (me == 0) { - fread(&value,sizeof(bigint),1,fp); - if (swapflag) {} - } + if (me == 0) fread(&value,sizeof(bigint),1,fp); MPI_Bcast(&value,1,MPI_LMP_BIGINT,0,world); return value; } /* ---------------------------------------------------------------------- - auto-detect if restart file needs to be byte-swapped on this platform - return 0 if not, 1 if it does - re-open file with fp after checking first few bytes - read a bigint from restart file and bcast it - NOTE: not yet fully implemented, ditto for swapflag logic + read a double from restart file and bcast it ------------------------------------------------------------------------- */ -int ReadRestart::autodetect(FILE **pfp, char *file) +double ReadRestart::read_double() { - FILE *fp = *pfp; - - // read, check, set return flag - - int flag = 0; - - // reset file pointer - - fclose(fp); - fp = fopen(file,"rb"); - *pfp = fp; - - return flag; + double value; + if (me == 0) fread(&value,sizeof(double),1,fp); + MPI_Bcast(&value,1,MPI_DOUBLE,0,world); + return value; +} + +/* ---------------------------------------------------------------------- + read a char string (including NULL) and bcast it + str is allocated here, ptr is returned, caller must deallocate +------------------------------------------------------------------------- */ + +char *ReadRestart::read_string() +{ + int n; + if (me == 0) fread(&n,sizeof(int),1,fp); + MPI_Bcast(&n,1,MPI_INT,0,world); + char *value = new char[n]; + if (me == 0) fread(value,sizeof(char),n,fp); + MPI_Bcast(value,n,MPI_CHAR,0,world); + return value; +} + +/* ---------------------------------------------------------------------- + read vector of N ints from restart file and bcast them + do not bcast them, caller does that if required +------------------------------------------------------------------------- */ + +void ReadRestart::read_int_vec(int n, int *vec) +{ + if (me == 0) fread(vec,sizeof(int),n,fp); + MPI_Bcast(vec,n,MPI_INT,0,world); +} + +/* ---------------------------------------------------------------------- + read vector of N doubles from restart file and bcast them + do not bcast them, caller does that if required +------------------------------------------------------------------------- */ + +void ReadRestart::read_double_vec(int n, double *vec) +{ + if (me == 0) fread(vec,sizeof(double),n,fp); + MPI_Bcast(vec,n,MPI_DOUBLE,0,world); } diff --git a/src/read_restart.h b/src/read_restart.h index d49189075c..b96516ab6d 100644 --- a/src/read_restart.h +++ b/src/read_restart.h @@ -31,24 +31,30 @@ class ReadRestart : protected Pointers { void command(int, char **); private: - int me,nprocs,nprocs_file; + int me,nprocs,nprocs_file,multiproc_file; FILE *fp; int nfix_restart_global,nfix_restart_peratom; - int swapflag; + + int mpiio; // 1 for MPIIO output, else 0 + int multiproc; // 0 = proc 0 writes for all + // else # of procs writing files void file_search(char *, char *); - void header(); + void header(int); void type_arrays(); void force_fields(); - void nread_int(int *, int, FILE *); - void nread_double(double *, int, FILE *); - void nread_char(char *, int, FILE *); + void magic_string(); + void endian(); + int version_numeric(); + void file_layout(); + int read_int(); - double read_double(); - char *read_char(); bigint read_bigint(); - int autodetect(FILE **, char *); + double read_double(); + char *read_string(); + void read_int_vec(int, int *); + void read_double_vec(int, double *); }; } diff --git a/src/write_restart.cpp b/src/write_restart.cpp index 19e430e6f9..78821e377c 100644 --- a/src/write_restart.cpp +++ b/src/write_restart.cpp @@ -39,23 +39,26 @@ using namespace LAMMPS_NS; -// same as read_restart.cpp and tools/restart2data.cpp +// same as read_restart.cpp + +#define MAGIC_STRING "LammpS RestartT" +#define ENDIAN 0x0001 +#define ENDIANSWAP 0x1000 +#define VERSION_NUMERIC 0 enum{VERSION,SMALLINT,TAGINT,BIGINT, - UNITS,NTIMESTEP,DIMENSION,NPROCS,PROCGRID_0,PROCGRID_1,PROCGRID_2, - NEWTON_PAIR,NEWTON_BOND,XPERIODIC,YPERIODIC,ZPERIODIC, - BOUNDARY_00,BOUNDARY_01,BOUNDARY_10,BOUNDARY_11,BOUNDARY_20,BOUNDARY_21, - ATOM_STYLE,NATOMS,NTYPES, - NBONDS,NBONDTYPES,BOND_PER_ATOM, - NANGLES,NANGLETYPES,ANGLE_PER_ATOM, - NDIHEDRALS,NDIHEDRALTYPES,DIHEDRAL_PER_ATOM, - NIMPROPERS,NIMPROPERTYPES,IMPROPER_PER_ATOM, - BOXLO_0,BOXHI_0,BOXLO_1,BOXHI_1,BOXLO_2,BOXHI_2, - SPECIAL_LJ_1,SPECIAL_LJ_2,SPECIAL_LJ_3, - SPECIAL_COUL_1,SPECIAL_COUL_2,SPECIAL_COUL_3, - XY,XZ,YZ}; -enum{MASS}; -enum{PAIR,BOND,ANGLE,DIHEDRAL,IMPROPER}; + UNITS,NTIMESTEP,DIMENSION,NPROCS,PROCGRID, + NEWTON_PAIR,NEWTON_BOND, + XPERIODIC,YPERIODIC,ZPERIODIC,BOUNDARY, + ATOM_STYLE,NATOMS,NTYPES, + NBONDS,NBONDTYPES,BOND_PER_ATOM, + NANGLES,NANGLETYPES,ANGLE_PER_ATOM, + NDIHEDRALS,NDIHEDRALTYPES,DIHEDRAL_PER_ATOM, + NIMPROPERS,NIMPROPERTYPES,IMPROPER_PER_ATOM, + TRICLINIC,BOXLO,BOXHI,XY,XZ,YZ, + SPECIAL_LJ,SPECIAL_COUL, + MASS,PAIR,BOND,ANGLE,DIHEDRAL,IMPROPER, + MULTIPROC,MPIIO,PROCSPERFILE,PERPROC}; enum{IGNORE,WARN,ERROR}; // same as thermo.cpp @@ -65,6 +68,7 @@ WriteRestart::WriteRestart(LAMMPS *lmp) : Pointers(lmp) { MPI_Comm_rank(world,&me); MPI_Comm_size(world,&nprocs); + multiproc = 0; } /* ---------------------------------------------------------------------- @@ -75,7 +79,7 @@ void WriteRestart::command(int narg, char **arg) { if (domain->box_exist == 0) error->all(FLERR,"Write_restart command before simulation box is defined"); - if (narg != 1) error->all(FLERR,"Illegal write_restart command"); + if (narg < 1) error->all(FLERR,"Illegal write_restart command"); // if filename contains a "*", replace with current timestep @@ -88,6 +92,21 @@ void WriteRestart::command(int narg, char **arg) sprintf(file,"%s" BIGINT_FORMAT "%s",arg[0],update->ntimestep,ptr+1); } else strcpy(file,arg[0]); + // check for multiproc output and an MPI-IO filename + + if (strchr(arg[0],'%')) multiproc = nprocs; + else multiproc = 0; + if (strstr(arg[0],".mpi")) mpiio = 1; + else mpiio = 0; + + if (multiproc && mpiio) + error->all(FLERR, + "Write restart MPI-IO output not allowed with '%' in filename"); + + // setup output style and process optional args + // also called by Output class for periodic restart files + + multiproc_options(multiproc,mpiio,narg-1,&arg[1]); // init entire system since comm->exchange is done // comm::init needs neighbor::init needs pair::init needs kspace::init, etc @@ -114,6 +133,78 @@ void WriteRestart::command(int narg, char **arg) delete [] file; } +/* ---------------------------------------------------------------------- +------------------------------------------------------------------------- */ + +void WriteRestart::multiproc_options(int multiproc_caller, int mpiio_caller, + int narg, char **arg) +{ + multiproc = multiproc_caller; + mpiio = mpiio_caller; + + // defaults for multiproc file writing + + nclusterprocs = nprocs; + filewriter = 0; + if (me == 0) filewriter = 1; + fileproc = 0; + + if (multiproc) { + nclusterprocs = 1; + filewriter = 1; + fileproc = me; + icluster = me; + } + + // optional args + + int iarg = 0; + while (iarg < narg) { + if (strcmp(arg[iarg],"fileper") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal write_restart command"); + if (!multiproc) + error->all(FLERR,"Cannot use write_restart fileper " + "without % in restart file name"); + int nper = force->inumeric(FLERR,arg[iarg+1]); + if (nper <= 0) error->all(FLERR,"Illegal write_restart command"); + + multiproc = nprocs/nper; + if (nprocs % nper) multiproc++; + fileproc = me/nper * nper; + int fileprocnext = MIN(fileproc+nper,nprocs); + nclusterprocs = fileprocnext - fileproc; + if (me == fileproc) filewriter = 1; + else filewriter = 0; + icluster = fileproc/nper; + iarg += 2; + + } else if (strcmp(arg[iarg],"nfile") == 0) { + if (iarg+2 > narg) error->all(FLERR,"Illegal write_restart command"); + if (!multiproc) + error->all(FLERR,"Cannot use write_restart nfile " + "without % in restart file name"); + int nfile = force->inumeric(FLERR,arg[iarg+1]); + if (nfile <= 0) error->all(FLERR,"Illegal write_restart command"); + nfile = MIN(nfile,nprocs); + + multiproc = nfile; + icluster = static_cast ((bigint) me * nfile/nprocs); + fileproc = static_cast ((bigint) icluster * nprocs/nfile); + int fcluster = static_cast ((bigint) fileproc * nfile/nprocs); + if (fcluster < icluster) fileproc++; + int fileprocnext = + static_cast ((bigint) (icluster+1) * nprocs/nfile); + fcluster = static_cast ((bigint) fileprocnext * nfile/nprocs); + if (fcluster < icluster+1) fileprocnext++; + nclusterprocs = fileprocnext - fileproc; + if (me == fileproc) filewriter = 1; + else filewriter = 0; + iarg += 2; + + } else error->all(FLERR,"Illegal write_restart command"); + } +} + /* ---------------------------------------------------------------------- called from command() and directly from output within run/minimize loop file = final file name to write, except may contain a "%" @@ -138,12 +229,6 @@ void WriteRestart::write(char *file) if (natoms != atom->natoms && output->thermo->lostflag == ERROR) error->all(FLERR,"Atom count is inconsistent, cannot write restart file"); - // check if filename contains "%" - - int multiproc; - if (strchr(file,'%')) multiproc = 1; - else multiproc = 0; - // open single restart file or base file for multiproc case if (me == 0) { @@ -164,8 +249,15 @@ void WriteRestart::write(char *file) if (multiproc) delete [] hfile; } - // proc 0 writes header, groups, ntype-length arrays, force field - // all procs write fix info + // proc 0 writes magic string, endian flag, numeric version + + if (me == 0) { + magic_string(); + endian(); + version_numeric(); + } + + // proc 0 writes header, groups, pertype info, force field info if (me == 0) { header(); @@ -174,9 +266,11 @@ void WriteRestart::write(char *file) force_fields(); } + // all procs write fix info + modify->write_restart(fp); - // communication buffer for all my atom's info + // communication buffer for my atom info // max_size = largest buffer needed by any proc int max_size; @@ -184,8 +278,35 @@ void WriteRestart::write(char *file) MPI_Allreduce(&send_size,&max_size,1,MPI_INT,MPI_MAX,world); double *buf; - if (me == 0) memory->create(buf,max_size,"write_restart:buf"); - else memory->create(buf,send_size,"write_restart:buf"); + memory->create(buf,max_size,"write_restart:buf"); + + // all procs write file layout info which may include per-proc sizes + + file_layout(send_size); + + // header info is complete + // if multiproc output: + // close header file, open multiname file on each writing proc + + if (multiproc) { + if (me == 0) fclose(fp); + + char *multiname = new char[strlen(file) + 16]; + char *ptr = strchr(file,'%'); + *ptr = '\0'; + sprintf(multiname,"%s%d%s",file,icluster,ptr+1); + + if (filewriter) { + fp = fopen(multiname,"wb"); + if (fp == NULL) { + char str[128]; + sprintf(str,"Cannot open restart file %s",multiname); + error->one(FLERR,str); + } + } + + delete [] multiname; + } // pack my atom data into buf @@ -242,55 +363,31 @@ void WriteRestart::write(char *file) } } - // if single file: - // write one chunk of atoms per proc to file - // proc 0 pings each proc, receives its chunk, writes to file - // all other procs wait for ping, send their chunk to proc 0 - // else if one file per proc: - // each proc opens its own file and writes its chunk directly + // filewriter = 1 = this proc writes to file + // ping each proc in my cluster, receive its data, write data to file + // else wait for ping from fileproc, send my data to fileproc - if (multiproc == 0) { - int tmp,recv_size; - MPI_Status status; - MPI_Request request; + int tmp,recv_size; + MPI_Status status; + MPI_Request request; - if (me == 0) { - for (int iproc = 0; iproc < nprocs; iproc++) { - if (iproc) { - MPI_Irecv(buf,max_size,MPI_DOUBLE,iproc,0,world,&request); - MPI_Send(&tmp,0,MPI_INT,iproc,0,world); - MPI_Wait(&request,&status); - MPI_Get_count(&status,MPI_DOUBLE,&recv_size); - } else recv_size = send_size; + if (filewriter) { + write_int(PROCSPERFILE,nclusterprocs); + for (int iproc = 0; iproc < nclusterprocs; iproc++) { + if (iproc) { + MPI_Irecv(buf,max_size,MPI_DOUBLE,me+iproc,0,world,&request); + MPI_Send(&tmp,0,MPI_INT,me+iproc,0,world); + MPI_Wait(&request,&status); + MPI_Get_count(&status,MPI_DOUBLE,&recv_size); + } else recv_size = send_size; - fwrite(&recv_size,sizeof(int),1,fp); - fwrite(buf,sizeof(double),recv_size,fp); - } - fclose(fp); - - } else { - MPI_Recv(&tmp,0,MPI_INT,0,0,world,&status); - MPI_Rsend(buf,send_size,MPI_DOUBLE,0,0,world); + write_double_vec(PERPROC,recv_size,buf); } + fclose(fp); } else { - if (me == 0) fclose(fp); - - char *perproc = new char[strlen(file) + 16]; - char *ptr = strchr(file,'%'); - *ptr = '\0'; - sprintf(perproc,"%s%d%s",file,me,ptr+1); - *ptr = '%'; - fp = fopen(perproc,"wb"); - if (fp == NULL) { - char str[128]; - sprintf(str,"Cannot open restart file %s",perproc); - error->one(FLERR,str); - } - delete [] perproc; - fwrite(&send_size,sizeof(int),1,fp); - fwrite(buf,sizeof(double),send_size,fp); - fclose(fp); + MPI_Recv(&tmp,0,MPI_INT,fileproc,0,world,&status); + MPI_Rsend(buf,send_size,MPI_DOUBLE,fileproc,0,world); } memory->destroy(buf); @@ -308,35 +405,28 @@ void WriteRestart::write(char *file) void WriteRestart::header() { - write_char(VERSION,universe->version); + write_string(VERSION,universe->version); write_int(SMALLINT,sizeof(smallint)); write_int(TAGINT,sizeof(tagint)); write_int(BIGINT,sizeof(bigint)); - write_char(UNITS,update->unit_style); + write_string(UNITS,update->unit_style); write_bigint(NTIMESTEP,update->ntimestep); write_int(DIMENSION,domain->dimension); write_int(NPROCS,nprocs); - write_int(PROCGRID_0,comm->procgrid[0]); - write_int(PROCGRID_1,comm->procgrid[1]); - write_int(PROCGRID_2,comm->procgrid[2]); + write_int_vec(PROCGRID,3,comm->procgrid); write_int(NEWTON_PAIR,force->newton_pair); write_int(NEWTON_BOND,force->newton_bond); write_int(XPERIODIC,domain->xperiodic); write_int(YPERIODIC,domain->yperiodic); write_int(ZPERIODIC,domain->zperiodic); - write_int(BOUNDARY_00,domain->boundary[0][0]); - write_int(BOUNDARY_01,domain->boundary[0][1]); - write_int(BOUNDARY_10,domain->boundary[1][0]); - write_int(BOUNDARY_11,domain->boundary[1][1]); - write_int(BOUNDARY_20,domain->boundary[2][0]); - write_int(BOUNDARY_21,domain->boundary[2][1]); + write_int_vec(BOUNDARY,6,&domain->boundary[0][0]); // atom_style must be written before atom class values // so read_restart can create class before reading class values // if style = hybrid, also write sub-class styles // avec->write_restart() writes atom_style specific info - write_char(ATOM_STYLE,atom->atom_style); + write_string(ATOM_STYLE,atom->atom_style); if (strcmp(atom->atom_style,"hybrid") == 0) { AtomVecHybrid *avec_hybrid = (AtomVecHybrid *) atom->avec; @@ -349,8 +439,7 @@ void WriteRestart::header() fwrite(keywords[i],sizeof(char),n,fp); } } - - if (me == 0) atom->avec->write_restart_settings(fp); + atom->avec->write_restart_settings(fp); write_bigint(NATOMS,natoms); write_int(NTYPES,atom->ntypes); @@ -367,25 +456,15 @@ void WriteRestart::header() write_int(NIMPROPERTYPES,atom->nimpropertypes); write_int(IMPROPER_PER_ATOM,atom->improper_per_atom); - write_double(BOXLO_0,domain->boxlo[0]); - write_double(BOXHI_0,domain->boxhi[0]); - write_double(BOXLO_1,domain->boxlo[1]); - write_double(BOXHI_1,domain->boxhi[1]); - write_double(BOXLO_2,domain->boxlo[2]); - write_double(BOXHI_2,domain->boxhi[2]); + write_int(TRICLINIC,domain->triclinic); + write_double_vec(BOXLO,3,domain->boxlo); + write_double_vec(BOXHI,3,domain->boxhi); + write_double(XY,domain->xy); + write_double(XZ,domain->xz); + write_double(YZ,domain->yz); - write_double(SPECIAL_LJ_1,force->special_lj[1]); - write_double(SPECIAL_LJ_2,force->special_lj[2]); - write_double(SPECIAL_LJ_3,force->special_lj[3]); - write_double(SPECIAL_COUL_1,force->special_coul[1]); - write_double(SPECIAL_COUL_2,force->special_coul[2]); - write_double(SPECIAL_COUL_3,force->special_coul[3]); - - if (domain->triclinic) { - write_double(XY,domain->xy); - write_double(XZ,domain->xz); - write_double(YZ,domain->yz); - } + write_double_vec(SPECIAL_LJ,3,&force->special_lj[1]); + write_double_vec(SPECIAL_COUL,3,&force->special_coul[1]); // -1 flag signals end of header @@ -399,11 +478,7 @@ void WriteRestart::header() void WriteRestart::type_arrays() { - if (atom->mass) { - int flag = MASS; - fwrite(&flag,sizeof(int),1,fp); - fwrite(&atom->mass[1],sizeof(double),atom->ntypes,fp); - } + if (atom->mass) write_double_vec(MASS,atom->ntypes,&atom->mass[1]); // -1 flag signals end of type arrays @@ -417,44 +492,24 @@ void WriteRestart::type_arrays() void WriteRestart::force_fields() { - if (force->pair) { - int flag = PAIR; - fwrite(&flag,sizeof(int),1,fp); - int n = strlen(force->pair_style) + 1; - fwrite(&n,sizeof(int),1,fp); - fwrite(force->pair_style,sizeof(char),n,fp); + if (force->pair && force->pair->restartinfo) { + write_string(PAIR,force->pair_style); force->pair->write_restart(fp); } if (atom->avec->bonds_allow && force->bond) { - int flag = BOND; - fwrite(&flag,sizeof(int),1,fp); - int n = strlen(force->bond_style) + 1; - fwrite(&n,sizeof(int),1,fp); - fwrite(force->bond_style,sizeof(char),n,fp); + write_string(BOND,force->bond_style); force->bond->write_restart(fp); } if (atom->avec->angles_allow && force->angle) { - int flag = ANGLE; - fwrite(&flag,sizeof(int),1,fp); - int n = strlen(force->angle_style) + 1; - fwrite(&n,sizeof(int),1,fp); - fwrite(force->angle_style,sizeof(char),n,fp); + write_string(ANGLE,force->angle_style); force->angle->write_restart(fp); } if (atom->avec->dihedrals_allow && force->dihedral) { - int flag = DIHEDRAL; - fwrite(&flag,sizeof(int),1,fp); - int n = strlen(force->dihedral_style) + 1; - fwrite(&n,sizeof(int),1,fp); - fwrite(force->dihedral_style,sizeof(char),n,fp); + write_string(DIHEDRAL,force->dihedral_style); force->dihedral->write_restart(fp); } if (atom->avec->impropers_allow && force->improper) { - int flag = IMPROPER; - fwrite(&flag,sizeof(int),1,fp); - int n = strlen(force->improper_style) + 1; - fwrite(&n,sizeof(int),1,fp); - fwrite(force->improper_style,sizeof(char),n,fp); + write_string(IMPROPER,force->improper_style); force->improper->write_restart(fp); } @@ -464,6 +519,62 @@ void WriteRestart::force_fields() fwrite(&flag,sizeof(int),1,fp); } +/* ---------------------------------------------------------------------- + proc 0 writes out file layout info + all procs call this method, only proc 0 writes to file +------------------------------------------------------------------------- */ + +void WriteRestart::file_layout(int send_size) +{ + if (me == 0) { + write_int(MULTIPROC,multiproc); + write_int(MPIIO,mpiio); + } + + // -1 flag signals end of file layout info + + if (me == 0) { + int flag = -1; + fwrite(&flag,sizeof(int),1,fp); + } +} + +// ---------------------------------------------------------------------- +// ---------------------------------------------------------------------- +// low-level fwrite methods +// ---------------------------------------------------------------------- +// ---------------------------------------------------------------------- + +/* ---------------------------------------------------------------------- +------------------------------------------------------------------------- */ + +void WriteRestart::magic_string() +{ + int n = strlen(MAGIC_STRING) + 1; + char *str = new char[n]; + strcpy(str,MAGIC_STRING); + fwrite(str,sizeof(char),n,fp); + delete [] str; +} + +/* ---------------------------------------------------------------------- +------------------------------------------------------------------------- */ + +void WriteRestart::endian() +{ + int endian = ENDIAN; + fwrite(&endian,sizeof(int),1,fp); +} + +/* ---------------------------------------------------------------------- +------------------------------------------------------------------------- */ + +void WriteRestart::version_numeric() +{ + int vn = VERSION_NUMERIC; + fwrite(&vn,sizeof(int),1,fp); +} + /* ---------------------------------------------------------------------- write a flag and an int into restart file ------------------------------------------------------------------------- */ @@ -474,6 +585,16 @@ void WriteRestart::write_int(int flag, int value) fwrite(&value,sizeof(int),1,fp); } +/* ---------------------------------------------------------------------- + write a flag and a bigint into restart file +------------------------------------------------------------------------- */ + +void WriteRestart::write_bigint(int flag, bigint value) +{ + fwrite(&flag,sizeof(int),1,fp); + fwrite(&value,sizeof(bigint),1,fp); +} + /* ---------------------------------------------------------------------- write a flag and a double into restart file ------------------------------------------------------------------------- */ @@ -485,23 +606,35 @@ void WriteRestart::write_double(int flag, double value) } /* ---------------------------------------------------------------------- - write a flag and a char str into restart file + write a flag and a char string (including NULL) into restart file ------------------------------------------------------------------------- */ -void WriteRestart::write_char(int flag, char *value) +void WriteRestart::write_string(int flag, char *value) { - fwrite(&flag,sizeof(int),1,fp); int n = strlen(value) + 1; + fwrite(&flag,sizeof(int),1,fp); fwrite(&n,sizeof(int),1,fp); fwrite(value,sizeof(char),n,fp); } /* ---------------------------------------------------------------------- - write a flag and a bigint into restart file + write a flag and vector of N ints into restart file ------------------------------------------------------------------------- */ -void WriteRestart::write_bigint(int flag, bigint value) +void WriteRestart::write_int_vec(int flag, int n, int *vec) { fwrite(&flag,sizeof(int),1,fp); - fwrite(&value,sizeof(bigint),1,fp); + fwrite(&n,sizeof(int),1,fp); + fwrite(vec,sizeof(int),n,fp); +} + +/* ---------------------------------------------------------------------- + write a flag and vector of N doubles into restart file +------------------------------------------------------------------------- */ + +void WriteRestart::write_double_vec(int flag, int n, double *vec) +{ + fwrite(&flag,sizeof(int),1,fp); + fwrite(&n,sizeof(int),1,fp); + fwrite(vec,sizeof(double),n,fp); } diff --git a/src/write_restart.h b/src/write_restart.h index 812c756283..d658f1d722 100644 --- a/src/write_restart.h +++ b/src/write_restart.h @@ -29,6 +29,7 @@ class WriteRestart : protected Pointers { public: WriteRestart(class LAMMPS *); void command(int, char **); + void multiproc_options(int, int, int, char **); void write(char *); private: @@ -36,14 +37,29 @@ class WriteRestart : protected Pointers { FILE *fp; bigint natoms; // natoms (sum of nlocal) to write into file + int mpiio; // 1 for MPIIO output, else 0 + int multiproc; // 0 = proc 0 writes for all + // else # of procs writing files + int nclusterprocs; // # of procs in my cluster that write to one file + int filewriter; // 1 if this proc writes a file, else 0 + int fileproc; // ID of proc in my cluster who writes to file + int icluster; // which cluster I am in + void header(); void type_arrays(); void force_fields(); + void file_layout(int); + + void magic_string(); + void endian(); + void version_numeric(); void write_int(int, int); - void write_double(int, double); - void write_char(int, char *); void write_bigint(int, bigint); + void write_double(int, double); + void write_string(int, char *); + void write_int_vec(int, int, int *); + void write_double_vec(int, int, double *); }; }