diff --git a/doc/src/thermo.rst b/doc/src/thermo.rst index 154fd59431..5621b554c8 100644 --- a/doc/src/thermo.rst +++ b/doc/src/thermo.rst @@ -32,18 +32,20 @@ The content and format of what is printed is controlled by the :doc:`thermo_style ` and :doc:`thermo_modify ` commands. -Instead of a numeric value, N can be specified as an :doc:`equal-style variable `, which should be specified as v_name, where -name is the variable name. In this case, the variable is evaluated at -the beginning of a run to determine the next timestep at which -thermodynamic info will be written out. On that timestep, the -variable will be evaluated again to determine the next timestep, etc. -Thus the variable should return timestep values. See the stagger() -and logfreq() and stride() math functions for :doc:`equal-style variables `, as examples of useful functions to use in -this context. Other similar math functions could easily be added as -options for :doc:`equal-style variables `. +Instead of a numeric value, N can be specified as an :doc:`equal-style +variable `, which should be specified as v_name, where name is +the variable name. In this case, the variable is evaluated at the +beginning of a run to determine the next timestep at which thermodynamic +info will be written out. On that timestep, the variable will be +evaluated again to determine the next timestep, etc. Thus the variable +should return timestep values. See the stagger() and logfreq() and +stride() math functions for :doc:`equal-style variables `, as +examples of useful functions to use in this context. Other similar math +functions could easily be added as options for :doc:`equal-style +variables `. For example, the following commands will output thermodynamic info at -timesteps 0,10,20,30,100,200,300,1000,2000,etc: +timesteps 0, 10, 20, 30, 100, 200, 300, 1000, 2000, *etc*: .. code-block:: LAMMPS diff --git a/doc/src/thermo_modify.rst b/doc/src/thermo_modify.rst index 31de925492..e209dd937b 100644 --- a/doc/src/thermo_modify.rst +++ b/doc/src/thermo_modify.rst @@ -20,7 +20,7 @@ Syntax *warn* value = *ignore* or *reset* or *default* or a number *norm* value = *yes* or *no* *flush* value = *yes* or *no* - *line* value = *one* or *multi* + *line* value = *one* or *multi* or *yaml* *format* values = *line* string, *int* string, *float* string, M string, or *none* string = C-style format string M = integer from 1 to N, where N = # of quantities being output @@ -36,35 +36,35 @@ Examples thermo_modify temp myTemp format 3 %15.8g thermo_modify temp myTemp format line "%ld %g %g %15.8g" thermo_modify line multi format float %g + themos_modify line yaml format none Description """"""""""" -Set options for how thermodynamic information is computed and printed -by LAMMPS. +Set options for how thermodynamic information is computed and printed by +LAMMPS. .. note:: - These options apply to the currently defined thermo style. When + These options apply to the *currently defined* thermo style. When you specify a :doc:`thermo_style ` command, all - thermodynamic settings are restored to their default values, including - those previously reset by a thermo_modify command. Thus if your input - script specifies a thermo_style command, you should use the - thermo_modify command after it. + thermodynamic settings are restored to their default values, + including those previously reset by a thermo_modify command. Thus if + your input script specifies a thermo_style command, you should use + the thermo_modify command **after** it. -The *lost* keyword determines whether LAMMPS checks for lost atoms -each time it computes thermodynamics and what it does if atoms are -lost. An atom can be "lost" if it moves across a non-periodic -simulation box :doc:`boundary ` or if it moves more than a box -length outside the simulation domain (or more than a processor -sub-domain length) before reneighboring occurs. The latter case is -typically due to bad dynamics, e.g. too large a timestep or huge -forces and velocities. If the value is *ignore*, LAMMPS does not -check for lost atoms. If the value is *error* or *warn*, LAMMPS -checks and either issues an error or warning. The code will exit with -an error and continue with a warning. A warning will only be issued -once, the first time an atom is lost. This can be a useful debugging -option. +The *lost* keyword determines whether LAMMPS checks for lost atoms each +time it computes thermodynamics and what it does if atoms are lost. An +atom can be "lost" if it moves across a non-periodic simulation box +:doc:`boundary ` or if it moves more than a box length outside +the simulation domain (or more than a processor sub-domain length) +before reneighboring occurs. The latter case is typically due to bad +dynamics, e.g. too large a timestep or huge forces and velocities. If +the value is *ignore*, LAMMPS does not check for lost atoms. If the +value is *error* or *warn*, LAMMPS checks and either issues an error or +warning. The code will exit with an error and continue with a warning. +A warning will only be issued once, the first time an atom is lost. +This can be a useful debugging option. The *lost/bond* keyword determines whether LAMMPS throws an error or not if an atom in a bonded interaction (bond, angle, etc) cannot be @@ -109,55 +109,55 @@ will be reset to zero, and with the value *default*, the counter is reset and the limit set to 100. An example usage of either *reset* or *default* would be to re-enable warnings that were disabled or have reached the limit during equilibration, where the warnings would be -acceptable while the system is still adjusting, but then change -to all warnings for the production run, where they would indicate -problems that would require a closer look at what is causing them. +acceptable while the system is still adjusting, but then change to all +warnings for the production run, where they would indicate problems that +would require a closer look at what is causing them. The *norm* keyword determines whether various thermodynamic output values are normalized by the number of atoms or not, depending on whether it is set to *yes* or *no*\ . Different unit styles have -different defaults for this setting (see below). Even if *norm* is -set to *yes*, a value is only normalized if it is an "extensive" -quantity, meaning that it scales with the number of atoms in the -system. For the thermo keywords described by the page for the -:doc:`thermo_style ` command, all energy-related keywords -are extensive, such as *pe* or *ebond* or *enthalpy*\ . Other keywords -such as *temp* or *press* are "intensive" meaning their value is -independent (in a statistical sense) of the number of atoms in the -system and thus are never normalized. For thermodynamic output values -extracted from fixes and computes in a :doc:`thermo_style custom ` command, the page for the individual -:doc:`fix ` or :doc:`compute ` lists whether the value is -"extensive" or "intensive" and thus whether it is normalized. -Thermodynamic output values calculated by a variable formula are -assumed to be "intensive" and thus are never normalized. You can -always include a divide by the number of atoms in the variable formula -if this is not the case. +different defaults for this setting (see below). Even if *norm* is set +to *yes*, a value is only normalized if it is an "extensive" quantity, +meaning that it scales with the number of atoms in the system. For the +thermo keywords described by the page for the :doc:`thermo_style +` command, all energy-related keywords are extensive, such +as *pe* or *ebond* or *enthalpy*\ . Other keywords such as *temp* or +*press* are "intensive" meaning their value is independent (in a +statistical sense) of the number of atoms in the system and thus are +never normalized. For thermodynamic output values extracted from fixes +and computes in a :doc:`thermo_style custom ` command, the +page for the individual :doc:`fix ` or :doc:`compute ` +lists whether the value is "extensive" or "intensive" and thus whether +it is normalized. Thermodynamic output values calculated by a variable +formula are assumed to be "intensive" and thus are never normalized. +You can always include a divide by the number of atoms in the variable +formula if this is not the case. The *flush* keyword invokes a flush operation after thermodynamic info is written to the screen and log file. This insures the output is updated and not buffered (by the application) even if LAMMPS halts -before the simulation completes. Please note that this does not -affect buffering by the OS or devices, so you may still lose data -in case the simulation stops due to a hardware failure. +before the simulation completes. Please note that this does not affect +buffering by the OS or devices, so you may still lose data in case the +simulation stops due to a hardware failure. -The *line* keyword determines whether thermodynamics will be output as -a series of numeric values on one line or in a multi-line format with -3 quantities with text strings per line and a dashed-line header -containing the timestep and CPU time. This modify option overrides -the *one* and *multi* thermo_style settings. +The *line* keyword determines whether thermodynamics will be output as a +series of numeric values on one line ("one"), in a multi-line format +with 3 quantities with text strings per line and a dashed-line header +containing the timestep and CPU time ("multi"), or in a YAML format +block ("yaml"). This modify option overrides the *one*, *multi*, or +*yaml* thermo_style settings. -The *format* keyword can be used to change the default numeric format -of any of quantities the :doc:`thermo_style ` command -outputs. All the specified format strings are C-style formats, -e.g. as used by the C/C++ printf() command. The *line* keyword takes -a single argument which is the format string for the entire line of -thermo output, with N fields, which you must enclose in quotes if it -is more than one field. The *int* and *float* keywords take a single -format argument and are applied to all integer or floating-point -quantities output. The setting for *M string* also takes a single -format argument which is used for the Mth value output in each line, -e.g. the fifth column is output in high precision for "format 5 -%20.15g". +The *format* keyword can be used to change the default numeric format of +any of quantities the :doc:`thermo_style ` command +outputs. All the specified format strings are C-style formats, e.g. as +used by the C/C++ printf() command. The *line* keyword takes a single +argument which is the format string for the entire line of thermo +output, with N fields, which you must enclose in quotes if it is more +than one field. The *int* and *float* keywords take a single format +argument and are applied to all integer or floating-point quantities +output. The setting for *M string* also takes a single format argument +which is used for the Mth value output in each line, e.g. the fifth +column is output in high precision for "format 5 %20.15g". The *format* keyword can be used multiple times. The precedence is that for each value in a line of output, the *M* format (if specified) @@ -168,46 +168,46 @@ settings, reverting all values to their default format. .. note:: - The thermo output values *step* and *atoms* are stored - internally as 8-byte signed integers, rather than the usual 4-byte - signed integers. When specifying the *format int* option you can use - a "%d"-style format identifier in the format string and LAMMPS will - convert this to the corresponding 8-byte form when it is applied to - those keywords. However, when specifying the *line* option or *format - M string* option for *step* and *natoms*, you should specify a format + The thermo output values *step* and *atoms* are stored internally as + 8-byte signed integers, rather than the usual 4-byte signed integers. + When specifying the *format int* option you can use a "%d"-style + format identifier in the format string and LAMMPS will convert this + to the corresponding 8-byte form when it is applied to those + keywords. However, when specifying the *line* option or *format M + string* option for *step* and *natoms*, you should specify a format string appropriate for an 8-byte signed integer, e.g. one with "%ld". -The *temp* keyword is used to determine how thermodynamic temperature -is calculated, which is used by all thermo quantities that require a +The *temp* keyword is used to determine how thermodynamic temperature is +calculated, which is used by all thermo quantities that require a temperature ("temp", "press", "ke", "etotal", "enthalpy", "pxx", etc). The specified compute ID must have been previously defined by the user via the :doc:`compute ` command and it must be a style of compute that calculates a temperature. As described in the :doc:`thermo_style ` command, thermo output uses a default -compute for temperature with ID = *thermo_temp*. This option allows -the user to override the default. +compute for temperature with ID = *thermo_temp*. This option allows the +user to override the default. The *press* keyword is used to determine how thermodynamic pressure is calculated, which is used by all thermo quantities that require a pressure ("press", "enthalpy", "pxx", etc). The specified compute ID -must have been previously defined by the user via the -:doc:`compute ` command and it must be a style of compute that -calculates a pressure. As described in the -:doc:`thermo_style ` command, thermo output uses a default -compute for pressure with ID = *thermo_press*. This option allows the -user to override the default. +must have been previously defined by the user via the :doc:`compute +` command and it must be a style of compute that calculates a +pressure. As described in the :doc:`thermo_style ` +command, thermo output uses a default compute for pressure with ID = +*thermo_press*. This option allows the user to override the default. .. note:: If both the *temp* and *press* keywords are used in a single - thermo_modify command (or in two separate commands), then the order in - which the keywords are specified is important. Note that a :doc:`pressure compute ` defines its own temperature compute as - an argument when it is specified. The *temp* keyword will override - this (for the pressure compute being used by thermodynamics), but only - if the *temp* keyword comes after the *press* keyword. If the *temp* - keyword comes before the *press* keyword, then the new pressure - compute specified by the *press* keyword will be unaffected by the - *temp* setting. + thermo_modify command (or in two separate commands), then the order + in which the keywords are specified is important. Note that a + :doc:`pressure compute ` defines its own + temperature compute as an argument when it is specified. The *temp* + keyword will override this (for the pressure compute being used by + thermodynamics), but only if the *temp* keyword comes after the + *press* keyword. If the *temp* keyword comes before the *press* + keyword, then the new pressure compute specified by the *press* + keyword will be unaffected by the *temp* setting. Restrictions """""""""""" @@ -225,7 +225,8 @@ The option defaults are lost = error, warn = 100, norm = yes for unit style of *lj*, norm = no for unit style of *real* and *metal*, flush = no, and temp/press = compute IDs defined by thermo_style. -The defaults for the line and format options depend on the thermo -style. For styles "one" and "custom", the line and format defaults -are "one", "%8d", and "%12.8g". For style "multi", the line and -format defaults are "multi", "%8d", and "%14.4f". +The defaults for the line and format options depend on the thermo style. +For styles "one" and "custom", the line and format defaults are "one", +"%10d", and "%12.8g". For style "multi", the line and format defaults +are "multi", "%14d", and "%14.4f". For style "yaml", the line and format +defaults are "%d" and "%.15g". diff --git a/doc/src/thermo_style.rst b/doc/src/thermo_style.rst index a04504b1a6..e2d5bcb58d 100644 --- a/doc/src/thermo_style.rst +++ b/doc/src/thermo_style.rst @@ -10,13 +10,14 @@ Syntax thermo_style style args -* style = *one* or *multi* or *custom* +* style = *one* or *multi* *yaml* or *custom* * args = list of arguments for a particular style .. parsed-literal:: *one* args = none *multi* args = none + *yaml* args = none *custom* args = list of keywords possible keywords = step, elapsed, elaplong, dt, time, cpu, tpcpu, spcpu, cpuremain, part, timeremain, @@ -92,6 +93,8 @@ Examples .. code-block:: LAMMPS thermo_style multi + thermo_style yaml + thermo_style one thermo_style custom step temp pe etotal press vol thermo_style custom step temp etotal c_myTemp v_abc thermo_style custom step temp etotal c_myTemp[*] v_abc @@ -99,18 +102,42 @@ Examples Description """"""""""" -Set the style and content for printing thermodynamic data to the -screen and log file. +Set the style and content for printing thermodynamic data to the screen +and log files. -Style *one* prints a one-line summary of thermodynamic info that is -the equivalent of "thermo_style custom step temp epair emol etotal -press". The line contains only numeric values. +Style *one* prints a single line of thermodynamic info that is the +equivalent of "thermo_style custom step temp epair emol etotal press". +The line contains only numeric values. Style *multi* prints a multiple-line listing of thermodynamic info that is the equivalent of "thermo_style custom etotal ke temp pe ebond eangle edihed eimp evdwl ecoul elong press". The listing contains numeric values and a string ID for each quantity. +Style *yaml* is similar to style *one* but prints the output in `YAML +`_ format which can be easily read by a variety of +script languages and data handling packages. Since LAMMPS may print +other output before, after, or in between thermodynamic output, the +YAML format content needs to be separated from the rest. All YAML +format thermodynamic output can be matched with a regular expression +and can thus be extracted with commands like ``egrep`` as follows: + +.. code-block:: sh + + egrep '^(keywords:|data:$|---$|\.\.\.$| - \[)' log.lammps > log.yaml + +A typical block of YAML format output looks like this: + +.. code-block:: yaml + + --- + keywords: [Step, Temp, KinEng, PotEng, E_bond, E_angle, E_dihed, E_impro, E_vdwl, E_coul, E_long, Press, Volume, ] + data: + - [0, 1.44000000000001, 2.15993250000001, -6.77336805323422, 0, 0, 0, 0, -6.77336805323422, 0, 0, -5.01970725908556, 37905.7095475006, ] + - [50, 0.740091517740786, 1.11010258482128, -5.73150426762886, 0, 0, 0, 0, -5.73150426762886, 0, 0, 0.335273324523691, 37905.7095475006, ] + - [100, 0.757453103239936, 1.13614414924569, -5.75850548601596, 0, 0, 0, 0, -5.75850548601596, 0, 0, 0.207261053624723, 37905.7095475006, ] + ... + Style *custom* is the most general setting and allows you to specify which of the keywords listed above you want printed on each thermodynamic timestep. Note that the keywords c_ID, f_ID, v_name are diff --git a/src/finish.cpp b/src/finish.cpp index f3dbc83498..35be03dca7 100644 --- a/src/finish.cpp +++ b/src/finish.cpp @@ -27,6 +27,8 @@ #include "neigh_list.h" #include "neigh_request.h" #include "neighbor.h" // IWYU pragma: keep +#include "output.h" +#include "thermo.h" #include "timer.h" // IWYU pragma: keep #include "universe.h" #include "update.h" @@ -121,10 +123,10 @@ void Finish::end(int flag) if (time_loop > 0.0) cpu_loop = cpu_loop/time_loop*100.0; if (me == 0) { + output->thermo->footer(); int ntasks = nprocs * nthreads; - utils::logmesg(lmp,"Loop time of {:.6g} on {} procs for " - "{} steps with {} atoms\n\n",time_loop, - ntasks,update->nsteps,atom->natoms); + utils::logmesg(lmp,"Loop time of {:.6g} on {} procs for {} steps with {} atoms\n\n", + time_loop,ntasks,update->nsteps,atom->natoms); // Gromacs/NAMD-style performance metric for suitable unit settings @@ -142,8 +144,7 @@ void Finish::end(int flag) if (strcmp(update->unit_style,"lj") == 0) { double tau_day = 24.0*3600.0 / t_step * update->dt / one_fs; - utils::logmesg(lmp,"Performance: {:.3f} tau/day, {:.3f} " - "timesteps/s\n",tau_day,step_t); + utils::logmesg(lmp,"Performance: {:.3f} tau/day, {:.3f} timesteps/s\n",tau_day,step_t); } else if (strcmp(update->unit_style,"electron") == 0) { double hrs_fs = t_step / update->dt * one_fs / 3600.0; double fs_day = 24.0*3600.0 / t_step * update->dt / one_fs; @@ -161,15 +162,15 @@ void Finish::end(int flag) if (timeflag) { if (lmp->kokkos) { - utils::logmesg(lmp,"{:.1f}% CPU use with {} MPI tasks x {} OpenMP " - "threads\n",cpu_loop,nprocs,lmp->kokkos->nthreads); + utils::logmesg(lmp,"{:.1f}% CPU use with {} MPI tasks x {} OpenMP threads\n", + cpu_loop,nprocs,lmp->kokkos->nthreads); } else { #if defined(_OPENMP) - utils::logmesg(lmp,"{:.1f}% CPU use with {} MPI tasks x {} OpenMP " - "threads\n",cpu_loop,nprocs,nthreads); + utils::logmesg(lmp,"{:.1f}% CPU use with {} MPI tasks x {} OpenMP threads\n", + cpu_loop,nprocs,nthreads); #else - utils::logmesg(lmp,"{:.1f}% CPU use with {} MPI tasks " - "x no OpenMP threads\n",cpu_loop,nprocs); + utils::logmesg(lmp,"{:.1f}% CPU use with {} MPI tasks x no OpenMP threads\n", + cpu_loop,nprocs); #endif } } @@ -192,8 +193,7 @@ void Finish::end(int flag) if (me == 0) { std::string mesg = "\nMinimization stats:\n"; - mesg += fmt::format(" Stopping criterion = {}\n", - update->minimize->stopstr); + mesg += fmt::format(" Stopping criterion = {}\n",update->minimize->stopstr); mesg += fmt::format(" Energy initial, next-to-last, final = \n" " {:18.15g} {:18.15g} {:18.15g}\n", update->minimize->einitial, @@ -222,33 +222,27 @@ void Finish::end(int flag) time = timer->get_wall(Timer::DEPHASE); MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; - if (me == 0) utils::logmesg(lmp," Dephase time (%) = {} ({})\n", - time,time/time_loop*100.0); + if (me == 0) utils::logmesg(lmp," Dephase time (%) = {} ({})\n",time,time/time_loop*100.0); time = timer->get_wall(Timer::DYNAMICS); MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; - if (me == 0) utils::logmesg(lmp," Dynamics time (%) = {} ({})\n", - time,time/time_loop*100.0); + if (me == 0) utils::logmesg(lmp," Dynamics time (%) = {} ({})\n",time,time/time_loop*100.0); time = timer->get_wall(Timer::QUENCH); MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; - if (me == 0) utils::logmesg(lmp," Quench time (%) = {} ({})\n", - time,time/time_loop*100.0); + if (me == 0) utils::logmesg(lmp," Quench time (%) = {} ({})\n",time,time/time_loop*100.0); time = timer->get_wall(Timer::REPCOMM); MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; - if (me == 0) utils::logmesg(lmp," Comm time (%) = {} ({})\n", - time,time/time_loop*100.0); + if (me == 0) utils::logmesg(lmp," Comm time (%) = {} ({})\n",time,time/time_loop*100.0); time = timer->get_wall(Timer::REPOUT); MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; - if (me == 0) utils::logmesg(lmp," Output time (%) = {} ({})\n", - time,time/time_loop*100.0); + if (me == 0) utils::logmesg(lmp," Output time (%) = {} ({})\n",time,time/time_loop*100.0); time = time_other; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; - if (me == 0) utils::logmesg(lmp," Other time (%) = {} ({})\n", - time,time/time_loop*100.0); + if (me == 0) utils::logmesg(lmp," Other time (%) = {} ({})\n",time,time/time_loop*100.0); } // TAD stats @@ -259,33 +253,27 @@ void Finish::end(int flag) time = timer->get_wall(Timer::NEB); MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; - if (me == 0) utils::logmesg(lmp," NEB time (%) = {} ({})\n", - time,time/time_loop*100.0); + if (me == 0) utils::logmesg(lmp," NEB time (%) = {} ({})\n",time,time/time_loop*100.0); time = timer->get_wall(Timer::DYNAMICS); MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; - if (me == 0) utils::logmesg(lmp," Dynamics time (%) = {} ({})\n", - time,time/time_loop*100.0); + if (me == 0) utils::logmesg(lmp," Dynamics time (%) = {} ({})\n",time,time/time_loop*100.0); time = timer->get_wall(Timer::QUENCH); MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; - if (me == 0) utils::logmesg(lmp," Quench time (%) = {} ({})\n", - time,time/time_loop*100.0); + if (me == 0) utils::logmesg(lmp," Quench time (%) = {} ({})\n",time,time/time_loop*100.0); time = timer->get_wall(Timer::REPCOMM); MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; - if (me == 0) utils::logmesg(lmp," Comm time (%) = {} ({})\n", - time,time/time_loop*100.0); + if (me == 0) utils::logmesg(lmp," Comm time (%) = {} ({})\n",time,time/time_loop*100.0); time = timer->get_wall(Timer::REPOUT); MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; - if (me == 0) utils::logmesg(lmp," Output time (%) = {} ({})\n", - time,time/time_loop*100.0); + if (me == 0) utils::logmesg(lmp," Output time (%) = {} ({})\n",time,time/time_loop*100.0); time = time_other; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; - if (me == 0) utils::logmesg(lmp," Other time (%) = {} ({})\n", - time,time/time_loop*100.0); + if (me == 0) utils::logmesg(lmp," Other time (%) = {} ({})\n",time,time/time_loop*100.0); } // HYPER stats @@ -296,18 +284,15 @@ void Finish::end(int flag) time = timer->get_wall(Timer::DYNAMICS); MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; - if (me == 0) utils::logmesg(lmp," Dynamics time (%) = {} ({})\n", - time,time/time_loop*100.0); + if (me == 0) utils::logmesg(lmp," Dynamics time (%) = {} ({})\n",time,time/time_loop*100.0); time = timer->get_wall(Timer::QUENCH); MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; - if (me == 0) utils::logmesg(lmp," Quench time (%) = {} ({})\n", - time,time/time_loop*100.0); + if (me == 0) utils::logmesg(lmp," Quench time (%) = {} ({})\n",time,time/time_loop*100.0); time = time_other; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); time = tmp/nprocs; - if (me == 0) utils::logmesg(lmp," Other time (%) = {} ({})\n", - time,time/time_loop*100.0); + if (me == 0) utils::logmesg(lmp," Other time (%) = {} ({})\n",time,time/time_loop*100.0); } // further timing breakdowns @@ -326,28 +311,20 @@ void Finish::end(int flag) "------------------------------------------------------\n"); } - mpi_timings("Pair",timer,Timer::PAIR, world,nprocs, - nthreads,me,time_loop,screen,logfile); + mpi_timings("Pair",timer,Timer::PAIR, world,nprocs,nthreads,me,time_loop,screen,logfile); if (atom->molecular != Atom::ATOMIC) - mpi_timings("Bond",timer,Timer::BOND,world,nprocs, - nthreads,me,time_loop,screen,logfile); + mpi_timings("Bond",timer,Timer::BOND,world,nprocs,nthreads,me,time_loop,screen,logfile); if (force->kspace) - mpi_timings("Kspace",timer,Timer::KSPACE,world,nprocs, - nthreads,me,time_loop,screen,logfile); + mpi_timings("Kspace",timer,Timer::KSPACE,world,nprocs,nthreads,me,time_loop,screen,logfile); - mpi_timings("Neigh",timer,Timer::NEIGH,world,nprocs, - nthreads,me,time_loop,screen,logfile); - mpi_timings("Comm",timer,Timer::COMM,world,nprocs, - nthreads,me,time_loop,screen,logfile); - mpi_timings("Output",timer,Timer::OUTPUT,world,nprocs, - nthreads,me,time_loop,screen,logfile); - mpi_timings("Modify",timer,Timer::MODIFY,world,nprocs, - nthreads,me,time_loop,screen,logfile); + mpi_timings("Neigh",timer,Timer::NEIGH,world,nprocs,nthreads,me,time_loop,screen,logfile); + mpi_timings("Comm",timer,Timer::COMM,world,nprocs,nthreads,me,time_loop,screen,logfile); + mpi_timings("Output",timer,Timer::OUTPUT,world,nprocs,nthreads,me,time_loop,screen,logfile); + mpi_timings("Modify",timer,Timer::MODIFY,world,nprocs,nthreads,me,time_loop,screen,logfile); if (timer->has_sync()) - mpi_timings("Sync",timer,Timer::SYNC,world,nprocs, - nthreads,me,time_loop,screen,logfile); + mpi_timings("Sync",timer,Timer::SYNC,world,nprocs,nthreads,me,time_loop,screen,logfile); time = time_other; MPI_Allreduce(&time,&tmp,1,MPI_DOUBLE,MPI_SUM,world); @@ -580,8 +557,7 @@ void Finish::end(int flag) if (atom->natoms > 0) mesg += fmt::format("Ave neighs/atom = {:.8}\n",nall/atom->natoms); if ((atom->molecular != Atom::ATOMIC) && (atom->natoms > 0)) - mesg += fmt::format("Ave special neighs/atom = {:.8}\n", - nspec_all/atom->natoms); + mesg += fmt::format("Ave special neighs/atom = {:.8}\n",nspec_all/atom->natoms); mesg += fmt::format("Neighbor list builds = {}\n",neighbor->ncalls); if (neighbor->dist_check) mesg += fmt::format("Dangerous builds = {}\n",neighbor->ndanger); diff --git a/src/fix_nh.cpp b/src/fix_nh.cpp index 91be322d82..28c0cafc60 100644 --- a/src/fix_nh.cpp +++ b/src/fix_nh.cpp @@ -93,8 +93,6 @@ FixNH::FixNH(LAMMPS *lmp, int narg, char **arg) : tcomputeflag = 0; pcomputeflag = 0; - id_temp = nullptr; - id_press = nullptr; // turn on tilt factor scaling, whenever applicable diff --git a/src/output.cpp b/src/output.cpp index a3c79d4cda..7a1eaaf807 100644 --- a/src/output.cpp +++ b/src/output.cpp @@ -69,7 +69,7 @@ Output::Output(LAMMPS *lmp) : Pointers(lmp) char **newarg = new char*[1]; newarg[0] = (char *) "one"; thermo = new Thermo(lmp,1,newarg); - delete [] newarg; + delete[] newarg; thermo_every = 0; var_thermo = nullptr; @@ -110,7 +110,7 @@ Output::Output(LAMMPS *lmp) : Pointers(lmp) Output::~Output() { if (thermo) delete thermo; - delete [] var_thermo; + delete[] var_thermo; memory->destroy(mode_dump); memory->destroy(every_dump); @@ -118,17 +118,17 @@ Output::~Output() memory->destroy(next_dump); memory->destroy(next_time_dump); memory->destroy(last_dump); - for (int i = 0; i < ndump; i++) delete [] var_dump[i]; + for (int i = 0; i < ndump; i++) delete[] var_dump[i]; memory->sfree(var_dump); memory->destroy(ivar_dump); for (int i = 0; i < ndump; i++) delete dump[i]; memory->sfree(dump); - delete [] restart1; - delete [] restart2a; - delete [] restart2b; - delete [] var_restart_single; - delete [] var_restart_double; + delete[] restart1; + delete[] restart2a; + delete[] restart2b; + delete[] var_restart_single; + delete[] var_restart_double; delete restart; delete dump_map; @@ -545,8 +545,7 @@ void Output::calculate_next_dump(int which, int idump, bigint ntimestep) } nextdump = ntimestep + - static_cast ((nexttime - tcurrent - EPSDT*update->dt) / - update->dt) + 1; + static_cast ((nexttime - tcurrent - EPSDT*update->dt) / update->dt) + 1; // if delta is too small to reach next timestep, use multiple of delta @@ -557,8 +556,7 @@ void Output::calculate_next_dump(int which, int idump, bigint ntimestep) ((tnext - nexttime) / every_time_dump[idump]); nexttime = nexttime + (multiple+1)*every_time_dump[idump]; nextdump = ntimestep + - static_cast ((nexttime - tcurrent - EPSDT*update->dt) / - update->dt) + 1; + static_cast ((nexttime - tcurrent - EPSDT*update->dt) / update->dt) + 1; } } else { @@ -575,8 +573,7 @@ void Output::calculate_next_dump(int which, int idump, bigint ntimestep) error->all(FLERR,"Dump every/time variable returned a bad time"); nextdump = ntimestep + - static_cast ((nexttime - tcurrent - EPSDT*update->dt) / - update->dt) + 1; + static_cast ((nexttime - tcurrent - EPSDT*update->dt) / update->dt) + 1; if (nextdump <= ntimestep) error->all(FLERR,"Dump every/time variable too small for next timestep"); } @@ -825,7 +822,7 @@ void Output::delete_dump(char *id) if (idump == ndump) error->all(FLERR,"Could not find undump ID"); delete dump[idump]; - delete [] var_dump[idump]; + delete[] var_dump[idump]; // move other dumps down in list one slot @@ -869,7 +866,7 @@ void Output::set_thermo(int narg, char **arg) // always reset var_thermo, so it is possible to switch back from // variable spaced thermo outputs to constant spaced ones. - delete [] var_thermo; + delete[] var_thermo; var_thermo = nullptr; if (utils::strmatch(arg[0],"^v_")) { @@ -929,12 +926,12 @@ void Output::create_restart(int narg, char **arg) delete restart; restart = nullptr; - delete [] restart1; - delete [] restart2a; - delete [] restart2b; + delete[] restart1; + delete[] restart2a; + delete[] restart2b; restart1 = restart2a = restart2b = nullptr; - delete [] var_restart_single; - delete [] var_restart_double; + delete[] var_restart_single; + delete[] var_restart_double; var_restart_single = var_restart_double = nullptr; return; @@ -950,13 +947,13 @@ void Output::create_restart(int narg, char **arg) restart_flag = restart_flag_single = 1; if (varflag) { - delete [] var_restart_single; + delete[] var_restart_single; var_restart_single = utils::strdup(arg[0]+2); restart_every_single = 0; } else restart_every_single = every; int n = strlen(arg[1]) + 3; - delete [] restart1; + delete[] restart1; restart1 = new char[n]; strcpy(restart1,arg[1]); if (strchr(restart1,'*') == nullptr) strcat(restart1,".*"); @@ -966,13 +963,13 @@ void Output::create_restart(int narg, char **arg) restart_flag = restart_flag_double = 1; if (varflag) { - delete [] var_restart_double; + delete[] var_restart_double; var_restart_double = utils::strdup(arg[0]+2); restart_every_double = 0; } else restart_every_double = every; - delete [] restart2a; - delete [] restart2b; + delete[] restart2a; + delete[] restart2b; restart_toggle = 0; restart2a = utils::strdup(arg[1]); restart2b = utils::strdup(arg[2]); diff --git a/src/thermo.cpp b/src/thermo.cpp index f95b665e4e..63a33f6d45 100644 --- a/src/thermo.cpp +++ b/src/thermo.cpp @@ -52,7 +52,7 @@ using namespace LAMMPS_NS; using namespace MathConst; -// customize a new keyword by adding to this list: +// CUSTOMIZATION: add a new keyword by adding it to this list: // step, elapsed, elaplong, dt, time, cpu, tpcpu, spcpu, cpuremain, // part, timeremain @@ -66,54 +66,65 @@ using namespace MathConst; // fmax, fnorm, nbuild, ndanger // cella, cellb, cellc, cellalpha, cellbeta, cellgamma -// customize a new thermo style by adding a DEFINE to this list -// also insure allocation of line string is correct in constructor +// CUSTOMIZATION: add a new thermo style by adding a constant to the enumerator, +// define a new string constant with the keywords and provide default formats. -#define ONE "step temp epair emol etotal press" -#define MULTI "etotal ke temp pe ebond eangle edihed eimp evdwl ecoul elong press" +enum{ ONELINE, MULTILINE, YAMLLINE }; +// style "one" +static constexpr char ONE[] = "step temp epair emol etotal press"; +#define FORMAT_FLOAT_ONE_DEFAULT "%12.8g" +#define FORMAT_INT_ONE_DEFAULT "%10d" +// style "multi" +static constexpr char MULTI[] = "etotal ke temp pe ebond eangle edihed eimp evdwl ecoul elong press"; +#define FORMAT_FLOAT_MULTI_DEFAULT "%14.4f" +#define FORMAT_INT_MULTI_DEFAULT "%14d" +// style "yaml" +static constexpr char YAML[] = "step temp ke pe ebond eangle edihed eimp evdwl ecoul elong press"; +#define FORMAT_FLOAT_YAML_DEFAULT "%.15g" +#define FORMAT_INT_YAML_DEFAULT "%d" -enum{ONELINE,MULTILINE}; -enum{SCALAR,VECTOR,ARRAY}; +#define FORMAT_MULTI_HEADER "------------ Step {:14} ----- CPU = {:12.7g} (sec) -------------" +enum{ SCALAR, VECTOR, ARRAY }; +static constexpr char id_temp[] = "thermo_temp"; +static constexpr char id_press[] = "thermo_press"; +static constexpr char id_pe[] = "thermo_pe"; + +static char fmtbuf[512]; #define DELTA 8 /* ---------------------------------------------------------------------- */ -Thermo::Thermo(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) +Thermo::Thermo(LAMMPS *_lmp, int narg, char **arg) : + Pointers(_lmp), style(nullptr), vtype(nullptr), field2index(nullptr), argindex1(nullptr), + argindex2(nullptr), temperature(nullptr), pressure(nullptr), pe(nullptr) { - MPI_Comm_rank(world,&me); - style = utils::strdup(arg[0]); // set thermo_modify defaults + lineflag = ONELINE; modified = 0; normuserflag = 0; - lineflag = ONELINE; lostflag = lostbond = Thermo::ERROR; lostbefore = warnbefore = 0; flushflag = 0; // set style and corresponding lineflag // custom style builds its own line of keywords, including wildcard expansion - // customize a new thermo style by adding to if statement - // allocate line string used for 3 tasks - // concat of custom style args - // one-time thermo output of header line - // each line of numeric thermo output - // 256 = extra for ONE or MULTI string or multi formatting - // 64 = max per-arg chars in header or numeric output + // CUSTOMIZATION: add a new thermo style by adding it to the if statement + // set line string with default keywords if not custom style. if (strcmp(style,"one") == 0) { - line = new char[256+6*64]; - memset(line,0,256+6*64); - strcpy(line,ONE); + line = ONE; + lineflag = ONELINE; } else if (strcmp(style,"multi") == 0) { - line = new char[256+12*64]; - memset(line,0,256+12*64); - strcpy(line,MULTI); + line = MULTI; lineflag = MULTILINE; + } else if (strcmp(style,"yaml") == 0) { + line = YAML; + lineflag = YAMLLINE; } else if (strcmp(style,"custom") == 0) { if (narg == 1) error->all(FLERR,"Illegal thermo style custom command"); @@ -125,35 +136,23 @@ Thermo::Thermo(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) int nvalues = utils::expand_args(FLERR,narg-1,&arg[1],0,earg,lmp); if (earg != &arg[1]) expand = 1; - line = new char[256+nvalues*64]; - line[0] = '\0'; + line.clear(); for (int iarg = 0; iarg < nvalues; iarg++) { - strcat(line,earg[iarg]); - strcat(line," "); + line += earg[iarg]; + line += ' '; } - line[strlen(line)-1] = '\0'; // if wildcard expansion occurred, free earg memory from exapnd_args() if (expand) { - for (int i = 0; i < nvalues; i++) delete [] earg[i]; + for (int i = 0; i < nvalues; i++) delete[] earg[i]; memory->sfree(earg); } } else error->all(FLERR,"Illegal thermo style command"); - // ptrs, flags, IDs for compute objects thermo may use or create - - temperature = nullptr; - pressure = nullptr; - pe = nullptr; - index_temp = index_press_scalar = index_press_vector = index_pe = -1; - id_temp = (char *) "thermo_temp"; - id_press = (char *) "thermo_press"; - id_pe = (char *) "thermo_pe"; - // count fields in line // allocate per-field memory // process line of keywords @@ -161,50 +160,20 @@ Thermo::Thermo(LAMMPS *lmp, int narg, char **arg) : Pointers(lmp) nfield_initial = utils::trim_and_count_words(line); allocate(); parse_fields(line); - - // format strings - - char *bigint_format = (char *) BIGINT_FORMAT; - char *fformat_multi = (char *) "---------------- Step %%8%s ----- " - "CPU = %%11.4f (sec) ----------------"; - - sprintf(format_multi,fformat_multi,&bigint_format[1]); - format_float_one_def = (char *) "%12.8g"; - format_float_multi_def = (char *) "%14.4f"; - format_int_one_def = (char *) "%8d"; - format_int_multi_def = (char *) "%14d"; - sprintf(format_bigint_one_def,"%%8%s",&bigint_format[1]); - sprintf(format_bigint_multi_def,"%%14%s",&bigint_format[1]); - - format_line_user = nullptr; - format_float_user = nullptr; - format_int_user = nullptr; - format_bigint_user = nullptr; } /* ---------------------------------------------------------------------- */ Thermo::~Thermo() { - delete [] style; - delete [] line; - + delete[] style; deallocate(); - - // format strings - - delete [] format_line_user; - delete [] format_float_user; - delete [] format_int_user; - delete [] format_bigint_user; } /* ---------------------------------------------------------------------- */ void Thermo::init() { - int i,n; - // set normvalue to default setting unless user has specified it if (normuserflag) normvalue = normuser; @@ -222,52 +191,66 @@ void Thermo::init() // include keyword if lineflag = MULTILINE // add '/n' every 3 values if lineflag = MULTILINE // add trailing '/n' to last value + // add YAML list item prefix for lineflag = YAMLLINE - ValueTokenizer * format_line = nullptr; - if (format_line_user) { - format_line = new ValueTokenizer(format_line_user); - } + ValueTokenizer *format_line = nullptr; + if (format_line_user.size()) format_line = new ValueTokenizer(format_line_user); - const char *ptr = nullptr; - std::string format_line_user_def; - for (i = 0; i < nfield; i++) { + std::string format_this, format_line_user_def; + for (int i = 0; i < nfield; i++) { - format[i][0] = '\0'; - if (lineflag == MULTILINE && i % 3 == 0) strcat(format[i],"\n"); + format[i].clear(); + format_this.clear(); + format_line_user_def.clear(); - if (format_line_user) { - format_line_user_def = format_line->next_string(); - } + if ((lineflag == MULTILINE) && ((i % 3) == 0)) format[i] += "\n"; + if ((lineflag == YAMLLINE) && (i == 0)) format[i] += " - ["; + if (format_line) format_line_user_def = format_line->next_string(); - if (format_column_user[i]) ptr = format_column_user[i]; + if (format_column_user[i].size()) format_this = format_column_user[i]; else if (vtype[i] == FLOAT) { - if (format_float_user) ptr = format_float_user; - else if (format_line_user) ptr = format_line_user_def.c_str(); - else if (lineflag == ONELINE) ptr = format_float_one_def; - else if (lineflag == MULTILINE) ptr = format_float_multi_def; - } else if (vtype[i] == INT) { - if (format_int_user) ptr = format_int_user; - else if (format_line_user) ptr = format_line_user_def.c_str(); - else if (lineflag == ONELINE) ptr = format_int_one_def; - else if (lineflag == MULTILINE) ptr = format_int_multi_def; - } else if (vtype[i] == BIGINT) { - if (format_bigint_user) ptr = format_bigint_user; - else if (format_line_user) ptr = format_line_user_def.c_str(); - else if (lineflag == ONELINE) ptr = format_bigint_one_def; - else if (lineflag == MULTILINE) ptr = format_bigint_multi_def; + if (format_float_user.size()) format_this = format_float_user; + else if (format_line_user_def.size()) format_this = format_line_user_def; + else if (lineflag == ONELINE) format_this = FORMAT_FLOAT_ONE_DEFAULT; + else if (lineflag == MULTILINE) format_this = FORMAT_FLOAT_MULTI_DEFAULT; + else if (lineflag == YAMLLINE) format_this = FORMAT_FLOAT_YAML_DEFAULT; + } else if ((vtype[i] == INT) || (vtype[i] == BIGINT)) { + if (format_int_user.size()) { + if (vtype[i] == INT) + format_this = format_int_user; + else + format_this = format_bigint_user; + } else if (format_line_user_def.size()) { + format_this = format_line_user_def; + } else { + if (lineflag == ONELINE) format_this = FORMAT_INT_ONE_DEFAULT; + else if (lineflag == MULTILINE) format_this = FORMAT_INT_MULTI_DEFAULT; + else format_this = FORMAT_INT_YAML_DEFAULT; + if (vtype[i] == BIGINT) { + // replace "d" in int format with bigint format specifier + auto found = format_this.find('%'); + found = format_this.find('d', found); + format_this = format_this.replace(found, 1, std::string(BIGINT_FORMAT).substr(1)); + } + } } - n = strlen(format[i]); - if (lineflag == ONELINE) sprintf(&format[i][n],"%s ",ptr); - else sprintf(&format[i][n],"%-8s = %s ",keyword[i],ptr); + if (lineflag == ONELINE) format[i] += format_this + " "; + else if (lineflag == YAMLLINE) format[i] += format_this + ", "; + else format[i] += fmt::format("{:<8} = {} ",keyword[i],format_this); } - strcat(format[nfield-1],"\n"); + + // chop off trailing blank or add closing bracket if needed and then add newline + if (lineflag == ONELINE) format[nfield-1].resize(format[nfield-1].size()-1); + else if (lineflag == MULTILINE) format[nfield-1].resize(format[nfield-1].size()-1); + else if (lineflag == YAMLLINE) format[nfield-1] += ']'; + format[nfield-1] += '\n'; delete format_line; // find current ptr for each Compute ID - for (i = 0; i < ncompute; i++) { + for (int i = 0; i < ncompute; i++) { computes[i] = modify->get_compute_by_id(id_compute[i]); if (!computes[i]) error->all(FLERR,"Could not find thermo compute with ID {}",id_compute[i]); } @@ -275,7 +258,7 @@ void Thermo::init() // find current ptr for each Fix ID // check that fix frequency is acceptable with thermo output frequency - for (i = 0; i < nfix; i++) { + for (int i = 0; i < nfix; i++) { fixes[i] = modify->get_fix_by_id(id_fix[i]); if (!fixes[i]) error->all(FLERR,"Could not find thermo fix ID {}",id_fix[i]); @@ -285,12 +268,9 @@ void Thermo::init() // find current ptr for each Variable ID - int ivariable; - for (i = 0; i < nvariable; i++) { - ivariable = input->variable->find(id_variable[i]); - if (ivariable < 0) - error->all(FLERR,"Could not find thermo variable name"); - variables[i] = ivariable; + for (int i = 0; i < nvariable; i++) { + variables[i] = input->variable->find(id_variable[i]); + if (variables[i] < 0) error->all(FLERR,"Could not find thermo variable {}",id_variable[i]); } // set ptrs to keyword-specific Compute objects @@ -301,16 +281,53 @@ void Thermo::init() if (index_pe >= 0) pe = computes[index_pe]; } -/* ---------------------------------------------------------------------- */ +/* ---------------------------------------------------------------------- + Print thermo style header text + if thermo style "multi": + nothing + + if thermo style "one": + ... + each column head is centered with default formatting + width should match the width of the default format string + + if thermo style "yaml": + --- + keywords: [ , , ...] + data: + + ---------------------------------------------------------------------- */ void Thermo::header() { if (lineflag == MULTILINE) return; std::string hdr; - for (int i = 0; i < nfield; i++) hdr += keyword[i] + std::string(" "); + if (lineflag == YAMLLINE) hdr = "---\nkeywords: ["; + for (int i = 0; i < nfield; i++) { + if (lineflag == ONELINE) { + if (vtype[i] == FLOAT) + hdr += fmt::format("{:^12} ", keyword[i]); + else if ((vtype[i] == INT) || (vtype[i] == BIGINT)) + hdr += fmt::format("{:^10} ", keyword[i]); + } else if (lineflag == YAMLLINE) { + hdr += keyword[i]; + hdr += ", "; + } + } + if (lineflag == YAMLLINE) + hdr += "]\ndata:"; + else + hdr.resize(hdr.size()-1); // chop off trailing blank - if (me == 0) utils::logmesg(lmp,hdr+"\n"); + if (comm->me == 0) utils::logmesg(lmp,hdr+"\n"); +} + +/* ---------------------------------------------------------------------- */ + +void Thermo::footer() +{ + if (lineflag == YAMLLINE) utils::logmesg(lmp,"...\n"); } /* ---------------------------------------------------------------------- */ @@ -351,29 +368,33 @@ void Thermo::compute(int flag) // if lineflag = MULTILINE, prepend step/cpu header line - int loc = 0; + line.clear(); if (lineflag == MULTILINE) { double cpu; if (flag) cpu = timer->elapsed(Timer::TOTAL); else cpu = 0.0; - loc = sprintf(&line[loc],format_multi,ntimestep,cpu); + line += fmt::format(FORMAT_MULTI_HEADER, ntimestep, cpu); } // add each thermo value to line with its specific format for (ifield = 0; ifield < nfield; ifield++) { (this->*vfunc[ifield])(); - if (vtype[ifield] == FLOAT) - loc += sprintf(&line[loc],format[ifield],dvalue); - else if (vtype[ifield] == INT) - loc += sprintf(&line[loc],format[ifield],ivalue); - else if (vtype[ifield] == BIGINT) - loc += sprintf(&line[loc],format[ifield],bivalue); + if (vtype[ifield] == FLOAT) { + snprintf(fmtbuf, sizeof(fmtbuf), format[ifield].c_str(), dvalue); + line += fmtbuf; + } else if (vtype[ifield] == INT) { + snprintf(fmtbuf, sizeof(fmtbuf), format[ifield].c_str(), ivalue); + line += fmtbuf; + } else if (vtype[ifield] == BIGINT) { + snprintf(fmtbuf, sizeof(fmtbuf), format[ifield].c_str(), bivalue); + line += fmtbuf; + } } // print line to screen and logfile - if (me == 0) { + if (comm->me == 0) { utils::logmesg(lmp,line); if (flushflag) utils::flush_buffers(lmp); } @@ -432,14 +453,12 @@ bigint Thermo::lost_check() // error message if (lostflag == Thermo::ERROR) - error->all(FLERR,"Lost atoms: original {} current {}", - atom->natoms,ntotal[0]); + error->all(FLERR,"Lost atoms: original {} current {}",atom->natoms,ntotal[0]); // warning message - if (me == 0) - error->warning(FLERR,"Lost atoms: original {} current {}", - atom->natoms,ntotal[0]); + if (comm->me == 0) + error->warning(FLERR,"Lost atoms: original {} current {}",atom->natoms,ntotal[0]); // reset total atom count @@ -498,11 +517,11 @@ void Thermo::modify_params(int narg, char **arg) error->all(FLERR,"Thermo style does not use press"); if (index_press_scalar >= 0) { - delete [] id_compute[index_press_scalar]; + delete[] id_compute[index_press_scalar]; id_compute[index_press_scalar] = utils::strdup(arg[iarg+1]); } if (index_press_vector >= 0) { - delete [] id_compute[index_press_vector]; + delete[] id_compute[index_press_vector]; id_compute[index_press_vector] = utils::strdup(arg[iarg+1]); } @@ -560,6 +579,7 @@ void Thermo::modify_params(int narg, char **arg) if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (strcmp(arg[iarg+1],"one") == 0) lineflag = ONELINE; else if (strcmp(arg[iarg+1],"multi") == 0) lineflag = MULTILINE; + else if (strcmp(arg[iarg+1],"yaml") == 0) lineflag = YAMLLINE; else error->all(FLERR,"Illegal thermo_modify command"); iarg += 2; @@ -567,18 +587,12 @@ void Thermo::modify_params(int narg, char **arg) if (iarg+2 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (strcmp(arg[iarg+1],"none") == 0) { - delete [] format_line_user; - delete [] format_int_user; - delete [] format_bigint_user; - delete [] format_float_user; - format_line_user = nullptr; - format_int_user = nullptr; - format_bigint_user = nullptr; - format_float_user = nullptr; - for (int i = 0; i < nfield_initial+1; i++) { - delete [] format_column_user[i]; - format_column_user[i] = nullptr; - } + format_line_user.clear(); + format_int_user.clear(); + format_bigint_user.clear(); + format_float_user.clear(); + for (int i = 0; i < nfield_initial+1; ++i) + format_column_user[i].clear(); iarg += 2; continue; } @@ -586,33 +600,22 @@ void Thermo::modify_params(int narg, char **arg) if (iarg+3 > narg) error->all(FLERR,"Illegal thermo_modify command"); if (strcmp(arg[iarg+1],"line") == 0) { - delete [] format_line_user; - format_line_user = utils::strdup(arg[iarg+2]); + format_line_user = arg[iarg+2]; } else if (strcmp(arg[iarg+1],"int") == 0) { - if (format_int_user) delete [] format_int_user; - format_int_user = utils::strdup(arg[iarg+2]); - if (format_bigint_user) delete [] format_bigint_user; + format_int_user = arg[iarg+2]; // replace "d" in format_int_user with bigint format specifier - char *ptr = strchr(format_int_user,'d'); - if (ptr == nullptr) - error->all(FLERR, - "Thermo_modify int format does not contain d character"); - - *ptr = '\0'; - std::string fnew = fmt::format("{}{}{}",format_int_user, - std::string(BIGINT_FORMAT).substr(1), - ptr+1); - format_bigint_user = utils::strdup(fnew); - *ptr = 'd'; + auto found = format_int_user.find('%'); + found = format_int_user.find('d', found); + if (found == std::string::npos) + error->all(FLERR,"Thermo_modify int format does not contain a d conversion character"); + format_bigint_user = format_int_user.replace(found, 1, std::string(BIGINT_FORMAT).substr(1)); } else if (strcmp(arg[iarg+1],"float") == 0) { - if (format_float_user) delete [] format_float_user; - format_float_user = utils::strdup(arg[iarg+2]); + format_float_user = arg[iarg+2]; } else { int i = utils::inumeric(FLERR,arg[iarg+1],false,lmp) - 1; if (i < 0 || i >= nfield_initial+1) error->all(FLERR,"Illegal thermo_modify command"); - if (format_column_user[i]) delete [] format_column_user[i]; - format_column_user[i] = utils::strdup(arg[iarg+2]); + format_column_user[i] = arg[iarg+2]; } iarg += 3; @@ -628,18 +631,20 @@ void Thermo::allocate() { // n = specified fields + Volume field (added at run time) - int n = nfield_initial + 1; + const int n = nfield_initial + 1; + + keyword.resize(n); + format.resize(n); + format_column_user.resize(n); + for (int i = 0; i < n; i++) { + keyword[i].clear(); + format[i].clear(); + format_column_user[i].clear(); + } - keyword = new char*[n]; - for (int i = 0; i < n; i++) keyword[i] = nullptr; vfunc = new FnPtr[n]; vtype = new int[n]; - format = new char*[n]; - for (int i = 0; i < n; i++) format[i] = new char[32]; - format_column_user = new char*[n]; - for (int i = 0; i < n; i++) format_column_user[i] = nullptr; - field2index = new int[n]; argindex1 = new int[n]; argindex2 = new int[n]; @@ -666,34 +671,25 @@ void Thermo::allocate() void Thermo::deallocate() { - int n = nfield_initial + 1; + delete[] vfunc; + delete[] vtype; - for (int i = 0; i < n; i++) delete [] keyword[i]; - delete [] keyword; - delete [] vfunc; - delete [] vtype; + delete[] field2index; + delete[] argindex1; + delete[] argindex2; - for (int i = 0; i < n; i++) delete [] format[i]; - delete [] format; - for (int i = 0; i < n; i++) delete [] format_column_user[i]; - delete [] format_column_user; + for (int i = 0; i < ncompute; i++) delete[] id_compute[i]; + delete[] id_compute; + delete[] compute_which; + delete[] computes; - delete [] field2index; - delete [] argindex1; - delete [] argindex2; + for (int i = 0; i < nfix; i++) delete[] id_fix[i]; + delete[] id_fix; + delete[] fixes; - for (int i = 0; i < ncompute; i++) delete [] id_compute[i]; - delete [] id_compute; - delete [] compute_which; - delete [] computes; - - for (int i = 0; i < nfix; i++) delete [] id_fix[i]; - delete [] id_fix; - delete [] fixes; - - for (int i = 0; i < nvariable; i++) delete [] id_variable[i]; - delete [] id_variable; - delete [] variables; + for (int i = 0; i < nvariable; i++) delete[] id_variable[i]; + delete[] id_variable; + delete[] variables; } /* ---------------------------------------------------------------------- @@ -701,11 +697,11 @@ void Thermo::deallocate() set compute flags (temp, press, pe, etc) ------------------------------------------------------------------------- */ -void Thermo::parse_fields(char *str) +void Thermo::parse_fields(const std::string &str) { nfield = 0; - // customize a new keyword by adding to if statement + // CUSTOMIZATION: add a new thermo keyword by adding it to the if statements ValueTokenizer keywords(str); while (keywords.has_next()) { @@ -983,8 +979,7 @@ void Thermo::parse_fields(char *str) void Thermo::addfield(const char *key, FnPtr func, int typeflag) { - delete[] keyword[nfield]; - keyword[nfield] = utils::strdup(key); + keyword[nfield] = key; vfunc[nfield] = func; vtype[nfield] = typeflag; nfield++; @@ -1037,7 +1032,7 @@ int Thermo::add_variable(const char *id) called when a variable is evaluated by Variable class return value as double in answer return 0 if str is recognized keyword, 1 if unrecognized - customize a new keyword by adding to if statement + CUSTOMIZATION: add a new keyword by adding a suitable if statement ------------------------------------------------------------------------- */ int Thermo::evaluate_keyword(const char *word, double *answer) @@ -1067,15 +1062,13 @@ int Thermo::evaluate_keyword(const char *word, double *answer) } else if (strcmp(word,"elapsed") == 0) { if (update->whichflag == 0) - error->all(FLERR, - "This variable thermo keyword cannot be used between runs"); + error->all(FLERR,"This variable thermo keyword cannot be used between runs"); compute_elapsed(); dvalue = bivalue; } else if (strcmp(word,"elaplong") == 0) { if (update->whichflag == 0) - error->all(FLERR, - "This variable thermo keyword cannot be used between runs"); + error->all(FLERR,"This variable thermo keyword cannot be used between runs"); compute_elapsed_long(); dvalue = bivalue; @@ -1577,7 +1570,7 @@ void Thermo::compute_variable() called by compute() or evaluate_keyword() compute will have already been called set ivalue/dvalue/bivalue if value is int/double/bigint - customize a new keyword by adding a method + CUSTOMIZATION: add a new thermo keyword by adding a new method ------------------------------------------------------------------------- */ void Thermo::compute_step() @@ -2215,4 +2208,3 @@ void Thermo::compute_cellgamma() dvalue = acos(cosgamma)*180.0/MY_PI; } } - diff --git a/src/thermo.h b/src/thermo.h index 9eca4df18b..2f69b501c0 100644 --- a/src/thermo.h +++ b/src/thermo.h @@ -39,26 +39,16 @@ class Thermo : protected Pointers { bigint lost_check(); void modify_params(int, char **); void header(); + void footer(); void compute(int); int evaluate_keyword(const char *, double *); private: - char *line; - char **keyword; - int *vtype; - int nfield, nfield_initial; - int me; - - char **format; - char *format_line_user; - char *format_float_user, *format_int_user, *format_bigint_user; - char **format_column_user; - - char *format_float_one_def, *format_float_multi_def; - char *format_int_one_def, *format_int_multi_def; - char format_multi[128]; - char format_bigint_one_def[8], format_bigint_multi_def[8]; + int *vtype; + std::string line; + std::vector keyword, format, format_column_user; + std::string format_line_user, format_float_user, format_int_user, format_bigint_user; int normvalue; // use this for normflag unless natoms = 0 int normuserflag; // 0 if user has not set, 1 if has @@ -88,7 +78,6 @@ class Thermo : protected Pointers { // id = ID of Compute objects // Compute * = ptrs to the Compute objects int index_temp, index_press_scalar, index_press_vector, index_pe; - char *id_temp, *id_press, *id_pe; class Compute *temperature, *pressure, *pe; int ncompute; // # of Compute objects called by thermo @@ -109,7 +98,7 @@ class Thermo : protected Pointers { void allocate(); void deallocate(); - void parse_fields(char *); + void parse_fields(const std::string &); int add_compute(const char *, int); int add_fix(const char *); int add_variable(const char *);