From ded48cc031ffa255b2e17cc55f13ec04214dd4a3 Mon Sep 17 00:00:00 2001 From: Steve Plimpton Date: Tue, 21 Dec 2021 10:57:42 -0700 Subject: [PATCH] more optimizations and extend to other dump styles --- doc/src/dump_modify.rst | 49 +++++++++++++++++++++------------- src/COMPRESS/dump_xyz_gz.cpp | 8 +++++- src/COMPRESS/dump_xyz_zstd.cpp | 6 ++++- src/EXTRA-DUMP/dump_dcd.cpp | 8 ++++-- src/EXTRA-DUMP/dump_xtc.cpp | 25 ++++++++++------- src/dump.h | 4 +-- src/dump_xyz.cpp | 7 +++-- src/fix_dt_reset.cpp | 8 ------ src/integrate.cpp | 11 ++++---- src/output.cpp | 38 ++++++++++++++++++-------- src/output.h | 3 ++- 11 files changed, 106 insertions(+), 61 deletions(-) diff --git a/doc/src/dump_modify.rst b/doc/src/dump_modify.rst index 42bb4d94fd..0094fceb7b 100644 --- a/doc/src/dump_modify.rst +++ b/doc/src/dump_modify.rst @@ -200,15 +200,16 @@ will be accepted. ---------- -The *every* keyword does two things. It specifies that the interval -between dump snapshots will be specified in timesteps, which is the -default if the *every* or *every/time* keywords are not used. See the +The *every* keyword can be used with any dump style except the *dcd* +and *xtc* styles. It does two things. It specifies that the interval +between dump snapshots will be set in timesteps, which is the default +if the *every* or *every/time* keywords are not used. See the *every/time* keyword for how to specify the interval in simulation -time, i.e. in time units of the :doc:`units ` command. This -command also sets the interval value, which overrides the dump +time, i.e. in time units of the :doc:`units ` command. The +*every* keyword also sets the interval value, which overrides the dump frequency originally specified by the :doc:`dump ` command. -The every keyword can be specified in one of two ways. It can be a +The *every* keyword can be specified in one of two ways. It can be a numeric value in which case it must be > 0. Or it can be an :doc:`equal-style variable `, which should be specified as v_name, where name is the variable name. @@ -266,13 +267,21 @@ in file tmp.times: ---------- -The *every/time* keyword does two things. It specifies that the -interval between dump snapshots will be specified in simulation time, +The *every/time* keyword can be used with any dump style except the +*dcd* and *xtc* styles. It does two things. It specifies that the +interval between dump snapshots will be set in simulation time, i.e. in time units of the :doc:`units ` command. This can be useful when the timestep size varies during a simulation run, e.g. by use of the :doc:`fix dt/reset ` command. The default is -to specify the interval in timesteps; see the *every* keyword. This -command also sets the interval value. +to specify the interval in timesteps; see the *every* keyword. The +*every/time* command also sets the interval value. + +.. note:: + + If you wish dump styles *atom*, *custom*, *local*, or *xyz* to + include the simulation time as a field in the header portion of + each snapshot, you also need to use the dump_modify *time* keyword + with a setting of *yes*. See its documentation below. Note that since snapshots are output on simulation steps, each snapshot will be written on the first timestep whose associated @@ -323,8 +332,8 @@ file tmp.times: .. note:: - When using a file-style variable with the *every* keyword, the file - of timesteps must list a first times that is beyond the time + When using a file-style variable with the *every/time* keyword, the + file of timesteps must list a first time that is beyond the time associated with the current timestep (e.g. it cannot be 0.0). And it must list one or more times beyond the length of the run you perform. This is because the dump command will generate an error @@ -342,8 +351,8 @@ always occur if the current timestep is a multiple of $N$, the frequency specified in the :doc:`dump ` command or :doc:`dump_modify every ` command, including timestep 0. It will also always occur if the current simulation time is a multiple -of *Delta*, the time interval specified in the doc:`dump_modify every/time -` command. +of *Delta*, the time interval specified in the doc:`dump_modify +every/time ` command. But if this is not the case, a dump snapshot will only be written if the setting of this keyword is *yes*\ . If it is *no*, which is the @@ -731,16 +740,20 @@ threshold criterion is met. Otherwise it is not met. ---------- -The *time* keyword only applies to the dump *atom*, *custom*, and -*local* styles (and their COMPRESS package versions *atom/gz*, -*custom/gz* and *local/gz*\ ). If set to *yes*, each frame will will -contain two extra lines before the "ITEM: TIMESTEP" entry: +The *time* keyword only applies to the dump *atom*, *custom*, *local*, +and *xyz* styles (and their COMPRESS package versions *atom/gz*, +*custom/gz* and *local/gz*\ ). For the first 3 styles, if set to +*yes*, each frame will will contain two extra lines before the "ITEM: +TIMESTEP" entry: .. parsed-literal:: ITEM: TIME \ +For the *xyz* style, the simulation time is included on the same line +as the timestep value. + This will output the current elapsed simulation time in current time units equivalent to the :doc:`thermo keyword ` *time*\ . This is to simplify post-processing of trajectories using a variable time diff --git a/src/COMPRESS/dump_xyz_gz.cpp b/src/COMPRESS/dump_xyz_gz.cpp index 9d38c4673c..cec32090cb 100644 --- a/src/COMPRESS/dump_xyz_gz.cpp +++ b/src/COMPRESS/dump_xyz_gz.cpp @@ -88,11 +88,17 @@ void DumpXYZGZ::openfile() if (multifile) delete[] filecurrent; } +/* ---------------------------------------------------------------------- */ + void DumpXYZGZ::write_header(bigint ndump) { if (me == 0) { std::string header = fmt::format("{}\n", ndump); - header += fmt::format("Atoms. Timestep: {}\n", update->ntimestep); + if (time_flag) + header += fmt::format("Atoms. Timestep: {} Time: {:.6f}\n", + update->ntimestep, update->atime); + else + header += fmt::format("Atoms. Timestep: {}\n", update->ntimestep); writer.write(header.c_str(), header.length()); } } diff --git a/src/COMPRESS/dump_xyz_zstd.cpp b/src/COMPRESS/dump_xyz_zstd.cpp index bcbdc08a24..24d31fe671 100644 --- a/src/COMPRESS/dump_xyz_zstd.cpp +++ b/src/COMPRESS/dump_xyz_zstd.cpp @@ -100,7 +100,11 @@ void DumpXYZZstd::write_header(bigint ndump) { if (me == 0) { std::string header = fmt::format("{}\n", ndump); - header += fmt::format("Atoms. Timestep: {}\n", update->ntimestep); + if (time_flag) + header += fmt::format("Atoms. Timestep: {} Time: {:.6f}\n", + update->ntimestep, update->atime); + else + header += fmt::format("Atoms. Timestep: {}\n", update->ntimestep); writer.write(header.c_str(), header.length()); } } diff --git a/src/EXTRA-DUMP/dump_dcd.cpp b/src/EXTRA-DUMP/dump_dcd.cpp index ec3973448a..3aca5e8a98 100644 --- a/src/EXTRA-DUMP/dump_dcd.cpp +++ b/src/EXTRA-DUMP/dump_dcd.cpp @@ -100,13 +100,17 @@ void DumpDCD::init_style() if (sort_flag == 0 || sortcol != 0) error->all(FLERR,"Dump dcd requires sorting by atom ID"); - // check that dump frequency has not changed and is not a variable - // but only when not being called from the "write_dump" command. + // check that dump modify settings are compatible with dcd + // but only when not being called from the "write_dump" command if (strcmp(id,"WRITE_DUMP") != 0) { int idump; for (idump = 0; idump < output->ndump; idump++) if (strcmp(id,output->dump[idump]->id) == 0) break; + + if (output->mode_dump[idump] == 1) + error->all(FLERR,"Cannot use every/time setting for dump dcd"); + if (output->every_dump[idump] == 0) error->all(FLERR,"Cannot use variable every setting for dump dcd"); diff --git a/src/EXTRA-DUMP/dump_xtc.cpp b/src/EXTRA-DUMP/dump_xtc.cpp index 94846671cd..94271f31a6 100644 --- a/src/EXTRA-DUMP/dump_xtc.cpp +++ b/src/EXTRA-DUMP/dump_xtc.cpp @@ -121,17 +121,24 @@ void DumpXTC::init_style() if (flush_flag) error->all(FLERR,"Cannot set dump_modify flush for dump xtc"); - // check that dump frequency has not changed and is not a variable + // check that dump modify settings are compatible with xtc + // but only when not being called from the "write_dump" command - int idump; - for (idump = 0; idump < output->ndump; idump++) - if (strcmp(id,output->dump[idump]->id) == 0) break; - if (output->every_dump[idump] == 0) - error->all(FLERR,"Cannot use variable every setting for dump xtc"); + if (strcmp(id,"WRITE_DUMP") != 0) { + int idump; + for (idump = 0; idump < output->ndump; idump++) + if (strcmp(id,output->dump[idump]->id) == 0) break; + + if (output->mode_dump[idump] == 1) + error->all(FLERR,"Cannot use every/time setting for dump xtc"); - if (nevery_save == 0) nevery_save = output->every_dump[idump]; - else if (nevery_save != output->every_dump[idump]) - error->all(FLERR,"Cannot change dump_modify every for dump xtc"); + if (output->every_dump[idump] == 0) + error->all(FLERR,"Cannot use every variable setting for dump xtc"); + + if (nevery_save == 0) nevery_save = output->every_dump[idump]; + else if (nevery_save != output->every_dump[idump]) + error->all(FLERR,"Cannot change dump_modify every for dump xtc"); + } } /* ---------------------------------------------------------------------- */ diff --git a/src/dump.h b/src/dump.h index 730d4c9ca9..caeef827c7 100644 --- a/src/dump.h +++ b/src/dump.h @@ -26,7 +26,7 @@ class Dump : protected Pointers { int igroup, groupbit; // group that Dump is performed on int first_flag; // 0 if no initial dump, 1 if yes initial dump - int clearstep; // 1 if dump invokes computes, 0 if not + int clearstep; // 1 if dump can invoke computes, 0 if not int comm_forward; // size of forward communication (0 if none) int comm_reverse; // size of reverse communication (0 if none) @@ -75,7 +75,7 @@ class Dump : protected Pointers { int sortcol; // 0 to sort on ID, 1-N on columns int sortcolm1; // sortcol - 1 int sortorder; // ASCEND or DESCEND - int time_flag; // 1 if output accumulated time + int time_flag; // 1 if output simulation time int unit_flag; // 1 if dump should contain unit information int unit_count; // # of times the unit information was written int delay_flag; // 1 if delay output until delaystep diff --git a/src/dump_xyz.cpp b/src/dump_xyz.cpp index e009937959..db929f9d6e 100644 --- a/src/dump_xyz.cpp +++ b/src/dump_xyz.cpp @@ -131,7 +131,11 @@ void DumpXYZ::write_header(bigint n) { if (me == 0) { fprintf(fp,BIGINT_FORMAT "\n",n); - fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT "\n",update->ntimestep); + if (time_flag) + fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT " Time: %f\n", + update->ntimestep, update->atime); + else + fprintf(fp,"Atoms. Timestep: " BIGINT_FORMAT "\n",update->ntimestep); } } @@ -159,7 +163,6 @@ void DumpXYZ::pack(tagint *ids) } } - /* ---------------------------------------------------------------------- convert mybuf of doubles to one big formatted string in sbuf return -1 if strlen exceeds an int, since used as arg in MPI calls in Dump diff --git a/src/fix_dt_reset.cpp b/src/fix_dt_reset.cpp index b7ab63f2d7..adb0082fc8 100644 --- a/src/fix_dt_reset.cpp +++ b/src/fix_dt_reset.cpp @@ -121,14 +121,6 @@ void FixDtReset::init() respaflag = 0; if (utils::strmatch(update->integrate_style, "^respa")) respaflag = 1; - // check for DCD or XTC dumps - - for (int i = 0; i < output->ndump; i++) - if ((strcmp(output->dump[i]->style, "dcd") == 0 || - strcmp(output->dump[i]->style, "xtc") == 0) && - comm->me == 0) - error->warning(FLERR, "Dump dcd/xtc timestamp may be wrong with fix dt/reset"); - ftm2v = force->ftm2v; mvv2e = force->mvv2e; dt = update->dt; diff --git a/src/integrate.cpp b/src/integrate.cpp index 7a1dbfaf34..c111532ee2 100644 --- a/src/integrate.cpp +++ b/src/integrate.cpp @@ -118,11 +118,10 @@ void Integrate::ev_setup() set eflag,vflag for current iteration based on (1) computes that need energy/virial info on this timestep - (2) time dumps that need unknown per-atom info on this timestep - NOTE: could not check time dumps if timestep size is not varying + (2) time dumps that may need per-atom compute info on this timestep + NOTE: inefficient to add all per-atom eng/virial computes + but don't know which ones the dump needs see NOTE in output.cpp - also inefficient to add all per-atom eng/virial computes - but don't know which ones the dump needs invoke matchstep() on all timestep-dependent computes to clear their arrays eflag: set any or no bits ENERGY_GLOBAL bit for global energy @@ -141,8 +140,8 @@ void Integrate::ev_set(bigint ntimestep) int i,flag; int tdflag = 0; - if (output->any_time_dumps) - tdflag = output->check_time_dumps(ntimestep); + if (output->any_time_dumps && + output->next_time_dump_any == ntimestep) tdflag = 1; flag = 0; int eflag_global = 0; diff --git a/src/output.cpp b/src/output.cpp index 94688cd74c..d828b5a417 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -12,6 +12,10 @@ See the README file in the top-level LAMMPS directory. ------------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Contributing author: Michal Kanski (Jagiellonian U) for simulation time dumps +------------------------------------------------------------------------- */ + #include "output.h" #include "style_dump.h" // IWYU pragma: keep @@ -177,6 +181,8 @@ void Output::setup(int memflag) // decide whether to write snapshot and/or calculate next step for dump if (ndump && update->restrict_output == 0) { + next_time_dump_any = MAXBIGINT; + for (int idump = 0; idump < ndump; idump++) { // wrap step dumps that invoke computes or do variable eval with clear/add @@ -237,6 +243,8 @@ void Output::setup(int memflag) else modify->addstep_compute_all(next_dump[idump]); } + if (mode_dump[idump] && (dump[idump]->clearstep || var_dump[idump])) + next_time_dump_any = MIN(next_time_dump_any,next_dump[idump]); if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]); else next_dump_any = next_dump[0]; } @@ -326,6 +334,9 @@ void Output::setup(int memflag) // set next_dump_any to smallest next_dump // wrap step dumps that invoke computes or do variable eval with clear/add // NOTE: + // not wrapping time dumps means that Integrate::ev_set() + // needs to trigger all per-atom eng/virial computes + // on a timestep where any time dump will be output // could wrap time dumps as well, if timestep size did not vary // if wrap when timestep size varies frequently, // then can do many unneeded addstep() --> inefficient @@ -336,7 +347,10 @@ void Output::setup(int memflag) int writeflag; if (next_dump_any == ntimestep) { + for (int idump = 0; idump < ndump; idump++) { + next_time_dump_any = MAXBIGINT; + if (next_dump[idump] == ntimestep) { if (last_dump[idump] == ntimestep) continue; @@ -356,6 +370,8 @@ void Output::setup(int memflag) modify->addstep_compute(next_dump[idump]); } + if (mode_dump[idump] && (dump[idump]->clearstep || var_dump[idump])) + next_time_dump_any = MIN(next_time_dump_any,next_dump[idump]); if (idump) next_dump_any = MIN(next_dump_any,next_dump[idump]); else next_dump_any = next_dump[0]; } @@ -680,23 +696,23 @@ void Output::reset_dt() { bigint ntimestep = update->ntimestep; - next_dump_any = MAXBIGINT; + next_time_dump_any = MAXBIGINT; for (int idump = 0; idump < ndump; idump++) { - if (mode_dump[idump] == 1) { + if (mode_dump[idump] == 0) continue; - // reset next_dump but do not change next_time_dump, 2 arg for reset_dt() - // do not invoke for a dump already scheduled for this step - // since timestep change affects next step + // reset next_dump but do not change next_time_dump, 2 arg for reset_dt() + // do not invoke for a dump already scheduled for this step + // since timestep change affects next step + + if (next_dump[idump] != ntimestep) + calculate_next_dump(2,idump,update->ntimestep); - if (next_dump[idump] != ntimestep) { - calculate_next_dump(2,idump,update->ntimestep); - } - } - - next_dump_any = MIN(next_dump_any,next_dump[idump]); + if (dump[idump]->clearstep || var_dump[idump]) + next_time_dump_any = MIN(next_time_dump_any,next_dump[idump]); } + next_dump_any = MIN(next_dump_any,next_time_dump_any); next = MIN(next_dump_any,next_restart); next = MIN(next,next_thermo); } diff --git a/src/output.h b/src/output.h index c7c4faf252..3f557bdef5 100644 --- a/src/output.h +++ b/src/output.h @@ -35,7 +35,8 @@ class Output : protected Pointers { int ndump; // # of Dumps defined int max_dump; // max size of Dump list - bigint next_dump_any; // next timestep for any Dump + bigint next_dump_any; // next timestep for any dump + bigint next_time_dump_any; // next timestep for any time dump with computes int any_time_dumps; // 1 if any time dump defined int *mode_dump; // 0/1 if write every N timesteps or Delta in sim time int *every_dump; // dump every N timesteps, 0 if variable