BFGS.C
Go to the documentation of this file.
1/*---------------------------------------------------------------------------*\
2 ========= |
3 \\ / F ield | OpenFOAM: The Open Source CFD Toolbox
4 \\ / O peration |
5 \\ / A nd | www.openfoam.com
6 \\/ M anipulation |
7-------------------------------------------------------------------------------
8 Copyright (C) 2007-2019 PCOpt/NTUA
9 Copyright (C) 2013-2019 FOSS GP
10 Copyright (C) 2019-2020 OpenCFD Ltd.
11-------------------------------------------------------------------------------
12License
13 This file is part of OpenFOAM.
14
15 OpenFOAM is free software: you can redistribute it and/or modify it
16 under the terms of the GNU General Public License as published by
17 the Free Software Foundation, either version 3 of the License, or
18 (at your option) any later version.
19
20 OpenFOAM is distributed in the hope that it will be useful, but WITHOUT
21 ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
22 FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
23 for more details.
24
25 You should have received a copy of the GNU General Public License
26 along with OpenFOAM. If not, see <http://www.gnu.org/licenses/>.
27
28\*---------------------------------------------------------------------------*/
29
30#include "BFGS.H"
32
33// * * * * * * * * * * * * * * Static Data Members * * * * * * * * * * * * * //
34
35namespace Foam
36{
39 (
41 BFGS,
43 );
44}
45
46
47// * * * * * * * * * * * * Protected Member Functions * * * * * * * * * * * //
48
50{
51 // Set active design variables, if necessary
53 {
55 }
56
57 // Set previous HessianInv to be a diagonal matrix
59
60 // Allocate correct size and content to HessianInv matrices
61 // has a max. capability of approximately 34000 variables.
62 HessianInvOld_ = temp;
63 HessianInv_ = temp;
64}
65
66
68{
69 // Vectors needed to construct the inverse HessianInv matrix
70 scalarField y(activeDesignVars_.size(), Zero);
71 scalarField s(activeDesignVars_.size(), Zero);
72 y.map(objectiveDerivatives_ - derivativesOld_, activeDesignVars_);
73 s.map(correctionOld_, activeDesignVars_);
74
75 scalar ys = globalSum(s*y);
76
77 if (counter_ == 1 && scaleFirstHessian_)
78 {
79 scalar scaleFactor = ys/globalSum(y*y);
80 Info<< "Scaling Hessian with factor " << scaleFactor << endl;
81 forAll(activeDesignVars_, varI)
82 {
83 HessianInvOld_[varI][varI] *= scaleFactor;
84 }
85 }
86
87 // Check curvature condition
88 if (ys < curvatureThreshold_)
89 {
91 << " y*s is below threshold! y*s=" << ys << endl;
92 }
93
95 << "Hessian curvature index " << ys << endl;
96
97 // Construct the inverse HessianInv
98 HessianInv_ =
99 HessianInvOld_
100 + (ys + globalSum(leftMult(y, HessianInvOld_)*y))/sqr(ys)*outerProd(s, s)
101 - (scalar(1)/ys)*
102 (
103 outerProd(rightMult(HessianInvOld_, y), s)
104 + outerProd(s, leftMult(y, HessianInvOld_))
105 );
106}
107
108
110{
111 // In the first few iterations, use steepest descent but update the Hessian
112 // matrix
113 if (counter_ < nSteepestDescent_)
114 {
115 Info<< "Using steepest descent to update design variables" << endl;
116 correction_ = -eta_*objectiveDerivatives_;
117 }
118 // else use BFGS formula to update the design variables
119 else
120 {
121 // Compute correction for active design variables
122 scalarField activeDerivs(activeDesignVars_.size(), Zero);
123 activeDerivs.map(objectiveDerivatives_, activeDesignVars_);
124 scalarField activeCorrection
125 (
126 -etaHessian_*rightMult(HessianInv_, activeDerivs)
127 );
128
129 // Transfer correction to the global list
130 correction_ = Zero;
131 forAll(activeDesignVars_, varI)
132 {
133 correction_[activeDesignVars_[varI]] = activeCorrection[varI];
134 }
135 }
136
137 // Store fields for the next iteration
138 derivativesOld_ = objectiveDerivatives_;
139 correctionOld_ = correction_;
140 HessianInvOld_ = HessianInv_;
141}
142
143
145{
146 if (optMethodIODict_.headerOk())
147 {
148 optMethodIODict_.readEntry("HessianInvOld", HessianInvOld_);
149 optMethodIODict_.readEntry("derivativesOld", derivativesOld_);
150 optMethodIODict_.readEntry("correctionOld", correctionOld_);
151 optMethodIODict_.readEntry("counter", counter_);
152 optMethodIODict_.readEntry("eta", eta_);
153
154 const label n(HessianInvOld_.n());
155 HessianInv_ = SquareMatrix<scalar>(n, Zero);
156 correction_ = scalarField(correctionOld_.size(), Zero);
157
158 if (activeDesignVars_.empty())
159 {
160 activeDesignVars_ = identity(n);
161 }
162 }
163}
164
165
166// * * * * * * * * * * * * * * * * Constructors * * * * * * * * * * * * * * //
167
169(
170 const fvMesh& mesh,
171 const dictionary& dict
172)
173:
175 etaHessian_
176 (
177 coeffsDict().getOrDefault<scalar>("etaHessian", 1)
178 ),
179 nSteepestDescent_
180 (
181 coeffsDict().getOrDefault<label>("nSteepestDescent", 1)
182 ),
183 activeDesignVars_(0),
184 scaleFirstHessian_
185 (
186 coeffsDict().getOrDefault<bool>("scaleFirstHessian", false)
187 ),
188 curvatureThreshold_
189 (
190 coeffsDict().getOrDefault<scalar>("curvatureThreshold", 1e-10)
191 ),
192 // Construct null matrix since we dont know the dimension yet
193 HessianInv_(),
194 HessianInvOld_(),
195 derivativesOld_(0),
196 correctionOld_(0),
197 counter_(Zero)
198{
199 if
200 (
201 !coeffsDict().readIfPresent("activeDesignVariables", activeDesignVars_)
202 )
203 {
204 // If not, all available design variables will be used. Number is not
205 // know at the moment
206 Info<< "\t Did not find explicit definition of active design variables."
207 << " Treating all available ones as active" << endl;
208 }
209
210 // Read old hessian, correction and derivatives, if present
211 readFromDict();
212}
213
214
215// * * * * * * * * * * * * * * * Member Functions * * * * * * * * * * * * * //
216
218{
219 if (counter_ == 0)
220 {
221 allocateMatrices();
222 }
223 else
224 {
225 updateHessian();
226 }
227
228 update();
229 ++counter_;
230}
231
232
234{
236 correctionOld_ = oldCorrection;
237}
238
239
241{
242 optMethodIODict_.add<SquareMatrix<scalar>>
243 (
244 "HessianInvOld",
245 HessianInvOld_,
246 true
247 );
248 optMethodIODict_.add<scalarField>("derivativesOld", derivativesOld_, true);
249 optMethodIODict_.add<scalarField>("correctionOld", correctionOld_, true);
250 optMethodIODict_.add<label>("counter", counter_, true);
251
253}
254
255
256// ************************************************************************* //
scalar y
label n
Macros for easy insertion into run-time selection tables.
#define addToRunTimeSelectionTable(baseType, thisType, argNames)
Add to construction table with typeName as the key.
The quasi-Newton BFGS formula.
Definition: BFGS.H:57
void computeCorrection()
Compute design variables correction.
Definition: BFGS.C:217
SquareMatrix< scalar > HessianInvOld_
The previous Hessian inverse.
Definition: BFGS.H:93
void readFromDict()
Read old info from dict.
Definition: BFGS.C:144
labelList activeDesignVars_
Map to active design variables.
Definition: BFGS.H:80
void allocateMatrices()
Allocate matrices in the first optimisation cycle.
Definition: BFGS.C:49
virtual void write()
Write old info to dict.
Definition: BFGS.C:240
SquareMatrix< scalar > HessianInv_
Definition: BFGS.H:90
virtual void updateOldCorrection(const scalarField &oldCorrection)
Definition: BFGS.C:233
void update()
Update design variables.
Definition: BFGS.C:109
void updateHessian()
Update approximation of the inverse Hessian.
Definition: BFGS.C:67
void map(const UList< Type > &mapF, const labelUList &mapAddressing)
1 to 1 map from the given field
Definition: Field.C:240
A templated (N x N) square matrix of objects of <Type>, containing N*N elements, derived from Matrix.
Definition: SquareMatrix.H:66
bool empty() const noexcept
True if the UList is empty (ie, size() is zero)
Definition: UListI.H:427
void size(const label n)
Older name for setAddressableSize.
Definition: UList.H:114
A list of keyword definitions, which are a keyword followed by a number of values (eg,...
Definition: dictionary.H:126
Mesh data needed to do the Finite Volume discretisation.
Definition: fvMesh.H:91
Abstract base class for optimisation methods.
Definition: updateMethod.H:55
scalarField objectiveDerivatives_
Derivatives of the objective functions.
Definition: updateMethod.H:68
dictionary coeffsDict()
Return optional dictionary with parameters specific to each method.
Definition: updateMethod.C:254
virtual void write()
Write useful quantities to files.
Definition: updateMethod.C:398
virtual void updateOldCorrection(const scalarField &oldCorrection)
Definition: updateMethod.C:390
#define defineTypeNameAndDebug(Type, DebugSwitch)
Define the typeName and debug information.
Definition: className.H:121
bool
Definition: EEqn.H:20
mesh update()
dynamicFvMesh & mesh
gmvFile<< "tracers "<< particles.size()<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().x()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().y()<< " ";}gmvFile<< nl;for(const passiveParticle &p :particles){ gmvFile<< p.position().z()<< " ";}gmvFile<< nl;forAll(lagrangianScalarNames, i){ word name=lagrangianScalarNames[i];IOField< scalar > s(IOobject(name, runTime.timeName(), cloud::prefix, mesh, IOobject::MUST_READ, IOobject::NO_WRITE))
#define DebugInfo
Report an information message using Foam::Info.
#define WarningInFunction
Report a warning using Foam::Warning.
Namespace for OpenFOAM.
labelList identity(const label len, label start=0)
Return an identity map of the given length with (map[i] == i)
Definition: labelList.C:38
dimensionedSymmTensor sqr(const dimensionedVector &dv)
messageStream Info
Information stream (stdout output on master, null elsewhere)
static const Identity< scalar > I
Definition: Identity.H:94
Field< scalar > scalarField
Specialisation of Field<T> for scalar.
Ostream & endl(Ostream &os)
Add newline and flush stream.
Definition: Ostream.H:372
static constexpr const zero Zero
Global zero (0)
Definition: zero.H:131
dictionary dict
volScalarField & e
Definition: createFields.H:11
#define forAll(list, i)
Loop across all elements in list.
Definition: stdFoam.H:333
propsDict readIfPresent("fields", acceptFields)