add chart viewer window to show graphs of ongoing runs from thermo data

This commit is contained in:
Axel Kohlmeyer
2023-08-05 14:27:26 -04:00
parent d414dd52d5
commit fe7681d0b3
8 changed files with 213 additions and 13 deletions

View File

@ -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)

View 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:

View 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:

View File

@ -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()

View File

@ -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;

View File

@ -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;

View File

@ -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;

View File

@ -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());