@@ -64,6 +64,22 @@ DASolver::DASolver(
64
64
primalMinResTol_ = daOptionPtr_ -> getOption < scalar > ("primalMinResTol" );
65
65
primalMinIters_ = daOptionPtr_ -> getOption < label > ("primalMinIters" );
66
66
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
+ }
82
+
67
83
Info << "DAOpton initialized " << endl ;
68
84
}
69
85
@@ -116,7 +132,7 @@ label DASolver::loop(Time& runTime)
116
132
{
117
133
/*
118
134
Description:
119
- The loop method to increment the runtime. The reason we implent this is
135
+ The loop method to increment the runtime. The reason we implement this is
120
136
because the runTime.loop() and simple.loop() give us seg fault...
121
137
*/
122
138
@@ -135,12 +151,23 @@ label DASolver::loop(Time& runTime)
135
151
funcObj .execute ();
136
152
}
137
153
138
- // check exit condition
139
- if (DAUtility ::primalMaxInitRes_ < primalMinResTol_ && runTime .timeIndex () > primalMinIters_ )
154
+ // calculate the objective function standard deviation. It will be used in determining if the primal converges
155
+ this -> calcObjStd (runTime );
156
+
157
+ // check exit condition, we need to satisfy both the residual and objFunc std condition
158
+ if (DAUtility ::primalMaxInitRes_ < primalMinResTol_ && runTime .timeIndex () > primalMinIters_ && primalObjStd_ < primalObjStdTol_ )
140
159
{
141
160
Info << "Time = " << t << endl ;
161
+
142
162
Info << "Minimal residual " << DAUtility ::primalMaxInitRes_ << " satisfied the prescribed tolerance " << primalMinResTol_ << endl
143
163
<< endl ;
164
+
165
+ if (primalObjStdActive_ )
166
+ {
167
+ Info << "ObjFunc standard deviation " << primalObjStd_ << " satisfied the prescribed tolerance " << primalObjStdTol_ << endl
168
+ << endl ;
169
+ }
170
+
144
171
this -> printAllObjFuncs ();
145
172
runTime .writeNow ();
146
173
prevPrimalSolTime_ = t ;
@@ -160,6 +187,59 @@ label DASolver::loop(Time& runTime)
160
187
}
161
188
}
162
189
190
+ void DASolver ::calcObjStd (Time & runTime )
191
+ {
192
+ /*
193
+ Description:
194
+ calculate the objective function's std, this will be used to stop the primal simulation and also
195
+ evaluate whether the primal converges
196
+ */
197
+
198
+ if (!primalObjStdActive_ )
199
+ {
200
+ return ;
201
+ }
202
+
203
+ label steps = daOptionPtr_ -> getSubDictOption < label > ("primalObjStdTol" , "steps" );
204
+
205
+ if (runTime .timeIndex () == 1 )
206
+ {
207
+ primalObjSeries_ .clear ();
208
+ }
209
+
210
+ word objFuncNameWanted = daOptionPtr_ -> getSubDictOption < word > ("primalObjStdTol" , "objFuncName" );
211
+
212
+ scalar objFunPartSum = 0.0 ;
213
+ forAll (daObjFuncPtrList_ , idxI )
214
+ {
215
+ DAObjFunc & daObjFunc = daObjFuncPtrList_ [idxI ];
216
+ word objFuncName = daObjFunc .getObjFuncName ();
217
+ if (objFuncName == objFuncNameWanted )
218
+ {
219
+ objFunPartSum += daObjFunc .getObjFuncValue ();
220
+ }
221
+ }
222
+ primalObjSeries_ .append (objFunPartSum );
223
+
224
+ label seriesSize = primalObjSeries_ .size ();
225
+
226
+ if (seriesSize >= steps )
227
+ {
228
+ scalar mean = 0 ;
229
+ for (label i = seriesSize - 1 ; i >= seriesSize - steps ; i -- )
230
+ {
231
+ mean += primalObjSeries_ [i ];
232
+ }
233
+ mean /= steps ;
234
+ primalObjStd_ = 0.0 ;
235
+ for (label i = seriesSize - 1 ; i >= seriesSize - steps ; i -- )
236
+ {
237
+ primalObjStd_ += (primalObjSeries_ [i ] - mean ) * (primalObjSeries_ [i ] - mean );
238
+ }
239
+ primalObjStd_ = sqrt (primalObjStd_ / steps );
240
+ }
241
+ }
242
+
163
243
void DASolver ::calcUnsteadyObjFuncs ()
164
244
{
165
245
/*
@@ -8481,14 +8561,26 @@ label DASolver::checkResidualTol()
8481
8561
If yes, return 0 else return 1
8482
8562
*/
8483
8563
8484
- scalar tol = daOptionPtr_ -> getOption < scalar > ("primalMinResTol ");
8564
+ // when checking the tolerance, we relax the criteria by tolMax
8565
+
8485
8566
scalar tolMax = daOptionPtr_ -> getOption < scalar > ("primalMinResTolDiff ");
8486
- if (DAUtility ::primalMaxInitRes_ / tol > tolMax )
8567
+ scalar stdTolMax = daOptionPtr_ -> getSubDictOption < scalar > ("primalObjStdTol ", "tolDiff ");
8568
+ if (DAUtility ::primalMaxInitRes_ / primalMinResTol_ > tolMax )
8487
8569
{
8488
8570
Info << "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * " << endl ;
8489
8571
Info << "Primal min residual " << DAUtility ::primalMaxInitRes_ << endl
8490
8572
<< "did not satisfy the prescribed tolerance "
8491
- << tol << endl ;
8573
+ << primalMinResTol_ << endl ;
8574
+ Info << "Primal solution failed !" << endl ;
8575
+ Info << "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * " << endl ;
8576
+ return 1 ;
8577
+ }
8578
+ else if (primalObjStd_ / primalObjStdTol_ > stdTolMax )
8579
+ {
8580
+ Info << "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * " << endl ;
8581
+ Info << "Primal objFunc standard deviation " << primalObjStd_ << endl
8582
+ << "did not satisfy the prescribed tolerance "
8583
+ << primalObjStdTol_ << endl ;
8492
8584
Info << "Primal solution failed !" << endl ;
8493
8585
Info << "* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * " << endl ;
8494
8586
return 1 ;
0 commit comments