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

@ -30,7 +30,7 @@ namespace LAMMPS_NS {
class PairMorseSoft : public PairMorse {
public:
PairMorseSoft(class LAMMPS *lmp) :
PairMorse(lmp), lambda(nullptr), nlambda(0), shift_range(1.0){};
PairMorse(lmp), lambda(nullptr), nlambda(0), shift_range(1.0) {};
~PairMorseSoft() override;
void compute(int, int) override;

File diff suppressed because it is too large Load Diff

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

@ -2721,7 +2721,9 @@ void Neighbor::modify_params(int narg, char **arg)
if (ex1_group[nex_group] == -1)
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]);
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(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