volumeOptimizerEvaluateGradients.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 "volumeOptimizer.H"
30 #include "tetrahedron.H"
31 
32 //#define DEBUGSmooth
33 
34 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
35 
36 namespace Foam
37 {
38 
39 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
40 
42 {
43  const scalar K = evaluateStabilisationFactor();
44 
45  scalar func(0.0);
46 
47  forAll(tets_, tetI)
48  {
49  const partTet& pt = tets_[tetI];
51  (
52  points_[pt.a()],
53  points_[pt.b()],
54  points_[pt.c()],
55  points_[pt.d()]
56  );
57 
58  const scalar LSqrTri
59  (
60  magSqr(tet.d() - tet.a()) +
61  magSqr(tet.d() - tet.b()) +
62  magSqr(tet.d() - tet.c())
63  );
64 
65  const scalar Vtri = tet.mag();
66  const scalar stab = sqrt(sqr(Vtri) + K);
67  const scalar Vstab = 0.5 * (Vtri + stab);
68 
69  func += LSqrTri / pow(Vstab, 2./3.);
70  }
71 
72  return func;
73 }
74 
76 {
77  scalar K = 0.0;
78 
79  scalar Vmin(VGREAT), LSqMax(0.0);
80 
81  forAll(tets_, tetI)
82  {
83  const partTet& pt = tets_[tetI];
85  (
86  points_[pt.a()],
87  points_[pt.b()],
88  points_[pt.c()],
89  points_[pt.d()]
90  );
91 
92  const scalar Vtri = tet.mag();
93 
94  Vmin = Foam::min(Vmin, Vtri);
95 
96  const scalar LSqrTri
97  (
98  magSqr(tet.d() - tet.a()) +
99  magSqr(tet.d() - tet.b()) +
100  magSqr(tet.d() - tet.c())
101  );
102 
103  LSqMax = Foam::max(LSqMax, LSqrTri);
104  }
105 
106  if( Vmin < SMALL * LSqMax )
107  K = SMALL * LSqMax;
108 
109  return K;
110 }
111 
113 (
114  vector& gradF,
115  tensor& gradGradF
116 ) const
117 {
118  gradF = vector::zero;
119  gradGradF = tensor::zero;
120 
121  const scalar K = evaluateStabilisationFactor();
122 
123  tensor gradGradLsq(tensor::zero);
124  gradGradLsq.xx() = 6.0;
125  gradGradLsq.yy() = 6.0;
126  gradGradLsq.zz() = 6.0;
127 
128  const point& p = points_[pointI_];
129 
130  const scalar C = 2./3. * pow(0.5, 2./3.);
131  const scalar C1 = C / 3.;
132 
133  forAll(tets_, tetI)
134  {
135  const partTet& pt = tets_[tetI];
136  const tetrahedron<point, point> tet
137  (
138  points_[pt.a()],
139  points_[pt.b()],
140  points_[pt.c()],
141  points_[pt.d()]
142  );
143 
144  //- calculate the gradient of the volume
145  const vector gradV
146  (
147  (1.0/6.0) *
148  (
149  (tet.b() - tet.a()) ^
150  (tet.c() - tet.a())
151  )
152  );
153 
154  //- calculate the Frobenius norm
155  const scalar LSqrTri
156  (
157  magSqr(tet.d() - tet.a()) +
158  magSqr(tet.d() - tet.b()) +
159  magSqr(tet.d() - tet.c())
160  );
161 
162  //- calculate the volume of the tetrahedron
163  const scalar Vtri = tet.mag();
164 
165  //- calculate the stabilisation factor for the volume
166  const scalar stab = sqrt(sqr(Vtri) + K);
167 
168  //- evaluate the stabilised volume
169  const scalar Vs = 0.5 * (Vtri + stab);
170 
171  if( Vs < VSMALL )
172  {
173  Info << "Tet " << tet << endl;
174  Info << "gradV " << gradV << endl;
175  Info << "Vtri " << Vtri << endl;
177  Info << "Vstab " << Vs << endl;
178 
180  (
181  "void nodeDisplacementVolumeOptimizer()"
182  ) << "I cannot continue " << exit(FatalError);
183  }
184 
185  //- calculate the gradient of the stabilisation volume
186  const vector gradStab = Vtri * gradV / stab;
187 
188  //- calculate the gradient of the Frobenius norm
189  const vector gradLsq = 2. * (3. * p - tet.a() - tet.b() - tet.c());
190 
191  //- calculate the gradient of the stabilised volume
192  const vector gradVs = 0.5 * (gradV + gradStab);
193 
194  //- calculate the gradient of the functional
195  const scalar Vs13 = pow(2. * Vs, 1./3.);
196  const scalar Vstab = pow(Vs, 2./3.);
197  const scalar sqrVstab = sqr(Vstab);
198  const vector gradVstab = C * (2. * gradVs) / Vs13;
199 
200  gradF += gradLsq / Vstab - LSqrTri * gradVstab / sqrVstab;
201 
202  //- calculate the second gradient of the stabilisation volume
203  const tensor gradGradStab =
204  (gradV * gradV) / stab -
205  sqr(Vtri) * (gradV * gradV) / pow(stab, 3);
206 
207  //- calculate the second gradient of the stabilised volume
208 
209  const tensor gradGradVstab =
210  C * (gradGradStab / Vs13) -
211  C1 * 4. * (gradVs * gradVs) / pow(Vs13, 4);
212 
213  //- calculate the second gradient
214  gradGradF +=
215  gradGradLsq / Vstab -
216  twoSymm(gradLsq * (gradVstab / sqrVstab)) -
217  LSqrTri * gradGradVstab / sqrVstab +
218  2.0 * LSqrTri * (gradVstab * gradVstab) / (sqrVstab * Vstab);
219  }
220 }
221 
223 {
224  point& pOpt = points_[pointI_];
225 
226  pOpt = 0.5 * (bb_.max() + bb_.min());
227  point currCentre = pOpt;
228  scalar dx = (bb_.max().x() - bb_.min().x()) / 2.0;
229  scalar dy = (bb_.max().y() - bb_.min().y()) / 2.0;
230  scalar dz = (bb_.max().z() - bb_.min().z()) / 2.0;
231 
232  label iter(0);
233 
234  //- find the value of the functional in the centre of the bnd box
235  scalar funcBefore, funcAfter(evaluateFunc());
236 
237  do
238  {
239  funcBefore = funcAfter;
240 
241  funcAfter = VGREAT;
242  point minCentre(vector::zero);
243 
244  for(label i=0;i<8;++i)
245  {
246  pOpt.x() = currCentre.x() + 0.5 * dirVecs[i].x() * dx;
247  pOpt.y() = currCentre.y() + 0.5 * dirVecs[i].y() * dy;
248  pOpt.z() = currCentre.z() + 0.5 * dirVecs[i].z() * dz;
249 
250  const scalar func = evaluateFunc();
251 
252  if( func < funcAfter )
253  {
254  minCentre = pOpt;
255  funcAfter = func;
256  }
257  }
258 
259  //- set the centre with the minimum value
260  //- as the centre for future search
261  currCentre = minCentre;
262  pOpt = minCentre;
263 
264  //- halve the search range
265  dx *= 0.5;
266  dy *= 0.5;
267  dz *= 0.5;
268 
269  //- calculate the tolerence
270  const scalar t = mag(funcAfter - funcBefore) / funcAfter;
271 
272  # ifdef DEBUGSmooth
273  Info << "Point position " << pOpt << endl;
274  Info << "Func before " << funcBefore << endl;
275  Info << "Func after " << funcAfter << endl;
276  Info << "Normalised difference " << t << endl;
277  # endif
278 
279  if( t < tol )
280  break;
281  } while( ++iter < 100 );
282 
283  return funcAfter;
284 }
285 
287 {
288  label iter(0);
289 
290  point& p = points_[pointI_];
291 
292  # ifdef DEBUGSmooth
293  Info << nl << "Smoothing point " << pointI_
294  << " with coordinates " << p << endl;
295  scalar Vmina(VGREAT);
296  forAll(tets_, tetI)
297  Vmina = Foam::min(Vmina, tets_[tetI].mag(points_));
298  Info << "Vmin before " << Vmina << endl;
299  # endif
300 
301  vector gradF;
302  vector disp(vector::zero);
303  tensor gradGradF;
304  point pOrig;
305 
306  scalar funcBefore, funcAfter(evaluateFunc());
307 
308  bool finished;
309  do
310  {
311  finished = false;
312  pOrig = p;
313  funcBefore = funcAfter;
314 
315  evaluateGradientsExact(gradF, gradGradF);
316 
317  const scalar determinant = Foam::det(gradGradF);
318  if( determinant > SMALL )
319  {
320  disp = (inv(gradGradF, determinant) & gradF);
321 
322  p -= disp;
323 
324  funcAfter = evaluateFunc();
325 
326  # ifdef DEBUGSmooth
327  Info << nl << "gradF " << gradF << endl;
328  Info << "gradGradF " << gradGradF << endl;
329  Info << "det(gradGradF) " << determinant << endl;
330  Info << "disp " << disp << endl;
331  Info << "Func before " << funcBefore << endl;
332  Info << "Func after " << funcAfter << endl;
333  # endif
334 
335  scalar relax(0.8);
336  label nLoops(0);
337 
338  while( funcAfter > funcBefore )
339  {
340  p = pOrig - relax * disp;
341  relax *= 0.5;
342  funcAfter = evaluateFunc();
343 
344  if( funcAfter < funcBefore )
345  continue;
346 
347  if( ++nLoops == 5 )
348  {
349  //- it seems that this direction is wrong, stop the loop
350  p = pOrig;
351  disp = vector::zero;
352  finished = true;
353  funcAfter = funcBefore;
354  }
355  }
356 
357  if( mag(funcBefore - funcAfter) / funcBefore < tol )
358  finished = true;
359  }
360  else
361  {
362  //- move in random direction
363  //- this is usually needed to move the point off the zero volume
364  disp = vector::zero;
365  forAll(tets_, tetI)
366  {
367  const partTet& tet = tets_[tetI];
368  const scalar Vtri = tet.mag(points_);
369 
370  if( Vtri < SMALL )
371  {
373  (
374  points_[tet.a()],
375  points_[tet.b()],
376  points_[tet.c()]
377  );
378 
379  vector n = tri.normal();
380  const scalar d = mag(n);
381 
382  if( d > VSMALL )
383  disp += 0.01 * (n / d);
384  }
385  }
386 
387  p += disp;
388  funcAfter = evaluateFunc();
389  }
390  } while( (++iter < 100) && !finished );
391 
392  # ifdef DEBUGSmooth
393  scalar Vmin(VGREAT);
394  forAll(tets_, tetI)
395  Vmin = Foam::min(Vmin, tets_[tetI].mag(points_));
396 
397  Info << nl << "New coordinates for point "
398  << pointI_ << " are " << p << endl;
399  Info << "Num iterations " << iter << " gradient " << gradF << endl;
400  Info << "Vmin " << Vmin << endl;
401  # endif
402 
403  return funcAfter;
404 }
405 
406 // * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * //
407 
408 } // End namespace Foam
409 
410 // ************************************************************************* //
Foam::volumeOptimizer::evaluateGradientsExact
void evaluateGradientsExact(vector &, tensor &) const
evaluate gradients of the functional
Definition: volumeOptimizerEvaluateGradients.C:113
Foam::Tensor
Templated 3D tensor derived from VectorSpace adding construction from 9 components,...
Definition: complexI.H:224
relax
p relax()
Foam::Vector< scalar >::zero
static const Vector zero
Definition: Vector.H:80
p
p
Definition: pEqn.H:62
Foam::volumeOptimizer::optimiseSteepestDescent
scalar optimiseSteepestDescent(const scalar tol)
optimise using the steepest descent
Definition: volumeOptimizerEvaluateGradients.C:286
Foam::boundBox::max
const point & max() const
Maximum describing the bounding box.
Definition: boundBoxI.H:60
Foam::partTet::d
label d() const
Definition: partTetI.H:78
forAll
#define forAll(list, i)
Loop across all elements in list.
Definition: UList.H:406
Foam::volumeOptimizer::evaluateStabilisationFactor
scalar evaluateStabilisationFactor() const
find appropriate value of K
Definition: volumeOptimizerEvaluateGradients.C:75
Foam::partTet::b
label b() const
Definition: partTetI.H:68
Foam::tetrahedron::d
const Point & d() const
Definition: tetrahedronI.H:94
demandDrivenData.H
Template functions to aid in the implementation of demand driven data.
Foam::partTet
Definition: partTet.H:53
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
Foam::triangle
A triangle primitive used to calculate face normals and swept volumes.
Definition: triangle.H:59
n
label n
Definition: TABSMDCalcMethod2.H:31
Foam::volumeOptimizer::evaluateFunc
scalar evaluateFunc() const
evaluate functional
Definition: volumeOptimizerEvaluateGradients.C:41
Foam::tetrahedron::c
const Point & c() const
Definition: tetrahedronI.H:87
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::Tensor::yy
const Cmpt & yy() const
Definition: TensorI.H:188
Foam::triangle::normal
vector normal() const
Return vector normal.
Definition: triangleI.H:116
Foam::inv
dimensionedSphericalTensor inv(const dimensionedSphericalTensor &dt)
Definition: dimensionedSphericalTensor.C:71
Foam::nl
static const char nl
Definition: Ostream.H:260
Foam::Info
messageStream Info
volumeOptimizer.H
Foam::Tensor::zz
const Cmpt & zz() const
Definition: TensorI.H:216
Foam::simplexSmoother::points_
DynList< point, 128 > & points_
mesh points
Definition: simplexSmoother.H:62
Foam::func
void func(FieldField< Field, Type > &f, const FieldField< Field, Type > &f1, const FieldField< Field, Type > &f2)
Foam::boundBox::min
const point & min() const
Minimum describing the bounding box.
Definition: boundBoxI.H:54
Foam::pow
dimensionedScalar pow(const dimensionedScalar &ds, const dimensionedScalar &expt)
Definition: dimensionedScalar.C:73
Foam::simplexSmoother::pointI_
const label pointI_
label of the point
Definition: simplexSmoother.H:68
Foam::simplexSmoother::tets_
const DynList< partTet, 128 > & tets_
list tets around the given vertex
Definition: simplexSmoother.H:65
Foam::Vector::x
const Cmpt & x() const
Definition: VectorI.H:65
Foam::partTet::c
label c() const
Definition: partTetI.H:73
Foam::FatalError
error FatalError
Foam::volumeOptimizer::dirVecs
static const vector dirVecs[8]
direction vectors for divide and conquer algorithm
Definition: volumeOptimizer.H:59
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::exit
errorManipArg< error, int > exit(error &err, const int errNo=1)
Definition: errorManip.H:124
Foam::tetrahedron::a
const Point & a() const
Return vertices.
Definition: tetrahedronI.H:73
Foam::Tensor::xx
const Cmpt & xx() const
Definition: TensorI.H:160
Foam::max
dimensioned< Type > max(const dimensioned< Type > &, const dimensioned< Type > &)
Foam::partTet::mag
scalar mag(const PointField &) const
Return volume.
Definition: partTetI.H:154
Foam::simplexSmoother::bb_
boundBox bb_
bound box
Definition: simplexSmoother.H:71
Foam::sqr
dimensionedSymmTensor sqr(const dimensionedVector &dv)
Definition: dimensionedSymmTensor.C:49
Foam::IOstream::defaultPrecision
static unsigned int defaultPrecision()
Return the default precision.
Definition: IOstream.H:461
Foam::Vector< scalar >
Foam::sqrt
dimensionedScalar sqrt(const dimensionedScalar &ds)
Definition: dimensionedScalar.C:142
Foam::volumeOptimizer::optimiseDivideAndConquer
scalar optimiseDivideAndConquer(const scalar tol)
optimize position using a divide and conquer algorithm
Definition: volumeOptimizerEvaluateGradients.C:222
Foam::Vector::y
const Cmpt & y() const
Definition: VectorI.H:71
FatalErrorIn
#define FatalErrorIn(functionName)
Report an error message using Foam::FatalError.
Definition: error.H:313
Foam::det
dimensionedScalar det(const dimensionedSphericalTensor &dt)
Definition: dimensionedSphericalTensor.C:60
Foam::tetrahedron::b
const Point & b() const
Definition: tetrahedronI.H:80
Foam::C
Graphite solid properties.
Definition: C.H:57
Foam::partTet::a
label a() const
Return vertices.
Definition: partTetI.H:63
Foam::tetrahedron::mag
scalar mag() const
Return volume.
Definition: tetrahedronI.H:171
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 > &)
tetrahedron.H
Foam::tetrahedron
A tetrahedron primitive.
Definition: tetrahedron.H:62