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 (2) If you **distribute** a modified version of LAMMPS, it must remain
open-source, meaning you are required to distribute **all** of it under 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 the terms of the GPLv2. You should **clearly** annotate such a modified
as a derivative version of LAMMPS. 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, (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 then it must also be open-sourced, meaning you distribute it under the
the terms of the GPL. You may write code that interfaces LAMMPS to terms of the GPLv2. You may write code that interfaces LAMMPS to a
a differently licensed library. In that case the code that provides differently licensed library. In that case the code that provides the
the interface must be licensed GPL, but not necessarily that library interface must be licensed GPLv2, but not necessarily that library
unless you are distributing binaries that require the library to run. 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 (4) If you give LAMMPS files to someone else, the GPLv2 LICENSE file and
source file headers (including the copyright and GPL notices) should source file headers (including the copyright and GPLv2 notices) should
remain part of the code. remain part of the code.

View File

@ -2,7 +2,12 @@
LAMMPS Documentation (|version| version) 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 LAMMPS stands for **L**\ arge-scale **A**\ tomic/**M**\ olecular
**M**\ assively **P**\ arallel **S**\ imulator. **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 *one* setting. This ensures neighbor pages are not mostly empty
space. space.
The *exclude group* setting is currently not compatible with dynamic groups.
Related commands Related commands
"""""""""""""""" """"""""""""""""

View File

@ -90,6 +90,16 @@ def get_lammps_version():
end_pos = line.find('"', start_pos) end_pos = line.find('"', start_pos)
return line[start_pos:end_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(): def get_git_info():
import subprocess,time import subprocess,time
@ -97,10 +107,10 @@ def get_git_info():
try: try:
gitinfo = subprocess.run(['git','describe'],stdout=subprocess.PIPE,stderr=subprocess.PIPE) gitinfo = subprocess.run(['git','describe'],stdout=subprocess.PIPE,stderr=subprocess.PIPE)
if gitinfo.returncode == 0: 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: except:
pass pass
return git_n_date return git_n_date.strip()
def get_git_commit(): def get_git_commit():
import subprocess,time import subprocess,time
@ -290,6 +300,16 @@ rst_prolog = r"""
# -- Options for LaTeX output --------------------------------------------- # -- 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 = { latex_elements = {
# The paper size ('letterpaper' or 'a4paper'). # The paper size ('letterpaper' or 'a4paper').
#'papersize': 'letterpaper', #'papersize': 'letterpaper',
@ -300,6 +320,7 @@ latex_elements = {
# Additional stuff for the LaTeX preamble. # Additional stuff for the LaTeX preamble.
'preamble': r''' 'preamble': r'''
\setcounter{tocdepth}{2} \setcounter{tocdepth}{2}
\setcounter{part}{-1}
\renewcommand{\sfdefault}{ptm} % Use Times New Roman font for \textrm \renewcommand{\sfdefault}{ptm} % Use Times New Roman font for \textrm
\renewcommand{\sfdefault}{phv} % Use Helvetica font for \textsf \renewcommand{\sfdefault}{phv} % Use Helvetica font for \textsf
\usepackage[columns=1]{idxlayout} % create index with only one column \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 % Make ToC number fields wider to accommodate sections with >= 100 subsections
% or >= 10 subsections with >= 10 subsubsections % or >= 10 subsections with >= 10 subsubsections
\makeatletter \makeatletter
% reset chapter counter for each part
\@addtoreset{chapter}{part} \@addtoreset{chapter}{part}
\renewcommand*{\sphinxtableofcontentshook}{% \renewcommand*{\sphinxtableofcontentshook}{%
\renewcommand*\l@section{\@dottedtocline{1}{1.5em}{3.1em}} \renewcommand*\l@section{\@dottedtocline{1}{1.5em}{3.1em}}
@ -345,6 +367,38 @@ latex_elements = {
} }
\makeatother \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 # copy custom style file for tweaking index layout
@ -364,19 +418,13 @@ latex_documents = [
# the title page. # the title page.
latex_logo = "_static/lammps-logo-large.jpg" 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' latex_toplevel_sectioning = 'part'
# If true, show page references after internal links. # If true, show page references after internal links.
#latex_show_pagerefs = False #latex_show_pagerefs = False
# If true, show URL addresses after external links. # If true, show URL addresses after external links.
latex_show_urls = 'no' 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. # If false, no module index is generated.
latex_domain_indices = False latex_domain_indices = False

View File

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

View File

@ -2059,6 +2059,7 @@ void Molecule::deallocate()
memory->destroy(type); memory->destroy(type);
memory->destroy(molecule); memory->destroy(molecule);
memory->destroy(q); memory->destroy(q);
memory->destroy(mu);
memory->destroy(radius); memory->destroy(radius);
memory->destroy(rmass); 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]); error->all(FLERR, "Invalid exclude group keyword: group {} not found", arg[iarg+2]);
if (ex2_group[nex_group] == -1) if (ex2_group[nex_group] == -1)
error->all(FLERR, "Invalid exclude group keyword: group {} not found", arg[iarg+3]); 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++; nex_group++;
iarg += 4; iarg += 4;
} else if (strcmp(arg[iarg+1],"molecule/inter") == 0 || } else if (strcmp(arg[iarg+1],"molecule/inter") == 0 ||

View File

@ -77,7 +77,7 @@ Output::Output(LAMMPS *lmp) : Pointers(lmp)
ndump = 0; ndump = 0;
max_dump = 0; max_dump = 0;
any_time_dumps = 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; mode_dump = nullptr;
every_dump = nullptr; every_dump = nullptr;
every_time_dump = nullptr; every_time_dump = nullptr;

View File

@ -254,6 +254,7 @@ void PairHybridScaled::settings(int narg, char **arg)
delete[] special_coul[m]; delete[] special_coul[m];
} }
delete[] styles; delete[] styles;
delete[] cutmax_style;
delete[] keywords; delete[] keywords;
delete[] multiple; delete[] multiple;
delete[] special_lj; 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"); fp = fopen(filename.c_str(), "r");
if (fp == nullptr) { if (fp == nullptr) {
delete[] line;
throw FileReaderException( throw FileReaderException(
fmt::format("cannot open {} file {}: {}", filetype, filename, utils::getsyserror())); 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) filetype(std::move(filetype)), closefp(false), line(nullptr), fp(fp), ignore_comments(true)
{ {
set_bufsize(1024); 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 */ /** Closes the file */
TextFileReader::~TextFileReader() TextFileReader::~TextFileReader()
{ {
if (closefp) fclose(fp); if (closefp) {
if (fp) fclose(fp);
fp = nullptr;
}
delete[] line; delete[] line;
} }
@ -90,6 +98,12 @@ TextFileReader::~TextFileReader()
void TextFileReader::set_bufsize(int newsize) void TextFileReader::set_bufsize(int newsize)
{ {
if (newsize < 100) { if (newsize < 100) {
delete[] line;
line = nullptr;
if (closefp) {
fclose(fp);
fp = nullptr;
}
throw FileReaderException( throw FileReaderException(
fmt::format("line buffer size {} for {} file too small, must be > 100", newsize, filetype)); 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() void TextFileReader::skip_line()
{ {
if (!line) return;
char *ptr = fgets(line, bufsize, fp); char *ptr = fgets(line, bufsize, fp);
if (ptr == nullptr) { if (ptr == nullptr) {
// EOF // EOF
delete[] line;
line = nullptr;
if (closefp) {
fclose(fp);
fp = nullptr;
}
throw EOFException(fmt::format("Missing line in {} file!", filetype)); throw EOFException(fmt::format("Missing line in {} file!", filetype));
} }
} }
@ -136,6 +157,7 @@ char *TextFileReader::next_line(int nparams)
int n = 0; int n = 0;
int nwords = 0; int nwords = 0;
if (!line) return nullptr;
char *ptr = fgets(line, bufsize, fp); char *ptr = fgets(line, bufsize, fp);
if (ptr == nullptr) { if (ptr == nullptr) {

View File

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

View File

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

View File

@ -133,7 +133,7 @@ static int get_pte_from_mass(double mass)
static const QString blank(" "); 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), QDialog(parent), menuBar(new QMenuBar), imageLabel(new QLabel), scrollArea(new QScrollArea),
saveAsAct(nullptr), copyAct(nullptr), cmdAct(nullptr), zoomInAct(nullptr), zoomOutAct(nullptr), saveAsAct(nullptr), copyAct(nullptr), cmdAct(nullptr), zoomInAct(nullptr), zoomOutAct(nullptr),
normalSizeAct(nullptr), lammps(_lammps), group("all"), filename(fileName), useelements(false), normalSizeAct(nullptr), lammps(_lammps), group("all"), filename(fileName), useelements(false),

View File

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

View File

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

View File

@ -256,4 +256,5 @@ TEST(lammps_open_no_mpi, lammps_error)
lammps_error(handle, 0, "test_warning"); lammps_error(handle, 0, "test_warning");
output = ::testing::internal::GetCapturedStdout(); output = ::testing::internal::GetCapturedStdout();
EXPECT_THAT(output, HasSubstr("WARNING: test_warning")); 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");); command("group five subtract all half xxx"););
TEST_FAILURE(".*ERROR: Group ID xxx does not exist.*", TEST_FAILURE(".*ERROR: Group ID xxx does not exist.*",
command("group five intersect half top xxx");); command("group five intersect half top xxx"););
delete[] flags;
} }
TEST_F(GroupTest, Molecular) 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); rv = utils::read_lines_from_file(fp, 2, MAX_BUF_SIZE / 2, buf, me, world);
ASSERT_EQ(rv, 1); ASSERT_EQ(rv, 1);
delete[] buf; delete[] buf;
if (me == 0) fclose(fp);
} }
TEST_F(FileOperationsTest, logmesg) TEST_F(FileOperationsTest, logmesg)

View File

@ -87,6 +87,16 @@ TEST_F(TextFileReaderTest, nofp)
ASSERT_THROW({ TextFileReader reader(nullptr, "test"); }, FileReaderException); 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_F(TextFileReaderTest, usefp)
{ {
test_files(); test_files();

View File

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