350 lines
9.6 KiB
C++
350 lines
9.6 KiB
C++
|
|
/**
|
|||
|
|
* @file SolverControlerBase.cpp
|
|||
|
|
* @brief 求解器控制基类源文件
|
|||
|
|
* @author FastCAE研发小组(fastcae@diso.cn)
|
|||
|
|
* @version 2.5.0
|
|||
|
|
* @date 2022-03-12 15:34
|
|||
|
|
* @copyright Copyright (c) Since 2020 青岛数智船海科技有限公司 All rights reserved.
|
|||
|
|
*
|
|||
|
|
* ============================================================================
|
|||
|
|
* Program: FastCAE
|
|||
|
|
*
|
|||
|
|
* Copyright (c) Since 2020 青岛数智船海科技有限公司 All rights reserved.
|
|||
|
|
* See License or http://www.fastcae.com/ for details.
|
|||
|
|
*
|
|||
|
|
* BSD 3-Clause License
|
|||
|
|
*
|
|||
|
|
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
|
|||
|
|
* AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
|
|||
|
|
* IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
|
|||
|
|
* DISCLAIMED.
|
|||
|
|
* ==================================================================================
|
|||
|
|
*/
|
|||
|
|
#include "SolverControlerBase.h"
|
|||
|
|
#include "MainWindow/MainWindow.h"
|
|||
|
|
#include "ModuleBase/processBar.h"
|
|||
|
|
#include "PostWidgets/RealTimeWindowBase.h"
|
|||
|
|
#include "ModelData/modelDataSingleton.h"
|
|||
|
|
#include "ModelData/modelDataBaseExtend.h"
|
|||
|
|
#include "ConfigOptions/ConfigOptions.h"
|
|||
|
|
#include "ConfigOptions/SolverConfig.h"
|
|||
|
|
#include "ConfigOptions/SolverInfo.h"
|
|||
|
|
#include "IO/SolverIO.h"
|
|||
|
|
#include <QMessageBox>
|
|||
|
|
#include <QCoreApplication>
|
|||
|
|
#include <QFileInfo>
|
|||
|
|
#include <QDir>
|
|||
|
|
#include <QDebug>
|
|||
|
|
#include "PythonModule/PyAgent.h"
|
|||
|
|
|
|||
|
|
namespace SolverControl
|
|||
|
|
{
|
|||
|
|
|
|||
|
|
SolverControlBase::SolverControlBase(GUI::MainWindow *mainwindow, ConfigOption::SolverInfo *solver, ModelData::ModelDataBase *m, bool sonly)
|
|||
|
|
: _mainWindow(mainwindow), _solver(solver), _model(m), _solveOnly(sonly)
|
|||
|
|
{
|
|||
|
|
connect(&_process, SIGNAL(readyReadStandardOutput()), this, SLOT(readSolverOutput()));
|
|||
|
|
connect(this, SIGNAL(sendMessage(QString)), _mainWindow, SIGNAL(printMessageToMessageWindow(QString)));
|
|||
|
|
connect(this, SIGNAL(solverStarted(QWidget *)), _mainWindow, SIGNAL(addProcessBarSig(QWidget *)));
|
|||
|
|
connect(_mainWindow, SIGNAL(stopSolve(QWidget *)), this, SLOT(stopSolver(QWidget *)));
|
|||
|
|
connect(&_process, SIGNAL(finished(int, QProcess::ExitStatus)), this, SLOT(processFinished(int, QProcess::ExitStatus)));
|
|||
|
|
connect(this, SIGNAL(processFinish(int)), _mainWindow, SIGNAL(processFinished(int)));
|
|||
|
|
connect(this, SIGNAL(openRealTime(Post::RealTimeWindowBase *, int)), _mainWindow, SIGNAL(openRealTimeWindowSig(Post::RealTimeWindowBase *, int)));
|
|||
|
|
}
|
|||
|
|
SolverControlBase::~SolverControlBase()
|
|||
|
|
{
|
|||
|
|
if (_processBar != nullptr)
|
|||
|
|
delete _processBar;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void SolverControlBase::setSolverDescription(QString des)
|
|||
|
|
{
|
|||
|
|
_description = des;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void SolverControlBase::startSolver()
|
|||
|
|
{
|
|||
|
|
QString solverPath = _solver->getExePath();
|
|||
|
|
qDebug() << solverPath;
|
|||
|
|
QFileInfo info(solverPath);
|
|||
|
|
int id = _model->getID();
|
|||
|
|
|
|||
|
|
if ((!info.exists()) || (!info.isFile()))
|
|||
|
|
{
|
|||
|
|
QMessageBox::warning(nullptr, tr("Warning"), tr("Solver Path Error! Solve Path : %1").arg(solverPath));
|
|||
|
|
emit processFinish(id);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
bool ok = preProcess();
|
|||
|
|
if (!ok)
|
|||
|
|
{
|
|||
|
|
QMessageBox::warning(nullptr, tr("Warning"), tr("Input file write failed !"));
|
|||
|
|
emit processFinish(id);
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString oldDir = "";
|
|||
|
|
|
|||
|
|
QString startPath = _model->getPath();
|
|||
|
|
|
|||
|
|
if (_solver->getType() == ConfigOption::SelfDevelop)
|
|||
|
|
{
|
|||
|
|
QDir dir(startPath);
|
|||
|
|
if (dir.exists() && (!startPath.isEmpty()))
|
|||
|
|
{
|
|||
|
|
oldDir = QDir::currentPath();
|
|||
|
|
QDir::setCurrent(startPath);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_processBar = new ModuleBase::ProcessBar(_mainWindow, _description, false);
|
|||
|
|
|
|||
|
|
QString args = _solver->getParameter();
|
|||
|
|
QRegExp regExp("%.*%");
|
|||
|
|
regExp.setMinimal(true);
|
|||
|
|
// int pos = regExp.indexIn(args);
|
|||
|
|
QStringList variables = regExp.capturedTexts();
|
|||
|
|
for (int i = 0; i < variables.size(); ++i)
|
|||
|
|
{
|
|||
|
|
QString variable = variables.at(i);
|
|||
|
|
QString va = variable.remove("%");
|
|||
|
|
if (va.toLower() == "modelpath")
|
|||
|
|
args.replace(variables.at(i), startPath);
|
|||
|
|
// qDebug() << args;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// QString startProcess = solverPath + " " + args;
|
|||
|
|
// if (solverPath.contains(" "))
|
|||
|
|
// startProcess = QString("\"%1\"").arg(startProcess);
|
|||
|
|
|
|||
|
|
// qDebug() << startProcess;
|
|||
|
|
// if (!_args.isEmpty())
|
|||
|
|
// startProcess = startProcess + " " + _args;
|
|||
|
|
// qDebug() << startProcess;
|
|||
|
|
|
|||
|
|
_process.start(solverPath, QStringList(args));
|
|||
|
|
|
|||
|
|
emit solverStarted(_processBar);
|
|||
|
|
|
|||
|
|
ModelData::ModelDataBaseExtend *extend = dynamic_cast<ModelData::ModelDataBaseExtend *>(_model);
|
|||
|
|
if (extend != nullptr && !_solveOnly)
|
|||
|
|
{
|
|||
|
|
QList<ConfigOption::PostCurve *> curves = extend->getMonitorCurves();
|
|||
|
|
if (curves.size() > 0)
|
|||
|
|
{
|
|||
|
|
int id = _model->getID();
|
|||
|
|
Post::RealTimeWindowBase *w = new Post::RealTimeWindowBase(_mainWindow, id);
|
|||
|
|
emit openRealTime(w, id);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (_solver->getType() == ConfigOption::SelfDevelop)
|
|||
|
|
{
|
|||
|
|
if (!oldDir.isEmpty())
|
|||
|
|
QDir::setCurrent(oldDir);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
void SolverControlBase::readSolverOutput()
|
|||
|
|
{
|
|||
|
|
_outputBuffer = QString::fromLocal8Bit(_process.readAll());
|
|||
|
|
QString process = _solver->getProcessKeyWord() + "(\\d+)(?:\\s*)";
|
|||
|
|
// qDebug() << process;
|
|||
|
|
QRegExp rx(process);
|
|||
|
|
int pos = _outputBuffer.indexOf(rx);
|
|||
|
|
if (pos > -1 && _processBar != nullptr)
|
|||
|
|
{
|
|||
|
|
QString s = rx.cap(1);
|
|||
|
|
_processBar->setProcess(s.toInt());
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
emit sendMessage(_outputBuffer);
|
|||
|
|
}
|
|||
|
|
void SolverControlBase::stopSolver(QWidget *w)
|
|||
|
|
{
|
|||
|
|
if (w != _processBar)
|
|||
|
|
return;
|
|||
|
|
|
|||
|
|
int id = -1;
|
|||
|
|
if (_model != nullptr)
|
|||
|
|
id = _model->getID();
|
|||
|
|
emit removeSolver(id);
|
|||
|
|
if (!_processFinished)
|
|||
|
|
{
|
|||
|
|
_process.kill();
|
|||
|
|
}
|
|||
|
|
_processBar = nullptr;
|
|||
|
|
// this->deleteLater();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void SolverControlBase::stopSolver()
|
|||
|
|
{
|
|||
|
|
if (!_processFinished)
|
|||
|
|
{
|
|||
|
|
_process.kill();
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void SolverControlBase::startMPI(int nprocess)
|
|||
|
|
{
|
|||
|
|
QString solverPath = _solver->getExePath();
|
|||
|
|
QFileInfo info(solverPath);
|
|||
|
|
if ((!info.exists()) || (!info.isFile()))
|
|||
|
|
{
|
|||
|
|
QMessageBox::warning(nullptr, tr("Warning"), tr("Solver Path Error! Solve Path : %1").arg(solverPath));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
bool ok = preProcess();
|
|||
|
|
if (!ok)
|
|||
|
|
{
|
|||
|
|
QMessageBox::warning(nullptr, tr("Warning"), tr("Input file write failed !"));
|
|||
|
|
return;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
QString oldDir = "";
|
|||
|
|
|
|||
|
|
QString startPath = _model->getPath();
|
|||
|
|
|
|||
|
|
if (_solver->getType() == ConfigOption::SelfDevelop)
|
|||
|
|
{
|
|||
|
|
QDir dir(startPath);
|
|||
|
|
if (dir.exists() && (!startPath.isEmpty()))
|
|||
|
|
{
|
|||
|
|
oldDir = QDir::currentPath();
|
|||
|
|
QDir::setCurrent(startPath);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
_processBar = new ModuleBase::ProcessBar(_mainWindow, _description, false);
|
|||
|
|
|
|||
|
|
QString args = _solver->getParameter();
|
|||
|
|
QRegExp regExp("%.*%");
|
|||
|
|
regExp.setMinimal(true);
|
|||
|
|
// int pos = regExp.indexIn(args);
|
|||
|
|
QStringList variables = regExp.capturedTexts();
|
|||
|
|
for (int i = 0; i < variables.size(); ++i)
|
|||
|
|
{
|
|||
|
|
QString variable = variables.at(i);
|
|||
|
|
QString va = variable.remove("%");
|
|||
|
|
if (va.toLower() == "modelpath")
|
|||
|
|
args.replace(variables.at(i), startPath);
|
|||
|
|
// qDebug() << args;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
// QString startProcess = solverPath + " " + args;
|
|||
|
|
// if (solverPath.contains(" "))
|
|||
|
|
// startProcess = QString("\"%1\"").arg(startProcess);
|
|||
|
|
|
|||
|
|
// qDebug() << startProcess;
|
|||
|
|
// if (!_args.isEmpty())
|
|||
|
|
// startProcess = startProcess + " " + _args;
|
|||
|
|
// qDebug() << startProcess;
|
|||
|
|
|
|||
|
|
QString c = QString("mpiexec -n %1 %2").arg(nprocess).arg(solverPath);
|
|||
|
|
|
|||
|
|
_process.start(c);
|
|||
|
|
|
|||
|
|
emit solverStarted(_processBar);
|
|||
|
|
|
|||
|
|
ModelData::ModelDataBaseExtend *extend = dynamic_cast<ModelData::ModelDataBaseExtend *>(_model);
|
|||
|
|
if (extend != nullptr && !_solveOnly)
|
|||
|
|
{
|
|||
|
|
QList<ConfigOption::PostCurve *> curves = extend->getMonitorCurves();
|
|||
|
|
if (curves.size() > 0)
|
|||
|
|
{
|
|||
|
|
int id = _model->getID();
|
|||
|
|
Post::RealTimeWindowBase *w = new Post::RealTimeWindowBase(_mainWindow, id);
|
|||
|
|
emit openRealTime(w, id);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
if (_solver->getType() == ConfigOption::SelfDevelop)
|
|||
|
|
{
|
|||
|
|
if (!oldDir.isEmpty())
|
|||
|
|
QDir::setCurrent(oldDir);
|
|||
|
|
}
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void SolverControlBase::setSolveArgs(QString arg)
|
|||
|
|
{
|
|||
|
|
_args = arg;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void SolverControlBase::startSolverClear()
|
|||
|
|
{
|
|||
|
|
_solveOnly = true;
|
|||
|
|
_processBar = new ModuleBase::ProcessBar(_mainWindow, _description, false);
|
|||
|
|
QString solverPath = _solver->getExePath();
|
|||
|
|
|
|||
|
|
_process.start(solverPath, QStringList(_args));
|
|||
|
|
|
|||
|
|
emit solverStarted(_processBar);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
void SolverControlBase::processFinished(int exitCode, QProcess::ExitStatus exitStatus)
|
|||
|
|
{
|
|||
|
|
Q_UNUSED(exitCode);
|
|||
|
|
|
|||
|
|
_processFinished = true;
|
|||
|
|
|
|||
|
|
int id = -1;
|
|||
|
|
if (_model != nullptr)
|
|||
|
|
id = _model->getID();
|
|||
|
|
emit processFinish(id);
|
|||
|
|
|
|||
|
|
switch (exitStatus)
|
|||
|
|
{
|
|||
|
|
case QProcess::NormalExit:
|
|||
|
|
emit sendMessage("************************************");
|
|||
|
|
emit sendMessage("***** Solving process finished *****");
|
|||
|
|
emit sendMessage("************************************");
|
|||
|
|
|
|||
|
|
break;
|
|||
|
|
case QProcess::CrashExit:
|
|||
|
|
emit sendMessage("************************************");
|
|||
|
|
emit sendMessage("***** Solving process Crashed ******");
|
|||
|
|
emit sendMessage("************************************");
|
|||
|
|
break;
|
|||
|
|
default:
|
|||
|
|
emit sendMessage("***********************************");
|
|||
|
|
emit sendMessage("***** Solving process Stopped *****");
|
|||
|
|
emit sendMessage("***********************************");
|
|||
|
|
break;
|
|||
|
|
}
|
|||
|
|
if (_processBar != nullptr)
|
|||
|
|
{
|
|||
|
|
if (_processBar->isBusy())
|
|||
|
|
_processBar->setProcessRange(0, 100);
|
|||
|
|
_processBar->setProcess(100);
|
|||
|
|
}
|
|||
|
|
postPorocess();
|
|||
|
|
Py::PythonAgent::getInstance()->unLock();
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool SolverControlBase::preProcess()
|
|||
|
|
{
|
|||
|
|
if (_solveOnly)
|
|||
|
|
return true;
|
|||
|
|
bool istemp = _solver->isWriteTemplate();
|
|||
|
|
if (istemp)
|
|||
|
|
{
|
|||
|
|
QString te = _solver->getTemplate();
|
|||
|
|
QString path = _model->getPath();
|
|||
|
|
return IO::SolverIO::replaceTemplate(te, path, _model);
|
|||
|
|
}
|
|||
|
|
else
|
|||
|
|
{
|
|||
|
|
QString format = _solver->getInputFormat();
|
|||
|
|
return IO::SolverIO::writeInpFile(format, _model);
|
|||
|
|
}
|
|||
|
|
return false;
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
bool SolverControlBase::postPorocess()
|
|||
|
|
{
|
|||
|
|
if (_solveOnly)
|
|||
|
|
return true;
|
|||
|
|
QString trans = _solver->getTransfer();
|
|||
|
|
QString path = _model->getPath();
|
|||
|
|
return IO::SolverIO::transformFile(trans, path);
|
|||
|
|
}
|
|||
|
|
|
|||
|
|
}
|