Skip to content

Commit b2cf8d4

Browse files
committed
Enables using objFuncStd as convergence criterion.
1 parent ff09fd9 commit b2cf8d4

File tree

4 files changed

+84
-46
lines changed

4 files changed

+84
-46
lines changed

src/adjoint/DASolver/DASolver.C

+65-30
Original file line numberDiff line numberDiff line change
@@ -64,21 +64,8 @@ DASolver::DASolver(
6464
primalMinResTol_ = daOptionPtr_->getOption<scalar>("primalMinResTol");
6565
primalMinIters_ = daOptionPtr_->getOption<label>("primalMinIters");
6666

67-
// check if the objective function std is used in determining the primal convergence
68-
primalObjStdActive_ = daOptionPtr_->getSubDictOption<label>("primalObjStdTol", "active");
69-
if (primalObjStdActive_)
70-
{
71-
// if it is active, read in the tolerance and set a large value for the initial std
72-
primalObjStdTol_ = daOptionPtr_->getSubDictOption<scalar>("primalObjStdTol", "tol");
73-
primalObjStd_ = 1e10;
74-
}
75-
else
76-
{
77-
// if it is not active, set primalObjStdTol_ > primalObjStd_, such that it will
78-
// always pass the condition in DASolver::loop (ignore primalObjStd)
79-
primalObjStdTol_ = 1e-5;
80-
primalObjStd_ = 0.0;
81-
}
67+
// initialize the objStd variables.
68+
this->initObjStd();
8269

8370
Info << "DAOpton initialized " << endl;
8471
}
@@ -187,26 +174,67 @@ label DASolver::loop(Time& runTime)
187174
}
188175
}
189176

177+
void DASolver::initObjStd()
178+
{
179+
/*
180+
Description:
181+
Initialize the objStd variables.
182+
*/
183+
184+
// check if the objective function std is used in determining the primal convergence
185+
primalObjStdActive_ = daOptionPtr_->getSubDictOption<label>("primalObjStdTol", "active");
186+
if (primalObjStdActive_)
187+
{
188+
// if it is active, read in the tolerance and set a large value for the initial std
189+
primalObjStdTol_ = daOptionPtr_->getSubDictOption<scalar>("primalObjStdTol", "tol");
190+
primalObjStd_ = 999.0;
191+
192+
label steps = daOptionPtr_->getSubDictOption<label>("primalObjStdTol", "steps");
193+
primalObjSeries_.setSize(steps, 0.0);
194+
195+
word objFuncNameWanted = daOptionPtr_->getSubDictOption<word>("primalObjStdTol", "objFuncName");
196+
197+
label objFuncNameFound = 0;
198+
const dictionary& objFuncDict = daOptionPtr_->getAllOptions().subDict("objFunc");
199+
forAll(objFuncDict.toc(), idxI)
200+
{
201+
word objFuncName = objFuncDict.toc()[idxI];
202+
if (objFuncName == objFuncNameWanted)
203+
{
204+
objFuncNameFound = 1;
205+
}
206+
}
207+
if (objFuncNameFound == 0)
208+
{
209+
FatalErrorIn("initObjStd") << "objStd->objFuncName not found! "
210+
<< abort(FatalError);
211+
}
212+
}
213+
else
214+
{
215+
// if it is not active, set primalObjStdTol_ > primalObjStd_, such that it will
216+
// always pass the condition in DASolver::loop (ignore primalObjStd)
217+
primalObjStdTol_ = 1e-5;
218+
primalObjStd_ = 0.0;
219+
}
220+
}
221+
190222
void DASolver::calcObjStd(Time& runTime)
191223
{
192224
/*
193225
Description:
194226
calculate the objective function's std, this will be used to stop the primal simulation and also
195-
evaluate whether the primal converges
227+
evaluate whether the primal converges. We will start calculating the objStd when primalObjSeries_
228+
is filled at least once, i.e., runTime.timeIndex() >= steps
196229
*/
197230

198-
if (!primalObjStdActive_)
231+
if (!primalObjStdActive_ || runTime.timeIndex() < 1)
199232
{
200233
return;
201234
}
202235

203236
label steps = daOptionPtr_->getSubDictOption<label>("primalObjStdTol", "steps");
204237

205-
if (runTime.timeIndex() == 1)
206-
{
207-
primalObjSeries_.clear();
208-
}
209-
210238
word objFuncNameWanted = daOptionPtr_->getSubDictOption<word>("primalObjStdTol", "objFuncName");
211239

212240
scalar objFunPartSum = 0.0;
@@ -219,22 +247,21 @@ void DASolver::calcObjStd(Time& runTime)
219247
objFunPartSum += daObjFunc.getObjFuncValue();
220248
}
221249
}
222-
primalObjSeries_.append(objFunPartSum);
250+
label seriesI = (runTime.timeIndex() - 1) % steps;
251+
primalObjSeries_[seriesI] = objFunPartSum;
223252

