Merge branch 'develop' into regression-tests
@ -28,7 +28,6 @@ fep scripts for free-energy perturbation with FEP pkg
|
||||
i-pi Python wrapper for performing path-integral MD (PIMD)
|
||||
ipp input pre-processor Perl tool for creating input scripts
|
||||
kate add-ons to Kate editor for editing LAMMPS input scripts
|
||||
lammps-shell LAMMPS executable enhanced for interactive use
|
||||
lmp2arc convert LAMMPS output to Accelrys Insight format
|
||||
lmp2cfg convert LAMMPS output to CFG files for AtomEye viz
|
||||
magic patterns to detect LAMMPS files with the file(1) command
|
||||
|
||||
@ -56,7 +56,8 @@
|
||||
"LAMMPS output.")
|
||||
|
||||
(defvar lammps-read
|
||||
'("include"
|
||||
'("geturl"
|
||||
"include"
|
||||
"read"
|
||||
"read_restart"
|
||||
"read_data")
|
||||
|
||||
@ -48,6 +48,7 @@
|
||||
<item>echo</item>
|
||||
<item>fix</item>
|
||||
<item>fix_modify</item>
|
||||
<item>geturl</item>
|
||||
<item>group</item>
|
||||
<item>if</item>
|
||||
<item>improper_coeff</item>
|
||||
|
||||
@ -1,6 +1,6 @@
|
||||
cmake_minimum_required(VERSION 3.16)
|
||||
|
||||
project(lammps-gui VERSION 1.5.12 LANGUAGES CXX)
|
||||
project(lammps-gui VERSION 1.6.8 LANGUAGES CXX)
|
||||
|
||||
set(CMAKE_AUTOUIC ON)
|
||||
set(CMAKE_AUTOMOC ON)
|
||||
@ -22,7 +22,13 @@ function(check_omp_h_include)
|
||||
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)
|
||||
# there are all kinds of problems with finding omp.h
|
||||
# for Clang and derived compilers so we pretend it is there.
|
||||
if(CMAKE_CXX_COMPILER_ID STREQUAL "Clang")
|
||||
set(_have_omp_h TRUE)
|
||||
else()
|
||||
check_include_file_cxx(omp.h _have_omp_h)
|
||||
endif()
|
||||
else()
|
||||
set(_have_omp_h FALSE)
|
||||
endif()
|
||||
@ -88,11 +94,6 @@ else()
|
||||
endif()
|
||||
endif()
|
||||
|
||||
#get_lammps_version(${LAMMPS_SOURCE_DIR}/version.h LAMMPS_VERSION)
|
||||
#if (LAMMPS_VERSION LESS_EQUAL 20230802)
|
||||
# message(FATAL_ERROR "LAMMPS GUI v${PROJECT_VERSION} is incompatible with LAMMPS 2 August 2023 or older")
|
||||
#endif()
|
||||
|
||||
set(LAMMPS_PLUGINLIB_DIR ${LAMMPS_DIR}/examples/COUPLE/plugin)
|
||||
if(LAMMPS_GUI_USE_PLUGIN)
|
||||
if(APPLE)
|
||||
@ -118,7 +119,7 @@ if(NOT Qt6_FOUND)
|
||||
else()
|
||||
set(QT_VERSION_MAJOR 6)
|
||||
endif()
|
||||
message(STATUS "Using Qt version ${Qt${QT_VERSION_MAJOR}_VERSION} for LAMMPS GUI")
|
||||
message(STATUS "Using Qt version ${Qt${QT_VERSION_MAJOR}_VERSION} for LAMMPS-GUI")
|
||||
|
||||
set(PROJECT_SOURCES
|
||||
main.cpp
|
||||
@ -140,6 +141,8 @@ set(PROJECT_SOURCES
|
||||
linenumberarea.h
|
||||
logwindow.cpp
|
||||
logwindow.h
|
||||
fileviewer.cpp
|
||||
fileviewer.h
|
||||
preferences.cpp
|
||||
preferences.h
|
||||
setvariables.cpp
|
||||
@ -195,14 +198,43 @@ if(BUILD_OMP)
|
||||
target_link_libraries(lammps-gui PRIVATE OpenMP::OpenMP_CXX)
|
||||
endif()
|
||||
|
||||
# build LAMMPS-GUI and LAMMPS as flatpak, if tools are installed
|
||||
find_program(FLATPAK_COMMAND flatpak DOC "Path to flatpak command")
|
||||
find_program(FLATPAK_BUILDER flatpak-builder DOC "Path to flatpak-builder command")
|
||||
if(FLATPAK_COMMAND AND FLATPAK_BUILDER)
|
||||
file(STRINGS ${LAMMPS_DIR}/src/version.h line REGEX LAMMPS_VERSION)
|
||||
string(REGEX REPLACE "#define LAMMPS_VERSION \"([0-9]+) ([A-Za-z][A-Za-z][A-Za-z])[A-Za-z]* ([0-9]+)\""
|
||||
"\\1\\2\\3" LAMMPS_RELEASE "${line}")
|
||||
set(FLATPAK_BUNDLE "LAMMPS_GUI-Linux-amd64-${LAMMPS_RELEASE}.flatpak")
|
||||
add_custom_target(flatpak
|
||||
COMMAND ${FLATPAK_COMMAND} --user remote-add --if-not-exists flathub https://dl.flathub.org/repo/flathub.flatpakrepo
|
||||
COMMAND ${FLATPAK_BUILDER} --force-clean --verbose --repo=${CMAKE_CURRENT_BINARY_DIR}/flatpak-repo
|
||||
--install-deps-from=flathub --state-dir=${CMAKE_CURRENT_BINARY_DIR}
|
||||
--user --ccache --default-branch=${LAMMPS_RELEASE}
|
||||
flatpak-build ${LAMMPS_DIR}/tools/lammps-gui/org.lammps.lammps-gui.yml
|
||||
COMMAND ${FLATPAK_COMMAND} build-bundle --runtime-repo=https://flathub.org/repo/flathub.flatpakrepo --verbose
|
||||
${CMAKE_CURRENT_BINARY_DIR}/flatpak-repo
|
||||
${FLATPAK_BUNDLE} org.lammps.lammps-gui ${LAMMPS_RELEASE}
|
||||
COMMENT "Create Flatpak bundle file of LAMMPS-GUI and LAMMPS"
|
||||
BYPRODUCT ${FLATPAK_BUNDLE}
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
else()
|
||||
add_custom_target(flatpak
|
||||
COMMAND ${CMAKE_COMMAND} -E echo "The flatpak and flatpak-builder commands required to build a LAMMPS-GUI flatpak bundle were not found. Skipping.")
|
||||
endif()
|
||||
|
||||
# when compiling on macOS, create an "app bundle"
|
||||
if(APPLE)
|
||||
file(STRINGS ${LAMMPS_DIR}/src/version.h line REGEX LAMMPS_VERSION)
|
||||
string(REGEX REPLACE "#define LAMMPS_VERSION \"([0-9]+) ([A-Za-z][A-Za-z][A-Za-z])[A-Za-z]* ([0-9]+)\""
|
||||
"\\1\\2\\3" LAMMPS_RELEASE "${line}")
|
||||
set_target_properties(lammps-gui PROPERTIES
|
||||
MACOSX_BUNDLE_INFO_PLIST ${LAMMPS_DIR}/cmake/packaging/MacOSXBundleInfo.plist.in
|
||||
MACOSX_BUNDLE_BUNDLE_VERSION ${PROJECT_VERSION}
|
||||
MACOSX_BUNDLE_SHORT_VERSION_STRING ${PROJECT_VERSION_MAJOR}.${PROJECT_VERSION_MINOR}
|
||||
MACOSX_BUNDLE_ICON_FILE lammps.icns
|
||||
MACOSX_BUNDLE_COPYRIGHT "(c) 2003 - 2023, The LAMMPS Developers"
|
||||
MACOSX_BUNDLE_COPYRIGHT "(c) 2003 - 2024, The LAMMPS Developers"
|
||||
MACOSX_BUNDLE TRUE
|
||||
)
|
||||
# additional targets to populate the bundle tree and create the .dmg image file
|
||||
@ -244,14 +276,17 @@ if(APPLE)
|
||||
set(FFMPEG_TARGET copy-ffmpeg)
|
||||
endif()
|
||||
add_custom_target(dmg
|
||||
COMMAND ${LAMMPS_DIR}/cmake/packaging/build_macos_dmg.sh
|
||||
COMMAND ${LAMMPS_DIR}/cmake/packaging/build_macos_dmg.sh ${LAMMPS_RELEASE}
|
||||
DEPENDS complete-bundle ${FFMPEG_TARGET}
|
||||
COMMENT "Create Drag-n-Drop installer disk image from app bundle"
|
||||
BYPRODUCT LAMMPS-macOS-multiarch.dmg
|
||||
BYPRODUCT LAMMPS-macOS-multiarch-${LAMMPS_VERSION}.dmg
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
# settings or building on Windows with Visual Studio
|
||||
elseif(MSVC)
|
||||
file(STRINGS ${LAMMPS_DIR}/src/version.h line REGEX LAMMPS_VERSION)
|
||||
string(REGEX REPLACE "#define LAMMPS_VERSION \"([0-9]+) ([A-Za-z][A-Za-z][A-Za-z])[A-Za-z]* ([0-9]+)\""
|
||||
"\\1\\2\\3" LAMMPS_RELEASE "${line}")
|
||||
install(TARGETS lammps-gui DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(FILES $<TARGET_RUNTIME_DLLS:lammps-gui> TYPE BIN)
|
||||
if(BUILD_SHARED_LIBS)
|
||||
@ -266,6 +301,9 @@ elseif(MSVC)
|
||||
get_filename_component(INSTNAME ${CMAKE_INSTALL_PREFIX} NAME)
|
||||
install(CODE "execute_process(COMMAND \"${CMAKE_COMMAND}\" -D INSTNAME=${INSTNAME} -D VC_INIT=\"${VC_INIT}\" -D QT5_BIN_DIR=\"${QT5_BIN_DIR}\" -P \"${CMAKE_SOURCE_DIR}/packaging/build_windows_vs.cmake\" WORKING_DIRECTORY \"${CMAKE_INSTALL_PREFIX}/..\" COMMAND_ECHO STDOUT)")
|
||||
elseif((CMAKE_SYSTEM_NAME STREQUAL "Windows") AND CMAKE_CROSSCOMPILING)
|
||||
file(STRINGS ${LAMMPS_DIR}/src/version.h line REGEX LAMMPS_VERSION)
|
||||
string(REGEX REPLACE "#define LAMMPS_VERSION \"([0-9]+) ([A-Za-z][A-Za-z][A-Za-z])[A-Za-z]* ([0-9]+)\""
|
||||
"\\1\\2\\3" LAMMPS_RELEASE "${line}")
|
||||
install(TARGETS lammps-gui DESTINATION ${CMAKE_INSTALL_BINDIR})
|
||||
install(FILES $<TARGET_RUNTIME_DLLS:lammps-gui> TYPE BIN)
|
||||
if(BUILD_SHARED_LIBS)
|
||||
@ -273,14 +311,18 @@ elseif((CMAKE_SYSTEM_NAME STREQUAL "Windows") AND CMAKE_CROSSCOMPILING)
|
||||
endif()
|
||||
install(FILES $<TARGET_RUNTIME_DLLS:lmp> TYPE BIN)
|
||||
add_custom_target(zip
|
||||
COMMAND sh -vx ${LAMMPS_DIR}/cmake/packaging/build_windows_cross_zip.sh ${CMAKE_INSTALL_PREFIX}
|
||||
COMMAND sh -vx ${LAMMPS_DIR}/cmake/packaging/build_windows_cross_zip.sh ${CMAKE_INSTALL_PREFIX} ${LAMMPS_RELEASE}
|
||||
DEPENDS lmp lammps-gui
|
||||
COMMENT "Create zip file with windows binaries"
|
||||
BYPRODUCT LAMMPS-Win10-amd64.zip
|
||||
BYPRODUCT LAMMPS-Win10-amd64-${LAMMPS_VERSION}.zip
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR})
|
||||
elseif((CMAKE_SYSTEM_NAME STREQUAL "Linux") AND NOT LAMMPS_GUI_USE_PLUGIN)
|
||||
file(STRINGS ${LAMMPS_DIR}/src/version.h line REGEX LAMMPS_VERSION)
|
||||
string(REGEX REPLACE "#define LAMMPS_VERSION \"([0-9]+) ([A-Za-z][A-Za-z][A-Za-z])[A-Za-z]* ([0-9]+)\""
|
||||
"\\1\\2\\3" LAMMPS_RELEASE "${line}")
|
||||
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-gui.appdata.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/appdata/)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/lammps-input.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/packages/)
|
||||
install(FILES ${CMAKE_CURRENT_SOURCE_DIR}/lammps-input.xml DESTINATION ${CMAKE_INSTALL_DATADIR}/mime/text/x-application-lammps.xml)
|
||||
install(DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}/icons/hicolor DESTINATION ${CMAKE_INSTALL_DATADIR}/icons/)
|
||||
@ -304,11 +346,12 @@ elseif((CMAKE_SYSTEM_NAME STREQUAL "Linux") AND NOT LAMMPS_GUI_USE_PLUGIN)
|
||||
message(WARNING "Unresolved dependencies detected: ${_u_deps}")
|
||||
endif() ]]
|
||||
)
|
||||
|
||||
add_custom_target(tgz
|
||||
COMMAND ${LAMMPS_DIR}/cmake/packaging/build_linux_tgz.sh
|
||||
COMMAND ${LAMMPS_DIR}/cmake/packaging/build_linux_tgz.sh ${LAMMPS_RELEASE}
|
||||
DEPENDS lammps-gui
|
||||
COMMENT "Create compressed tar file of LAMMPS with dependent libraries and wrapper"
|
||||
BYPRODUCT LAMMPS-Linux-amd64.tar.gz
|
||||
COMMENT "Create compressed tar file of LAMMPS-GUI with dependent libraries and wrapper"
|
||||
BYPRODUCT LAMMPS-Linux-amd64-${LAMMPS_RELEASE}.tar.gz
|
||||
WORKING_DIRECTORY ${CMAKE_BINARY_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
@ -1,14 +1,14 @@
|
||||
LAMMPS GUI
|
||||
LAMMPS-GUI
|
||||
|
||||
LAMMPS GUI is essentially a small graphical text editor that is linked
|
||||
LAMMPS-GUI is essentially a small graphical text editor that is linked
|
||||
to the LAMMPS library and thus can run LAMMPS using the contents of the
|
||||
text buffer as input directly without requiring an additional LAMMPS
|
||||
executable. It can also capture and show the screen output, a line graph
|
||||
of thermodynamic data and snapshot images in separate windows.
|
||||
|
||||
Detailed documentation about installing and using LAMMPS GUI is in
|
||||
Detailed documentation about installing and using LAMMPS-GUI is in
|
||||
the LAMMPS manual.
|
||||
|
||||
--------
|
||||
|
||||
updated by Axel Kohlmeyer, 2023-08-12
|
||||
updated by Axel Kohlmeyer, 2024-07-17
|
||||
|
||||
@ -2,6 +2,14 @@ LAMMPS-GUI TODO list:
|
||||
|
||||
# Short term goals (v1.x)
|
||||
|
||||
- figure out how widgets can be resized to fraction of available screen size.
|
||||
- figure out stacking order of frames and whether it can be more flexible
|
||||
- figure out how to avoid corrupted cached thermo data while reading it.
|
||||
- implement a timed "Auto-Save" feature that saves after some idle time. set timeout in Editor preferences.
|
||||
- add a "Colors" menu to the image viewer to adjust color settings for the
|
||||
current image (unlike the defaults in the perferences). Support color by
|
||||
property (e.g. scan computes or fixes with per-atom data), define colormaps etc.
|
||||
|
||||
- implement indenting regions for (nested) loops?
|
||||
- implement data file manager GUI with the following features:
|
||||
- import coordinates and topology via VMD molfile plugins
|
||||
|
||||
@ -17,6 +17,11 @@
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QChart>
|
||||
#include <QCheckBox>
|
||||
#include <QCloseEvent>
|
||||
#include <QComboBox>
|
||||
#include <QEvent>
|
||||
#include <QFileDialog>
|
||||
#include <QHBoxLayout>
|
||||
#include <QKeySequence>
|
||||
@ -28,15 +33,21 @@
|
||||
#include <QPushButton>
|
||||
#include <QSettings>
|
||||
#include <QSpacerItem>
|
||||
#include <QSpinBox>
|
||||
#include <QTextStream>
|
||||
#include <QTime>
|
||||
#include <QVBoxLayout>
|
||||
#include <QValueAxis>
|
||||
#include <QVariant>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
using namespace QtCharts;
|
||||
|
||||
ChartWindow::ChartWindow(const QString &_filename, QWidget *parent) :
|
||||
QWidget(parent), menu(new QMenuBar), file(new QMenu("&File")), filename(_filename)
|
||||
QWidget(parent), menu(new QMenuBar), file(new QMenu("&File")), saveAsAct(nullptr),
|
||||
exportCsvAct(nullptr), exportDatAct(nullptr), exportYamlAct(nullptr), closeAct(nullptr),
|
||||
stopAct(nullptr), quitAct(nullptr), filename(_filename)
|
||||
{
|
||||
auto *top = new QHBoxLayout;
|
||||
menu->addMenu(file);
|
||||
@ -45,6 +56,20 @@ ChartWindow::ChartWindow(const QString &_filename, QWidget *parent) :
|
||||
// workaround for incorrect highlight bug on macOS
|
||||
auto *dummy = new QPushButton(QIcon(), "");
|
||||
dummy->hide();
|
||||
|
||||
smooth = new QCheckBox("Show smooth graph");
|
||||
smooth->setCheckState(Qt::Unchecked);
|
||||
window = new QSpinBox;
|
||||
window->setRange(5, 100);
|
||||
window->setValue(10);
|
||||
window->setEnabled(false);
|
||||
window->setToolTip("Smoothing Window Size");
|
||||
order = new QSpinBox;
|
||||
order->setRange(1, 10);
|
||||
order->setValue(4);
|
||||
order->setEnabled(false);
|
||||
order->setToolTip("Smoothing Order");
|
||||
|
||||
auto *normal = new QPushButton(QIcon(":/icons/gtk-zoom-fit.png"), "");
|
||||
normal->setToolTip("Reset zoom to normal");
|
||||
|
||||
@ -52,7 +77,12 @@ ChartWindow::ChartWindow(const QString &_filename, QWidget *parent) :
|
||||
top->addWidget(menu);
|
||||
top->addSpacerItem(new QSpacerItem(1, 1, QSizePolicy::Expanding, QSizePolicy::Minimum));
|
||||
top->addWidget(dummy);
|
||||
top->addWidget(smooth);
|
||||
top->addWidget(window);
|
||||
top->addWidget(order);
|
||||
top->addWidget(new QLabel(" "));
|
||||
top->addWidget(normal);
|
||||
top->addWidget(new QLabel(" "));
|
||||
top->addWidget(new QLabel("Select data:"));
|
||||
top->addWidget(columns);
|
||||
saveAsAct = file->addAction("&Save Graph As...", this, &ChartWindow::saveAs);
|
||||
@ -61,6 +91,8 @@ ChartWindow::ChartWindow(const QString &_filename, QWidget *parent) :
|
||||
exportCsvAct->setIcon(QIcon(":/icons/application-calc.png"));
|
||||
exportDatAct = file->addAction("Export data to &Gnuplot...", this, &ChartWindow::exportDat);
|
||||
exportDatAct->setIcon(QIcon(":/icons/application-plot.png"));
|
||||
exportYamlAct = file->addAction("Export data to &YAML...", this, &ChartWindow::exportYaml);
|
||||
exportYamlAct->setIcon(QIcon(":/icons/yaml-file-icon.png"));
|
||||
file->addSeparator();
|
||||
stopAct = file->addAction("Stop &Run", this, &ChartWindow::stop_run);
|
||||
stopAct->setIcon(QIcon(":/icons/process-stop.png"));
|
||||
@ -75,6 +107,11 @@ ChartWindow::ChartWindow(const QString &_filename, QWidget *parent) :
|
||||
layout->addLayout(top);
|
||||
setLayout(layout);
|
||||
|
||||
connect(smooth, &QPushButton::released, this, &ChartWindow::update_smooth);
|
||||
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);
|
||||
connect(order, QOverload<int>::of(&QSpinBox::valueChanged), this, &ChartWindow::update_smooth);
|
||||
connect(normal, &QPushButton::released, this, &ChartWindow::reset_zoom);
|
||||
connect(columns, SIGNAL(currentIndexChanged(int)), this, SLOT(change_chart(int)));
|
||||
installEventFilter(this);
|
||||
@ -137,9 +174,8 @@ void ChartWindow::quit()
|
||||
|
||||
void ChartWindow::reset_zoom()
|
||||
{
|
||||
int choice = columns->currentData().toInt();
|
||||
if ((choice >= 0) && (choice < charts.size()))
|
||||
charts[choice]->reset_zoom();
|
||||
int choice = columns->currentData().toInt() - 1;
|
||||
if ((choice >= 0) && (choice < charts.size())) charts[choice]->reset_zoom();
|
||||
}
|
||||
|
||||
void ChartWindow::stop_run()
|
||||
@ -150,6 +186,19 @@ void ChartWindow::stop_run()
|
||||
if (main) main->stop_run();
|
||||
}
|
||||
|
||||
void ChartWindow::update_smooth()
|
||||
{
|
||||
bool do_smooth = smooth->isChecked();
|
||||
window->setEnabled(do_smooth);
|
||||
order->setEnabled(do_smooth);
|
||||
|
||||
int wval = window->value();
|
||||
int oval = order->value();
|
||||
|
||||
for (auto &c : charts)
|
||||
c->smooth_param(do_smooth, wval, oval);
|
||||
}
|
||||
|
||||
void ChartWindow::saveAs()
|
||||
{
|
||||
if (charts.empty()) return;
|
||||
@ -228,6 +277,40 @@ void ChartWindow::exportCsv()
|
||||
}
|
||||
}
|
||||
}
|
||||
void ChartWindow::exportYaml()
|
||||
{
|
||||
if (charts.empty()) return;
|
||||
QString defaultname = filename + ".yaml";
|
||||
if (filename.isEmpty()) defaultname = "lammpsdata.yaml";
|
||||
QString fileName = QFileDialog::getSaveFileName(this, "Save Chart as YAML data", defaultname,
|
||||
"Image Files (*.yaml, *.yml)");
|
||||
if (!fileName.isEmpty()) {
|
||||
QFile file(fileName);
|
||||
if (file.open(QIODevice::WriteOnly | QIODevice::Text)) {
|
||||
QTextStream out(&file);
|
||||
out.setRealNumberPrecision(8);
|
||||
out << "---\n";
|
||||
|
||||
out << "keywords: ['Step'";
|
||||
for (auto &c : charts)
|
||||
out << ", " << c->get_title();
|
||||
out << "]\n";
|
||||
|
||||
out << "data: \n";
|
||||
int lines = charts[0]->get_count();
|
||||
for (int i = 0; i < lines; ++i) {
|
||||
// timestep
|
||||
out << " - [" << charts[0]->get_step(i);
|
||||
// data
|
||||
for (auto &c : charts)
|
||||
out << ", " << c->get_data(i);
|
||||
out << "]\n";
|
||||
}
|
||||
out << "...\n";
|
||||
file.close();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void ChartWindow::change_chart(int)
|
||||
{
|
||||
@ -273,8 +356,9 @@ bool ChartWindow::eventFilter(QObject *watched, QEvent *event)
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
ChartViewer::ChartViewer(const QString &title, int _index, QWidget *parent) :
|
||||
QChartView(parent), last_step(-1), index(_index), chart(new QChart), series(new QLineSeries),
|
||||
xaxis(new QValueAxis), yaxis(new QValueAxis)
|
||||
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)
|
||||
{
|
||||
chart->legend()->hide();
|
||||
chart->addAxis(xaxis, Qt::AlignBottom);
|
||||
@ -294,6 +378,18 @@ ChartViewer::ChartViewer(const QString &title, int _index, QWidget *parent) :
|
||||
setRenderHint(QPainter::Antialiasing);
|
||||
setChart(chart);
|
||||
setRubberBand(QChartView::RectangleRubberBand);
|
||||
last_update = QTime::currentTime();
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
ChartViewer::~ChartViewer()
|
||||
{
|
||||
delete xaxis;
|
||||
delete yaxis;
|
||||
delete smooth;
|
||||
delete series;
|
||||
delete chart;
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
@ -302,8 +398,36 @@ void ChartViewer::add_data(int step, double data)
|
||||
{
|
||||
if (last_step < step) {
|
||||
last_step = step;
|
||||
|
||||
// do not add data that deviates by more than 5 sigma from the average
|
||||
// over the last 5 to 20 data items. this is a hack to work around
|
||||
// getting corrupted data from lammps_get_last_thermo()
|
||||
const auto &points = series->points();
|
||||
const auto count = points.count();
|
||||
if (count > 4) {
|
||||
double ysum = 0.0;
|
||||
double ysumsq = 0.0;
|
||||
int first = count - 20;
|
||||
if (first < 0) first = 0;
|
||||
for (int i = first; i < count; ++i) {
|
||||
double val = points[i].y();
|
||||
ysum += val;
|
||||
ysumsq += val * val;
|
||||
}
|
||||
const double num = count - first;
|
||||
const double avg = ysum / num;
|
||||
const double avgsq = ysumsq / num;
|
||||
if (fabs(data - avg) > (5.0 * sqrt(avgsq - (avg * avg)))) return;
|
||||
}
|
||||
series->append(step, data);
|
||||
reset_zoom();
|
||||
|
||||
QSettings settings;
|
||||
// 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();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -313,6 +437,7 @@ void ChartViewer::reset_zoom()
|
||||
{
|
||||
auto points = series->points();
|
||||
|
||||
// get min/max for plot
|
||||
qreal xmin = 1.0e100;
|
||||
qreal xmax = -1.0e100;
|
||||
qreal ymin = 1.0e100;
|
||||
@ -324,6 +449,17 @@ void ChartViewer::reset_zoom()
|
||||
ymax = qMax(ymax, p.y());
|
||||
}
|
||||
|
||||
// if plotting the smoothed plot, check for its min/max values, too
|
||||
if (smooth) {
|
||||
auto spoints = smooth->points();
|
||||
for (auto &p : spoints) {
|
||||
xmin = qMin(xmin, p.x());
|
||||
xmax = qMax(xmax, p.x());
|
||||
ymin = qMin(ymin, p.y());
|
||||
ymax = qMax(ymax, p.y());
|
||||
}
|
||||
}
|
||||
|
||||
// avoid (nearly) empty ranges
|
||||
double deltax = xmax - xmin;
|
||||
if ((deltax / ((xmax == 0.0) ? 1.0 : xmax)) < 1.0e-10) {
|
||||
@ -351,6 +487,490 @@ void ChartViewer::reset_zoom()
|
||||
yaxis->setRange(ymin, ymax);
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
void ChartViewer::smooth_param(bool _do_smooth, int _window, int _order)
|
||||
{
|
||||
// turn off smooth plot
|
||||
if (!_do_smooth) {
|
||||
if (smooth) {
|
||||
chart->removeSeries(smooth);
|
||||
delete smooth;
|
||||
smooth = nullptr;
|
||||
}
|
||||
}
|
||||
do_smooth = _do_smooth;
|
||||
window = _window;
|
||||
order = _order;
|
||||
update_smooth();
|
||||
}
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
// update smooth plot data
|
||||
|
||||
static QList<QPointF> calc_sgsmooth(const QList<QPointF> &input, const int window, const int order);
|
||||
|
||||
void ChartViewer::update_smooth()
|
||||
{
|
||||
if (do_smooth) {
|
||||
if (series->count() > (2 * window)) {
|
||||
if (!smooth) {
|
||||
smooth = new QLineSeries;
|
||||
chart->addSeries(smooth);
|
||||
smooth->attachAxis(xaxis);
|
||||
smooth->attachAxis(yaxis);
|
||||
}
|
||||
smooth->clear();
|
||||
smooth->append(calc_sgsmooth(series->points(), window, order));
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//! default convergence
|
||||
static constexpr double TINY_FLOAT = 1.0e-300;
|
||||
|
||||
//! comfortable array of doubles
|
||||
typedef std::vector<double> float_vect;
|
||||
//! comfortable array of ints;
|
||||
typedef std::vector<int> int_vect;
|
||||
|
||||
// savitzky golay smoothing.
|
||||
static float_vect sg_smooth(const float_vect &v, const int w, const int deg);
|
||||
|
||||
QList<QPointF> calc_sgsmooth(const QList<QPointF> &input, int window, int order)
|
||||
{
|
||||
const int ndat = input.count();
|
||||
if (ndat < 2 * window + 2) window = ndat / 2 - 1;
|
||||
|
||||
if (window > 1) {
|
||||
float_vect in(ndat);
|
||||
QList<QPointF> rv;
|
||||
|
||||
for (int i = 0; i < ndat; ++i) {
|
||||
in[i] = input[i].y();
|
||||
}
|
||||
float_vect out = sg_smooth(in, window, order);
|
||||
|
||||
for (int i = 0; i < ndat; ++i) {
|
||||
rv.append(QPointF(input[i].x(), out[i]));
|
||||
}
|
||||
return rv;
|
||||
} else {
|
||||
return input;
|
||||
}
|
||||
}
|
||||
|
||||
/*! matrix class.
|
||||
*
|
||||
* This is a matrix class derived from a vector of float_vects. Note that
|
||||
* the matrix elements indexed [row][column] with indices starting at 0 (c
|
||||
* style). Also note that because of its design looping through rows should
|
||||
* be faster than looping through columns.
|
||||
*
|
||||
* \brief two dimensional floating point array
|
||||
*/
|
||||
class float_mat : public std::vector<float_vect> {
|
||||
private:
|
||||
//! disable the default constructor
|
||||
explicit float_mat() {};
|
||||
//! disable assignment operator until it is implemented.
|
||||
float_mat &operator=(const float_mat &) { return *this; };
|
||||
|
||||
public:
|
||||
//! constructor with sizes
|
||||
float_mat(const std::size_t rows, const std::size_t cols, const double def = 0.0);
|
||||
//! copy constructor for matrix
|
||||
float_mat(const float_mat &m);
|
||||
//! copy constructor for vector
|
||||
float_mat(const float_vect &v);
|
||||
|
||||
//! use default destructor
|
||||
// ~float_mat() {};
|
||||
|
||||
//! get size
|
||||
int nr_rows(void) const { return size(); };
|
||||
//! get size
|
||||
int nr_cols(void) const { return front().size(); };
|
||||
};
|
||||
|
||||
// constructor with sizes
|
||||
float_mat::float_mat(const std::size_t rows, const std::size_t cols, const double defval) :
|
||||
std::vector<float_vect>(rows)
|
||||
{
|
||||
for (std::size_t i = 0; i < rows; ++i) {
|
||||
(*this)[i].resize(cols, defval);
|
||||
}
|
||||
#if 0
|
||||
if ((rows < 1) || (cols < 1)) {
|
||||
char buffer[1024];
|
||||
|
||||
sprintf(buffer, "cannot build matrix with %d rows and %d columns\n",
|
||||
rows, cols);
|
||||
sgs_error(buffer);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
// copy constructor for matrix
|
||||
float_mat::float_mat(const float_mat &m) : std::vector<float_vect>(m.size())
|
||||
{
|
||||
|
||||
float_mat::iterator inew = begin();
|
||||
float_mat::const_iterator iold = m.begin();
|
||||
for (/* empty */; iold < m.end(); ++inew, ++iold) {
|
||||
const auto oldsz = iold->size();
|
||||
inew->resize(oldsz);
|
||||
const float_vect oldvec(*iold);
|
||||
*inew = oldvec;
|
||||
}
|
||||
}
|
||||
|
||||
// copy constructor for vector
|
||||
float_mat::float_mat(const float_vect &v) : std::vector<float_vect>(1)
|
||||
{
|
||||
|
||||
const auto oldsz = v.size();
|
||||
front().resize(oldsz);
|
||||
front() = v;
|
||||
}
|
||||
|
||||
//////////////////////
|
||||
// Helper functions //
|
||||
//////////////////////
|
||||
|
||||
//! permute() orders the rows of A to match the integers in the index array.
|
||||
void permute(float_mat &A, int_vect &idx)
|
||||
{
|
||||
int_vect i(idx.size());
|
||||
|
||||
for (int j = 0; j < A.nr_rows(); ++j) {
|
||||
i[j] = j;
|
||||
}
|
||||
|
||||
// loop over permuted indices
|
||||
for (int j = 0; j < A.nr_rows(); ++j) {
|
||||
if (i[j] != idx[j]) {
|
||||
|
||||
// search only the remaining indices
|
||||
for (int k = j + 1; k < A.nr_rows(); ++k) {
|
||||
if (i[k] == idx[j]) {
|
||||
std::swap(A[j], A[k]); // swap the rows and
|
||||
i[k] = i[j]; // the elements of
|
||||
i[j] = idx[j]; // the ordered index.
|
||||
break; // next j
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Implicit partial pivoting.
|
||||
*
|
||||
* The function looks for pivot element only in rows below the current
|
||||
* element, A[idx[row]][column], then swaps that row with the current one in
|
||||
* the index map. The algorithm is for implicit pivoting (i.e., the pivot is
|
||||
* chosen as if the max coefficient in each row is set to 1) based on the
|
||||
* scaling information in the vector scale. The map of swapped indices is
|
||||
* recorded in swp. The return value is +1 or -1 depending on whether the
|
||||
* number of row swaps was even or odd respectively. */
|
||||
static int partial_pivot(float_mat &A, const std::size_t row, const std::size_t col,
|
||||
float_vect &scale, int_vect &idx, double tol)
|
||||
{
|
||||
if (tol <= 0.0) tol = TINY_FLOAT;
|
||||
|
||||
int swapNum = 1;
|
||||
|
||||
// default pivot is the current position, [row,col]
|
||||
std::size_t pivot = row;
|
||||
double piv_elem = fabs(A[idx[row]][col]) * scale[idx[row]];
|
||||
|
||||
// loop over possible pivots below current
|
||||
for (int j = row + 1; j < A.nr_rows(); ++j) {
|
||||
|
||||
const double tmp = fabs(A[idx[j]][col]) * scale[idx[j]];
|
||||
|
||||
// if this elem is larger, then it becomes the pivot
|
||||
if (tmp > piv_elem) {
|
||||
pivot = j;
|
||||
piv_elem = tmp;
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if(piv_elem < tol) {
|
||||
sgs_error("partial_pivot(): Zero pivot encountered.\n")
|
||||
#endif
|
||||
|
||||
if (pivot > row) { // bring the pivot to the diagonal
|
||||
int j = idx[row]; // reorder swap array
|
||||
idx[row] = idx[pivot];
|
||||
idx[pivot] = j;
|
||||
swapNum = -swapNum; // keeping track of odd or even swap
|
||||
}
|
||||
return swapNum;
|
||||
}
|
||||
|
||||
/*! \brief Perform backward substitution.
|
||||
*
|
||||
* Solves the system of equations A*b=a, ASSUMING that A is upper
|
||||
* triangular. If diag==1, then the diagonal elements are additionally
|
||||
* assumed to be 1. Note that the lower triangular elements are never
|
||||
* checked, so this function is valid to use after a LU-decomposition in
|
||||
* place. A is not modified, and the solution, b, is returned in a. */
|
||||
static void lu_backsubst(float_mat &A, float_mat &a, bool diag = false)
|
||||
{
|
||||
for (int r = (A.nr_rows() - 1); r >= 0; --r) {
|
||||
for (int c = (A.nr_cols() - 1); c > r; --c) {
|
||||
for (int k = 0; k < A.nr_cols(); ++k) {
|
||||
a[r][k] -= A[r][c] * a[c][k];
|
||||
}
|
||||
}
|
||||
if (!diag) {
|
||||
for (int k = 0; k < A.nr_cols(); ++k) {
|
||||
a[r][k] /= A[r][r];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Perform forward substitution.
|
||||
*
|
||||
* Solves the system of equations A*b=a, ASSUMING that A is lower
|
||||
* triangular. If diag==1, then the diagonal elements are additionally
|
||||
* assumed to be 1. Note that the upper triangular elements are never
|
||||
* checked, so this function is valid to use after a LU-decomposition in
|
||||
* place. A is not modified, and the solution, b, is returned in a. */
|
||||
static void lu_forwsubst(float_mat &A, float_mat &a, bool diag = true)
|
||||
{
|
||||
for (int r = 0; r < A.nr_rows(); ++r) {
|
||||
for (int c = 0; c < r; ++c) {
|
||||
for (int k = 0; k < A.nr_cols(); ++k) {
|
||||
a[r][k] -= A[r][c] * a[c][k];
|
||||
}
|
||||
}
|
||||
if (!diag) {
|
||||
for (int k = 0; k < A.nr_cols(); ++k) {
|
||||
a[r][k] /= A[r][r];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*! \brief Performs LU factorization in place.
|
||||
*
|
||||
* This is Crout's algorithm (cf., Num. Rec. in C, Section 2.3). The map of
|
||||
* swapped indeces is recorded in idx. The return value is +1 or -1
|
||||
* depending on whether the number of row swaps was even or odd
|
||||
* respectively. idx must be preinitialized to a valid set of indices
|
||||
* (e.g., {1,2, ... ,A.nr_rows()}). */
|
||||
static int lu_factorize(float_mat &A, int_vect &idx, double tol = TINY_FLOAT)
|
||||
{
|
||||
if (tol <= 0.0) tol = TINY_FLOAT;
|
||||
#if 0
|
||||
if ((A.nr_rows() == 0) || (A.nr_rows() != A.nr_cols())) {
|
||||
sgs_error("lu_factorize(): cannot handle empty "
|
||||
"or nonsquare matrices.\n");
|
||||
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
float_vect scale(A.nr_rows()); // implicit pivot scaling
|
||||
for (int i = 0; i < A.nr_rows(); ++i) {
|
||||
double maxval = 0.0;
|
||||
for (int j = 0; j < A.nr_cols(); ++j) {
|
||||
if (fabs(A[i][j]) > maxval) maxval = fabs(A[i][j]);
|
||||
}
|
||||
if (maxval == 0.0) {
|
||||
#if 0
|
||||
sgs_error("lu_factorize(): zero pivot found.\n");
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
scale[i] = 1.0 / maxval;
|
||||
}
|
||||
|
||||
int swapNum = 1;
|
||||
for (int c = 0; c < A.nr_cols(); ++c) { // loop over columns
|
||||
swapNum *= partial_pivot(A, c, c, scale, idx, tol); // bring pivot to diagonal
|
||||
for (int r = 0; r < A.nr_rows(); ++r) { // loop over rows
|
||||
int lim = (r < c) ? r : c;
|
||||
for (int j = 0; j < lim; ++j) {
|
||||
A[idx[r]][c] -= A[idx[r]][j] * A[idx[j]][c];
|
||||
}
|
||||
if (r > c) A[idx[r]][c] /= A[idx[c]][c];
|
||||
}
|
||||
}
|
||||
permute(A, idx);
|
||||
return swapNum;
|
||||
}
|
||||
|
||||
/*! \brief Solve a system of linear equations.
|
||||
* Solves the inhomogeneous matrix problem with lu-decomposition. Note that
|
||||
* inversion may be accomplished by setting a to the identity_matrix. */
|
||||
static float_mat lin_solve(const float_mat &A, const float_mat &a, double tol = TINY_FLOAT)
|
||||
{
|
||||
float_mat B(A);
|
||||
float_mat b(a);
|
||||
int_vect idx(B.nr_rows());
|
||||
|
||||
for (int j = 0; j < B.nr_rows(); ++j) {
|
||||
idx[j] = j; // init row swap label array
|
||||
}
|
||||
lu_factorize(B, idx, tol); // get the lu-decomp.
|
||||
permute(b, idx); // sort the inhomogeneity to match the lu-decomp
|
||||
lu_forwsubst(B, b); // solve the forward problem
|
||||
lu_backsubst(B, b); // solve the backward problem
|
||||
return b;
|
||||
}
|
||||
|
||||
///////////////////////
|
||||
// related functions //
|
||||
///////////////////////
|
||||
|
||||
//! Returns the inverse of a matrix using LU-decomposition.
|
||||
static float_mat invert(const float_mat &A)
|
||||
{
|
||||
const int n = A.size();
|
||||
float_mat E(n, n, 0.0);
|
||||
float_mat B(A);
|
||||
|
||||
for (int i = 0; i < n; ++i) {
|
||||
E[i][i] = 1.0;
|
||||
}
|
||||
|
||||
return lin_solve(B, E);
|
||||
}
|
||||
|
||||
//! returns the transposed matrix.
|
||||
static float_mat transpose(const float_mat &a)
|
||||
{
|
||||
float_mat res(a.nr_cols(), a.nr_rows());
|
||||
|
||||
for (int i = 0; i < a.nr_rows(); ++i) {
|
||||
for (int j = 0; j < a.nr_cols(); ++j) {
|
||||
res[j][i] = a[i][j];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//! matrix multiplication.
|
||||
float_mat operator*(const float_mat &a, const float_mat &b)
|
||||
{
|
||||
float_mat res(a.nr_rows(), b.nr_cols());
|
||||
#if 0
|
||||
if (a.nr_cols() != b.nr_rows()) {
|
||||
sgs_error("incompatible matrices in multiplication\n");
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
for (int i = 0; i < a.nr_rows(); ++i) {
|
||||
for (int j = 0; j < b.nr_cols(); ++j) {
|
||||
double sum(0.0);
|
||||
for (int k = 0; k < a.nr_cols(); ++k) {
|
||||
sum += a[i][k] * b[k][j];
|
||||
}
|
||||
res[i][j] = sum;
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
//! calculate savitzky golay coefficients.
|
||||
static float_vect sg_coeff(const float_vect &b, const std::size_t deg)
|
||||
{
|
||||
const std::size_t rows(b.size());
|
||||
const std::size_t cols(deg + 1);
|
||||
float_mat A(rows, cols);
|
||||
float_vect res(rows);
|
||||
|
||||
// generate input matrix for least squares fit
|
||||
for (std::size_t i = 0; i < rows; ++i) {
|
||||
for (std::size_t j = 0; j < cols; ++j) {
|
||||
A[i][j] = pow(double(i), double(j));
|
||||
}
|
||||
}
|
||||
|
||||
float_mat c(invert(transpose(A) * A) * (transpose(A) * transpose(b)));
|
||||
|
||||
for (std::size_t i = 0; i < b.size(); ++i) {
|
||||
res[i] = c[0][0];
|
||||
for (std::size_t j = 1; j <= deg; ++j) {
|
||||
res[i] += c[j][0] * pow(double(i), double(j));
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
/*! \brief savitzky golay smoothing.
|
||||
*
|
||||
* This method means fitting a polynome of degree 'deg' to a sliding window
|
||||
* of width 2w+1 throughout the data. The needed coefficients are
|
||||
* generated dynamically by doing a least squares fit on a "symmetric" unit
|
||||
* vector of size 2w+1, e.g. for w=2 b=(0,0,1,0,0). evaluating the polynome
|
||||
* yields the sg-coefficients. at the border non symmectric vectors b are
|
||||
* used. */
|
||||
float_vect sg_smooth(const float_vect &v, const int width, const int deg)
|
||||
{
|
||||
float_vect res(v.size(), 0.0);
|
||||
#if 0
|
||||
if ((width < 1) || (deg < 0) || (v.size() < (2 * width + 2))) {
|
||||
sgs_error("sgsmooth: parameter error.\n");
|
||||
return res;
|
||||
}
|
||||
#endif
|
||||
const int window = 2 * width + 1;
|
||||
const int endidx = v.size() - 1;
|
||||
|
||||
// do a regular sliding window average
|
||||
if (deg == 0) {
|
||||
// handle border cases first because we need different coefficients
|
||||
for (int i = 0; i < width; ++i) {
|
||||
const double scale = 1.0 / double(i + 1);
|
||||
const float_vect c1(width, scale);
|
||||
for (int j = 0; j <= i; ++j) {
|
||||
res[i] += c1[j] * v[j];
|
||||
res[endidx - i] += c1[j] * v[endidx - j];
|
||||
}
|
||||
}
|
||||
|
||||
// now loop over rest of data. reusing the "symmetric" coefficients.
|
||||
const double scale = 1.0 / double(window);
|
||||
const float_vect c2(window, scale);
|
||||
for (std::size_t i = 0; i <= (v.size() - window); ++i) {
|
||||
for (int j = 0; j < window; ++j) {
|
||||
res[i + width] += c2[j] * v[i + j];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// handle border cases first because we need different coefficients
|
||||
for (int i = 0; i < width; ++i) {
|
||||
float_vect b1(window, 0.0);
|
||||
b1[i] = 1.0;
|
||||
|
||||
const float_vect c1(sg_coeff(b1, deg));
|
||||
for (int j = 0; j < window; ++j) {
|
||||
res[i] += c1[j] * v[j];
|
||||
res[endidx - i] += c1[j] * v[endidx - j];
|
||||
}
|
||||
}
|
||||
|
||||
// now loop over rest of data. reusing the "symmetric" coefficients.
|
||||
float_vect b2(window, 0.0);
|
||||
b2[width] = 1.0;
|
||||
const float_vect c2(sg_coeff(b2, deg));
|
||||
|
||||
for (std::size_t i = 0; i <= (v.size() - window); ++i) {
|
||||
for (int j = 0; j < window; ++j) {
|
||||
res[i + width] += c2[j] * v[i + j];
|
||||
}
|
||||
}
|
||||
return res;
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// c-basic-offset: 4
|
||||
// End:
|
||||
|
||||
@ -17,11 +17,16 @@
|
||||
#include <QComboBox>
|
||||
#include <QList>
|
||||
#include <QString>
|
||||
#include <QTime>
|
||||
#include <QWidget>
|
||||
|
||||
class QAction;
|
||||
class QCloseEvent;
|
||||
class QEvent;
|
||||
class QMenuBar;
|
||||
class QMenu;
|
||||
class QCheckBox;
|
||||
class QSpinBox;
|
||||
namespace QtCharts {
|
||||
class ChartViewer;
|
||||
}
|
||||
@ -46,10 +51,12 @@ private slots:
|
||||
void quit();
|
||||
void reset_zoom();
|
||||
void stop_run();
|
||||
void update_smooth();
|
||||
|
||||
void saveAs();
|
||||
void exportDat();
|
||||
void exportCsv();
|
||||
void exportYaml();
|
||||
|
||||
void change_chart(int index);
|
||||
|
||||
@ -61,8 +68,10 @@ private:
|
||||
QMenuBar *menu;
|
||||
QMenu *file;
|
||||
QComboBox *columns;
|
||||
QAction *saveAsAct, *exportCsvAct, *exportDatAct;
|
||||
QAction *saveAsAct, *exportCsvAct, *exportDatAct, *exportYamlAct;
|
||||
QAction *closeAct, *stopAct, *quitAct;
|
||||
QCheckBox *smooth;
|
||||
QSpinBox *window, *order;
|
||||
|
||||
QString filename;
|
||||
QList<QtCharts::ChartViewer *> charts;
|
||||
@ -70,10 +79,10 @@ private:
|
||||
|
||||
/* -------------------------------------------------------------------- */
|
||||
|
||||
#include <QChart>
|
||||
#include <QChartView>
|
||||
#include <QLineSeries>
|
||||
#include <QValueAxis>
|
||||
class QChart;
|
||||
|
||||
namespace QtCharts {
|
||||
class ChartViewer : public QChartView {
|
||||
@ -81,22 +90,28 @@ class ChartViewer : public QChartView {
|
||||
|
||||
public:
|
||||
explicit ChartViewer(const QString &title, int index, QWidget *parent = nullptr);
|
||||
~ChartViewer();
|
||||
|
||||
void add_data(int step, double data);
|
||||
void reset_zoom();
|
||||
void smooth_param(bool _do_smooth, int _window, int _order);
|
||||
void update_smooth();
|
||||
|
||||
int get_index() const { return index; };
|
||||
int get_count() const { return series->count(); }
|
||||
const char *get_title() const { return series->name().toLocal8Bit(); }
|
||||
QString get_title() const { return series->name(); }
|
||||
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;
|
||||
int window, order;
|
||||
QChart *chart;
|
||||
QLineSeries *series;
|
||||
QLineSeries *series, *smooth;
|
||||
QValueAxis *xaxis;
|
||||
QValueAxis *yaxis;
|
||||
QTime last_update;
|
||||
bool do_smooth;
|
||||
};
|
||||
} // namespace QtCharts
|
||||
#endif
|
||||
|
||||
@ -12,7 +12,9 @@
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
#include "codeeditor.h"
|
||||
#include "fileviewer.h"
|
||||
#include "lammpsgui.h"
|
||||
#include "lammpswrapper.h"
|
||||
#include "linenumberarea.h"
|
||||
|
||||
#include <QAbstractItemView>
|
||||
@ -23,20 +25,27 @@
|
||||
#include <QDragEnterEvent>
|
||||
#include <QDropEvent>
|
||||
#include <QFileInfo>
|
||||
#include <QFont>
|
||||
#include <QIcon>
|
||||
#include <QKeySequence>
|
||||
#include <QMenu>
|
||||
#include <QMimeData>
|
||||
#include <QPainter>
|
||||
#include <QRect>
|
||||
#include <QRegularExpression>
|
||||
#include <QScrollBar>
|
||||
#include <QSettings>
|
||||
#include <QShortcut>
|
||||
#include <QStringListModel>
|
||||
#include <QTextBlock>
|
||||
#include <QTextCursor>
|
||||
#include <QTextDocumentFragment>
|
||||
#include <QUrl>
|
||||
#include <QVariant>
|
||||
#include <QWidget>
|
||||
|
||||
#include <cstdlib>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
@ -134,10 +143,12 @@ CodeEditor::CodeEditor(QWidget *parent) :
|
||||
minimize_comp(new QCompleter(this)), variable_comp(new QCompleter(this)),
|
||||
units_comp(new QCompleter(this)), group_comp(new QCompleter(this)),
|
||||
varname_comp(new QCompleter(this)), fixid_comp(new QCompleter(this)),
|
||||
compid_comp(new QCompleter(this)), file_comp(new QCompleter(this)), highlight(NO_HIGHLIGHT)
|
||||
compid_comp(new QCompleter(this)), file_comp(new QCompleter(this)),
|
||||
extra_comp(new QCompleter(this)), highlight(NO_HIGHLIGHT)
|
||||
{
|
||||
help_action = new QShortcut(QKeySequence::fromString("Ctrl+?"), parent);
|
||||
connect(help_action, &QShortcut::activated, this, &CodeEditor::get_help);
|
||||
docver = "";
|
||||
|
||||
// set up completer class (without a model currently)
|
||||
#define COMPLETER_SETUP(completer) \
|
||||
@ -170,6 +181,7 @@ CodeEditor::CodeEditor(QWidget *parent) :
|
||||
COMPLETER_SETUP(fixid_comp);
|
||||
COMPLETER_SETUP(compid_comp);
|
||||
COMPLETER_SETUP(file_comp);
|
||||
COMPLETER_SETUP(extra_comp);
|
||||
#undef COMPLETER_SETUP
|
||||
|
||||
// initialize help system
|
||||
@ -238,6 +250,7 @@ CodeEditor::~CodeEditor()
|
||||
delete fixid_comp;
|
||||
delete compid_comp;
|
||||
delete file_comp;
|
||||
delete extra_comp;
|
||||
}
|
||||
|
||||
int CodeEditor::lineNumberAreaWidth()
|
||||
@ -386,6 +399,7 @@ COMPLETER_INIT_FUNC(integrate, Integrate)
|
||||
COMPLETER_INIT_FUNC(minimize, Minimize)
|
||||
COMPLETER_INIT_FUNC(variable, Variable)
|
||||
COMPLETER_INIT_FUNC(units, Units)
|
||||
COMPLETER_INIT_FUNC(extra, Extra)
|
||||
|
||||
#undef COMPLETER_INIT_FUNC
|
||||
|
||||
@ -419,7 +433,7 @@ void CodeEditor::setVarNameList()
|
||||
{
|
||||
QStringList vars;
|
||||
|
||||
// variable "gui_run" is always defined by LAMMPS GUI
|
||||
// variable "gui_run" is always defined by LAMMPS-GUI
|
||||
vars << QString("${gui_run}");
|
||||
vars << QString("v_gui_run");
|
||||
|
||||
@ -574,7 +588,7 @@ void CodeEditor::keyPressEvent(QKeyEvent *event)
|
||||
auto line = cursor.block().text();
|
||||
if (line.isEmpty()) return;
|
||||
|
||||
// QTextCursor::WordUnderCursor is unusable here since recognizes '/' as word boundary.
|
||||
// QTextCursor::WordUnderCursor is unusable here since it recognizes '/' as word boundary.
|
||||
// Work around it by manually searching for the location of the beginning of the word.
|
||||
int begin = qMin(cursor.positionInBlock(), line.length() - 1);
|
||||
|
||||
@ -736,11 +750,63 @@ void CodeEditor::contextMenuEvent(QContextMenuEvent *event)
|
||||
connect(action2, &QAction::triggered, this, &CodeEditor::open_help);
|
||||
}
|
||||
}
|
||||
|
||||
// check if word under cursor is file
|
||||
{
|
||||
auto cursor = textCursor();
|
||||
auto line = cursor.block().text();
|
||||
if (!line.isEmpty()) {
|
||||
// QTextCursor::WordUnderCursor is unusable here since it recognizes '/' as word
|
||||
// boundary. Work around it by manually searching for the location of the beginning of
|
||||
// the word.
|
||||
int begin = qMin(cursor.positionInBlock(), line.length() - 1);
|
||||
|
||||
while (begin >= 0) {
|
||||
if (line[begin].isSpace()) break;
|
||||
--begin;
|
||||
}
|
||||
int end = begin + 1;
|
||||
while (end < line.length()) {
|
||||
if (line[end].isSpace()) break;
|
||||
++end;
|
||||
}
|
||||
|
||||
QString word = line.mid(begin, end - begin).trimmed();
|
||||
QFileInfo fi(word);
|
||||
if (fi.exists() && fi.isFile()) {
|
||||
// check if file is a LAMMPS restart
|
||||
char magic[16] = " ";
|
||||
QFile file(word);
|
||||
if (file.open(QIODevice::ReadOnly)) {
|
||||
QDataStream in(&file);
|
||||
in.readRawData(magic, 16);
|
||||
file.close();
|
||||
}
|
||||
if (strcmp(magic, LAMMPS_MAGIC) == 0) {
|
||||
auto *action = menu->addAction(QString("Inspect restart file '%1'").arg(word));
|
||||
action->setIcon(QIcon(":/icons/document-open.png"));
|
||||
action->setData(word);
|
||||
connect(action, &QAction::triggered, this, &CodeEditor::inspect_file);
|
||||
} else {
|
||||
auto *action = menu->addAction(QString("View file '%1'").arg(word));
|
||||
action->setIcon(QIcon(":/icons/document-open.png"));
|
||||
action->setData(word);
|
||||
connect(action, &QAction::triggered, this, &CodeEditor::view_file);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
auto *action = menu->addAction(QString("LAMMPS Manual"));
|
||||
action->setIcon(QIcon(":/icons/help-browser.png"));
|
||||
action->setData(QString());
|
||||
connect(action, &QAction::triggered, this, &CodeEditor::open_help);
|
||||
|
||||
action = menu->addAction(QString("LAMMPS Tutorial"));
|
||||
action->setIcon(QIcon(":/icons/help-tutorial.png"));
|
||||
action->setData(QString("https://lammpstutorials.github.io/"));
|
||||
connect(action, &QAction::triggered, this, &CodeEditor::open_url);
|
||||
|
||||
menu->exec(event->globalPos());
|
||||
delete menu;
|
||||
}
|
||||
@ -989,6 +1055,8 @@ void CodeEditor::runCompletion()
|
||||
current_comp = fixid_comp;
|
||||
else if (selected.startsWith("F_"))
|
||||
current_comp = fixid_comp;
|
||||
else if ((words[0] == "read_data") && selected.startsWith("ex"))
|
||||
current_comp = extra_comp;
|
||||
else if ((words[0] == "fitpod") || (words[0] == "molecule")) {
|
||||
if (selected.contains('/')) {
|
||||
if (popup && popup->isVisible()) popup->hide();
|
||||
@ -1037,6 +1105,8 @@ void CodeEditor::runCompletion()
|
||||
current_comp = fixid_comp;
|
||||
else if (selected.startsWith("F_"))
|
||||
current_comp = fixid_comp;
|
||||
else if ((words[0] == "read_data") && selected.startsWith("ex"))
|
||||
current_comp = extra_comp;
|
||||
|
||||
if (current_comp) {
|
||||
current_comp->setCompletionPrefix(words[3].c_str());
|
||||
@ -1066,6 +1136,8 @@ void CodeEditor::runCompletion()
|
||||
current_comp = fixid_comp;
|
||||
else if (selected.startsWith("F_"))
|
||||
current_comp = fixid_comp;
|
||||
else if ((words[0] == "read_data") && selected.startsWith("ex"))
|
||||
current_comp = extra_comp;
|
||||
|
||||
if (current_comp) {
|
||||
current_comp->setCompletionPrefix(selected);
|
||||
@ -1091,7 +1163,7 @@ void CodeEditor::insertCompletedCommand(const QString &completion)
|
||||
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
|
||||
// we need to do it in this complicated way, since QTextCursor does not recognize
|
||||
// special characters as part of a word.
|
||||
auto cursor = textCursor();
|
||||
auto line = cursor.block().text();
|
||||
@ -1114,12 +1186,30 @@ void CodeEditor::insertCompletedCommand(const QString &completion)
|
||||
setTextCursor(cursor);
|
||||
}
|
||||
|
||||
void CodeEditor::setDocver()
|
||||
{
|
||||
LammpsWrapper *lammps = &qobject_cast<LammpsGui *>(parent())->lammps;
|
||||
docver = "/";
|
||||
if (lammps) {
|
||||
QString git_branch = (const char *)lammps->extract_global("git_branch");
|
||||
if ((git_branch == "stable") || (git_branch == "maintenance")) {
|
||||
docver = "/stable/";
|
||||
} else if (git_branch == "release") {
|
||||
docver = "/";
|
||||
} else {
|
||||
docver = "/latest/";
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void CodeEditor::get_help()
|
||||
{
|
||||
QString page, help;
|
||||
find_help(page, help);
|
||||
if (docver.isEmpty()) setDocver();
|
||||
if (!page.isEmpty())
|
||||
QDesktopServices::openUrl(QUrl(QString("https://docs.lammps.org/%1").arg(page)));
|
||||
QDesktopServices::openUrl(
|
||||
QUrl(QString("https://docs.lammps.org%1%2").arg(docver).arg(page)));
|
||||
}
|
||||
|
||||
void CodeEditor::find_help(QString &page, QString &help)
|
||||
@ -1170,8 +1260,31 @@ void CodeEditor::find_help(QString &page, QString &help)
|
||||
void CodeEditor::open_help()
|
||||
{
|
||||
auto *act = qobject_cast<QAction *>(sender());
|
||||
if (docver.isEmpty()) setDocver();
|
||||
QDesktopServices::openUrl(
|
||||
QUrl(QString("https://docs.lammps.org/%1").arg(act->data().toString())));
|
||||
QUrl(QString("https://docs.lammps.org%1%2").arg(docver).arg(act->data().toString())));
|
||||
}
|
||||
|
||||
void CodeEditor::open_url()
|
||||
{
|
||||
auto *act = qobject_cast<QAction *>(sender());
|
||||
QDesktopServices::openUrl(QUrl(act->data().toString()));
|
||||
}
|
||||
|
||||
// forward requests to view or inspect files to the corresponding LammpsGui methods
|
||||
|
||||
void CodeEditor::view_file()
|
||||
{
|
||||
auto *act = qobject_cast<QAction *>(sender());
|
||||
auto *guimain = qobject_cast<LammpsGui *>(parent());
|
||||
guimain->view_file(act->data().toString());
|
||||
}
|
||||
|
||||
void CodeEditor::inspect_file()
|
||||
{
|
||||
auto *act = qobject_cast<QAction *>(sender());
|
||||
auto *guimain = qobject_cast<LammpsGui *>(parent());
|
||||
guimain->inspect_file(act->data().toString());
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
|
||||
@ -14,15 +14,23 @@
|
||||
#ifndef CODEEDITOR_H
|
||||
#define CODEEDITOR_H
|
||||
|
||||
#include <QFont>
|
||||
#include <QMap>
|
||||
#include <QPlainTextEdit>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
|
||||
class QCompleter;
|
||||
class QStringListModel;
|
||||
class QContextMenuEvent;
|
||||
class QDragEnterEvent;
|
||||
class QDropEvent;
|
||||
class QFont;
|
||||
class QKeyEvent;
|
||||
class QMimeData;
|
||||
class QPaintEvent;
|
||||
class QRect;
|
||||
class QResizeEvent;
|
||||
class QShortcut;
|
||||
class QWidget;
|
||||
|
||||
class CodeEditor : public QPlainTextEdit {
|
||||
Q_OBJECT
|
||||
@ -56,6 +64,7 @@ public:
|
||||
void setMinimizeList(const QStringList &words);
|
||||
void setVariableList(const QStringList &words);
|
||||
void setUnitsList(const QStringList &words);
|
||||
void setExtraList(const QStringList &words);
|
||||
void setGroupList();
|
||||
void setVarNameList();
|
||||
void setComputeIDList();
|
||||
@ -71,6 +80,7 @@ protected:
|
||||
void dropEvent(QDropEvent *event) override;
|
||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||
void keyPressEvent(QKeyEvent *event) override;
|
||||
void setDocver();
|
||||
|
||||
private slots:
|
||||
void updateLineNumberAreaWidth(int newBlockCount);
|
||||
@ -78,6 +88,9 @@ private slots:
|
||||
void get_help();
|
||||
void find_help(QString &page, QString &help);
|
||||
void open_help();
|
||||
void open_url();
|
||||
void view_file();
|
||||
void inspect_file();
|
||||
void reformatCurrentLine();
|
||||
void runCompletion();
|
||||
void insertCompletedCommand(const QString &completion);
|
||||
@ -92,11 +105,12 @@ private:
|
||||
QCompleter *current_comp, *command_comp, *fix_comp, *compute_comp, *dump_comp, *atom_comp,
|
||||
*pair_comp, *bond_comp, *angle_comp, *dihedral_comp, *improper_comp, *kspace_comp,
|
||||
*region_comp, *integrate_comp, *minimize_comp, *variable_comp, *units_comp, *group_comp,
|
||||
*varname_comp, *fixid_comp, *compid_comp, *file_comp;
|
||||
*varname_comp, *fixid_comp, *compid_comp, *file_comp, *extra_comp;
|
||||
|
||||
int highlight;
|
||||
bool reformat_on_return;
|
||||
bool automatic_completion;
|
||||
QString docver;
|
||||
|
||||
QMap<QString, QString> cmd_map;
|
||||
QMap<QString, QString> fix_map;
|
||||
|
||||
146
tools/lammps-gui/fileviewer.cpp
Normal file
@ -0,0 +1,146 @@
|
||||
/* ----------------------------------------------------------------------
|
||||
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||
https://www.lammps.org/, Sandia National Laboratories
|
||||
LAMMPS development team: developers@lammps.org
|
||||
|
||||
Copyright (2003) Sandia Corporation. Under the terms of Contract
|
||||
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
||||
certain rights in this software. This software is distributed under
|
||||
the GNU General Public License.
|
||||
|
||||
See the README file in the top-level LAMMPS directory.
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
#include "fileviewer.h"
|
||||
|
||||
#include "lammpsgui.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QEvent>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QIcon>
|
||||
#include <QKeySequence>
|
||||
#include <QProcess>
|
||||
#include <QSettings>
|
||||
#include <QShortcut>
|
||||
#include <QString>
|
||||
#include <QStringList>
|
||||
#include <QTextCursor>
|
||||
#include <QTextStream>
|
||||
|
||||
FileViewer::FileViewer(const QString &_filename, QString title, QWidget *parent) :
|
||||
QPlainTextEdit(parent), fileName(_filename)
|
||||
{
|
||||
auto *action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q), this);
|
||||
connect(action, &QShortcut::activated, this, &FileViewer::quit);
|
||||
action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Slash), this);
|
||||
connect(action, &QShortcut::activated, this, &FileViewer::stop_run);
|
||||
|
||||
installEventFilter(this);
|
||||
|
||||
// open and read file. Set editor to read-only.
|
||||
QFile file(fileName);
|
||||
QFileInfo finfo(file);
|
||||
QString command;
|
||||
QString content;
|
||||
QProcess decomp;
|
||||
QStringList args = {"-cdf", fileName};
|
||||
bool compressed = false;
|
||||
|
||||
// match suffix with decompression program
|
||||
if (finfo.suffix() == "gz") {
|
||||
command = "gzip";
|
||||
compressed = true;
|
||||
} else if (finfo.suffix() == "bz2") {
|
||||
command = "bzip2";
|
||||
compressed = true;
|
||||
} else if (finfo.suffix() == "zst") {
|
||||
command = "zstd";
|
||||
compressed = true;
|
||||
} else if (finfo.suffix() == "xz") {
|
||||
command = "xz";
|
||||
compressed = true;
|
||||
} else if (finfo.suffix() == "lzma") {
|
||||
command = "xz";
|
||||
args.insert(1, "--format=lzma");
|
||||
compressed = true;
|
||||
} else if (finfo.suffix() == "lz4") {
|
||||
command = "lz4";
|
||||
compressed = true;
|
||||
}
|
||||
|
||||
// read compressed file from pipe
|
||||
if (compressed) {
|
||||
decomp.start(command, args, QIODevice::ReadOnly);
|
||||
if (decomp.waitForStarted()) {
|
||||
while (decomp.waitForReadyRead())
|
||||
content += decomp.readAll();
|
||||
} else {
|
||||
content = "\nCould not open compressed file %1 with decompression program %2\n";
|
||||
content = content.arg(fileName).arg(command);
|
||||
}
|
||||
decomp.close();
|
||||
} else if (file.open(QIODevice::Text | QIODevice::ReadOnly)) {
|
||||
// read plain text
|
||||
QTextStream in(&file);
|
||||
content = in.readAll();
|
||||
file.close();
|
||||
}
|
||||
|
||||
QFont text_font;
|
||||
QSettings settings;
|
||||
text_font.fromString(settings.value("textfont", text_font.toString()).toString());
|
||||
document()->setDefaultFont(text_font);
|
||||
|
||||
document()->setPlainText(content);
|
||||
moveCursor(QTextCursor::Start, QTextCursor::MoveAnchor);
|
||||
setReadOnly(true);
|
||||
setLineWrapMode(NoWrap);
|
||||
setMinimumSize(800, 500);
|
||||
setWindowIcon(QIcon(":/icons/lammps-icon-128x128.png"));
|
||||
if (title.isEmpty())
|
||||
setWindowTitle("LAMMPS-GUI - Viewer - " + fileName);
|
||||
else
|
||||
setWindowTitle(title);
|
||||
}
|
||||
|
||||
void FileViewer::quit()
|
||||
{
|
||||
LammpsGui *main = nullptr;
|
||||
for (QWidget *widget : QApplication::topLevelWidgets())
|
||||
if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget);
|
||||
if (main) main->quit();
|
||||
}
|
||||
|
||||
void FileViewer::stop_run()
|
||||
{
|
||||
LammpsGui *main = nullptr;
|
||||
for (QWidget *widget : QApplication::topLevelWidgets())
|
||||
if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget);
|
||||
if (main) main->stop_run();
|
||||
}
|
||||
|
||||
// event filter to handle "Ambiguous shortcut override" issues
|
||||
bool FileViewer::eventFilter(QObject *watched, QEvent *event)
|
||||
{
|
||||
if (event->type() == QEvent::ShortcutOverride) {
|
||||
auto *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:
|
||||
39
tools/lammps-gui/fileviewer.h
Normal file
@ -0,0 +1,39 @@
|
||||
/* -*- c++ -*- ----------------------------------------------------------
|
||||
LAMMPS - Large-scale Atomic/Molecular Massively Parallel Simulator
|
||||
https://www.lammps.org/, Sandia National Laboratories
|
||||
LAMMPS development team: developers@lammps.org
|
||||
|
||||
Copyright (2003) Sandia Corporation. Under the terms of Contract
|
||||
DE-AC04-94AL85000 with Sandia Corporation, the U.S. Government retains
|
||||
certain rights in this software. This software is distributed under
|
||||
the GNU General Public License.
|
||||
|
||||
See the README file in the top-level LAMMPS directory.
|
||||
------------------------------------------------------------------------- */
|
||||
|
||||
#ifndef FILEVIEWER_H
|
||||
#define FILEVIEWER_H
|
||||
|
||||
#include <QPlainTextEdit>
|
||||
|
||||
class FileViewer : public QPlainTextEdit {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
FileViewer(const QString &filename, QString title = "", QWidget *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void quit();
|
||||
void stop_run();
|
||||
|
||||
protected:
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
|
||||
private:
|
||||
QString fileName;
|
||||
};
|
||||
|
||||
#endif
|
||||
// Local Variables:
|
||||
// c-basic-offset: 4
|
||||
// End:
|
||||
@ -20,6 +20,8 @@ angle_cosine_shift_exp.html angle_style cosine/shift/exp
|
||||
angle_cosine_shift_exp.html angle_style cosine/shift/exp/omp
|
||||
angle_cosine_shift.html angle_style cosine/shift
|
||||
angle_cosine_shift.html angle_style cosine/shift/omp
|
||||
angle_cosine_squared_restricted.html angle_style cosine/squared/restricted
|
||||
angle_cosine_squared_restricted.html angle_style cosine/squared/restricted/omp
|
||||
angle_cosine_squared.html angle_style cosine/squared
|
||||
angle_cosine_squared.html angle_style cosine/squared/omp
|
||||
angle_cross.html angle_style cross
|
||||
@ -35,6 +37,7 @@ angle_harmonic.html angle_style harmonic/intel
|
||||
angle_harmonic.html angle_style harmonic/kk
|
||||
angle_harmonic.html angle_style harmonic/omp
|
||||
angle_hybrid.html angle_style hybrid
|
||||
angle_hybrid.html angle_style hybrid/kk
|
||||
angle_lepton.html angle_style lepton
|
||||
angle_lepton.html angle_style lepton/omp
|
||||
angle_mesocnt.html angle_style mesocnt
|
||||
@ -43,6 +46,7 @@ angle_none.html angle_style none
|
||||
angle_quartic.html angle_style quartic
|
||||
angle_quartic.html angle_style quartic/omp
|
||||
angle_spica.html angle_style spica
|
||||
angle_spica.html angle_style spica/kk
|
||||
angle_spica.html angle_style spica/omp
|
||||
angle_style.html angle_style
|
||||
angle_table.html angle_style table
|
||||
@ -150,6 +154,7 @@ bond_harmonic_shift_cut.html bond_style harmonic/shift/cut/omp
|
||||
bond_harmonic_shift.html bond_style harmonic/shift
|
||||
bond_harmonic_shift.html bond_style harmonic/shift/omp
|
||||
bond_hybrid.html bond_style hybrid
|
||||
bond_hybrid.html bond_style hybrid/kk
|
||||
bond_lepton.html bond_style lepton
|
||||
bond_lepton.html bond_style lepton/omp
|
||||
bond_mesocnt.html bond_style mesocnt
|
||||
@ -164,6 +169,7 @@ bond_oxdna.html bond_style oxdna/fene
|
||||
bond_oxdna.html bond_style oxrna2/fene
|
||||
bond_quartic.html bond_style quartic
|
||||
bond_quartic.html bond_style quartic/omp
|
||||
bond_rheo_shell.html bond_style rheo/shell
|
||||
bond_special.html bond_style special
|
||||
bond_style.html bond_style
|
||||
bond_table.html bond_style table
|
||||
@ -260,6 +266,10 @@ compute_pair.html compute pair
|
||||
compute_pe_atom.html compute pe/atom
|
||||
compute_pe.html compute pe
|
||||
compute_plasticity_atom.html compute plasticity/atom
|
||||
compute_pod_atom.html compute pod/atom
|
||||
compute_pod_atom.html compute podd/atom
|
||||
compute_pod_atom.html compute pod/global
|
||||
compute_pod_atom.html compute pod/local
|
||||
compute_pressure_alchemy.html compute pressure/alchemy
|
||||
compute_pressure.html compute pressure
|
||||
compute_pressure_uef.html compute pressure/uef
|
||||
@ -275,6 +285,7 @@ compute_reaxff_atom.html compute reaxff/atom/kk
|
||||
compute_reduce_chunk.html compute reduce/chunk
|
||||
compute_reduce.html compute reduce
|
||||
compute_reduce.html compute reduce/region
|
||||
compute_rheo_property_atom.html compute rheo/property/atom
|
||||
compute_rigid_local.html compute rigid/local
|
||||
compute.html compute
|
||||
compute_saed.html compute saed
|
||||
@ -360,6 +371,7 @@ delete_bonds.html delete_bonds
|
||||
dielectric.html dielectric
|
||||
dihedral_charmm.html dihedral_style charmm
|
||||
dihedral_charmm.html dihedral_style charmmfsw
|
||||
dihedral_charmm.html dihedral_style charmmfsw/kk
|
||||
dihedral_charmm.html dihedral_style charmm/intel
|
||||
dihedral_charmm.html dihedral_style charmm/kk
|
||||
dihedral_charmm.html dihedral_style charmm/omp
|
||||
@ -369,6 +381,7 @@ dihedral_class2.html dihedral_style class2/omp
|
||||
dihedral_coeff.html dihedral_coeff
|
||||
dihedral_cosine_shift_exp.html dihedral_style cosine/shift/exp
|
||||
dihedral_cosine_shift_exp.html dihedral_style cosine/shift/exp/omp
|
||||
dihedral_cosine_squared_restricted.html dihedral_style cosine/squared/restricted
|
||||
dihedral_fourier.html dihedral_style fourier
|
||||
dihedral_fourier.html dihedral_style fourier/intel
|
||||
dihedral_fourier.html dihedral_style fourier/omp
|
||||
@ -379,6 +392,7 @@ dihedral_harmonic.html dihedral_style harmonic/omp
|
||||
dihedral_helix.html dihedral_style helix
|
||||
dihedral_helix.html dihedral_style helix/omp
|
||||
dihedral_hybrid.html dihedral_style hybrid
|
||||
dihedral_hybrid.html dihedral_style hybrid/kk
|
||||
dihedral_lepton.html dihedral_style lepton
|
||||
dihedral_lepton.html dihedral_style lepton/omp
|
||||
dihedral_multi_harmonic.html dihedral_style multi/harmonic
|
||||
@ -443,6 +457,7 @@ fix_acks2_reaxff.html fix acks2/reaxff/kk
|
||||
fix_adapt_fep.html fix adapt/fep
|
||||
fix_adapt.html fix adapt
|
||||
fix_addforce.html fix addforce
|
||||
fix_add_heat.html fix add/heat
|
||||
fix_addtorque.html fix addtorque
|
||||
fix_alchemy.html fix alchemy
|
||||
fix_amoeba_bitorsion.html fix amoeba/bitorsion
|
||||
@ -475,6 +490,7 @@ fix_cmap.html fix cmap
|
||||
fix_colvars.html fix colvars
|
||||
fix_controller.html fix controller
|
||||
fix_damping_cundall.html fix damping/cundall
|
||||
fix_deform_pressure.html fix deform/pressure
|
||||
fix_deform.html fix deform
|
||||
fix_deform.html fix deform/kk
|
||||
fix_deposit.html fix deposit
|
||||
@ -667,6 +683,11 @@ fix_reaxff_species.html fix reaxff/species
|
||||
fix_reaxff_species.html fix reaxff/species/kk
|
||||
fix_recenter.html fix recenter
|
||||
fix_restrain.html fix restrain
|
||||
fix_rheo_oxidation.html fix rheo/oxidation
|
||||
fix_rheo_pressure.html fix rheo/pressure
|
||||
fix_rheo.html fix rheo
|
||||
fix_rheo_thermal.html fix rheo/thermal
|
||||
fix_rheo_viscosity.html fix rheo/viscosity
|
||||
fix_rhok.html fix rhok
|
||||
fix_rigid_meso.html fix rigid/meso
|
||||
fix_rigid.html fix rigid
|
||||
@ -741,6 +762,8 @@ fix_wall_body_polygon.html fix wall/body/polygon
|
||||
fix_wall_body_polyhedron.html fix wall/body/polyhedron
|
||||
fix_wall_ees.html fix wall/ees
|
||||
fix_wall_ees.html fix wall/region/ees
|
||||
fix_wall_flow.html fix wall/flow
|
||||
fix_wall_flow.html fix wall/flow/kk
|
||||
fix_wall_gran_region.html fix wall/gran/region
|
||||
fix_wall_gran.html fix wall/gran
|
||||
fix_wall_gran.html fix wall/gran/kk
|
||||
@ -784,6 +807,7 @@ improper_harmonic.html improper_style harmonic/intel
|
||||
improper_harmonic.html improper_style harmonic/kk
|
||||
improper_harmonic.html improper_style harmonic/omp
|
||||
improper_hybrid.html improper_style hybrid
|
||||
improper_hybrid.html improper_style hybrid/kk
|
||||
improper_inversion_harmonic.html improper_style inversion/harmonic
|
||||
improper_none.html improper_style none
|
||||
improper_ring.html improper_style ring
|
||||
@ -937,6 +961,7 @@ pair_charmm.html pair_style lj/charmm/coul/msm
|
||||
pair_charmm.html pair_style lj/charmm/coul/msm/omp
|
||||
pair_charmm.html pair_style lj/charmmfsw/coul/charmmfsh
|
||||
pair_charmm.html pair_style lj/charmmfsw/coul/long
|
||||
pair_charmm.html pair_style lj/charmmfsw/coul/long/kk
|
||||
pair_class2.html pair_style lj/class2
|
||||
pair_class2.html pair_style lj/class2/coul/cut
|
||||
pair_class2.html pair_style lj/class2/coul/cut/kk
|
||||
@ -1024,6 +1049,8 @@ pair_dipole.html pair_style lj/long/dipole/long
|
||||
pair_dipole.html pair_style lj/sf/dipole/sf
|
||||
pair_dipole.html pair_style lj/sf/dipole/sf/gpu
|
||||
pair_dipole.html pair_style lj/sf/dipole/sf/omp
|
||||
pair_dpd_coul_slater_long.html pair_style dpd/coul/slater/long
|
||||
pair_dpd_coul_slater_long.html pair_style dpd/coul/slater/long/gpu
|
||||
pair_dpd_ext.html pair_style dpd/ext
|
||||
pair_dpd_ext.html pair_style dpd/ext/kk
|
||||
pair_dpd_ext.html pair_style dpd/ext/omp
|
||||
@ -1132,9 +1159,14 @@ pair_hbond_dreiding.html pair_style hbond/dreiding/morse/omp
|
||||
pair_hdnnp.html pair_style hdnnp
|
||||
pair_hybrid.html pair_style hybrid
|
||||
pair_hybrid.html pair_style hybrid/kk
|
||||
pair_hybrid.html pair_style hybrid/molecular
|
||||
pair_hybrid.html pair_style hybrid/molecular/omp
|
||||
pair_hybrid.html pair_style hybrid/omp
|
||||
pair_hybrid.html pair_style hybrid/overlay
|
||||
pair_hybrid.html pair_style hybrid/overlay/kk
|
||||
pair_hybrid.html pair_style hybrid/overlay/omp
|
||||
pair_hybrid.html pair_style hybrid/scaled
|
||||
pair_hybrid.html pair_style hybrid/scaled/omp
|
||||
pair_ilp_graphene_hbn.html pair_style ilp/graphene/hbn
|
||||
pair_ilp_graphene_hbn.html pair_style ilp/graphene/hbn/opt
|
||||
pair_ilp_tmd.html pair_style ilp/tmd
|
||||
@ -1292,6 +1324,8 @@ pair_pace.html pair_style pace
|
||||
pair_pace.html pair_style pace/extrapolation
|
||||
pair_pace.html pair_style pace/extrapolation/kk
|
||||
pair_pace.html pair_style pace/kk
|
||||
pair_pedone.html pair_style pedone
|
||||
pair_pedone.html pair_style pedone/omp
|
||||
pair_peri.html pair_style peri/eps
|
||||
pair_peri.html pair_style peri/lps
|
||||
pair_peri.html pair_style peri/lps/omp
|
||||
@ -1299,6 +1333,7 @@ pair_peri.html pair_style peri/pmb
|
||||
pair_peri.html pair_style peri/pmb/omp
|
||||
pair_peri.html pair_style peri/ves
|
||||
pair_pod.html pair_style pod
|
||||
pair_pod.html pair_style pod/kk
|
||||
pair_polymorphic.html pair_style polymorphic
|
||||
pair_python.html pair_style python
|
||||
pair_quip.html pair_style quip
|
||||
@ -1306,9 +1341,13 @@ pair_rann.html pair_style rann
|
||||
pair_reaxff.html pair_style reaxff
|
||||
pair_reaxff.html pair_style reaxff/kk
|
||||
pair_reaxff.html pair_style reaxff/omp
|
||||
pair_rebomos.html pair_style rebomos
|
||||
pair_rebomos.html pair_style rebomos/omp
|
||||
pair_resquared.html pair_style resquared
|
||||
pair_resquared.html pair_style resquared/gpu
|
||||
pair_resquared.html pair_style resquared/omp
|
||||
pair_rheo.html pair_style rheo
|
||||
pair_rheo_solid.html pair_style rheo/solid
|
||||
pair_saip_metal.html pair_style saip/metal
|
||||
pair_saip_metal.html pair_style saip/metal/opt
|
||||
pair_sdpd_taitwater_isothermal.html pair_style sdpd/taitwater/isothermal
|
||||
@ -1324,6 +1363,7 @@ pair_snap.html pair_style snap/intel
|
||||
pair_snap.html pair_style snap/kk
|
||||
pair_soft.html pair_style soft
|
||||
pair_soft.html pair_style soft/gpu
|
||||
pair_soft.html pair_style soft/kk
|
||||
pair_soft.html pair_style soft/omp
|
||||
pair_sph_heatconduction.html pair_style sph/heatconduction
|
||||
pair_sph_heatconduction.html pair_style sph/heatconduction/gpu
|
||||
@ -1337,6 +1377,7 @@ pair_sph_taitwater.html pair_style sph/taitwater/gpu
|
||||
pair_spica.html pair_style lj/spica
|
||||
pair_spica.html pair_style lj/spica/coul/long
|
||||
pair_spica.html pair_style lj/spica/coul/long/gpu
|
||||
pair_spica.html pair_style lj/spica/coul/long/kk
|
||||
pair_spica.html pair_style lj/spica/coul/long/omp
|
||||
pair_spica.html pair_style lj/spica/coul/msm
|
||||
pair_spica.html pair_style lj/spica/coul/msm/omp
|
||||
@ -1390,6 +1431,8 @@ pair_thole.html pair_style thole
|
||||
pair_threebody_table.html pair_style threebody/table
|
||||
pair_tracker.html pair_style tracker
|
||||
pair_tri_lj.html pair_style tri/lj
|
||||
pair_uf3.html pair_style uf3
|
||||
pair_uf3.html pair_style uf3/kk
|
||||
pair_ufm.html pair_style ufm
|
||||
pair_ufm.html pair_style ufm/gpu
|
||||
pair_ufm.html pair_style ufm/omp
|
||||
|
||||
@ -13,6 +13,7 @@
|
||||
|
||||
#include "helpers.h"
|
||||
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileInfo>
|
||||
#include <QProcess>
|
||||
@ -66,6 +67,23 @@ bool has_exe(const QString &exe)
|
||||
return false; // Not found!
|
||||
}
|
||||
|
||||
// recursively remove all contents from a directory
|
||||
|
||||
void purge_directory(const QString &dir)
|
||||
{
|
||||
QDir directory(dir);
|
||||
|
||||
directory.setFilter(QDir::AllEntries | QDir::NoDotAndDotDot);
|
||||
const auto &entries = directory.entryList();
|
||||
for (auto &entry : entries) {
|
||||
if (!directory.remove(entry)) {
|
||||
directory.cd(entry);
|
||||
directory.removeRecursively();
|
||||
directory.cdUp();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Local Variables:
|
||||
// c-basic-offset: 4
|
||||
// End:
|
||||
|
||||
@ -25,6 +25,9 @@ extern char *mystrdup(const QString &text);
|
||||
// find if executable is in path
|
||||
extern bool has_exe(const QString &exe);
|
||||
|
||||
// recursively purge a directory
|
||||
extern void purge_directory(const QString &dir);
|
||||
|
||||
#endif
|
||||
// Local Variables:
|
||||
// c-basic-offset: 4
|
||||
|
||||
@ -23,7 +23,7 @@ Highlighter::Highlighter(QTextDocument *parent) :
|
||||
"thermo|print|thermo_style|"
|
||||
"timer|pair_write|bond_write|angle_write|dihedral_write)\\s+(\\S+)")),
|
||||
isOutput2(QStringLiteral("^\\s*(write_dump|shell|thermo_modify)\\s+(\\S+)\\s+(\\S+)")),
|
||||
isRead(QStringLiteral("^\\s*(include|read_restart|read_data|read_dump|molecule)")),
|
||||
isRead(QStringLiteral("^\\s*(include|read_restart|read_data|read_dump|molecule|geturl)\\s+(\\S+)")),
|
||||
isStyle(QStringLiteral("^\\s*(fix|compute|dump)\\s+(\\S+)\\s+(\\S+)\\s+(\\S+)")),
|
||||
isForce(QStringLiteral(
|
||||
"^\\s*(pair_style|bond_style|angle_style|dihedral_style|improper_style|kspace_style|pair_"
|
||||
|
||||
BIN
tools/lammps-gui/icons/application-yaml.png
Normal file
|
After Width: | Height: | Size: 2.8 KiB |
BIN
tools/lammps-gui/icons/chart-smooth.png
Normal file
|
After Width: | Height: | Size: 1.7 KiB |
BIN
tools/lammps-gui/icons/file-clipboard.png
Normal file
|
After Width: | Height: | Size: 2.6 KiB |
|
Before Width: | Height: | Size: 5.0 KiB After Width: | Height: | Size: 4.0 KiB |
BIN
tools/lammps-gui/icons/help-tutorial.png
Normal file
|
After Width: | Height: | Size: 3.3 KiB |
BIN
tools/lammps-gui/icons/image-shiny.png
Normal file
|
After Width: | Height: | Size: 3.8 KiB |
BIN
tools/lammps-gui/icons/move-recenter.png
Normal file
|
After Width: | Height: | Size: 3.9 KiB |
BIN
tools/lammps-gui/icons/trash.png
Normal file
|
After Width: | Height: | Size: 3.6 KiB |
BIN
tools/lammps-gui/icons/tutorial-logo.png
Normal file
|
After Width: | Height: | Size: 5.0 KiB |
BIN
tools/lammps-gui/icons/tutorial1-logo.png
Normal file
|
After Width: | Height: | Size: 81 KiB |
BIN
tools/lammps-gui/icons/tutorial2-logo.png
Normal file
|
After Width: | Height: | Size: 71 KiB |
BIN
tools/lammps-gui/icons/yaml-file-icon.png
Normal file
|
After Width: | Height: | Size: 4.3 KiB |
@ -18,28 +18,31 @@
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QClipboard>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QFontMetrics>
|
||||
#include <QGuiApplication>
|
||||
#include <QHBoxLayout>
|
||||
#include <QIcon>
|
||||
#include <QImage>
|
||||
#include <QImageReader>
|
||||
#include <QKeySequence>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QMenu>
|
||||
#include <QMenuBar>
|
||||
#include <QMessageBox>
|
||||
#include <QPalette>
|
||||
#include <QPoint>
|
||||
#include <QPixmap>
|
||||
#include <QPushButton>
|
||||
#include <QScreen>
|
||||
#include <QScrollArea>
|
||||
#include <QScrollBar>
|
||||
#include <QSettings>
|
||||
#include <QSizePolicy>
|
||||
#include <QSpinBox>
|
||||
#include <QStatusBar>
|
||||
#include <QVBoxLayout>
|
||||
#include <QWheelEvent>
|
||||
#include <QWidgetAction>
|
||||
#include <QVariant>
|
||||
|
||||
#include <cmath>
|
||||
|
||||
@ -130,9 +133,11 @@ static int get_pte_from_mass(double mass)
|
||||
|
||||
static const QString blank(" ");
|
||||
|
||||
ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidget *parent) :
|
||||
ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QString title, QWidget *parent) :
|
||||
QDialog(parent), menuBar(new QMenuBar), imageLabel(new QLabel), scrollArea(new QScrollArea),
|
||||
lammps(_lammps), group("all"), filename(fileName), useelements(false), usediameter(false)
|
||||
saveAsAct(nullptr), copyAct(nullptr), cmdAct(nullptr), zoomInAct(nullptr), zoomOutAct(nullptr),
|
||||
normalSizeAct(nullptr), lammps(_lammps), group("all"), filename(fileName), useelements(false),
|
||||
usediameter(false), usesigma(false)
|
||||
{
|
||||
imageLabel->setBackgroundRole(QPalette::Base);
|
||||
imageLabel->setSizePolicy(QSizePolicy::Ignored, QSizePolicy::Ignored);
|
||||
@ -147,8 +152,11 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge
|
||||
|
||||
QSettings settings;
|
||||
|
||||
vdwfactor = 0.5;
|
||||
auto pix = QPixmap(":/icons/emblem-photos.png");
|
||||
vdwfactor = 0.5;
|
||||
shinyfactor = 0.6;
|
||||
auto pix = QPixmap(":/icons/emblem-photos.png");
|
||||
xcenter = ycenter = zcenter = 0.5;
|
||||
auto bsize = QFontMetrics(QApplication::font()).size(Qt::TextSingleLine, "Height: 200");
|
||||
|
||||
auto *renderstatus = new QLabel(QString());
|
||||
renderstatus->setPixmap(pix.scaled(22, 22, Qt::KeepAspectRatio));
|
||||
@ -159,22 +167,26 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge
|
||||
auto *xval = new QSpinBox;
|
||||
xval->setRange(100, 10000);
|
||||
xval->setStepType(QAbstractSpinBox::AdaptiveDecimalStepType);
|
||||
xval->setValue(settings.value("xsize", "800").toInt());
|
||||
xval->setValue(settings.value("xsize", "600").toInt());
|
||||
xval->setObjectName("xsize");
|
||||
xval->setToolTip("Set rendered image width");
|
||||
xval->setMinimumSize(bsize);
|
||||
auto *yval = new QSpinBox;
|
||||
yval->setRange(100, 10000);
|
||||
yval->setStepType(QAbstractSpinBox::AdaptiveDecimalStepType);
|
||||
yval->setValue(settings.value("ysize", "600").toInt());
|
||||
yval->setObjectName("ysize");
|
||||
yval->setToolTip("Set rendered image height");
|
||||
yval->setMinimumSize(bsize);
|
||||
settings.endGroup();
|
||||
connect(xval, &QAbstractSpinBox::editingFinished, this, &ImageViewer::edit_size);
|
||||
connect(yval, &QAbstractSpinBox::editingFinished, this, &ImageViewer::edit_size);
|
||||
|
||||
// workaround for incorrect highlight bug on macOS
|
||||
auto *dummy = new QPushButton(QIcon(), "");
|
||||
dummy->hide();
|
||||
auto *dummy1 = new QPushButton(QIcon(), "");
|
||||
dummy1->hide();
|
||||
auto *dummy2 = new QPushButton(QIcon(), "");
|
||||
dummy2->hide();
|
||||
|
||||
auto *dossao = new QPushButton(QIcon(":/icons/hd-img.png"), "");
|
||||
dossao->setCheckable(true);
|
||||
@ -184,6 +196,10 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge
|
||||
doanti->setCheckable(true);
|
||||
doanti->setToolTip("Toggle anti-aliasing");
|
||||
doanti->setObjectName("antialias");
|
||||
auto *doshiny = new QPushButton(QIcon(":/icons/image-shiny.png"), "");
|
||||
doshiny->setCheckable(true);
|
||||
doshiny->setToolTip("Toggle shininess");
|
||||
doshiny->setObjectName("shiny");
|
||||
auto *dovdw = new QPushButton(QIcon(":/icons/vdw-style.png"), "");
|
||||
dovdw->setCheckable(true);
|
||||
dovdw->setToolTip("Toggle VDW style representation");
|
||||
@ -208,13 +224,15 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge
|
||||
rotup->setToolTip("Rotate up by 15 degrees");
|
||||
auto *rotdown = new QPushButton(QIcon(":/icons/gtk-go-down.png"), "");
|
||||
rotdown->setToolTip("Rotate down by 15 degrees");
|
||||
auto *recenter = new QPushButton(QIcon(":/icons/move-recenter.png"), "");
|
||||
recenter->setToolTip("Recenter on group");
|
||||
auto *reset = new QPushButton(QIcon(":/icons/gtk-zoom-fit.png"), "");
|
||||
reset->setToolTip("Reset view to defaults");
|
||||
auto *combo = new QComboBox;
|
||||
combo->setObjectName("group");
|
||||
combo->setToolTip("Select group to display");
|
||||
combo->setObjectName("group");
|
||||
int ngroup = lammps->id_count("group");
|
||||
int ngroup = lammps->id_count("group");
|
||||
constexpr int BUFLEN = 256;
|
||||
char gname[BUFLEN];
|
||||
for (int i = 0; i < ngroup; ++i) {
|
||||
@ -223,31 +241,41 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge
|
||||
combo->addItem(gname);
|
||||
}
|
||||
|
||||
auto *menuLayout = new QHBoxLayout;
|
||||
auto *menuLayout = new QHBoxLayout;
|
||||
auto *buttonLayout = new QHBoxLayout;
|
||||
auto *topLayout = new QVBoxLayout;
|
||||
topLayout->addLayout(menuLayout);
|
||||
topLayout->addLayout(buttonLayout);
|
||||
|
||||
menuLayout->addWidget(menuBar);
|
||||
menuLayout->addWidget(renderstatus);
|
||||
menuLayout->addWidget(new QLabel(" Width: "));
|
||||
menuLayout->addWidget(xval);
|
||||
menuLayout->addWidget(new QLabel(" Height: "));
|
||||
menuLayout->addWidget(yval);
|
||||
menuLayout->addWidget(dummy);
|
||||
menuLayout->addWidget(dossao);
|
||||
menuLayout->addWidget(doanti);
|
||||
menuLayout->addWidget(dovdw);
|
||||
menuLayout->addWidget(dobox);
|
||||
menuLayout->addWidget(doaxes);
|
||||
menuLayout->addWidget(zoomin);
|
||||
menuLayout->addWidget(zoomout);
|
||||
menuLayout->addWidget(rotleft);
|
||||
menuLayout->addWidget(rotright);
|
||||
menuLayout->addWidget(rotup);
|
||||
menuLayout->addWidget(rotdown);
|
||||
menuLayout->addWidget(reset);
|
||||
menuLayout->addWidget(dummy1);
|
||||
menuLayout->addWidget(new QLabel(" Group: "));
|
||||
menuLayout->addWidget(combo);
|
||||
buttonLayout->addWidget(dummy2);
|
||||
buttonLayout->addWidget(dossao);
|
||||
buttonLayout->addWidget(doanti);
|
||||
buttonLayout->addWidget(doshiny);
|
||||
buttonLayout->addWidget(dovdw);
|
||||
buttonLayout->addWidget(dobox);
|
||||
buttonLayout->addWidget(doaxes);
|
||||
buttonLayout->addWidget(zoomin);
|
||||
buttonLayout->addWidget(zoomout);
|
||||
buttonLayout->addWidget(rotleft);
|
||||
buttonLayout->addWidget(rotright);
|
||||
buttonLayout->addWidget(rotup);
|
||||
buttonLayout->addWidget(rotdown);
|
||||
buttonLayout->addWidget(recenter);
|
||||
buttonLayout->addWidget(reset);
|
||||
buttonLayout->addStretch(1);
|
||||
|
||||
connect(dossao, &QPushButton::released, this, &ImageViewer::toggle_ssao);
|
||||
connect(doanti, &QPushButton::released, this, &ImageViewer::toggle_anti);
|
||||
connect(doshiny, &QPushButton::released, this, &ImageViewer::toggle_shiny);
|
||||
connect(dovdw, &QPushButton::released, this, &ImageViewer::toggle_vdw);
|
||||
connect(dobox, &QPushButton::released, this, &ImageViewer::toggle_box);
|
||||
connect(doaxes, &QPushButton::released, this, &ImageViewer::toggle_axes);
|
||||
@ -257,21 +285,23 @@ ImageViewer::ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QWidge
|
||||
connect(rotright, &QPushButton::released, this, &ImageViewer::do_rot_right);
|
||||
connect(rotup, &QPushButton::released, this, &ImageViewer::do_rot_up);
|
||||
connect(rotdown, &QPushButton::released, this, &ImageViewer::do_rot_down);
|
||||
connect(recenter, &QPushButton::released, this, &ImageViewer::do_recenter);
|
||||
connect(reset, &QPushButton::released, this, &ImageViewer::reset_view);
|
||||
connect(combo, SIGNAL(currentIndexChanged(int)), this, SLOT(change_group(int)));
|
||||
|
||||
mainLayout->addLayout(menuLayout);
|
||||
mainLayout->addLayout(topLayout);
|
||||
mainLayout->addWidget(scrollArea);
|
||||
setWindowIcon(QIcon(":/icons/lammps-icon-128x128.png"));
|
||||
setWindowTitle(QString("Image Viewer: ") + QFileInfo(fileName).fileName());
|
||||
setWindowTitle(QString("LAMMPS-GUI - Image Viewer - ") + QFileInfo(fileName).fileName());
|
||||
createActions();
|
||||
|
||||
reset_view();
|
||||
// layout has not yet be established, so we need to fix up some pushbutton
|
||||
// properties directly since lookup in reset_view() will have failed
|
||||
dobox->setChecked(showbox);
|
||||
doshiny->setChecked(shinyfactor > 0.4);
|
||||
dovdw->setChecked(vdwfactor > 1.0);
|
||||
dovdw->setEnabled(useelements || usediameter);
|
||||
dovdw->setEnabled(useelements || usediameter || usesigma);
|
||||
doaxes->setChecked(showaxes);
|
||||
dossao->setChecked(usessao);
|
||||
doanti->setChecked(antialias);
|
||||
@ -288,16 +318,18 @@ void ImageViewer::reset_view()
|
||||
{
|
||||
QSettings settings;
|
||||
settings.beginGroup("snapshot");
|
||||
xsize = settings.value("xsize", "800").toInt();
|
||||
ysize = settings.value("ysize", "600").toInt();
|
||||
zoom = settings.value("zoom", 1.0).toDouble();
|
||||
hrot = settings.value("hrot", 60).toInt();
|
||||
vrot = settings.value("vrot", 30).toInt();
|
||||
vdwfactor = settings.value("vdwstyle", false).toBool() ? 1.6 : 0.5;
|
||||
showbox = settings.value("box", true).toBool();
|
||||
showaxes = settings.value("axes", false).toBool();
|
||||
usessao = settings.value("ssao", false).toBool();
|
||||
antialias = settings.value("antialias", false).toBool();
|
||||
xsize = settings.value("xsize", "600").toInt();
|
||||
ysize = settings.value("ysize", "600").toInt();
|
||||
zoom = settings.value("zoom", 1.0).toDouble();
|
||||
hrot = settings.value("hrot", 60).toInt();
|
||||
vrot = settings.value("vrot", 30).toInt();
|
||||
shinyfactor = settings.value("shinystyle", true).toBool() ? 0.6 : 0.2;
|
||||
vdwfactor = settings.value("vdwstyle", false).toBool() ? 1.6 : 0.5;
|
||||
showbox = settings.value("box", true).toBool();
|
||||
showaxes = settings.value("axes", false).toBool();
|
||||
usessao = settings.value("ssao", false).toBool();
|
||||
antialias = settings.value("antialias", false).toBool();
|
||||
xcenter = ycenter = zcenter = 0.5;
|
||||
settings.endGroup();
|
||||
|
||||
// reset state of checkable push buttons and combo box (if accessible)
|
||||
@ -311,6 +343,8 @@ void ImageViewer::reset_view()
|
||||
if (button) button->setChecked(usessao);
|
||||
button = findChild<QPushButton *>("antialias");
|
||||
if (button) button->setChecked(antialias);
|
||||
button = findChild<QPushButton *>("shiny");
|
||||
if (button) button->setChecked(shinyfactor > 0.4);
|
||||
button = findChild<QPushButton *>("vdw");
|
||||
if (button) button->setChecked(vdwfactor > 1.0);
|
||||
button = findChild<QPushButton *>("box");
|
||||
@ -336,7 +370,7 @@ void ImageViewer::edit_size()
|
||||
void ImageViewer::toggle_ssao()
|
||||
{
|
||||
auto *button = qobject_cast<QPushButton *>(sender());
|
||||
usessao = !usessao;
|
||||
usessao = !usessao;
|
||||
button->setChecked(usessao);
|
||||
createImage();
|
||||
}
|
||||
@ -344,11 +378,22 @@ void ImageViewer::toggle_ssao()
|
||||
void ImageViewer::toggle_anti()
|
||||
{
|
||||
auto *button = qobject_cast<QPushButton *>(sender());
|
||||
antialias = !antialias;
|
||||
antialias = !antialias;
|
||||
button->setChecked(antialias);
|
||||
createImage();
|
||||
}
|
||||
|
||||
void ImageViewer::toggle_shiny()
|
||||
{
|
||||
auto *button = qobject_cast<QPushButton *>(sender());
|
||||
if (shinyfactor > 0.4)
|
||||
shinyfactor = 0.2;
|
||||
else
|
||||
shinyfactor = 0.6;
|
||||
button->setChecked(shinyfactor > 0.4);
|
||||
createImage();
|
||||
}
|
||||
|
||||
void ImageViewer::toggle_vdw()
|
||||
{
|
||||
auto *button = qobject_cast<QPushButton *>(sender());
|
||||
@ -363,7 +408,7 @@ void ImageViewer::toggle_vdw()
|
||||
void ImageViewer::toggle_box()
|
||||
{
|
||||
auto *button = qobject_cast<QPushButton *>(sender());
|
||||
showbox = !showbox;
|
||||
showbox = !showbox;
|
||||
button->setChecked(showbox);
|
||||
createImage();
|
||||
}
|
||||
@ -371,7 +416,7 @@ void ImageViewer::toggle_box()
|
||||
void ImageViewer::toggle_axes()
|
||||
{
|
||||
auto *button = qobject_cast<QPushButton *>(sender());
|
||||
showaxes = !showaxes;
|
||||
showaxes = !showaxes;
|
||||
button->setChecked(showaxes);
|
||||
createImage();
|
||||
}
|
||||
@ -418,6 +463,44 @@ void ImageViewer::do_rot_up()
|
||||
createImage();
|
||||
}
|
||||
|
||||
void ImageViewer::do_recenter()
|
||||
{
|
||||
QString commands = QString("variable LAMMPSGUI_CX delete\n"
|
||||
"variable LAMMPSGUI_CY delete\n"
|
||||
"variable LAMMPSGUI_CZ delete\n"
|
||||
"variable LAMMPSGUI_CX equal (xcm(%1,x)-xlo)/lx\n"
|
||||
"variable LAMMPSGUI_CY equal (xcm(%1,y)-ylo)/ly\n"
|
||||
"variable LAMMPSGUI_CZ equal (xcm(%1,z)-zlo)/lz\n").arg(group);
|
||||
lammps->commands_string(commands.toLocal8Bit());
|
||||
xcenter = lammps->extract_variable("LAMMPSGUI_CX");
|
||||
ycenter = lammps->extract_variable("LAMMPSGUI_CZ");
|
||||
zcenter = lammps->extract_variable("LAMMPSGUI_CZ");
|
||||
lammps->commands_string("variable LAMMPSGUI_CX delete\n"
|
||||
"variable LAMMPSGUI_CY delete\n"
|
||||
"variable LAMMPSGUI_CZ delete\n");
|
||||
createImage();
|
||||
}
|
||||
|
||||
void ImageViewer::cmd_to_clipboard()
|
||||
{
|
||||
auto words = last_dump_cmd.split(" ");
|
||||
QString blank = QStringLiteral(" ");
|
||||
int modidx = words.indexOf("modify");
|
||||
int maxidx = words.size();
|
||||
|
||||
QString dumpcmd = "dump viz ";
|
||||
dumpcmd += words[1] + " image 100 myimage-*.ppm";
|
||||
for (int i = 4; i < modidx; ++i)
|
||||
if (words[i] != "noinit") dumpcmd += blank + words[i];
|
||||
dumpcmd += '\n';
|
||||
|
||||
dumpcmd += "dump_modify viz pad 9";
|
||||
for (int i = modidx + 1; i < maxidx; ++i)
|
||||
dumpcmd += blank + words[i];
|
||||
dumpcmd += '\n';
|
||||
QGuiApplication::clipboard()->setText(dumpcmd);
|
||||
}
|
||||
|
||||
void ImageViewer::change_group(int)
|
||||
{
|
||||
auto *box = findChild<QComboBox *>("group");
|
||||
@ -443,7 +526,7 @@ void ImageViewer::createImage()
|
||||
// determine elements from masses and set their covalent radii
|
||||
int ntypes = lammps->extract_setting("ntypes");
|
||||
int nbondtypes = lammps->extract_setting("nbondtypes");
|
||||
auto *masses = (double *)lammps->extract_atom("mass");
|
||||
auto *masses = (double *)lammps->extract_atom("mass");
|
||||
QString units = (const char *)lammps->extract_global("units");
|
||||
QString elements = "element ";
|
||||
QString adiams;
|
||||
@ -458,9 +541,21 @@ void ImageViewer::createImage()
|
||||
}
|
||||
}
|
||||
usediameter = lammps->extract_setting("radius_flag") != 0;
|
||||
|
||||
// use Lennard-Jones sigma for radius, if available
|
||||
usesigma = false;
|
||||
const char *pair_style = (const char *)lammps->extract_global("pair_style");
|
||||
if (!useelements && !usediameter && pair_style && (strncmp(pair_style, "lj/", 3) == 0)) {
|
||||
double **sigma = (double **)lammps->extract_pair("sigma");
|
||||
if (sigma) {
|
||||
usesigma = true;
|
||||
for (int i = 1; i <= ntypes; ++i) {
|
||||
if (sigma[i][i] > 0.0)
|
||||
adiams += QString("adiam %1 %2 ").arg(i).arg(vdwfactor * sigma[i][i]);
|
||||
}
|
||||
}
|
||||
}
|
||||
// adjust pushbutton state and clear adiams string to disable VDW display, if needed
|
||||
if (useelements || usediameter) {
|
||||
if (useelements || usediameter || usesigma) {
|
||||
auto *button = findChild<QPushButton *>("vdw");
|
||||
if (button) button->setEnabled(true);
|
||||
} else {
|
||||
@ -469,17 +564,20 @@ void ImageViewer::createImage()
|
||||
if (button) button->setEnabled(false);
|
||||
}
|
||||
|
||||
if (!adiams.isEmpty())
|
||||
// color
|
||||
if (useelements)
|
||||
dumpcmd += blank + "element";
|
||||
else
|
||||
dumpcmd += blank + settings.value("color", "type").toString();
|
||||
|
||||
// diameter
|
||||
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 ";
|
||||
dumpcmd += QString(" shiny %1 ").arg(shinyfactor);
|
||||
dumpcmd += QString(" fsaa %1").arg(antialias ? "yes" : "no");
|
||||
if (nbondtypes > 0) {
|
||||
if (vdwfactor > 1.0)
|
||||
@ -501,11 +599,15 @@ void ImageViewer::createImage()
|
||||
else
|
||||
dumpcmd += " axes no 0.0 0.0";
|
||||
|
||||
dumpcmd += QString(" center s %1 %2 %3").arg(xcenter).arg(ycenter).arg(zcenter);
|
||||
dumpcmd += " noinit";
|
||||
dumpcmd += " modify boxcolor " + settings.value("boxcolor", "yellow").toString();
|
||||
dumpcmd += " backcolor " + settings.value("background", "black").toString();
|
||||
if (!adiams.isEmpty()) dumpcmd += blank + elements + blank + adiams + blank;
|
||||
if (useelements) dumpcmd += blank + elements + blank + adiams + blank;
|
||||
if (usesigma) dumpcmd += blank + adiams + blank;
|
||||
settings.endGroup();
|
||||
|
||||
last_dump_cmd = dumpcmd;
|
||||
lammps->command(dumpcmd.toLocal8Bit());
|
||||
|
||||
QImageReader reader(dumpfile.fileName());
|
||||
@ -554,10 +656,13 @@ void ImageViewer::createActions()
|
||||
saveAsAct->setIcon(QIcon(":/icons/document-save-as.png"));
|
||||
saveAsAct->setEnabled(false);
|
||||
fileMenu->addSeparator();
|
||||
copyAct = fileMenu->addAction("&Copy", this, &ImageViewer::copy);
|
||||
copyAct = fileMenu->addAction("&Copy Image", this, &ImageViewer::copy);
|
||||
copyAct->setIcon(QIcon(":/icons/edit-copy.png"));
|
||||
copyAct->setShortcut(QKeySequence::Copy);
|
||||
copyAct->setEnabled(false);
|
||||
cmdAct = fileMenu->addAction("Copy &dump image command", this, &ImageViewer::cmd_to_clipboard);
|
||||
cmdAct->setIcon(QIcon(":/icons/file-clipboard.png"));
|
||||
cmdAct->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_D));
|
||||
fileMenu->addSeparator();
|
||||
QAction *exitAct = fileMenu->addAction("&Close", this, &QWidget::close);
|
||||
exitAct->setIcon(QIcon(":/icons/window-close.png"));
|
||||
|
||||
@ -34,7 +34,7 @@ class ImageViewer : public QDialog {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
explicit ImageViewer(const QString &fileName, LammpsWrapper *_lammps,
|
||||
explicit ImageViewer(const QString &fileName, LammpsWrapper *_lammps, QString title = "",
|
||||
QWidget *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
@ -46,6 +46,7 @@ private slots:
|
||||
void reset_view();
|
||||
void toggle_ssao();
|
||||
void toggle_anti();
|
||||
void toggle_shiny();
|
||||
void toggle_vdw();
|
||||
void toggle_box();
|
||||
void toggle_axes();
|
||||
@ -55,6 +56,8 @@ private slots:
|
||||
void do_rot_right();
|
||||
void do_rot_up();
|
||||
void do_rot_down();
|
||||
void do_recenter();
|
||||
void cmd_to_clipboard();
|
||||
void change_group(int);
|
||||
|
||||
public:
|
||||
@ -77,18 +80,20 @@ private:
|
||||
|
||||
QAction *saveAsAct;
|
||||
QAction *copyAct;
|
||||
QAction *cmdAct;
|
||||
QAction *zoomInAct;
|
||||
QAction *zoomOutAct;
|
||||
QAction *normalSizeAct;
|
||||
QAction *fitToWindowAct;
|
||||
|
||||
LammpsWrapper *lammps;
|
||||
QString group;
|
||||
QString filename;
|
||||
QString last_dump_cmd;
|
||||
int xsize, ysize;
|
||||
int hrot, vrot;
|
||||
double zoom, vdwfactor;
|
||||
bool showbox, showaxes, antialias, usessao, useelements, usediameter;
|
||||
double zoom, vdwfactor, shinyfactor;
|
||||
double xcenter, ycenter, zcenter;
|
||||
bool showbox, showaxes, antialias, usessao, useelements, usediameter, usesigma;
|
||||
};
|
||||
#endif
|
||||
|
||||
|
||||
72
tools/lammps-gui/lammps-gui.appdata.xml
Normal file
@ -0,0 +1,72 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<component type="desktop">
|
||||
<id>lammps-gui.desktop</id>
|
||||
<metadata_license>CC-BY-3.0</metadata_license>
|
||||
<project_license>GPL-2.0</project_license>
|
||||
<name>LAMMPS-GUI</name>
|
||||
<summary>
|
||||
Graphical interface to edit, run, plot, and visualize simulations with the LAMMPS MD code
|
||||
</summary>
|
||||
|
||||
<description>
|
||||
<p>LAMMPS-GUI is an editor customized for editing input files for the LAMMPS MD simulation software. It also includes LAMMPS and thus can run it directly from the GUI. Furthermore it has facilities to create or view and animate snapshot images, monitor and plot thermodynamic properties and show the console output of the running simulation.</p>
|
||||
</description>
|
||||
<screenshots>
|
||||
<screenshot type="default">
|
||||
<image>https://docs.lammps.org/_images/lammps-gui-main.png</image>
|
||||
<caption>LAMMPS-GUI main editor window</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://docs.lammps.org/_images/lammps-gui-log.png</image>
|
||||
<caption>LAMMPS-GUI output window</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://docs.lammps.org/_images/lammps-gui-chart.png</image>
|
||||
<caption>LAMMPS-GUI chart window</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://docs.lammps.org/_images/lammps-gui-slideshow.png</image>
|
||||
<caption>LAMMPS-GUI slideshow window</caption>
|
||||
</screenshot>
|
||||
<screenshot>
|
||||
<image>https://docs.lammps.org/_images/lammps-gui-image.png</image>
|
||||
<caption>LAMMPS-GUI snapshot image window</caption>
|
||||
</screenshot>
|
||||
</screenshots>
|
||||
|
||||
<url type="homepage">https://www.lammps.org/</url>
|
||||
<url type="bugtracker">https://github.com/lammps/lammps/issues</url>
|
||||
<url type="help">https://docs.lammps.org/stable/</url>
|
||||
|
||||
<update_contact>packages@lammps.org</update_contact>
|
||||
<developer_name>Axel Kohlmeyer</developer_name>
|
||||
<project_group>LAMMPS</project_group>
|
||||
<keywords>
|
||||
<keyword>Molecular Dynamics</keyword>
|
||||
<keyword>Physics</keyword>
|
||||
<keyword>Editor</keyword>
|
||||
<keyword>N-body</keyword>
|
||||
</keywords>
|
||||
|
||||
<provides>
|
||||
<binary>lammps-gui</binary>
|
||||
<binary>lmp</binary>
|
||||
</provides>
|
||||
|
||||
<releases>
|
||||
<release version="1.6.8" timestamp="1723581926">
|
||||
<description>
|
||||
</description>
|
||||
</release>
|
||||
<release version="1.6.7" timestamp="1723394796">
|
||||
<description>
|
||||
Add wizards for setting up LAMMPS tutorials and restart file inspector
|
||||
</description>
|
||||
</release>
|
||||
<release version="1.6.6" timestamp="1722581799">
|
||||
<description>
|
||||
First version packaged in flatpak format
|
||||
</description>
|
||||
</release>
|
||||
</releases>
|
||||
</component>
|
||||
@ -4,7 +4,7 @@ Type=Application
|
||||
Categories=Education;Science
|
||||
MimeType=text/x-application-lammps
|
||||
Exec=lammps-gui %f
|
||||
Name=The LAMMPS GUI
|
||||
Name=LAMMPS-GUI
|
||||
Terminal=false
|
||||
GenericName=LAMMPS MD Simulator GUI
|
||||
Keywords=MD Simulation;LAMMPS;Molecular Dynamics;N-Body
|
||||
|
||||
@ -16,20 +16,32 @@
|
||||
|
||||
#include <QMainWindow>
|
||||
|
||||
#include <QEvent>
|
||||
#include <QGridLayout>
|
||||
#include <QList>
|
||||
#include <QPair>
|
||||
#include <QSpacerItem>
|
||||
#include <QString>
|
||||
#include <QWizard>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#include "lammpswrapper.h"
|
||||
|
||||
// identifier for LAMMPS restart files
|
||||
#if !defined(LAMMPS_MAGIC)
|
||||
#define LAMMPS_MAGIC "LammpS RestartT"
|
||||
#endif
|
||||
|
||||
// forward declarations
|
||||
|
||||
class GeneralTab;
|
||||
class LammpsRunner;
|
||||
class LogWindow;
|
||||
class QFont;
|
||||
class QLabel;
|
||||
class QPlainTextEdit;
|
||||
class QProgressBar;
|
||||
class QTimer;
|
||||
class QWidget;
|
||||
class QWizardPage;
|
||||
|
||||
QT_BEGIN_NAMESPACE
|
||||
namespace Ui {
|
||||
@ -37,23 +49,23 @@ class LammpsGui;
|
||||
}
|
||||
QT_END_NAMESPACE
|
||||
|
||||
class QLabel;
|
||||
class QPlainTextEdit;
|
||||
class QProgressBar;
|
||||
class QTimer;
|
||||
|
||||
class Highlighter;
|
||||
class StdCapture;
|
||||
class Preferences;
|
||||
class ImageViewer;
|
||||
class ChartWindow;
|
||||
class GeneralTab;
|
||||
class Highlighter;
|
||||
class ImageViewer;
|
||||
class LammpsRunner;
|
||||
class LogWindow;
|
||||
class Preferences;
|
||||
class SlideShow;
|
||||
class StdCapture;
|
||||
|
||||
class LammpsGui : public QMainWindow {
|
||||
Q_OBJECT
|
||||
|
||||
friend class CodeEditor;
|
||||
friend class GeneralTab;
|
||||
friend class Tutorial1Wizard;
|
||||
friend class Tutorial2Wizard;
|
||||
|
||||
public:
|
||||
LammpsGui(QWidget *parent = nullptr, const char *filename = nullptr);
|
||||
@ -61,12 +73,28 @@ public:
|
||||
|
||||
protected:
|
||||
void open_file(const QString &filename);
|
||||
void view_file(const QString &filename);
|
||||
void inspect_file(const QString &filename);
|
||||
void write_file(const QString &filename);
|
||||
void update_recents(const QString &filename = "");
|
||||
void update_variables();
|
||||
void do_run(bool use_buffer);
|
||||
void start_lammps();
|
||||
void run_done();
|
||||
void setDocver();
|
||||
void autoSave();
|
||||
void setFont(const QFont &newfont);
|
||||
QWizardPage *tutorial1_intro();
|
||||
QWizardPage *tutorial1_info();
|
||||
QWizardPage *tutorial1_directory();
|
||||
QWizardPage *tutorial1_finish();
|
||||
QWizardPage *tutorial2_intro();
|
||||
QWizardPage *tutorial2_info();
|
||||
QWizardPage *tutorial2_directory();
|
||||
QWizardPage *tutorial2_finish();
|
||||
void setup_tutorial(int tutno, const QString &dir, bool purgedir, bool getsolution);
|
||||
void purge_inspect_list();
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
|
||||
public slots:
|
||||
void quit();
|
||||
@ -75,7 +103,10 @@ public slots:
|
||||
private slots:
|
||||
void new_document();
|
||||
void open();
|
||||
void view();
|
||||
void inspect();
|
||||
void open_recent();
|
||||
void get_directory();
|
||||
void start_exe();
|
||||
void save();
|
||||
void save_as();
|
||||
@ -97,6 +128,9 @@ private slots:
|
||||
void about();
|
||||
void help();
|
||||
void manual();
|
||||
void tutorial_web();
|
||||
void start_tutorial1();
|
||||
void start_tutorial2();
|
||||
void howto();
|
||||
void logupdate();
|
||||
void modified();
|
||||
@ -120,6 +154,14 @@ private:
|
||||
Preferences *prefdialog;
|
||||
QLabel *lammpsstatus;
|
||||
QLabel *varwindow;
|
||||
QWizard *wizard;
|
||||
|
||||
struct InspectData {
|
||||
QWidget *info;
|
||||
QWidget *data;
|
||||
QWidget *image;
|
||||
};
|
||||
QList<InspectData *> inspectList;
|
||||
|
||||
QString current_file;
|
||||
QString current_dir;
|
||||
@ -128,11 +170,28 @@ private:
|
||||
|
||||
LammpsWrapper lammps;
|
||||
LammpsRunner *runner;
|
||||
QString docver;
|
||||
std::string plugin_path;
|
||||
bool is_running;
|
||||
int run_counter;
|
||||
std::vector<char *> lammps_args;
|
||||
};
|
||||
|
||||
class Tutorial1Wizard : public QWizard {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Tutorial1Wizard(QWidget *parent = nullptr);
|
||||
void accept() override;
|
||||
};
|
||||
|
||||
class Tutorial2Wizard : public QWizard {
|
||||
Q_OBJECT
|
||||
|
||||
public:
|
||||
Tutorial2Wizard(QWidget *parent = nullptr);
|
||||
void accept() override;
|
||||
};
|
||||
#endif // LAMMPSGUI_H
|
||||
|
||||
// Local Variables:
|
||||
|
||||
@ -2,6 +2,8 @@
|
||||
<RCC>
|
||||
<qresource prefix="/">
|
||||
<file>icons/lammps-icon-128x128.png</file>
|
||||
<file>icons/tutorial1-logo.png</file>
|
||||
<file>icons/tutorial2-logo.png</file>
|
||||
<file>help_index.table</file>
|
||||
<!-- This file is updated with: grep 'mycmd ==' ../../src/input.cpp | sed -e 's/^.*mycmd == "\(.*\)".*$/\1/' > lammps_internal_commands.txt -->
|
||||
<file>lammps_internal_commands.txt</file>
|
||||
@ -9,7 +11,9 @@
|
||||
<file>icons/application-calc.png</file>
|
||||
<file>icons/application-exit.png</file>
|
||||
<file>icons/application-plot.png</file>
|
||||
<file>icons/application-yaml.png</file>
|
||||
<file>icons/axes-img.png</file>
|
||||
<file>icons/chart-smooth.png</file>
|
||||
<file>icons/document-new.png</file>
|
||||
<file>icons/document-open-recent.png</file>
|
||||
<file>icons/document-open.png</file>
|
||||
@ -25,6 +29,7 @@
|
||||
<file>icons/emblem-photos.png</file>
|
||||
<file>icons/expand-text.png</file>
|
||||
<file>icons/export-movie.png</file>
|
||||
<file>icons/file-clipboard.png</file>
|
||||
<file>icons/format-indent-less-3.png</file>
|
||||
<file>icons/go-first.png</file>
|
||||
<file>icons/go-last.png</file>
|
||||
@ -39,9 +44,12 @@
|
||||
<file>icons/help-about.png</file>
|
||||
<file>icons/help-browser.png</file>
|
||||
<file>icons/help-faq.png</file>
|
||||
<file>icons/help-tutorial.png</file>
|
||||
<file>icons/image-shiny.png</file>
|
||||
<file>icons/image-x-generic.png</file>
|
||||
<file>icons/media-playback-start-2.png</file>
|
||||
<file>icons/media-playlist-repeat.png</file>
|
||||
<file>icons/move-recenter.png</file>
|
||||
<file>icons/object-rotate-left.png</file>
|
||||
<file>icons/object-rotate-right.png</file>
|
||||
<file>icons/ovito.png</file>
|
||||
@ -53,10 +61,13 @@
|
||||
<file>icons/system-box.png</file>
|
||||
<file>icons/system-help.png</file>
|
||||
<file>icons/system-run.png</file>
|
||||
<file>icons/trash.png</file>
|
||||
<file>icons/tutorial-logo.png</file>
|
||||
<file>icons/utilities-terminal.png</file>
|
||||
<file>icons/vdw-style.png</file>
|
||||
<file>icons/vmd.png</file>
|
||||
<file>icons/window-close.png</file>
|
||||
<file>icons/x-office-drawing.png</file>
|
||||
<file>icons/yaml-file-icon.png</file>
|
||||
</qresource>
|
||||
</RCC>
|
||||
|
||||
@ -37,6 +37,8 @@
|
||||
<addaction name="actionNew"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="actionOpen"/>
|
||||
<addaction name="actionView"/>
|
||||
<addaction name="actionInspect"/>
|
||||
<addaction name="separator"/>
|
||||
<addaction name="action_1"/>
|
||||
<addaction name="action_2"/>
|
||||
@ -77,6 +79,13 @@
|
||||
<addaction name="actionView_in_OVITO"/>
|
||||
<addaction name="actionView_in_VMD"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_Tutorial">
|
||||
<property name="title">
|
||||
<string>&Tutorials</string>
|
||||
</property>
|
||||
<addaction name="actionTutorial1"/>
|
||||
<addaction name="actionTutorial2"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menuAbout">
|
||||
<property name="title">
|
||||
<string>&About</string>
|
||||
@ -85,6 +94,7 @@
|
||||
<addaction name="action_Help"/>
|
||||
<addaction name="actionLAMMPS_GUI_Howto"/>
|
||||
<addaction name="actionLAMMPS_Manual"/>
|
||||
<addaction name="actionLAMMPS_Tutorial"/>
|
||||
</widget>
|
||||
<widget class="QMenu" name="menu_View">
|
||||
<property name="title">
|
||||
@ -100,6 +110,7 @@
|
||||
<addaction name="menuEdit"/>
|
||||
<addaction name="menu_Run"/>
|
||||
<addaction name="menu_View"/>
|
||||
<addaction name="menu_Tutorial"/>
|
||||
<addaction name="menuAbout"/>
|
||||
</widget>
|
||||
<widget class="QStatusBar" name="statusbar"/>
|
||||
@ -125,6 +136,28 @@
|
||||
<string>Ctrl+O</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionView">
|
||||
<property name="icon">
|
||||
<iconset theme=":/icons/document-open.png"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&View</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+F</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionInspect">
|
||||
<property name="icon">
|
||||
<iconset theme=":/icons/document-open.png"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Inspect &Restart</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+R</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionSave">
|
||||
<property name="icon">
|
||||
<iconset theme=":/icons/document-save.png"/>
|
||||
@ -262,7 +295,7 @@
|
||||
<iconset theme=":/icons/help-about.png"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&About LAMMPS</string>
|
||||
<string>&About LAMMPS-GUI</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+A</string>
|
||||
@ -295,18 +328,29 @@
|
||||
<iconset theme=":/icons/help-browser.png"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>LAMMPS &Manual</string>
|
||||
<string>LAMMPS Online &Manual</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+M</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLAMMPS_Tutorial">
|
||||
<property name="icon">
|
||||
<iconset theme=":/icons/help-tutorial.png"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>LAMMPS &Tutorial Website</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+T</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionDefaults">
|
||||
<property name="icon">
|
||||
<iconset theme=":/icons/document-revert.png"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Reset to &Defaults</string>
|
||||
<string>Reset Preferences to &Defaults</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionView_in_OVITO">
|
||||
@ -336,7 +380,7 @@
|
||||
<iconset theme=":/icons/utilities-terminal.png"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Log Window</string>
|
||||
<string>&Output Window</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+L</string>
|
||||
@ -347,7 +391,7 @@
|
||||
<iconset theme=":/icons/x-office-drawing.png"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Chart Window</string>
|
||||
<string>&Charts Window</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+C</string>
|
||||
@ -437,12 +481,28 @@
|
||||
<string>Ctrl+Shift+W</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTutorial1">
|
||||
<property name="icon">
|
||||
<iconset theme=":/icons/tutorial-logo.png"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start LAMMPS Tutorial &1</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionTutorial2">
|
||||
<property name="icon">
|
||||
<iconset theme=":/icons/tutorial-logo.png"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Start LAMMPS Tutorial &2</string>
|
||||
</property>
|
||||
</action>
|
||||
<action name="actionLAMMPS_GUI_Howto">
|
||||
<property name="icon">
|
||||
<iconset theme=":/icons/system-help.png"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>LAMMPS GUI Howto</string>
|
||||
<string>LAMMPS-&GUI Howto</string>
|
||||
</property>
|
||||
<property name="shortcut">
|
||||
<string>Ctrl+Shift+G</string>
|
||||
|
||||
@ -28,7 +28,7 @@ LammpsWrapper::LammpsWrapper() : lammps_handle(nullptr)
|
||||
|
||||
void LammpsWrapper::open(int narg, char **args)
|
||||
{
|
||||
// since there may only be one LAMMPS instance in LAMMPS GUI we don't open a second
|
||||
// since there may only be one LAMMPS instance in LAMMPS-GUI we don't open a second one
|
||||
if (lammps_handle) return;
|
||||
#if defined(LAMMPS_GUI_USE_PLUGIN)
|
||||
lammps_handle = ((liblammpsplugin_t *)plugin_handle)->open_no_mpi(narg, args, nullptr);
|
||||
@ -76,6 +76,19 @@ void *LammpsWrapper::extract_global(const char *keyword)
|
||||
return val;
|
||||
}
|
||||
|
||||
void *LammpsWrapper::extract_pair(const char *keyword)
|
||||
{
|
||||
void *val = nullptr;
|
||||
if (lammps_handle) {
|
||||
#if defined(LAMMPS_GUI_USE_PLUGIN)
|
||||
val = ((liblammpsplugin_t *)plugin_handle)->extract_pair(lammps_handle, keyword);
|
||||
#else
|
||||
val = lammps_extract_pair(lammps_handle, keyword);
|
||||
#endif
|
||||
}
|
||||
return val;
|
||||
}
|
||||
|
||||
void *LammpsWrapper::extract_atom(const char *keyword)
|
||||
{
|
||||
void *val = nullptr;
|
||||
@ -89,6 +102,26 @@ void *LammpsWrapper::extract_atom(const char *keyword)
|
||||
return val;
|
||||
}
|
||||
|
||||
// note: equal style and compatible variables only
|
||||
double LammpsWrapper::extract_variable(const char *keyword)
|
||||
{
|
||||
void *ptr = nullptr;
|
||||
if (lammps_handle) {
|
||||
#if defined(LAMMPS_GUI_USE_PLUGIN)
|
||||
ptr = ((liblammpsplugin_t *)plugin_handle)->extract_variable(lammps_handle, keyword, nullptr);
|
||||
#else
|
||||
ptr = lammps_extract_variable(lammps_handle, keyword, nullptr);
|
||||
#endif
|
||||
}
|
||||
double val = *((double *)ptr);
|
||||
#if defined(LAMMPS_GUI_USE_PLUGIN)
|
||||
ptr = ((liblammpsplugin_t *)plugin_handle)->free(ptr);
|
||||
#else
|
||||
lammps_free(ptr);
|
||||
#endif
|
||||
return val;
|
||||
}
|
||||
|
||||
int LammpsWrapper::id_count(const char *keyword)
|
||||
{
|
||||
int val = 0;
|
||||
|
||||
@ -32,7 +32,9 @@ public:
|
||||
int version();
|
||||
int extract_setting(const char *keyword);
|
||||
void *extract_global(const char *keyword);
|
||||
void *extract_pair(const char *keyword);
|
||||
void *extract_atom(const char *keyword);
|
||||
double extract_variable(const char *keyword);
|
||||
|
||||
int id_count(const char *idtype);
|
||||
int id_name(const char *idtype, int idx, char *buf, int buflen);
|
||||
|
||||
@ -17,18 +17,21 @@
|
||||
|
||||
#include <QAction>
|
||||
#include <QApplication>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QIcon>
|
||||
#include <QKeySequence>
|
||||
#include <QMenu>
|
||||
#include <QMessageBox>
|
||||
#include <QRegularExpression>
|
||||
#include <QSettings>
|
||||
#include <QShortcut>
|
||||
#include <QString>
|
||||
#include <QTextStream>
|
||||
|
||||
const QString LogWindow::yaml_regex =
|
||||
QStringLiteral("^(keywords:.*$|data:$|---$|\\.\\.\\.$| - \\[.*\\]$)");
|
||||
|
||||
LogWindow::LogWindow(const QString &_filename, QWidget *parent) :
|
||||
QPlainTextEdit(parent), filename(_filename)
|
||||
{
|
||||
@ -37,6 +40,8 @@ LogWindow::LogWindow(const QString &_filename, QWidget *parent) :
|
||||
|
||||
auto *action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_S), this);
|
||||
connect(action, &QShortcut::activated, this, &LogWindow::save_as);
|
||||
action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Y), this);
|
||||
connect(action, &QShortcut::activated, this, &LogWindow::extract_yaml);
|
||||
action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Q), this);
|
||||
connect(action, &QShortcut::activated, this, &LogWindow::quit);
|
||||
action = new QShortcut(QKeySequence(Qt::CTRL | Qt::Key_Slash), this);
|
||||
@ -94,6 +99,43 @@ void LogWindow::save_as()
|
||||
file.close();
|
||||
}
|
||||
|
||||
bool LogWindow::check_yaml()
|
||||
{
|
||||
QRegularExpression is_yaml(yaml_regex);
|
||||
QStringList lines = toPlainText().split('\n');
|
||||
for (const auto &line : lines)
|
||||
if (is_yaml.match(line).hasMatch()) return true;
|
||||
return false;
|
||||
}
|
||||
|
||||
void LogWindow::extract_yaml()
|
||||
{
|
||||
// ignore if no YAML format lines in buffer
|
||||
if (!check_yaml()) return;
|
||||
|
||||
QString defaultname = filename + ".yaml";
|
||||
if (filename.isEmpty()) defaultname = "lammps.yaml";
|
||||
QString yamlFileName = QFileDialog::getSaveFileName(this, "Save YAML data to File", defaultname,
|
||||
"YAML files (*.yaml *.yml)");
|
||||
// cannot save without filename
|
||||
if (yamlFileName.isEmpty()) return;
|
||||
|
||||
QFileInfo path(yamlFileName);
|
||||
QFile file(path.absoluteFilePath());
|
||||
if (!file.open(QIODevice::WriteOnly | QFile::Text)) {
|
||||
QMessageBox::warning(this, "Warning", "Cannot save file: " + file.errorString());
|
||||
return;
|
||||
}
|
||||
|
||||
QRegularExpression is_yaml(yaml_regex);
|
||||
QTextStream out(&file);
|
||||
QStringList lines = toPlainText().split('\n');
|
||||
for (const auto &line : lines) {
|
||||
if (is_yaml.match(line).hasMatch()) out << line << '\n';
|
||||
}
|
||||
file.close();
|
||||
}
|
||||
|
||||
void LogWindow::contextMenuEvent(QContextMenuEvent *event)
|
||||
{
|
||||
// show augmented context menu
|
||||
@ -103,6 +145,13 @@ void LogWindow::contextMenuEvent(QContextMenuEvent *event)
|
||||
action->setIcon(QIcon(":/icons/document-save-as.png"));
|
||||
action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_S));
|
||||
connect(action, &QAction::triggered, this, &LogWindow::save_as);
|
||||
// only show export-to-yaml entry if there is YAML format content.
|
||||
if (check_yaml()) {
|
||||
action = menu->addAction(QString("&Export YAML Data to File ..."));
|
||||
action->setIcon(QIcon(":/icons/yaml-file-icon.png"));
|
||||
action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_Y));
|
||||
connect(action, &QAction::triggered, this, &LogWindow::extract_yaml);
|
||||
}
|
||||
action = menu->addAction("&Close Window", this, &QWidget::close);
|
||||
action->setIcon(QIcon(":/icons/window-close.png"));
|
||||
action->setShortcut(QKeySequence(Qt::CTRL | Qt::Key_W));
|
||||
|
||||
@ -23,6 +23,7 @@ public:
|
||||
LogWindow(const QString &filename, QWidget *parent = nullptr);
|
||||
|
||||
private slots:
|
||||
void extract_yaml();
|
||||
void quit();
|
||||
void save_as();
|
||||
void stop_run();
|
||||
@ -31,9 +32,11 @@ protected:
|
||||
void closeEvent(QCloseEvent *event) override;
|
||||
void contextMenuEvent(QContextMenuEvent *event) override;
|
||||
bool eventFilter(QObject *watched, QEvent *event) override;
|
||||
bool check_yaml();
|
||||
|
||||
private:
|
||||
QString filename;
|
||||
static const QString yaml_regex;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
||||
@ -14,7 +14,6 @@
|
||||
#include "lammpsgui.h"
|
||||
|
||||
#include <QApplication>
|
||||
#include <QFileInfo>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
|
||||
112
tools/lammps-gui/org.lammps.lammps-gui.yml
Normal file
@ -0,0 +1,112 @@
|
||||
id: org.lammps.lammps-gui
|
||||
runtime: org.kde.Platform
|
||||
runtime-version: "5.15-23.08"
|
||||
sdk: org.kde.Sdk
|
||||
command: lammps-gui
|
||||
finish-args:
|
||||
- --share=ipc
|
||||
- --socket=fallback-x11
|
||||
- --socket=wayland
|
||||
- --filesystem=host
|
||||
- --share=network
|
||||
build-options:
|
||||
build-args:
|
||||
- --share=network
|
||||
rename-icon: lammps
|
||||
rename-desktop-file: lammps-gui.desktop
|
||||
rename-appdata-file: lammps-gui.appdata.xml
|
||||
rename-mime-file: lammps-input.xml
|
||||
modules:
|
||||
- name: lammps-gui
|
||||
buildsystem: cmake-ninja
|
||||
builddir: true
|
||||
subdir: cmake
|
||||
config-opts:
|
||||
- -D PKG_AMOEBA=yes
|
||||
- -D PKG_ASPHERE=yes
|
||||
- -D PKG_AWPMD=yes
|
||||
- -D PKG_BOCS=yes
|
||||
- -D PKG_BODY=yes
|
||||
- -D PKG_BPM=yes
|
||||
- -D PKG_BROWNIAN=yes
|
||||
- -D PKG_CG-DNA=yes
|
||||
- -D PKG_CG-SPICA=yes
|
||||
- -D PKG_CLASS2=yes
|
||||
- -D PKG_COLLOID=yes
|
||||
- -D PKG_COLVARS=yes
|
||||
- -D PKG_COMPRESS=yes
|
||||
- -D PKG_CORESHELL=yes
|
||||
- -D PKG_DIELECTRIC=yes
|
||||
- -D PKG_DIFFRACTION=yes
|
||||
- -D PKG_DIPOLE=yes
|
||||
- -D PKG_DPD-BASIC=yes
|
||||
- -D PKG_DPD-MESO=yes
|
||||
- -D PKG_DPD-REACT=yes
|
||||
- -D PKG_DPD-SMOOTH=yes
|
||||
- -D PKG_DRUDE=yes
|
||||
- -D PKG_EFF=yes
|
||||
- -D PKG_ELECTRODE=yes
|
||||
- -D PKG_EXTRA-COMMAND=yes
|
||||
- -D PKG_EXTRA-COMPUTE=yes
|
||||
- -D PKG_EXTRA-DUMP=yes
|
||||
- -D PKG_EXTRA-FIX=yes
|
||||
- -D PKG_EXTRA-MOLECULE=yes
|
||||
- -D PKG_EXTRA-PAIR=yes
|
||||
- -D PKG_FEP=yes
|
||||
- -D PKG_GRANULAR=yes
|
||||
- -D PKG_GPU=yes
|
||||
- -D GPU_API=opencl
|
||||
- -D PKG_INTERLAYER=yes
|
||||
- -D PKG_KSPACE=yes
|
||||
- -D PKG_LEPTON=yes
|
||||
- -D PKG_MACHDYN=yes
|
||||
- -D PKG_MANYBODY=yes
|
||||
- -D PKG_MANIFOLD=yes
|
||||
- -D PKG_MC=yes
|
||||
- -D PKG_MEAM=yes
|
||||
- -D PKG_MESONT=yes
|
||||
- -D PKG_MGPT=yes
|
||||
- -D PKG_MISC=yes
|
||||
- -D PKG_ML-IAP=yes
|
||||
- -D PKG_ML-PACE=yes
|
||||
- -D PKG_ML-POD=yes
|
||||
- -D PKG_ML-RANN=yes
|
||||
- -D PKG_ML-SNAP=yes
|
||||
- -D PKG_ML-UF3=yes
|
||||
- -D PKG_MOFFF=yes
|
||||
- -D PKG_MOLECULE=yes
|
||||
- -D PKG_OPENMP=yes
|
||||
- -D PKG_OPT=yes
|
||||
- -D PKG_ORIENT=yes
|
||||
- -D PKG_PERI=yes
|
||||
- -D PKG_PHONON=yes
|
||||
- -D PKG_PLUGIN=yes
|
||||
- -D PKG_POEMS=yes
|
||||
- -D PKG_PTM=yes
|
||||
- -D PKG_PYTHON=yes
|
||||
- -D PKG_QEQ=yes
|
||||
- -D PKG_QTB=yes
|
||||
- -D PKG_REACTION=yes
|
||||
- -D PKG_REAXFF=yes
|
||||
- -D PKG_RIGID=yes
|
||||
- -D PKG_SHOCK=yes
|
||||
- -D PKG_SMTBQ=yes
|
||||
- -D PKG_SPH=yes
|
||||
- -D PKG_SPIN=yes
|
||||
- -D PKG_SRD=yes
|
||||
- -D PKG_TALLY=yes
|
||||
- -D PKG_UEF=yes
|
||||
- -D PKG_VORONOI=yes
|
||||
- -D PKG_YAFF=yes
|
||||
- -D BUILD_LAMMPS_GUI=yes
|
||||
- -D BUILD_SHARED_LIBS=yes
|
||||
- -D CMAKE_CXX_COMPILER=g++
|
||||
- -D CMAKE_C_COMPILER=gcc
|
||||
- -D CMAKE_Fortran_COMPILER=gfortran
|
||||
- -D CMAKE_BUILD_TYPE=Release
|
||||
- -D DOWNLOAD_POTENTIALS=no
|
||||
- -D BUILD_TOOLS=yes
|
||||
sources:
|
||||
- type: git
|
||||
url: https://github.com/akohlmey/lammps.git
|
||||
branch: collected-small-fixes
|
||||
@ -23,7 +23,6 @@
|
||||
#include <QComboBox>
|
||||
#include <QCoreApplication>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDir>
|
||||
#include <QDoubleValidator>
|
||||
#include <QFileDialog>
|
||||
#include <QFontDialog>
|
||||
@ -40,7 +39,9 @@
|
||||
#include <QSpacerItem>
|
||||
#include <QSpinBox>
|
||||
#include <QTabWidget>
|
||||
#if defined(_OPENMP)
|
||||
#include <QThread>
|
||||
#endif
|
||||
#include <QVBoxLayout>
|
||||
|
||||
#if defined(_OPENMP)
|
||||
@ -93,7 +94,7 @@ void Preferences::accept()
|
||||
|
||||
// store selected accelerator
|
||||
QList<QRadioButton *> allButtons = tabWidget->findChildren<QRadioButton *>();
|
||||
for (auto & allButton : allButtons) {
|
||||
for (auto &allButton : allButtons) {
|
||||
if (allButton->isChecked()) {
|
||||
if (allButton->objectName() == "none")
|
||||
settings->setValue("accelerator", QString::number(AcceleratorTab::None));
|
||||
@ -136,6 +137,8 @@ void Preferences::accept()
|
||||
if (box) settings->setValue("antialias", box->isChecked());
|
||||
box = tabWidget->findChild<QCheckBox *>("ssao");
|
||||
if (box) settings->setValue("ssao", box->isChecked());
|
||||
box = tabWidget->findChild<QCheckBox *>("shiny");
|
||||
if (box) settings->setValue("shinystyle", box->isChecked());
|
||||
box = tabWidget->findChild<QCheckBox *>("box");
|
||||
if (box) settings->setValue("box", box->isChecked());
|
||||
box = tabWidget->findChild<QCheckBox *>("axes");
|
||||
@ -195,6 +198,8 @@ void Preferences::accept()
|
||||
if (box) settings->setValue("return", box->isChecked());
|
||||
box = tabWidget->findChild<QCheckBox *>("autoval");
|
||||
if (box) settings->setValue("automatic", box->isChecked());
|
||||
box = tabWidget->findChild<QCheckBox *>("savval");
|
||||
if (box) settings->setValue("autosave", box->isChecked());
|
||||
settings->endGroup();
|
||||
|
||||
QDialog::accept();
|
||||
@ -211,23 +216,23 @@ GeneralTab::GeneralTab(QSettings *_settings, LammpsWrapper *_lammps, QWidget *pa
|
||||
auto *cite = new QCheckBox("Include citation details");
|
||||
cite->setObjectName("cite");
|
||||
cite->setCheckState(settings->value("cite", false).toBool() ? Qt::Checked : Qt::Unchecked);
|
||||
auto *logv = new QCheckBox("Show log window by default");
|
||||
auto *logv = new QCheckBox("Show Output window by default");
|
||||
logv->setObjectName("viewlog");
|
||||
logv->setCheckState(settings->value("viewlog", true).toBool() ? Qt::Checked : Qt::Unchecked);
|
||||
auto *pltv = new QCheckBox("Show chart window by default");
|
||||
auto *pltv = new QCheckBox("Show Charts window by default");
|
||||
pltv->setObjectName("viewchart");
|
||||
pltv->setCheckState(settings->value("viewchart", true).toBool() ? Qt::Checked : Qt::Unchecked);
|
||||
auto *sldv = new QCheckBox("Show slide show window by default");
|
||||
auto *sldv = new QCheckBox("Show Slide Show window by default");
|
||||
sldv->setObjectName("viewslide");
|
||||
sldv->setCheckState(settings->value("viewslide", true).toBool() ? Qt::Checked : Qt::Unchecked);
|
||||
auto *logr = new QCheckBox("Replace log window on new run");
|
||||
auto *logr = new QCheckBox("Replace Output window on new run");
|
||||
logr->setObjectName("logreplace");
|
||||
logr->setCheckState(settings->value("logreplace", true).toBool() ? Qt::Checked : Qt::Unchecked);
|
||||
auto *imgr = new QCheckBox("Replace image window on new render");
|
||||
auto *imgr = new QCheckBox("Replace Image window on new render");
|
||||
imgr->setObjectName("imagereplace");
|
||||
imgr->setCheckState(settings->value("imagereplace", true).toBool() ? Qt::Checked
|
||||
: Qt::Unchecked);
|
||||
auto *pltr = new QCheckBox("Replace chart window on new run");
|
||||
auto *pltr = new QCheckBox("Replace Charts window on new run");
|
||||
pltr->setObjectName("chartreplace");
|
||||
pltr->setCheckState(settings->value("chartreplace", true).toBool() ? Qt::Checked
|
||||
: Qt::Unchecked);
|
||||
@ -245,26 +250,33 @@ GeneralTab::GeneralTab(QSettings *_settings, LammpsWrapper *_lammps, QWidget *pa
|
||||
connect(pluginbrowse, &QPushButton::released, this, &GeneralTab::pluginpath);
|
||||
#endif
|
||||
|
||||
auto *fontlayout = new QHBoxLayout;
|
||||
auto *gridlayout = new QGridLayout;
|
||||
auto *getallfont =
|
||||
new QPushButton(QIcon(":/icons/preferences-desktop-font.png"), "Select Default Font...");
|
||||
auto *gettextfont =
|
||||
new QPushButton(QIcon(":/icons/preferences-desktop-font.png"), "Select Text Font...");
|
||||
fontlayout->addWidget(getallfont);
|
||||
fontlayout->addWidget(gettextfont);
|
||||
gridlayout->addWidget(getallfont, 0, 0);
|
||||
gridlayout->addWidget(gettextfont, 0, 1);
|
||||
connect(getallfont, &QPushButton::released, this, &GeneralTab::newallfont);
|
||||
connect(gettextfont, &QPushButton::released, this, &GeneralTab::newtextfont);
|
||||
|
||||
auto *freqlayout = new QHBoxLayout;
|
||||
auto *freqlabel = new QLabel("GUI update interval (ms)");
|
||||
auto *freqval = new QSpinBox;
|
||||
auto *freqlabel = new QLabel("Data update interval (ms)");
|
||||
auto *freqval = new QSpinBox;
|
||||
freqval->setRange(1, 1000);
|
||||
freqval->setStepType(QAbstractSpinBox::AdaptiveDecimalStepType);
|
||||
freqval->setValue(settings->value("updfreq", "10").toInt());
|
||||
freqval->setObjectName("updfreq");
|
||||
freqlayout->addWidget(freqlabel);
|
||||
freqlayout->addWidget(freqval);
|
||||
freqlayout->addStretch(1);
|
||||
gridlayout->addWidget(freqlabel, 1, 0);
|
||||
gridlayout->addWidget(freqval, 1, 1);
|
||||
|
||||
auto *chartlabel = new QLabel("Charts update interval (ms)");
|
||||
auto *chartval = new QSpinBox;
|
||||
chartval->setRange(1, 5000);
|
||||
chartval->setStepType(QAbstractSpinBox::AdaptiveDecimalStepType);
|
||||
chartval->setValue(settings->value("updchart", "500").toInt());
|
||||
chartval->setObjectName("updchart");
|
||||
gridlayout->addWidget(chartlabel, 2, 0);
|
||||
gridlayout->addWidget(chartval, 2, 1);
|
||||
|
||||
layout->addWidget(echo);
|
||||
layout->addWidget(cite);
|
||||
@ -278,8 +290,7 @@ GeneralTab::GeneralTab(QSettings *_settings, LammpsWrapper *_lammps, QWidget *pa
|
||||
layout->addWidget(pluginlabel);
|
||||
layout->addLayout(pluginlayout);
|
||||
#endif
|
||||
layout->addLayout(fontlayout);
|
||||
layout->addLayout(freqlayout);
|
||||
layout->addLayout(gridlayout);
|
||||
layout->addStretch(1);
|
||||
setLayout(layout);
|
||||
}
|
||||
@ -290,16 +301,24 @@ void GeneralTab::updatefonts(const QFont &all, const QFont &text)
|
||||
for (QWidget *widget : QApplication::topLevelWidgets())
|
||||
if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget);
|
||||
|
||||
QApplication::setFont(all);
|
||||
if (main) main->ui->textEdit->document()->setDefaultFont(text);
|
||||
if (main) {
|
||||
main->setFont(all);
|
||||
main->ui->textEdit->document()->setDefaultFont(text);
|
||||
if (main->wizard) main->wizard->setFont(all);
|
||||
}
|
||||
|
||||
Preferences *prefs = nullptr;
|
||||
for (QWidget *widget : QApplication::topLevelWidgets())
|
||||
if (widget->objectName() == "preferences") prefs = dynamic_cast<Preferences *>(widget);
|
||||
if (prefs) prefs->setFont(all);
|
||||
}
|
||||
|
||||
void GeneralTab::newallfont()
|
||||
{
|
||||
QSettings settings;
|
||||
QFont all, text;
|
||||
all.fromString(settings.value("allfont", "").toString());
|
||||
text.fromString(settings.value("textfont", "").toString());
|
||||
all.fromString(settings.value("allfont", QFont("Arial", -1).toString()).toString());
|
||||
text.fromString(settings.value("textfont", QFont("Monospace", -1).toString()).toString());
|
||||
|
||||
bool ok = false;
|
||||
QFont font = QFontDialog::getFont(&ok, all, this, QString("Select Default Font"));
|
||||
@ -312,8 +331,8 @@ void GeneralTab::newtextfont()
|
||||
{
|
||||
QSettings settings;
|
||||
QFont all, text;
|
||||
all.fromString(settings.value("allfont", "").toString());
|
||||
text.fromString(settings.value("textfont", "").toString());
|
||||
all.fromString(settings.value("allfont", QFont("Arial", -1).toString()).toString());
|
||||
text.fromString(settings.value("textfont", QFont("Monospace", -1).toString()).toString());
|
||||
|
||||
bool ok = false;
|
||||
QFont font = QFontDialog::getFont(&ok, text, this, QString("Select Text Font"));
|
||||
@ -411,13 +430,13 @@ AcceleratorTab::AcceleratorTab(QSettings *_settings, LammpsWrapper *_lammps, QWi
|
||||
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());
|
||||
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");
|
||||
auto *ntlabel = new QLabel(QString("Number of threads (OpenMP not available):"));
|
||||
auto *ntchoice = new QLineEdit("1");
|
||||
#endif
|
||||
auto *intval = new QIntValidator(1, maxthreads, this);
|
||||
auto *intval = new QIntValidator(1, maxthreads, this);
|
||||
ntchoice->setValidator(intval);
|
||||
ntchoice->setObjectName("nthreads");
|
||||
#if !defined(_OPENMP)
|
||||
@ -443,17 +462,19 @@ SnapshotTab::SnapshotTab(QSettings *_settings, QWidget *parent) :
|
||||
auto *zoom = new QLabel("Zoom factor:");
|
||||
auto *anti = new QLabel("Antialias:");
|
||||
auto *ssao = new QLabel("HQ Image mode:");
|
||||
auto *shiny = new QLabel("Shiny Image mode:");
|
||||
auto *bbox = new QLabel("Show Box:");
|
||||
auto *axes = new QLabel("Show Axes:");
|
||||
auto *vdw = new QLabel("VDW Style:");
|
||||
auto *cback = new QLabel("Background Color:");
|
||||
auto *cbox = new QLabel("Box Color:");
|
||||
settings->beginGroup("snapshot");
|
||||
auto *xval = new QLineEdit(settings->value("xsize", "800").toString());
|
||||
auto *xval = new QLineEdit(settings->value("xsize", "600").toString());
|
||||
auto *yval = new QLineEdit(settings->value("ysize", "600").toString());
|
||||
auto *zval = new QLineEdit(settings->value("zoom", "1.0").toString());
|
||||
auto *aval = new QCheckBox;
|
||||
auto *sval = new QCheckBox;
|
||||
auto *hval = new QCheckBox;
|
||||
auto *bval = new QCheckBox;
|
||||
auto *eval = new QCheckBox;
|
||||
auto *vval = new QCheckBox;
|
||||
@ -461,6 +482,8 @@ SnapshotTab::SnapshotTab(QSettings *_settings, QWidget *parent) :
|
||||
sval->setObjectName("ssao");
|
||||
aval->setCheckState(settings->value("antialias", false).toBool() ? Qt::Checked : Qt::Unchecked);
|
||||
aval->setObjectName("anti");
|
||||
hval->setCheckState(settings->value("shinystyle", true).toBool() ? Qt::Checked : Qt::Unchecked);
|
||||
hval->setObjectName("shiny");
|
||||
bval->setCheckState(settings->value("box", true).toBool() ? Qt::Checked : Qt::Unchecked);
|
||||
bval->setObjectName("box");
|
||||
eval->setCheckState(settings->value("axes", false).toBool() ? Qt::Checked : Qt::Unchecked);
|
||||
@ -507,6 +530,8 @@ SnapshotTab::SnapshotTab(QSettings *_settings, QWidget *parent) :
|
||||
grid->addWidget(aval, i++, 1, Qt::AlignTop);
|
||||
grid->addWidget(ssao, i, 0, Qt::AlignTop);
|
||||
grid->addWidget(sval, i++, 1, Qt::AlignVCenter);
|
||||
grid->addWidget(shiny, i, 0, Qt::AlignTop);
|
||||
grid->addWidget(hval, i++, 1, Qt::AlignVCenter);
|
||||
grid->addWidget(bbox, i, 0, Qt::AlignTop);
|
||||
grid->addWidget(bval, i++, 1, Qt::AlignVCenter);
|
||||
grid->addWidget(axes, i, 0, Qt::AlignTop);
|
||||
@ -535,29 +560,34 @@ EditorTab::EditorTab(QSettings *_settings, QWidget *parent) : QWidget(parent), s
|
||||
auto *namelbl = new QLabel("Name width:");
|
||||
auto *retlbl = new QLabel("Reformat with 'Enter':");
|
||||
auto *autolbl = new QLabel("Automatic completion:");
|
||||
auto *savlbl = new QLabel("Auto-save on 'Run' and 'Quit':");
|
||||
auto *cmdval = new QSpinBox;
|
||||
auto *typeval = new QSpinBox;
|
||||
auto *idval = new QSpinBox;
|
||||
auto *nameval = new QSpinBox;
|
||||
auto *retval = new QCheckBox;
|
||||
auto *autoval = new QCheckBox;
|
||||
auto *savval = new QCheckBox;
|
||||
cmdval->setObjectName("cmdval");
|
||||
cmdval->setRange(1, 32);
|
||||
cmdval->setValue(settings->value("command", "16").toInt());
|
||||
cmdval->setObjectName("cmdval");
|
||||
typeval->setObjectName("typeval");
|
||||
typeval->setRange(1, 32);
|
||||
typeval->setValue(settings->value("type", "4").toInt());
|
||||
typeval->setObjectName("typeval");
|
||||
idval->setObjectName("idval");
|
||||
idval->setRange(1, 32);
|
||||
idval->setValue(settings->value("id", "8").toInt());
|
||||
idval->setObjectName("idval");
|
||||
nameval->setObjectName("nameval");
|
||||
nameval->setRange(1, 32);
|
||||
nameval->setValue(settings->value("name", "8").toInt());
|
||||
nameval->setObjectName("nameval");
|
||||
retval->setCheckState(settings->value("return", true).toBool() ? Qt::Checked : Qt::Unchecked);
|
||||
retval->setObjectName("retval");
|
||||
retval->setCheckState(settings->value("return", false).toBool() ? Qt::Checked : Qt::Unchecked);
|
||||
autoval->setObjectName("autoval");
|
||||
autoval->setCheckState(settings->value("automatic", true).toBool() ? Qt::Checked
|
||||
: Qt::Unchecked);
|
||||
autoval->setObjectName("autoval");
|
||||
savval->setObjectName("savval");
|
||||
savval->setCheckState(settings->value("autosave", false).toBool() ? Qt::Checked
|
||||
: Qt::Unchecked);
|
||||
settings->endGroup();
|
||||
|
||||
int i = 0;
|
||||
@ -574,6 +604,8 @@ EditorTab::EditorTab(QSettings *_settings, QWidget *parent) : QWidget(parent), s
|
||||
grid->addWidget(retval, i++, 1, Qt::AlignVCenter);
|
||||
grid->addWidget(autolbl, i, 0, Qt::AlignTop);
|
||||
grid->addWidget(autoval, i++, 1, Qt::AlignVCenter);
|
||||
grid->addWidget(savlbl, i, 0, Qt::AlignTop);
|
||||
grid->addWidget(savval, i++, 1, Qt::AlignVCenter);
|
||||
|
||||
grid->addItem(new QSpacerItem(100, 100, QSizePolicy::Minimum, QSizePolicy::Expanding), i, 0);
|
||||
grid->addItem(new QSpacerItem(100, 100, QSizePolicy::Minimum, QSizePolicy::Expanding), i, 1);
|
||||
|
||||
@ -14,12 +14,12 @@
|
||||
#include "setvariables.h"
|
||||
|
||||
#include <QDialogButtonBox>
|
||||
#include <QGridLayout>
|
||||
#include <QIcon>
|
||||
#include <QLabel>
|
||||
#include <QLineEdit>
|
||||
#include <QPushButton>
|
||||
#include <QSizePolicy>
|
||||
#include <QVBoxLayout>
|
||||
|
||||
SetVariables::SetVariables(QList<QPair<QString, QString>> &_vars, QWidget *parent) :
|
||||
QDialog(parent), vars(_vars), layout(new QVBoxLayout)
|
||||
|
||||
@ -19,6 +19,7 @@
|
||||
#include <QApplication>
|
||||
#include <QDialogButtonBox>
|
||||
#include <QDir>
|
||||
#include <QFile>
|
||||
#include <QFileDialog>
|
||||
#include <QFileInfo>
|
||||
#include <QGuiApplication>
|
||||
@ -31,7 +32,6 @@
|
||||
#include <QProcess>
|
||||
#include <QPushButton>
|
||||
#include <QScreen>
|
||||
#include <QSettings>
|
||||
#include <QShortcut>
|
||||
#include <QSpacerItem>
|
||||
#include <QTemporaryFile>
|
||||
@ -75,6 +75,9 @@ SlideShow::SlideShow(const QString &fileName, QWidget *parent) :
|
||||
tomovie->setToolTip("Export to movie file");
|
||||
tomovie->setEnabled(has_exe("ffmpeg"));
|
||||
|
||||
auto *totrash = new QPushButton(QIcon(":/icons/trash.png"), "");
|
||||
totrash->setToolTip("Delete all image files");
|
||||
|
||||
auto *gofirst = new QPushButton(QIcon(":/icons/go-first.png"), "");
|
||||
gofirst->setToolTip("Go to first Image");
|
||||
auto *goprev = new QPushButton(QIcon(":/icons/go-previous-2.png"), "");
|
||||
@ -101,6 +104,7 @@ SlideShow::SlideShow(const QString &fileName, QWidget *parent) :
|
||||
normal->setToolTip("Reset zoom to normal");
|
||||
|
||||
connect(tomovie, &QPushButton::released, this, &SlideShow::movie);
|
||||
connect(totrash, &QPushButton::released, this, &SlideShow::delete_images);
|
||||
connect(gofirst, &QPushButton::released, this, &SlideShow::first);
|
||||
connect(goprev, &QPushButton::released, this, &SlideShow::prev);
|
||||
connect(goplay, &QPushButton::released, this, &SlideShow::play);
|
||||
@ -115,6 +119,7 @@ SlideShow::SlideShow(const QString &fileName, QWidget *parent) :
|
||||
navLayout->addSpacerItem(new QSpacerItem(10, 10, QSizePolicy::Expanding, QSizePolicy::Minimum));
|
||||
navLayout->addWidget(dummy);
|
||||
navLayout->addWidget(tomovie);
|
||||
navLayout->addWidget(totrash);
|
||||
navLayout->addWidget(gofirst);
|
||||
navLayout->addWidget(goprev);
|
||||
navLayout->addWidget(goplay);
|
||||
@ -157,6 +162,14 @@ void SlideShow::add_image(const QString &filename)
|
||||
}
|
||||
}
|
||||
|
||||
void SlideShow::delete_images()
|
||||
{
|
||||
for (const auto &file : imagefiles) {
|
||||
QFile::remove(file);
|
||||
}
|
||||
clear();
|
||||
}
|
||||
|
||||
void SlideShow::clear()
|
||||
{
|
||||
imagefiles.clear();
|
||||
@ -316,7 +329,7 @@ void SlideShow::prev()
|
||||
void SlideShow::loop()
|
||||
{
|
||||
auto *button = qobject_cast<QPushButton *>(sender());
|
||||
do_loop = !do_loop;
|
||||
do_loop = !do_loop;
|
||||
button->setChecked(do_loop);
|
||||
}
|
||||
|
||||
|
||||
@ -33,6 +33,7 @@ public:
|
||||
|
||||
private slots:
|
||||
void quit();
|
||||
void delete_images();
|
||||
void stop_run();
|
||||
void movie();
|
||||
void first();
|
||||
|
||||
@ -94,7 +94,8 @@ bool StdCapture::EndCapture()
|
||||
buf[bytesRead] = 0;
|
||||
m_captured += buf;
|
||||
} else if (bytesRead < 0) {
|
||||
fd_blocked = ((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR)) && (maxwait > 0);
|
||||
fd_blocked =
|
||||
((errno == EAGAIN) || (errno == EWOULDBLOCK) || (errno == EINTR)) && (maxwait > 0);
|
||||
|
||||
if (fd_blocked) std::this_thread::sleep_for(std::chrono::milliseconds(10));
|
||||
--maxwait;
|
||||
|
||||
@ -1 +0,0 @@
|
||||
../../unittest/.clang-format
|
||||
1
tools/lammps-shell/.gitignore
vendored
@ -1 +0,0 @@
|
||||
/lammps-shell
|
||||
@ -1,17 +0,0 @@
|
||||
SHELL=/bin/sh
|
||||
|
||||
CXX=g++ -std=c++11
|
||||
#CXX=g++
|
||||
CXXFLAGS=-O -g -Wall -I../../src $(shell pkg-config --cflags readline)
|
||||
#CXXFLAGS=-O -g -Wall -I../../src
|
||||
LDFLAGS= -L../../src -Wl,-rpath,../../src -llammps $(shell pkg-config --libs readline)
|
||||
#LDFLAGS= -L../../src -llammps -lreadline
|
||||
|
||||
lammps-shell: lammps-shell.o
|
||||
$(CXX) -o $@ $^ $(LDFLAGS)
|
||||
|
||||
lammps-shell.o: lammps-shell.cpp
|
||||
$(CXX) -c $(CXXFLAGS) -o $@ $<
|
||||
|
||||
clean:
|
||||
@rm -f lammps-shell lammps-shell.o core *~ .lammps-history log.lammps log.cite
|
||||
@ -1,175 +0,0 @@
|
||||
The LAMMPS Shell. An enhanced LAMMPS executable for interactive sessions.
|
||||
|
||||
Overview
|
||||
^^^^^^^^
|
||||
|
||||
This is a program that functions very similar to the regular LAMMPS
|
||||
executable but has several modifications and additions that make it
|
||||
more powerful for interactive sessions, i.e. where you type LAMMPS
|
||||
commands from the prompt instead of reading them from a file.
|
||||
|
||||
- It uses the readline and history libraries to provide command line
|
||||
editing and context aware TAB-expansion (details on that below).
|
||||
|
||||
- When processing an input file with the '-in' or '-i' flag from the
|
||||
command line, it does not exit at the end of that input file but
|
||||
stops at a prompt, so that additional commands can be issued
|
||||
|
||||
- Errors will not abort the shell but return to the prompt.
|
||||
|
||||
- It has additional commands aimed at interactive use (details below).
|
||||
|
||||
- Interrupting a calculation with CTRL-C will not terminate the
|
||||
session but rather enforce a timeout to cleanly stop an ongoing
|
||||
run (more info on timeouts is in the timer command documentation).
|
||||
|
||||
These enhancements makes the LAMMPS shell an attractive choice for
|
||||
interactive LAMMPS sessions in graphical user interfaces.
|
||||
|
||||
TAB-expansion
|
||||
^^^^^^^^^^^^^
|
||||
|
||||
When writing commands interactively at the shell prompt, you can hit
|
||||
the TAB key at any time to try and complete the text. This completion
|
||||
is context aware and will expand any first word only to commands
|
||||
available in that executable.
|
||||
|
||||
- For style commands it will expand to available styles of the
|
||||
corresponding category (e.g. pair styles after a pair_style command).
|
||||
|
||||
- For "compute", "fix", or "dump" it will also expand only to already
|
||||
defined groups for the group-ID keyword.
|
||||
|
||||
- For commands like "compute_modify", "fix_modify", or "dump_modify"
|
||||
it will expand to known compute/fix/dump IDs only.
|
||||
|
||||
- When typing references to computes, fixes, or variables with a
|
||||
"c_", "f_", or "v_" prefix, respectively, then the expansion will
|
||||
to known compute/fix IDs and variable names. Variable name expansion
|
||||
is also available for the ${name} variable syntax.
|
||||
|
||||
- In all other cases TAB expansion will complete to names of files
|
||||
and directories.
|
||||
|
||||
Command line editing and history
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
When typing commands, command line editing similar to what BASH
|
||||
provides is available. Thus it is possible to move around the
|
||||
currently line and perform various cut and insert and edit operations.
|
||||
Previous commands can be retrieved by scrolling up (and down)
|
||||
or searching (e.g. with CTRL-r).
|
||||
|
||||
Also history expansion through using the exclamation mark '!'
|
||||
can be performed. Examples: '!!' will be replaced with the previous
|
||||
command, '!-2' will repeat the command before that, '!30' will be
|
||||
replaced with event number 30 in the command history list, and
|
||||
'!run' with the last command line that started with "run". Adding
|
||||
a ":p" to such a history expansion will result that the expansion is
|
||||
printed and added to the history list, but NOT executed.
|
||||
On exit the LAMMPS shell will write the history list to a file
|
||||
".lammps_history" in the current working directory. If such a
|
||||
file exists when the LAMMPS shell is launched it will be read to
|
||||
populate the history list.
|
||||
|
||||
This is realized via the readline library and can thus be customized
|
||||
with an ".inputrc" file in the home directory. For application specific
|
||||
customization, the LAMMPS shell uses the name "lammps-shell".
|
||||
For more information about using and customizing an application using
|
||||
readline, please see the available documentation at:
|
||||
http://www.gnu.org/s/readline/#Documentation
|
||||
|
||||
Additional commands
|
||||
^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The followind commands are added to the LAMMPS shell on top of the
|
||||
regular LAMMPS commands:
|
||||
|
||||
- help (or ?) print a brief help message
|
||||
- history display the current command history list
|
||||
- clear_history wipe out the current command history list
|
||||
- save_history <range> <file>
|
||||
write commands from the history to file.
|
||||
The range is given as <from>-<to>, where <from> and <to>
|
||||
may be empty. Example: save_history 100- in.recent
|
||||
- source <file> read commands from file (same as "include")
|
||||
- pwd print current working directory
|
||||
- cd <directory> change current working directory (same as pwd if no directory)
|
||||
- mem print current and maximum memory usage
|
||||
- |<command> execute <command> as a shell command and return to the command prompt
|
||||
- exit exit the LAMMPS shell cleanly (unlike the "quit" command)
|
||||
|
||||
Please note that some known shell operations are implemented in the
|
||||
LAMMPS "shell" command in a platform neutral fashion, while using
|
||||
the '\|' character will always pass the following text to the
|
||||
operating system's shell command.
|
||||
|
||||
Compilation
|
||||
^^^^^^^^^^^
|
||||
|
||||
Compilation of the LAMMPS shell can be enabled by setting the CMake
|
||||
variable BUILD_LAMMPS_SHELL to "on" or using the makefile in the
|
||||
tools/lammps-shell folder to compile after building LAMMPS using
|
||||
the conventional make procedure. The makefile will likely need
|
||||
customization depending on the features and settings used for
|
||||
compiling LAMMPS.
|
||||
|
||||
Limitations
|
||||
^^^^^^^^^^^
|
||||
|
||||
The LAMMPS shell was not designed for use with MPI parallelization
|
||||
via "mpirun" or "mpiexec" or "srun".
|
||||
|
||||
Readline customization
|
||||
^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
The behavior of the readline functionality can be customized in the
|
||||
"${HOME}/.inputrc" file. This can be used to alter the default
|
||||
settings or change the key-bindings. The LAMMPS Shell sets the
|
||||
application name "lammps-shell", so customizations can be either
|
||||
global or specific for the LAMMPS shell by bracketing them between
|
||||
"$if lammps-shell" and "$endif" like in the following example:
|
||||
|
||||
$if lammps-shell
|
||||
# disable "beep" or "screen flash"
|
||||
set bell-style none
|
||||
# bind the "Insert" key to toggle overwrite mode
|
||||
"\e[2~": overwrite-mode
|
||||
$endif
|
||||
|
||||
More details about this are in the readline documentation https://tiswww.cwru.edu/php/chet/readline/rluserman.html#SEC9
|
||||
|
||||
|
||||
LAMMPS Shell tips and tricks
|
||||
^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
||||
|
||||
Enable tilde expansion
|
||||
""""""""""""""""""""""
|
||||
|
||||
Adding "set expand-tilde on" to "${HOME}/.inputrc" is recommended as
|
||||
this will change the filename expansion behavior to replace any text
|
||||
starting with "~" by the full path to the corresponding user's home
|
||||
directory. While the expansion of filenames **will** happen on all
|
||||
arguments where the context is not known (e.g. "~/compile/lamm<TAB>"
|
||||
will expand to "~/compile/lammps/"), it will not replace the tilde by
|
||||
default. But since LAMMPS does not do tilde expansion itself (unlike a
|
||||
shell), this will result in errors. Instead the tilde-expression should
|
||||
be expanded into a valid path, where the plain "~/" stands for the
|
||||
current user's home directory and "~someuser/" stands for
|
||||
"/home/someuser" or whatever the full path to that user's home directory
|
||||
is.
|
||||
|
||||
File extension association
|
||||
""""""""""""""""""""""""""
|
||||
|
||||
The LAMMPS shell (unlike the regular LAMMPS executable) does not
|
||||
exit when an input file is passed on the command line, which can be
|
||||
either with the "-in" or "-i" flag (the behavior is like for
|
||||
"python -i <filename>") or as the first argument without a flag.
|
||||
Thus the LAMMPS shell is suitable for associating it with input files
|
||||
based on their filename extension (e.g. ".lmp"). Since "lammps-shell"
|
||||
is a console application, you have to run it inside a terminal program.
|
||||
|
||||
A "lammps-shell.desktop" and suitable icon files are provided, so that
|
||||
it can be integrated into compatible desktop environments.
|
||||
|
||||
|
Before Width: | Height: | Size: 39 KiB |
|
Before Width: | Height: | Size: 15 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 16 KiB |
|
Before Width: | Height: | Size: 19 KiB |
|
Before Width: | Height: | Size: 22 KiB |
|
Before Width: | Height: | Size: 204 KiB |
|
Before Width: | Height: | Size: 186 KiB |
@ -1,811 +0,0 @@
|
||||
// LAMMPS Shell. An improved interactive LAMMPS session with
|
||||
// command line editing, history, TAB expansion and shell escapes
|
||||
|
||||
// Copyright (c) 2020, 2021 Axel Kohlmeyer <akohlmey@gmail.com>
|
||||
|
||||
// This software is distributed under the GNU General Public License.
|
||||
|
||||
#include "library.h"
|
||||
#include "platform.h"
|
||||
#include "utils.h"
|
||||
|
||||
#include <cstring>
|
||||
#include <fstream>
|
||||
#include <iostream>
|
||||
#include <string>
|
||||
#include <vector>
|
||||
|
||||
#if defined(_WIN32)
|
||||
#if !defined(WIN32_LEAN_AND_MEAN)
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#endif
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <csignal>
|
||||
#endif
|
||||
|
||||
#if defined(_OPENMP)
|
||||
#include <omp.h>
|
||||
#endif
|
||||
|
||||
#include <readline/history.h>
|
||||
#include <readline/readline.h>
|
||||
|
||||
using namespace LAMMPS_NS;
|
||||
|
||||
void *lmp = nullptr;
|
||||
char *omp_threads = nullptr;
|
||||
constexpr int BUFLEN = 512;
|
||||
char buf[BUFLEN];
|
||||
|
||||
enum {
|
||||
ATOM_STYLE,
|
||||
INTEGRATE_STYLE,
|
||||
MINIMIZE_STYLE,
|
||||
PAIR_STYLE,
|
||||
BOND_STYLE,
|
||||
ANGLE_STYLE,
|
||||
DIHEDRAL_STYLE,
|
||||
IMPROPER_STYLE,
|
||||
KSPACE_STYLE,
|
||||
FIX_STYLE,
|
||||
COMPUTE_STYLE,
|
||||
REGION_STYLE,
|
||||
DUMP_STYLE
|
||||
};
|
||||
const char *lmp_style[] = {"atom", "integrate", "minimize", "pair", "bond",
|
||||
"angle", "dihedral", "improper", "kspace", "fix",
|
||||
"compute", "region", "dump"};
|
||||
|
||||
enum { COMPUTE_ID, DUMP_ID, FIX_ID, MOLECULE_ID, REGION_ID, VARIABLE_ID };
|
||||
const char *lmp_id[] = {"compute", "dump", "fix", "molecule", "region", "variable"};
|
||||
|
||||
std::vector<std::string> commands;
|
||||
|
||||
// this list of commands is generated by:
|
||||
// grep 'mycmd ==' src/input.cpp | sed -e 's/^.*mycmd == \(".*"\).*$/\1,/
|
||||
|
||||
const char *cmdlist[] = {"clear",
|
||||
"echo",
|
||||
"if",
|
||||
"include",
|
||||
"jump",
|
||||
"label",
|
||||
"log",
|
||||
"next",
|
||||
"partition",
|
||||
"print",
|
||||
"python",
|
||||
"quit",
|
||||
"shell",
|
||||
"variable",
|
||||
"angle_coeff",
|
||||
"angle_style",
|
||||
"atom_modify",
|
||||
"atom_style",
|
||||
"bond_coeff",
|
||||
"bond_style",
|
||||
"bond_write",
|
||||
"boundary",
|
||||
"comm_modify",
|
||||
"comm_style",
|
||||
"compute",
|
||||
"compute_modify",
|
||||
"dielectric",
|
||||
"dihedral_coeff",
|
||||
"dihedral_style",
|
||||
"dimension",
|
||||
"dump",
|
||||
"dump_modify",
|
||||
"fix",
|
||||
"fix_modify",
|
||||
"group",
|
||||
"improper_coeff",
|
||||
"improper_style",
|
||||
"kspace_modify",
|
||||
"kspace_style",
|
||||
"labelmap",
|
||||
"lattice",
|
||||
"mass",
|
||||
"min_modify",
|
||||
"min_style",
|
||||
"molecule",
|
||||
"neigh_modify",
|
||||
"neighbor",
|
||||
"newton",
|
||||
"package",
|
||||
"pair_coeff",
|
||||
"pair_modify",
|
||||
"pair_style",
|
||||
"pair_write",
|
||||
"processors",
|
||||
"region",
|
||||
"reset_timestep",
|
||||
"restart",
|
||||
"run_style",
|
||||
"special_bonds",
|
||||
"suffix",
|
||||
"thermo",
|
||||
"thermo_modify",
|
||||
"thermo_style",
|
||||
"timestep",
|
||||
"timer",
|
||||
"uncompute",
|
||||
"undump",
|
||||
"unfix",
|
||||
"units",
|
||||
"reset_atoms"};
|
||||
|
||||
static char *dupstring(const std::string &text)
|
||||
{
|
||||
int len = text.size() + 1;
|
||||
char *copy = (char *)malloc(len);
|
||||
strcpy(copy, text.c_str());
|
||||
return copy;
|
||||
}
|
||||
|
||||
static int save_history(const std::string &range, const std::string &file)
|
||||
{
|
||||
int from = history_base;
|
||||
int to = from + history_length - 1;
|
||||
|
||||
if (!range.empty()) {
|
||||
std::size_t found = range.find_first_of("-");
|
||||
|
||||
if (found == std::string::npos) { // only a single number
|
||||
int num = strtol(range.c_str(), nullptr, 10);
|
||||
if ((num >= from) && (num <= to)) {
|
||||
from = to = num;
|
||||
} else
|
||||
return 1;
|
||||
} else { // range of numbers
|
||||
if (found > 0) { // get number before '-'
|
||||
int num = strtol(range.substr(0, found).c_str(), nullptr, 10);
|
||||
if ((num >= from) && (num <= to)) {
|
||||
from = num;
|
||||
} else
|
||||
return 1;
|
||||
}
|
||||
|
||||
if (range.size() > found + 1) { // get number after '-'
|
||||
int num = strtol(range.substr(found + 1).c_str(), nullptr, 10);
|
||||
if ((num >= from) && (num <= to)) {
|
||||
to = num;
|
||||
} else
|
||||
return 1;
|
||||
}
|
||||
}
|
||||
std::ofstream out(file, std::ios::out | std::ios::trunc);
|
||||
if (out.fail()) {
|
||||
std::cerr << "'" << utils::getsyserror() << "' error when "
|
||||
<< "trying to open file '" << file << "' for writing.\n";
|
||||
return 0;
|
||||
}
|
||||
out << "# saved LAMMPS Shell history\n";
|
||||
for (int i = from; i <= to; ++i) {
|
||||
HIST_ENTRY *item = history_get(i);
|
||||
if (item == nullptr) {
|
||||
out.close();
|
||||
return 1;
|
||||
}
|
||||
out << item->line << "\n";
|
||||
}
|
||||
out.close();
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
template <int STYLE> char *style_generator(const char *text, int state)
|
||||
{
|
||||
static int idx, num, len;
|
||||
if (!state) {
|
||||
idx = 0;
|
||||
num = lammps_style_count(lmp, lmp_style[STYLE]);
|
||||
len = strlen(text);
|
||||
}
|
||||
|
||||
while (idx < num) {
|
||||
lammps_style_name(lmp, lmp_style[STYLE], idx, buf, BUFLEN);
|
||||
++idx;
|
||||
if ((len == 0) || (strncmp(text, buf, len) == 0)) return dupstring(buf);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <int ID> char *id_generator(const char *text, int state)
|
||||
{
|
||||
static int idx, num, len;
|
||||
if (!state) {
|
||||
idx = 0;
|
||||
num = lammps_id_count(lmp, lmp_id[ID]);
|
||||
len = strlen(text);
|
||||
}
|
||||
|
||||
while (idx < num) {
|
||||
lammps_id_name(lmp, lmp_id[ID], idx, buf, BUFLEN);
|
||||
++idx;
|
||||
if ((len == 0) || (strncmp(text, buf, len) == 0)) return dupstring(buf);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
template <int ID, char PREFIX> char *ref_generator(const char *text, int state)
|
||||
{
|
||||
char prefix[] = "X_";
|
||||
prefix[0] = PREFIX;
|
||||
|
||||
if (strncmp(text, prefix, 2) == 0) {
|
||||
char *id = id_generator<ID>(text + 2, state);
|
||||
char *ref = nullptr;
|
||||
if (id) {
|
||||
ref = (char *)malloc(strlen(id) + 3);
|
||||
if (ref) {
|
||||
ref[0] = PREFIX;
|
||||
ref[1] = '_';
|
||||
ref[2] = 0;
|
||||
strcat(ref, id);
|
||||
}
|
||||
free(id);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
extern "C" {
|
||||
|
||||
#if !defined(_WIN32)
|
||||
static void ctrl_c_handler(int)
|
||||
#else
|
||||
static BOOL WINAPI ctrl_c_handler(DWORD event)
|
||||
#endif
|
||||
{
|
||||
#if defined(_WIN32)
|
||||
if (event == CTRL_C_EVENT) {
|
||||
#endif
|
||||
if (lmp)
|
||||
if (lammps_is_running(lmp)) lammps_force_timeout(lmp);
|
||||
#if defined(_WIN32)
|
||||
return TRUE;
|
||||
}
|
||||
return FALSE;
|
||||
#endif
|
||||
}
|
||||
|
||||
static char *cmd_generator(const char *text, int state)
|
||||
{
|
||||
static std::size_t idx, len;
|
||||
if (!state) idx = 0;
|
||||
len = strlen(text);
|
||||
|
||||
do {
|
||||
if ((idx < commands.size()) && ((len == 0) || (commands[idx].substr(0, len) == text)))
|
||||
return dupstring(commands[idx++]);
|
||||
else
|
||||
++idx;
|
||||
} while (idx < commands.size());
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static char *compute_id_generator(const char *text, int state)
|
||||
{
|
||||
return id_generator<COMPUTE_ID>(text, state);
|
||||
}
|
||||
|
||||
static char *compute_ref_generator(const char *text, int state)
|
||||
{
|
||||
return ref_generator<COMPUTE_ID, 'c'>(text, state);
|
||||
}
|
||||
|
||||
static char *dump_id_generator(const char *text, int state)
|
||||
{
|
||||
return id_generator<DUMP_ID>(text, state);
|
||||
}
|
||||
|
||||
static char *fix_id_generator(const char *text, int state)
|
||||
{
|
||||
return id_generator<FIX_ID>(text, state);
|
||||
}
|
||||
|
||||
static char *fix_ref_generator(const char *text, int state)
|
||||
{
|
||||
return ref_generator<FIX_ID, 'f'>(text, state);
|
||||
}
|
||||
|
||||
static char *variable_ref_generator(const char *text, int state)
|
||||
{
|
||||
return ref_generator<VARIABLE_ID, 'v'>(text, state);
|
||||
}
|
||||
|
||||
static char *variable_expand_generator(const char *text, int state)
|
||||
{
|
||||
if (strncmp(text, "${", 2) == 0) {
|
||||
char *id = id_generator<VARIABLE_ID>(text + 2, state);
|
||||
char *ref = nullptr;
|
||||
if (id) {
|
||||
ref = (char *)malloc(strlen(id) + 4);
|
||||
if (ref) {
|
||||
ref[0] = '$';
|
||||
ref[1] = '{';
|
||||
ref[2] = 0;
|
||||
strcat(ref, id);
|
||||
strcat(ref, "}");
|
||||
}
|
||||
free(id);
|
||||
}
|
||||
return ref;
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static char *plugin_generator(const char *text, int state)
|
||||
{
|
||||
const char *subcmd[] = {"load", "unload", "list", "clear", nullptr};
|
||||
const char *sub;
|
||||
static std::size_t idx = 0, len;
|
||||
if (!state) idx = 0;
|
||||
len = strlen(text);
|
||||
|
||||
while ((sub = subcmd[idx]) != nullptr) {
|
||||
++idx;
|
||||
if (strncmp(text, sub, len) == 0) return dupstring(sub);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static char *plugin_style_generator(const char *text, int state)
|
||||
{
|
||||
const char *styles[] = {"pair",
|
||||
"bond",
|
||||
"angle",
|
||||
"dihedral"
|
||||
"improper",
|
||||
"kspace",
|
||||
"compute",
|
||||
"fix",
|
||||
"region",
|
||||
"command",
|
||||
nullptr};
|
||||
const char *s;
|
||||
static std::size_t idx = 0, len;
|
||||
if (!state) idx = 0;
|
||||
len = strlen(text);
|
||||
while ((s = styles[idx]) != nullptr) {
|
||||
++idx;
|
||||
if (strncmp(text, s, len) == 0) return dupstring(s);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static char *plugin_name_generator(const char *text, int state)
|
||||
{
|
||||
auto words = utils::split_words(text);
|
||||
if (words.size() < 4) return nullptr;
|
||||
|
||||
static std::size_t idx, len, nmax;
|
||||
if (!state) idx = 0;
|
||||
len = words[3].size();
|
||||
nmax = lammps_plugin_count();
|
||||
|
||||
while (idx < nmax) {
|
||||
char style[BUFLEN], name[BUFLEN];
|
||||
lammps_plugin_name(idx, style, name, BUFLEN);
|
||||
++idx;
|
||||
if (words[2] == style) {
|
||||
if (strncmp(name, words[3].c_str(), len) == 0) return dupstring(name);
|
||||
}
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static char *atom_generator(const char *text, int state)
|
||||
{
|
||||
return style_generator<ATOM_STYLE>(text, state);
|
||||
}
|
||||
|
||||
static char *integrate_generator(const char *text, int state)
|
||||
{
|
||||
return style_generator<INTEGRATE_STYLE>(text, state);
|
||||
}
|
||||
|
||||
static char *minimize_generator(const char *text, int state)
|
||||
{
|
||||
return style_generator<MINIMIZE_STYLE>(text, state);
|
||||
}
|
||||
|
||||
static char *pair_generator(const char *text, int state)
|
||||
{
|
||||
return style_generator<PAIR_STYLE>(text, state);
|
||||
}
|
||||
|
||||
static char *bond_generator(const char *text, int state)
|
||||
{
|
||||
return style_generator<BOND_STYLE>(text, state);
|
||||
}
|
||||
|
||||
static char *angle_generator(const char *text, int state)
|
||||
{
|
||||
return style_generator<ANGLE_STYLE>(text, state);
|
||||
}
|
||||
|
||||
static char *dihedral_generator(const char *text, int state)
|
||||
{
|
||||
return style_generator<DIHEDRAL_STYLE>(text, state);
|
||||
}
|
||||
|
||||
static char *improper_generator(const char *text, int state)
|
||||
{
|
||||
return style_generator<IMPROPER_STYLE>(text, state);
|
||||
}
|
||||
|
||||
static char *kspace_generator(const char *text, int state)
|
||||
{
|
||||
return style_generator<KSPACE_STYLE>(text, state);
|
||||
}
|
||||
|
||||
static char *fix_generator(const char *text, int state)
|
||||
{
|
||||
return style_generator<FIX_STYLE>(text, state);
|
||||
}
|
||||
|
||||
static char *compute_generator(const char *text, int state)
|
||||
{
|
||||
return style_generator<COMPUTE_STYLE>(text, state);
|
||||
}
|
||||
|
||||
static char *region_generator(const char *text, int state)
|
||||
{
|
||||
return style_generator<REGION_STYLE>(text, state);
|
||||
}
|
||||
|
||||
static char *dump_generator(const char *text, int state)
|
||||
{
|
||||
return style_generator<DUMP_STYLE>(text, state);
|
||||
}
|
||||
|
||||
char *group_generator(const char *text, int state)
|
||||
{
|
||||
static int idx, num, len;
|
||||
if (!state) {
|
||||
idx = 0;
|
||||
num = lammps_id_count(lmp, "group");
|
||||
len = strlen(text);
|
||||
}
|
||||
|
||||
while (idx < num) {
|
||||
lammps_id_name(lmp, "group", idx, buf, BUFLEN);
|
||||
++idx;
|
||||
if ((len == 0) || (strncmp(text, buf, len) == 0)) return dupstring(buf);
|
||||
}
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
static char **cmd_completion(const char *text, int start, int)
|
||||
{
|
||||
char **matches = nullptr;
|
||||
|
||||
// avoid segfaults
|
||||
if (strlen(text) == 0) return matches;
|
||||
|
||||
if (start == 0) {
|
||||
// match command names from the beginning of a line
|
||||
matches = rl_completion_matches(text, cmd_generator);
|
||||
} else {
|
||||
// try to provide context specific matches
|
||||
// first split the already completed text into words for position specific expansion
|
||||
auto words = utils::split_words(std::string(rl_line_buffer).substr(0, start));
|
||||
|
||||
if (strncmp(text, "c_", 2) == 0) { // expand references to computes or fixes
|
||||
matches = rl_completion_matches(text, compute_ref_generator);
|
||||
} else if (strncmp(text, "f_", 2) == 0) {
|
||||
matches = rl_completion_matches(text, fix_ref_generator);
|
||||
} else if (strncmp(text, "v_", 2) == 0) {
|
||||
matches = rl_completion_matches(text, variable_ref_generator);
|
||||
} else if (strncmp(text, "${", 2) == 0) {
|
||||
matches = rl_completion_matches(text, variable_expand_generator);
|
||||
} else if (words.size() == 1) { // expand second word
|
||||
if (words[0] == "atom_style") {
|
||||
matches = rl_completion_matches(text, atom_generator);
|
||||
} else if (words[0] == "pair_style") {
|
||||
matches = rl_completion_matches(text, pair_generator);
|
||||
} else if (words[0] == "bond_style") {
|
||||
matches = rl_completion_matches(text, bond_generator);
|
||||
} else if (words[0] == "angle_style") {
|
||||
matches = rl_completion_matches(text, angle_generator);
|
||||
} else if (words[0] == "dihedral_style") {
|
||||
matches = rl_completion_matches(text, dihedral_generator);
|
||||
} else if (words[0] == "improper_style") {
|
||||
matches = rl_completion_matches(text, improper_generator);
|
||||
} else if (words[0] == "kspace_style") {
|
||||
matches = rl_completion_matches(text, kspace_generator);
|
||||
} else if (words[0] == "run_style") {
|
||||
matches = rl_completion_matches(text, integrate_generator);
|
||||
} else if (words[0] == "min_style") {
|
||||
matches = rl_completion_matches(text, minimize_generator);
|
||||
} else if (words[0] == "compute_modify") {
|
||||
matches = rl_completion_matches(text, compute_id_generator);
|
||||
} else if (words[0] == "dump_modify") {
|
||||
matches = rl_completion_matches(text, dump_id_generator);
|
||||
} else if (words[0] == "fix_modify") {
|
||||
matches = rl_completion_matches(text, fix_id_generator);
|
||||
} else if (words[0] == "plugin") {
|
||||
matches = rl_completion_matches(text, plugin_generator);
|
||||
}
|
||||
} else if (words.size() == 2) { // expand third word
|
||||
|
||||
// these commands have a group name as 3rd word
|
||||
if ((words[0] == "fix") || (words[0] == "compute") || (words[0] == "dump")) {
|
||||
matches = rl_completion_matches(text, group_generator);
|
||||
} else if (words[0] == "region") {
|
||||
matches = rl_completion_matches(text, region_generator);
|
||||
// plugin style is the third word
|
||||
} else if ((words[0] == "plugin") && (words[1] == "unload")) {
|
||||
matches = rl_completion_matches(text, plugin_style_generator);
|
||||
}
|
||||
} else if (words.size() == 3) { // expand fourth word
|
||||
|
||||
// style name is the fourth word
|
||||
if (words[0] == "fix") {
|
||||
matches = rl_completion_matches(text, fix_generator);
|
||||
} else if (words[0] == "compute") {
|
||||
matches = rl_completion_matches(text, compute_generator);
|
||||
} else if (words[0] == "dump") {
|
||||
matches = rl_completion_matches(text, dump_generator);
|
||||
// plugin name is the fourth word
|
||||
} else if ((words[0] == "plugin") && (words[1] == "unload")) {
|
||||
matches = rl_completion_matches(rl_line_buffer, plugin_name_generator);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return matches;
|
||||
}
|
||||
|
||||
} // end of extern "C"
|
||||
|
||||
static void init_commands()
|
||||
{
|
||||
// store internal commands
|
||||
int ncmds = sizeof(cmdlist) / sizeof(const char *);
|
||||
for (int i = 0; i < ncmds; ++i)
|
||||
commands.emplace_back(cmdlist[i]);
|
||||
|
||||
// store optional commands from command styles
|
||||
ncmds = lammps_style_count(lmp, "command");
|
||||
for (int i = 0; i < ncmds; ++i) {
|
||||
if (lammps_style_name(lmp, "command", i, buf, BUFLEN)) commands.emplace_back(buf);
|
||||
}
|
||||
|
||||
// store LAMMPS shell specific command names
|
||||
commands.emplace_back("help");
|
||||
commands.emplace_back("exit");
|
||||
commands.emplace_back("pwd");
|
||||
commands.emplace_back("cd");
|
||||
commands.emplace_back("mem");
|
||||
commands.emplace_back("source");
|
||||
commands.emplace_back("history");
|
||||
commands.emplace_back("clear_history");
|
||||
commands.emplace_back("save_history");
|
||||
|
||||
// set name so there can be specific entries in ~/.inputrc
|
||||
rl_readline_name = "lammps-shell";
|
||||
rl_basic_word_break_characters = " \t\n\"\\'`@><=;|&(";
|
||||
|
||||
// attempt completions only if we are connected to a tty or are running tests.
|
||||
// otherwise any tabs in redirected input will cause havoc.
|
||||
const char *test_mode = getenv("LAMMPS_SHELL_TESTING");
|
||||
if (test_mode) std::cout << "*TESTING* using LAMMPS Shell in test mode *TESTING*\n";
|
||||
if (platform::is_console(stdin) || test_mode) {
|
||||
rl_attempted_completion_function = cmd_completion;
|
||||
} else {
|
||||
rl_bind_key('\t', rl_insert);
|
||||
}
|
||||
|
||||
// read saved history, but not in test mode.
|
||||
if (!test_mode) read_history(".lammps_history");
|
||||
|
||||
// intercept CTRL-C
|
||||
#if defined(_WIN32)
|
||||
SetConsoleCtrlHandler(ctrl_c_handler, TRUE);
|
||||
#else
|
||||
signal(SIGINT, ctrl_c_handler);
|
||||
#endif
|
||||
}
|
||||
|
||||
static int help_cmd()
|
||||
{
|
||||
std::cout << "\nThis is the LAMMPS Shell. An interactive LAMMPS session with command \n"
|
||||
"line editing, context aware command expansion, and history.\n\n"
|
||||
"- Hit the TAB key any time to try to expand the current word\n"
|
||||
"- Issue shell commands by prefixing them with '|' (Example: '|ls -la')\n"
|
||||
"- Use the '!' character for bash-like history epansion. (Example: '!run)\n\n"
|
||||
"A history of the session will be written to the a file '.lammps_history'\n"
|
||||
"in the current working directory and - if present - this file will be\n"
|
||||
"read at the beginning of the next session of the LAMMPS shell.\n\n"
|
||||
"Additional information is at https://packages.lammps.org/lammps-shell.html\n\n";
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shell_end()
|
||||
{
|
||||
write_history(".lammps_history");
|
||||
if (lmp) lammps_close(lmp);
|
||||
lammps_mpi_finalize();
|
||||
lmp = nullptr;
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int shell_cmd(const std::string &cmd)
|
||||
{
|
||||
char *expansion;
|
||||
char *text = dupstring(cmd);
|
||||
int retval = history_expand(text, &expansion);
|
||||
|
||||
// history expansion error
|
||||
if (retval < 0) {
|
||||
free(text);
|
||||
free(expansion);
|
||||
std::cout << "History error: " << utils::getsyserror() << "\n";
|
||||
return 1;
|
||||
}
|
||||
|
||||
// use expanded or original text and add to history
|
||||
if (retval > 0) {
|
||||
free(text);
|
||||
text = expansion;
|
||||
} else
|
||||
free(expansion);
|
||||
|
||||
add_history(text);
|
||||
|
||||
// only print, don't execute.
|
||||
if (retval == 2) {
|
||||
std::cout << text << "\n";
|
||||
free(text);
|
||||
return 0;
|
||||
}
|
||||
|
||||
// check for commands particular to lammps-shell
|
||||
auto words = utils::split_words(text);
|
||||
if (words[0][0] == '|') {
|
||||
int rv = system(text + 1);
|
||||
free(text);
|
||||
return rv;
|
||||
} else if ((words[0] == "help") || (words[0] == "?")) {
|
||||
free(text);
|
||||
return help_cmd();
|
||||
} else if (words[0] == "exit") {
|
||||
free(text);
|
||||
return shell_end();
|
||||
} else if (words[0] == "source") {
|
||||
lammps_file(lmp, words[1].c_str());
|
||||
free(text);
|
||||
return 0;
|
||||
} else if ((words[0] == "pwd") || ((words[0] == "cd") && (words.size() == 1))) {
|
||||
std::cout << platform::current_directory() << "\n";
|
||||
free(text);
|
||||
return 0;
|
||||
} else if (words[0] == "cd") {
|
||||
std::string shellcmd = "shell ";
|
||||
shellcmd += text;
|
||||
lammps_command(lmp, shellcmd.c_str());
|
||||
free(text);
|
||||
return 0;
|
||||
} else if (words[0] == "mem") {
|
||||
double meminfo[3];
|
||||
lammps_memory_usage(lmp, meminfo);
|
||||
std::cout << "Memory usage. Current: " << meminfo[0] << " MByte, "
|
||||
<< "Maximum : " << meminfo[2] << " MByte\n";
|
||||
free(text);
|
||||
return 0;
|
||||
} else if (words[0] == "history") {
|
||||
free(text);
|
||||
HIST_ENTRY **list = history_list();
|
||||
for (int i = 0; i < history_length; ++i) {
|
||||
std::cout << i + history_base << ": " << list[i]->line << "\n";
|
||||
}
|
||||
return 0;
|
||||
} else if (words[0] == "clear_history") {
|
||||
free(text);
|
||||
clear_history();
|
||||
return 0;
|
||||
} else if (words[0] == "save_history") {
|
||||
free(text);
|
||||
if (words.size() == 3) {
|
||||
if (save_history(words[1], words[2]) != 0) {
|
||||
int from = history_base;
|
||||
int to = from + history_length - 1;
|
||||
std::cerr << "Range error: min = " << from << " max = " << to << "\n";
|
||||
return 1;
|
||||
}
|
||||
} else {
|
||||
std::cerr << "Usage: save_history <range> <filename>\n";
|
||||
return 1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
lammps_command(lmp, text);
|
||||
free(text);
|
||||
return lammps_has_error(lmp);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
char *line;
|
||||
std::string trimmed;
|
||||
|
||||
#if defined(_WIN32)
|
||||
// Special hack for Windows: if the current working directory is
|
||||
// the "system folder" (because that is where cmd.exe lives)
|
||||
// switch to the user's documents directory.
|
||||
|
||||
auto curdir = platform::current_directory();
|
||||
if (utils::strmatch(curdir, "[Ss]ystem32")) {
|
||||
std::string docdir = getenv("HOMEDRIVE");
|
||||
docdir += getenv("HOMEPATH");
|
||||
docdir += "\\Documents";
|
||||
platform::chdir(docdir);
|
||||
}
|
||||
#endif
|
||||
|
||||
lammps_get_os_info(buf, BUFLEN);
|
||||
std::cout << "LAMMPS Shell version 1.2 OS: " << buf;
|
||||
|
||||
if (!lammps_config_has_exceptions())
|
||||
std::cout << "WARNING: LAMMPS was compiled without exceptions\n"
|
||||
"WARNING: The shell will terminate on errors.\n";
|
||||
|
||||
#if defined(_OPENMP)
|
||||
int nthreads = omp_get_max_threads();
|
||||
#else
|
||||
int nthreads = 1;
|
||||
#endif
|
||||
// avoid OMP_NUM_THREADS warning and change the default behavior
|
||||
// to use the maximum number of threads available since this is
|
||||
// not intended to be run with MPI.
|
||||
omp_threads = dupstring(std::string("OMP_NUM_THREADS=" + std::to_string(nthreads)));
|
||||
platform::putenv(omp_threads);
|
||||
|
||||
// handle the special case where the first argument is not a flag but a file
|
||||
// this happens for example when using file type associations on Windows.
|
||||
// in this case we save the pointer and remove it from argv.
|
||||
// we also get the directory name and switch to that folder
|
||||
std::string input_file;
|
||||
if ((argc > 1) && (argv[1][0] != '-')) {
|
||||
--argc;
|
||||
input_file = platform::path_basename(argv[1]);
|
||||
platform::chdir(platform::path_dirname(input_file));
|
||||
for (int i = 1; i < argc; ++i)
|
||||
argv[i] = argv[i + 1];
|
||||
}
|
||||
|
||||
lmp = lammps_open_no_mpi(argc, argv, nullptr);
|
||||
if (lmp == nullptr) return 1;
|
||||
|
||||
using_history();
|
||||
init_commands();
|
||||
|
||||
// pre-load an input file that was provided on the command line
|
||||
if (!input_file.empty()) {
|
||||
lammps_file(lmp, input_file.c_str());
|
||||
} else {
|
||||
for (int i = 0; i < argc; ++i) {
|
||||
if ((strcmp(argv[i], "-in") == 0) || (strcmp(argv[i], "-i") == 0)) {
|
||||
lammps_file(lmp, argv[i + 1]);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
while (lmp != nullptr) {
|
||||
line = readline("LAMMPS Shell> ");
|
||||
if (!line) break;
|
||||
trimmed = utils::trim(line);
|
||||
if (trimmed.size() > 0) {
|
||||
shell_cmd(trimmed);
|
||||
}
|
||||
free(line);
|
||||
}
|
||||
|
||||
return shell_end();
|
||||
}
|
||||
@ -1,10 +0,0 @@
|
||||
[Desktop Entry]
|
||||
Version=1.0
|
||||
Type=Application
|
||||
Categories=Science;Engineering;
|
||||
Exec=/bin/sh -c "echo -e -n \"\033]0;The LAMMPS Shell\007\"; LC_ALL=C lammps-shell %f"
|
||||
Name=The LAMMPS Shell
|
||||
Terminal=true
|
||||
GenericName=MD Simulator
|
||||
Keywords=MD Simulation;LAMMPS;Molecular Dynamics;N-Body
|
||||
Icon=lammps
|
||||
@ -1,2 +0,0 @@
|
||||
id1 ICON icons/lammps.ico
|
||||
id2 ICON icons/lmpfile.ico
|
||||
@ -125,6 +125,8 @@ extern int lammps_get_mpi_comm(void *handle);
|
||||
extern int lammps_extract_setting(void *handle, const char *keyword);
|
||||
extern int lammps_extract_global_datatype(void *handle, const char *name);
|
||||
extern void *lammps_extract_global(void *handle, const char *name);
|
||||
extern int lammps_extract_pair_dimension(void *handle, const char *name);
|
||||
extern void *lammps_extract_pair(void *handle, const char *name);
|
||||
extern int lammps_map_atom(void *handle, const void *id);
|
||||
|
||||
extern int lammps_extract_atom_datatype(void *handle, const char *name);
|
||||
@ -169,6 +171,7 @@ extern int lammps_config_has_gzip_support();
|
||||
extern int lammps_config_has_png_support();
|
||||
extern int lammps_config_has_jpeg_support();
|
||||
extern int lammps_config_has_ffmpeg_support();
|
||||
extern int lammps_config_has_curl_support();
|
||||
extern int lammps_config_has_exceptions();
|
||||
extern int lammps_config_has_package(const char *);
|
||||
extern int lammps_config_package_count();
|
||||
@ -311,6 +314,8 @@ extern int lammps_get_mpi_comm(void *handle);
|
||||
extern int lammps_extract_setting(void *handle, const char *keyword);
|
||||
extern int lammps_extract_global_datatype(void *handle, const char *name);
|
||||
extern void *lammps_extract_global(void *handle, const char *name);
|
||||
extern int lammps_extract_pair_dimension(void *handle, const char *name);
|
||||
extern void *lammps_extract_pair(void *handle, const char *name);
|
||||
extern int lammps_map_atom(void *handle, const void *id);
|
||||
|
||||
extern int lammps_extract_atom_datatype(void *handle, const char *name);
|
||||
@ -355,6 +360,7 @@ extern int lammps_config_has_gzip_support();
|
||||
extern int lammps_config_has_png_support();
|
||||
extern int lammps_config_has_jpeg_support();
|
||||
extern int lammps_config_has_ffmpeg_support();
|
||||
extern int lammps_config_has_curl_support();
|
||||
extern int lammps_config_has_exceptions();
|
||||
extern int lammps_config_has_package(const char *);
|
||||
extern int lammps_config_package_count();
|
||||
|
||||
@ -39,3 +39,45 @@
|
||||
fun:PMPI_Init
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
MPICH_MPI_init4
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: reachable
|
||||
fun:calloc
|
||||
fun:psmx3_recv_generic
|
||||
...
|
||||
obj:*
|
||||
...
|
||||
fun:MPIDI_Init.constprop.0
|
||||
...
|
||||
fun:PMPI_Init
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
MPICH_MPI_init5
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: reachable
|
||||
fun:calloc
|
||||
obj:*
|
||||
...
|
||||
fun: usdf_getinfo.lto_priv.0
|
||||
...
|
||||
fun:MPID_Init.constprop.0
|
||||
...
|
||||
fun:PMPI_Init
|
||||
fun:main
|
||||
}
|
||||
{
|
||||
MPICH_MPI_init6
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: reachable
|
||||
fun:malloc
|
||||
fun:strdup
|
||||
obj:*
|
||||
...
|
||||
fun:MPID_Init.constprop.0
|
||||
...
|
||||
obj:*
|
||||
fun:PMPI_Init
|
||||
fun:main
|
||||
}
|
||||
|
||||
@ -193,3 +193,13 @@
|
||||
fun:GOMP_parallel
|
||||
}
|
||||
|
||||
{
|
||||
gomp_realloc1
|
||||
Memcheck:Leak
|
||||
match-leak-kinds: reachable
|
||||
fun:realloc
|
||||
fun:gomp_realloc
|
||||
fun:gomp_team_start
|
||||
fun:GOMP_parallel
|
||||
}
|
||||
|
||||
|
||||
@ -11,7 +11,7 @@ set iskeyword+=/
|
||||
|
||||
syn keyword lammpsOutput log write_data write_dump write_coeff info shell write_restart restart dump undump thermo thermo_modify
|
||||
syn keyword lammpsOutput thermo_style print timer
|
||||
syn keyword lammpsRead include read_restart read_data read_dump molecule
|
||||
syn keyword lammpsRead include read_restart read_data read_dump molecule geturl
|
||||
syn keyword lammpsLattice boundary units atom_style lattice region create_box create_atoms dielectric
|
||||
syn keyword lammpsLattice delete_atoms displace_atoms change_box dimension replicate
|
||||
syn keyword lammpsParticle pair_coeff pair_style pair_modify pair_write mass velocity angle_coeff angle_style angle_write
|
||||
|
||||