2 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
4 // + This file is part of enGrid. +
6 // + Copyright 2008,2009 Oliver Gloth +
8 // + enGrid is free software: you can redistribute it and/or modify +
9 // + it under the terms of the GNU General Public License as published by +
10 // + the Free Software Foundation, either version 3 of the License, or +
11 // + (at your option) any later version. +
13 // + enGrid is distributed in the hope that it will be useful, +
14 // + but WITHOUT ANY WARRANTY; without even the implied warranty of +
15 // + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +
16 // + GNU General Public License for more details. +
18 // + You should have received a copy of the GNU General Public License +
19 // + along with enGrid. If not, see <http://www.gnu.org/licenses/>. +
21 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
23 #include "openfoamtools.h"
25 #include "guimainwindow.h"
29 #include <QFileDialog>
30 #include <QInputDialog>
37 OpenFOAMTools::OpenFOAMTools(QObject
*parent
) : QObject( parent
)
39 m_SolverProcess
= new QProcess(this);
40 m_ToolsProcess
= new QProcess(this);
42 // connect(m_SolverProcess, SIGNAL(error(QProcess::ProcessError)), this, SLOT(errorHandler(QProcess::ProcessError)));
43 connect(m_SolverProcess
, SIGNAL(finished(int, QProcess::ExitStatus
)), this, SLOT(finishedHandler(int, QProcess::ExitStatus
)));
44 connect(m_SolverProcess
, SIGNAL(readyReadStandardError()), this, SLOT(readFromStderr()));
45 connect(m_SolverProcess
, SIGNAL(readyReadStandardOutput()), this, SLOT(readFromStdout()));
46 connect(m_SolverProcess
, SIGNAL(started()), this, SLOT(startedHandler()));
47 // connect(m_SolverProcess, SIGNAL(stateChanged(QProcess::ProcessState)), this, SLOT(stateChangedHandler(QProcess::ProcessState)));
50 m_WorkingDirectory
= "";
51 m_HostFile
= "hostfile.txt";
55 QSettings
*settings
= GuiMainWindow::pointer()->settings();
56 if (settings
->contains("openfoam_directory")) {
57 m_OpenFoamPath
= settings
->value("openfoam_directory").toString();
59 m_OpenFoamPath
= getenv("HOME");
60 m_OpenFoamPath
+= "/OpenFOAM/OpenFOAM-1.5";
61 settings
->setValue("openfoam_directory", m_OpenFoamPath
);
63 if (settings
->contains("openfoam_architecture")) {
64 m_OpenFoamArch
= settings
->value("openfoam_architecture").toString();
66 m_OpenFoamArch
= "linux64GccDPOpt";
67 settings
->setValue("openfoam_architecture", m_OpenFoamArch
);
72 OpenFOAMTools::~OpenFOAMTools()
74 this->stopSolverProcess();
77 void OpenFOAMTools::writeMpiParameters()
79 QString hostfile_text
= GuiMainWindow::pointer()->getXmlSection( "solver/general/host_weight_list" );
81 QVector
<QString
> host
;
82 QVector
<QString
> weight
;
84 QStringList host_weight_list
= hostfile_text
.split(",");
85 foreach(QString host_weight
, host_weight_list
) {
86 if(!host_weight
.isEmpty()){
87 QStringList values
= host_weight
.split(":");
88 qWarning()<<"values="<<values
;
89 host
.push_back(values
[0].trimmed());
90 weight
.push_back(values
[1].trimmed());
95 // create the hostfile
96 QFileInfo
fileinfo( m_WorkingDirectory
+ "/" + m_HostFile
);
97 QFile
hostfile( fileinfo
.filePath() );
98 if (!hostfile
.open(QIODevice::WriteOnly
| QIODevice::Text
)) {
100 EG_ERR_RETURN( "ERROR: Failed to open file " + fileinfo
.filePath() );
101 } catch ( Error err
) {
105 QTextStream
out( &hostfile
);
106 for(int i
= 0; i
< host
.size(); i
++) {
107 out
<< host
[i
] << endl
;
111 // create the decomposeParDict file
112 QFileInfo
fileinfo_decomposeParDict( m_WorkingDirectory
+ "/system/decomposeParDict" );
113 QFile
decomposeParDict( fileinfo_decomposeParDict
.filePath() );
114 if (!decomposeParDict
.open(QIODevice::WriteOnly
| QIODevice::Text
)) {
116 EG_ERR_RETURN( "ERROR: Failed to open file " + fileinfo_decomposeParDict
.filePath() );
117 } catch ( Error err
) {
121 QTextStream
out_decomposeParDict( &decomposeParDict
);
122 out_decomposeParDict
<< "/*--------------------------------*- C++ -*----------------------------------*\\" << endl
;
123 out_decomposeParDict
<< "| ========= | |" << endl
;
124 out_decomposeParDict
<< "| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |" << endl
;
125 out_decomposeParDict
<< "| \\ / O peration | Version: 1.5 |" << endl
;
126 out_decomposeParDict
<< "| \\ / A nd | Web: http://www.OpenFOAM.org |" << endl
;
127 out_decomposeParDict
<< "| \\/ M anipulation | |" << endl
;
128 out_decomposeParDict
<< "\\*---------------------------------------------------------------------------*/" << endl
;
129 out_decomposeParDict
<< "FoamFile" << endl
;
130 out_decomposeParDict
<< "{" << endl
;
131 out_decomposeParDict
<< " version 2.0;" << endl
;
132 out_decomposeParDict
<< " format ascii;" << endl
;
133 out_decomposeParDict
<< " class dictionary;" << endl
;
134 out_decomposeParDict
<< " object decomposeParDict;" << endl
;
135 out_decomposeParDict
<< "}" << endl
;
136 out_decomposeParDict
<< "// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //" << endl
;
137 out_decomposeParDict
<< "" << endl
;
138 out_decomposeParDict
<< "numberOfSubdomains "<<weight
.size()<<";" << endl
;
139 out_decomposeParDict
<< "" << endl
;
140 out_decomposeParDict
<< "method metis;" << endl
;
141 out_decomposeParDict
<< "" << endl
;
142 out_decomposeParDict
<< "metisCoeffs" << endl
;
143 out_decomposeParDict
<< "{" << endl
;
144 out_decomposeParDict
<< " processorWeights " << endl
;
145 out_decomposeParDict
<< " (" << endl
;
146 for(int i
= 0; i
< weight
.size(); i
++) {
147 out_decomposeParDict
<< " "<<weight
[i
]<<"" << endl
;
149 out_decomposeParDict
<< " );" << endl
;
150 out_decomposeParDict
<< "}" << endl
;
151 out_decomposeParDict
<< "" << endl
;
152 out_decomposeParDict
<< "distributed no;" << endl
;
153 out_decomposeParDict
<< "" << endl
;
154 out_decomposeParDict
<< "roots " << endl
;
155 out_decomposeParDict
<< "(" << endl
;
156 out_decomposeParDict
<< ");" << endl
;
157 out_decomposeParDict
<< "" << endl
;
158 out_decomposeParDict
<< "// ************************************************************************* //" << endl
;
159 out_decomposeParDict
<< "" << endl
;
160 decomposeParDict
.close();
162 m_NumProcesses
= weight
.size();
163 m_MainHost
= host
[0];
171 int OpenFOAMTools::getArguments()
173 // resest command-line
178 int solver_type
= GuiMainWindow::pointer()->getXmlSection("solver/general/solver_type").toInt();
180 QFileInfo solvers_fileinfo
;
181 solvers_fileinfo
.setFile(":/resources/solvers/solvers.txt");
182 QFile
file( solvers_fileinfo
.filePath() );
183 if ( !file
.exists() ) {
184 qDebug() << "ERROR: " << solvers_fileinfo
.filePath() << " not found.";
188 if ( !file
.open( QIODevice::ReadOnly
| QIODevice::Text
) ) {
189 qDebug() << "ERROR: Failed to open file " << solvers_fileinfo
.filePath();
193 QTextStream
text_stream( &file
);
194 QString intext
= text_stream
.readAll();
197 QStringList page_list
= intext
.split( "=" );
198 QString page
= page_list
[solver_type
];
202 QVector
<QString
> files
;
203 QStringList variable_list
= page
.split( ";" );
204 foreach( QString variable
, variable_list
) {
205 QStringList name_value
= variable
.split( ":" );
206 if ( name_value
[0].trimmed() == "title" ) title
= name_value
[1].trimmed();
207 if ( name_value
[0].trimmed() == "section" ) section
= name_value
[1].trimmed();
208 if ( name_value
[0].trimmed() == "binary" ) binary
= name_value
[1].trimmed();
209 if ( name_value
[0].trimmed() == "files" ) {
210 QStringList file_list
= name_value
[1].split( "," );
211 foreach( QString file
, file_list
) {
212 files
.push_back( file
.trimmed() );
217 m_SolverBinary
= m_OpenFoamPath
+ "/applications/bin/" + m_OpenFoamArch
+ "/" + binary
;
218 m_StrippedSolverBinary
= binary
;
220 m_WorkingDirectory
= GuiMainWindow::pointer()->getXmlSection("openfoam/CaseDir");
221 if ( m_WorkingDirectory
.isEmpty() ) {
222 m_WorkingDirectory
= QFileDialog::getExistingDirectory( NULL
, "select case directory", GuiMainWindow::getCwd() );
223 if ( !m_WorkingDirectory
.isNull() ) {
224 GuiMainWindow::setCwd( QFileInfo( m_WorkingDirectory
).absolutePath() );
230 // create hostfile + decomposeParDict + get necessary parameters
231 writeMpiParameters();
233 // set working directory of the process
234 m_SolverProcess
->setWorkingDirectory(m_WorkingDirectory
);
239 //=====================================
241 //=====================================
243 void OpenFOAMTools::runSolver()
245 if (m_SolverProcess
->state() == QProcess::NotRunning
) {
246 if (getArguments() < 0) {
249 if (m_NumProcesses
<= 1) {
250 if(m_MainHost
.isEmpty()) {
251 m_Program
= m_SolverBinary
;
252 m_Arguments
<< "-case" << m_WorkingDirectory
;
255 m_Arguments
<< m_MainHost
<< m_SolverBinary
<< "-case" << m_WorkingDirectory
;
259 if(m_SolverProcess
->waitForFinished() && m_SolverProcess
->exitCode() == 0 ) {
260 QString numprocesses_str
;
261 numprocesses_str
.setNum(m_NumProcesses
);
263 //m_Program = "mpirun";
264 //m_Arguments << "--hostfile" << m_HostFile << "-np" << numprocesses_str << m_SolverBinary << "-case" << m_WorkingDirectory << "-parallel";
266 m_Arguments
<< m_MainHost
<< "mpirun";
267 m_Arguments
<< "--hostfile" << m_WorkingDirectory
+ "/" + m_HostFile
;
268 m_Arguments
<< "-np" << numprocesses_str
<< m_SolverBinary
<< "-case" << m_WorkingDirectory
<< "-parallel";
271 qDebug()<<"ERROR: decomposePar failed.";
275 m_SolverProcess
->start(m_Program
, m_Arguments
);
279 void OpenFOAMTools::runTool(QString path
, QString name
, QStringList args
)
281 args
<< "-case" << m_WorkingDirectory
;
282 m_ToolsProcess
->start(m_OpenFoamPath
+ "/" + path
+ "/" + m_OpenFoamArch
+ "/" + name
, args
);
284 m_ToolsProcess
->waitForFinished(500);
285 if (m_SolverProcess
->state() == QProcess::NotRunning
) {
286 cout
<< m_ToolsProcess
->readAllStandardOutput().data();
289 QApplication::processEvents();
290 } while (m_ToolsProcess
->state() == QProcess::Running
);
291 if (m_SolverProcess
->state() == QProcess::NotRunning
) {
292 cout
<< m_ToolsProcess
->readAllStandardOutput().data();
297 void OpenFOAMTools::runDecomposePar()
299 if (getArguments() < 0) {
302 this->stopSolverProcess();
303 m_Program
= getBinary("applications/bin", "decomposePar");
304 m_Arguments
<< "-force";
305 m_SolverProcess
->start(m_Program
, m_Arguments
);
308 void OpenFOAMTools::runPostProcessingTools()
311 args
<< "-latestTime";
312 runTool("applications/bin", "reconstructPar", args
);
313 runTool("applications/bin", "foamToVTK", args
);
316 void OpenFOAMTools::stopSolverProcess()
318 if (m_SolverProcess
->state() == QProcess::Running
) {
319 m_SolverProcess
->kill();
320 QString cmd
= "ssh " + m_MainHost
+ " killall -9 " + m_StrippedSolverBinary
;
321 system(cmd
.toAscii().data());
325 void OpenFOAMTools::runImportFluentCase()
327 QString fluent_file_name
= QFileDialog::getOpenFileName(NULL
, "import FLUENT case",GuiMainWindow::pointer()->getCwd(), "*.msh");
328 if (!fluent_file_name
.isNull()) {
329 QString foam_case_dir
= QFileDialog::getExistingDirectory(NULL
, "select OpenFOAM case directory", GuiMainWindow::getCwd());
330 if (!foam_case_dir
.isNull()) {
331 QString p1
= foam_case_dir
;
332 QString p2
= p1
+ "/system";
337 items
<< tr("millimetres") << tr("centimetres") << tr("metres") << tr("inches");
339 QString scale_txt
= QInputDialog::getItem(NULL
, tr("Select scale"), tr("scale:"), items
, 0, false, &ok
);
340 if (ok
&& !scale_txt
.isEmpty()) {
346 args
<< fluent_file_name
;
348 if (scale_txt
== "millimetres") {
350 } else if (scale_txt
== "centimetres") {
352 } else if (scale_txt
== "metres") {
354 } else if (scale_txt
== "inches") {
359 m_WorkingDirectory
= foam_case_dir
;
360 QFile
file(m_WorkingDirectory
+ "/system/controlDict");
361 if (!file
.open(QIODevice::WriteOnly
| QIODevice::Text
)) {
363 EG_ERR_RETURN( "ERROR: Failed to open file " + foam_case_dir
+ "/system/controlDict");
364 } catch (Error err
) {
368 QTextStream
f(&file
);
369 f
<< "/*--------------------------------*- C++ -*----------------------------------*\\\n";
370 f
<< "| ========= | |\n";
371 f
<< "| \\ / F ield | OpenFOAM: The Open Source CFD Toolbox |\n";
372 f
<< "| \\ / O peration | Version: 1.5 |\n";
373 f
<< "| \\ / A nd | Web: http://www.OpenFOAM.org |\n";
374 f
<< "| \\/ M anipulation | |\n";
375 f
<< "\\*---------------------------------------------------------------------------*/\n";
378 f
<< " version 2.0;\n";
379 f
<< " format ascii;\n";
380 f
<< " class dictionary;\n";
381 f
<< " object controlDict;\n";
383 f
<< "// * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //\n";
385 f
<< "application simpleFoam;\n";
387 f
<< "startFrom startTime;\n";
388 f
<< "startTime 0;\n";
389 f
<< "stopAt endTime;\n";
390 f
<< "endTime 1000;\n";
392 f
<< "writeControl timeStep;\n";
393 f
<< "writeInterval 100;\n";
394 f
<< "purgeWrite 0;\n";
395 f
<< "writeFormat ascii;\n";
396 f
<< "writePrecision 6;\n";
397 f
<< "writeCompression uncompressed;\n";
398 f
<< "timeFormat general;\n";
399 f
<< "timePrecision 6;\n";
400 f
<< "runTimeModifiable yes;\n";
402 runTool("applications/bin", "fluentMeshToFoam", args
);
409 //=====================================
411 //=====================================
413 void OpenFOAMTools::finishedHandler(int exitCode
, QProcess::ExitStatus exitStatus
)
415 qDebug() << "=== solver-process finished with exit-code = " << exitCode
<< " ===";
418 void OpenFOAMTools::readFromStderr()
420 cout
<< m_SolverProcess
->readAllStandardError().data();
424 void OpenFOAMTools::readFromStdout()
426 cout
<< m_SolverProcess
->readAllStandardOutput().data();
430 void OpenFOAMTools::startedHandler()
432 qDebug() << "=== started solver-process with PID = " << m_SolverProcess
->pid() << "===";
433 QString cmd
= m_Program
;
434 foreach(QString arg
, m_Arguments
) {
437 cout
<< "[" << qPrintable(m_WorkingDirectory
) << "]$ " << qPrintable(cmd
) << endl
;