Merge pull request #4287 from akohlmey/collected-small-fixes

Collected small fixes and updates for LAMMPS and LAMMPS-GUI
This commit is contained in:
Axel Kohlmeyer
2024-08-21 17:51:58 -04:00
committed by GitHub
22 changed files with 572 additions and 418 deletions

View File

@ -34,18 +34,20 @@ choose, including for commercial purposes.
(2) If you **distribute** a modified version of LAMMPS, it must remain
open-source, meaning you are required to distribute **all** of it under
the terms of the GPL. You should clearly annotate such a modified code
as a derivative version of LAMMPS.
the terms of the GPLv2. You should **clearly** annotate such a modified
code as a derivative version of LAMMPS. This is best done by changing
the name (example: LIGGGHTS is such a modified and extended version of
LAMMPS).
(3) If you release any code that includes or uses LAMMPS source code,
then it must also be open-sourced, meaning you distribute it under
the terms of the GPL. You may write code that interfaces LAMMPS to
a differently licensed library. In that case the code that provides
the interface must be licensed GPL, but not necessarily that library
then it must also be open-sourced, meaning you distribute it under the
terms of the GPLv2. You may write code that interfaces LAMMPS to a
differently licensed library. In that case the code that provides the
interface must be licensed GPLv2, but not necessarily that library
unless you are distributing binaries that require the library to run.
(4) If you give LAMMPS files to someone else, the GPL LICENSE file and
source file headers (including the copyright and GPL notices) should
(4) If you give LAMMPS files to someone else, the GPLv2 LICENSE file and
source file headers (including the copyright and GPLv2 notices) should
remain part of the code.

View File

@ -2,7 +2,12 @@
LAMMPS Documentation (|version| version)
########################################
**About LAMMPS and this manual**
.. toctree::
:caption: About LAMMPS
****************************
About LAMMPS and this manual
****************************
LAMMPS stands for **L**\ arge-scale **A**\ tomic/**M**\ olecular
**M**\ assively **P**\ arallel **S**\ imulator.

View File

@ -271,6 +271,8 @@ The value of the *page* setting must be at least 10x larger than the
*one* setting. This ensures neighbor pages are not mostly empty
space.
The *exclude group* setting is currently not compatible with dynamic groups.
Related commands
""""""""""""""""

View File

@ -90,6 +90,16 @@ def get_lammps_version():
end_pos = line.find('"', start_pos)
return line[start_pos:end_pos]
def get_lammps_update():
import os
script_dir = os.path.dirname(os.path.realpath(__file__))
with open(os.path.join(LAMMPS_SOURCE_DIR, 'version.h'), 'r') as f:
line = f.readline()
line = f.readline()
start_pos = line.find('"')+1
end_pos = line.find('"', start_pos)
return line[start_pos:end_pos]
def get_git_info():
import subprocess,time
@ -97,10 +107,10 @@ def get_git_info():
try:
gitinfo = subprocess.run(['git','describe'],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
if gitinfo.returncode == 0:
git_n_date = gitinfo.stdout.decode().replace('_',' ').replace('patch ','')
git_n_date = gitinfo.stdout.decode().replace('_',' ').replace('patch ','').replace('stable ','')
except:
pass
return git_n_date
return git_n_date.strip()
def get_git_commit():
import subprocess,time
@ -290,6 +300,16 @@ rst_prolog = r"""
# -- Options for LaTeX output ---------------------------------------------
latex_engine = 'pdflatex'
if (get_lammps_update() == 'Development') or (get_lammps_update() == 'Maintenance'):
if get_git_info() == '':
lammpsversion = format("\\newcommand{\\lammpsversion}{%s %s}\n" \
% (get_lammps_update(), get_lammps_version()))
else:
lammpsversion = format("\\newcommand{\\lammpsversion}{Git: %s}\n" % (get_git_info()))
else:
lammpsversion = format("\\newcommand{\\lammpsversion}{Release %s %s}\n" \
% (get_lammps_version(), get_lammps_update()))
latex_elements = {
# The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper',
@ -300,6 +320,7 @@ latex_elements = {
# Additional stuff for the LaTeX preamble.
'preamble': r'''
\setcounter{tocdepth}{2}
\setcounter{part}{-1}
\renewcommand{\sfdefault}{ptm} % Use Times New Roman font for \textrm
\renewcommand{\sfdefault}{phv} % Use Helvetica font for \textsf
\usepackage[columns=1]{idxlayout} % create index with only one column
@ -338,6 +359,7 @@ latex_elements = {
% Make ToC number fields wider to accommodate sections with >= 100 subsections
% or >= 10 subsections with >= 10 subsubsections
\makeatletter
% reset chapter counter for each part
\@addtoreset{chapter}{part}
\renewcommand*{\sphinxtableofcontentshook}{%
\renewcommand*\l@section{\@dottedtocline{1}{1.5em}{3.1em}}
@ -345,6 +367,38 @@ latex_elements = {
}
\makeatother
''',
'maketitle': lammpsversion + r'''
% customized titlepage
{%
\hypersetup{pageanchor=false}% avoid duplicate destination warnings
\begin{titlepage}%
\sffamily\bfseries
\begingroup % for PDF information dictionary
\def\endgraf{ }\def\and{\& }%
\pdfstringdefDisableCommands{\def\\{, }}% overwrite hyperref setup
\hypersetup{pdfauthor={The LAMMPS Developers}, pdftitle={LAMMPS Documentation}}%
\endgroup
\noindent\rule{\textwidth}{4pt}\par
\begin{center}%
\sphinxlogo
\vfill
{\Huge LAMMPS Documentation \par}
\vfill
{\LARGE \lammpsversion \par}
\vfill
{\LARGE The LAMMPS Developers \par}
{\Large developers@lammps.org $^*$ \par}
\vfill\vfill\vfill
{\normalsize ${}^*$ see
\sphinxhref{https://www.lammps.org/authors.html}{https://www.lammps.org/authors.html}
for details \par}
\end{center}
\noindent\rule{\textwidth}{4pt}\par
\end{titlepage}%
\setcounter{footnote}{0}%
\clearpage
}
''',
}
# copy custom style file for tweaking index layout
@ -364,19 +418,13 @@ latex_documents = [
# the title page.
latex_logo = "_static/lammps-logo-large.jpg"
# For "manual" documents, if this is true, then toplevel headings are parts,
# not chapters.
#latex_use_parts = False
latex_toplevel_sectioning = 'part'
# If true, show page references after internal links.
#latex_show_pagerefs = False
# If true, show URL addresses after external links.
latex_show_urls = 'no'
# latex_show_urls = 'footnote'
# Documents to append as an appendix to all manuals.
#latex_appendices = []
# If false, no module index is generated.
latex_domain_indices = False

View File

@ -35,7 +35,7 @@ using namespace MathSpecial;
PairMorseSoft::~PairMorseSoft()
{
if (allocated) { memory->destroy(lambda); }
if (allocated) memory->destroy(lambda);
}
/* ---------------------------------------------------------------------- */

