1 /* ----------------------------------------------------------------------
2     This is the
3 
4     ██╗     ██╗ ██████╗  ██████╗  ██████╗ ██╗  ██╗████████╗███████╗
5     ██║     ██║██╔════╝ ██╔════╝ ██╔════╝ ██║  ██║╚══██╔══╝██╔════╝
6     ██║     ██║██║  ███╗██║  ███╗██║  ███╗███████║   ██║   ███████╗
7     ██║     ██║██║   ██║██║   ██║██║   ██║██╔══██║   ██║   ╚════██║
8     ███████╗██║╚██████╔╝╚██████╔╝╚██████╔╝██║  ██║   ██║   ███████║
9     ╚══════╝╚═╝ ╚═════╝  ╚═════╝  ╚═════╝ ╚═╝  ╚═╝   ╚═╝   ╚══════╝®
10 
11     DEM simulation engine, released by
12     DCS Computing Gmbh, Linz, Austria
13     http://www.dcs-computing.com, office@dcs-computing.com
14 
15     LIGGGHTS® is part of CFDEM®project:
16     http://www.liggghts.com | http://www.cfdem.com
17 
18     Core developer and main author:
19     Christoph Kloss, christoph.kloss@dcs-computing.com
20 
21     LIGGGHTS® is open-source, distributed under the terms of the GNU Public
22     License, version 2 or later. It is distributed in the hope that it will
23     be useful, but WITHOUT ANY WARRANTY; without even the implied warranty
24     of MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. You should have
25     received a copy of the GNU General Public License along with LIGGGHTS®.
26     If not, see http://www.gnu.org/licenses . See also top-level README
27     and LICENSE files.
28 
29     LIGGGHTS® and CFDEM® are registered trade marks of DCS Computing GmbH,
30     the producer of the LIGGGHTS® software and the CFDEM®coupling software
31     See http://www.cfdem.com/terms-trademark-policy for details.
32 
33 -------------------------------------------------------------------------
34     Contributing author and copyright for this file:
35     This file is from LAMMPS
36     LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
37     http://lammps.sandia.gov, Sandia National Laboratories
38     Steve Plimpton, sjplimp@sandia.gov
39 
40     Copyright (2003) Sandia Corporation.  Under the terms of Contract
41     DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
42     certain rights in this software.  This software is distributed under
43     the GNU General Public License.
44 ------------------------------------------------------------------------- */
45 
46 #include <stdio.h>
47 #include <stdlib.h>
48 #include <string.h>
49 #include "output.h"
50 #include "style_dump.h"
51 #include "atom.h"
52 #include "neighbor.h"
53 #include "input.h"
54 #include "variable.h"
55 #include "comm.h"
56 #include "update.h"
57 #include "group.h"
58 #include "domain.h"
59 #include "thermo.h"
60 #include "modify.h"
61 #include "compute.h"
62 #include "force.h"
63 #include "dump.h"
64 #include "write_restart.h"
65 #include "accelerator_cuda.h"
66 #include "memory.h"
67 #include "error.h"
68 #include "signal_handling.h"
69 
70 using namespace LAMMPS_NS;
71 
72 #define DELTA 1
73 
74 /* ----------------------------------------------------------------------
75    initialize all output
76 ------------------------------------------------------------------------- */
77 
Output(LAMMPS * lmp)78 Output::Output(LAMMPS *lmp) :
79     Pointers(lmp),
80     restart_flag(false),
81     restart_flag_single(false),
82     restart_flag_double(false),
83     next_restart(0),
84     next_restart_single(0),
85     next_restart_double(0),
86     restart_every_single(0),
87     restart_every_double(0),
88     last_restart(0),
89     restart_toggle(0),
90     var_restart_single(NULL),
91     var_restart_double(NULL),
92     ivar_restart_single(0),
93     ivar_restart_double(0),
94     restart1(NULL),
95     restart2a(NULL),
96     restart2b(NULL),
97     restart(NULL)
98 {
99   char **newarg = new char*[4];
100   // create a default compute that calculates the temperature of the system
101   // NOTE: This compute is deprecated and will be removed in the future
102   newarg[0] = (char *) "thermo_temp";
103   newarg[1] = (char *) "all";
104   newarg[2] = (char *) "temp";
105   modify->add_compute(3,newarg,lmp->suffix);
106   // create a default compute that calculates the kinetic energy of the system
107   newarg[0] = (char *) "thermo_kin_eng";
108   newarg[1] = (char *) "all";
109   newarg[2] = (char *) "ke";
110   modify->add_compute(3,newarg,lmp->suffix);
111   delete [] newarg;
112 
113   // create default Thermo class
114   newarg = new char*[1];
115   newarg[0] = (char *) "one";
116   thermo = new Thermo(lmp,1,newarg);
117   delete [] newarg;
118 
119   thermo_every = 0;
120   var_thermo = NULL;
121 
122   ndump = 0;
123   max_dump = 0;
124   every_dump = NULL;
125   next_dump = NULL;
126   last_dump = NULL;
127   var_dump = NULL;
128   ivar_dump = NULL;
129   dump = NULL;
130 }
131 
132 /* ----------------------------------------------------------------------
133    free all memory
134 ------------------------------------------------------------------------- */
135 
~Output()136 Output::~Output()
137 {
138     if (thermo)
139         delete thermo;
140     delete [] var_thermo;
141 
142     memory->destroy(every_dump);
143     memory->destroy(next_dump);
144     memory->destroy(last_dump);
145     for (int i = 0; i < ndump; i++)
146         delete [] var_dump[i];
147     memory->sfree(var_dump);
148     memory->destroy(ivar_dump);
149     for (int i = 0; i < ndump; i++)
150         delete dump[i];
151     memory->sfree(dump);
152 
153     delete [] restart1;
154     delete [] restart2a;
155     delete [] restart2b;
156     delete [] var_restart_single;
157     delete [] var_restart_double;
158     delete restart;
159 }
160 
161 /* ---------------------------------------------------------------------- */
162 
init()163 void Output::init()
164 {
165   thermo->init();
166   if (var_thermo) {
167     ivar_thermo = input->variable->find(var_thermo);
168     if (ivar_thermo < 0)
169       error->all(FLERR,"Variable name for thermo every does not exist");
170     if (!input->variable->equalstyle(ivar_thermo))
171       error->all(FLERR,"Variable for thermo every is invalid style");
172   }
173 
174   for (int i = 0; i < ndump; i++) dump[i]->init();
175   for (int i = 0; i < ndump; i++)
176     if (every_dump[i] == 0) {
177       ivar_dump[i] = input->variable->find(var_dump[i]);
178       if (ivar_dump[i] < 0)
179         error->all(FLERR,"Variable name for dump every does not exist");
180       if (!input->variable->equalstyle(ivar_dump[i]))
181         error->all(FLERR,"Variable for dump every is invalid style");
182     }
183 
184   if (restart_flag_single && restart_every_single == 0) {
185     ivar_restart_single = input->variable->find(var_restart_single);
186     if (ivar_restart_single < 0)
187       error->all(FLERR,"Variable name for restart does not exist");
188     if (!input->variable->equalstyle(ivar_restart_single))
189       error->all(FLERR,"Variable for restart is invalid style");
190   }
191   if (restart_flag_double && restart_every_double == 0) {
192     ivar_restart_double = input->variable->find(var_restart_double);
193     if (ivar_restart_double < 0)
194       error->all(FLERR,"Variable name for restart does not exist");
195     if (!input->variable->equalstyle(ivar_restart_double))
196       error->all(FLERR,"Variable for restart is invalid style");
197   }
198 }
199 
200 /* ----------------------------------------------------------------------
201    perform output for setup of run/min
202    do dump first, so memory_usage will include dump allocation
203    do thermo last, so will print after memory_usage
204    memflag = 0/1 for printing out memory usage
205 ------------------------------------------------------------------------- */
206 
setup(int memflag)207 void Output::setup(int memflag)
208 {
209   bigint ntimestep = update->ntimestep;
210 
211   // perform dump at start of run only if:
212   //   current timestep is multiple of every and last dump not >= this step
213   //   this is first run after dump created and firstflag is set
214   //   note that variable freq will not write unless triggered by firstflag
215   // set next_dump to multiple of every or variable value
216   // set next_dump_any to smallest next_dump
217   // wrap dumps that invoke computes and variable eval with clear/add
218   // if dump not written now, use addstep_compute_all() since don't know
219   //   what computes the dump write would invoke
220   // if no dumps, set next_dump_any to last+1 so will not influence next
221 
222   int writeflag;
223 
224   if (ndump && update->restrict_output == 0) {
225     for (int idump = 0; idump < ndump; idump++) {
226       if (dump[idump]->clearstep || every_dump[idump] == 0)
227         modify->clearstep_compute();
228       writeflag = 0;
229       if (every_dump[idump] && ntimestep % every_dump[idump] == 0 &&
230           last_dump[idump] != ntimestep) writeflag = 1;
231       if (last_dump[idump] < 0 && dump[idump]->first_flag == 1) writeflag = 1;
232 
233       if (writeflag) {
234         dump[idump]->write();
235         last_dump[idump] = ntimestep;
236       }
237       if (every_dump[idump])
238         next_dump[idump] =
239           (ntimestep/every_dump[idump])*every_dump[idump] + every_dump[idump];
240       else {
241         bigint nextdump = static_cast<bigint>
242           (input->variable->compute_equal(ivar_dump[idump]));
243         if (nextdump <= ntimestep)
244           error->all(FLERR,"Dump every variable returned a bad timestep");
245         next_dump[idump] = nextdump;
246       }
247       if (dump[idump]->clearstep || every_dump[idump] == 0) {
248         if (writeflag) modify->addstep_compute(next_dump[idump]);
249         else modify->addstep_compute_all(next_dump[idump]);
250       }
251       if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]);
252       else next_dump_any = next_dump[0];
253     }
254   } else next_dump_any = update->laststep + 1;
255 
256   // do not write restart files at start of run
257   // set next_restart values to multiple of every or variable value
258   // wrap variable eval with clear/add
259   // if no restarts, set next_restart to last+1 so will not influence next
260 
261   if (restart_flag && update->restrict_output == 0) {
262     if (restart_flag_single) {
263       if (restart_every_single)
264         next_restart_single =
265           (ntimestep/restart_every_single)*restart_every_single +
266           restart_every_single;
267       else {
268         bigint nextrestart = static_cast<bigint>
269           (input->variable->compute_equal(ivar_restart_single));
270         if (nextrestart <= ntimestep)
271           error->all(FLERR,"Restart variable returned a bad timestep");
272         next_restart_single = nextrestart;
273       }
274     } else next_restart_single = update->laststep + 1;
275     if (restart_flag_double) {
276       if (restart_every_double)
277         next_restart_double =
278           (ntimestep/restart_every_double)*restart_every_double +
279           restart_every_double;
280       else {
281         bigint nextrestart = static_cast<bigint>
282           (input->variable->compute_equal(ivar_restart_double));
283         if (nextrestart <= ntimestep)
284           error->all(FLERR,"Restart variable returned a bad timestep");
285         next_restart_double = nextrestart;
286       }
287     } else next_restart_double = update->laststep + 1;
288     next_restart = MIN(next_restart_single,next_restart_double);
289   } else next_restart = update->laststep + 1;
290 
291   // print memory usage unless being called between multiple runs
292 
293   if (memflag) memory_usage();
294 
295   // set next_thermo to multiple of every or variable eval if var defined
296   // insure thermo output on last step of run
297   // thermo may invoke computes so wrap with clear/add
298 
299   modify->clearstep_compute();
300 
301   thermo->header();
302   thermo->compute(0);
303   last_thermo = ntimestep;
304 
305   if (var_thermo) {
306     next_thermo = static_cast<bigint>
307       (input->variable->compute_equal(ivar_thermo));
308     if (next_thermo <= ntimestep)
309       error->all(FLERR,"Thermo every variable returned a bad timestep");
310   } else if (thermo_every) {
311     next_thermo = (ntimestep/thermo_every)*thermo_every + thermo_every;
312     next_thermo = MIN(next_thermo,update->laststep);
313   } else next_thermo = update->laststep;
314 
315   modify->addstep_compute(next_thermo);
316 
317   // next = next timestep any output will be done
318 
319   next = MIN(next_dump_any,next_restart);
320   next = MIN(next,next_thermo);
321 }
322 
323 /* ----------------------------------------------------------------------
324    perform all output for this timestep
325    only perform output if next matches current step and last output doesn't
326    do dump/restart before thermo so thermo CPU time will include them
327 ------------------------------------------------------------------------- */
328 
write(bigint ntimestep)329 void Output::write(bigint ntimestep)
330 {
331   // next_dump does not force output on last step of run
332   // wrap dumps that invoke computes or eval of variable with clear/add
333   // download data from GPU if necessary
334 
335   if (next_dump_any == ntimestep) {
336     if (lmp->cuda && !lmp->cuda->oncpu) lmp->cuda->downloadAll();
337 
338     for (int idump = 0; idump < ndump; idump++) {
339       if (next_dump[idump] == ntimestep) {
340         if (dump[idump]->clearstep || every_dump[idump] == 0)
341           modify->clearstep_compute();
342         if (last_dump[idump] != ntimestep) {
343           dump[idump]->write();
344           last_dump[idump] = ntimestep;
345         }
346         if (every_dump[idump]) next_dump[idump] += every_dump[idump];
347         else {
348           bigint nextdump = static_cast<bigint>
349             (input->variable->compute_equal(ivar_dump[idump]));
350           if (nextdump <= ntimestep)
351             error->all(FLERR,"Dump every variable returned a bad timestep");
352           next_dump[idump] = nextdump;
353         }
354         if (dump[idump]->clearstep || every_dump[idump] == 0)
355           modify->addstep_compute(next_dump[idump]);
356       }
357       if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]);
358       else next_dump_any = next_dump[0];
359     }
360   }
361 
362   // next_restart does not force output on last step of run
363   // for toggle = 0, replace "*" with current timestep in restart filename
364   // download data from GPU if necessary
365   // eval of variable may invoke computes so wrap with clear/add
366 
367   if (next_restart == ntimestep) {
368     if (lmp->cuda && !lmp->cuda->oncpu) lmp->cuda->downloadAll();
369 
370     if (next_restart_single == ntimestep) {
371       char *file = new char[strlen(restart1) + 16];
372       char *ptr = strchr(restart1,'*');
373       *ptr = '\0';
374       sprintf(file,"%s" BIGINT_FORMAT "%s",restart1,ntimestep,ptr+1);
375       *ptr = '*';
376       if (last_restart != ntimestep) restart->write(file);
377       delete [] file;
378       if (restart_every_single) next_restart_single += restart_every_single;
379       else {
380         modify->clearstep_compute();
381         bigint nextrestart = static_cast<bigint>
382           (input->variable->compute_equal(ivar_restart_single));
383         if (nextrestart <= ntimestep)
384           error->all(FLERR,"Restart variable returned a bad timestep");
385         next_restart_single = nextrestart;
386         modify->addstep_compute(next_restart_single);
387       }
388     }
389     if (next_restart_double == ntimestep) {
390       if (last_restart != ntimestep) {
391         if (restart_toggle == 0) {
392           restart->write(restart2a);
393           restart_toggle = 1;
394         } else {
395           restart->write(restart2b);
396           restart_toggle = 0;
397         }
398       }
399       if (restart_every_double) next_restart_double += restart_every_double;
400       else {
401         modify->clearstep_compute();
402         bigint nextrestart = static_cast<bigint>
403           (input->variable->compute_equal(ivar_restart_double));
404         if (nextrestart <= ntimestep)
405           error->all(FLERR,"Restart variable returned a bad timestep");
406         next_restart_double = nextrestart;
407         modify->addstep_compute(next_restart_double);
408       }
409     }
410     last_restart = ntimestep;
411     next_restart = MIN(next_restart_single,next_restart_double);
412 
413     if (SignalHandler::request_write_restart) {
414         char *file = new char[24 + 16 + 5];
415         sprintf(file,"restart_forced_liggghts_" BIGINT_FORMAT ".data",ntimestep);
416         bool has_restart = restart != NULL;
417         if (!has_restart)
418             restart = new WriteRestart(lmp);
419         restart->write(file);
420         if (!has_restart)
421         {
422             delete restart;
423             restart = NULL;
424         }
425         delete [] file;
426         SignalHandler::request_write_restart = false;
427         error->warning(FLERR, "Forced restart written");
428     }
429   }
430 
431   // insure next_thermo forces output on last step of run
432   // thermo may invoke computes so wrap with clear/add
433 
434   if (next_thermo == ntimestep) {
435     modify->clearstep_compute();
436     // check all computes and those with update_on_run_end activated will be updated
437     if (ntimestep == update->laststep)
438         modify->update_computes_on_run_end();
439     if (last_thermo != ntimestep) thermo->compute(1);
440     last_thermo = ntimestep;
441     if (var_thermo) {
442       next_thermo = static_cast<bigint>
443         (input->variable->compute_equal(ivar_thermo));
444       if (next_thermo <= ntimestep)
445         error->all(FLERR,"Thermo every variable returned a bad timestep");
446     } else if (thermo_every) next_thermo += thermo_every;
447     else next_thermo = update->laststep;
448     next_thermo = MIN(next_thermo,update->laststep);
449     modify->addstep_compute(next_thermo);
450   }
451 
452   // next = next timestep any output will be done
453 
454   next = MIN(next_dump_any,next_restart);
455   next = MIN(next,next_thermo);
456 }
457 
458 /* ----------------------------------------------------------------------
459    force a snapshot to be written for all dumps
460    called from PRD and TAD
461 ------------------------------------------------------------------------- */
462 
write_dump(bigint ntimestep)463 void Output::write_dump(bigint ntimestep)
464 {
465   for (int idump = 0; idump < ndump; idump++) {
466     dump[idump]->write();
467     last_dump[idump] = ntimestep;
468   }
469 }
470 
471 /* ----------------------------------------------------------------------
472    force restart file(s) to be written
473    called from PRD and TAD
474 ------------------------------------------------------------------------- */
475 
write_restart(bigint ntimestep)476 void Output::write_restart(bigint ntimestep)
477 {
478   if (restart_flag_single) {
479     char *file = new char[strlen(restart1) + 16];
480     char *ptr = strchr(restart1,'*');
481     *ptr = '\0';
482     sprintf(file,"%s" BIGINT_FORMAT "%s",restart1,ntimestep,ptr+1);
483     *ptr = '*';
484     restart->write(file);
485     delete [] file;
486   }
487 
488   if (restart_flag_double) {
489     if (restart_toggle == 0) {
490       restart->write(restart2a);
491       restart_toggle = 1;
492     } else {
493       restart->write(restart2b);
494       restart_toggle = 0;
495     }
496   }
497 
498   last_restart = ntimestep;
499 }
500 
501 /* ----------------------------------------------------------------------
502    timestep is being changed, called by update->reset_timestep()
503    reset next timestep values for dumps, restart, thermo output
504    reset to smallest value >= new timestep
505    if next timestep set by variable evaluation,
506      eval for ntimestep-1, so current ntimestep can be returned if needed
507      no guarantee that variable can be evaluated for ntimestep-1
508        if it depends on computes, but live with that rare case for now
509 ------------------------------------------------------------------------- */
510 
reset_timestep(bigint ntimestep)511 void Output::reset_timestep(bigint ntimestep)
512 {
513   next_dump_any = MAXBIGINT;
514   for (int idump = 0; idump < ndump; idump++) {
515     if (every_dump[idump]) {
516       next_dump[idump] = (ntimestep/every_dump[idump])*every_dump[idump];
517       if (next_dump[idump] < ntimestep) next_dump[idump] += every_dump[idump];
518     } else {
519       modify->clearstep_compute();
520       update->ntimestep--;
521       bigint nextdump = static_cast<bigint>
522         (input->variable->compute_equal(ivar_dump[idump]));
523       if (nextdump < ntimestep)
524         error->all(FLERR,"Dump every variable returned a bad timestep");
525       update->ntimestep++;
526       next_dump[idump] = nextdump;
527       modify->addstep_compute(next_dump[idump]);
528     }
529     next_dump_any = MIN(next_dump_any,next_dump[idump]);
530   }
531 
532   if (restart_flag_single) {
533     if (restart_every_single) {
534       next_restart_single =
535         (ntimestep/restart_every_single)*restart_every_single;
536       if (next_restart_single < ntimestep)
537         next_restart_single += restart_every_single;
538     } else {
539       modify->clearstep_compute();
540       update->ntimestep--;
541       bigint nextrestart = static_cast<bigint>
542         (input->variable->compute_equal(ivar_restart_single));
543       if (nextrestart < ntimestep)
544         error->all(FLERR,"Restart variable returned a bad timestep");
545       update->ntimestep++;
546       next_restart_single = nextrestart;
547       modify->addstep_compute(next_restart_single);
548     }
549   } else next_restart_single = update->laststep + 1;
550 
551   if (restart_flag_double) {
552     if (restart_every_double) {
553       next_restart_double =
554         (ntimestep/restart_every_double)*restart_every_double;
555       if (next_restart_double < ntimestep)
556         next_restart_double += restart_every_double;
557     } else {
558       modify->clearstep_compute();
559       update->ntimestep--;
560       bigint nextrestart = static_cast<bigint>
561         (input->variable->compute_equal(ivar_restart_double));
562       if (nextrestart < ntimestep)
563         error->all(FLERR,"Restart variable returned a bad timestep");
564       update->ntimestep++;
565       next_restart_double = nextrestart;
566       modify->addstep_compute(next_restart_double);
567     }
568   } else next_restart_double = update->laststep + 1;
569 
570   next_restart = MIN(next_restart_single,next_restart_double);
571 
572   if (var_thermo) {
573     modify->clearstep_compute();
574     update->ntimestep--;
575     next_thermo = static_cast<bigint>
576       (input->variable->compute_equal(ivar_thermo));
577     if (next_thermo < ntimestep)
578       error->all(FLERR,"Thermo every variable returned a bad timestep");
579     update->ntimestep++;
580     next_thermo = MIN(next_thermo,update->laststep);
581     modify->addstep_compute(next_thermo);
582   } else if (thermo_every) {
583     next_thermo = (ntimestep/thermo_every)*thermo_every;
584     if (next_thermo < ntimestep) next_thermo += thermo_every;
585     next_thermo = MIN(next_thermo,update->laststep);
586   } else next_thermo = update->laststep;
587 
588   next = MIN(next_dump_any,next_restart);
589   next = MIN(next,next_thermo);
590 }
591 
592 /* ----------------------------------------------------------------------
593    add a Dump to list of Dumps
594 ------------------------------------------------------------------------- */
595 
add_dump(int narg,char ** arg)596 void Output::add_dump(int narg, char **arg)
597 {
598   if (narg < 5) error->all(FLERR,"Illegal dump command");
599 
600   // error checks
601 
602   for (int idump = 0; idump < ndump; idump++)
603     if (strcmp(arg[0],dump[idump]->id) == 0)
604       error->all(FLERR,"Reuse of dump ID");
605   int igroup = group->find(arg[1]);
606   if (igroup == -1) error->all(FLERR,"Could not find dump group ID");
607   if (force->inumeric(FLERR,arg[3]) <= 0)
608     error->all(FLERR,"Invalid dump frequency");
609 
610   // extend Dump list if necessary
611 
612   if (ndump == max_dump) {
613     max_dump += DELTA;
614     dump = (Dump **)
615       memory->srealloc(dump,max_dump*sizeof(Dump *),"output:dump");
616     memory->grow(every_dump,max_dump,"output:every_dump");
617     memory->grow(next_dump,max_dump,"output:next_dump");
618     memory->grow(last_dump,max_dump,"output:last_dump");
619     var_dump = (char **)
620       memory->srealloc(var_dump,max_dump*sizeof(char *),"output:var_dump");
621     memory->grow(ivar_dump,max_dump,"output:ivar_dump");
622   }
623 
624   // create the Dump
625 
626   if (0) return;         // dummy line to enable else-if macro expansion
627 
628 #define DUMP_CLASS
629 #define DumpStyle(key,Class) \
630   else if (strcmp(arg[2],#key) == 0) dump[ndump] = new Class(lmp,narg,arg);
631 #include "style_dump.h"
632 #undef DUMP_CLASS
633 
634   else error->all(FLERR,"Invalid dump style");
635 
636   every_dump[ndump] = force->inumeric(FLERR,arg[3]);
637   if (every_dump[ndump] <= 0) error->all(FLERR,"Illegal dump command");
638   last_dump[ndump] = -1;
639   var_dump[ndump] = NULL;
640   ndump++;
641 }
642 
643 /* ----------------------------------------------------------------------
644    modify parameters of a Dump
645 ------------------------------------------------------------------------- */
646 
modify_dump(int narg,char ** arg)647 void Output::modify_dump(int narg, char **arg)
648 {
649   if (narg < 1) error->all(FLERR,"Illegal dump_modify command");
650 
651   // find which dump it is
652 
653   int idump;
654   for (idump = 0; idump < ndump; idump++)
655     if (strcmp(arg[0],dump[idump]->id) == 0) break;
656   if (idump == ndump) error->all(FLERR,"Cound not find dump_modify ID");
657 
658   dump[idump]->modify_params(narg-1,&arg[1]);
659 }
660 
661 /* ----------------------------------------------------------------------
662    delete a Dump from list of Dumps
663 ------------------------------------------------------------------------- */
664 
delete_dump(char * id)665 void Output::delete_dump(char *id)
666 {
667   // find which dump it is and delete it
668 
669   int idump;
670   for (idump = 0; idump < ndump; idump++)
671     if (strcmp(id,dump[idump]->id) == 0) break;
672   if (idump == ndump) error->all(FLERR,"Could not find undump ID");
673 
674   delete dump[idump];
675   delete [] var_dump[idump];
676 
677   // move other dumps down in list one slot
678 
679   for (int i = idump+1; i < ndump; i++) {
680     dump[i-1] = dump[i];
681     every_dump[i-1] = every_dump[i];
682     next_dump[i-1] = next_dump[i];
683     last_dump[i-1] = last_dump[i];
684     var_dump[i-1] = var_dump[i];
685     ivar_dump[i-1] = ivar_dump[i];
686   }
687   ndump--;
688 }
689 
690 /* ----------------------------------------------------------------------
691    set thermo output frequency from input script
692 ------------------------------------------------------------------------- */
693 
set_thermo(int narg,char ** arg)694 void Output::set_thermo(int narg, char **arg)
695 {
696   if (narg != 1) error->all(FLERR,"Illegal thermo command");
697 
698   if (strstr(arg[0],"v_") == arg[0]) {
699     delete [] var_thermo;
700     int n = strlen(&arg[0][2]) + 1;
701     var_thermo = new char[n];
702     strcpy(var_thermo,&arg[0][2]);
703   } else {
704     thermo_every = force->inumeric(FLERR,arg[0]);
705     if (thermo_every < 0) error->all(FLERR,"Illegal thermo command");
706   }
707 }
708 
709 /* ----------------------------------------------------------------------
710    new Thermo style
711 ------------------------------------------------------------------------- */
712 
create_thermo(int narg,char ** arg)713 void Output::create_thermo(int narg, char **arg)
714 {
715   if (narg < 1) error->all(FLERR,"Illegal thermo_style command");
716 
717   // don't allow this so that dipole style can safely allocate inertia vector
718 
719   if (domain->box_exist == 0)
720     error->all(FLERR,"Thermo_style command before simulation box is defined");
721 
722   // warn if previous thermo had been modified via thermo_modify command
723 
724   if (thermo->modified && comm->me == 0 && !lmp->wb)
725     error->warning(FLERR,"New thermo_style command, "
726                    "previous thermo_modify settings will be lost");
727 
728   // set thermo = NULL in case new Thermo throws an error
729 
730   delete thermo;
731   thermo = NULL;
732   thermo = new Thermo(lmp,narg,arg);
733 }
734 
735 /* ----------------------------------------------------------------------
736    setup restart capability for single or double output files
737    if only one filename and it contains no "*", then append ".*"
738 ------------------------------------------------------------------------- */
739 
create_restart(int narg,char ** arg)740 void Output::create_restart(int narg, char **arg)
741 {
742   if (narg < 1) error->all(FLERR,"Illegal restart command");
743 
744   int every = 0;
745   int varflag = 0;
746 
747   if (strstr(arg[0],"v_") == arg[0]) varflag = 1;
748   else every = force->inumeric(FLERR,arg[0]);
749 
750   if (!varflag && every == 0) {
751     if (narg != 1) error->all(FLERR,"Illegal restart command");
752 
753     restart_flag = restart_flag_single = restart_flag_double = false;
754     last_restart = -1;
755 
756     delete restart;
757     restart = NULL;
758     delete [] restart1;
759     delete [] restart2a;
760     delete [] restart2b;
761     restart1 = restart2a = restart2b = NULL;
762     delete [] var_restart_single;
763     delete [] var_restart_double;
764     var_restart_single = var_restart_double = NULL;
765 
766     return;
767   }
768 
769   if (narg != 2 && narg != 3) error->all(FLERR,"Illegal restart command");
770 
771   if (narg == 2) {
772     restart_flag = restart_flag_single = true;
773 
774     if (varflag) {
775       delete [] var_restart_single;
776       int n = strlen(&arg[0][2]) + 1;
777       var_restart_single = new char[n];
778       strcpy(var_restart_single,&arg[0][2]);
779       restart_every_single = 0;
780     } else restart_every_single = every;
781 
782     int n = strlen(arg[1]) + 3;
783     restart1 = new char[n];
784     strcpy(restart1,arg[1]);
785     if (strchr(restart1,'*') == NULL) strcat(restart1,".*");
786   }
787 
788   if (narg == 3) {
789     restart_flag = restart_flag_double = true;
790 
791     if (varflag) {
792       delete [] var_restart_double;
793       int n = strlen(&arg[0][2]) + 1;
794       var_restart_double = new char[n];
795       strcpy(var_restart_double,&arg[0][2]);
796       restart_every_double = 0;
797     } else restart_every_double = every;
798 
799     restart_toggle = 0;
800     int n = strlen(arg[1]) + 3;
801     restart2a = new char[n];
802     strcpy(restart2a,arg[1]);
803     n = strlen(arg[2]) + 1;
804     restart2b = new char[n];
805     strcpy(restart2b,arg[2]);
806   }
807 
808   if (restart == NULL) restart = new WriteRestart(lmp);
809 }
810 
811 /* ----------------------------------------------------------------------
812    sum and print memory usage
813    result is only memory on proc 0, not averaged across procs
814 ------------------------------------------------------------------------- */
815 
memory_usage()816 void Output::memory_usage()
817 {
818   bigint bytes = 0;
819   bytes += atom->memory_usage();
820   bytes += neighbor->memory_usage();
821   bytes += comm->memory_usage();
822   bytes += update->memory_usage();
823   bytes += force->memory_usage();
824   bytes += modify->memory_usage();
825   for (int i = 0; i < ndump; i++) bytes += dump[i]->memory_usage();
826 
827   double mbytes = bytes/1024.0/1024.0;
828 
829   if (comm->me == 0) {
830     if (screen)
831       fprintf(screen,"Memory usage per processor = %g Mbytes\n",mbytes);
832     if (logfile)
833       fprintf(logfile,"Memory usage per processor = %g Mbytes\n",mbytes);
834   }
835 }
836 
837 /* ----------------------------------------------------------------------
838    identifies when the next restart will be written
839    also handles signals to force writing of a restart
840    this function is called by Neighbor::decide
841 ------------------------------------------------------------------------- */
842 
restart_requested(const bigint ntimestep)843 bool Output::restart_requested(const bigint ntimestep)
844 {
845     if (SignalHandler::request_write_restart || SignalHandler::request_quit)
846     {
847         // we have something to write now
848         next = ntimestep;
849         // if quit is request write thermo
850         if (SignalHandler::request_quit)
851             next_thermo = ntimestep;
852         // if restart writing is request do it
853         if (SignalHandler::request_write_restart)
854             next_restart = ntimestep;
855     }
856     return next_restart == ntimestep;
857 }
858 
859 /* ----------------------------------------------------------------------
860    request a restart for a certain timestep
861 ------------------------------------------------------------------------- */
862 
request_restart(const bigint ntimestep)863 void Output::request_restart(const bigint ntimestep)
864 {
865     if (restart_flag)
866     {
867         next_restart = ntimestep;
868         if (restart_every_single)
869             next_restart_single = ntimestep;
870         if (restart_every_double)
871             next_restart_double = ntimestep;
872     }
873 }
874