Merge pull request #3937 from akohlmey/collected-small-changes

Collected small changes and fixes
This commit is contained in:
Axel Kohlmeyer
2023-10-13 11:20:33 -04:00
committed by GitHub
20 changed files with 277 additions and 118 deletions

View File

@ -702,11 +702,15 @@ Prerequisites and portability
LAMMPS GUI is programmed in C++ based on the C++11 standard and using
the `Qt GUI framework <https://www.qt.io/product/framework>`_.
Currently, Qt version 5.12 or later is required; Qt 5.15LTS is
recommended; Qt 6.x not (yet) supported. Building LAMMPS with CMake is
required. The LAMMPS GUI has been successfully compiled and tested on:
recommended; support for Qt version 6.x is under active development and
thus far only tested with Qt 6.5LTS on Linux. Building LAMMPS with
CMake is required.
The LAMMPS GUI has been successfully compiled and tested on:
- Ubuntu Linux 20.04LTS x86_64 using GCC 9, Qt version 5.12
- Fedora Linux 38 x86\_64 using GCC 13 and Clang 16, Qt version 5.15LTS
- Fedora Linux 38 x86\_64 using GCC 13, Qt version 6.5LTS
- Apple macOS 12 (Monterey) and macOS 13 (Ventura) with Xcode on arm64 and x86\_64, Qt version 5.15LTS
- Windows 10 and 11 x86_64 with Visual Studio 2022 and Visual C++ 14.36, Qt version 5.15LTS
- Windows 10 and 11 x86_64 with MinGW / GCC 10.0 cross-compiler on Fedora 38, Qt version 5.15LTS
@ -717,7 +721,7 @@ required. The LAMMPS GUI has been successfully compiled and tested on:
Pre-compiled executables
^^^^^^^^^^^^^^^^^^^^^^^^
Pre-compiled LAMMPS executables including the GUI are currently
Pre-compiled LAMMPS executable packages that include the GUI are currently
available from https://download.lammps.org/static or
https://github.com/lammps/lammps/releases. You can unpack the archives
(or mount the macOS disk image) and run the GUI directly in place. The
@ -742,7 +746,10 @@ stored in a location where CMake can find them without additional help.
Otherwise, the location of the Qt library installation must be indicated
by setting ``-D Qt5_DIR=/path/to/qt5/lib/cmake/Qt5``, which is a path to
a folder inside the Qt installation that contains the file
``Qt5Config.cmake``.
``Qt5Config.cmake``. Similarly, for Qt6 the location of the Qt library
installation can be indicated by setting ``-D Qt6_DIR=/path/to/qt6/lib/cmake/Qt6``,
if necessary. When both, Qt5 and Qt6 are available, Qt6 will be preferred
unless ``-D LAMMPS_GUI_USE_QT5=yes`` is set.
It should be possible to build the LAMMPS GUI as a standalone
compilation (e.g. when LAMMPS has been compiled with traditional make),

View File

