add code paths for all 8 tutorial wizards. only descriptive text is missing.

This commit is contained in:
Axel Kohlmeyer
2024-12-27 15:38:01 -05:00
parent 9241f89582
commit 90d1e4d45f
5 changed files with 378 additions and 330 deletions

View File

@ -1,6 +1,6 @@
cmake_minimum_required(VERSION 3.16)
project(lammps-gui VERSION 1.6.11 LANGUAGES CXX)
project(lammps-gui VERSION 1.6.12 LANGUAGES CXX)
set(CMAKE_AUTOUIC ON)
set(CMAKE_AUTOMOC ON)

View File

@ -54,11 +54,17 @@
</provides>
<releases>
<release version="1.6.12" timestamp="1734890080">
<description>
Update Tutorial menu entries to cover all 8 tutorials
Highlight warnings and error messages in Output window
</description>
</release>
<release version="1.6.11" timestamp="1725080055">
<description>
move cursor to end of log buffer before inserting new text
remove empirical filter to remove outliers from corrupted data
change tutorial download URL to tutorial website
Move cursor to end of log buffer before inserting new text
Remove empirical filter to remove outliers from corrupted data
Change tutorial download URL to tutorial website
</description>
</release>
<release version="1.6.10" timestamp="1724585189">

View File

@ -217,6 +217,12 @@ LammpsGui::LammpsGui(QWidget *parent, const QString &filename) :
connect(ui->actionLAMMPS_Tutorial, &QAction::triggered, this, &LammpsGui::tutorial_web);
connect(ui->actionTutorial1, &QAction::triggered, this, &LammpsGui::start_tutorial1);
connect(ui->actionTutorial2, &QAction::triggered, this, &LammpsGui::start_tutorial2);
connect(ui->actionTutorial3, &QAction::triggered, this, &LammpsGui::start_tutorial3);
connect(ui->actionTutorial4, &QAction::triggered, this, &LammpsGui::start_tutorial4);
connect(ui->actionTutorial5, &QAction::triggered, this, &LammpsGui::start_tutorial5);
connect(ui->actionTutorial6, &QAction::triggered, this, &LammpsGui::start_tutorial6);
connect(ui->actionTutorial7, &QAction::triggered, this, &LammpsGui::start_tutorial7);
connect(ui->actionTutorial8, &QAction::triggered, this, &LammpsGui::start_tutorial8);
connect(ui->actionAbout_LAMMPS_GUI, &QAction::triggered, this, &LammpsGui::about);
connect(ui->action_Help, &QAction::triggered, this, &LammpsGui::help);
connect(ui->actionLAMMPS_GUI_Howto, &QAction::triggered, this, &LammpsGui::howto);
@ -438,9 +444,7 @@ void LammpsGui::open_recent()
void LammpsGui::get_directory()
{
if (wizard) {
// figure out which wizard we are following
auto *line = wizard->findChild<QLineEdit *>("t1_directory");
if (!line) line = wizard->findChild<QLineEdit *>("t2_directory");
auto *line = wizard->findChild<QLineEdit *>("t_directory");
if (line) {
auto curdir = line->text();
QFileDialog dialog(this, "Choose Directory for Tutorial Files", curdir);
@ -1560,287 +1564,313 @@ void LammpsGui::tutorial_web()
QDesktopServices::openUrl(QUrl("https://lammpstutorials.github.io/"));
}
QWizardPage *LammpsGui::tutorial_intro(const int ntutorial)
{
auto *page = new QWizardPage;
page->setTitle(QString("Getting Started With Tutorial %1").arg(ntutorial));
page->setPixmap(QWizard::WatermarkPixmap,
QPixmap(QString(":/icons/tutorial%1-logo.png").arg(ntutorial)));
// XXX TODO: update URL to published tutorial DOI
auto *label = new QLabel(
QString("<p>This wizard will help you to select and populate a folder with materials "
"required to work through tutorial %1 from the LAMMPS tutorials article by "
"Simon Gravelle, Jake Gissinger, and Axel Kohlmeyer.</p>\nThe materials for this "
"tutorial are downloaded from:<br><b><a "
"href=\"https://github.com/lammpstutorials/lammpstutorials-article\">github.com/"
"lammpstutorials/lammpstutorials-article</a></b></p><br>\n<hr width=\"33%\"\\>\n<p "
"align=\"center\">Click on the \"Next\" button to begin.</p>")
.arg(ntutorial));
label->setWordWrap(true);
auto *layout = new QVBoxLayout;
layout->addWidget(label);
page->setLayout(layout);
return page;
}
QWizardPage *LammpsGui::tutorial_info(const int ntutorial, const QString &infotext)
{
auto *page = new QWizardPage;
page->setTitle(QString("Contents of Tutorial %1").arg(ntutorial));
page->setPixmap(QWizard::WatermarkPixmap,
QPixmap(QString(":/icons/tutorial%1-logo.png").arg(ntutorial)));
auto *label = new QLabel(infotext);
label->setWordWrap(true);
auto *layout = new QVBoxLayout;
layout->addWidget(label);
page->setLayout(layout);
return page;
}
QWizardPage *LammpsGui::tutorial_directory(const int ntutorial)
{
auto *page = new QWizardPage;
page->setTitle(QString("Select Directory for Tutorial %1").arg(ntutorial));
page->setPixmap(QWizard::WatermarkPixmap,
QPixmap(QString(":/icons/tutorial%1-logo.png").arg(ntutorial)));
auto *frame = new QFrame;
auto *label = new QLabel(
QString("<p>Select a directory to store the files for tutorial %1. The directory will be "
"created if necessary and LAMMPS-GUI will download the files required for the "
"tutorial.</p>\n<p>If selected, an existing directory may be "
"cleared.</p>\n<p>Also, available files of the tutorial solution may be downloaded "
"to a folder \"solution\", if requested.</p>\n<hr width=\"33%\">\n")
.arg(ntutorial));
label->setWordWrap(true);
auto *dirlayout = new QHBoxLayout;
auto *directory = new QLineEdit;
// if we are already in a tutorial folder, stay there or pick folder in same parent dir
bool haveDir = false;
for (int i = 1; i < 99; ++i) {
if (current_dir.endsWith(QString("tutorial%1").arg(i))) {
if (i > 9) { // We assume there are no more than 99 tutorials
current_dir.chop(2);
} else {
current_dir.chop(1);
}
current_dir.append(QString::number(ntutorial));
haveDir = true;
}
}
// if current dir is home, or application folder, switch to desktop path
if ((current_dir == QDir::homePath()) || current_dir.contains("AppData") ||
current_dir.contains("Program Files")) {
current_dir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
}
if (!haveDir) current_dir.append(QString("/tutorial%1").arg(ntutorial));
directory->setText(current_dir);
auto *dirbutton = new QPushButton("&Choose");
dirlayout->addWidget(directory);
dirlayout->addWidget(dirbutton);
directory->setObjectName("t_directory");
connect(dirbutton, &QPushButton::released, this, &LammpsGui::get_directory);
auto *grid = new QGridLayout;
auto *purgeval = new QCheckBox;
auto *solval = new QCheckBox;
auto *purgelabel = new QLabel("Remove existing files from directory");
auto *sollabel = new QLabel("Download solutions");
purgeval->setCheckState(Qt::Unchecked);
purgeval->setObjectName("t_dirpurge");
solval->setCheckState(Qt::Unchecked);
solval->setObjectName("t_getsolution");
grid->addWidget(purgeval, 0, 0, Qt::AlignVCenter);
grid->addWidget(purgelabel, 0, 1, Qt::AlignVCenter);
grid->addWidget(solval, 1, 0, Qt::AlignVCenter);
grid->addWidget(sollabel, 1, 1, Qt::AlignVCenter);
grid->setColumnStretch(0, 0);
grid->setColumnStretch(1, 100);
auto *layout = new QVBoxLayout(frame);
layout->addWidget(label);
layout->addLayout(dirlayout);
layout->addLayout(grid);
page->setLayout(layout);
return page;
}
QWizardPage *LammpsGui::tutorial_finish(const int ntutorial)
{
auto *page = new QWizardPage;
page->setTitle(QString("Start Tutorial %1").arg(ntutorial));
page->setPixmap(QWizard::WatermarkPixmap,
QPixmap(QString(":/icons/tutorial%1-logo.png").arg(ntutorial)));
auto *label = new QLabel(QString("<p align=\"center\">You are now ready to start tutorial "
"%1.</p>\n<hr width=\"33%\"\\>\n<p align=\"center\">Click on "
"the \"Finish\" button to complete the setup.</p>")
.arg(ntutorial));
label->setWordWrap(true);
auto *layout = new QVBoxLayout;
layout->addWidget(label);
layout->setStretch(0, 100);
page->setLayout(layout);
return page;
}
void LammpsGui::start_tutorial1()
{
if (wizard) delete wizard;
wizard = new Tutorial1Wizard;
wizard = new TutorialWizard(1);
const auto infotext =
QString("<p>In tutorial 1 you will learn about LAMMPS input files, their syntax and "
"structure, how to create and set up models and their interactions, how to run a "
"minimization and a molecular dynamics trajectory, how to plot thermodynamic data "
"and how to create visualizations of your system</p><hr width=\"33%\"\\>\n<p "
"align=\"center\">Click on the \"Next\" button to select a folder.</p>");
wizard->setFont(font());
wizard->addPage(tutorial1_intro());
wizard->addPage(tutorial1_info());
wizard->addPage(tutorial1_directory());
wizard->addPage(tutorial1_finish());
wizard->addPage(tutorial_intro(1));
wizard->addPage(tutorial_info(1, infotext));
wizard->addPage(tutorial_directory(1));
wizard->addPage(tutorial_finish(1));
wizard->setWindowTitle("Tutorial 1 Setup Wizard");
wizard->setWizardStyle(QWizard::ModernStyle);
wizard->show();
}
QWizardPage *LammpsGui::tutorial1_intro()
{
auto *page = new QWizardPage;
page->setTitle("Getting Started With Tutorial 1");
page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial1-logo.png"));
// XXX TODO: update URL to published tutorial DOI
auto *label =
new QLabel("<p>This wizard will help you to select and populate a folder with "
"materials required to work through tutorial 1 from a fourthcoming "
"LAMMPS tutorial using LAMMPS-GUI by Simon Gravelle, Jake Gissinger, "
"and Axel Kohlmeyer.</p>\n"
"The work-in-progress materials for this tutorial are available at: <a"
"<b><a href=\"https://github.com/lammpstutorials/lammpstutorials-article\">"
"github.com/lammpstutorials/lammpstutorials-article</a></b></p><br>\n"
"<hr width=\"33%\"\\>\n"
"<p align=\"center\">Click on the \"Next\" button to begin.</p>");
label->setWordWrap(true);
auto *layout = new QVBoxLayout;
layout->addWidget(label);
page->setLayout(layout);
return page;
}
QWizardPage *LammpsGui::tutorial1_info()
{
auto *page = new QWizardPage;
page->setTitle("Contents of Tutorial 1");
page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial1-logo.png"));
auto *label =
new QLabel("<p>In tutorial 1 you will learn about LAMMPS input files, their syntax and "
" structure, how to create and set up models and their interactions, how to "
"run a minimization and a molecular dynamics trajectory, how to plot "
"thermodynamic data and how to create visualizations of your system</p>"
"<hr width=\"33%\"\\>\n"
"<p align=\"center\">Click on the \"Next\" button to select a folder.</p>");
label->setWordWrap(true);
auto *layout = new QVBoxLayout;
layout->addWidget(label);
page->setLayout(layout);
return page;
}
QWizardPage *LammpsGui::tutorial1_directory()
{
auto *page = new QWizardPage;
page->setTitle("Select Directory for Tutorial 1");
page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial1-logo.png"));
auto *frame = new QFrame;
auto *label = new QLabel(
"<p>Select a directory to store the files for tutorial 1. The directory will be "
"created if necessary and LAMMPS-GUI will download the files required for the "
"tutorial.</p>\n"
"<p>If selected, an existing directory may be cleared.</p>\n"
"<p>Also, available files of the tutorial solution may be downloaded to a "
"folder \"solution\", if requested.</p>\n"
"<hr width=\"33%\">\n");
label->setWordWrap(true);
auto *dirlayout = new QHBoxLayout;
auto *directory = new QLineEdit;
// if we are already in the tutorial folder, stay there
if (!current_dir.endsWith("tutorial1")) {
// if current dir is home, or application folder, switch to desktop path
if ((current_dir == QDir::homePath()) || current_dir.contains("AppData") ||
current_dir.contains("Program Files")) {
current_dir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
}
current_dir += "/tutorial1";
}
directory->setText(current_dir);
auto *dirbutton = new QPushButton("&Choose");
dirlayout->addWidget(directory);
dirlayout->addWidget(dirbutton);
directory->setObjectName("t1_directory");
connect(dirbutton, &QPushButton::released, this, &LammpsGui::get_directory);
auto *grid = new QGridLayout;
auto *purgeval = new QCheckBox;
auto *solval = new QCheckBox;
auto *purgelabel = new QLabel("Remove existing files from directory");
auto *sollabel = new QLabel("Download solutions");
purgeval->setCheckState(Qt::Unchecked);
purgeval->setObjectName("t1_dirpurge");
solval->setCheckState(Qt::Unchecked);
solval->setObjectName("t1_getsolution");
grid->addWidget(purgeval, 0, 0, Qt::AlignVCenter);
grid->addWidget(purgelabel, 0, 1, Qt::AlignVCenter);
grid->addWidget(solval, 1, 0, Qt::AlignVCenter);
grid->addWidget(sollabel, 1, 1, Qt::AlignVCenter);
grid->setColumnStretch(0, 0);
grid->setColumnStretch(1, 100);
auto *layout = new QVBoxLayout(frame);
layout->addWidget(label);
layout->addLayout(dirlayout);
layout->addLayout(grid);
page->setLayout(layout);
return page;
}
QWizardPage *LammpsGui::tutorial1_finish()
{
auto *page = new QWizardPage;
page->setTitle("Start Tutorial 1");
page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial1-logo.png"));
auto *label = new QLabel("<p align=\"center\">You are now ready to start tutorial 1.</p>\n"
"<hr width=\"33%\"\\>\n"
"<p align=\"center\">Click on the \"Finish\" button to "
"complete the setup.</p>");
label->setWordWrap(true);
auto *layout = new QVBoxLayout;
layout->addWidget(label);
layout->setStretch(0, 100);
page->setLayout(layout);
return page;
}
void LammpsGui::start_tutorial2()
{
if (wizard) delete wizard;
wizard = new Tutorial2Wizard;
wizard->addPage(tutorial2_intro());
wizard->addPage(tutorial2_info());
wizard->addPage(tutorial2_directory());
wizard->addPage(tutorial2_finish());
wizard = new TutorialWizard(2);
const auto infotext =
QString("<p>In tutorial 2 you will learn about setting up a simulation for a molecular "
"system with bonds. The target is to simulate a carbon nanotube with a "
"conventional molecular force field under growing strain and observe the response "
"to it. Since bonds are represented by a harmonic potential, they cannot break. "
"This is then compared to simulating the same system with a reactive force field "
"(AIREBO) where bonds may be broken and formed.</p><hr width=\"33%\"\\>\n<p "
"align=\"center\">Click on the \"Next\" button to select a folder.</p>");
wizard->setFont(font());
wizard->addPage(tutorial_intro(2));
wizard->addPage(tutorial_info(2, infotext));
wizard->addPage(tutorial_directory(2));
wizard->addPage(tutorial_finish(2));
wizard->setWindowTitle("Tutorial 2 Setup Wizard");
wizard->setWizardStyle(QWizard::ModernStyle);
wizard->show();
}
QWizardPage *LammpsGui::tutorial2_intro()
void LammpsGui::start_tutorial3()
{
auto *page = new QWizardPage;
page->setTitle("Getting Started With Tutorial 2");
page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial2-logo.png"));
if (wizard) delete wizard;
wizard = new TutorialWizard(3);
const auto infotext =
QString("<p>In tutorial 3 you will learn about setting up a simulation for a molecular "
"system with bonds. The target is to simulate a carbon nanotube with a "
"conventional molecular force field under growing strain and observe the response "
"to it. Since bonds are represented by a harmonic potential, they cannot break. "
"This is then compared to simulating the same system with a reactive force field "
"(AIREBO) where bonds may be broken and formed.</p><hr width=\"33%\"\\>\n<p "
"align=\"center\">Click on the \"Next\" button to select a folder.</p>");
// XXX TODO: update URL to published tutorial DOI
auto *label =
new QLabel("<p>This wizard will help you to select and populate a folder with "
"materials required to work through tutorial 2 from a fourthcoming "
"LAMMPS tutorial using LAMMPS-GUI by Simon Gravelle, Jake Gissinger, "
"and Axel Kohlmeyer.</p>\n"
"The work-in-progress materials for this tutorial are available at: <a"
"<b><a href=\"https://github.com/lammpstutorials/lammpstutorials-article\">"
"github.com/lammpstutorials/lammpstutorials-article</a></b></p><br>\n"
"<hr width=\"33%\"\\>\n"
"<p align=\"center\">Click on the \"Next\" button to begin.</p>");
label->setWordWrap(true);
auto *layout = new QVBoxLayout;
layout->addWidget(label);
page->setLayout(layout);
return page;
wizard->setFont(font());
wizard->addPage(tutorial_intro(3));
wizard->addPage(tutorial_info(3, infotext));
wizard->addPage(tutorial_directory(3));
wizard->addPage(tutorial_finish(3));
wizard->setWindowTitle("Tutorial 3 Setup Wizard");
wizard->setWizardStyle(QWizard::ModernStyle);
wizard->show();
}
QWizardPage *LammpsGui::tutorial2_info()
void LammpsGui::start_tutorial4()
{
auto *page = new QWizardPage;
page->setTitle("Contents of Tutorial 2");
page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial2-logo.png"));
auto *label =
new QLabel("<p>In tutorial 2 you will learn about setting up a simulation for a molecular "
"system with bonds. The target is to simulate a carbon nanotube with a "
"conventional molecular force field under growing strain and observe the "
"response to it. Since bonds are represented by a harmonic potential, they "
"cannot break. This is then compared to simulating the same system with a "
"reactive force field (AIREBO) where bonds may be broken and formed.</p>"
"<hr width=\"33%\"\\>\n"
"<p align=\"center\">Click on the \"Next\" button to select a folder.</p>");
label->setWordWrap(true);
auto *layout = new QVBoxLayout;
layout->addWidget(label);
page->setLayout(layout);
return page;
if (wizard) delete wizard;
wizard = new TutorialWizard(4);
const auto infotext =
QString("<p>In tutorial 4 you will learn about setting up a simulation for a molecular "
"system with bonds. The target is to simulate a carbon nanotube with a "
"conventional molecular force field under growing strain and observe the response "
"to it. Since bonds are represented by a harmonic potential, they cannot break. "
"This is then compared to simulating the same system with a reactive force field "
"(AIREBO) where bonds may be broken and formed.</p><hr width=\"33%\"\\>\n<p "
"align=\"center\">Click on the \"Next\" button to select a folder.</p>");
wizard->setFont(font());
wizard->addPage(tutorial_intro(4));
wizard->addPage(tutorial_info(4, infotext));
wizard->addPage(tutorial_directory(4));
wizard->addPage(tutorial_finish(4));
wizard->setWindowTitle("Tutorial 4 Setup Wizard");
wizard->setWizardStyle(QWizard::ModernStyle);
wizard->show();
}
QWizardPage *LammpsGui::tutorial2_directory()
void LammpsGui::start_tutorial5()
{
auto *page = new QWizardPage;
page->setTitle("Select Directory for Tutorial 2");
page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial2-logo.png"));
auto *frame = new QFrame;
auto *label = new QLabel(
"<p>Select a directory to store the files for tutorial 2. The directory will be "
"created if necessary and LAMMPS-GUI will download the files required for the "
"tutorial.</p>\n"
"<p>If selected, an existing directory may be cleared.</p>\n"
"<p>Also, available files of the tutorial solution may be downloaded to a "
"folder \"solution\", if requested.</p>\n"
"<hr width=\"33%\">\n");
label->setWordWrap(true);
auto *dirlayout = new QHBoxLayout;
auto *directory = new QLineEdit;
// if we are already in the tutorial folder, stay there
if (!current_dir.endsWith("tutorial2")) {
// if current dir is home, or application folder, switch to desktop path
if ((current_dir == QDir::homePath()) || current_dir.contains("AppData") ||
current_dir.contains("Program Files")) {
current_dir = QStandardPaths::writableLocation(QStandardPaths::DesktopLocation);
}
current_dir += "/tutorial2";
}
directory->setText(current_dir);
auto *dirbutton = new QPushButton("&Choose");
dirlayout->addWidget(directory);
dirlayout->addWidget(dirbutton);
directory->setObjectName("t2_directory");
connect(dirbutton, &QPushButton::released, this, &LammpsGui::get_directory);
auto *grid = new QGridLayout;
auto *purgeval = new QCheckBox;
auto *solval = new QCheckBox;
auto *purgelabel = new QLabel("Remove existing files from directory");
auto *sollabel = new QLabel("Download solutions");
purgeval->setCheckState(Qt::Unchecked);
purgeval->setObjectName("t2_dirpurge");
solval->setCheckState(Qt::Unchecked);
solval->setObjectName("t2_getsolution");
grid->addWidget(purgeval, 0, 0, Qt::AlignVCenter);
grid->addWidget(purgelabel, 0, 1, Qt::AlignVCenter);
grid->addWidget(solval, 1, 0, Qt::AlignVCenter);
grid->addWidget(sollabel, 1, 1, Qt::AlignVCenter);
grid->setColumnStretch(0, 0);
grid->setColumnStretch(1, 100);
auto *layout = new QVBoxLayout(frame);
layout->addWidget(label);
layout->addLayout(dirlayout);
layout->addLayout(grid);
page->setLayout(layout);
return page;
if (wizard) delete wizard;
wizard = new TutorialWizard(5);
const auto infotext =
QString("<p>In tutorial 5 you will learn about setting up a simulation for a molecular "
"system with bonds. The target is to simulate a carbon nanotube with a "
"conventional molecular force field under growing strain and observe the response "
"to it. Since bonds are represented by a harmonic potential, they cannot break. "
"This is then compared to simulating the same system with a reactive force field "
"(AIREBO) where bonds may be broken and formed.</p><hr width=\"33%\"\\>\n<p "
"align=\"center\">Click on the \"Next\" button to select a folder.</p>");
wizard->setFont(font());
wizard->addPage(tutorial_intro(5));
wizard->addPage(tutorial_info(5, infotext));
wizard->addPage(tutorial_directory(5));
wizard->addPage(tutorial_finish(5));
wizard->setWindowTitle("Tutorial 5 Setup Wizard");
wizard->setWizardStyle(QWizard::ModernStyle);
wizard->show();
}
QWizardPage *LammpsGui::tutorial2_finish()
void LammpsGui::start_tutorial6()
{
auto *page = new QWizardPage;
page->setTitle("Start Tutorial 2");
page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial2-logo.png"));
if (wizard) delete wizard;
wizard = new TutorialWizard(6);
const auto infotext =
QString("<p>In tutorial 6 you will learn about setting up a simulation for a molecular "
"system with bonds. The target is to simulate a carbon nanotube with a "
"conventional molecular force field under growing strain and observe the response "
"to it. Since bonds are represented by a harmonic potential, they cannot break. "
"This is then compared to simulating the same system with a reactive force field "
"(AIREBO) where bonds may be broken and formed.</p><hr width=\"33%\"\\>\n<p "
"align=\"center\">Click on the \"Next\" button to select a folder.</p>");
wizard->setFont(font());
wizard->addPage(tutorial_intro(6));
wizard->addPage(tutorial_info(6, infotext));
wizard->addPage(tutorial_directory(6));
wizard->addPage(tutorial_finish(6));
wizard->setWindowTitle("Tutorial 6 Setup Wizard");
wizard->setWizardStyle(QWizard::ModernStyle);
wizard->show();
}
auto *label = new QLabel("<p align=\"center\">You are now ready to start tutorial 2.</p>\n"
"<hr width=\"33%\"\\>\n"
"<p align=\"center\">Click on the \"Finish\" button to "
"complete the setup.</p>");
label->setWordWrap(true);
void LammpsGui::start_tutorial7()
{
if (wizard) delete wizard;
wizard = new TutorialWizard(7);
const auto infotext =
QString("<p>In tutorial 7 you will learn about setting up a simulation for a molecular "
"system with bonds. The target is to simulate a carbon nanotube with a "
"conventional molecular force field under growing strain and observe the response "
"to it. Since bonds are represented by a harmonic potential, they cannot break. "
"This is then compared to simulating the same system with a reactive force field "
"(AIREBO) where bonds may be broken and formed.</p><hr width=\"33%\"\\>\n<p "
"align=\"center\">Click on the \"Next\" button to select a folder.</p>");
wizard->setFont(font());
wizard->addPage(tutorial_intro(7));
wizard->addPage(tutorial_info(7, infotext));
wizard->addPage(tutorial_directory(7));
wizard->addPage(tutorial_finish(7));
wizard->setWindowTitle("Tutorial 7 Setup Wizard");
wizard->setWizardStyle(QWizard::ModernStyle);
wizard->show();
}
auto *layout = new QVBoxLayout;
layout->addWidget(label);
layout->setStretch(0, 100);
page->setLayout(layout);
return page;
void LammpsGui::start_tutorial8()
{
if (wizard) delete wizard;
wizard = new TutorialWizard(8);
const auto infotext =
QString("<p>In tutorial 8 you will learn about setting up a simulation for a molecular "
"system with bonds. The target is to simulate a carbon nanotube with a "
"conventional molecular force field under growing strain and observe the response "
"to it. Since bonds are represented by a harmonic potential, they cannot break. "
"This is then compared to simulating the same system with a reactive force field "
"(AIREBO) where bonds may be broken and formed.</p><hr width=\"33%\"\\>\n<p "
"align=\"center\">Click on the \"Next\" button to select a folder.</p>");
wizard->setFont(font());
wizard->addPage(tutorial_intro(8));
wizard->addPage(tutorial_info(8, infotext));
wizard->addPage(tutorial_directory(8));
wizard->addPage(tutorial_finish(8));
wizard->setWindowTitle("Tutorial 8 Setup Wizard");
wizard->setWizardStyle(QWizard::ModernStyle);
wizard->show();
}
void LammpsGui::howto()
@ -1983,12 +2013,12 @@ void LammpsGui::start_lammps()
lammps.open(narg, args);
lammpsstatus->show();
// must have a version newer than the 2 August 2023 release of LAMMPS
// must have a version newer than the 29 August 2024 release of LAMMPS
// TODO: must update this check before next feature release
if (lammps.version() <= 20230802) {
if (lammps.version() < 20240829) {
QMessageBox::critical(this, "Incompatible LAMMPS Version",
"LAMMPS-GUI version " LAMMPS_GUI_VERSION " requires\n"
"a LAMMPS version more recent than 2 August 2023");
"a LAMMPS version of at least 29 August 2024");
exit(1);
}
@ -2017,7 +2047,8 @@ bool LammpsGui::eventFilter(QObject *watched, QEvent *event)
}
// LAMMPS geturl command with current location of the input and solution files on the web
static const QString geturl = "geturl https://raw.githubusercontent.com/lammpstutorials/"
static const QString geturl =
"geturl https://raw.githubusercontent.com/lammpstutorials/"
"lammpstutorials-article/refs/heads/main/files/tutorial%1/%2 output %2 verify no";
void LammpsGui::setup_tutorial(int tutno, const QString &dir, bool purgedir, bool getsolution)
@ -2071,7 +2102,8 @@ void LammpsGui::setup_tutorial(int tutno, const QString &dir, bool purgedir, boo
if (!first.isEmpty()) open_file(first);
}
Tutorial1Wizard::Tutorial1Wizard(QWidget *parent) : QWizard(parent)
TutorialWizard::TutorialWizard(int ntutorial, QWidget *parent) :
QWizard(parent), _ntutorial(ntutorial)
{
setWindowIcon(QIcon(":/icons/tutorial-logo.png"));
}
@ -2079,12 +2111,12 @@ Tutorial1Wizard::Tutorial1Wizard(QWidget *parent) : QWizard(parent)
// actions to perform when the wizard for tutorial 1 is complete
// and the user has clicked on "Finish"
void Tutorial1Wizard::accept()
void TutorialWizard::accept()
{
// get pointers to the widgets with the information we need
auto *dirname = findChild<QLineEdit *>("t1_directory");
auto *dirpurge = findChild<QCheckBox *>("t1_dirpurge");
auto *getsol = findChild<QCheckBox *>("t1_getsolution");
auto *dirname = findChild<QLineEdit *>("t_directory");
auto *dirpurge = findChild<QCheckBox *>("t_dirpurge");
auto *getsol = findChild<QCheckBox *>("t_getsolution");
// create and populate directory.
if (dirname) {
@ -2092,8 +2124,8 @@ void Tutorial1Wizard::accept()
auto curdir = dirname->text().trimmed();
if (!directory.mkpath(curdir)) {
QMessageBox::warning(this, "Warning",
"Cannot create tutorial 1 working directory " + curdir +
".\n\nGoing back to directory selection.");
"Cannot create tutorial working directory '" + curdir +
"'.\n\nGoing back to directory selection.");
back();
return;
}
@ -2105,46 +2137,7 @@ void Tutorial1Wizard::accept()
LammpsGui *main = nullptr;
for (QWidget *widget : QApplication::topLevelWidgets())
if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget);
if (main) main->setup_tutorial(1, curdir, purgedir, getsolution);
}
QDialog::accept();
}
Tutorial2Wizard::Tutorial2Wizard(QWidget *parent) : QWizard(parent)
{
setWindowIcon(QIcon(":/icons/tutorial-logo.png"));
}
// actions to perform when the wizard for tutorial 2 is complete
// and the user has clicked on "Finish"
void Tutorial2Wizard::accept()
{
// get pointers to the widgets with the information we need
auto *dirname = findChild<QLineEdit *>("t2_directory");
auto *dirpurge = findChild<QCheckBox *>("t2_dirpurge");
auto *getsol = findChild<QCheckBox *>("t2_getsolution");
// create and populate directory.
if (dirname) {
QDir directory;
auto curdir = dirname->text().trimmed();
if (!directory.mkpath(curdir)) {
QMessageBox::warning(this, "Warning",
"Cannot create tutorial 2 working directory " + curdir +
".\n\nGoing back to directory selection.");
back();
return;
}
bool purgedir = dirpurge && (dirpurge->checkState() == Qt::Checked);
bool getsolution = getsol && (getsol->checkState() == Qt::Checked);
// get hold of LAMMPS-GUI main widget
LammpsGui *main = nullptr;
for (QWidget *widget : QApplication::topLevelWidgets())
if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget);
if (main) main->setup_tutorial(2, curdir, purgedir, getsolution);
if (main) main->setup_tutorial(_ntutorial, curdir, purgedir, getsolution);
}
QDialog::accept();
}

