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 "gridsmoother.h"
24 #include "guimainwindow.h"
30 GridSmoother::GridSmoother()
34 N_boundary_corrections
= 20;
42 getSet("boundary layer", "relative height of boundary layer", 0.75, m_RelativeHeight
);
43 getSet("boundary layer", "under relaxation", 1.00, m_UnderRelaxation
);
44 getSet("boundary layer", "maximal relative edge length", 1.50, m_MaxRelLength
);
46 getSet("boundary layer", "number of smoothing sub-iterations", 5, N_iterations
);
48 getSet("boundary layer", "use strict prism checking", true, m_StrictPrismChecking
);
49 getSet("boundary layer", "write debug file", true, m_WriteDebugFile
);
51 getErrSet("boundary layer", "layer height error", 200.0, 2.0, 2.0, 0.10, m_HeightError
);
52 getErrSet("boundary layer", "edge length error" , 200.0, 0.1, 2.0, 0.10, m_EdgeLengthError
);
53 getErrSet("boundary layer", "edge direction error" , 0.0, 0.0, 2.0, 0.00, m_EdgeDirectionError
);
54 getErrSet("boundary layer", "tetra error", 50.0, 0.1, 2.0, 0.05, m_TetraError
);
55 getErrSet("boundary layer", "parallel edges error", 1.0, 10.0, 2.0, 0.00, m_ParallelEdgesError
);
56 getErrSet("boundary layer", "parallel faces error", 1.0, 20.0, 2.0, 0.00, m_ParallelFacesError
);
57 getErrSet("boundary layer", "sharp nodes error", 0.0, 0.0, 2.0, 0.00, m_SharpNodesError
);
58 getErrSet("boundary layer", "sharp edges error", 0.0, 0.0, 2.0, 0.00, m_SharpEdgesError
);
59 getErrSet("boundary layer", "similar face area error", 0.0, 1.0, 2.0, 0.00, m_SimilarFaceAreaError
);
60 getErrSet("boundary layer", "feature line error", 0.0, 0.0, 2.0, 0.00, m_FeatureLineError
);
62 m_CritAngle
= GeometryTools::deg2rad(450.0);
66 void GridSmoother::computeNormals()
68 EG_VTKDCC(vtkIntArray
, cell_code
, grid
, "cell_code");
69 m_NodeNormal
.fill(vec3_t(0,0,0), grid
->GetNumberOfPoints());
70 for (vtkIdType id_node
= 0; id_node
< grid
->GetNumberOfPoints(); ++id_node
) {
72 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
73 vtkIdType id_cell
= m_Part
.n2cGG(id_node
, i
);
74 if (isSurface(id_cell
, grid
)) {
75 int bc
= cell_code
->GetValue(id_cell
);
76 if (m_BoundaryCodes
.contains(bc
)) {
81 int num_bcs
= bcs
.size();
82 QVector
<vec3_t
> normal(num_bcs
, vec3_t(0,0,0));
85 foreach (int bc
, bcs
) {
89 for (int i
= 0; i
< m_Part
.n2cGSize(id_node
); ++i
) {
90 vtkIdType id_cell
= m_Part
.n2cGG(id_node
, i
);
91 if (isSurface(id_cell
, grid
)) {
92 int bc
= cell_code
->GetValue(id_cell
);
93 if (m_BoundaryCodes
.contains(bc
)) {
94 vtkIdType N_pts
, *pts
;
95 grid
->GetCellPoints(id_cell
, N_pts
, pts
);
97 for (int j
= 0; j
< N_pts
; ++j
) {
98 if (pts
[j
] == id_node
) {
99 grid
->GetPoint(pts
[j
], a
.data());
101 grid
->GetPoint(pts
[j
-1], b
.data());
103 grid
->GetPoint(pts
[N_pts
-1], b
.data());
106 grid
->GetPoint(pts
[j
+1], c
.data());
108 grid
->GetPoint(pts
[0], c
.data());
114 double alpha
= GeometryTools::angle(u
, v
);
115 vec3_t n
= u
.cross(v
);
117 normal
[bcmap
[bc
]] += alpha
*n
;
121 for (int i
= 0; i
< num_bcs
; ++i
) {
122 normal
[i
].normalise();
126 for (int i
= 0; i
< num_bcs
; ++i
) {
127 for (int j
= i
+ 1; j
< num_bcs
; ++j
) {
128 vec3_t n
= normal
[i
] + normal
[j
];
130 m_NodeNormal
[id_node
] += n
;
134 m_NodeNormal
[id_node
] = normal
[0];
136 m_NodeNormal
[id_node
].normalise();
141 void GridSmoother::markNodes()
143 node_marked
.fill(false,grid
->GetNumberOfPoints());
144 QVector
<bool> new_mark(grid
->GetNumberOfPoints());
145 for (int i_iterations
= 0; i_iterations
< 4; ++i_iterations
) {
146 qCopy(node_marked
.begin(),node_marked
.end(),new_mark
.begin());
147 for (vtkIdType id_cell
= 0; id_cell
< grid
->GetNumberOfCells(); ++id_cell
) {
148 bool mark_cell
= false;
149 vtkIdType type_cell
, N_pts
, *pts
;
150 type_cell
= grid
->GetCellType(id_cell
);
151 grid
->GetCellPoints(id_cell
, N_pts
, pts
);
152 if (type_cell
== VTK_WEDGE
) {
155 for (int i_pts
= 0; i_pts
< N_pts
; ++i_pts
) {
156 if (node_marked
[pts
[i_pts
]]) {
162 for (int i_pts
= 0; i_pts
< N_pts
; ++i_pts
) {
163 new_mark
[pts
[i_pts
]] = true;
167 qCopy(new_mark
.begin(),new_mark
.end(),node_marked
.begin());
170 QVector
<vtkIdType
> nodes
= m_Part
.getNodes();
171 foreach (vtkIdType id_node
, nodes
) {
172 if (id_node
< 0) EG_BUG
;
173 if (id_node
> grid
->GetNumberOfPoints()) EG_BUG
;
174 if (node_marked
[id_node
]) {
180 bool GridSmoother::setNewPosition(vtkIdType id_node
, vec3_t x_new
)
182 using namespace GeometryTools
;
185 grid
->GetPoint(id_node
, x_old
.data());
186 grid
->GetPoints()->SetPoint(id_node
, x_new
.data());
190 l2g_t cells
= getPartCells();
191 l2l_t n2c
= getPartN2C();
192 foreach (int i_cells
, n2c
[id_node
]) {
193 vtkIdType id_cell
= cells
[i_cells
];
194 vtkIdType type_cell
= grid
->GetCellType(id_cell
);
195 if (type_cell
== VTK_TETRA
) {
196 if (GeometryTools::cellVA(grid
, id_cell
) < 0) {
198 //if (dbg) cout << id_node << " : tetra negative" << endl;
201 if (type_cell
== VTK_WEDGE
&& m_StrictPrismChecking
) {
202 vtkIdType N_pts
, *pts
;
204 grid
->GetCellPoints(id_cell
, N_pts
, pts
);
206 for (int i
= 0; i
< 4; ++i
) { // variation
208 for (int j
= 0; j
< 3; ++j
) { // tetrahedron
209 for (int k
= 0; k
< 4; ++k
) { // node
210 grid
->GetPoint(pts
[E
.priTet(i
,j
,k
)], xtet
[k
].data());
212 if (GeometryTools::tetraVol(xtet
[0], xtet
[1], xtet
[2], xtet
[3]) < 0) {
214 //if (dbg) cout << id_node << " : prism negative" << endl;
228 grid
->GetPoints()->SetPoint(id_node
, x_old
.data());
233 void GridSmoother::correctDx(int i_nodes
, vec3_t
&Dx
)
235 l2g_t nodes
= m_Part
.getNodes();
236 l2l_t n2c
= m_Part
.getN2C();
238 for (int i_boundary_correction
= 0; i_boundary_correction
< N_boundary_corrections
; ++i_boundary_correction
) {
239 foreach (vtkIdType id_cell
, n2c
[i_nodes
]) {
240 if (isSurface(id_cell
, grid
)) {
241 double A
= GeometryTools::cellVA(grid
, id_cell
);
243 vec3_t n
= GeometryTools::cellNormal(grid
, id_cell
);
248 if (grid
->GetCellType(id_cell
) == VTK_WEDGE
) {
249 vtkIdType N_pts
, *pts
;
250 grid
->GetCellPoints(id_cell
, N_pts
, pts
);
251 vtkIdType id_surf_node
= -1;
252 if (pts
[3] == nodes
[i_nodes
]) id_surf_node
= pts
[0];
253 if (pts
[4] == nodes
[i_nodes
]) id_surf_node
= pts
[1];
254 if (pts
[5] == nodes
[i_nodes
]) id_surf_node
= pts
[2];
255 if (id_surf_node
!= -1) {
257 grid
->GetPoint(pts
[0],x0
.data());
258 grid
->GetPoint(pts
[1],x1
.data());
259 grid
->GetPoint(pts
[2],x2
.data());
263 double L
= (a
.abs()+b
.abs()+c
.abs())/3.0;
264 vec3_t n
= b
.cross(a
);
267 grid
->GetPoint(nodes
[i_nodes
],x_old
.data());
268 vec3_t x_new
= x_old
+ Dx
- x0
;
269 if ( (n
*x_new
) <= 0 ) {
270 x_new
-= (x_new
*n
)*n
;
282 bool GridSmoother::moveNode(int i_nodes
, vec3_t
&Dx
)
284 l2g_t nodes
= getPartNodes();
285 vtkIdType id_node
= nodes
[i_nodes
];
287 grid
->GetPoint(id_node
, x_old
.data());
289 if (m_IdFoot
[id_node
] != -1) {
291 grid
->GetPoint(m_IdFoot
[id_node
], x_foot
.data());
292 Dx
+= x_old
- x_foot
;
293 if (Dx
.abs() > m_MaxRelLength
*m_L
[id_node
]) {
295 Dx
*= m_MaxRelLength
*m_L
[id_node
];
297 Dx
-= x_old
- x_foot
;
301 for (int i_relaxation
= 0; i_relaxation
< N_relaxations
; ++i_relaxation
) {
302 if (setNewPosition(id_node
, x_old
+ Dx
)) {
311 double GridSmoother::func(vec3_t x
)
313 l2g_t nodes
= getPartNodes();
314 l2l_t n2c
= getPartN2C();
315 l2g_t cells
= getPartCells();
316 l2l_t c2c
= getPartC2C();
319 grid
->GetPoint(nodes
[i_nodes_opt
], x_old
.data());
320 grid
->GetPoints()->SetPoint(nodes
[i_nodes_opt
], x
.data());
322 double f13
= 1.0/3.0;
325 vec3_t
n_node(1,0,0);
328 EG_VTKDCN(vtkDoubleArray
, cl
, grid
, "node_meshdensity_desired" );
334 foreach (int i_cells
, n2c
[i_nodes_opt
]) {
335 vtkIdType id_cell
= cells
[i_cells
];
336 if (isVolume(id_cell
, grid
)) {
337 vtkIdType type_cell
= grid
->GetCellType(id_cell
);
338 vtkIdType N_pts
, *pts
;
339 grid
->GetCellPoints(id_cell
, N_pts
, pts
);
340 QVector
<vec3_t
> xn(N_pts
);
341 for (int i_pts
= 0; i_pts
< N_pts
; ++i_pts
) {
342 grid
->GetPoint(pts
[i_pts
],xn
[i_pts
].data());
344 if (type_cell
== VTK_TETRA
) {
345 if (m_TetraError
.active()) {
347 L
= max(L
, (xn
[0]-xn
[1]).abs());
348 L
= max(L
, (xn
[0]-xn
[2]).abs());
349 L
= max(L
, (xn
[0]-xn
[3]).abs());
350 L
= max(L
, (xn
[1]-xn
[2]).abs());
351 L
= max(L
, (xn
[1]-xn
[3]).abs());
352 L
= max(L
, (xn
[2]-xn
[3]).abs());
353 double H
= sqrt(2.0/3.0)*L
;
355 vec3_t n012
= GeometryTools::triNormal(xn
[0], xn
[1], xn
[2]);
356 vec3_t n031
= GeometryTools::triNormal(xn
[0], xn
[3], xn
[1]);
357 vec3_t n023
= GeometryTools::triNormal(xn
[0], xn
[2], xn
[3]);
358 vec3_t n213
= GeometryTools::triNormal(xn
[2], xn
[1], xn
[3]);
364 h
= min(h
, fabs((xn
[0]-xn
[3])*n012
));
365 h
= min(h
, fabs((xn
[0]-xn
[2])*n031
));
366 h
= min(h
, fabs((xn
[0]-xn
[1])*n023
));
367 h
= min(h
, fabs((xn
[0]-xn
[3])*n213
));
369 f
+= m_TetraError(h
);
372 if (type_cell
== VTK_WEDGE
) {
374 vec3_t a
= xn
[2]-xn
[0];
375 vec3_t b
= xn
[1]-xn
[0];
376 vec3_t c
= xn
[5]-xn
[3];
377 vec3_t d
= xn
[4]-xn
[3];
380 n_face
[0] = GeometryTools::triNormal(xn
[0],xn
[1],xn
[2]);
381 n_face
[1] = GeometryTools::triNormal(xn
[3],xn
[5],xn
[4]);
382 n_face
[2] = GeometryTools::quadNormal(xn
[0],xn
[3],xn
[4],xn
[1]);
383 n_face
[3] = GeometryTools::quadNormal(xn
[1],xn
[4],xn
[5],xn
[2]);
384 n_face
[4] = GeometryTools::quadNormal(xn
[0],xn
[2],xn
[5],xn
[3]);
385 x_face
[0] = f13
*(xn
[0]+xn
[1]+xn
[2]);
386 x_face
[1] = f13
*(xn
[3]+xn
[4]+xn
[5]);
387 x_face
[2] = f14
*(xn
[0]+xn
[3]+xn
[4]+xn
[1]);
388 x_face
[3] = f14
*(xn
[1]+xn
[4]+xn
[5]+xn
[2]);
389 x_face
[4] = f14
*(xn
[0]+xn
[2]+xn
[5]+xn
[3]);
391 double A1
= 0.5*n_face
[0].abs();
392 double A2
= 0.5*n_face
[1].abs();
393 for (int i_face
= 0; i_face
< 5; ++i_face
) {
394 n_face
[i_face
].normalise();
396 m_IdFoot
[pts
[3]] = pts
[0];
397 m_IdFoot
[pts
[4]] = pts
[1];
398 m_IdFoot
[pts
[5]] = pts
[2];
399 vec3_t v0
= xn
[0]-xn
[3];
400 vec3_t v1
= xn
[1]-xn
[4];
401 vec3_t v2
= xn
[2]-xn
[5];
402 double h0
= v0
*n_face
[0];
403 double h1
= v1
*n_face
[0];
404 double h2
= v2
*n_face
[0];
405 if (m_HeightError
.active() || m_EdgeLengthError
.active() || m_EdgeDirectionError
.active()) {
408 if (nodes
[i_nodes_opt
] == pts
[3]) {
411 if (nodes
[i_nodes_opt
] == pts
[4]) {
414 if (nodes
[i_nodes_opt
] == pts
[5]) {
418 L
= m_RelativeHeight
*cl
->GetValue(pts
[i_foot
]);
419 n_node
= xn
[i_foot
+ 3] - xn
[i_foot
];
420 n_pri
.append(n_face
[1]);
426 m_L
[nodes
[i_nodes_opt
]] = L
;
429 l
= -(v0
*m_NodeNormal
[pts
[0]])/L
;
431 } else if (i_foot
== 1) {
433 l
= -(v1
*m_NodeNormal
[pts
[1]])/L
;
435 } else if (i_foot
== 2) {
437 l
= -(v2
*m_NodeNormal
[pts
[2]])/L
;
442 f
+= m_HeightError(h
);
443 f
+= m_EdgeLengthError(l
);
444 f
+= m_EdgeDirectionError(angleX(m_NodeNormal
[pts
[i_foot
]],ve
));
446 if (m_ParallelEdgesError
.active()) {
447 if ((h0
> 0.01*L
) && (h1
> 0.01*L
) && (h2
> 0.01*L
)) {
451 f
+= f13
*m_ParallelEdgesError(angleX(v0
,v1
));
452 f
+= f13
*m_ParallelEdgesError(angleX(v0
,v2
));
453 f
+= f13
*m_ParallelEdgesError(angleX(v1
,v2
));
456 if (m_ParallelFacesError
.active()) {
457 if ((h0
> 0.01*L
) && (h1
> 0.01*L
) && (h2
> 0.01*L
)) {
458 f
+= m_ParallelFacesError(angleX(-1*n_face
[0],n_face
[1]));
461 if (m_SimilarFaceAreaError
.active()) {
462 if ((h0
> 0.01*L
) && (h1
> 0.01*L
) && (h2
> 0.01*L
)) {
463 f
+= m_SimilarFaceAreaError(fabs(1.0 - 2*(A1
-A2
)/(A1
+A2
)));
468 if (m_SharpEdgesError
.active()) {
469 for (int j
= 2; j
<= 4; ++j
) {
470 vtkIdType id_ncell
= c2c
[id_cell
][j
];
471 if (id_ncell
!= -1) {
472 if (grid
->GetCellType(id_ncell
) == VTK_WEDGE
) {
473 vtkIdType N_pts
, *pts
;
474 grid
->GetCellPoints(id_ncell
, N_pts
, pts
);
475 QVector
<vec3_t
> x(3);
476 for (int i_pts
= 3; i_pts
<= 5; ++i_pts
) {
477 grid
->GetPoint(pts
[i_pts
],x
[i_pts
-3].data());
479 vec3_t n
= GeometryTools::triNormal(x
[0], x
[2], x
[1]);
481 f
+= f13
*m_SharpEdgesError(0.5*(1 + n_face
[1]*n
));
489 grid
->GetPoints()->SetPoint(nodes
[i_nodes_opt
], x_old
.data());
492 //CHECK THAT THERE ARE NO BOUNDARY NODE NEIGHBOURS!!!!!!!!!!
494 if (m_SharpNodesError
.active()) {
495 if (n_pri
.size() > 0) {
496 bool apply_error
= true;
497 for (int i
= 0; i
< m_Part
.n2nLSize(i_nodes_opt
); ++i
) {
498 vtkIdType id_neigh_node
= m_Part
.n2nLG(i_nodes_opt
, i
);
499 vtkIdType id_foot
= m_IdFoot
[nodes
[i_nodes_opt
]];
500 int Nbcs
= m_Node2BC
[id_neigh_node
].size();
501 if (m_Node2BC
[id_neigh_node
].size() != 0 && id_neigh_node
!= m_IdFoot
[nodes
[i_nodes_opt
]]) {
508 foreach (vec3_t n1
, n_pri
) {
509 foreach (vec3_t n2
, n_pri
) {
510 //e = max(e, m_SharpNodesError(angleX(n1, n2)));
511 e
= max(e
, m_SharpNodesError(0.5*(1 + n1
*n2
)));
519 // smooth feature lines
520 vtkIdType id_node1
= nodes
[i_nodes_opt
];
521 vtkIdType id_foot1
= m_IdFoot
[id_node1
];
522 if (id_foot1
!= -1 && m_FeatureLineError
.active()) {
523 if (m_Node2BC
[id_foot1
].size() == 2) {
524 QVector
<vtkIdType
> ids(2, -1);
526 for (int i
= 0; i
< m_Part
.n2nGSize(id_node1
); ++i
) {
527 vtkIdType id_node2
= m_Part
.n2nGG(id_node1
, i
);
528 vtkIdType id_foot2
= m_IdFoot
[id_node2
];
529 if (id_foot2
!= -1) {
531 foreach (int bc
, m_Node2BC
[id_foot1
]) {
532 if (!m_Node2BC
[id_foot2
].contains(bc
)) {
547 grid
->GetPoint(ids
[0], a
.data());
548 grid
->GetPoint(ids
[1], b
.data());
551 f
+= m_FeatureLineError(0.5*(1 + u
*v
));
559 void GridSmoother::resetStencil()
564 void GridSmoother::addToStencil(double C
, vec3_t x
)
572 void GridSmoother::operate()
577 EG_VTKDCC(vtkIntArray
, bc
, grid
, "cell_code");
578 EG_VTKDCN(vtkIntArray
, node_status
, grid
, "node_status");
579 EG_VTKDCN(vtkIntArray
, node_layer
, grid
, "node_layer");
581 m_Node2BC
.fill(QSet
<int>(), grid
->GetNumberOfPoints());
582 for (vtkIdType id_cell
= 0; id_cell
< grid
->GetNumberOfCells(); ++id_cell
) {
583 if (isSurface(id_cell
, grid
)) {
584 vtkIdType N_pts
, *pts
;
585 grid
->GetCellPoints(id_cell
, N_pts
, pts
);
586 for (int i_pts
= 0; i_pts
< N_pts
; ++i_pts
) {
587 m_Node2BC
[pts
[i_pts
]].insert(bc
->GetValue(id_cell
));
592 m_IdFoot
.fill(-1, grid
->GetNumberOfPoints());
593 m_L
.fill(0, grid
->GetNumberOfPoints());
596 l2g_t nodes
= getPartNodes();
597 g2l_t _nodes
= getPartLocalNodes();
598 l2g_t cells
= getPartCells();
599 l2l_t n2c
= getPartN2C();
600 l2l_t n2n
= getPartN2N();
602 QVector
<bool> prism_node(nodes
.size(),false);
603 foreach (vtkIdType id_cell
, cells
) {
604 if (grid
->GetCellType(id_cell
) == VTK_WEDGE
) {
605 vtkIdType N_pts
, *pts
;
606 grid
->GetCellPoints(id_cell
, N_pts
, pts
);
607 for (int i_pts
= 0; i_pts
< N_pts
; ++i_pts
) {
608 if (_nodes
[pts
[i_pts
]] != -1) {
609 prism_node
[_nodes
[pts
[i_pts
]]] = true;
617 for (int i_nodes
= 0; i_nodes
< nodes
.size(); ++i_nodes
) {
618 if (prism_node
[i_nodes
]) {
620 i_nodes_opt
= i_nodes
;
621 grid
->GetPoint(nodes
[i_nodes
], x
.data());
624 F_max_old
= max(F_max_old
,f
);
628 cout
<< "\nsmoothing volume mesh (" << N_marked_nodes
<< " nodes)" << endl
;
629 for (int i_iterations
= 0; i_iterations
< N_iterations
; ++i_iterations
) {
630 cout
<< "iteration " << i_iterations
+1 << "/" << N_iterations
<< endl
;
637 QTime start
= QTime::currentTime();
638 for (int i_nodes
= 0; i_nodes
< nodes
.size(); ++i_nodes
) {
640 bool smooth
= node_marked
[nodes
[i_nodes
]];
642 foreach (int bc
, m_Node2BC
[_nodes
[i_nodes
]]) {
643 if (m_BoundaryCodes
.contains(bc
) || (m_BoundaryCodes
.size() ==0)) {
647 foreach (int i_cells
, n2c
[i_nodes
]) {
648 vtkIdType type_cell
= grid
->GetCellType(cells
[i_cells
]);
649 if ((type_cell
== VTK_WEDGE
) && !smooth_prisms
) {
655 vtkIdType id_node
= nodes
[i_nodes
];
658 grid
->GetPoint(id_node
, x_old
.data());
660 bool is_surf
= m_Node2BC
[_nodes
[i_nodes
]].size() > 0;
662 foreach (int j_nodes
, n2n
[i_nodes
]) {
663 if (!is_surf
|| (m_Node2BC
[_nodes
[j_nodes
]].size() > 0)) {
664 vtkIdType id_neigh_node
= nodes
[j_nodes
];
665 grid
->GetPoint(id_neigh_node
, xn
.data());
666 addToStencil(1.0, xn
);
673 vec3_t x_new1
= vec3_t(0,0,0);
677 foreach (stencil_node_t sn
, stencil
) {
680 double L
= (sn
.x
- x_old
).abs();
682 L_min
= min(L_min
, L
);
686 vec3_t Dx1
= x_new1
- x_old
;
689 i_nodes_opt
= i_nodes
;
691 Dx2
= m_UnderRelaxation
*optimise(x_old
);
692 vec3_t Dx3
= (-1e-4/func(x_old
))*grad_f
;
693 correctDx(i_nodes
, Dx1
);
694 correctDx(i_nodes
, Dx2
);
695 correctDx(i_nodes
, Dx3
);
697 double f
= func(x_old
+ Dx1
);
701 if (f
> func(x_old
+ Dx2
)) {
703 f
= func(x_old
+ Dx2
);
708 if (f
> func(x_old
+ Dx3
)) {
715 if (!moveNode(i_nodes
, Dx
)) {
716 // search for a better place
717 vec3_t x_save
= x_old
;
718 vec3_t
ex(L_search
*L0
/N_search
,0,0);
719 vec3_t
ey(0,L_search
*L0
/N_search
,0);
720 vec3_t
ez(0,0,L_search
*L0
/N_search
);
721 vec3_t x_best
= x_old
;
722 double f_min
= func(x_old
);
724 bool illegal
= false;
725 if (!setNewPosition(id_node
,x_old
)) {
728 for (int i
= -N_search
; i
<= N_search
; ++i
) {
729 for (int j
= -N_search
; j
<= N_search
; ++j
) {
730 for (int k
= -N_search
; k
<= N_search
; ++k
) {
731 if ((i
!= 0) || (j
!= 0) || (k
!= 0)) {
732 vec3_t Dx
= double(i
)*ex
+ double(j
)*ey
+ double(k
)*ez
;
733 correctDx(i_nodes
, Dx
);
734 vec3_t x
= x_old
+ x
;
735 if (setNewPosition(id_node
, x
)) {
736 grid
->GetPoints()->SetPoint(id_node
, x_old
.data());
750 grid
->GetPoints()->SetPoint(id_node
, x_best
.data());
766 cout
<< N1
<< " type 1 movements (simple)" << endl
;
767 cout
<< N2
<< " type 2 movements (Newton)" << endl
;
768 cout
<< N3
<< " type 3 movements (gradient)" << endl
;
769 cout
<< N_searched
<< " type X movements (search)" << endl
;
770 cout
<< N_blocked
<< " type 0 movements (failure)" << endl
;
772 cout
<< start
.secsTo(QTime::currentTime()) << " seconds elapsed" << endl
;
776 m_HeightError
.reset();
777 m_EdgeLengthError
.reset();
778 m_TetraError
.reset();
779 m_SharpEdgesError
.reset();
780 m_SharpNodesError
.reset();
781 m_ParallelEdgesError
.reset();
782 m_ParallelFacesError
.reset();
783 m_SimilarFaceAreaError
.reset();
784 m_FeatureLineError
.reset();
785 for (int i_nodes
= 0; i_nodes
< nodes
.size(); ++i_nodes
) {
786 if (prism_node
[i_nodes
]) {
788 i_nodes_opt
= i_nodes
;
789 grid
->GetPoint(nodes
[i_nodes
], x
.data());
792 F_max_new
= max(F_max_new
,f
);
795 cout
<< "total error (old) = " << F_old
<< endl
;
796 cout
<< "total error (new) = " << F_new
<< endl
;
797 double f_old
= max(1e-10,F_old
);
798 cout
<< "total improvement = " << 100*(1-F_new
/f_old
) << "%" << endl
;
801 if (m_WriteDebugFile
) {
802 writeDebugFile("gridsmoother");
804 cout
<< "done" << endl
;
807 double GridSmoother::improvement()
809 double f_max_old
= max(1e-10,F_max_old
);
810 double f_old
= max(1e-10,F_old
);
811 double i2
= 1-F_new
/f_old
;
815 void GridSmoother::printMaxErrors()
817 cout
<< "maximal height error = " << m_HeightError
.maxError() << endl
;
818 cout
<< "maximal edge lenth error = " << m_EdgeLengthError
.maxError() << endl
;
819 cout
<< "maximal tetra error = " << m_TetraError
.maxError() << endl
;
820 cout
<< "maximal sharp nodes error = " << m_SharpNodesError
.maxError() << endl
;
821 cout
<< "maximal sharp edges error = " << m_SharpEdgesError
.maxError() << endl
;
822 cout
<< "maximal parallel edges error = " << m_ParallelEdgesError
.maxError() << endl
;
823 cout
<< "maximal parallel faces error = " << m_ParallelFacesError
.maxError() << endl
;
824 cout
<< "maximal face area error = " << m_SimilarFaceAreaError
.maxError() << endl
;
825 cout
<< "maximal feature line error = " << m_FeatureLineError
.maxError() << endl
;
828 void GridSmoother::writeDebugFile(QString file_name
)
830 QVector
<vtkIdType
> bcells
;
831 getSurfaceCells(m_BoundaryCodes
, bcells
, grid
);
832 MeshPartition
bpart(grid
);
833 bpart
.setCells(bcells
);
834 QVector
<vtkIdType
> foot2field(bpart
.getNumberOfNodes(), -1);
835 for (vtkIdType id_node
= 0; id_node
< grid
->GetNumberOfPoints(); ++id_node
) {
836 vtkIdType id_foot
= m_IdFoot
[id_node
];
838 if (bpart
.localNode(id_foot
) == -1) {
841 foot2field
[bpart
.localNode(id_foot
)] = id_node
;
844 file_name
= GuiMainWindow::pointer()->getCwd() + "/" + file_name
+ ".vtk";
845 QFile
file(file_name
);
846 file
.open(QIODevice::WriteOnly
);
847 QTextStream
f(&file
);
848 f
<< "# vtk DataFile Version 2.0\n";
849 f
<< "m_NodeNormal\n";
851 f
<< "DATASET UNSTRUCTURED_GRID\n";
852 f
<< "POINTS " << 2*bpart
.getNumberOfNodes() << " float\n";
853 for (int i
= 0; i
< bpart
.getNumberOfNodes(); ++i
) {
855 vtkIdType id_node
= bpart
.globalNode(i
);
856 grid
->GetPoint(id_node
, x
.data());
857 f
<< x
[0] << " " << x
[1] << " " << x
[2] << "\n";
859 for (int i
= 0; i
< bpart
.getNumberOfNodes(); ++i
) {
861 vtkIdType id_node
= foot2field
[i
];
862 grid
->GetPoint(id_node
, x
.data());
863 f
<< x
[0] << " " << x
[1] << " " << x
[2] << "\n";
865 f
<< "CELLS " << 2*bpart
.getNumberOfCells() << " " << 8*bpart
.getNumberOfCells() << "\n";
866 for (int i
= 0; i
< bpart
.getNumberOfCells(); ++ i
) {
867 vtkIdType id_cell
= bpart
.globalCell(i
);
868 vtkIdType N_pts
, *pts
;
869 if (grid
->GetCellType(id_cell
) != VTK_TRIANGLE
) {
872 grid
->GetCellPoints(id_cell
, N_pts
, pts
);
873 QVector
<int> nds1(3), nds2(3);
874 for (int j
= 0; j
< 3; ++j
) {
875 nds1
[j
] = bpart
.localNode(pts
[j
]);
876 nds2
[j
] = nds1
[j
] + bpart
.getNumberOfNodes();
878 f
<< "3 " << nds1
[0] << " " << nds1
[1] << " " << nds1
[2] << "\n";
879 f
<< "3 " << nds2
[0] << " " << nds2
[1] << " " << nds2
[2] << "\n";
882 f
<< "CELL_TYPES " << 2*bpart
.getNumberOfCells() << "\n";
883 for (int i
= 0; i
< 2*bpart
.getNumberOfCells(); ++ i
) {
884 f
<< VTK_TRIANGLE
<< "\n";
886 f
<< "POINT_DATA " << 2*bpart
.getNumberOfNodes() << "\n";
887 f
<< "VECTORS N float\n";
889 for (int i
= 0; i
< bpart
.getNumberOfNodes(); ++i
) {
890 vtkIdType id_node
= bpart
.globalNode(i
);
891 f
<< m_NodeNormal
[id_node
][0] << " " << m_NodeNormal
[id_node
][1] << " " << m_NodeNormal
[id_node
][2] << "\n";
893 for (int i
= 0; i
< bpart
.getNumberOfNodes(); ++i
) {