@ -71,14 +71,15 @@ imbue the SRD particles with fluid-like properties, including an
effective viscosity. Thus simulations with large solute particles can
be run more quickly, to measure solute properties like diffusivity
and viscosity in a background fluid. The usual LAMMPS fixes for such
simulations, such as :doc:`fix deform <fix_deform>`, :doc:`fix viscosity <fix_viscosity>`, and :doc:`fix nvt/sllod <fix_nvt_sllod>`,
simulations, such as :doc:`fix deform <fix_deform>`,
:doc:`fix viscosity <fix_viscosity>`, and :doc:`fix nvt/sllod <fix_nvt_sllod>`,
can be used in conjunction with the SRD model.
For more details on how the SRD model is implemented in LAMMPS, :ref:`this paper <Petersen1>` describes the implementation and usage of pure SRD
fluids. :ref:`This paper <Lechman>`, which is nearly complete, describes
the implementation and usage of mixture systems (solute particles in
an SRD fluid). See the examples/srd directory for sample input
scripts using SRD particles in both settings.
For more details on how the SRD model is implemented in LAMMPS,
:ref:`(Petersen) <Petersen1>` describes the implementation and usage of
pure SRD fluids. See the ``examples/srd`` directory for sample input
scripts using SRD particles for that and for mixture systems (solute
particles in an SRD fluid).
This fix does two things:
@ -357,28 +358,28 @@ These are the 12 quantities. All are values for the current timestep,
except for quantity 5 and the last three, each of which are
cumulative quantities since the beginning of the run.
* (1) # of SRD/big collision checks performed
* (2) # of SRDs which had a collision
* (3) # of SRD/big collisions (including multiple bounces)
* (4) # of SRD particles inside a big particle
* (5) # of SRD particles whose velocity was rescaled to be < Vmax
* (6) # of bins for collision searching
* (7) # of bins for SRD velocity rotation
* (8) # of bins in which SRD temperature was computed
* (9) SRD temperature
* (10) # of SRD particles which have undergone max # of bounces
* (11) max # of bounces any SRD particle has had in a single step
* (12) # of reneighborings due to SRD particles moving too far
(1) # of SRD/big collision checks performed
(2) # of SRDs which had a collision
(3) # of SRD/big collisions (including multiple bounces)
(4) # of SRD particles inside a big particle
(5) # of SRD particles whose velocity was rescaled to be < Vmax
(6) # of bins for collision searching
(7) # of bins for SRD velocity rotation
(8) # of bins in which SRD temperature was computed
(9) SRD temperature
(10) # of SRD particles which have undergone max # of bounces
(11) max # of bounces any SRD particle has had in a single step
(12) # of reneighborings due to SRD particles moving too far
No parameter of this fix can be used with the *start/stop* keywords of
the :doc:`run <run>` command. This fix is not invoked during :doc:`energy minimization <minimize>`.
the :doc:`run <run>` command. This fix is not invoked during
:doc:`energy minimization <minimize>`.
Restrictions
""""""""""""
This command can only be used if LAMMPS was built with the SRD
package. See the :doc:`Build package <Build_package>` doc
page for more info.
This command can only be used if LAMMPS was built with the SRD package.
See the :doc:`Build package <Build_package>` doc page for more info.
Related commands
""""""""""""""""
@ -403,7 +404,3 @@ no, and rescale = yes.
**(Petersen)** Petersen, Lechman, Plimpton, Grest, in' t Veld, Schunk, J
Chem Phys, 132, 174106 (2010).
.. _Lechman:
**(Lechman)** Lechman, et al, in preparation (2010).

View File

@ -22,12 +22,12 @@ Examples
.. code-block:: LAMMPS
pair_style hybrid/overlay ilp/tmd 16.0 1
pair_coeff * * ilp/tmd TMD.ILP Mo S S
pair_coeff * * ilp/tmd MoS2.ILP Mo S S
pair_style hybrid/overlay sw/mod sw/mod ilp/tmd 16.0
pair_coeff * * sw/mod 1 tmd.sw.mod Mo S S NULL NULL NULL
pair_coeff * * sw/mod 2 tmd.sw.mod NULL NULL NULL Mo S S
pair_coeff * * ilp/tmd TMD.ILP Mo S S Mo S S
pair_coeff * * ilp/tmd MoS2.ILP Mo S S Mo S S
Description
"""""""""""
@ -69,7 +69,7 @@ calculating the normals.
each atom `i`, its six nearest neighboring atoms belonging to the same
sub-layer are chosen to define the normal vector `{\bf n}_i`.
The parameter file (e.g. TMD.ILP), is intended for use with *metal*
The parameter file (e.g. MoS2.ILP), is intended for use with *metal*
:doc:`units <units>`, with energies in meV. Two additional parameters,
*S*, and *rcut* are included in the parameter file. *S* is designed to
facilitate scaling of energies. *rcut* is designed to build the neighbor
@ -77,7 +77,7 @@ list for calculating the normals for each atom pair.
.. note::
The parameters presented in the parameter file (e.g. TMD.ILP),
The parameters presented in the parameter file (e.g. MoS2.ILP),
are fitted with taper function by setting the cutoff equal to 16.0
Angstrom. Using different cutoff or taper function should be careful.
These parameters provide a good description in both short- and long-range
@ -133,10 +133,10 @@ if LAMMPS was built with that package. See the :doc:`Build package
This pair style requires the newton setting to be *on* for pair
interactions.
The TMD.ILP potential file provided with LAMMPS (see the potentials
The MoS2.ILP potential file provided with LAMMPS (see the potentials
directory) are parameterized for *metal* units. You can use this
potential with any LAMMPS units, but you would need to create your own
custom TMD.ILP potential file with coefficients listed in the appropriate
custom MoS2.ILP potential file with coefficients listed in the appropriate
units, if your simulation does not use *metal* units.
Related commands

View File

@ -43,22 +43,22 @@ Examples
Description
"""""""""""
Style *reaxff* computes the ReaxFF potential of van Duin, Goddard and
co-workers. ReaxFF uses distance-dependent bond-order functions to
Pair style *reaxff* computes the ReaxFF potential of van Duin, Goddard
and co-workers. ReaxFF uses distance-dependent bond-order functions to
represent the contributions of chemical bonding to the potential
energy. There is more than one version of ReaxFF. The version
energy. There is more than one version of ReaxFF. The version
implemented in LAMMPS uses the functional forms documented in the
supplemental information of the following paper:
:ref:`(Chenoweth et al., 2008) <Chenoweth_20082>`. The version integrated
into LAMMPS matches the version of ReaxFF From Summer 2010. For more
technical details about the pair reaxff implementation of ReaxFF, see
the :ref:`(Aktulga) <Aktulga>` paper. The *reaxff* style was initially
implemented as a stand-alone C code and is now converted to C++ and
integrated into LAMMPS as a package.
:ref:`(Chenoweth et al., 2008) <Chenoweth_20082>` and matches the
version of the reference ReaxFF implementation from Summer 2010. For
more technical details about the implementation of ReaxFF in pair style
*reaxff*, see the :ref:`(Aktulga) <Aktulga>` paper. The *reaxff* style
was initially implemented as a stand-alone C code and is now converted
to C++ and integrated into LAMMPS as a package.
The *reaxff/kk* style is a Kokkos version of the ReaxFF potential that
is derived from the *reaxff* style. The Kokkos version can run on GPUs
and can also use OpenMP multithreading. For more information about the
is derived from the *reaxff* style. The Kokkos version can run on GPUs
and can also use OpenMP multithreading. For more information about the
Kokkos package, see :doc:`Packages details <Packages_details>` and
:doc:`Speed kokkos <Speed_kokkos>` doc pages. One important
consideration when using the *reaxff/kk* style is the choice of either

View File

@ -32,6 +32,7 @@ namespace LAMMPS_NS {
// get access to number of threads and per-thread data structures via FixOMP
#define NPAIR_OMP_INIT \
const int nthreads = comm->nthreads; \
omp_set_num_threads(nthreads); \
const int ifix = modify->find_fix("package_omp")
// get thread id and then assign each thread a fixed chunk of atoms

View File

@ -27,8 +27,8 @@ using namespace LAMMPS_NS;
/* ---------------------------------------------------------------------- */
ComputeMSDChunk::ComputeMSDChunk(LAMMPS *lmp, int narg, char **arg) :
ComputeChunk(lmp, narg, arg), id_fix(nullptr), massproc(nullptr), masstotal(nullptr),
com(nullptr), comall(nullptr), msd(nullptr)
ComputeChunk(lmp, narg, arg), id_fix(nullptr), fix(nullptr), massproc(nullptr),
masstotal(nullptr), com(nullptr), comall(nullptr), msd(nullptr)
{
if (narg != 4) error->all(FLERR, "Illegal compute msd/chunk command");
@ -196,6 +196,12 @@ void ComputeMSDChunk::compute_array()
void ComputeMSDChunk::allocate()
{
ComputeChunk::allocate();
memory->destroy(massproc);
memory->destroy(masstotal);
memory->destroy(com);
memory->destroy(comall);
memory->destroy(msd);
memory->create(massproc, nchunk, "msd/chunk:massproc");
memory->create(masstotal, nchunk, "msd/chunk:masstotal");
memory->create(com, nchunk, 3, "msd/chunk:com");

View File

@ -11,6 +11,42 @@ set(CMAKE_CXX_STANDARD_REQUIRED ON)
option(LAMMPS_GUI_USE_PLUGIN "Load LAMMPS library dynamically at runtime" OFF)
mark_as_advanced(LAMMPS_GUI_USE_PLUGIN)
option(LAMMPS_GUI_USE_QT5 "Prefer using Qt5 over Qt6" OFF)
include(CheckIncludeFileCXX)
# helper function to check for usable omp.h header
function(check_omp_h_include)
find_package(OpenMP COMPONENTS CXX QUIET)
if(OpenMP_CXX_FOUND)
set(CMAKE_REQUIRED_FLAGS ${OpenMP_CXX_FLAGS})
set(CMAKE_REQUIRED_INCLUDES ${OpenMP_CXX_INCLUDE_DIRS})
set(CMAKE_REQUIRED_LINK_OPTIONS ${OpenMP_CXX_FLAGS})
set(CMAKE_REQUIRED_LIBRARIES ${OpenMP_CXX_LIBRARIES})
check_include_file_cxx(omp.h _have_omp_h)
else()
set(_have_omp_h FALSE)
endif()
set(HAVE_OMP_H_INCLUDE ${_have_omp_h} PARENT_SCOPE)
endfunction()
# detect if we may enable OpenMP support by default
set(BUILD_OMP_DEFAULT OFF)
find_package(OpenMP COMPONENTS CXX QUIET)
if(OpenMP_CXX_FOUND)
check_omp_h_include()
if(HAVE_OMP_H_INCLUDE)
set(BUILD_OMP_DEFAULT ON)
endif()
endif()
option(BUILD_OMP "Build with OpenMP support" ${BUILD_OMP_DEFAULT})
if(BUILD_OMP)
find_package(OpenMP COMPONENTS CXX REQUIRED)
check_omp_h_include()
if(NOT HAVE_OMP_H_INCLUDE)
message(FATAL_ERROR "Cannot find the 'omp.h' header file required for full OpenMP support")
endif()
endif()
# checks
# when this file is included as subdirectory in the LAMMPS build, many settings are directly imported
@ -73,7 +109,15 @@ if(CMAKE_SYSTEM_NAME STREQUAL "Windows")
endif()
# we require Qt 5 and at least version 5.12 at that.
find_package(Qt5 5.12 REQUIRED COMPONENTS Widgets Charts)
if(NOT LAMMPS_GUI_USE_QT5)
find_package(Qt6 6.2 COMPONENTS Widgets Charts)
endif()
if(NOT Qt6_FOUND)
find_package(Qt5 5.12 REQUIRED COMPONENTS Widgets Charts)
set(QT_VERSION_MAJOR "5")
else()
set(QT_VERSION_MAJOR "6")
endif()
set(PROJECT_SOURCES
main.cpp
@ -105,7 +149,11 @@ set(PROJECT_SOURCES
${PLUGIN_LOADER_SRC}
${ICON_RC_FILE}
)
qt5_add_resources(PROJECT_SOURCES lammpsgui.qrc)
if(QT_VERSION_MAJOR EQUAL 6)
qt6_add_resources(PROJECT_SOURCES lammpsgui.qrc)
else()
qt5_add_resources(PROJECT_SOURCES lammpsgui.qrc)
endif()
if(APPLE)
set(MACOSX_ICON_FILE ${LAMMPS_DIR}/cmake/packaging/lammps.icns)
@ -113,10 +161,22 @@ if(APPLE)
set(MACOSX_BACKGROUND_FILE ${LAMMPS_DIR}/cmake/packaging/LAMMPS_DMG_Background.png)
endif()
add_executable(lammps-gui
${MACOSX_ICON_FILE}
${PROJECT_SOURCES}
)
if(QT_VERSION_MAJOR EQUAL 6)
qt_add_executable(lammps-gui
MANUAL_FINALIZATION
${MACOSX_ICON_FILE}
${PROJECT_SOURCES}
)
else()
add_executable(lammps-gui
${MACOSX_ICON_FILE}
${PROJECT_SOURCES}
)
endif()
if(QT_VERSION_MAJOR EQUAL 6)
qt_finalize_executable(lammps-gui)
endif()
# compilation settings
if(LAMMPS_GUI_USE_PLUGIN)
@ -128,7 +188,7 @@ else()
endif()
target_include_directories(lammps-gui PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
target_compile_definitions(lammps-gui PRIVATE LAMMPS_GUI_VERSION="${PROJECT_VERSION}")
target_link_libraries(lammps-gui PRIVATE Qt5::Widgets Qt5::Charts)
target_link_libraries(lammps-gui PRIVATE Qt${QT_VERSION_MAJOR}::Widgets Qt${VERSION_MAJOR}::Charts)
if(BUILD_OMP)
find_package(OpenMP COMPONENTS CXX REQUIRED)
target_link_libraries(lammps-gui PRIVATE OpenMP::OpenMP_CXX)
@ -209,7 +269,7 @@ elseif((CMAKE_SYSTEM_NAME STREQUAL "Windows") AND CMAKE_CROSSCOMPILING)
COMMENT "Create zip file with windows binaries"
BYPRODUCT LAMMPS-Win10-amd64.zip
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
elseif(CMAKE_SYSTEM_NAME STREQUAL "Linux")
elseif((CMAKE_SYSTEM_NAME STREQUAL "Linux") AND NOT LAMMPS_GUI_USE_PLUGIN)
install(TARGETS lammps-gui DESTINATION ${CMAKE_INSTALL_BINDIR})
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/lammps-gui.desktop DESTINATION ${CMAKE_INSTALL_DATADIR}/applications/)
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/lammps-input.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/packages/)

View File

@ -23,7 +23,6 @@ LAMMPS-GUI TODO list:
# Long term ideas (v2.x)
- rewrite entire application to build the App and its layout manually
- port to Qt6 (with compatibility to Qt5?)
- also a rewrite should establish consistent naming conventions. now we have a mix of LAMMPS style, Qt style, and others.
- add option to attach a debugger to the running program (highly non-portable, need customization support in preferences)
- write a "wizard" dialog that can be used for beginners to create an input file template for a few typical use scenarios

View File

@ -15,11 +15,20 @@
#include "lammpsgui.h"
#include <QAction>
#include <QApplication>
#include <QFileDialog>
#include <QHBoxLayout>
#include <QKeySequence>
#include <QLabel>
#include <QLayout>
#include <QLineSeries>
#include <QMenu>
#include <QMenuBar>
#include <QPushButton>
#include <QSettings>
#include <QSpacerItem>
#include <QTextStream>
#include <QVBoxLayout>
using namespace QtCharts;
@ -53,13 +62,13 @@ ChartWindow::ChartWindow(const QString &_filename, QWidget *parent) :
file->addSeparator();
stopAct = file->addAction("Stop &Run", this, &ChartWindow::stop_run);
stopAct->setIcon(QIcon(":/icons/process-stop.png"));
stopAct->setShortcut(QKeySequence::fromString("Ctrl+/"));
stopAct->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Slash));
closeAct = file->addAction("&Close", this, &QWidget::close);
closeAct->setIcon(QIcon(":/icons/window-close.png"));
closeAct->setShortcut(QKeySequence::fromString("Ctrl+W"));
closeAct->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_W));
quitAct = file->addAction("&Quit", this, &ChartWindow::quit);
quitAct->setIcon(QIcon(":/icons/application-exit.png"));
quitAct->setShortcut(QKeySequence::fromString("Ctrl+Q"));
quitAct->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q));
auto *layout = new QVBoxLayout;
layout->addLayout(top);
setLayout(layout);
@ -76,7 +85,10 @@ int ChartWindow::get_step() const
{
if (charts.size() > 0) {
auto *v = charts[0];
return (int)v->get_step(v->get_count() - 1);
if (v)
return (int)v->get_step(v->get_count() - 1);
else
return -1;
} else {
return -1;
}
@ -115,10 +127,10 @@ void ChartWindow::add_data(int step, double data, int index)
void ChartWindow::quit()
{
LammpsGui *main;
LammpsGui *main = nullptr;
for (QWidget *widget : QApplication::topLevelWidgets())
if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget);
main->quit();
if (main) main->quit();
}
void ChartWindow::reset_zoom()
@ -129,10 +141,10 @@ void ChartWindow::reset_zoom()
void ChartWindow::stop_run()
{
LammpsGui *main;
LammpsGui *main = nullptr;
for (QWidget *widget : QApplication::topLevelWidgets())
if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget);
main->stop_run();
if (main) main->stop_run();
}
void ChartWindow::saveAs()
@ -288,7 +300,7 @@ void ChartViewer::add_data(int step, double data)
if (last_step < step) {
last_step = step;
series->append(step, data);
auto points = series->pointsVector();
auto points = series->points();
qreal xmin = 1.0e100;
qreal xmax = -1.0e100;
@ -309,7 +321,7 @@ void ChartViewer::add_data(int step, double data)
void ChartViewer::reset_zoom()
{
auto points = series->pointsVector();
auto points = series->points();
qreal xmin = 1.0e100;
qreal xmax = -1.0e100;

View File

@ -14,16 +14,17 @@
#ifndef CHARTVIEWER_H
#define CHARTVIEWER_H
#include <QComboBox>
#include <QList>
#include <QString>
#include <QWidget>
#include <QtCharts>
class QAction;
class QMenuBar;
class QMenu;
class QComboBox;
namespace QtCharts {
class ChartViewer;
}
class ChartWindow : public QWidget {
Q_OBJECT
@ -64,12 +65,18 @@ private:
QAction *closeAct, *stopAct, *quitAct;
QString filename;
QList<ChartViewer *> charts;
QList<QtCharts::ChartViewer *> charts;
};
/* -------------------------------------------------------------------- */
class ChartViewer : public QtCharts::QChartView {
#include <QChart>
#include <QChartView>
#include <QLineSeries>
#include <QValueAxis>
namespace QtCharts {
class ChartViewer : public QChartView {
Q_OBJECT
public:
@ -81,16 +88,17 @@ public:
int get_index() const { return index; };
int get_count() const { return series->count(); }
const char *get_title() const { return series->name().toLocal8Bit(); }
double get_step(int index) const { return series->at(index).x(); }
double get_data(int index) const { return series->at(index).y(); }
double get_step(int index) const { return (index < 0) ? 0.0 : series->at(index).x(); }
double get_data(int index) const { return (index < 0) ? 0.0 : series->at(index).y(); }
private:
int last_step, index;
QtCharts::QChart *chart;
QtCharts::QLineSeries *series;
QtCharts::QValueAxis *xaxis;
QtCharts::QValueAxis *yaxis;
QChart *chart;
QLineSeries *series;
QValueAxis *xaxis;
QValueAxis *yaxis;
};
} // namespace QtCharts
#endif
// Local Variables:

View File

@ -564,14 +564,16 @@ void CodeEditor::keyPressEvent(QKeyEvent *event)
// process key event in parent class
QPlainTextEdit::keyPressEvent(event);
// if enabled, try pop up completion automatically after 3 characters
// if enabled, try pop up completion automatically after 2 characters
if (automatic_completion) {
auto cursor = textCursor();
auto line = cursor.block().text();
if (line.isEmpty()) return;
// QTextCursor::WordUnderCursor is unusable here since recognizes '/' as word boundary.
// Work around it by manually searching for the location of the beginning of the word.
int begin = cursor.positionInBlock();
int begin = qMin(cursor.positionInBlock(), line.length() - 1);
while (begin >= 0) {
if (line[begin].isSpace()) break;
--begin;
@ -748,7 +750,7 @@ void CodeEditor::runCompletion()
// QTextCursor::WordUnderCursor is unusable here since it recognizes '/' as word boundary.
// Work around it by manually searching for the beginning and end position of the word
// under the cursor and then using that substring.
int begin = cursor.positionInBlock();
int begin = qMin(cursor.positionInBlock(), line.length() - 1);
line = cursor.block().text();
while (begin >= 0) {
if (line[begin].isSpace()) break;
@ -990,8 +992,26 @@ void CodeEditor::insertCompletedCommand(const QString &completion)
{
auto *completer = qobject_cast<QCompleter *>(sender());
if (completer->widget() != this) return;
// select the entire word (non-space text) under the cursor
// we need to do it in this compicated way, since QTextCursor does not recognize
// special characters as part of a word.
auto cursor = textCursor();
cursor.movePosition(QTextCursor::StartOfWord, QTextCursor::KeepAnchor);
auto line = cursor.block().text();
int begin = cursor.positionInBlock();
do {
if (line[begin].isSpace()) break;
--begin;
} while (begin >= 0);
int end = begin + 1;
while (end < line.length()) {
if (line[end].isSpace()) break;
++end;
}
cursor.setPosition(cursor.position() - cursor.positionInBlock() + begin + 1);
cursor.movePosition(QTextCursor::NextCharacter, QTextCursor::KeepAnchor, end - begin - 1);
cursor.insertText(completion);
setTextCursor(cursor);
}

View File

@ -23,6 +23,7 @@
#include <QGuiApplication>
#include <QImage>
#include <QImageReader>
#include <QKeySequence>
#include <QLabel>
#include <QLineEdit>
#include <QMenuBar>
@ -131,7 +132,7 @@ static const QString blank(" ");
ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidget *parent) :
QDialog(parent), menuBar(new QMenuBar), imageLabel(new QLabel), scrollArea(new QScrollArea),
lammps(_lammps), group("all"), filename(fileName), useelements(false)
lammps(_lammps), group("all"), filename(fileName), useelements(false), usediameter(false)
{
imageLabel->setBackgroundRole(QPalette::Base);
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
@ -268,7 +269,7 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge
// properties directly since lookup in reset_view() will have failed
dobox->setChecked(showbox);
dovdw->setChecked(vdwfactor > 1.0);
dovdw->setEnabled(useelements);
dovdw->setEnabled(useelements || usediameter);
doaxes->setChecked(showaxes);
dossao->setChecked(usessao);
doanti->setChecked(antialias);
@ -435,7 +436,7 @@ void ImageViewer::createImage()
dumpcmd += "'" + dumpfile.fileName() + "'";
settings.beginGroup("snapshot");
int hhrot = (hrot > 180) ? 360 - hrot : hrot;
int hhrot = (hrot > 180) ? 360 - hrot : hrot;
// determine elements from masses and set their covalent radii
int ntypes = lammps->extract_setting("ntypes");
@ -454,9 +455,10 @@ void ImageViewer::createImage()
adiams += QString("adiam %1 %2 ").arg(i).arg(vdwfactor * pte_vdw_radius[idx]);
}
}
usediameter = lammps->extract_setting("radius_flag") != 0;
// adjust pushbutton state and clear adiams string to disable VDW display, if needed
if (useelements) {
if (useelements || usediameter) {
auto *button = findChild<QPushButton *>("vdw");
if (button) button->setEnabled(true);
} else {
@ -469,7 +471,10 @@ void ImageViewer::createImage()
dumpcmd += blank + "element";
else
dumpcmd += blank + settings.value("color", "type").toString();
dumpcmd += blank + settings.value("diameter", "type").toString();
if (usediameter && (vdwfactor > 1.0))
dumpcmd += blank + "diameter";
else
dumpcmd += blank + settings.value("diameter", "type").toString();
dumpcmd += QString(" size %1 %2").arg(xsize).arg(ysize);
dumpcmd += QString(" zoom %1").arg(zoom);
dumpcmd += " shiny 0.5 ";
@ -528,10 +533,10 @@ void ImageViewer::copy() {}
void ImageViewer::quit()
{
LammpsGui *main;
LammpsGui *main = nullptr;
for (QWidget *widget : QApplication::topLevelWidgets())
if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget);
main->quit();
if (main) main->quit();
}
void ImageViewer::saveFile(const QString &fileName)
@ -554,10 +559,10 @@ void ImageViewer::createActions()
fileMenu->addSeparator();
QAction *exitAct = fileMenu->addAction("&Close", this, &QWidget::close);
exitAct->setIcon(QIcon(":/icons/window-close.png"));
exitAct->setShortcut(QKeySequence::fromString("Ctrl+W"));
exitAct->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_W));
QAction *quitAct = fileMenu->addAction("&Quit", this, &ImageViewer::quit);
quitAct->setIcon(QIcon(":/icons/application-exit.png"));
quitAct->setShortcut(QKeySequence::fromString("Ctrl+Q"));
quitAct->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q));
}
void ImageViewer::updateActions()

View File

@ -88,7 +88,7 @@ private:
int xsize, ysize;
int hrot, vrot;
double zoom, vdwfactor;
bool showbox, showaxes, antialias, usessao, useelements;
bool showbox, showaxes, antialias, usessao, useelements, usediameter;
};
#endif

View File

@ -35,6 +35,7 @@
#include <QLabel>
#include <QLocale>
#include <QMessageBox>
#include <QMetaType>
#include <QPlainTextEdit>
#include <QProcess>
#include <QProgressBar>
@ -69,8 +70,10 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) :
// enforce using the plain ASCII C locale within the GUI.
QLocale::setDefault(QLocale("C"));
// register QList<QString>
#if QT_VERSION < QT_VERSION_CHECK(6, 0, 0)
// register QList<QString> only needed for Qt5
qRegisterMetaTypeStreamOperators<QList<QString>>("QList<QString>");
#endif
ui->setupUi(this);
this->setCentralWidget(ui->textEdit);
@ -81,9 +84,13 @@ LammpsGui::LammpsGui(QWidget *parent, const char *filename) :
// use $HOME if we get dropped to "/" like on macOS
if (current_dir == "/") current_dir = QDir::homePath();
#define stringify(x) myxstr(x)
#define myxstr(x) #x
QCoreApplication::setOrganizationName("The LAMMPS Developers");
QCoreApplication::setOrganizationDomain("lammps.org");
QCoreApplication::setApplicationName("LAMMPS GUI");
QCoreApplication::setApplicationName("LAMMPS GUI - QT" stringify(QT_VERSION_MAJOR));
#undef stringify
#undef myxstr
// restore and initialize settings
QSettings settings;
@ -588,7 +595,8 @@ void LammpsGui::open_file(const QString &fileName)
if (!file.open(QIODevice::ReadOnly | QFile::Text)) {
QMessageBox::warning(this, "Warning",
"Cannot open file " + path.absoluteFilePath() + ": " +
file.errorString() + ".\nWill create new file on saving editor buffer.");
file.errorString() +
".\nWill create new file on saving editor buffer.");
ui->textEdit->document()->setPlainText(QString());
} else {
QTextStream in(&file);
@ -1039,9 +1047,9 @@ void LammpsGui::do_run(bool use_buffer)
logwindow->document()->setDefaultFont(text_font);
logwindow->setLineWrapMode(LogWindow::NoWrap);
logwindow->setMinimumSize(400, 300);
QShortcut *shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), logwindow);
QShortcut *shortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_W), logwindow);
QObject::connect(shortcut, &QShortcut::activated, logwindow, &LogWindow::close);
shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Slash), logwindow);
shortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Slash), logwindow);
QObject::connect(shortcut, &QShortcut::activated, this, &LammpsGui::stop_run);
if (settings.value("viewlog", true).toBool())
logwindow->show();
@ -1058,9 +1066,9 @@ void LammpsGui::do_run(bool use_buffer)
.arg(run_counter));
chartwindow->setWindowIcon(QIcon(":/icons/lammps-icon-128x128.png"));
chartwindow->setMinimumSize(400, 300);
shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), chartwindow);
shortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_W), chartwindow);
QObject::connect(shortcut, &QShortcut::activated, chartwindow, &ChartWindow::close);
shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Slash), chartwindow);
shortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Slash), chartwindow);
QObject::connect(shortcut, &QShortcut::activated, this, &LammpsGui::stop_run);
if (settings.value("viewchart", true).toBool())
chartwindow->show();

View File

@ -16,8 +16,10 @@
#include <QMainWindow>
#include <QGridLayout>
#include <QList>
#include <QPair>
#include <QSpacerItem>
#include <QString>
#include <vector>

View File

@ -35,12 +35,14 @@ LogWindow::LogWindow(const QString &_filename, QWidget *parent) :
QSettings settings;
resize(settings.value("logx", 500).toInt(), settings.value("logy", 320).toInt());
auto action = new QShortcut(QKeySequence::fromString("Ctrl+S"), this);
auto action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_S), this);
connect(action, &QShortcut::activated, this, &LogWindow::save_as);
action = new QShortcut(QKeySequence::fromString("Ctrl+Q"), this);
action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q), this);
connect(action, &QShortcut::activated, this, &LogWindow::quit);
action = new QShortcut(QKeySequence(Qt::Key_Slash, Qt::CTRL), this);
action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Slash), this);
connect(action, &QShortcut::activated, this, &LogWindow::stop_run);
installEventFilter(this);
}
void LogWindow::closeEvent(QCloseEvent *event)
@ -55,18 +57,18 @@ void LogWindow::closeEvent(QCloseEvent *event)
void LogWindow::quit()
{
LammpsGui *main;
LammpsGui *main = nullptr;
for (QWidget *widget : QApplication::topLevelWidgets())
if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget);
main->quit();
if (main) main->quit();
}
void LogWindow::stop_run()
{
LammpsGui *main;
LammpsGui *main = nullptr;
for (QWidget *widget : QApplication::topLevelWidgets())
if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget);
main->stop_run();
if (main) main->stop_run();
}
void LogWindow::save_as()
@ -99,15 +101,35 @@ void LogWindow::contextMenuEvent(QContextMenuEvent *event)
menu->addSeparator();
auto action = menu->addAction(QString("Save Log to File ..."));
action->setIcon(QIcon(":/icons/document-save-as.png"));
action->setShortcut(QKeySequence::fromString("Ctrl+S"));
action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S));
connect(action, &QAction::triggered, this, &LogWindow::save_as);
action = menu->addAction("&Close Window", this, &QWidget::close);
action->setIcon(QIcon(":/icons/window-close.png"));
action->setShortcut(QKeySequence::fromString("Ctrl+W"));
action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_W));
menu->exec(event->globalPos());
delete menu;
}
// event filter to handle "Ambiguous shortcut override" issues
bool LogWindow::eventFilter(QObject *watched, QEvent *event)
{
if (event->type() == QEvent::ShortcutOverride) {
QKeyEvent *keyEvent = dynamic_cast<QKeyEvent *>(event);
if (!keyEvent) return QWidget::eventFilter(watched, event);
if (keyEvent->modifiers().testFlag(Qt::ControlModifier) && keyEvent->key() == '/') {
stop_run();
event->accept();
return true;
}
if (keyEvent->modifiers().testFlag(Qt::ControlModifier) && keyEvent->key() == 'W') {
close();
event->accept();
return true;
}
}
return QWidget::eventFilter(watched, event);
}
// Local Variables:
// c-basic-offset: 4
// End:

View File

@ -30,6 +30,7 @@ private slots:
protected:
void closeEvent(QCloseEvent *event) override;
void contextMenuEvent(QContextMenuEvent *event) override;
bool eventFilter(QObject *watched, QEvent *event) override;
private:
QString filename;

View File

@ -286,12 +286,12 @@ GeneralTab::GeneralTab(QSettings *_settings, LammpsWrapper *_lammps, QWidget *pa
void GeneralTab::updatefonts(const QFont &all, const QFont &text)
{
LammpsGui *main;
LammpsGui *main = nullptr;
for (QWidget *widget : QApplication::topLevelWidgets())
if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget);
QApplication::setFont(all);
main->ui->textEdit->document()->setDefaultFont(text);
if (main) main->ui->textEdit->document()->setDefaultFont(text);
}
void GeneralTab::newallfont()
@ -410,11 +410,19 @@ AcceleratorTab::AcceleratorTab(QSettings *_settings, LammpsWrapper *_lammps, QWi
#endif
auto *choices = new QFrame;
auto *choiceLayout = new QVBoxLayout;
#if defined(_OPENMP)
auto *ntlabel = new QLabel(QString("Number of threads (max %1):").arg(maxthreads));
auto *ntchoice = new QLineEdit(settings->value("nthreads", maxthreads).toString());
#else
auto *ntlabel = new QLabel(QString("Number of threads (OpenMP not available):"));
auto *ntchoice = new QLineEdit("1");
#endif
auto *intval = new QIntValidator(1, maxthreads, this);
ntchoice->setValidator(intval);
ntchoice->setObjectName("nthreads");
#if !defined(_OPENMP)
ntchoice->setEnabled(false);
#endif
choiceLayout->addWidget(ntlabel);
choiceLayout->addWidget(ntchoice);

View File

@ -25,6 +25,7 @@
#include <QHBoxLayout>
#include <QImage>
#include <QImageReader>
#include <QKeySequence>
#include <QLabel>
#include <QPalette>
#include <QProcess>
@ -50,11 +51,11 @@ SlideShow::SlideShow(const QString &fileName, QWidget *parent) :
imageName->setAlignment(Qt::AlignCenter);
imageName->setSizePolicy(QSizePolicy::Expanding, QSizePolicy::Expanding);
auto *shortcut = new QShortcut(QKeySequence::fromString("Ctrl+W"), this);
auto *shortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_W), this);
QObject::connect(shortcut, &QShortcut::activated, this, &QWidget::close);
shortcut = new QShortcut(QKeySequence::fromString("Ctrl+/"), this);
shortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Slash), this);
QObject::connect(shortcut, &QShortcut::activated, this, &SlideShow::stop_run);
shortcut = new QShortcut(QKeySequence::fromString("Ctrl+Q"), this);
shortcut = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q), this);
QObject::connect(shortcut, &QShortcut::activated, this, &SlideShow::quit);
buttonBox = new QDialogButtonBox(QDialogButtonBox::Close);
@ -198,18 +199,18 @@ void SlideShow::loadImage(int idx)
void SlideShow::quit()
{
LammpsGui *main;
LammpsGui *main = nullptr;
for (QWidget *widget : QApplication::topLevelWidgets())
if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget);
main->quit();
if (main) main->quit();
}
void SlideShow::stop_run()
{
LammpsGui *main;
LammpsGui *main = nullptr;
for (QWidget *widget : QApplication::topLevelWidgets())
if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget);
main->stop_run();
if (main) main->stop_run();
}
void SlideShow::movie()

View File

@ -77,6 +77,7 @@ bool StdCapture::EndCapture()
int bytesRead;
bool fd_blocked;
int maxwait = 100;
do {
bytesRead = 0;
@ -93,9 +94,10 @@ bool StdCapture::EndCapture()
buf[bytesRead] = 0;
m_captured += buf;
} else if (bytesRead < 0) {
fd_blocked = ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR));
fd_blocked = ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR)) && (maxwait > 0);
if (fd_blocked) std::this_thread::sleep_for(std::chrono::milliseconds(10));
--maxwait;
}
} while (fd_blocked || (bytesRead == (bufSize - 1)));
m_capturing = false;