View File

@ -64,8 +64,7 @@ class LammpsGui : public QMainWindow {
friend class CodeEditor;
friend class GeneralTab;
friend class Tutorial1Wizard;
friend class Tutorial2Wizard;
friend class TutorialWizard;
public:
LammpsGui(QWidget *parent = nullptr, const QString &filename = QString());
@ -84,15 +83,11 @@ protected:
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);
QWizardPage *tutorial_intro(const int ntutorial);
QWizardPage *tutorial_info(const int ntutorial, const QString &infotext);
QWizardPage *tutorial_directory(const int ntutorial);
QWizardPage *tutorial_finish(const int ntutorial);
void setup_tutorial(int ntutorial, const QString &dir, bool purgedir, bool getsolution);
void purge_inspect_list();
bool eventFilter(QObject *watched, QEvent *event) override;
@ -132,6 +127,12 @@ private slots:
void tutorial_web();
void start_tutorial1();
void start_tutorial2();
void start_tutorial3();
void start_tutorial4();
void start_tutorial5();
void start_tutorial6();
void start_tutorial7();
void start_tutorial8();
void howto();
void logupdate();
void modified();
@ -178,20 +179,14 @@ private:
std::vector<char *> lammps_args;
};
class Tutorial1Wizard : public QWizard {
class TutorialWizard : public QWizard {
Q_OBJECT
public:
Tutorial1Wizard(QWidget *parent = nullptr);
void accept() override;
};
class Tutorial2Wizard : public QWizard {
Q_OBJECT
public:
Tutorial2Wizard(QWidget *parent = nullptr);
TutorialWizard(int ntutorial, QWidget *parent = nullptr);
void accept() override;
private:
int _ntutorial;
};
#endif // LAMMPSGUI_H

View File

@ -87,6 +87,12 @@
</property>
<addaction name="actionTutorial1"/>
<addaction name="actionTutorial2"/>
<addaction name="actionTutorial3"/>
<addaction name="actionTutorial4"/>
<addaction name="actionTutorial5"/>
<addaction name="actionTutorial6"/>
<addaction name="actionTutorial7"/>
<addaction name="actionTutorial8"/>
</widget>
<widget class="QMenu" name="menuAbout">
<property name="title">
@ -510,6 +516,54 @@
<string>Start LAMMPS Tutorial &amp;2</string>
</property>
</action>
<action name="actionTutorial3">
<property name="icon">
<iconset theme=":/icons/tutorial-logo.png"/>
</property>
<property name="text">
<string>Start LAMMPS Tutorial &amp;3</string>
</property>
</action>
<action name="actionTutorial4">
<property name="icon">
<iconset theme=":/icons/tutorial-logo.png"/>
</property>
<property name="text">
<string>Start LAMMPS Tutorial &amp;4</string>
</property>
</action>
<action name="actionTutorial5">
<property name="icon">
<iconset theme=":/icons/tutorial-logo.png"/>
</property>
<property name="text">
<string>Start LAMMPS Tutorial &amp;5</string>
</property>
</action>
<action name="actionTutorial6">
<property name="icon">
<iconset theme=":/icons/tutorial-logo.png"/>
</property>
<property name="text">
<string>Start LAMMPS Tutorial &amp;6</string>
</property>
</action>
<action name="actionTutorial7">
<property name="icon">
<iconset theme=":/icons/tutorial-logo.png"/>
</property>
<property name="text">
<string>Start LAMMPS Tutorial &amp;7</string>
</property>
</action>
<action name="actionTutorial8">
<property name="icon">
<iconset theme=":/icons/tutorial-logo.png"/>
</property>
<property name="text">
<string>Start LAMMPS Tutorial &amp;8</string>
</property>
</action>
<action name="actionLAMMPS_GUI_Howto">
<property name="icon">
<iconset theme=":/icons/system-help.png"/>