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) 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_AUTOUIC ON)
set(CMAKE_AUTOMOC ON) set(CMAKE_AUTOMOC ON)

View File

@ -54,11 +54,17 @@
</provides> </provides>
<releases> <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"> <release version="1.6.11" timestamp="1725080055">
<description> <description>
move cursor to end of log buffer before inserting new text Move cursor to end of log buffer before inserting new text
remove empirical filter to remove outliers from corrupted data Remove empirical filter to remove outliers from corrupted data
change tutorial download URL to tutorial website Change tutorial download URL to tutorial website
</description> </description>
</release> </release>
<release version="1.6.10" timestamp="1724585189"> <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->actionLAMMPS_Tutorial, &QAction::triggered, this, &LammpsGui::tutorial_web);
connect(ui->actionTutorial1, &QAction::triggered, this, &LammpsGui::start_tutorial1); connect(ui->actionTutorial1, &QAction::triggered, this, &LammpsGui::start_tutorial1);
connect(ui->actionTutorial2, &QAction::triggered, this, &LammpsGui::start_tutorial2); 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->actionAbout_LAMMPS_GUI, &QAction::triggered, this, &LammpsGui::about);
connect(ui->action_Help, &QAction::triggered, this, &LammpsGui::help); connect(ui->action_Help, &QAction::triggered, this, &LammpsGui::help);
connect(ui->actionLAMMPS_GUI_Howto, &QAction::triggered, this, &LammpsGui::howto); connect(ui->actionLAMMPS_GUI_Howto, &QAction::triggered, this, &LammpsGui::howto);
@ -438,9 +444,7 @@ void LammpsGui::open_recent()
void LammpsGui::get_directory() void LammpsGui::get_directory()
{ {
if (wizard) { if (wizard) {
// figure out which wizard we are following auto *line = wizard->findChild<QLineEdit *>("t_directory");
auto *line = wizard->findChild<QLineEdit *>("t1_directory");
if (!line) line = wizard->findChild<QLineEdit *>("t2_directory");
if (line) { if (line) {
auto curdir = line->text(); auto curdir = line->text();
QFileDialog dialog(this, "Choose Directory for Tutorial Files", curdir); QFileDialog dialog(this, "Choose Directory for Tutorial Files", curdir);
@ -1560,287 +1564,313 @@ void LammpsGui::tutorial_web()
QDesktopServices::openUrl(QUrl("https://lammpstutorials.github.io/")); 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() void LammpsGui::start_tutorial1()
{ {
if (wizard) delete wizard; 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->setFont(font());
wizard->addPage(tutorial1_intro()); wizard->addPage(tutorial_intro(1));
wizard->addPage(tutorial1_info()); wizard->addPage(tutorial_info(1, infotext));
wizard->addPage(tutorial1_directory()); wizard->addPage(tutorial_directory(1));
wizard->addPage(tutorial1_finish()); wizard->addPage(tutorial_finish(1));
wizard->setWindowTitle("Tutorial 1 Setup Wizard"); wizard->setWindowTitle("Tutorial 1 Setup Wizard");
wizard->setWizardStyle(QWizard::ModernStyle); wizard->setWizardStyle(QWizard::ModernStyle);
wizard->show(); 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() void LammpsGui::start_tutorial2()
{ {
if (wizard) delete wizard; if (wizard) delete wizard;
wizard = new Tutorial2Wizard; wizard = new TutorialWizard(2);
wizard->addPage(tutorial2_intro()); const auto infotext =
wizard->addPage(tutorial2_info()); QString("<p>In tutorial 2 you will learn about setting up a simulation for a molecular "
wizard->addPage(tutorial2_directory()); "system with bonds. The target is to simulate a carbon nanotube with a "
wizard->addPage(tutorial2_finish()); "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->setWindowTitle("Tutorial 2 Setup Wizard");
wizard->setWizardStyle(QWizard::ModernStyle); wizard->setWizardStyle(QWizard::ModernStyle);
wizard->show(); wizard->show();
} }
QWizardPage *LammpsGui::tutorial2_intro() void LammpsGui::start_tutorial3()
{ {
auto *page = new QWizardPage; if (wizard) delete wizard;
page->setTitle("Getting Started With Tutorial 2"); wizard = new TutorialWizard(3);
page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial2-logo.png")); 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 wizard->setFont(font());
auto *label = wizard->addPage(tutorial_intro(3));
new QLabel("<p>This wizard will help you to select and populate a folder with " wizard->addPage(tutorial_info(3, infotext));
"materials required to work through tutorial 2 from a fourthcoming " wizard->addPage(tutorial_directory(3));
"LAMMPS tutorial using LAMMPS-GUI by Simon Gravelle, Jake Gissinger, " wizard->addPage(tutorial_finish(3));
"and Axel Kohlmeyer.</p>\n" wizard->setWindowTitle("Tutorial 3 Setup Wizard");
"The work-in-progress materials for this tutorial are available at: <a" wizard->setWizardStyle(QWizard::ModernStyle);
"<b><a href=\"https://github.com/lammpstutorials/lammpstutorials-article\">" wizard->show();
"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::tutorial2_info() void LammpsGui::start_tutorial4()
{ {
auto *page = new QWizardPage; if (wizard) delete wizard;
page->setTitle("Contents of Tutorial 2"); wizard = new TutorialWizard(4);
page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial2-logo.png")); const auto infotext =
QString("<p>In tutorial 4 you will learn about setting up a simulation for a molecular "
auto *label = "system with bonds. The target is to simulate a carbon nanotube with a "
new QLabel("<p>In tutorial 2 you will learn about setting up a simulation for a molecular " "conventional molecular force field under growing strain and observe the response "
"system with bonds. The target is to simulate a carbon nanotube with a " "to it. Since bonds are represented by a harmonic potential, they cannot break. "
"conventional molecular force field under growing strain and observe the " "This is then compared to simulating the same system with a reactive force field "
"response to it. Since bonds are represented by a harmonic potential, they " "(AIREBO) where bonds may be broken and formed.</p><hr width=\"33%\"\\>\n<p "
"cannot break. This is then compared to simulating the same system with a " "align=\"center\">Click on the \"Next\" button to select a folder.</p>");
"reactive force field (AIREBO) where bonds may be broken and formed.</p>" wizard->setFont(font());
"<hr width=\"33%\"\\>\n" wizard->addPage(tutorial_intro(4));
"<p align=\"center\">Click on the \"Next\" button to select a folder.</p>"); wizard->addPage(tutorial_info(4, infotext));
label->setWordWrap(true); wizard->addPage(tutorial_directory(4));
wizard->addPage(tutorial_finish(4));
auto *layout = new QVBoxLayout; wizard->setWindowTitle("Tutorial 4 Setup Wizard");
layout->addWidget(label); wizard->setWizardStyle(QWizard::ModernStyle);
page->setLayout(layout); wizard->show();
return page;
} }
QWizardPage *LammpsGui::tutorial2_directory() void LammpsGui::start_tutorial5()
{ {
auto *page = new QWizardPage; if (wizard) delete wizard;
page->setTitle("Select Directory for Tutorial 2"); wizard = new TutorialWizard(5);
page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial2-logo.png")); const auto infotext =
QString("<p>In tutorial 5 you will learn about setting up a simulation for a molecular "
auto *frame = new QFrame; "system with bonds. The target is to simulate a carbon nanotube with a "
auto *label = new QLabel( "conventional molecular force field under growing strain and observe the response "
"<p>Select a directory to store the files for tutorial 2. The directory will be " "to it. Since bonds are represented by a harmonic potential, they cannot break. "
"created if necessary and LAMMPS-GUI will download the files required for the " "This is then compared to simulating the same system with a reactive force field "
"tutorial.</p>\n" "(AIREBO) where bonds may be broken and formed.</p><hr width=\"33%\"\\>\n<p "
"<p>If selected, an existing directory may be cleared.</p>\n" "align=\"center\">Click on the \"Next\" button to select a folder.</p>");
"<p>Also, available files of the tutorial solution may be downloaded to a " wizard->setFont(font());
"folder \"solution\", if requested.</p>\n" wizard->addPage(tutorial_intro(5));
"<hr width=\"33%\">\n"); wizard->addPage(tutorial_info(5, infotext));
label->setWordWrap(true); wizard->addPage(tutorial_directory(5));
wizard->addPage(tutorial_finish(5));
auto *dirlayout = new QHBoxLayout; wizard->setWindowTitle("Tutorial 5 Setup Wizard");
auto *directory = new QLineEdit; wizard->setWizardStyle(QWizard::ModernStyle);
// if we are already in the tutorial folder, stay there wizard->show();
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;
} }
QWizardPage *LammpsGui::tutorial2_finish() void LammpsGui::start_tutorial6()
{ {
auto *page = new QWizardPage; if (wizard) delete wizard;
page->setTitle("Start Tutorial 2"); wizard = new TutorialWizard(6);
page->setPixmap(QWizard::WatermarkPixmap, QPixmap(":/icons/tutorial2-logo.png")); 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" void LammpsGui::start_tutorial7()
"<hr width=\"33%\"\\>\n" {
"<p align=\"center\">Click on the \"Finish\" button to " if (wizard) delete wizard;
"complete the setup.</p>"); wizard = new TutorialWizard(7);
label->setWordWrap(true); 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; void LammpsGui::start_tutorial8()
layout->addWidget(label); {
layout->setStretch(0, 100); if (wizard) delete wizard;
wizard = new TutorialWizard(8);
page->setLayout(layout); const auto infotext =
return page; 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() void LammpsGui::howto()
@ -1983,12 +2013,12 @@ void LammpsGui::start_lammps()
lammps.open(narg, args); lammps.open(narg, args);
lammpsstatus->show(); 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 // TODO: must update this check before next feature release
if (lammps.version() <= 20230802) { if (lammps.version() < 20240829) {
QMessageBox::critical(this, "Incompatible LAMMPS Version", QMessageBox::critical(this, "Incompatible LAMMPS Version",
"LAMMPS-GUI version " LAMMPS_GUI_VERSION " requires\n" "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); 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 // 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"; "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) 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); 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")); 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 // actions to perform when the wizard for tutorial 1 is complete
// and the user has clicked on "Finish" // and the user has clicked on "Finish"
void Tutorial1Wizard::accept() void TutorialWizard::accept()
{ {
// get pointers to the widgets with the information we need // get pointers to the widgets with the information we need
auto *dirname = findChild<QLineEdit *>("t1_directory"); auto *dirname = findChild<QLineEdit *>("t_directory");
auto *dirpurge = findChild<QCheckBox *>("t1_dirpurge"); auto *dirpurge = findChild<QCheckBox *>("t_dirpurge");
auto *getsol = findChild<QCheckBox *>("t1_getsolution"); auto *getsol = findChild<QCheckBox *>("t_getsolution");
// create and populate directory. // create and populate directory.
if (dirname) { if (dirname) {
@ -2092,8 +2124,8 @@ void Tutorial1Wizard::accept()
auto curdir = dirname->text().trimmed(); auto curdir = dirname->text().trimmed();
if (!directory.mkpath(curdir)) { if (!directory.mkpath(curdir)) {
QMessageBox::warning(this, "Warning", QMessageBox::warning(this, "Warning",
"Cannot create tutorial 1 working directory " + curdir + "Cannot create tutorial working directory '" + curdir +
".\n\nGoing back to directory selection."); "'.\n\nGoing back to directory selection.");
back(); back();
return; return;
} }
@ -2105,46 +2137,7 @@ void Tutorial1Wizard::accept()
LammpsGui *main = nullptr; LammpsGui *main = nullptr;
for (QWidget *widget : QApplication::topLevelWidgets()) for (QWidget *widget : QApplication::topLevelWidgets())
if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget); if (widget->objectName() == "LammpsGui") main = dynamic_cast<LammpsGui *>(widget);
if (main) main->setup_tutorial(1, curdir, purgedir, getsolution); if (main) main->setup_tutorial(_ntutorial, 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);
} }
QDialog::accept(); QDialog::accept();
} }

View File

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

View File

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