1 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
3 // + This file is part of enGrid. +
5 // + Copyright 2008-2014 enGits GmbH +
7 // + enGrid is free software: you can redistribute it and/or modify +
8 // + it under the terms of the GNU General Public License as published by +
9 // + the Free Software Foundation, either version 3 of the License, or +
10 // + (at your option) any later version. +
12 // + enGrid is distributed in the hope that it will be useful, +
13 // + but WITHOUT ANY WARRANTY; without even the implied warranty of +
14 // + MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +
15 // + GNU General Public License for more details. +
17 // + You should have received a copy of the GNU General Public License +
18 // + along with enGrid. If not, see <http://www.gnu.org/licenses/>. +
20 // ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
21 #include "guicreateboundarylayer.h"
22 #include "guimainwindow.h"
23 #include "seedsimpleprismaticlayer.h"
24 #include "gridsmoother.h"
25 #include "createvolumemesh.h"
26 #include "swaptriangles.h"
27 #include "deletetetras.h"
28 #include "deletecells.h"
29 #include "meshpartition.h"
30 #include "laplacesmoother.h"
31 #include "updatedesiredmeshdensity.h"
32 #include "insertpoints.h"
34 GuiCreateBoundaryLayer::GuiCreateBoundaryLayer()
36 getSet("boundary layer", "number of smoothing iterations", 10, m_NumIterations
);
37 getSet("boundary layer", "remove points", true, m_RemovePoints
);
39 connect(m_Ui
.pushButton_SelectAll_BC
, SIGNAL(clicked()), this, SLOT(SelectAll_BC()));
40 connect(m_Ui
.pushButton_ClearAll_BC
, SIGNAL(clicked()), this, SLOT(ClearAll_BC()));
43 void GuiCreateBoundaryLayer::before()
45 m_Ui
.checkBoxImprove
->setChecked(false);
46 l2g_t cells
= m_Part
.getCells();
47 foreach (vtkIdType id_cell
, cells
) {
48 if (m_Grid
->GetCellType(id_cell
) == VTK_WEDGE
) {
49 m_Ui
.checkBoxImprove
->setChecked(true);
53 m_Ui
.checkBoxRemovePoints
->setChecked(m_RemovePoints
);
54 m_Ui
.checkBoxSafeMode
->setChecked(false);
55 populateBoundaryCodes(m_Ui
.listWidgetBC
);
56 populateVolumes(m_Ui
.listWidgetVC
);
57 m_Ui
.spinBoxIterations
->setValue(m_NumIterations
);
58 double hr
, ha
, b
, ds
= 1.5, fr
= 0.8;
61 getSet("boundary layer", "relative height of boundary layer", 0.01, hr
);
62 getSet("boundary layer", "absolute height of boundary layer", 1.0, ha
);
63 getSet("boundary layer", "blending between absolute and relative", 0.0, b
);
64 getSet("boundary layer", "number of layer height relax iterations", 5, num_hr
);
65 getSet("boundary layer", "number of normal vector relax iterations", 20, num_nr
);
67 QString blayer_txt
= GuiMainWindow::pointer()->getXmlSection("blayer/global");
68 QTextStream
s(&blayer_txt
);
69 if (!s
.atEnd()) s
>> ha
;
70 if (!s
.atEnd()) s
>> hr
;
71 if (!s
.atEnd()) s
>> b
;
72 if (!s
.atEnd()) s
>> ds
;
73 if (!s
.atEnd()) s
>> fr
;
74 if (!s
.atEnd()) s
>> num_layers
;
75 if (!s
.atEnd()) s
>> num_hr
;
76 if (!s
.atEnd()) s
>> num_nr
;
81 m_Ui
.doubleSpinBoxHeight
->setValue(hr
);
86 m_Ui
.lineEditAbsolute
->setText(num
);
90 m_Ui
.checkBoxAbsolute
->setChecked(true);
92 m_Ui
.checkBoxAbsolute
->setChecked(false);
96 m_Ui
.doubleSpinBoxStretching
->setValue(ds
);
97 m_Ui
.doubleSpinBoxFarRatio
->setValue(fr
);
99 m_Ui
.spinBoxHeightIterations
->setValue(num_hr
);
100 m_Ui
.spinBoxNormalIterations
->setValue(num_nr
);
101 if (num_layers
> 0) {
103 num
.setNum(num_layers
);
104 m_Ui
.lineEditNumLayers
->setText(num
);
106 m_Ui
.lineEditNumLayers
->setText("not yet available");
110 void GuiCreateBoundaryLayer::reduceSurface()
112 RemovePoints remove_points
;
114 part
.setGrid(m_Grid
);
116 remove_points
.setMeshPartition(part
);
117 remove_points
.setBoundaryCodes(m_LayerAdjacentBoundaryCodes
);
118 remove_points
.setUpdatePSPOn();
119 remove_points
.setThreshold(3);
120 QVector
<bool> fix(m_Grid
->GetNumberOfPoints(), true);
122 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
123 for (int i
= 0; i
< part
.n2cGSize(id_node
); ++i
) {
124 if (m_Grid
->GetCellType(part
.n2cGG(id_node
, i
)) == VTK_WEDGE
) {
125 fix
[id_node
] = false;
129 for (int layer
= 0; layer
< 3; ++layer
) {
130 QVector
<bool> tmp
= fix
;
131 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
133 for (int i
= 0; i
< part
.n2nGSize(id_node
); ++i
) {
134 fix
[part
.n2nGG(id_node
, i
)] = false;
139 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
140 for (int i
= 0; i
< part
.n2cGSize(id_node
); ++i
) {
141 if (m_Grid
->GetCellType(part
.n2cGG(id_node
, i
)) == VTK_WEDGE
) {
147 remove_points
.fixNodes(fix
);
151 void GuiCreateBoundaryLayer::updateSurface()
153 QString buffer
= GuiMainWindow::pointer()->getXmlSection("engrid/surface/table").replace("\n", " ");
155 int column_count
= 0;
156 QVector
<VertexMeshDensity
> vmd
;
157 if(!buffer
.isEmpty()) {
158 QTextStream
in(&buffer
, QIODevice::ReadOnly
);
159 in
>> row_count
>> column_count
;
160 QVector
<int> tmp_bcs
;
161 GuiMainWindow::pointer()->getAllBoundaryCodes(tmp_bcs
);
162 if (column_count
== tmp_bcs
.size() + 3) {
163 vmd
.fill(VertexMeshDensity(), row_count
);
164 for (int i
= 0; i
< row_count
; ++i
) {
167 foreach (int bc
, tmp_bcs
) {
168 in
>> row
>> column
>> formula
;
169 vmd
[row
].BCmap
[bc
] = formula
.toInt();
171 in
>> row
>> column
>> formula
;
172 vmd
[row
].type
= Str2VertexType(formula
);
173 in
>> row
>> column
>> formula
;
174 if (formula
== "{{{empty}}}") {
177 vmd
[i
].setNodes(formula
);
178 in
>> row
>> column
>> formula
;
179 vmd
[i
].density
= formula
.toDouble();
182 EG_ERR_RETURN(QObject::tr("Mismatch of number of boundary codes!"));
185 UpdateDesiredMeshDensity update
;
187 part
.setGrid(m_Grid
);
189 update
.setMeshPartition(part
);
190 update
.setVertexMeshDensityVector(vmd
);
191 update
.setBoundaryCodes(m_LayerAdjacentBoundaryCodes
);
195 void GuiCreateBoundaryLayer::insertPoints()
197 InsertPoints insert_points
;
199 part
.setGrid(m_Grid
);
201 insert_points
.setMeshPartition(part
);
202 insert_points
.setBoundaryCodes(m_LayerAdjacentBoundaryCodes
);
206 void GuiCreateBoundaryLayer::smoothSurface()
208 LaplaceSmoother smooth
;
210 part
.setGrid(m_Grid
);
212 smooth
.setMeshPartition(part
);
213 smooth
.setNumberOfIterations(5);
214 smooth
.setBoundaryCodes(m_LayerAdjacentBoundaryCodes
);
216 QVector
<bool> fix(m_Grid
->GetNumberOfPoints(), true);
217 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
218 for (int i
= 0; i
< part
.n2cGSize(id_node
); ++i
) {
219 if (m_Grid
->GetCellType(part
.n2cGG(id_node
, i
)) == VTK_WEDGE
) {
220 fix
[id_node
] = false;
224 for (int layer
= 0; layer
< 3; ++layer
) {
225 QVector
<bool> tmp
= fix
;
226 for (vtkIdType id_node
= 0; id_node
< m_Grid
->GetNumberOfPoints(); ++id_node
) {
228 for (int i
= 0; i
< part
.n2nGSize(id_node
); ++i
) {
229 fix
[part
.n2nGG(id_node
, i
)] = false;
235 smooth
.fixNodes(fix
);
239 void GuiCreateBoundaryLayer::operate()
241 if (!GuiMainWindow::pointer()->checkCadInterfaces()) {
242 GuiMainWindow::pointer()->storeCadInterfaces();
244 ///////////////////////////////////////////////////////////////
245 // set m_Grid to selected volume
246 getSelectedItems(m_Ui
.listWidgetBC
, m_BoundaryCodes
); // fill m_BoundaryCodes with values from listWidgetBC
247 QString volume_name
= getSelectedVolume(m_Ui
.listWidgetVC
);
248 VolumeDefinition V
= GuiMainWindow::pointer()->getVol(volume_name
);
249 foreach (int bc
, m_BoundaryCodes
) {
250 qDebug()<<"V.getSign("<<bc
<<")="<<V
.getSign(bc
);
251 if (V
.getSign(bc
) == 0) {
254 msg
= "Boundary code " + msg
+ " is not part of the volume '" + volume_name
+"'.";
259 EG_VTKSP(vtkUnstructuredGrid
, rest_grid
);
261 EG_VTKSP(vtkUnstructuredGrid
, vol_grid
);
262 MeshPartition
volume(volume_name
);
263 MeshPartition
rest(m_Grid
);
264 rest
.setRemainder(volume
);
265 volume
.setVolumeOrientation();
266 volume
.extractToVtkGrid(vol_grid
);
267 rest
.extractToVtkGrid(rest_grid
);
268 makeCopy(vol_grid
, m_Grid
);
272 l2g_t nodes
= getPartNodes();
273 g2l_t _nodes
= getPartLocalNodes();
274 l2g_t cells
= getPartCells();
275 g2l_t _cells
= getPartLocalCells();
276 l2l_t n2c
= getPartN2C();
277 l2l_t c2c
= getPartC2C();
278 getSurfaceCells(m_BoundaryCodes
, layer_cells
, m_Grid
);
280 bool delete_nodes
= m_Ui
.checkBoxRemovePoints
->isChecked();
282 // fill m_LayerAdjacentBoundaryCodes
283 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
284 foreach(vtkIdType id_cell
, layer_cells
) {
285 foreach(int i_cell_neighbour
, c2c
[_cells
[id_cell
]]) {
286 m_LayerAdjacentBoundaryCodes
.insert(cell_code
->GetValue(cells
[i_cell_neighbour
]));
289 m_LayerAdjacentBoundaryCodes
= m_LayerAdjacentBoundaryCodes
- m_BoundaryCodes
;
291 cout
<< "\n\ncreating boundary layer mesh)" << endl
;
293 if (!m_Ui
.checkBoxImprove
->isChecked()) {
294 EG_VTKDCN(vtkIntArray
, node_status
, m_Grid
, "node_status");
295 EG_VTKDCN(vtkIntArray
, node_layer
, m_Grid
, "node_layer");
296 EG_VTKDCC(vtkIntArray
, bc
, m_Grid
, "cell_code");
297 foreach(vtkIdType id_node
, nodes
) {
298 node_status
->SetValue(id_node
, 0);
300 foreach (int i_neigh_cells
, n2c
[_nodes
[id_node
]]) {
301 vtkIdType id_neigh_cell
= cells
[i_neigh_cells
];
302 if (isSurface(id_neigh_cell
, m_Grid
)) {
303 if (m_BoundaryCodes
.contains(bc
->GetValue(id_neigh_cell
))) {
304 bcs
.insert(bc
->GetValue(id_neigh_cell
));
308 if (bcs
.size() >= 2) {
309 node_status
->SetValue(id_node
, 1);
311 node_layer
->SetValue(id_node
, -1);
313 foreach (vtkIdType id_cell
, layer_cells
) {
314 EG_GET_CELL(id_cell
, m_Grid
);
315 for (int i_pts
= 0; i_pts
< num_pts
; ++i_pts
) {
316 node_layer
->SetValue(pts
[i_pts
], 0);
323 smooth
.setGrid(m_Grid
);
324 smooth
.setBoundaryCodes(m_BoundaryCodes
);
325 smooth
.setLayerAdjacentBoundaryCodes(m_LayerAdjacentBoundaryCodes
);
327 SeedSimplePrismaticLayer seed_layer
;
329 CreateVolumeMesh vol
;
332 swap
.setGrid(m_Grid
);
333 QSet
<int> swap_codes
= getAllBoundaryCodes(m_Grid
);
334 swap_codes
-= m_LayerAdjacentBoundaryCodes
;
335 swap
.setBoundaryCodes(swap_codes
);
336 swap
.setVerboseOff();
341 if (!m_Ui
.checkBoxImprove
->isChecked()) {
342 cout
<< "preparing prismatic layer" << endl
;
343 seed_layer
.setGrid(m_Grid
);
346 seed_layer
.setAllCells();
347 seed_layer
.setLayerCells(layer_cells
);
348 seed_layer
.setBoundaryCodes(m_BoundaryCodes
);
350 seed_layer
.getLayerCells(layer_cells
);
353 double Hr
= m_Ui
.doubleSpinBoxHeight
->value();
354 double Ha
= m_Ui
.lineEditAbsolute
->text().toDouble();
356 if (m_Ui
.checkBoxAbsolute
->isChecked()) {
359 smooth
.setRelativeHeight(Hr
);
360 smooth
.setAbsoluteHeight(Ha
);
361 smooth
.setBlending(bl
);
362 smooth
.setDesiredStretching(m_Ui
.doubleSpinBoxStretching
->value());
363 smooth
.setFarRatio(m_Ui
.doubleSpinBoxFarRatio
->value());
364 smooth
.setNumHeightRelaxations(m_Ui
.spinBoxHeightIterations
->value());
365 smooth
.setNumNormalRelaxations(m_Ui
.spinBoxNormalIterations
->value());
368 QString blayer_txt
= "";
369 QTextStream
s(&blayer_txt
);
373 s
<< m_Ui
.doubleSpinBoxStretching
->value() << " ";
374 s
<< m_Ui
.doubleSpinBoxFarRatio
->value() << " ";
376 s
<< m_Ui
.spinBoxHeightIterations
->value() << " ";
377 s
<< m_Ui
.spinBoxNormalIterations
->value() << " ";
378 GuiMainWindow::pointer()->setXmlSection("blayer/global", blayer_txt
);
382 for (int j
= 0; j
< m_Ui
.spinBoxIterations
->value(); ++j
) {
383 cout
<< "improving prismatic layer -> iteration " << j
+1 << "/" << m_Ui
.spinBoxIterations
->value() << endl
;
384 if (!m_Ui
.checkBoxSafeMode
->isChecked()) {
388 if (delete_nodes
|| m_Ui
.checkBoxSafeMode
->isChecked()) {
389 smooth
.forceNormalCalculation();
391 smooth
.setAllCells();
401 //vol.setTraceCells(layer_cells);
402 if (m_Ui
.checkBoxSafeMode
->isChecked()) {
405 //vol.getTraceCells(layer_cells);
409 EG_VTKDCC(vtkIntArray
, cell_code
, m_Grid
, "cell_code");
410 for (vtkIdType id_cell
= 0; id_cell
< m_Grid
->GetNumberOfCells(); ++id_cell
) {
411 if (isVolume(id_cell
, m_Grid
)) {
412 cell_code
->SetValue(id_cell
, V
.getVC());
417 ///////////////////////////////////////////////////////////////
418 // set m_Grid to modified selected volume + unselected volumes
420 MeshPartition
volume(m_Grid
, true);
421 MeshPartition
rest(rest_grid
, true);
422 volume
.addPartition(rest
);
424 resetOrientation(m_Grid
);
425 createIndices(m_Grid
);
426 ///////////////////////////////////////////////////////////////
429 void GuiCreateBoundaryLayer::SelectAll_BC()
431 for (int i
= 0; i
< m_Ui
.listWidgetBC
->count(); ++i
) {
432 m_Ui
.listWidgetBC
->item(i
)->setCheckState(Qt::Checked
);
436 void GuiCreateBoundaryLayer::ClearAll_BC()
438 for (int i
= 0; i
< m_Ui
.listWidgetBC
->count(); ++i
) {
439 m_Ui
.listWidgetBC
->item(i
)->setCheckState(Qt::Unchecked
);