1 // clang-format off
2 /* ----------------------------------------------------------------------
3 LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
4 https://www.lammps.org/, Sandia National Laboratories
5 Steve Plimpton, sjplimp@sandia.gov
6
7 Copyright (2003) Sandia Corporation. Under the terms of Contract
8 DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
9 certain rights in this software. This software is distributed under
10 the GNU General Public License.
11
12 See the README file in the top-level LAMMPS directory.
13 ------------------------------------------------------------------------- */
14
15 #include "write_restart.h"
16
17 #include "angle.h"
18 #include "atom.h"
19 #include "atom_vec.h"
20 #include "bond.h"
21 #include "comm.h"
22 #include "dihedral.h"
23 #include "domain.h"
24 #include "error.h"
25 #include "fix.h"
26 #include "force.h"
27 #include "group.h"
28 #include "improper.h"
29 #include "memory.h"
30 #include "modify.h"
31 #include "mpiio.h"
32 #include "neighbor.h"
33 #include "output.h"
34 #include "pair.h"
35 #include "thermo.h"
36 #include "update.h"
37
38 #include <cstring>
39
40 #include "lmprestart.h"
41
42 using namespace LAMMPS_NS;
43
44 /* ---------------------------------------------------------------------- */
45
WriteRestart(LAMMPS * lmp)46 WriteRestart::WriteRestart(LAMMPS *lmp) : Command(lmp)
47 {
48 MPI_Comm_rank(world,&me);
49 MPI_Comm_size(world,&nprocs);
50 multiproc = 0;
51 noinit = 0;
52 fp = nullptr;
53 }
54
55 /* ----------------------------------------------------------------------
56 called as write_restart command in input script
57 ------------------------------------------------------------------------- */
58
command(int narg,char ** arg)59 void WriteRestart::command(int narg, char **arg)
60 {
61 if (domain->box_exist == 0)
62 error->all(FLERR,"Write_restart command before simulation box is defined");
63 if (narg < 1) error->all(FLERR,"Illegal write_restart command");
64
65 // if filename contains a "*", replace with current timestep
66
67 std::string file = arg[0];
68 std::size_t found = file.find('*');
69 if (found != std::string::npos)
70 file.replace(found,1,fmt::format("{}",update->ntimestep));
71
72 // check for multiproc output and an MPI-IO filename
73
74 if (strchr(arg[0],'%')) multiproc = nprocs;
75 else multiproc = 0;
76 if (strstr(arg[0],".mpiio")) mpiioflag = 1;
77 else mpiioflag = 0;
78
79 // setup output style and process optional args
80 // also called by Output class for periodic restart files
81
82 multiproc_options(multiproc,mpiioflag,narg-1,&arg[1]);
83
84 // init entire system since comm->exchange is done
85 // comm::init needs neighbor::init needs pair::init needs kspace::init, etc
86
87 if (noinit == 0) {
88 if (comm->me == 0) utils::logmesg(lmp,"System init for write_restart ...\n");
89 lmp->init();
90
91 // move atoms to new processors before writing file
92 // enforce PBC in case atoms are outside box
93 // call borders() to rebuild atom map since exchange() destroys map
94 // NOTE: removed call to setup_pre_exchange
95 // used to be needed by fixShearHistory for granular
96 // to move history info from neigh list to atoms between runs
97 // but now that is done via FIx::post_run()
98 // don't think any other fix needs this or should do it
99 // e.g. fix evaporate should not delete more atoms
100
101 // modify->setup_pre_exchange();
102 if (domain->triclinic) domain->x2lamda(atom->nlocal);
103 domain->pbc();
104 domain->reset_box();
105 comm->setup();
106 comm->exchange();
107 comm->borders();
108 if (domain->triclinic) domain->lamda2x(atom->nlocal+atom->nghost);
109 }
110
111 // write single restart file
112
113 write(file);
114 }
115
116 /* ---------------------------------------------------------------------- */
117
multiproc_options(int multiproc_caller,int mpiioflag_caller,int narg,char ** arg)118 void WriteRestart::multiproc_options(int multiproc_caller, int mpiioflag_caller,
119 int narg, char **arg)
120 {
121 multiproc = multiproc_caller;
122 mpiioflag = mpiioflag_caller;
123
124 // error checks
125
126 if (multiproc && mpiioflag)
127 error->all(FLERR,
128 "Restart file MPI-IO output not allowed with % in filename");
129
130 if (mpiioflag) {
131 mpiio = new RestartMPIIO(lmp);
132 if (!mpiio->mpiio_exists)
133 error->all(FLERR,"Writing to MPI-IO filename when "
134 "MPIIO package is not installed");
135 }
136
137 // defaults for multiproc file writing
138
139 nclusterprocs = nprocs;
140 filewriter = 0;
141 if (me == 0) filewriter = 1;
142 fileproc = 0;
143
144 if (multiproc) {
145 nclusterprocs = 1;
146 filewriter = 1;
147 fileproc = me;
148 icluster = me;
149 }
150
151 // optional args
152
153 int iarg = 0;
154 while (iarg < narg) {
155 if (strcmp(arg[iarg],"fileper") == 0) {
156 if (iarg+2 > narg) error->all(FLERR,"Illegal write_restart command");
157 if (!multiproc)
158 error->all(FLERR,"Cannot use write_restart fileper "
159 "without % in restart file name");
160 int nper = utils::inumeric(FLERR,arg[iarg+1],false,lmp);
161 if (nper <= 0) error->all(FLERR,"Illegal write_restart command");
162
163 multiproc = nprocs/nper;
164 if (nprocs % nper) multiproc++;
165 fileproc = me/nper * nper;
166 int fileprocnext = MIN(fileproc+nper,nprocs);
167 nclusterprocs = fileprocnext - fileproc;
168 if (me == fileproc) filewriter = 1;
169 else filewriter = 0;
170 icluster = fileproc/nper;
171 iarg += 2;
172
173 } else if (strcmp(arg[iarg],"nfile") == 0) {
174 if (iarg+2 > narg) error->all(FLERR,"Illegal write_restart command");
175 if (!multiproc)
176 error->all(FLERR,"Cannot use write_restart nfile "
177 "without % in restart file name");
178 int nfile = utils::inumeric(FLERR,arg[iarg+1],false,lmp);
179 if (nfile <= 0) error->all(FLERR,"Illegal write_restart command");
180 nfile = MIN(nfile,nprocs);
181
182 multiproc = nfile;
183 icluster = static_cast<int> ((bigint) me * nfile/nprocs);
184 fileproc = static_cast<int> ((bigint) icluster * nprocs/nfile);
185 int fcluster = static_cast<int> ((bigint) fileproc * nfile/nprocs);
186 if (fcluster < icluster) fileproc++;
187 int fileprocnext =
188 static_cast<int> ((bigint) (icluster+1) * nprocs/nfile);
189 fcluster = static_cast<int> ((bigint) fileprocnext * nfile/nprocs);
190 if (fcluster < icluster+1) fileprocnext++;
191 nclusterprocs = fileprocnext - fileproc;
192 if (me == fileproc) filewriter = 1;
193 else filewriter = 0;
194 iarg += 2;
195
196 } else if (strcmp(arg[iarg],"noinit") == 0) {
197 noinit = 1;
198 iarg++;
199 } else error->all(FLERR,"Illegal write_restart command");
200 }
201 }
202
203 /* ----------------------------------------------------------------------
204 called from command() and directly from output within run/minimize loop
205 file = final file name to write, except may contain a "%"
206 ------------------------------------------------------------------------- */
207
write(const std::string & file)208 void WriteRestart::write(const std::string &file)
209 {
210 // special case where reneighboring is not done in integrator
211 // on timestep restart file is written (due to build_once being set)
212 // if box is changing, must be reset, else restart file will have
213 // wrong box size and atoms will be lost when restart file is read
214 // other calls to pbc and domain and comm are not made,
215 // b/c they only make sense if reneighboring is actually performed
216
217 if (neighbor->build_once) domain->reset_box();
218
219 // natoms = sum of nlocal = value to write into restart file
220 // if unequal and thermo lostflag is "error", don't write restart file
221
222 bigint nblocal = atom->nlocal;
223 MPI_Allreduce(&nblocal,&natoms,1,MPI_LMP_BIGINT,MPI_SUM,world);
224 if (natoms != atom->natoms && output->thermo->lostflag == Thermo::ERROR)
225 error->all(FLERR,"Atom count is inconsistent, cannot write restart file");
226
227 // open single restart file or base file for multiproc case
228
229 if (me == 0) {
230 std::string base = file;
231 if (multiproc) base.replace(base.find('%'),1,"base");
232
233 fp = fopen(base.c_str(),"wb");
234 if (fp == nullptr)
235 error->one(FLERR, "Cannot open restart file {}: {}",
236 base, utils::getsyserror());
237 }
238
239 // proc 0 writes magic string, endian flag, numeric version
240
241 if (me == 0) {
242 magic_string();
243 endian();
244 version_numeric();
245 }
246
247 // proc 0 writes header, groups, pertype info, force field info
248
249 if (me == 0) {
250 header();
251 group->write_restart(fp);
252 type_arrays();
253 force_fields();
254 }
255
256 // all procs write fix info
257
258 modify->write_restart(fp);
259
260 // communication buffer for my atom info
261 // max_size = largest buffer needed by any proc
262 // NOTE: are assuming size_restart() returns 32-bit int
263 // for a huge one-proc problem, nlocal could be 32-bit
264 // but nlocal * doubles-peratom could overflow
265
266 int max_size;
267 int send_size = atom->avec->size_restart();
268 MPI_Allreduce(&send_size,&max_size,1,MPI_INT,MPI_MAX,world);
269
270 double *buf;
271 memory->create(buf,max_size,"write_restart:buf");
272 memset(buf,0,max_size*sizeof(buf));
273
274 // all procs write file layout info which may include per-proc sizes
275
276 file_layout(send_size);
277
278 // header info is complete
279 // if multiproc output:
280 // close header file, open multiname file on each writing proc,
281 // write PROCSPERFILE into new file
282
283 int io_error = 0;
284 if (multiproc) {
285 if (me == 0 && fp) {
286 magic_string();
287 if (ferror(fp)) io_error = 1;
288 fclose(fp);
289 fp = nullptr;
290 }
291
292 std::string multiname = file;
293 multiname.replace(multiname.find('%'),1,fmt::format("{}",icluster));
294
295 if (filewriter) {
296 fp = fopen(multiname.c_str(),"wb");
297 if (fp == nullptr)
298 error->one(FLERR, "Cannot open restart file {}: {}",
299 multiname, utils::getsyserror());
300 write_int(PROCSPERFILE,nclusterprocs);
301 }
302 }
303
304 // pack my atom data into buf
305
306 AtomVec *avec = atom->avec;
307 int n = 0;
308 for (int i = 0; i < atom->nlocal; i++) n += avec->pack_restart(i,&buf[n]);
309
310 // if any fix requires it, remap each atom's coords via PBC
311 // is because fix changes atom coords (excepting an integrate fix)
312 // just remap in buffer, not actual atoms
313
314 if (modify->restart_pbc_any) {
315 int triclinic = domain->triclinic;
316 double *lo,*hi,*period;
317
318 if (triclinic == 0) {
319 lo = domain->boxlo;
320 hi = domain->boxhi;
321 period = domain->prd;
322 } else {
323 lo = domain->boxlo_lamda;
324 hi = domain->boxhi_lamda;
325 period = domain->prd_lamda;
326 }
327
328 int xperiodic = domain->xperiodic;
329 int yperiodic = domain->yperiodic;
330 int zperiodic = domain->zperiodic;
331
332 double *x;
333 int m = 0;
334 for (int i = 0; i < atom->nlocal; i++) {
335 x = &buf[m+1];
336 if (triclinic) domain->x2lamda(x,x);
337
338 if (xperiodic) {
339 if (x[0] < lo[0]) x[0] += period[0];
340 if (x[0] >= hi[0]) x[0] -= period[0];
341 x[0] = MAX(x[0],lo[0]);
342 }
343 if (yperiodic) {
344 if (x[1] < lo[1]) x[1] += period[1];
345 if (x[1] >= hi[1]) x[1] -= period[1];
346 x[1] = MAX(x[1],lo[1]);
347 }
348 if (zperiodic) {
349 if (x[2] < lo[2]) x[2] += period[2];
350 if (x[2] >= hi[2]) x[2] -= period[2];
351 x[2] = MAX(x[2],lo[2]);
352 }
353
354 if (triclinic) domain->lamda2x(x,x);
355 m += static_cast<int> (buf[m]);
356 }
357 }
358
359 // MPI-IO output to single file
360
361 if (mpiioflag) {
362 if (me == 0 && fp) {
363 magic_string();
364 if (ferror(fp)) io_error = 1;
365 fclose(fp);
366 fp = nullptr;
367 }
368 mpiio->openForWrite(file.c_str());
369 mpiio->write(headerOffset,send_size,buf);
370 mpiio->close();
371 } else {
372
373 // output of one or more native files
374 // filewriter = 1 = this proc writes to file
375 // ping each proc in my cluster, receive its data, write data to file
376 // else wait for ping from fileproc, send my data to fileproc
377
378 int tmp,recv_size;
379
380 if (filewriter) {
381 MPI_Status status;
382 MPI_Request request;
383 for (int iproc = 0; iproc < nclusterprocs; iproc++) {
384 if (iproc) {
385 MPI_Irecv(buf,max_size,MPI_DOUBLE,me+iproc,0,world,&request);
386 MPI_Send(&tmp,0,MPI_INT,me+iproc,0,world);
387 MPI_Wait(&request,&status);
388 MPI_Get_count(&status,MPI_DOUBLE,&recv_size);
389 } else recv_size = send_size;
390
391 write_double_vec(PERPROC,recv_size,buf);
392 }
393 magic_string();
394 if (ferror(fp)) io_error = 1;
395 fclose(fp);
396 fp = nullptr;
397
398 } else {
399 MPI_Recv(&tmp,0,MPI_INT,fileproc,0,world,MPI_STATUS_IGNORE);
400 MPI_Rsend(buf,send_size,MPI_DOUBLE,fileproc,0,world);
401 }
402 }
403
404 // Check for I/O error status
405
406 int io_all = 0;
407 MPI_Allreduce(&io_error,&io_all,1,MPI_INT,MPI_MAX,world);
408 if (io_all) error->all(FLERR,"I/O error while writing restart");
409
410 // clean up
411
412 memory->destroy(buf);
413
414 // invoke any fixes that write their own restart file
415
416 for (int ifix = 0; ifix < modify->nfix; ifix++)
417 if (modify->fix[ifix]->restart_file)
418 modify->fix[ifix]->write_restart_file(file.c_str());
419 }
420
421 /* ----------------------------------------------------------------------
422 proc 0 writes out problem description
423 ------------------------------------------------------------------------- */
424
header()425 void WriteRestart::header()
426 {
427 write_string(VERSION,lmp->version);
428 write_int(SMALLINT,sizeof(smallint));
429 write_int(IMAGEINT,sizeof(imageint));
430 write_int(TAGINT,sizeof(tagint));
431 write_int(BIGINT,sizeof(bigint));
432 write_string(UNITS,update->unit_style);
433 write_bigint(NTIMESTEP,update->ntimestep);
434 write_int(DIMENSION,domain->dimension);
435 write_int(NPROCS,nprocs);
436 write_int_vec(PROCGRID,3,comm->procgrid);
437 write_int(NEWTON_PAIR,force->newton_pair);
438 write_int(NEWTON_BOND,force->newton_bond);
439 write_int(XPERIODIC,domain->xperiodic);
440 write_int(YPERIODIC,domain->yperiodic);
441 write_int(ZPERIODIC,domain->zperiodic);
442 write_int_vec(BOUNDARY,6,&domain->boundary[0][0]);
443
444 // added field for shrink-wrap boundaries with minimum - 2 Jul 2015
445
446 double minbound[6];
447 minbound[0] = domain->minxlo; minbound[1] = domain->minxhi;
448 minbound[2] = domain->minylo; minbound[3] = domain->minyhi;
449 minbound[4] = domain->minzlo; minbound[5] = domain->minzhi;
450 write_double_vec(BOUNDMIN,6,minbound);
451
452 // write atom_style and its args
453
454 write_string(ATOM_STYLE,atom->atom_style);
455 fwrite(&atom->avec->nargcopy,sizeof(int),1,fp);
456 for (int i = 0; i < atom->avec->nargcopy; i++) {
457 int n = strlen(atom->avec->argcopy[i]) + 1;
458 fwrite(&n,sizeof(int),1,fp);
459 fwrite(atom->avec->argcopy[i],sizeof(char),n,fp);
460 }
461
462 write_bigint(NATOMS,natoms);
463 write_int(NTYPES,atom->ntypes);
464 write_bigint(NBONDS,atom->nbonds);
465 write_int(NBONDTYPES,atom->nbondtypes);
466 write_int(BOND_PER_ATOM,atom->bond_per_atom);
467 write_bigint(NANGLES,atom->nangles);
468 write_int(NANGLETYPES,atom->nangletypes);
469 write_int(ANGLE_PER_ATOM,atom->angle_per_atom);
470 write_bigint(NDIHEDRALS,atom->ndihedrals);
471 write_int(NDIHEDRALTYPES,atom->ndihedraltypes);
472 write_int(DIHEDRAL_PER_ATOM,atom->dihedral_per_atom);
473 write_bigint(NIMPROPERS,atom->nimpropers);
474 write_int(NIMPROPERTYPES,atom->nimpropertypes);
475 write_int(IMPROPER_PER_ATOM,atom->improper_per_atom);
476
477 write_int(TRICLINIC,domain->triclinic);
478 write_double_vec(BOXLO,3,domain->boxlo);
479 write_double_vec(BOXHI,3,domain->boxhi);
480 write_double(XY,domain->xy);
481 write_double(XZ,domain->xz);
482 write_double(YZ,domain->yz);
483
484 write_double_vec(SPECIAL_LJ,3,&force->special_lj[1]);
485 write_double_vec(SPECIAL_COUL,3,&force->special_coul[1]);
486
487 write_double(TIMESTEP,update->dt);
488
489 write_int(ATOM_ID,atom->tag_enable);
490 write_int(ATOM_MAP_STYLE,atom->map_style);
491 write_int(ATOM_MAP_USER,atom->map_user);
492 write_int(ATOM_SORTFREQ,atom->sortfreq);
493 write_double(ATOM_SORTBIN,atom->userbinsize);
494
495 write_int(COMM_MODE,comm->mode);
496 write_double(COMM_CUTOFF,comm->cutghostuser);
497 write_int(COMM_VEL,comm->ghost_velocity);
498
499 write_int(EXTRA_BOND_PER_ATOM,atom->extra_bond_per_atom);
500 write_int(EXTRA_ANGLE_PER_ATOM,atom->extra_angle_per_atom);
501 write_int(EXTRA_DIHEDRAL_PER_ATOM,atom->extra_dihedral_per_atom);
502 write_int(EXTRA_IMPROPER_PER_ATOM,atom->extra_improper_per_atom);
503 write_int(ATOM_MAXSPECIAL,atom->maxspecial);
504
505 write_bigint(NELLIPSOIDS,atom->nellipsoids);
506 write_bigint(NLINES,atom->nlines);
507 write_bigint(NTRIS,atom->ntris);
508 write_bigint(NBODIES,atom->nbodies);
509
510 // -1 flag signals end of header
511
512 int flag = -1;
513 fwrite(&flag,sizeof(int),1,fp);
514 }
515
516 /* ----------------------------------------------------------------------
517 proc 0 writes out any type-based arrays that are defined
518 ------------------------------------------------------------------------- */
519
type_arrays()520 void WriteRestart::type_arrays()
521 {
522 if (atom->mass) write_double_vec(MASS,atom->ntypes,&atom->mass[1]);
523
524 // -1 flag signals end of type arrays
525
526 int flag = -1;
527 fwrite(&flag,sizeof(int),1,fp);
528 }
529
530 /* ----------------------------------------------------------------------
531 proc 0 writes out and force field styles and data that are defined
532 ------------------------------------------------------------------------- */
533
force_fields()534 void WriteRestart::force_fields()
535 {
536 if (force->pair) {
537 if (force->pair->restartinfo) {
538 write_string(PAIR,force->pair_style);
539 force->pair->write_restart(fp);
540 } else {
541 write_string(NO_PAIR,force->pair_style);
542 }
543 }
544 if (atom->avec->bonds_allow && force->bond) {
545 write_string(BOND,force->bond_style);
546 force->bond->write_restart(fp);
547 }
548 if (atom->avec->angles_allow && force->angle) {
549 write_string(ANGLE,force->angle_style);
550 force->angle->write_restart(fp);
551 }
552 if (atom->avec->dihedrals_allow && force->dihedral) {
553 write_string(DIHEDRAL,force->dihedral_style);
554 force->dihedral->write_restart(fp);
555 }
556 if (atom->avec->impropers_allow && force->improper) {
557 write_string(IMPROPER,force->improper_style);
558 force->improper->write_restart(fp);
559 }
560
561 // -1 flag signals end of force field info
562
563 int flag = -1;
564 fwrite(&flag,sizeof(int),1,fp);
565 }
566
567 /* ----------------------------------------------------------------------
568 proc 0 writes out file layout info
569 all procs call this method, only proc 0 writes to file
570 ------------------------------------------------------------------------- */
571
file_layout(int send_size)572 void WriteRestart::file_layout(int send_size)
573 {
574 if (me == 0) {
575 write_int(MULTIPROC,multiproc);
576 write_int(MPIIO,mpiioflag);
577 }
578
579 if (mpiioflag) {
580 int *all_send_sizes;
581 memory->create(all_send_sizes,nprocs,"write_restart:all_send_sizes");
582 MPI_Gather(&send_size, 1, MPI_INT, all_send_sizes, 1, MPI_INT, 0,world);
583 if (me == 0) fwrite(all_send_sizes,sizeof(int),nprocs,fp);
584 memory->destroy(all_send_sizes);
585 }
586
587 // -1 flag signals end of file layout info
588
589 if (me == 0) {
590 int flag = -1;
591 fwrite(&flag,sizeof(int),1,fp);
592 }
593
594 // if MPI-IO file, broadcast the end of the header offste
595 // this allows all ranks to compute offset to their data
596
597 if (mpiioflag) {
598 if (me == 0) headerOffset = ftell(fp);
599 MPI_Bcast(&headerOffset,1,MPI_LMP_BIGINT,0,world);
600 }
601 }
602
603 // ----------------------------------------------------------------------
604 // ----------------------------------------------------------------------
605 // low-level fwrite methods
606 // ----------------------------------------------------------------------
607 // ----------------------------------------------------------------------
608
609 /* ---------------------------------------------------------------------- */
610
magic_string()611 void WriteRestart::magic_string()
612 {
613 const char magic[] = MAGIC_STRING;
614 fwrite(magic,sizeof(char),strlen(magic)+1,fp);
615 }
616
617 /* ---------------------------------------------------------------------- */
618
endian()619 void WriteRestart::endian()
620 {
621 int endian = ENDIAN;
622 fwrite(&endian,sizeof(int),1,fp);
623 }
624
625 /* ---------------------------------------------------------------------- */
626
version_numeric()627 void WriteRestart::version_numeric()
628 {
629 int vn = FORMAT_REVISION;
630 fwrite(&vn,sizeof(int),1,fp);
631 }
632
633 /* ----------------------------------------------------------------------
634 write a flag and an int into the restart file
635 ------------------------------------------------------------------------- */
636
write_int(int flag,int value)637 void WriteRestart::write_int(int flag, int value)
638 {
639 fwrite(&flag,sizeof(int),1,fp);
640 fwrite(&value,sizeof(int),1,fp);
641 }
642
643 /* ----------------------------------------------------------------------
644 write a flag and a bigint into the restart file
645 ------------------------------------------------------------------------- */
646
write_bigint(int flag,bigint value)647 void WriteRestart::write_bigint(int flag, bigint value)
648 {
649 fwrite(&flag,sizeof(int),1,fp);
650 fwrite(&value,sizeof(bigint),1,fp);
651 }
652
653 /* ----------------------------------------------------------------------
654 write a flag and a double into the restart file
655 ------------------------------------------------------------------------- */
656
write_double(int flag,double value)657 void WriteRestart::write_double(int flag, double value)
658 {
659 fwrite(&flag,sizeof(int),1,fp);
660 fwrite(&value,sizeof(double),1,fp);
661 }
662
663 /* ----------------------------------------------------------------------
664 write a flag and a C-style char string (including the terminating null
665 byte) into the restart file
666 ------------------------------------------------------------------------- */
667
write_string(int flag,const char * value)668 void WriteRestart::write_string(int flag, const char *value)
669 {
670 int n = strlen(value) + 1;
671 fwrite(&flag,sizeof(int),1,fp);
672 fwrite(&n,sizeof(int),1,fp);
673 fwrite(value,sizeof(char),n,fp);
674 }
675
676 /* ----------------------------------------------------------------------
677 write a flag and vector of N ints into the restart file
678 ------------------------------------------------------------------------- */
679
write_int_vec(int flag,int n,int * vec)680 void WriteRestart::write_int_vec(int flag, int n, int *vec)
681 {
682 fwrite(&flag,sizeof(int),1,fp);
683 fwrite(&n,sizeof(int),1,fp);
684 fwrite(vec,sizeof(int),n,fp);
685 }
686
687 /* ----------------------------------------------------------------------
688 write a flag and vector of N doubles into the restart file
689 ------------------------------------------------------------------------- */
690
write_double_vec(int flag,int n,double * vec)691 void WriteRestart::write_double_vec(int flag, int n, double *vec)
692 {
693 fwrite(&flag,sizeof(int),1,fp);
694 fwrite(&n,sizeof(int),1,fp);
695 fwrite(vec,sizeof(double),n,fp);
696 }
697