View File

@ -1,4 +1,3 @@
// clang-format off
/* ----------------------------------------------------------------------
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
https://www.lammps.org/, Sandia National Laboratories
@ -20,18 +19,18 @@
#include "domain.h"
#include "dump.h"
#include "error.h"
#include "exceptions.h"
#include "fix.h"
#include "force.h"
#include "input.h"
#include "math_extra.h"
#include "math_eigen.h"
#include "math_extra.h"
#include "memory.h"
#include "modify.h"
#include "output.h"
#include "region.h"
#include "tokenizer.h"
#include "variable.h"
#include "exceptions.h"
#include <cmath>
#include <cstring>
@ -93,8 +92,7 @@ void Group::assign(int narg, char **arg)
{
int i;
if (domain->box_exist == 0)
error->all(FLERR,"Group command before simulation box is defined");
if (domain->box_exist == 0) error->all(FLERR, "Group command before simulation box is defined");
if (narg < 2) utils::missing_cmd_args(FLERR, "group", error);
// delete the group if not being used elsewhere
@ -122,8 +120,7 @@ void Group::assign(int narg, char **arg)
int bits = inversemask[igroup];
for (i = 0; i < nlocal; i++) mask[i] &= bits;
if (dynamic[igroup])
modify->delete_fix(std::string("GROUP_") + names[igroup]);
if (dynamic[igroup]) modify->delete_fix(std::string("GROUP_") + names[igroup]);
delete[] names[igroup];
names[igroup] = nullptr;
@ -181,8 +178,7 @@ void Group::assign(int narg, char **arg)
region->prematch();
for (i = 0; i < nlocal; i++)
if (region->match(x[i][0],x[i][1],x[i][2]))
mask[i] |= bit;
if (region->match(x[i][0], x[i][1], x[i][2])) mask[i] |= bit;
// create an empty group
@ -200,9 +196,12 @@ void Group::assign(int narg, char **arg)
if (narg < 3) utils::missing_cmd_args(FLERR, std::string("group ") + arg[1], error);
int category = NONE;
if (strcmp(arg[1],"type") == 0) category = TYPE;
else if (strcmp(arg[1],"molecule") == 0) category = MOLECULE;
else if (strcmp(arg[1],"id") == 0) category = ID;
if (strcmp(arg[1], "type") == 0)
category = TYPE;
else if (strcmp(arg[1], "molecule") == 0)
category = MOLECULE;
else if (strcmp(arg[1], "id") == 0)
category = ID;
if ((category == MOLECULE) && (!atom->molecule_flag))
error->all(FLERR, "Group molecule command requires atom attribute molecule");
@ -213,39 +212,52 @@ void Group::assign(int narg, char **arg)
// args = logical condition
if (narg > 3 &&
(strcmp(arg[2],"<") == 0 || strcmp(arg[2],">") == 0 ||
strcmp(arg[2],"<=") == 0 || strcmp(arg[2],">=") == 0 ||
strcmp(arg[2],"==") == 0 || strcmp(arg[2],"!=") == 0 ||
(strcmp(arg[2], "<") == 0 || strcmp(arg[2], ">") == 0 || strcmp(arg[2], "<=") == 0 ||
strcmp(arg[2], ">=") == 0 || strcmp(arg[2], "==") == 0 || strcmp(arg[2], "!=") == 0 ||
strcmp(arg[2], "<>") == 0)) {
int condition = -1;
if (strcmp(arg[2],"<") == 0) condition = LT;
else if (strcmp(arg[2],"<=") == 0) condition = LE;
else if (strcmp(arg[2],">") == 0) condition = GT;
else if (strcmp(arg[2],">=") == 0) condition = GE;
else if (strcmp(arg[2],"==") == 0) condition = EQ;
else if (strcmp(arg[2],"!=") == 0) condition = NEQ;
else if (strcmp(arg[2],"<>") == 0) condition = BETWEEN;
else error->all(FLERR,"Illegal group command");
if (strcmp(arg[2], "<") == 0)
condition = LT;
else if (strcmp(arg[2], "<=") == 0)
condition = LE;
else if (strcmp(arg[2], ">") == 0)
condition = GT;
else if (strcmp(arg[2], ">=") == 0)
condition = GE;
else if (strcmp(arg[2], "==") == 0)
condition = EQ;
else if (strcmp(arg[2], "!=") == 0)
condition = NEQ;
else if (strcmp(arg[2], "<>") == 0)
condition = BETWEEN;
else
error->all(FLERR, "Illegal group command");
tagint bound1, bound2;
if (category == TYPE)
bound1 = (tagint) utils::expand_type_int(FLERR, arg[3], Atom::ATOM, lmp);
else bound1 = utils::tnumeric(FLERR, arg[3], false, lmp);
else
bound1 = utils::tnumeric(FLERR, arg[3], false, lmp);
bound2 = -1;
if (condition == BETWEEN) {
if (narg != 5) error->all(FLERR, "Illegal group command");
if (category == TYPE)
bound2 = (tagint) utils::expand_type_int(FLERR, arg[4], Atom::ATOM, lmp);
else bound2 = utils::tnumeric(FLERR, arg[4], false, lmp);
} else if (narg != 4) error->all(FLERR,"Illegal group command");
else
bound2 = utils::tnumeric(FLERR, arg[4], false, lmp);
} else if (narg != 4)
error->all(FLERR, "Illegal group command");
int *attribute = nullptr;
tagint *tattribute = nullptr;
if (category == TYPE) attribute = atom->type;
else if (category == MOLECULE) tattribute = atom->molecule;
else if (category == ID) tattribute = atom->tag;
if (category == TYPE)
attribute = atom->type;
else if (category == MOLECULE)
tattribute = atom->molecule;
else if (category == ID)
tattribute = atom->tag;
// add to group if meets condition
@ -270,8 +282,7 @@ void Group::assign(int narg, char **arg)
if (attribute[i] != bound1) mask[i] |= bit;
} else if (condition == BETWEEN) {
for (i = 0; i < nlocal; i++)
if (attribute[i] >= bound1 && attribute[i] <= bound2)
mask[i] |= bit;
if (attribute[i] >= bound1 && attribute[i] <= bound2) mask[i] |= bit;
}
} else {
if (condition == LT) {
@ -294,8 +305,7 @@ void Group::assign(int narg, char **arg)
if (tattribute[i] != bound1) mask[i] |= bit;
} else if (condition == BETWEEN) {
for (i = 0; i < nlocal; i++)
if (tattribute[i] >= bound1 && tattribute[i] <= bound2)
mask[i] |= bit;
if (tattribute[i] >= bound1 && tattribute[i] <= bound2) mask[i] |= bit;
}
}
@ -304,9 +314,12 @@ void Group::assign(int narg, char **arg)
} else {
int *attribute = nullptr;
tagint *tattribute = nullptr;
if (category == TYPE) attribute = atom->type;
else if (category == MOLECULE) tattribute = atom->molecule;
else if (category == ID) tattribute = atom->tag;
if (category == TYPE)
attribute = atom->type;
else if (category == MOLECULE)
tattribute = atom->molecule;
else if (category == ID)
tattribute = atom->tag;
char *typestr = nullptr;
tagint start, stop, delta;
@ -329,12 +342,12 @@ void Group::assign(int narg, char **arg)
} else if (utils::strmatch(arg[iarg], "^-?\\d+:-?\\d+:\\d+$")) {
stop = values.next_tagint();
delta = values.next_tagint();
} else throw TokenizerException("Syntax error","");
} else
throw TokenizerException("Syntax error", "");
} catch (TokenizerException &e) {
error->all(FLERR, "Incorrect range string '{}': {}", arg[iarg], e.what());
}
if (delta < 1)
error->all(FLERR,"Illegal range increment value");
if (delta < 1) error->all(FLERR, "Illegal range increment value");
}
// add to group if attribute matches value or sequence
@ -342,11 +355,13 @@ void Group::assign(int narg, char **arg)
if (attribute) {
for (i = 0; i < nlocal; i++)
if (attribute[i] >= start && attribute[i] <= stop &&
(attribute[i]-start) % delta == 0) mask[i] |= bit;
(attribute[i] - start) % delta == 0)
mask[i] |= bit;
} else {
for (i = 0; i < nlocal; i++)
if (tattribute[i] >= start && tattribute[i] <= stop &&
(tattribute[i]-start) % delta == 0) mask[i] |= bit;
(tattribute[i] - start) % delta == 0)
mask[i] |= bit;
}
}
@ -388,7 +403,8 @@ void Group::assign(int narg, char **arg)
add_molecules(igroup, bit);
} else error->all(FLERR,"Unknown group include keyword {}",arg[2]);
} else
error->all(FLERR, "Unknown group include keyword {}", arg[2]);
// style = subtract
@ -465,8 +481,7 @@ void Group::assign(int narg, char **arg)
for (int iarg = 2; iarg < narg; iarg++) {
jgroup = find(arg[iarg]);
if (jgroup == -1) error->all(FLERR, "Group ID {} does not exist", arg[iarg]);
if (dynamic[jgroup])
error->all(FLERR,"Cannot intersect groups using a dynamic group");
if (dynamic[jgroup]) error->all(FLERR, "Cannot intersect groups using a dynamic group");
list[iarg - 2] = jgroup;
}
@ -489,16 +504,14 @@ void Group::assign(int narg, char **arg)
} else if (strcmp(arg[1], "dynamic") == 0) {
if (narg < 4) error->all(FLERR, "Illegal group command");
if (strcmp(arg[0],arg[2]) == 0)
error->all(FLERR,"Group dynamic cannot reference itself");
if (strcmp(arg[0], arg[2]) == 0) error->all(FLERR, "Group dynamic cannot reference itself");
if (find(arg[2]) < 0)
error->all(FLERR, "Group dynamic parent group {} does not exist", arg[2]);
if (igroup == 0) error->all(FLERR, "Group all cannot be made dynamic");
// if group is already dynamic, delete existing FixGroup
if (dynamic[igroup])
modify->delete_fix(std::string("GROUP_") + names[igroup]);
if (dynamic[igroup]) modify->delete_fix(std::string("GROUP_") + names[igroup]);
dynamic[igroup] = 1;
@ -514,14 +527,14 @@ void Group::assign(int narg, char **arg)
if (narg != 2) error->all(FLERR, "Illegal group static command");
if (dynamic[igroup])
modify->delete_fix(std::string("GROUP_") + names[igroup]);
if (dynamic[igroup]) modify->delete_fix(std::string("GROUP_") + names[igroup]);
dynamic[igroup] = 0;
// not a valid group style
} else error->all(FLERR,"Unknown group command keyword: {}",arg[1]);
} else
error->all(FLERR, "Unknown group command keyword: {}", arg[1]);
} catch (LAMMPSException &e) {
// undo created group in case of an error
@ -537,7 +550,8 @@ void Group::assign(int narg, char **arg)
int n;
n = 0;
for (i = 0; i < nlocal; i++) if (mask[i] & bit) n++;
for (i = 0; i < nlocal; i++)
if (mask[i] & bit) n++;
double rlocal = n;
double all;
@ -560,9 +574,7 @@ void Group::assign(const std::string &groupcmd)
auto args = utils::split_words(groupcmd);
std::vector<char *> newarg(args.size());
int i = 0;
for (const auto &arg : args) {
newarg[i++] = (char *)arg.c_str();
}
for (const auto &arg : args) { newarg[i++] = (char *) arg.c_str(); }
assign(args.size(), newarg.data());
}
@ -715,8 +727,10 @@ void Group::write_restart(FILE *fp)
int n;
int count = 0;
for (int i = 0; i < MAX_GROUP; i++) {
if (names[i]) n = strlen(names[i]) + 1;
else n = 0;
if (names[i])
n = strlen(names[i]) + 1;
else
n = 0;
fwrite(&n, sizeof(int), 1, fp);
if (n) {
fwrite(names[i], sizeof(char), n, fp);
@ -759,7 +773,8 @@ void Group::read_restart(FILE *fp)
if (me == 0) utils::sfread(FLERR, names[i], sizeof(char), n, fp, nullptr, error);
MPI_Bcast(names[i], n, MPI_CHAR, 0, world);
count++;
} else names[i] = nullptr;
} else
names[i] = nullptr;
}
}
@ -874,12 +889,10 @@ double Group::mass(int igroup, Region *region)
if (rmass) {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2]))
one += rmass[i];
if (mask[i] & groupbit && region->match(x[i][0], x[i][1], x[i][2])) one += rmass[i];
} else {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2]))
one += mass[type[i]];
if (mask[i] & groupbit && region->match(x[i][0], x[i][1], x[i][2])) one += mass[type[i]];
}
double all;
@ -924,8 +937,7 @@ double Group::charge(int igroup, Region *region)
double qone = 0.0;
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0],x[i][1],x[i][2]))
qone += q[i];
if (mask[i] & groupbit && region->match(x[i][0], x[i][1], x[i][2])) qone += q[i];
double qall;
MPI_Allreduce(&qone, &qall, 1, MPI_DOUBLE, MPI_SUM, world);
@ -1292,13 +1304,11 @@ double Group::ke(int igroup)
if (rmass) {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit)
one += (v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]) *
rmass[i];
one += (v[i][0] * v[i][0] + v[i][1] * v[i][1] + v[i][2] * v[i][2]) * rmass[i];
} else {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit)
one += (v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]) *
mass[type[i]];
one += (v[i][0] * v[i][0] + v[i][1] * v[i][1] + v[i][2] * v[i][2]) * mass[type[i]];
}
double all;
@ -1329,13 +1339,11 @@ double Group::ke(int igroup, Region *region)
if (rmass) {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0], x[i][1], x[i][2]))
one += (v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]) *
rmass[i];
one += (v[i][0] * v[i][0] + v[i][1] * v[i][1] + v[i][2] * v[i][2]) * rmass[i];
} else {
for (int i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0], x[i][1], x[i][2]))
one += (v[i][0]*v[i][0] + v[i][1]*v[i][1] + v[i][2]*v[i][2]) *
mass[type[i]];
one += (v[i][0] * v[i][0] + v[i][1] * v[i][1] + v[i][2] * v[i][2]) * mass[type[i]];
}
double all;
@ -1372,8 +1380,10 @@ double Group::gyration(int igroup, double masstotal, double *cm)
dx = unwrap[0] - cm[0];
dy = unwrap[1] - cm[1];
dz = unwrap[2] - cm[2];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
if (rmass)
massone = rmass[i];
else
massone = mass[type[i]];
rg += (dx * dx + dy * dy + dz * dz) * massone;
}
double rg_all;
@ -1412,8 +1422,10 @@ double Group::gyration(int igroup, double masstotal, double *cm, Region *region)
dx = unwrap[0] - cm[0];
dy = unwrap[1] - cm[1];
dz = unwrap[2] - cm[2];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
if (rmass)
massone = rmass[i];
else
massone = mass[type[i]];
rg += (dx * dx + dy * dy + dz * dz) * massone;
}
double rg_all;
@ -1454,8 +1466,10 @@ void Group::angmom(int igroup, double *cm, double *lmom)
dx = unwrap[0] - cm[0];
dy = unwrap[1] - cm[1];
dz = unwrap[2] - cm[2];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
if (rmass)
massone = rmass[i];
else
massone = mass[type[i]];
p[0] += massone * (dy * v[i][2] - dz * v[i][1]);
p[1] += massone * (dz * v[i][0] - dx * v[i][2]);
p[2] += massone * (dx * v[i][1] - dy * v[i][0]);
@ -1496,8 +1510,10 @@ void Group::angmom(int igroup, double *cm, double *lmom, Region *region)
dx = unwrap[0] - cm[0];
dy = unwrap[1] - cm[1];
dz = unwrap[2] - cm[2];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
if (rmass)
massone = rmass[i];
else
massone = mass[type[i]];
p[0] += massone * (dy * v[i][2] - dz * v[i][1]);
p[1] += massone * (dz * v[i][0] - dx * v[i][2]);
p[2] += massone * (dx * v[i][1] - dy * v[i][0]);
@ -1603,8 +1619,7 @@ void Group::inertia(int igroup, double *cm, double itensor[3][3])
double ione[3][3];
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
ione[i][j] = 0.0;
for (j = 0; j < 3; j++) ione[i][j] = 0.0;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit) {
@ -1612,8 +1627,10 @@ void Group::inertia(int igroup, double *cm, double itensor[3][3])
dx = unwrap[0] - cm[0];
dy = unwrap[1] - cm[1];
dz = unwrap[2] - cm[2];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
if (rmass)
massone = rmass[i];
else
massone = mass[type[i]];
ione[0][0] += massone * (dy * dy + dz * dz);
ione[1][1] += massone * (dx * dx + dz * dz);
ione[2][2] += massone * (dx * dx + dy * dy);
@ -1653,8 +1670,7 @@ void Group::inertia(int igroup, double *cm, double itensor[3][3], Region *region
double ione[3][3];
for (i = 0; i < 3; i++)
for (j = 0; j < 3; j++)
ione[i][j] = 0.0;
for (j = 0; j < 3; j++) ione[i][j] = 0.0;
for (i = 0; i < nlocal; i++)
if (mask[i] & groupbit && region->match(x[i][0], x[i][1], x[i][2])) {
@ -1662,8 +1678,10 @@ void Group::inertia(int igroup, double *cm, double itensor[3][3], Region *region
dx = unwrap[0] - cm[0];
dy = unwrap[1] - cm[1];
dz = unwrap[2] - cm[2];
if (rmass) massone = rmass[i];
else massone = mass[type[i]];
if (rmass)
massone = rmass[i];
else
massone = mass[type[i]];
ione[0][0] += massone * (dy * dy + dz * dz);
ione[1][1] += massone * (dx * dx + dz * dz);
ione[2][2] += massone * (dx * dx + dy * dy);
@ -1693,8 +1711,7 @@ void Group::omega(double *angmom, double inertia[3][3], double *w)
inertia[0][1] * inertia[1][2] * inertia[2][0] +
inertia[0][2] * inertia[1][0] * inertia[2][1] -
inertia[0][0] * inertia[1][2] * inertia[2][1] -
inertia[0][1]*inertia[1][0]*inertia[2][2] -
inertia[2][0]*inertia[1][1]*inertia[0][2];
inertia[0][1] * inertia[1][0] * inertia[2][2] - inertia[2][0] * inertia[1][1] * inertia[0][2];
// non-singular I matrix
// use L = Iw, inverting I to solve for w
@ -1703,31 +1720,23 @@ void Group::omega(double *angmom, double inertia[3][3], double *w)
if (determinant > EPSILON) {
inverse[0][0] = inertia[1][1] * inertia[2][2] - inertia[1][2] * inertia[2][1];
inverse[0][1] = -(inertia[0][1]*inertia[2][2] -
inertia[0][2]*inertia[2][1]);
inverse[0][1] = -(inertia[0][1] * inertia[2][2] - inertia[0][2] * inertia[2][1]);
inverse[0][2] = inertia[0][1] * inertia[1][2] - inertia[0][2] * inertia[1][1];
inverse[1][0] = -(inertia[1][0]*inertia[2][2] -
inertia[1][2]*inertia[2][0]);
inverse[1][0] = -(inertia[1][0] * inertia[2][2] - inertia[1][2] * inertia[2][0]);
inverse[1][1] = inertia[0][0] * inertia[2][2] - inertia[0][2] * inertia[2][0];
inverse[1][2] = -(inertia[0][0]*inertia[1][2] -
inertia[0][2]*inertia[1][0]);
inverse[1][2] = -(inertia[0][0] * inertia[1][2] - inertia[0][2] * inertia[1][0]);
inverse[2][0] = inertia[1][0] * inertia[2][1] - inertia[1][1] * inertia[2][0];
inverse[2][1] = -(inertia[0][0]*inertia[2][1] -
inertia[0][1]*inertia[2][0]);
inverse[2][1] = -(inertia[0][0] * inertia[2][1] - inertia[0][1] * inertia[2][0]);
inverse[2][2] = inertia[0][0] * inertia[1][1] - inertia[0][1] * inertia[1][0];
for (int i = 0; i < 3; i++)
for (int j = 0; j < 3; j++)
inverse[i][j] /= determinant;
for (int j = 0; j < 3; j++) inverse[i][j] /= determinant;
w[0] = inverse[0][0]*angmom[0] + inverse[0][1]*angmom[1] +
inverse[0][2]*angmom[2];
w[1] = inverse[1][0]*angmom[0] + inverse[1][1]*angmom[1] +
inverse[1][2]*angmom[2];
w[2] = inverse[2][0]*angmom[0] + inverse[2][1]*angmom[1] +
inverse[2][2]*angmom[2];
w[0] = inverse[0][0] * angmom[0] + inverse[0][1] * angmom[1] + inverse[0][2] * angmom[2];
w[1] = inverse[1][0] * angmom[0] + inverse[1][1] * angmom[1] + inverse[1][2] * angmom[2];
w[2] = inverse[2][0] * angmom[0] + inverse[2][1] * angmom[1] + inverse[2][2] * angmom[2];
// handle (nearly) singular I matrix
// typically due to 2-atom group or linear molecule

View File

@ -2059,6 +2059,7 @@ void Molecule::deallocate()
memory->destroy(type);
memory->destroy(molecule);
memory->destroy(q);
memory->destroy(mu);
memory->destroy(radius);
memory->destroy(rmass);

View File

@ -2722,6 +2722,8 @@ void Neighbor::modify_params(int narg, char **arg)
error->all(FLERR, "Invalid exclude group keyword: group {} not found", arg[iarg+2]);
if (ex2_group[nex_group] == -1)
error->all(FLERR, "Invalid exclude group keyword: group {} not found", arg[iarg+3]);
if (group->dynamic[ex1_group[nex_group]] || group->dynamic[ex2_group[nex_group]])
error->all(FLERR, "Neigh_modify exclude group is not compatible with dynamic groups");
nex_group++;
iarg += 4;
} else if (strcmp(arg[iarg+1],"molecule/inter") == 0 ||

View File

@ -77,7 +77,7 @@ Output::Output(LAMMPS *lmp) : Pointers(lmp)
ndump = 0;
max_dump = 0;
any_time_dumps = 0;
next_dump_any = next_time_dump_any = MAXBIGINT;
next_thermo = next_restart = next_dump_any = next_time_dump_any = MAXBIGINT;
mode_dump = nullptr;
every_dump = nullptr;
every_time_dump = nullptr;

View File

@ -254,6 +254,7 @@ void PairHybridScaled::settings(int narg, char **arg)
delete[] special_coul[m];
}
delete[] styles;
delete[] cutmax_style;
delete[] keywords;
delete[] multiple;
delete[] special_lj;

View File

@ -48,6 +48,7 @@ TextFileReader::TextFileReader(const std::string &filename, const std::string &f
fp = fopen(filename.c_str(), "r");
if (fp == nullptr) {
delete[] line;
throw FileReaderException(
fmt::format("cannot open {} file {}: {}", filetype, filename, utils::getsyserror()));
}
@ -74,14 +75,21 @@ TextFileReader::TextFileReader(FILE *fp, std::string filetype) :
filetype(std::move(filetype)), closefp(false), line(nullptr), fp(fp), ignore_comments(true)
{
set_bufsize(1024);
if (fp == nullptr) throw FileReaderException("Invalid file descriptor");
if (fp == nullptr) {
delete[] line;
line = nullptr;
throw FileReaderException("Invalid file descriptor");
}
}
/** Closes the file */
TextFileReader::~TextFileReader()
{
if (closefp) fclose(fp);
if (closefp) {
if (fp) fclose(fp);
fp = nullptr;
}
delete[] line;
}
@ -90,6 +98,12 @@ TextFileReader::~TextFileReader()
void TextFileReader::set_bufsize(int newsize)
{
if (newsize < 100) {
delete[] line;
line = nullptr;
if (closefp) {
fclose(fp);
fp = nullptr;
}
throw FileReaderException(
fmt::format("line buffer size {} for {} file too small, must be > 100", newsize, filetype));
}
@ -109,9 +123,16 @@ void TextFileReader::rewind()
void TextFileReader::skip_line()
{
if (!line) return;
char *ptr = fgets(line, bufsize, fp);
if (ptr == nullptr) {
// EOF
delete[] line;
line = nullptr;
if (closefp) {
fclose(fp);
fp = nullptr;
}
throw EOFException(fmt::format("Missing line in {} file!", filetype));
}
}
@ -136,6 +157,7 @@ char *TextFileReader::next_line(int nparams)
int n = 0;
int nwords = 0;
if (!line) return nullptr;
char *ptr = fgets(line, bufsize, fp);
if (ptr == nullptr) {

View File

@ -18,7 +18,6 @@
#include <QAction>
#include <QApplication>
#include <QChart>
#include <QCheckBox>
#include <QCloseEvent>
#include <QComboBox>
#include <QEvent>
@ -57,17 +56,23 @@ ChartWindow::ChartWindow(const QString &_filename, QWidget *parent) :
auto *dummy = new QPushButton(QIcon(), "");
dummy->hide();
smooth = new QCheckBox("Show smooth graph");
smooth->setCheckState(Qt::Unchecked);
do_raw = true;
do_smooth = true;
smooth = new QComboBox;
smooth->addItem("Raw");
smooth->addItem("Smooth");
smooth->addItem("Both");
smooth->setCurrentIndex(2);
smooth->show();
window = new QSpinBox;
window->setRange(5, 100);
window->setRange(5, 999);
window->setValue(10);
window->setEnabled(false);
window->setEnabled(true);
window->setToolTip("Smoothing Window Size");
order = new QSpinBox;
order->setRange(1, 10);
order->setRange(1, 20);
order->setValue(4);
order->setEnabled(false);
order->setEnabled(true);
order->setToolTip("Smoothing Order");
auto *normal = new QPushButton(QIcon(":/icons/gtk-zoom-fit.png"), "");
@ -78,12 +83,12 @@ ChartWindow::ChartWindow(const QString &_filename, QWidget *parent) :
top->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum));
top->addWidget(dummy);
top->addWidget(smooth);
top->addWidget(new QLabel(" Smooth:"));
top->addWidget(window);
top->addWidget(order);
top->addWidget(new QLabel(" "));
top->addWidget(normal);
top->addWidget(new QLabel(" "));
top->addWidget(new QLabel("Select data:"));
top->addWidget(new QLabel(" Data:"));
top->addWidget(columns);
saveAsAct = file->addAction("&Save Graph As...", this, &ChartWindow::saveAs);
saveAsAct->setIcon(QIcon(":/icons/document-save-as.png"));
@ -107,7 +112,7 @@ ChartWindow::ChartWindow(const QString &_filename, QWidget *parent) :
layout->addLayout(top);
setLayout(layout);
connect(smooth, &QPushButton::released, this, &ChartWindow::update_smooth);
connect(smooth, SIGNAL(currentIndexChanged(int)), this, SLOT(select_smooth(int)));
connect(window, &QAbstractSpinBox::editingFinished, this, &ChartWindow::update_smooth);
connect(order, &QAbstractSpinBox::editingFinished, this, &ChartWindow::update_smooth);
connect(window, QOverload<int>::of(&QSpinBox::valueChanged), this, &ChartWindow::update_smooth);
@ -174,8 +179,11 @@ void ChartWindow::quit()
void ChartWindow::reset_zoom()
{
int choice = columns->currentData().toInt() - 1;
if ((choice >= 0) && (choice < charts.size())) charts[choice]->reset_zoom();
int choice = columns->currentData().toInt();
if ((choice >= 0) && (choice < charts.size())) {
charts[choice]->update_smooth();
charts[choice]->reset_zoom();
}
}
void ChartWindow::stop_run()
@ -186,17 +194,35 @@ void ChartWindow::stop_run()
if (main) main->stop_run();
}
void ChartWindow::update_smooth()
void ChartWindow::select_smooth(int)
{
bool do_smooth = smooth->isChecked();
switch (smooth->currentIndex()) {
case 0:
do_raw = true;
do_smooth = false;
break;
case 1:
do_raw = false;
do_smooth = true;
break;
case 2: // fallthrough
default:
do_raw = true;
do_smooth = true;
break;
}
window->setEnabled(do_smooth);
order->setEnabled(do_smooth);
update_smooth();
}
void ChartWindow::update_smooth()
{
int wval = window->value();
int oval = order->value();
for (auto &c : charts)
c->smooth_param(do_smooth, wval, oval);
c->smooth_param(do_raw, do_smooth, wval, oval);
}
void ChartWindow::saveAs()
@ -358,14 +384,11 @@ bool ChartWindow::eventFilter(QObject *watched, QEvent *event)
ChartViewer::ChartViewer(const QString &title, int _index, QWidget *parent) :
QChartView(parent), last_step(-1), index(_index), window(10), order(4), chart(new QChart),
series(new QLineSeries), smooth(nullptr), xaxis(new QValueAxis), yaxis(new QValueAxis),
do_smooth(false)
do_raw(true), do_smooth(true)
{
chart->legend()->hide();
chart->addAxis(xaxis, Qt::AlignBottom);
chart->addAxis(yaxis, Qt::AlignLeft);
chart->addSeries(series);
series->attachAxis(xaxis);
series->attachAxis(yaxis);
xaxis->setTitleText("Time step");
xaxis->setTickCount(5);
xaxis->setLabelFormat("%d");
@ -379,6 +402,7 @@ ChartViewer::ChartViewer(const QString &title, int _index, QWidget *parent) :
setChart(chart);
setRubberBand(QChartView::RectangleRubberBand);
last_update = QTime::currentTime();
update_smooth();
}
/* -------------------------------------------------------------------- */
@ -425,8 +449,8 @@ void ChartViewer::add_data(int step, double data)
// update the chart display only after at least updchart milliseconds have passed
if (last_update.msecsTo(QTime::currentTime()) > settings.value("updchart", "500").toInt()) {
last_update = QTime::currentTime();
reset_zoom();
update_smooth();
reset_zoom();
}
}
}
@ -489,8 +513,12 @@ void ChartViewer::reset_zoom()
/* -------------------------------------------------------------------- */
void ChartViewer::smooth_param(bool _do_smooth, int _window, int _order)
void ChartViewer::smooth_param(bool _do_raw, bool _do_smooth, int _window, int _order)
{
// turn off raw plot
if (!_do_raw) {
if (do_raw) chart->removeSeries(series);
}
// turn off smooth plot
if (!_do_smooth) {
if (smooth) {
@ -499,6 +527,7 @@ void ChartViewer::smooth_param(bool _do_smooth, int _window, int _order)
smooth = nullptr;
}
}
do_raw = _do_raw;
do_smooth = _do_smooth;
window = _window;
order = _order;
@ -513,10 +542,22 @@ static QList<QPointF> calc_sgsmooth(const QList<QPointF> &input, const int windo
void ChartViewer::update_smooth()
{
auto allseries = chart->series();
if (do_raw) {
// add raw data if not in chart
if (!allseries.contains(series)) {
series->setPen(QPen(QBrush(QColor(100, 150, 255)), 3, Qt::SolidLine, Qt::RoundCap));
chart->addSeries(series);
series->attachAxis(xaxis);
series->attachAxis(yaxis);
}
}
if (do_smooth) {
if (series->count() > (2 * window)) {
if (!smooth) {
smooth = new QLineSeries;
smooth->setPen(QPen(QBrush(QColor(255, 125, 125)), 3, Qt::SolidLine, Qt::RoundCap));
chart->addSeries(smooth);
smooth->attachAxis(xaxis);
smooth->attachAxis(yaxis);

View File

@ -25,7 +25,6 @@ class QCloseEvent;
class QEvent;
class QMenuBar;
class QMenu;
class QCheckBox;
class QSpinBox;
namespace QtCharts {
class ChartViewer;
@ -51,6 +50,7 @@ private slots:
void quit();
void reset_zoom();
void stop_run();
void select_smooth(int selection);
void update_smooth();
void saveAs();
@ -65,12 +65,13 @@ protected:
bool eventFilter(QObject *watched, QEvent *event) override;
private:
bool do_raw, do_smooth;
QMenuBar *menu;
QMenu *file;
QComboBox *columns;
QAction *saveAsAct, *exportCsvAct, *exportDatAct, *exportYamlAct;
QAction *closeAct, *stopAct, *quitAct;
QCheckBox *smooth;
QComboBox *smooth;
QSpinBox *window, *order;
QString filename;
@ -94,7 +95,7 @@ public:
void add_data(int step, double data);
void reset_zoom();
void smooth_param(bool _do_smooth, int _window, int _order);
void smooth_param(bool _do_raw, bool _do_smooth, int _window, int _order);
void update_smooth();
int get_index() const { return index; };
@ -111,7 +112,7 @@ private:
QValueAxis *xaxis;
QValueAxis *yaxis;
QTime last_update;
bool do_smooth;
bool do_raw, do_smooth;
};
} // namespace QtCharts
#endif

View File

@ -133,7 +133,7 @@ static int get_pte_from_mass(double mass)
static const QString blank(" ");
ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QString title, QWidget *parent) :
ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidget *parent) :
QDialog(parent), menuBar(new QMenuBar), imageLabel(new QLabel), scrollArea(new QScrollArea),
saveAsAct(nullptr), copyAct(nullptr), cmdAct(nullptr), zoomInAct(nullptr), zoomOutAct(nullptr),
normalSizeAct(nullptr), lammps(_lammps), group("all"), filename(fileName), useelements(false),

View File

@ -34,8 +34,7 @@ class ImageViewer : public QDialog {
Q_OBJECT
public:
explicit ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QString title = "",
QWidget *parent = nullptr);
explicit ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidget *parent = nullptr);
private slots:
void saveAs();

View File

@ -823,8 +823,7 @@ void LammpsGui::inspect_file(const QString &fileName)
dataviewer->show();
ilist->data = dataviewer;
QFile(infodata).remove();
auto *inspect_image = new ImageViewer(
fileName, &lammps, QString("LAMMPS-GUI: Image for %1").arg(shortName));
auto *inspect_image = new ImageViewer(fileName, &lammps);
inspect_image->setFont(font());
inspect_image->show();
ilist->image = inspect_image;

View File

@ -256,4 +256,5 @@ TEST(lammps_open_no_mpi, lammps_error)
lammps_error(handle, 0, "test_warning");
output = ::testing::internal::GetCapturedStdout();
EXPECT_THAT(output, HasSubstr("WARNING: test_warning"));
lammps_close(handle);
}

View File

@ -229,6 +229,7 @@ TEST_F(GroupTest, SelectRestart)
command("group five subtract all half xxx"););
TEST_FAILURE(".*ERROR: Group ID xxx does not exist.*",
command("group five intersect half top xxx"););
delete[] flags;
}
TEST_F(GroupTest, Molecular)

