refactor thermo output processing and add new yaml thermo style

This commit is contained in:
Axel Kohlmeyer
2022-03-19 16:39:09 -04:00
parent 3f28768b5e
commit f5ebfbf90b
8 changed files with 397 additions and 415 deletions

View File

@ -32,18 +32,20 @@ The content and format of what is printed is controlled by the
:doc:`thermo_style <thermo_style>` and
:doc:`thermo_modify <thermo_modify>` commands.
Instead of a numeric value, N can be specified as an :doc:`equal-style variable <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 <variable>`, 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 <variable>`.
Instead of a numeric value, N can be specified as an :doc:`equal-style
variable <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 <variable>`, 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 <variable>`.
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

View File

@ -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 <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 <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 <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 <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 <thermo_style>` command, the page for the individual
:doc:`fix <fix>` or :doc:`compute <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
<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 <thermo_style>` command, the
page for the individual :doc:`fix <fix>` or :doc:`compute <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 <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 <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 <compute>` command and it must be a style of
compute that calculates a temperature. As described in the
:doc:`thermo_style <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 <compute>` command and it must be a style of compute that
calculates a pressure. As described in the
:doc:`thermo_style <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
<compute>` command and it must be a style of compute that calculates a
pressure. As described in the :doc:`thermo_style <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 <compute_pressure>` 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 <compute_pressure>` 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".

View File

@ -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
<https://yaml.org/>`_ 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

View File

@ -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);

View File

@ -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

View File

@ -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<bigint> ((nexttime - tcurrent - EPSDT*update->dt) /
update->dt) + 1;
static_cast<bigint> ((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<bigint> ((nexttime - tcurrent - EPSDT*update->dt) /
update->dt) + 1;
static_cast<bigint> ((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<bigint> ((nexttime - tcurrent - EPSDT*update->dt) /
update->dt) + 1;
static_cast<bigint> ((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]);

View File

@ -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":
<keyword1> <keyword2> <keyword3> ...
each column head is centered with default formatting
width should match the width of the default format string
if thermo style "yaml":
---
keywords: [ <keyword1>, <keyword2>, <keyword3> ...]
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;
}
}

View File

@ -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<std::string> 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 *);