add chart viewer window to show graphs of ongoing runs from thermo data
This commit is contained in:
@ -1,6 +1,6 @@
|
|||||||
cmake_minimum_required(VERSION 3.16)
|
cmake_minimum_required(VERSION 3.16)
|
||||||
|
|
||||||
project(lammps-gui VERSION 1.0.0 LANGUAGES CXX)
|
project(lammps-gui VERSION 1.1.0 LANGUAGES CXX)
|
||||||
|
|
||||||
set(CMAKE_AUTOUIC ON)
|
set(CMAKE_AUTOUIC ON)
|
||||||
set(CMAKE_AUTOMOC ON)
|
set(CMAKE_AUTOMOC ON)
|
||||||
@ -13,10 +13,6 @@ option(LAMMPS_GUI_USE_PLUGIN "Load LAMMPS library dynamically at runtime" OFF)
|
|||||||
mark_as_advanced(LAMMPS_GUI_USE_PLUGIN)
|
mark_as_advanced(LAMMPS_GUI_USE_PLUGIN)
|
||||||
|
|
||||||
# checks
|
# checks
|
||||||
if(BUILD_MPI)
|
|
||||||
message(FATAL_ERROR "Must disable BUILD_MPI for building the LAMMPS GUI")
|
|
||||||
endif()
|
|
||||||
|
|
||||||
# when this file is included as subdirectory in the LAMMPS build, many settings are directly imported
|
# when this file is included as subdirectory in the LAMMPS build, many settings are directly imported
|
||||||
if(LAMMPS_DIR)
|
if(LAMMPS_DIR)
|
||||||
set(LAMMPS_HEADER_DIR ${LAMMPS_SOURCE_DIR})
|
set(LAMMPS_HEADER_DIR ${LAMMPS_SOURCE_DIR})
|
||||||
@ -62,7 +58,7 @@ if(LAMMPS_GUI_USE_PLUGIN)
|
|||||||
endif()
|
endif()
|
||||||
|
|
||||||
# we require Qt 5 and at least version 5.12 at that.
|
# we require Qt 5 and at least version 5.12 at that.
|
||||||
find_package(Qt5 5.12 REQUIRED COMPONENTS Widgets)
|
find_package(Qt5 5.12 REQUIRED COMPONENTS Widgets Charts)
|
||||||
|
|
||||||
set(PROJECT_SOURCES
|
set(PROJECT_SOURCES
|
||||||
main.cpp
|
main.cpp
|
||||||
@ -72,6 +68,8 @@ set(PROJECT_SOURCES
|
|||||||
highlighter.h
|
highlighter.h
|
||||||
imageviewer.cpp
|
imageviewer.cpp
|
||||||
imageviewer.h
|
imageviewer.h
|
||||||
|
chartviewer.cpp
|
||||||
|
chartviewer.h
|
||||||
lammpsgui.cpp
|
lammpsgui.cpp
|
||||||
lammpsgui.h
|
lammpsgui.h
|
||||||
lammpsgui.ui
|
lammpsgui.ui
|
||||||
@ -109,7 +107,7 @@ else()
|
|||||||
endif()
|
endif()
|
||||||
target_include_directories(lammps-gui PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
target_include_directories(lammps-gui PRIVATE ${CMAKE_CURRENT_SOURCE_DIR})
|
||||||
target_compile_definitions(lammps-gui PRIVATE LAMMPS_GUI_VERSION="${PROJECT_VERSION}")
|
target_compile_definitions(lammps-gui PRIVATE LAMMPS_GUI_VERSION="${PROJECT_VERSION}")
|
||||||
target_link_libraries(lammps-gui PRIVATE Qt5::Widgets)
|
target_link_libraries(lammps-gui PRIVATE Qt5::Widgets Qt5::Charts)
|
||||||
if(BUILD_OMP)
|
if(BUILD_OMP)
|
||||||
find_package(OpenMP COMPONENTS CXX REQUIRED)
|
find_package(OpenMP COMPONENTS CXX REQUIRED)
|
||||||
target_link_libraries(lammps-gui PRIVATE OpenMP::OpenMP_CXX)
|
target_link_libraries(lammps-gui PRIVATE OpenMP::OpenMP_CXX)
|
||||||
|
|||||||
85
tools/lammps-gui/chartviewer.cpp
Normal file
85
tools/lammps-gui/chartviewer.cpp
Normal file
@ -0,0 +1,85 @@
|
|||||||
|
/* ----------------------------------------------------------------------
|
||||||
|
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 "chartviewer.h"
|
||||||
|
|
||||||
|
#include <QLineSeries>
|
||||||
|
#include <QSettings>
|
||||||
|
|
||||||
|
using namespace QtCharts;
|
||||||
|
|
||||||
|
ChartViewer::ChartViewer(QWidget *parent) :
|
||||||
|
QChartView(parent), last_step(-1), chart(new QChart), series(new QLineSeries),
|
||||||
|
xaxis(new QValueAxis), yaxis(new QValueAxis)
|
||||||
|
{
|
||||||
|
chart->legend()->hide();
|
||||||
|
chart->addAxis(xaxis,Qt::AlignBottom);
|
||||||
|
chart->addAxis(yaxis,Qt::AlignLeft);
|
||||||
|
chart->addSeries(series);
|
||||||
|
series->attachAxis(xaxis);
|
||||||
|
series->attachAxis(yaxis);
|
||||||
|
xaxis->setTitleText("Time step");
|
||||||
|
xaxis->setTickCount(5);
|
||||||
|
yaxis->setTickCount(5);
|
||||||
|
xaxis->setMinorTickCount(5);
|
||||||
|
yaxis->setMinorTickCount(5);
|
||||||
|
|
||||||
|
setRenderHint(QPainter::Antialiasing);
|
||||||
|
setChart(chart);
|
||||||
|
setRubberBand(QChartView::RectangleRubberBand);
|
||||||
|
|
||||||
|
QSettings settings;
|
||||||
|
resize(settings.value("chartx", 500).toInt(), settings.value("charty", 320).toInt());
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChartViewer::add_column(const QString &title)
|
||||||
|
{
|
||||||
|
yaxis->setTitleText(title);
|
||||||
|
series->setName(title);
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChartViewer::add_data(int step, int column, double data)
|
||||||
|
{
|
||||||
|
if (last_step < step) {
|
||||||
|
last_step = step;
|
||||||
|
series->append(step, data);
|
||||||
|
auto points = series->pointsVector();
|
||||||
|
|
||||||
|
qreal xmin = 1.0e100;
|
||||||
|
qreal xmax = -1.0e100;
|
||||||
|
qreal ymin = 1.0e100;
|
||||||
|
qreal ymax = -1.0e100;
|
||||||
|
for (auto &p : points) {
|
||||||
|
xmin = qMin(xmin, p.x());
|
||||||
|
xmax = qMax(xmax, p.x());
|
||||||
|
ymin = qMin(ymin, p.y());
|
||||||
|
ymax = qMax(ymax, p.y());
|
||||||
|
}
|
||||||
|
xaxis->setRange(xmin, xmax);
|
||||||
|
yaxis->setRange(ymin, ymax);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void ChartViewer::closeEvent(QCloseEvent *event)
|
||||||
|
{
|
||||||
|
QSettings settings;
|
||||||
|
if (!isMaximized()) {
|
||||||
|
settings.setValue("chartx", width());
|
||||||
|
settings.setValue("charty", height());
|
||||||
|
}
|
||||||
|
QChartView::closeEvent(event);
|
||||||
|
}
|
||||||
|
|
||||||
|
// Local Variables:
|
||||||
|
// c-basic-offset: 4
|
||||||
|
// End:
|
||||||
43
tools/lammps-gui/chartviewer.h
Normal file
43
tools/lammps-gui/chartviewer.h
Normal file
@ -0,0 +1,43 @@
|
|||||||
|
/* -*- 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 CHARTVIEWER_H
|
||||||
|
#define CHARTVIEWER_H
|
||||||
|
|
||||||
|
#include <QtCharts>
|
||||||
|
|
||||||
|
class ChartViewer : public QtCharts::QChartView {
|
||||||
|
Q_OBJECT
|
||||||
|
|
||||||
|
public:
|
||||||
|
ChartViewer(QWidget *parent = nullptr);
|
||||||
|
bool has_columns() const { return last_step >= 0; }
|
||||||
|
void add_column(const QString &title);
|
||||||
|
void add_data(int step, int column, double data);
|
||||||
|
int get_last_step() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void closeEvent(QCloseEvent *event) override;
|
||||||
|
|
||||||
|
private:
|
||||||
|
int last_step;
|
||||||
|
QtCharts::QChart *chart;
|
||||||
|
QtCharts::QLineSeries *series;
|
||||||
|
QtCharts::QValueAxis *xaxis;
|
||||||
|
QtCharts::QValueAxis *yaxis;
|
||||||
|
};
|
||||||
|
#endif
|
||||||
|
|
||||||
|
// Local Variables:
|
||||||
|
// c-basic-offset: 4
|
||||||
|
// End:
|
||||||
@ -13,6 +13,7 @@
|
|||||||
|
|
||||||
#include "lammpsgui.h"
|
#include "lammpsgui.h"
|
||||||
|
|
||||||
|
#include "chartviewer.h"
|
||||||
#include "highlighter.h"
|
#include "highlighter.h"
|
||||||
#include "imageviewer.h"
|
#include "imageviewer.h"
|
||||||
#include "lammpsrunner.h"
|
#include "lammpsrunner.h"
|
||||||
@ -64,8 +65,8 @@ static char *mystrdup(const std::string &text)
|
|||||||
|
|
||||||
LammpsGui::LammpsGui(QWidget *parent, const char *filename) :
|
LammpsGui::LammpsGui(QWidget *parent, const char *filename) :
|
||||||
QMainWindow(parent), ui(new Ui::LammpsGui), highlighter(nullptr), capturer(nullptr),
|
QMainWindow(parent), ui(new Ui::LammpsGui), highlighter(nullptr), capturer(nullptr),
|
||||||
status(nullptr), logwindow(nullptr), imagewindow(nullptr), logupdater(nullptr),
|
status(nullptr), logwindow(nullptr), imagewindow(nullptr), chartwindow(nullptr),
|
||||||
dirstatus(nullptr), progress(nullptr), prefdialog(nullptr)
|
logupdater(nullptr), dirstatus(nullptr), progress(nullptr), prefdialog(nullptr)
|
||||||
{
|
{
|
||||||
ui->setupUi(this);
|
ui->setupUi(this);
|
||||||
this->setCentralWidget(ui->textEdit);
|
this->setCentralWidget(ui->textEdit);
|
||||||
@ -203,6 +204,7 @@ LammpsGui::~LammpsGui()
|
|||||||
delete status;
|
delete status;
|
||||||
delete logwindow;
|
delete logwindow;
|
||||||
delete imagewindow;
|
delete imagewindow;
|
||||||
|
delete chartwindow;
|
||||||
delete dirstatus;
|
delete dirstatus;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -384,6 +386,7 @@ void LammpsGui::logupdate()
|
|||||||
double t_elapsed, t_remain, t_total;
|
double t_elapsed, t_remain, t_total;
|
||||||
int completed = 1000;
|
int completed = 1000;
|
||||||
|
|
||||||
|
// estimate completion percentage
|
||||||
if (lammps.is_running()) {
|
if (lammps.is_running()) {
|
||||||
t_elapsed = lammps.get_thermo("cpu");
|
t_elapsed = lammps.get_thermo("cpu");
|
||||||
t_remain = lammps.get_thermo("cpuremain");
|
t_remain = lammps.get_thermo("cpuremain");
|
||||||
@ -400,6 +403,28 @@ void LammpsGui::logupdate()
|
|||||||
logwindow->textCursor().deleteChar();
|
logwindow->textCursor().deleteChar();
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// extract chache thermo data
|
||||||
|
if (chartwindow) {
|
||||||
|
void *ptr = lammps.last_thermo("step", 0);
|
||||||
|
if (ptr) {
|
||||||
|
int step = 0;
|
||||||
|
if (lammps.extract_setting("bigint") == 4)
|
||||||
|
step = *(int *)ptr;
|
||||||
|
else
|
||||||
|
step = (int)*(int64_t *)ptr;
|
||||||
|
int ncols = *(int *)lammps.last_thermo("num", 0);
|
||||||
|
if (!chartwindow->has_columns()) {
|
||||||
|
// for (int i = 0; i < ncols; ++i) {
|
||||||
|
chartwindow->add_column((const char *)lammps.last_thermo("keyword", 1));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// for (int i = 0; i < ncols; ++i) {
|
||||||
|
chartwindow->add_data(step, 0, *(double *)lammps.last_thermo("data", 1));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void LammpsGui::modified()
|
void LammpsGui::modified()
|
||||||
@ -424,6 +449,27 @@ void LammpsGui::run_done()
|
|||||||
logwindow->insertPlainText(log.c_str());
|
logwindow->insertPlainText(log.c_str());
|
||||||
logwindow->moveCursor(QTextCursor::End);
|
logwindow->moveCursor(QTextCursor::End);
|
||||||
|
|
||||||
|
if (chartwindow) {
|
||||||
|
void *ptr = lammps.last_thermo("step", 0);
|
||||||
|
if (ptr) {
|
||||||
|
int step = 0;
|
||||||
|
if (lammps.extract_setting("bigint") == 4)
|
||||||
|
step = *(int *)ptr;
|
||||||
|
else
|
||||||
|
step = (int)*(int64_t *)ptr;
|
||||||
|
int ncols = *(int *)lammps.last_thermo("num", 0);
|
||||||
|
if (!chartwindow->has_columns()) {
|
||||||
|
// for (int i = 0; i < ncols; ++i) {
|
||||||
|
chartwindow->add_column((const char *)lammps.last_thermo("keyword", 1));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
|
||||||
|
// for (int i = 0; i < ncols; ++i) {
|
||||||
|
chartwindow->add_data(step, 0, *(double *)lammps.last_thermo("data", 1));
|
||||||
|
// }
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
bool success = true;
|
bool success = true;
|
||||||
constexpr int BUFLEN = 1024;
|
constexpr int BUFLEN = 1024;
|
||||||
char errorbuf[BUFLEN];
|
char errorbuf[BUFLEN];
|
||||||
@ -458,7 +504,8 @@ void LammpsGui::run_buffer()
|
|||||||
int nthreads = settings.value("nthreads", 1).toInt();
|
int nthreads = settings.value("nthreads", 1).toInt();
|
||||||
int accel = settings.value("accelerator", AcceleratorTab::None).toInt();
|
int accel = settings.value("accelerator", AcceleratorTab::None).toInt();
|
||||||
if ((accel != AcceleratorTab::OpenMP) && (accel != AcceleratorTab::Intel) &&
|
if ((accel != AcceleratorTab::OpenMP) && (accel != AcceleratorTab::Intel) &&
|
||||||
(accel != AcceleratorTab::Kokkos)) nthreads = 1;
|
(accel != AcceleratorTab::Kokkos))
|
||||||
|
nthreads = 1;
|
||||||
if (nthreads > 1)
|
if (nthreads > 1)
|
||||||
status->setText(QString("Running LAMMPS with %1 thread(s)...").arg(nthreads));
|
status->setText(QString("Running LAMMPS with %1 thread(s)...").arg(nthreads));
|
||||||
else
|
else
|
||||||
@ -503,9 +550,22 @@ void LammpsGui::run_buffer()
|
|||||||
QObject::connect(shortcut, &QShortcut::activated, this, &LammpsGui::stop_run);
|
QObject::connect(shortcut, &QShortcut::activated, this, &LammpsGui::stop_run);
|
||||||
logwindow->show();
|
logwindow->show();
|
||||||
|
|
||||||
|
// if configured, delete old log window before opening new one
|
||||||
|
if (settings.value("chartreplace", false).toBool()) delete chartwindow;
|
||||||
|
chartwindow = new ChartViewer();
|
||||||
|
chartwindow->setWindowTitle("LAMMPS-GUI - Thermo charts from running LAMMPS on buffer - " +
|
||||||
|
current_file);
|
||||||
|
chartwindow->setWindowIcon(QIcon(":/lammps-icon-128x128.png"));
|
||||||
|
chartwindow->setMinimumSize(400, 300);
|
||||||
|
shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_W), chartwindow);
|
||||||
|
QObject::connect(shortcut, &QShortcut::activated, chartwindow, &ChartViewer::close);
|
||||||
|
shortcut = new QShortcut(QKeySequence(Qt::CTRL + Qt::Key_Slash), chartwindow);
|
||||||
|
QObject::connect(shortcut, &QShortcut::activated, this, &LammpsGui::stop_run);
|
||||||
|
chartwindow->show();
|
||||||
|
|
||||||
logupdater = new QTimer(this);
|
logupdater = new QTimer(this);
|
||||||
connect(logupdater, &QTimer::timeout, this, &LammpsGui::logupdate);
|
connect(logupdater, &QTimer::timeout, this, &LammpsGui::logupdate);
|
||||||
logupdater->start(500);
|
logupdater->start(200);
|
||||||
}
|
}
|
||||||
|
|
||||||
void LammpsGui::view_image()
|
void LammpsGui::view_image()
|
||||||
|
|||||||
@ -39,6 +39,7 @@ class Highlighter;
|
|||||||
class StdCapture;
|
class StdCapture;
|
||||||
class Preferences;
|
class Preferences;
|
||||||
class ImageViewer;
|
class ImageViewer;
|
||||||
|
class ChartViewer;
|
||||||
|
|
||||||
class LammpsGui : public QMainWindow {
|
class LammpsGui : public QMainWindow {
|
||||||
Q_OBJECT
|
Q_OBJECT
|
||||||
@ -85,6 +86,7 @@ private:
|
|||||||
QLabel *status;
|
QLabel *status;
|
||||||
QPlainTextEdit *logwindow;
|
QPlainTextEdit *logwindow;
|
||||||
ImageViewer *imagewindow;
|
ImageViewer *imagewindow;
|
||||||
|
ChartViewer *chartwindow;
|
||||||
QTimer *logupdater;
|
QTimer *logupdater;
|
||||||
QLabel *dirstatus;
|
QLabel *dirstatus;
|
||||||
QProgressBar *progress;
|
QProgressBar *progress;
|
||||||
|
|||||||
@ -58,6 +58,19 @@ double LammpsWrapper::get_thermo(const char *keyword)
|
|||||||
return val;
|
return val;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void *LammpsWrapper::last_thermo(const char *keyword, int index)
|
||||||
|
{
|
||||||
|
void *ptr = nullptr;
|
||||||
|
if (lammps_handle) {
|
||||||
|
#if defined(LAMMPS_GUI_USE_PLUGIN)
|
||||||
|
ptr = ((liblammpsplugin_t *)plugin_handle)->last_thermo(lammps_handle, keyword, index);
|
||||||
|
#else
|
||||||
|
ptr = lammps_last_thermo(lammps_handle, keyword, index);
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
return ptr;
|
||||||
|
}
|
||||||
|
|
||||||
bool LammpsWrapper::is_running()
|
bool LammpsWrapper::is_running()
|
||||||
{
|
{
|
||||||
int val = 0;
|
int val = 0;
|
||||||
|
|||||||
@ -30,6 +30,7 @@ public:
|
|||||||
|
|
||||||
int extract_setting(const char *keyword);
|
int extract_setting(const char *keyword);
|
||||||
double get_thermo(const char *keyword);
|
double get_thermo(const char *keyword);
|
||||||
|
void *last_thermo(const char *keyword, int idx);
|
||||||
bool is_open() const { return lammps_handle != nullptr; }
|
bool is_open() const { return lammps_handle != nullptr; }
|
||||||
bool is_running();
|
bool is_running();
|
||||||
bool has_error() const;
|
bool has_error() const;
|
||||||
|
|||||||
@ -13,7 +13,6 @@
|
|||||||
|
|
||||||
#include "logwindow.h"
|
#include "logwindow.h"
|
||||||
#include <QSettings>
|
#include <QSettings>
|
||||||
#include <cstdio>
|
|
||||||
|
|
||||||
LogWindow::LogWindow(QWidget *parent) : QPlainTextEdit(parent)
|
LogWindow::LogWindow(QWidget *parent) : QPlainTextEdit(parent)
|
||||||
{
|
{
|
||||||
@ -23,7 +22,6 @@ LogWindow::LogWindow(QWidget *parent) : QPlainTextEdit(parent)
|
|||||||
|
|
||||||
void LogWindow::closeEvent(QCloseEvent *event)
|
void LogWindow::closeEvent(QCloseEvent *event)
|
||||||
{
|
{
|
||||||
fprintf(stderr, "log closing\n");
|
|
||||||
QSettings settings;
|
QSettings settings;
|
||||||
if (!isMaximized()) {
|
if (!isMaximized()) {
|
||||||
settings.setValue("logx", width());
|
settings.setValue("logx", width());
|
||||||
|
|||||||
Reference in New Issue
Block a user