Skip to content

Commit 19e159a

Browse files
committed
Add contaminant dispersion setup widget, update fluid help and translations, show only latest run in convergence report
1 parent d2d343b commit 19e159a

13 files changed

Lines changed: 1997 additions & 1450 deletions

‎src/fea/CMakeLists.txt‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -134,6 +134,7 @@ qt_add_executable(fea
134134
src/monitoring_points_dialog.cpp
135135
src/move_node_dialog.cpp
136136
src/new_model_dialog.cpp
137+
src/particle_setup_widget.cpp
137138
src/pick_details_tree.cpp
138139
src/pick_item.cpp
139140
src/pick_list.cpp
@@ -316,6 +317,7 @@ qt_add_executable(fea
316317
src/monitoring_points_dialog.h
317318
src/move_node_dialog.h
318319
src/new_model_dialog.h
320+
src/particle_setup_widget.h
319321
src/pick_details_tree.h
320322
src/pick_item.h
321323
src/pick_list.h

‎src/fea/help/theory/en/theory_fluid.md‎

Lines changed: 199 additions & 34 deletions
Large diffs are not rendered by default.

‎src/fea/help/theory/sk/theory_fluid.md‎

Lines changed: 1037 additions & 884 deletions
Large diffs are not rendered by default.

‎src/fea/src/action.cpp‎

Lines changed: 37 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,6 @@
11
#include <QString>
22
#include <QFileDialog>
3+
#include <QFileInfo>
34
#include <QMessageBox>
45

56
#include <rbl_error.h>
@@ -2118,26 +2119,52 @@ void Action::onReportConvergenceGraph()
21182119

21192120
for (int i=0;i<modelIDs.size();i++)
21202121
{
2121-
QStringList fileNames;
2122+
const Model &rModel = Application::instance()->getSession()->getModel(modelIDs[i]);
21222123

2123-
QString filePattern(Application::instance()->getSession()->getModel(modelIDs[i]).buildTmpFileName("cvg",QString("*")));
2124+
QString filePattern(rModel.buildTmpFileName("cvg",QString("*")));
2125+
// Convergence files are named <model>-<task ID>-<suffix>.cvg
2126+
QString filePrefix(QFileInfo(rModel.buildTmpFileName("cvg",QString())).completeBaseName() + "-");
21242127

2128+
QStringList suffixes;
21252129
std::vector<RProblemType> problemTypes = RProblem::getTypes(R_PROBLEM_ALL);
2126-
for (uint i=0;i<problemTypes.size();i++)
2130+
for (uint j=0;j<problemTypes.size();j++)
2131+
{
2132+
suffixes.append(RProblem::getId(problemTypes[j]));
2133+
}
2134+
for (RMatrixSolverType type=RMatrixSolverConf::None;type<RMatrixSolverConf::NTypes;type++)
2135+
{
2136+
suffixes.append(RMatrixSolverConf::getId(type));
2137+
}
2138+
2139+
// Newest file of each problem and matrix solver type together with its task ID.
2140+
QStringList lastFileNames;
2141+
QStringList lastTaskIDs;
2142+
QString latestTaskID;
2143+
for (const QString &suffix : std::as_const(suffixes))
21272144
{
2128-
QString fileName(RFileUtils::findLastFile(RFileUtils::getFileNameWithSuffix(filePattern,RProblem::getId(problemTypes[i]))));
2129-
if (!fileName.isEmpty())
2145+
QString fileName(RFileUtils::findLastFile(RFileUtils::getFileNameWithSuffix(filePattern,suffix)));
2146+
if (fileName.isEmpty())
2147+
{
2148+
continue;
2149+
}
2150+
QString baseName(QFileInfo(fileName).completeBaseName());
2151+
QString taskID(baseName.mid(filePrefix.length(),baseName.length() - filePrefix.length() - suffix.length() - 1));
2152+
2153+
lastFileNames.append(fileName);
2154+
lastTaskIDs.append(taskID);
2155+
if (taskID > latestTaskID)
21302156
{
2131-
fileNames.append(fileName);
2157+
latestTaskID = taskID;
21322158
}
21332159
}
21342160

2135-
for (RMatrixSolverType type=RMatrixSolverConf::None;type<RMatrixSolverConf::NTypes;type++)
2161+
// Show only files written by the latest solver run - older files belong to tasks which were not solved in it.
2162+
QStringList fileNames;
2163+
for (int j=0;j<lastFileNames.size();j++)
21362164
{
2137-
QString fileName(RFileUtils::findLastFile(RFileUtils::getFileNameWithSuffix(filePattern,RMatrixSolverConf::getId(type))));
2138-
if (!fileName.isEmpty())
2165+
if (lastTaskIDs.at(j) == latestTaskID)
21392166
{
2140-
fileNames.append(fileName);
2167+
fileNames.append(lastFileNames.at(j));
21412168
}
21422169
}
21432170

‎src/fea/src/convergence_graph_object.cpp‎

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ void ConvergenceGraphObject::readSource()
111111

112112
this->graphData.clear();
113113

114+
// Matrix solver files hold one block per solve, each counting its iterations from 1.
115+
// Blocks are chained so that a new solve is appended instead of overwriting the previous one.
116+
double iterationOffset = 0.0;
117+
double lastIteration = 0.0;
118+
114119
bool isFirst = true;
115120
while (!in.atEnd())
116121
{
@@ -136,7 +141,14 @@ void ConvergenceGraphObject::readSource()
136141
iteration = query.at(0).toDouble();
137142
error[0] = query.at(this->dataColumn).toDouble();
138143

139-
this->graphData[iteration] = error;
144+
if (iteration <= lastIteration)
145+
{
146+
// Iteration number did not grow - next solve has started.
147+
iterationOffset += lastIteration;
148+
}
149+
lastIteration = iteration;
150+
151+
this->graphData[iterationOffset + iteration] = error;
140152
}
141153
}
142154

Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
#include <QGridLayout>
2+
#include <QGroupBox>
3+
#include <QLabel>
4+
#include <QVBoxLayout>
5+
6+
#include "particle_setup_widget.h"
7+
#include "value_line_edit.h"
8+
9+
ParticleSetupWidget::ParticleSetupWidget(const RParticleSetup &particleSetup, QWidget *parent)
10+
: QWidget(parent)
11+
, particleSetup(particleSetup)
12+
{
13+
QVBoxLayout *mainLayout = new QVBoxLayout;
14+
this->setLayout(mainLayout);
15+
16+
QGroupBox *groupBox = new QGroupBox(tr("Contaminant dispersion setup"));
17+
mainLayout->addWidget(groupBox);
18+
19+
QGridLayout *groupLayout = new QGridLayout;
20+
groupBox->setLayout(groupLayout);
21+
22+
int groupLayoutRow = 0;
23+
24+
// Maximum saturation
25+
QLabel *labelMaximumSaturation = new QLabel(tr("Maximum saturation") + " [kg/m^3]");
26+
groupLayout->addWidget(labelMaximumSaturation,groupLayoutRow,0);
27+
28+
ValueLineEdit *lineMaximumSaturation = new ValueLineEdit(R_PARTICLE_MAXIMUM_SATURATION_MIN_VALUE,R_PARTICLE_MAXIMUM_SATURATION_MAX_VALUE);
29+
lineMaximumSaturation->setValue(this->particleSetup.getMaximumSaturation());
30+
lineMaximumSaturation->setToolTip(tr("Maximum possible concentration of the contaminant. "
31+
"Particle rate decreases as the concentration approaches this value and stops at saturation. "
32+
"Relative saturation is computed when set. "
33+
"Zero means unlimited."));
34+
groupLayout->addWidget(lineMaximumSaturation,groupLayoutRow++,1);
35+
36+
QObject::connect(lineMaximumSaturation,&ValueLineEdit::valueChanged,this,&ParticleSetupWidget::onMaximumSaturationChanged);
37+
38+
// Diffusion coefficient
39+
QLabel *labelDiffusionCoefficient = new QLabel(tr("Diffusion coefficient") + " [m^2/s]");
40+
groupLayout->addWidget(labelDiffusionCoefficient,groupLayoutRow,0);
41+
42+
ValueLineEdit *lineDiffusionCoefficient = new ValueLineEdit(R_PARTICLE_DIFFUSION_COEFFICIENT_MIN_VALUE,R_PARTICLE_DIFFUSION_COEFFICIENT_MAX_VALUE);
43+
lineDiffusionCoefficient->setValue(this->particleSetup.getDiffusionCoefficient());
44+
lineDiffusionCoefficient->setToolTip(tr("Effective diffusion coefficient of the contaminant in the fluid. "
45+
"Molecular diffusion (about 1e-5 m^2/s in gases, 1e-9 m^2/s in liquids) is negligible in most flows; "
46+
"mixing is dominated by turbulence, which can be estimated as turbulent viscosity divided by 0.7. "
47+
"When diffusion dominates, use backward difference time march approximation to avoid oscillations. "
48+
"Zero means no diffusion."));
49+
groupLayout->addWidget(lineDiffusionCoefficient,groupLayoutRow++,1);
50+
51+
QObject::connect(lineDiffusionCoefficient,&ValueLineEdit::valueChanged,this,&ParticleSetupWidget::onDiffusionCoefficientChanged);
52+
}
53+
54+
void ParticleSetupWidget::onMaximumSaturationChanged(double maximumSaturation)
55+
{
56+
this->particleSetup.setMaximumSaturation(maximumSaturation);
57+
emit this->changed(this->particleSetup);
58+
}
59+
60+
void ParticleSetupWidget::onDiffusionCoefficientChanged(double diffusionCoefficient)
61+
{
62+
this->particleSetup.setDiffusionCoefficient(diffusionCoefficient);
63+
emit this->changed(this->particleSetup);
64+
}
Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,35 @@
1+
#ifndef PARTICLE_SETUP_WIDGET_H
2+
#define PARTICLE_SETUP_WIDGET_H
3+
4+
#include <QWidget>
5+
6+
#include <rml_particle_setup.h>
7+
8+
class ParticleSetupWidget : public QWidget
9+
{
10+
Q_OBJECT
11+
12+
protected:
13+
14+
//! Particle setup.
15+
RParticleSetup particleSetup;
16+
17+
public:
18+
19+
//! Constructor.
20+
explicit ParticleSetupWidget(const RParticleSetup &particleSetup, QWidget *parent = nullptr);
21+
22+
signals:
23+
24+
//! Particle setup has changed.
25+
void changed(const RParticleSetup &particleSetup);
26+
27+
private slots:
28+
29+
void onMaximumSaturationChanged(double maximumSaturation);
30+
31+
void onDiffusionCoefficientChanged(double diffusionCoefficient);
32+
33+
};
34+
35+
#endif // PARTICLE_SETUP_WIDGET_H

‎src/fea/src/problem_tree.cpp‎

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33
#include "application.h"
44
#include "mesh_setup_widget.h"
55
#include "modal_setup_widget.h"
6+
#include "particle_setup_widget.h"
67
#include "radiation_setup_widget.h"
78
#include "time_solver_setup_widget.h"
89

@@ -90,6 +91,14 @@ void ProblemTree::populate()
9091
QObject::connect(acousticSetupWidget,&AcousticSetupWidget::changed,this,&ProblemTree::onAcousticSetupChanged);
9192
}
9293

94+
if (rModel.getProblemTaskTree().getProblemTypeMask() & R_PROBLEM_FLUID_PARTICLE)
95+
{
96+
QTreeWidgetItem *particleSetup = new QTreeWidgetItem(this);
97+
ParticleSetupWidget *particleSetupWidget = new ParticleSetupWidget(rModel.getProblemSetup().getParticleSetup());
98+
this->setItemWidget(particleSetup,PROBLEM_TREE_COLUMN_1,particleSetupWidget);
99+
QObject::connect(particleSetupWidget,&ParticleSetupWidget::changed,this,&ProblemTree::onParticleSetupChanged);
100+
}
101+
93102
if (rModel.getProblemTaskTree().getProblemTypeMask() & R_PROBLEM_RADIATIVE_HEAT)
94103
{
95104
QString vfFileName = rModel.buildDataFileName(RViewFactorMatrix::getDefaultFileExtension(true),rModel.getTimeSolver().getEnabled());
@@ -158,6 +167,17 @@ void ProblemTree::onAcousticSetupChanged(const RAcousticSetup &acousticSetup)
158167
}
159168
}
160169

170+
void ProblemTree::onParticleSetupChanged(const RParticleSetup &particleSetup)
171+
{
172+
QList<uint> modelIDs = Application::instance()->getSession()->getSelectedModelIDs();
173+
174+
for (int i=0;i<modelIDs.size();i++)
175+
{
176+
Application::instance()->getSession()->getModel(modelIDs[i]).getProblemSetup().setParticleSetup(particleSetup);
177+
Application::instance()->getSession()->setProblemChanged(modelIDs[i]);
178+
}
179+
}
180+
161181
void ProblemTree::onRadiationSetupChanged(const RRadiationSetup &radiationSetup)
162182
{
163183
QList<uint> modelIDs = Application::instance()->getSession()->getSelectedModelIDs();

‎src/fea/src/problem_tree.h‎

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,9 @@ class ProblemTree : public QTreeWidget
4040
//! Acoustic setup has changed.
4141
void onAcousticSetupChanged(const RAcousticSetup &acousticSetup);
4242

43+
//! Particle setup has changed.
44+
void onParticleSetupChanged(const RParticleSetup &particleSetup);
45+
4346
//! Radiation setup has changed.
4447
void onRadiationSetupChanged(const RRadiationSetup &radiationSetup);
4548

0 commit comments

Comments
 (0)