672 lines
24 KiB
C++
672 lines
24 KiB
C++
#include <QtWidgets>
|
|
#include <assert.h>
|
|
#include <cmath>
|
|
#include <thread>
|
|
#include <chrono>
|
|
#include "boost/format.hpp"
|
|
#include "mainwindow.h"
|
|
|
|
#include "csv_parser.h"
|
|
#include "options.h"
|
|
#include "threed_beam_fea.h"
|
|
|
|
#include "rapidjson/writer.h"
|
|
#include "rapidjson/stringbuffer.h"
|
|
|
|
MainWindow::MainWindow(QWidget *parent) : QMainWindow(parent)
|
|
{
|
|
createMenu();
|
|
createChooseFilesGroupBox();
|
|
createOptionsGroupBox();
|
|
createSubmitGroupBox();
|
|
createStatusBar();
|
|
|
|
readSettings();
|
|
|
|
QVBoxLayout *mainLayout = new QVBoxLayout;
|
|
mainLayout->setMenuBar(menuBar);
|
|
mainLayout->addWidget(chooseFilesGroupBox);
|
|
mainLayout->addWidget(optionsGroupBox);
|
|
mainLayout->addWidget(submitGroupBox);
|
|
|
|
QWidget *widget = new QWidget();
|
|
widget->setLayout(mainLayout);
|
|
setCentralWidget(widget);
|
|
|
|
feaProgram = QCoreApplication::applicationDirPath().toStdString() + "/fea_cmd";
|
|
feaTmpConfigFilename = QCoreApplication::applicationDirPath().toStdString() +"/tmp_config.json";
|
|
setMinimumWidth(600);
|
|
|
|
setWindowTitle(tr("3D Beam FEA"));
|
|
setWindowIcon(QIcon(":images/logo_64x64.png"));
|
|
setUnifiedTitleAndToolBarOnMac(true);
|
|
}
|
|
|
|
void MainWindow::closeEvent(QCloseEvent *event)
|
|
{
|
|
writeSettings();
|
|
event->accept();
|
|
}
|
|
|
|
void MainWindow::open() {
|
|
QString filename = QFileDialog::getOpenFileName(this);
|
|
if (!filename.isEmpty()) {
|
|
|
|
try {
|
|
rapidjson::Document config_doc = fea::parseJSONConfig(filename.toStdString());
|
|
loadOptionsFromConfig(config_doc);
|
|
statusBar()->showMessage(tr("File loaded"), 2000);
|
|
}
|
|
catch (std::exception &e) {
|
|
std::cerr << "error: " << e.what() << std::endl;
|
|
QMessageBox::critical(this, QString("Error"), QString(e.what()));
|
|
statusBar()->showMessage(tr("Error loading file"), 2000);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::save() {
|
|
QString filename = QFileDialog::getSaveFileName(this);
|
|
if (!filename.isEmpty()) {
|
|
rapidjson::Document config_doc = createConfigDoc();
|
|
try {
|
|
writeConfigDocToFile(config_doc, filename.toStdString());
|
|
statusBar()->showMessage(tr("File saved"), 2000);
|
|
}
|
|
catch (std::exception &e) {
|
|
std::cerr << "error: " << e.what() << std::endl;
|
|
QString message_title("Error");
|
|
QString message_text(e.what());
|
|
QMessageBox::critical(this, message_title, message_text);
|
|
setEnabled(true);
|
|
}
|
|
}
|
|
}
|
|
|
|
void MainWindow::handleFinishedFEA(int exitCode, QProcess::ExitStatus exitStatus) {
|
|
if (exitStatus == QProcess::NormalExit && !feaTerminated) {
|
|
QString message_text;
|
|
if (progress) {
|
|
progress->done(QDialog::Accepted);
|
|
message_text = progress->labelText();
|
|
delete progress;
|
|
}
|
|
removeTmpFiles();
|
|
|
|
message_text.insert(0, "<pre>");
|
|
message_text.append("</pre>");
|
|
|
|
QMessageBox *message = new QMessageBox(QMessageBox::Information, "Summary", message_text, QMessageBox::Ok, this);
|
|
message->exec();
|
|
setEnabled(true);
|
|
}
|
|
}
|
|
|
|
void MainWindow::handleCanceledFEA() {
|
|
feaTerminated = true;
|
|
QString error_text(feaProcess->readAllStandardError());
|
|
feaProcess->kill();
|
|
removeTmpFiles();
|
|
if (progress) {
|
|
progress->done(QDialog::Accepted);
|
|
delete progress;
|
|
}
|
|
if (!error_text.isEmpty()) {
|
|
QMessageBox::critical(this, "FEA exited with error(s)", error_text);
|
|
}
|
|
|
|
statusBar()->showMessage(tr("Analysis aborted"), 2000);
|
|
setEnabled(true);
|
|
}
|
|
|
|
void MainWindow::submit() {
|
|
if(checkFilesReady()) {
|
|
progress = new QProgressDialog("Solving analysis...", "Abort", 0, 0);
|
|
progress->setWindowModality(Qt::WindowModal);
|
|
statusBar()->showMessage(tr("Analysis submitted"), 0);
|
|
setEnabled(false);
|
|
progress->show();
|
|
|
|
solveFEA();
|
|
}
|
|
}
|
|
|
|
void MainWindow::setNodesText() {
|
|
QString filename = QFileDialog::getOpenFileName(this, tr("Select nodes"), QDir::currentPath(), tr("Data files (*.txt *.csv);; All files (*)"));
|
|
if (!filename.isEmpty()) {
|
|
nodesLineEdit->setText(filename);
|
|
}
|
|
}
|
|
|
|
void MainWindow::setElemsText() {
|
|
QString filename = QFileDialog::getOpenFileName(this, tr("Select elements"), QDir::currentPath(), tr("Data files (*.txt *.csv);; All files (*)"));
|
|
if (!filename.isEmpty()) {
|
|
elemsLineEdit->setText(filename);
|
|
}
|
|
}
|
|
|
|
void MainWindow::setPropsText() {
|
|
QString filename = QFileDialog::getOpenFileName(this, tr("Select properties"), QDir::currentPath(), tr("Data files (*.txt *.csv);; All files (*)"));
|
|
if (!filename.isEmpty()) {
|
|
propsLineEdit->setText(filename);
|
|
}
|
|
}
|
|
|
|
void MainWindow::setBCsText() {
|
|
QString filename = QFileDialog::getOpenFileName(this, tr("Select boundary conditions"), QDir::currentPath(), tr("Data files (*.txt *.csv);; All files (*)"));
|
|
if (!filename.isEmpty()) {
|
|
bcsLineEdit->setText(filename);
|
|
}
|
|
}
|
|
|
|
void MainWindow::setForcesText() {
|
|
QString filename = QFileDialog::getOpenFileName(this, tr("Select forces"), QDir::currentPath(), tr("Data files (*.txt *.csv);; All files (*)"));
|
|
if (!filename.isEmpty()) {
|
|
forcesLineEdit->setText(filename);
|
|
}
|
|
}
|
|
|
|
void MainWindow::setTiesText() {
|
|
QString filename = QFileDialog::getOpenFileName(this, tr("Select ties"), QDir::currentPath(), tr("Data files (*.txt *.csv);; All files (*)"));
|
|
if (!filename.isEmpty()) {
|
|
tiesLineEdit->setText(filename);
|
|
}
|
|
}
|
|
|
|
void MainWindow::setEquationsText() {
|
|
QString filename = QFileDialog::getOpenFileName(this, tr("Select equations"), QDir::currentPath(), tr("Data files (*.txt *.csv);; All files (*)"));
|
|
if (!filename.isEmpty()) {
|
|
equationsLineEdit->setText(filename);
|
|
}
|
|
}
|
|
|
|
void MainWindow::updateProgressText() {
|
|
if (progress) {
|
|
progress->setLabelText(QString(feaProcess->readAllStandardOutput()));
|
|
}
|
|
}
|
|
|
|
void MainWindow::createMenu()
|
|
{
|
|
menuBar = new QMenuBar;
|
|
|
|
fileMenu = new QMenu(tr("&File"), this);
|
|
openAction = fileMenu->addAction(QIcon(":/images/default-document-open.png"), tr("&Open"));
|
|
openAction->setStatusTip(tr("Open an existing file"));
|
|
saveAction = fileMenu->addAction(QIcon(":/images/document-save.png"), tr("&Save"));
|
|
saveAction->setStatusTip(tr("Save configuration file"));
|
|
exitAction = fileMenu->addAction(QIcon(":/images/window-close.png"), tr("E&xit"));
|
|
exitAction->setStatusTip(tr("Exit the application"));
|
|
menuBar->addMenu(fileMenu);
|
|
|
|
connect(openAction, SIGNAL(triggered()), this, SLOT(open()));
|
|
connect(saveAction, SIGNAL(triggered()), this, SLOT(save()));
|
|
connect(exitAction, SIGNAL(triggered()), this, SLOT(close()));
|
|
}
|
|
|
|
void MainWindow::createStatusBar()
|
|
{
|
|
statusBar()->showMessage(tr("Ready"));
|
|
}
|
|
|
|
void MainWindow::initializeChooseFilesRow(QGridLayout *glayout,
|
|
QLineEdit* line_edit,
|
|
QPushButton* button,
|
|
int row_number) {
|
|
line_edit->setPlaceholderText("No file chosen...");
|
|
glayout->addWidget(button, row_number, 0);
|
|
glayout->addWidget(line_edit, row_number, 1);
|
|
}
|
|
|
|
void MainWindow::createChooseFilesGroupBox()
|
|
{
|
|
chooseFilesGroupBox = new QGroupBox(tr("Choose files"));
|
|
QGridLayout *glayout = new QGridLayout;
|
|
int row_counter = 0;
|
|
|
|
nodesLineEdit = new QLineEdit(this);
|
|
loadNodesButton = new QPushButton("Nodes");
|
|
loadNodesButton->setStatusTip(tr("Choose file containing nodal coordinates"));
|
|
initializeChooseFilesRow(glayout,
|
|
nodesLineEdit,
|
|
loadNodesButton,
|
|
row_counter++);
|
|
connect(loadNodesButton, &QPushButton::clicked, this, &MainWindow::setNodesText);
|
|
|
|
elemsLineEdit = new QLineEdit();
|
|
loadElemsButton = new QPushButton("Elements");
|
|
loadElemsButton->setStatusTip(tr("Choose file containing element indices"));
|
|
initializeChooseFilesRow(glayout,
|
|
elemsLineEdit,
|
|
loadElemsButton,
|
|
row_counter++);
|
|
connect(loadElemsButton, &QPushButton::clicked, this, &MainWindow::setElemsText);
|
|
|
|
propsLineEdit = new QLineEdit();
|
|
loadPropsButton = new QPushButton("Properties");
|
|
loadPropsButton->setStatusTip(tr("Choose file containing elemental properties"));
|
|
initializeChooseFilesRow(glayout,
|
|
propsLineEdit,
|
|
loadPropsButton,
|
|
row_counter++);
|
|
connect(loadPropsButton, &QPushButton::clicked, this, &MainWindow::setPropsText);
|
|
|
|
bcsLineEdit = new QLineEdit();
|
|
loadBCsButton = new QPushButton("Boundary conditions");
|
|
loadBCsButton->setStatusTip(tr("Choose file containing boundary conditions"));
|
|
initializeChooseFilesRow(glayout,
|
|
bcsLineEdit,
|
|
loadBCsButton,
|
|
row_counter++);
|
|
connect(loadBCsButton, &QPushButton::clicked, this, &MainWindow::setBCsText);
|
|
|
|
forcesLineEdit = new QLineEdit();
|
|
loadForcesButton = new QPushButton("Prescribed forces");
|
|
loadForcesButton->setStatusTip(tr("Choose file containing prescribed forces"));
|
|
initializeChooseFilesRow(glayout,
|
|
forcesLineEdit,
|
|
loadForcesButton,
|
|
row_counter++);
|
|
connect(loadForcesButton, &QPushButton::clicked, this, &MainWindow::setForcesText);
|
|
|
|
tiesLineEdit = new QLineEdit();
|
|
loadTiesButton = new QPushButton("Ties");
|
|
loadTiesButton->setStatusTip(tr("Choose file containing ties"));
|
|
initializeChooseFilesRow(glayout,
|
|
tiesLineEdit,
|
|
loadTiesButton,
|
|
row_counter++);
|
|
connect(loadTiesButton, &QPushButton::clicked, this, &MainWindow::setTiesText);
|
|
|
|
equationsLineEdit = new QLineEdit();
|
|
loadEquationsButton = new QPushButton("Equations");
|
|
loadEquationsButton->setStatusTip(tr("Choose file containing equation constraints"));
|
|
initializeChooseFilesRow(glayout,
|
|
equationsLineEdit,
|
|
loadEquationsButton,
|
|
row_counter++);
|
|
connect(loadEquationsButton, &QPushButton::clicked, this, &MainWindow::setEquationsText);
|
|
|
|
chooseFilesGroupBox->setLayout(glayout);
|
|
}
|
|
|
|
void MainWindow::createOptionsGroupBox()
|
|
{
|
|
optionsGroupBox = new QGroupBox(tr("Options"));
|
|
QGridLayout *glayout = new QGridLayout;
|
|
|
|
int row_counter = 0;
|
|
|
|
nodalDispCheckBox = new QCheckBox(tr("Save nodal displacements"));
|
|
nodalDispCheckBox->setLayoutDirection(Qt::RightToLeft);
|
|
nodalDispCheckBox->setChecked(false);
|
|
nodalDispLineEdit = new QLineEdit(tr("nodal_displacements.csv"));
|
|
nodalDispLineEdit->setDisabled(true);
|
|
connect(nodalDispCheckBox, SIGNAL(toggled(bool)), nodalDispLineEdit, SLOT(setEnabled(bool)));
|
|
glayout->addWidget(nodalDispCheckBox, row_counter, 0);
|
|
glayout->addWidget(nodalDispLineEdit, row_counter, 1, 1, 5);
|
|
|
|
nodalForcesCheckBox = new QCheckBox(tr("Save nodal forces"));
|
|
nodalForcesCheckBox->setLayoutDirection(Qt::RightToLeft);
|
|
nodalForcesCheckBox->setChecked(false);
|
|
nodalForcesLineEdit = new QLineEdit(tr("nodal_forces.csv"));
|
|
nodalForcesLineEdit->setDisabled(true);
|
|
connect(nodalForcesCheckBox, SIGNAL(toggled(bool)), nodalForcesLineEdit, SLOT(setEnabled(bool)));
|
|
glayout->addWidget(nodalForcesCheckBox, ++row_counter, 0);
|
|
glayout->addWidget(nodalForcesLineEdit, row_counter, 1, 1, 5);
|
|
|
|
tieForcesCheckBox = new QCheckBox(tr("Save tie forces"));
|
|
tieForcesCheckBox->setLayoutDirection(Qt::RightToLeft);
|
|
tieForcesCheckBox->setChecked(false);
|
|
tieForcesLineEdit = new QLineEdit(tr("tie_forces.csv"));
|
|
tieForcesLineEdit->setDisabled(true);
|
|
connect(tieForcesCheckBox, SIGNAL(toggled(bool)), tieForcesLineEdit, SLOT(setEnabled(bool)));
|
|
glayout->addWidget(tieForcesCheckBox, ++row_counter, 0);
|
|
glayout->addWidget(tieForcesLineEdit, row_counter, 1, 1, 5);
|
|
|
|
reportCheckBox = new QCheckBox(tr("Save report"));
|
|
reportCheckBox->setLayoutDirection(Qt::RightToLeft);
|
|
reportCheckBox->setChecked(false);
|
|
reportLineEdit = new QLineEdit(tr("report.txt"));
|
|
reportLineEdit->setDisabled(true);
|
|
connect(reportCheckBox, SIGNAL(toggled(bool)), reportLineEdit, SLOT(setEnabled(bool)));
|
|
glayout->addWidget(reportCheckBox, ++row_counter, 0);
|
|
glayout->addWidget(reportLineEdit, row_counter, 1, 1, 5);
|
|
|
|
epsilonLabel = new QLabel(tr("epsilon\t1E"));
|
|
epsilonSpinBox = new QSpinBox();
|
|
epsilonSpinBox->setMinimum(-16);
|
|
epsilonSpinBox->setMaximum(0);
|
|
epsilonSpinBox->setValue(-14);
|
|
epsilonSpinBox->setMaximumWidth(50);
|
|
|
|
precisionLabel = new QLabel(tr("csv precision"));
|
|
precisionSpinBox = new QSpinBox();
|
|
precisionSpinBox->setMinimum(0);
|
|
precisionSpinBox->setMaximum(16);
|
|
precisionSpinBox->setValue(8);
|
|
precisionSpinBox->setMaximumWidth(50);
|
|
|
|
delimiterLabel = new QLabel(tr("csv delimiter"));
|
|
delimiterLineEdit = new QLineEdit(tr(","));
|
|
delimiterLineEdit->setMaximumWidth(50);
|
|
|
|
glayout->addWidget(epsilonLabel, ++row_counter, 0, Qt::AlignRight);
|
|
glayout->addWidget(epsilonSpinBox, row_counter, 1);
|
|
|
|
glayout->addWidget(precisionLabel, row_counter, 2, Qt::AlignRight);
|
|
glayout->addWidget(precisionSpinBox, row_counter, 3);
|
|
|
|
glayout->addWidget(delimiterLabel, row_counter, 4, Qt::AlignRight);
|
|
glayout->addWidget(delimiterLineEdit, row_counter, 5);
|
|
|
|
optionsGroupBox->setLayout(glayout);
|
|
}
|
|
|
|
void MainWindow::createSubmitGroupBox() {
|
|
submitGroupBox = new QGroupBox();
|
|
QGridLayout *glayout = new QGridLayout();
|
|
submitButton = new QPushButton("Submit");
|
|
glayout->addWidget(submitButton, 0, 0, Qt::AlignRight);
|
|
submitGroupBox->setLayout(glayout);
|
|
submitGroupBox->setMaximumHeight(80);
|
|
connect(submitButton, SIGNAL(clicked()), this, SLOT(submit()));
|
|
}
|
|
|
|
bool MainWindow::checkFileOpens(const std::string &filename) {
|
|
FILE* file_ptr = fopen(filename.c_str(), "r");
|
|
if (!file_ptr) {
|
|
return false;
|
|
}
|
|
else {
|
|
fclose(file_ptr);
|
|
return true;
|
|
}
|
|
}
|
|
|
|
bool MainWindow::checkFilesReady() {
|
|
int errorCounter = 0;
|
|
QString message_text("");
|
|
|
|
if(!checkFileOpens(feaProgram)){
|
|
++errorCounter;
|
|
message_text.append("Unable to find command line application `fea_gui`.\n"
|
|
"The command line application should be in the same"
|
|
"directory as the gui.\n\n");
|
|
}
|
|
if (nodesLineEdit->displayText().isEmpty()) {
|
|
++errorCounter;
|
|
message_text.append("No file for nodes selected.\n");
|
|
}
|
|
else {
|
|
std::string filename = nodesLineEdit->displayText().toStdString();
|
|
if (!checkFileOpens(filename))
|
|
{
|
|
++errorCounter;
|
|
message_text.append("Unable to open file selected for nodes.\n");
|
|
}
|
|
}
|
|
if (elemsLineEdit->displayText().isEmpty()) {
|
|
++errorCounter;
|
|
message_text.append("No file for elements selected.\n");
|
|
}
|
|
else {
|
|
std::string filename = elemsLineEdit->displayText().toStdString();
|
|
if (!checkFileOpens(filename))
|
|
{
|
|
++errorCounter;
|
|
message_text.append("Unable to open file selected for elements.\n");
|
|
}
|
|
}
|
|
if (propsLineEdit->displayText().isEmpty()) {
|
|
++errorCounter;
|
|
message_text.append("No file for properties selected.\n");
|
|
}
|
|
else {
|
|
std::string filename = propsLineEdit->displayText().toStdString();
|
|
if (!checkFileOpens(filename))
|
|
{
|
|
++errorCounter;
|
|
message_text.append("Unable to open file selected for properties.\n");
|
|
}
|
|
}
|
|
if (bcsLineEdit->displayText().isEmpty() && forcesLineEdit->displayText().isEmpty()) {
|
|
++errorCounter;
|
|
message_text.append("No prescribed boundary conditions or forces.\n");
|
|
}
|
|
if (!bcsLineEdit->displayText().isEmpty())
|
|
{
|
|
std::string filename = bcsLineEdit->displayText().toStdString();
|
|
if (!checkFileOpens(filename))
|
|
{
|
|
++errorCounter;
|
|
message_text.append("Unable to open file selected for boundary conditions.\n");
|
|
}
|
|
}
|
|
if (!forcesLineEdit->displayText().isEmpty())
|
|
{
|
|
std::string filename = forcesLineEdit->displayText().toStdString();
|
|
if (!checkFileOpens(filename))
|
|
{
|
|
++errorCounter;
|
|
message_text.append("Unable to open file selected for forces.\n");
|
|
}
|
|
}
|
|
if (!tiesLineEdit->displayText().isEmpty())
|
|
{
|
|
std::string filename = tiesLineEdit->displayText().toStdString();
|
|
if (!checkFileOpens(filename))
|
|
{
|
|
++errorCounter;
|
|
message_text.append("Unable to open file selected for ties.\n");
|
|
}
|
|
}
|
|
|
|
bool isReady = true;
|
|
if(errorCounter > 0) {
|
|
QString message_title(tr("%1 Error(s) found.").arg(QString::number(errorCounter)));
|
|
QMessageBox::critical(this, message_title, message_text);
|
|
isReady = false;
|
|
}
|
|
|
|
return isReady;
|
|
}
|
|
|
|
rapidjson::Document MainWindow::createConfigDoc() {
|
|
|
|
char json[] = "{}";
|
|
rapidjson::Document config_doc;
|
|
config_doc.ParseInsitu(json);
|
|
|
|
addMemberToDoc(config_doc, "nodes", nodesLineEdit->displayText().toStdString());
|
|
addMemberToDoc(config_doc, "elems", elemsLineEdit->displayText().toStdString());
|
|
addMemberToDoc(config_doc, "props", propsLineEdit->displayText().toStdString());
|
|
|
|
if (!bcsLineEdit->displayText().isEmpty()) {
|
|
addMemberToDoc(config_doc, "bcs", bcsLineEdit->displayText().toStdString());
|
|
}
|
|
if (!forcesLineEdit->displayText().isEmpty()) {
|
|
addMemberToDoc(config_doc, "forces", forcesLineEdit->displayText().toStdString());
|
|
}
|
|
if (!tiesLineEdit->displayText().isEmpty()) {
|
|
addMemberToDoc(config_doc, "ties", tiesLineEdit->displayText().toStdString());
|
|
}
|
|
|
|
addOptionsToDoc(config_doc);
|
|
|
|
return config_doc;
|
|
}
|
|
|
|
void MainWindow::addMemberToDoc(rapidjson::Document &doc,
|
|
const std::string &key,
|
|
const std::string &value) {
|
|
|
|
rapidjson::Value rj_key;
|
|
rj_key.SetString(key.c_str(), key.length(), doc.GetAllocator());
|
|
|
|
rapidjson::Value rj_val;
|
|
rj_val.SetString(value.c_str(), value.length(), doc.GetAllocator());
|
|
|
|
doc.AddMember(rj_key, rj_val, doc.GetAllocator());
|
|
}
|
|
|
|
void MainWindow::addOptionsToDoc(rapidjson::Document &doc) {
|
|
rapidjson::Value options(rapidjson::kObjectType);
|
|
|
|
if (nodalDispCheckBox->isChecked()) {
|
|
options.AddMember("save_nodal_displacements", true, doc.GetAllocator());
|
|
rapidjson::Value rj_val;
|
|
std::string val = nodalDispLineEdit->displayText().toStdString();
|
|
rj_val.SetString(val.c_str(), val.length(), doc.GetAllocator());
|
|
options.AddMember("nodal_displacements_filename", rj_val, doc.GetAllocator());
|
|
}
|
|
if (nodalForcesCheckBox->isChecked()) {
|
|
options.AddMember("save_nodal_forces", true, doc.GetAllocator());
|
|
rapidjson::Value rj_val;
|
|
std::string val = nodalForcesLineEdit->displayText().toStdString();
|
|
rj_val.SetString(val.c_str(), val.length(), doc.GetAllocator());
|
|
options.AddMember("nodal_forces_filename", rj_val, doc.GetAllocator());
|
|
}
|
|
if (tieForcesCheckBox->isChecked()) {
|
|
options.AddMember("save_tie_forces", true, doc.GetAllocator());
|
|
rapidjson::Value rj_val;
|
|
std::string val = tieForcesLineEdit->displayText().toStdString();
|
|
rj_val.SetString(val.c_str(), val.length(), doc.GetAllocator());
|
|
options.AddMember("ties_forces_filename", rj_val, doc.GetAllocator());
|
|
}
|
|
if (reportCheckBox->isChecked()) {
|
|
options.AddMember("save_report", true, doc.GetAllocator());
|
|
rapidjson::Value rj_val;
|
|
std::string val = tieForcesLineEdit->displayText().toStdString();
|
|
rj_val.SetString(val.c_str(), val.length(), doc.GetAllocator());
|
|
options.AddMember("report_filename", rj_val, doc.GetAllocator());
|
|
}
|
|
options.AddMember("verbose", true, doc.GetAllocator());
|
|
doc.AddMember("options", options, doc.GetAllocator());
|
|
}
|
|
|
|
void MainWindow::writeConfigDocToFile(const rapidjson::Document &doc,
|
|
const std::string &filename) {
|
|
rapidjson::StringBuffer buffer;
|
|
rapidjson::Writer<rapidjson::StringBuffer> writer(buffer);
|
|
doc.Accept(writer);
|
|
|
|
std::ofstream output_file;
|
|
output_file.open(filename);
|
|
|
|
if (!output_file.is_open()) {
|
|
throw std::runtime_error(
|
|
(boost::format("Could not open file %s.") % filename).str()
|
|
);
|
|
}
|
|
else {
|
|
output_file << buffer.GetString();
|
|
output_file.close();
|
|
}
|
|
}
|
|
|
|
void MainWindow::readSettings()
|
|
{
|
|
QSettings settings("Latture", "beam-fea");
|
|
QPoint pos = settings.value("pos", QPoint(200, 200)).toPoint();
|
|
QSize size = settings.value("size", QSize(640, 480)).toSize();
|
|
resize(size);
|
|
move(pos);
|
|
}
|
|
|
|
void MainWindow::writeSettings()
|
|
{
|
|
QSettings settings("Latture", "beam-fea");
|
|
settings.setValue("pos", pos());
|
|
settings.setValue("size", size());
|
|
}
|
|
|
|
void MainWindow::removeTmpFiles() {
|
|
remove(feaTmpConfigFilename.c_str());
|
|
}
|
|
|
|
void MainWindow::setLineEditTextFromConfig(QLineEdit *ledit, const std::string &variable, const rapidjson::Document &config_doc) {
|
|
if (config_doc.HasMember(variable.c_str())) {
|
|
if (!config_doc[variable.c_str()].IsString()){
|
|
throw std::runtime_error(
|
|
(boost::format("Value associated with variable %s is not a string.") % variable).str()
|
|
);
|
|
}
|
|
ledit->setText(tr(config_doc[variable.c_str()].GetString()));
|
|
}
|
|
}
|
|
|
|
void MainWindow::loadOptionsFromConfig(const rapidjson::Document &config_doc) {
|
|
|
|
try {
|
|
setLineEditTextFromConfig(nodesLineEdit, "nodes", config_doc);
|
|
setLineEditTextFromConfig(elemsLineEdit, "elems", config_doc);
|
|
setLineEditTextFromConfig(propsLineEdit, "props", config_doc);
|
|
setLineEditTextFromConfig(bcsLineEdit, "bcs", config_doc);
|
|
setLineEditTextFromConfig(tiesLineEdit, "ties", config_doc);
|
|
setLineEditTextFromConfig(forcesLineEdit, "forces", config_doc);
|
|
|
|
fea::Options options = fea::createOptionsFromJSON(config_doc);
|
|
|
|
epsilonSpinBox->setValue(std::log10(options.epsilon));
|
|
precisionSpinBox->setValue(options.csv_precision);
|
|
delimiterLineEdit->setText(tr(options.csv_delimiter.c_str()));
|
|
if (options.save_nodal_displacements) {
|
|
nodalDispCheckBox->setChecked(true);
|
|
nodalDispLineEdit->setText(tr(options.nodal_displacements_filename.c_str()));
|
|
}
|
|
else {
|
|
nodalDispCheckBox->setChecked(false);
|
|
}
|
|
if (options.save_nodal_forces) {
|
|
nodalForcesCheckBox->setChecked(true);
|
|
nodalForcesLineEdit->setText(tr(options.nodal_forces_filename.c_str()));
|
|
}
|
|
else {
|
|
nodalForcesCheckBox->setChecked(false);
|
|
}
|
|
if (options.save_tie_forces) {
|
|
tieForcesCheckBox->setChecked(true);
|
|
tieForcesLineEdit->setText(tr(options.tie_forces_filename.c_str()));
|
|
}
|
|
else {
|
|
tieForcesCheckBox->setChecked(false);
|
|
}
|
|
if (options.save_report) {
|
|
reportCheckBox->setChecked(true);
|
|
reportLineEdit->setText(tr(options.report_filename.c_str()));
|
|
}
|
|
else {
|
|
reportCheckBox->setChecked(false);
|
|
}
|
|
}
|
|
catch (std::exception &e) {
|
|
throw;
|
|
}
|
|
}
|
|
|
|
void MainWindow::solveFEA() {
|
|
rapidjson::Document configDoc = createConfigDoc();
|
|
feaTerminated = false;
|
|
try {
|
|
writeConfigDocToFile(configDoc, feaTmpConfigFilename);
|
|
QStringList feaProgramArgs;
|
|
feaProgramArgs << "-c" << feaTmpConfigFilename.c_str();
|
|
feaProcess = new QProcess(this);
|
|
|
|
connect(progress, SIGNAL(canceled()), this, SLOT(handleCanceledFEA()));
|
|
connect(feaProcess, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(handleFinishedFEA(int, QProcess::ExitStatus)));
|
|
connect(feaProcess, SIGNAL(readyReadStandardOutput()), this, SLOT(updateProgressText()));
|
|
connect(feaProcess, SIGNAL(readyReadStandardError()), this, SLOT(handleCanceledFEA()));
|
|
|
|
feaProcess->start(QString::fromStdString(feaProgram), feaProgramArgs);
|
|
}
|
|
catch (std::exception &e) {
|
|
std::cerr << "error: " << e.what();
|
|
QString message_title("Error");
|
|
QString message_text(e.what());
|
|
QMessageBox::critical(this, message_title, message_text);
|
|
setEnabled(true);
|
|
}
|
|
}
|