View File

@ -232,6 +232,7 @@ TEST_F(FileOperationsTest, read_lines_from_file)
rv = utils::read_lines_from_file(fp, 2, MAX_BUF_SIZE / 2, buf, me, world);
ASSERT_EQ(rv, 1);
delete[] buf;
if (me == 0) fclose(fp);
}
TEST_F(FileOperationsTest, logmesg)

View File

@ -87,6 +87,16 @@ TEST_F(TextFileReaderTest, nofp)
ASSERT_THROW({ TextFileReader reader(nullptr, "test"); }, FileReaderException);
}
TEST_F(TextFileReaderTest, buffer)
{
test_files();
auto *reader = new TextFileReader("text_reader_two.file", "test");
reader->set_bufsize(4096);
auto *line = reader->next_line();
ASSERT_THROW({ reader->set_bufsize(20); }, FileReaderException);
delete reader;
}
TEST_F(TextFileReaderTest, usefp)
{
test_files();

View File

@ -85,10 +85,19 @@ TEST_F(LAMMPS_thermo, last_thermo)
f_lammps_last_thermo_setup();
EXPECT_EQ(f_lammps_last_thermo_step(), 15);
EXPECT_EQ(f_lammps_last_thermo_num(), 6);
EXPECT_STREQ(f_lammps_last_thermo_string(1), "Step");
EXPECT_STREQ(f_lammps_last_thermo_string(2), "Temp");
EXPECT_STREQ(f_lammps_last_thermo_string(3), "E_pair");
EXPECT_STREQ(f_lammps_last_thermo_string(6), "Press");
char *thermostr;
thermostr = (char *)f_lammps_last_thermo_string(1);
EXPECT_STREQ(thermostr, "Step");
free(thermostr);
thermostr = (char *)f_lammps_last_thermo_string(2);
EXPECT_STREQ(thermostr, "Temp");
free(thermostr);
thermostr = (char *)f_lammps_last_thermo_string(3);
EXPECT_STREQ(thermostr, "E_pair");
free(thermostr);
thermostr = (char *)f_lammps_last_thermo_string(6);
EXPECT_STREQ(thermostr, "Press");
free(thermostr);
#if defined(LAMMPS_SMALLSMALL)
EXPECT_EQ(f_lammps_last_thermo_type(1), multitype::LAMMPS_INT);
#else