224-
label seriesSize = primalObjSeries_.size();
225-
226-
if (seriesSize >= steps)
253+
if (runTime.timeIndex() >= steps)
227254
{
228255
scalar mean = 0;
229-
for (label i = seriesSize - 1; i >= seriesSize - steps; i--)
256+
forAll(primalObjSeries_, idxI)
230257
{
231-
mean += primalObjSeries_[i];
258+
mean += primalObjSeries_[idxI];
232259
}
233260
mean /= steps;
234261
primalObjStd_ = 0.0;
235-
for (label i = seriesSize - 1; i >= seriesSize - steps; i--)
262+
forAll(primalObjSeries_, idxI)
236263
{
237-
primalObjStd_ += (primalObjSeries_[i] - mean) * (primalObjSeries_[i] - mean);
264+
primalObjStd_ += (primalObjSeries_[idxI] - mean) * (primalObjSeries_[idxI] - mean);
238265
}
239266
primalObjStd_ = sqrt(primalObjStd_ / steps);
240267
}
@@ -328,6 +355,14 @@ void DASolver::printAllObjFuncs()
328355
<< "-" << objFuncPart
329356
<< "-" << daObjFunc.getObjFuncType()
330357
<< ": " << objFuncVal;
358+
if (primalObjStdActive_)
359+
{
360+
word objFuncNameWanted = daOptionPtr_->getSubDictOption<word>("primalObjStdTol", "objFuncName");
361+
if (objFuncNameWanted == objFuncName)
362+
{
363+
Info << " Std " << primalObjStd_;
364+
}
365+
}
331366
if (timeOperator == "average" || timeOperator == "sum")
332367
{
333368
Info << " Unsteady " << timeOperator << " " << unsteadyObjFuncs_[uKey];

src/adjoint/DASolver/DASolver.H

+3
Original file line numberDiff line numberDiff line change
@@ -1315,6 +1315,9 @@ public:
13151315
return latestTime;
13161316
}
13171317

1318+
/// initialize the objStd vars
1319+
void initObjStd();
1320+
13181321
/// calculate the objective function's std
13191322
void calcObjStd(Time& runTime);
13201323
};
Original file line numberDiff line numberDiff line change
@@ -1,26 +1,26 @@
11
Dictionary Key: NU
2-
@value 322.2353921318797 1e-08 1e-10
2+
@value 322.5176001120205 1e-08 1e-10
33
Dictionary Key: PL
4-
@value 2.310286713734058 1e-08 1e-10
4+
@value 2.31161488891712 1e-08 1e-10
55
Dictionary Key: fail
66
@value 0 1e-08 1e-10
77
Dictionary Key: NU
88
Dictionary Key: shapey
9-
@value -140.1709592966036 0.0001 1e-06
10-
@value 60.78016818466478 0.0001 1e-06
11-
@value -68.73500447578726 0.0001 1e-06
9+
@value 152.1541024728527 0.0001 1e-06
10+
@value 138.432194899197 0.0001 1e-06
11+
@value 29.84397412606532 0.0001 1e-06
1212
Dictionary Key: shapez
13-
@value -4.362814513888678 0.0001 1e-06
14-
@value 6.619514670089002 0.0001 1e-06
15-
@value 8.125727969252937 0.0001 1e-06
13+
@value -20.5162746556844 0.0001 1e-06
14+
@value -168.3587625937871 0.0001 1e-06
15+
@value -86.23596162719087 0.0001 1e-06
1616
Dictionary Key: PL
1717
Dictionary Key: shapey
18-
@value 3.545442933817327 0.0001 1e-06
19-
@value 0.6419043697747193 0.0001 1e-06
20-
@value -0.8440552457793308 0.0001 1e-06
18+
@value 2.677963956813089 0.0001 1e-06
19+
@value 7.13696478920283 0.0001 1e-06
20+
@value 4.288518523483048 0.0001 1e-06
2121
Dictionary Key: shapez
22-
@value -0.0006037858402438943 0.0001 1e-06
23-
@value 0.2348244172148388 0.0001 1e-06
24-
@value 0.1332789140632325 0.0001 1e-06
22+
@value -1.12856634205818 0.0001 1e-06
23+
@value -13.40132223266928 0.0001 1e-06
24+
@value -7.605506838786253 0.0001 1e-06
2525
Dictionary Key: fail
2626
@value 0 0.0001 1e-06

tests/runTests_DARhoSimpleFoamUBend.py

+2-2
Original file line numberDiff line numberDiff line change
@@ -40,9 +40,9 @@
4040
"useAD": {"mode": "reverse"},
4141
"useMeanStates": {"active": True, "start": 0.5},
4242
"designSurfaces": ["ubend"],
43-
"primalMinResTol": 1e-5,
43+
"primalMinResTol": 1e0,
4444
"primalMinResTolDiff": 1e5,
45-
"primalObjStdTol": {"active": True, "objFuncName": "PL", "steps": 500, "tol": 1e-4, "tolDiff": 1e2},
45+
"primalObjStdTol": {"active": True, "objFuncName": "NU", "steps": 50, "tol": 0.27, "tolDiff": 1e2},
4646
"primalBC": {
4747
"U0": {"variable": "U", "patches": ["inlet"], "value": [U0, 0.0, 0.0]},
4848
"p0": {"variable": "p", "patches": ["outlet"], "value": [p0]},

0 commit comments

Comments
 (0)