surfaceOptimizer.C
Go to the documentation of this file.
1 /*---------------------------------------------------------------------------*\
2  ========= |
3  \\ / F ield | cfMesh: A library for mesh generation
4  \\ / O peration |
5  \\ / A nd | Author: Franjo Juretic (franjo.juretic@c-fields.com)
6  \\/ M anipulation | Copyright (C) Creative Fields, Ltd.
7 -------------------------------------------------------------------------------
8 License
9  This file is part of cfMesh.
10 
11  cfMesh is free software; you can redistribute it and/or modify it
12  under the terms of the GNU General Public License as published by the
13  Free Software Foundation; either version 3 of the License, or (at your
14  option) any later version.
15 
16  cfMesh is distributed in the hope that it will be useful, but WITHOUT
17  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
18  FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
19  for more details.
20 
21  You should have received a copy of the GNU General Public License
22  along with cfMesh. If not, see <http://www.gnu.org/licenses/>.
23 
24 Description
25 
26 \*---------------------------------------------------------------------------*/
27 
28 #include "demandDrivenData.H"
29 #include "surfaceOptimizer.H"
30 #include "matrix2D.H"
31 
32 //#define DEBUGSmooth
33 
34 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
35 
36 namespace Foam
37 {
38 
39 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
40 
42  {
43  vector(-1.0, -1.0, 0.0),
44  vector(1.0, -1.0, 0.0),
45  vector(-1.0, 1.0, 0.0),
46  vector(1.0, 1.0, 0.0)
47  };
48 
49 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
50 
52 {
53  //- find the minimum area
54  scalar Amin(VGREAT), LsqMax(0.0);
55  forAll(trias_, triI)
56  {
57  const point& p0 = pts_[trias_[triI][0]];
58  const point& p1 = pts_[trias_[triI][1]];
59  const point& p2 = pts_[trias_[triI][2]];
60 
61  const scalar Atri =
62  0.5 *
63  (
64  (p1.x() - p0.x()) * (p2.y() - p0.y()) -
65  (p2.x() - p0.x()) * (p1.y() - p0.y())
66  );
67 
68  # ifdef DEBUGSmooth
69  Info << "Triangle " << triI << " area " << Atri << endl;
70  # endif
71 
72  const scalar LSqrTri
73  (
74  magSqr(p0 - p1) +
75  magSqr(p2 - p0)
76  );
77 
78  Amin = Foam::min(Amin, Atri);
79  LsqMax = Foam::max(LsqMax, LSqrTri);
80  }
81 
82  # ifdef DEBUGSmooth
83  Info << "Amin " << Amin << endl;
84  Info << "LsqMax " << LsqMax << endl;
85  # endif
86 
87  //- K is greater than zero in case the stabilisation is needed
88  scalar K = 0.0;
89  if( Amin < SMALL * LsqMax )
90  {
91  K = SMALL * LsqMax;
92  }
93 
94  return K;
95 }
96 
97 scalar surfaceOptimizer::evaluateFunc(const scalar& K) const
98 {
99  scalar func(0.0);
100 
101  forAll(trias_, triI)
102  {
103  const point& p0 = pts_[trias_[triI][0]];
104  const point& p1 = pts_[trias_[triI][1]];
105  const point& p2 = pts_[trias_[triI][2]];
106 
107  const scalar Atri =
108  0.5 *
109  (
110  (p1.x() - p0.x()) * (p2.y() - p0.y()) -
111  (p2.x() - p0.x()) * (p1.y() - p0.y())
112  );
113 
114  const scalar stab = sqrt(sqr(Atri) + K);
115 
116  # ifdef DEBUGSmooth
117  Info << "Triangle " << triI << " area " << Atri << endl;
118  # endif
119 
120  const scalar LSqrTri
121  (
122  magSqr(p0 - p1) +
123  magSqr(p2 - p0)
124  );
125 
126  const scalar Astab = Foam::max(VSMALL, 0.5 * (Atri + stab));
127  func += LSqrTri / Astab;
128  }
129 
130  return func;
131 }
132 
133 //- evaluate gradients needed for optimisation
135 (
136  const scalar& K,
137  vector& gradF,
138  tensor& gradGradF
139 ) const
140 {
141  gradF = vector::zero;
142  gradGradF = tensor::zero;
143 
144  tensor gradGradLt(tensor::zero);
145  gradGradLt.xx() = 4.0;
146  gradGradLt.yy() = 4.0;
147 
148  forAll(trias_, triI)
149  {
150  const point& p0 = pts_[trias_[triI][0]];
151  const point& p1 = pts_[trias_[triI][1]];
152  const point& p2 = pts_[trias_[triI][2]];
153 
154  if( magSqr(p1 - p2) < VSMALL ) continue;
155 
156  const scalar LSqrTri
157  (
158  magSqr(p0 - p1) +
159  magSqr(p2 - p0)
160  );
161 
162  const scalar Atri =
163  0.5 *
164  (
165  (p1.x() - p0.x()) * (p2.y() - p0.y()) -
166  (p2.x() - p0.x()) * (p1.y() - p0.y())
167  );
168 
169  const scalar stab = sqrt(sqr(Atri) + K);
170 
171  const scalar Astab = Foam::max(ROOTVSMALL, 0.5 * (Atri + stab));
172 
173  const vector gradAtri
174  (
175  0.5 * (p1.y() - p2.y()),
176  0.5 * (p2.x() - p1.x()),
177  0.0
178  );
179 
180  const vector gradAstab = 0.5 * (gradAtri + Atri * gradAtri / stab);
181 
182  const tensor gradGradAstab =
183  0.5 *
184  (
185  (gradAtri * gradAtri) / stab -
186  sqr(Atri) * (gradAtri * gradAtri) / pow(stab, 3)
187  );
188 
189  const vector gradLt(4.0 * p0 - 2.0 * p1 - 2.0 * p2);
190 
191  //- calculate the gradient
192  const scalar sqrAstab = sqr(Astab);
193  gradF += gradLt / Astab - (LSqrTri * gradAstab) / sqrAstab;
194 
195  //- calculate the second gradient
196  gradGradF +=
197  gradGradLt / Astab -
198  twoSymm(gradLt * gradAstab) / sqrAstab -
199  gradGradAstab * LSqrTri / sqrAstab +
200  2.0 * LSqrTri * (gradAstab * gradAstab) / (sqrAstab * Astab);
201  }
202 
203  //- stabilise diagonal terms
204  if( mag(gradGradF.xx()) < VSMALL ) gradGradF.xx() = VSMALL;
205  if( mag(gradGradF.yy()) < VSMALL ) gradGradF.yy() = VSMALL;
206 }
207 
209 {
210  point& pOpt = pts_[trias_[0][0]];
211 
212  pOpt = 0.5 * (pMax_ + pMin_);
213  point currCentre = pOpt;
214  scalar dx = (pMax_.x() - pMin_.x()) / 2.0;
215  scalar dy = (pMax_.y() - pMin_.y()) / 2.0;
216 
217  label iter(0);
218 
219  //- find the value of the functional in the centre of the bnd box
220  scalar K = evaluateStabilisationFactor();
221  scalar funcBefore, funcAfter(evaluateFunc(K));
222 
223  do
224  {
225  funcBefore = funcAfter;
226 
227  funcAfter = VGREAT;
228  point minCentre(vector::zero);
229 
230  for(label i=0;i<4;++i)
231  {
232  pOpt.x() = currCentre.x() + 0.5 * dirVecs[i].x() * dx;
233  pOpt.y() = currCentre.y() + 0.5 * dirVecs[i].y() * dy;
234 
236  const scalar func = evaluateFunc(K);
237 
238  if( func < funcAfter )
239  {
240  minCentre = pOpt;
241  funcAfter = func;
242  }
243  }
244 
245  //- set the centre with the minimum value
246  //- as the centre for future search
247  currCentre = minCentre;
248  pOpt = minCentre;
249 
250  //- halve the search range
251  dx *= 0.5;
252  dy *= 0.5;
253 
254  //- calculate the tolerence
255  const scalar t = mag(funcAfter - funcBefore) / funcAfter;
256 
257  # ifdef DEBUGSmooth
258  Info << "Point position " << pOpt << endl;
259  Info << "Func before " << funcBefore << endl;
260  Info << "Func after " << funcAfter << endl;
261  Info << "Normalised difference " << t << endl;
262  # endif
263 
264  if( t < tol )
265  break;
266  } while( ++iter < 100 );
267 
268  return funcAfter;
269 }
270 
272 {
273  point& pOpt = pts_[trias_[0][0]];
274 
275  //- find the bounding box
276  const scalar avgEdge = Foam::mag(pMax_ - pMin_);
277 
278  //- find the minimum value on the 5 x 5 raster
279  scalar K = evaluateStabilisationFactor();
280  scalar funcBefore, funcAfter(evaluateFunc(K));
281 
282  //- start with steepest descent optimisation
283  vector gradF;
284  tensor gradGradF;
285  vector disp;
286  disp.z() = 0.0;
287 
288  direction nIterations(0);
289  do
290  {
291  funcBefore = funcAfter;
292 
293  evaluateGradients(K, gradF, gradGradF);
294 
295  //- store data into a matrix
296  matrix2D mat;
297  mat[0][0] = gradGradF.xx();
298  mat[0][1] = gradGradF.xy();
299  mat[1][0] = gradGradF.yx();
300  mat[1][1] = gradGradF.yy();
301  FixedList<scalar, 2> source;
302  source[0] = gradF.x();
303  source[1] = gradF.y();
304 
305  //- calculate the determinant
306  const scalar det = mat.determinant();
307 
308  if( mag(det) < VSMALL )
309  {
310  disp = vector::zero;
311  }
312  else
313  {
314  disp.x() = mat.solveFirst(source);
315  disp.y() = mat.solveSecond(source);
316 
317  if( mag(disp) > 0.2 * avgEdge )
318  {
319  vector dir = disp / mag(disp);
320 
321  disp = dir * 0.2 * avgEdge;
322  }
323  }
324 
325  # ifdef DEBUGSmooth
326  Info << "Second gradient " << gradGradF << endl;
327  Info << "Gradient " << gradF << endl;
328  Info << "Displacement " << disp << endl;
329  Info << "K = " << K << endl;
330  # endif
331 
332  pOpt -= disp;
333 
335  funcAfter = evaluateFunc(K);
336 
337  if( mag(funcAfter - funcBefore) / funcBefore < tol )
338  break;
339 
340  #ifdef DEBUGSmooth
341  Info << "New coordinates " << pOpt << endl;
342  # endif
343 
344  } while( ++nIterations < 100 );
345 
346  return funcAfter;
347 }
348 
349 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
350 
352 (
353  DynList<point>& pts,
354  const DynList<triFace>& trias
355 )
356 :
357  pts_(pts),
358  trias_(trias),
359  pMin_(),
360  pMax_()
361 {
362  pMin_ = pts_[trias_[0][1]];
363  pMax_ = pMin_;
364 
365  forAll(trias_, triI)
366  {
367  const triFace& tf = trias_[triI];
368 
369  for(label i=1;i<3;++i)
370  {
371  pMin_ = Foam::min(pMin_, pts_[tf[i]]);
372  pMax_ = Foam::max(pMax_, pts_[tf[i]]);
373  }
374  }
375 }
376 
378 {}
379 
380 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
381 
383 {
384  const scalar scale = mag(pMax_ - pMin_);
385  forAll(pts_, i)
386  pts_[i] /= scale;
387  pMin_ /= scale;
388  pMax_ /= scale;
389 
390  point& pOpt = pts_[trias_[0][0]];
391 
392  const scalar funcDivide = optimiseDivideAndConquer(tol);
393  const point newPoint = pOpt;
394 
395  const scalar funcSteepest = optimiseSteepestDescent(tol);
396 
397  if( funcSteepest > funcDivide )
398  pOpt = newPoint;
399 
400  forAll(pts_, i)
401  pts_[i] *= scale;
402  pMin_ *= scale;
403  pMax_ *= scale;
404 
405  return pOpt;
406 }
407 
408 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
409 
410 } // End namespace Foam
411 
412 // ************************************************************************* //
Foam::surfaceOptimizer::pts_
DynList< point > & pts_
reference to the simplex points
Definition: surfaceOptimizer.H:58
Foam::matrix2D::determinant
scalar determinant()
return matrix determinant
Definition: matrix2DI.H:70
Foam::Tensor
Templated 3D tensor derived from VectorSpace adding construction from 9 components,...
Definition: complexI.H:224
Foam::Vector< scalar >::zero
static const Vector zero
Definition: Vector.H:80
Foam::surfaceOptimizer::optimizePoint
point optimizePoint(const scalar tol=0.1)
optimizes position of a central point in the simplex
Definition: surfaceOptimizer.C:382
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::matrix2D::solveSecond
scalar solveSecond(const FixedList< scalar, 2 > &source)
return the second component of the solution vector
Definition: matrix2DI.H:117
Foam::surfaceOptimizer::evaluateFunc
scalar evaluateFunc(const scalar &K) const
evaluate the functional
Definition: surfaceOptimizer.C:97
demandDrivenData.H
Template functions to aid in the implementation of demand driven data.
Foam::matrix2D::solveFirst
scalar solveFirst(const FixedList< scalar, 2 > &source)
return the first component of the solution vector
Definition: matrix2DI.H:104
Foam::Tensor::yx
const Cmpt & yx() const
Definition: TensorI.H:181
Foam::endl
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:251
Foam::mag
dimensioned< scalar > mag(const dimensioned< Type > &)
K
CGAL::Exact_predicates_exact_constructions_kernel K
Definition: CGALTriangulation3DKernel.H:56
tf
const tensorField & tf
Definition: getPatchFieldTensor.H:36
Foam::label
intWM_LABEL_SIZE_t label
A label is an int32_t or int64_t as specified by the pre-processor macro WM_LABEL_SIZE.
Definition: label.H:59
Foam::matrix2D
Definition: matrix2D.H:48
Foam::Tensor::yy
const Cmpt & yy() const
Definition: TensorI.H:188
Foam::Info
messageStream Info
Foam::surfaceOptimizer::dirVecs
static const vector dirVecs[4]
direction vectors for divide and conquer algorithm
Definition: surfaceOptimizer.H:54
Foam::func
void func(FieldField< Field, Type > &f, const FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
Foam::pow
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Definition: dimensionedScalar.C:73
Foam::Vector::x
const Cmpt & x() const
Definition: VectorI.H:65
Foam::Tensor::xy
const Cmpt & xy() const
Definition: TensorI.H:167
Foam::Tensor::zero
static const Tensor zero
Definition: Tensor.H:80
Foam
Namespace for OpenFOAM.
Definition: combustionModel.C:30
Foam::Vector::z
const Cmpt & z() const
Definition: VectorI.H:77
Foam::vector
Vector< scalar > vector
A scalar version of the templated Vector.
Definition: vector.H:49
Foam::DynList
Definition: DynList.H:53
Foam::Tensor::xx
const Cmpt & xx() const
Definition: TensorI.H:160
Foam::max
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
surfaceOptimizer.H
Foam::surfaceOptimizer::~surfaceOptimizer
~surfaceOptimizer()
Definition: surfaceOptimizer.C:377
Foam::surfaceOptimizer::pMin_
point pMin_
min position of the bnd box
Definition: surfaceOptimizer.H:64
Foam::surfaceOptimizer::evaluateStabilisationFactor
scalar evaluateStabilisationFactor() const
evaluate stabilisation factor
Definition: surfaceOptimizer.C:51
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:49
Foam::surfaceOptimizer::trias_
const DynList< triFace > & trias_
reference to the triangles forming a simplex
Definition: surfaceOptimizer.H:61
Foam::triFace
A triangular face using a FixedList of labels corresponding to mesh vertices.
Definition: triFace.H:68
Foam::Vector< scalar >
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:142
Foam::FixedList
A 1D vector of objects of type <T> with a fixed size <Size>.
Definition: FixedList.H:53
Foam::surfaceOptimizer::optimiseSteepestDescent
scalar optimiseSteepestDescent(const scalar tol)
optimise point position via the steepest descent method
Definition: surfaceOptimizer.C:271
matrix2D.H
Foam::direction
unsigned char direction
Definition: direction.H:43
Foam::Vector::y
const Cmpt & y() const
Definition: VectorI.H:71
Foam::surfaceOptimizer::pMax_
point pMax_
max position of the bnd box
Definition: surfaceOptimizer.H:67
Foam::det
dimensionedScalar det(const dimensionedSphericalTensor &dt)
Definition: dimensionedSphericalTensor.C:60
Foam::surfaceOptimizer::surfaceOptimizer
surfaceOptimizer(const surfaceOptimizer &)
Disallow default bitwise copy construct.
Foam::min
dimensioned< Type > min(const dimensioned< Type > &, const dimensioned< Type > &)
Foam::twoSymm
dimensionedSymmTensor twoSymm(const dimensionedSymmTensor &dt)
Definition: dimensionedSymmTensor.C:93
Foam::magSqr
dimensioned< scalar > magSqr(const dimensioned< Type > &)
Foam::surfaceOptimizer::evaluateGradients
void evaluateGradients(const scalar &, vector &, tensor &) const
evaluate gradients needed for optimisation
Definition: surfaceOptimizer.C:135
Foam::surfaceOptimizer::optimiseDivideAndConquer
scalar optimiseDivideAndConquer(const scalar tol)
optimise point position using the divide and conquer technique
Definition: surfaceOptimizer.C:208