22 #include "cantera/base/mdp_allo.h"
38 # define SQUARE(x) ( (x) * (x) )
42 #define DSIGN(x) (( (x) == (0.0) ) ? (0.0) : ( ((x) > 0.0) ? 1.0 : -1.0 ))
56 static void print_funcEval(FILE* fp, doublereal xval, doublereal fval,
int its)
59 fprintf(fp,
"...............................................................\n");
60 fprintf(fp,
".................. RootFind Function Evaluation ...............\n");
61 fprintf(fp,
".................. iteration = %5d ........................\n", its);
62 fprintf(fp,
".................. value = %12.5g ......................\n", xval);
63 fprintf(fp,
".................. funct = %12.5g ......................\n", fval);
64 fprintf(fp,
"...............................................................\n");
73 m_funcTargetValue(0.0),
80 writeLogAllowed_(false),
82 specifiedDeltaXnorm_(0),
84 specifiedDeltaXMax_(0),
85 FuncIsGenerallyIncreasing_(false),
86 FuncIsGenerallyDecreasing_(false),
87 deltaXConverged_(0.0),
88 x_maxTried_(-1.0E300),
97 m_residFunc(r.m_residFunc),
98 m_funcTargetValue(0.0),
105 writeLogAllowed_(false),
107 specifiedDeltaXnorm_(0),
109 specifiedDeltaXMax_(0),
110 FuncIsGenerallyIncreasing_(false),
111 FuncIsGenerallyDecreasing_(false),
112 deltaXConverged_(0.0),
113 x_maxTried_(-1.0E300),
115 x_minTried_(1.0E300),
128 if (
this == &right) {
164 doublereal deltaX = 1.0E-14 * fabs(x1);
166 if (delmin > deltaX) {
199 doublereal sgnn = 1.0;
203 doublereal deltaX = x2 - x1;
204 doublereal x = fabs(x2) + fabs(x1);
206 if (fabs(deltaX) < deltaXm) {
207 deltaX = sgnn * deltaXm;
225 doublereal x = fabs(x2) + fabs(x1);
227 doublereal deltaXSmall = factor * deltaX;
228 deltaXSmall =
std::max(deltaXSmall , x * 1.0E-15);
229 if (fabs(x2 - x1) < deltaXSmall) {
245 int RootFind::solve(doublereal xmin, doublereal xmax,
int itmax, doublereal& funcTargetValue, doublereal* xbest)
257 static int callNum = 0;
258 const char* stre =
"RootFind ERROR: ";
259 const char* strw =
"RootFind WARNING: ";
267 int doFinalFuncCall = 0;
268 doublereal x1, x2, xnew, f1, f2, fnew, slope;
269 doublereal deltaX2 = 0.0, deltaXnew = 0.0;
275 int foundStraddle = 0;
276 doublereal xPosF = 0.0;
277 doublereal fPosF = 1.0E300;
278 doublereal xNegF = 0.0;
279 doublereal fNegF = -1.0E300;
283 doublereal fnoise = 0.0;
287 rfT.reasoning =
"First Point: ";
292 sprintf(fileName,
"RootFind_%d.log", callNum);
293 fp = fopen(fileName,
"w");
294 fprintf(fp,
" Iter TP_its xval Func_val | Reasoning\n");
295 fprintf(fp,
"-----------------------------------------------------"
296 "-------------------------------\n");
300 writelog(
"WARNING: RootFind: printlvl >= 3, but debug mode not turned on\n");
304 writelogf(
"%sxmin and xmax are bad: %g %g\n", stre, xmin, xmax);
305 funcTargetValue =
func(*xbest);
334 writelogf(
"%s DeltaXnorm_, %g, is too small compared to tols, increasing to %g\n",
344 if (x1 < xmin || x1 > xmax) {
345 x1 = (xmin + xmax) / 2.0;
346 rfT.reasoning +=
" x1 set middle between xmin and xmax because entrance is outside bounds.";
348 rfT.reasoning +=
" x1 set to entrance x.";
359 fprintf(fp,
"%-5d %-5d %-15.5E %-15.5E\n", -2, 0, x1, f1);
367 }
else if (f1 > fnoise) {
371 }
else if (f1 < -fnoise) {
380 rfT.foundPos = foundPosF;
381 rfT.foundNeg = foundNegF;
382 rfT.deltaXConverged =
m_rtolx * (fabs(x1) + 0.001);
383 rfT.deltaFConverged = fabs(f1) *
m_rtolf;
384 rfT.delX = xmax - xmin;
393 rfT.reasoning =
"Second Point: ";
396 rfT.reasoning +=
"Set by DeltaXnorm_";
399 rfT.reasoning +=
"Set slightly higher.";
403 rfT.reasoning +=
" - But adjusted to be within bounds";
415 fprintf(fp,
"%-5d %-5d %-15.5E %-15.5E", -1, 0, x2, f2);
437 }
else if (f2 < - fnoise) {
443 }
else if (f2 == 0.0) {
451 rfT.foundPos = foundPosF;
452 rfT.foundNeg = foundNegF;
458 foundStraddle = foundPosF && foundNegF;
467 bool useNextStrat =
false;
468 bool slopePointingToHigher =
true;
478 if (fabs(x2 - x1) < 1.0E-14) {
479 printf(
" RootFind: we are here x2 = %g x1 = %g\n", x2, x1);
484 slope = (f2 - f1) / delXtmp;
489 if (fabs(slope) <= 1.0E-100) {
491 writelogf(
"%s functions evals produced the same result, %g, at %g and %g\n",
495 slopePointingToHigher =
true;
497 rfT.reasoning +=
"Slope is close to zero. ";
499 useNextStrat =
false;
500 xnew = x2 - f2 / slope;
502 slopePointingToHigher =
true;
504 slopePointingToHigher =
false;
506 rfT.reasoning +=
"Slope is good. ";
510 fprintf(fp,
" | xlin = %-11.5E", xnew);
513 deltaXnew = xnew - x2;
517 if (!foundStraddle) {
520 rfT.reasoning +=
"Too large change in xnew from slope. ";
522 if (fabs(deltaXnew) < fabs(deltaX2)) {
523 deltaXnew = 1.2 * deltaXnew;
524 xnew = x2 + deltaXnew;
531 rfT.reasoning +=
"Using DeltaXnorm, " +
fp2str(
DeltaXnorm_) +
" and FuncIsGenerallyIncreasing hints. ";
534 if (slopePointingToHigher) {
540 if (!slopePointingToHigher) {
546 if (slopePointingToHigher) {
554 if (!slopePointingToHigher) {
560 if (! slopePointingToHigher) {
566 if (slopePointingToHigher) {
580 double delta = fabs(x2 - x1);
581 if (fabs(xnew - x1) < .01 * delta) {
582 xnew = x1 + 0.01 * (x2 - x1);
583 }
else if (fabs(xnew - x2) < .01 * delta) {
584 xnew = x1 + 0.01 * (x2 - x1);
585 }
else if ((xnew > x1 && xnew < x2) || (xnew < x1 && xnew > x2)) {
586 if (fabs(xnew - x1) < fabs(x2 - xnew)) {
587 xnew = x1 + 20./19. * (xnew - x1);
589 xnew = x2 + 20./19. * (xnew - x2);
599 if ((xnew > x1 && xnew < x2) || (xnew < x1 && xnew > x2)) {
605 xDelMin = fabs(x2 - x1) / 10.;
606 if (fabs(xnew - x1) < xDelMin) {
607 xnew = x1 + DSIGN(xnew-x1) * xDelMin;
610 fprintf(fp,
" | x10%% = %-11.5E", xnew);
614 if (fabs(xnew - x2) < 0.1 * xDelMin) {
615 xnew = x2 + DSIGN(xnew-x2) * 0.1 * xDelMin;
618 fprintf(fp,
" | x10%% = %-11.5E", xnew);
628 doublereal xDelMax = 1.5 * fabs(x2 - x1);
634 if (fabs(xDelMax) < fabs(xnew - x2)) {
635 xnew = x2 + DSIGN(xnew-x2) * xDelMax;
638 fprintf(fp,
" | xlimitsize = %-11.5E", xnew);
647 xDelMin = 0.1 * fabs(x2 - x1);
648 if (fabs(xnew - x2) < xDelMin) {
649 xnew = x2 + DSIGN(xnew - x2) * xDelMin;
652 fprintf(fp,
" | x10%% = %-11.5E", xnew);
656 if (fabs(xnew - x1) < xDelMin) {
657 xnew = x1 + DSIGN(xnew - x1) * xDelMin;
660 fprintf(fp,
" | x10%% = %-11.5E", xnew);
675 xnew = (xNegF + x2)/2;
678 xnew = (xNegF + x2)/2;
682 xnew = (xPosF + x2)/2;
685 xnew = (xPosF + x2)/2;
691 xnew = (xNegF + x2)/2;
694 xnew = (xNegF + x2)/2;
698 xnew = (xPosF + x2)/2;
701 xnew = (xPosF + x2)/2;
708 fprintf(fp,
" | xstraddle = %-11.5E", xnew);
717 deltaXnew = xnew - x2;
719 if (!foundStraddle) {
725 rfT.reasoning +=
"Enforcing minimum stepsize from " +
fp2str(xnew - x2) +
726 " to " +
fp2str(deltaXnew);
727 xnew = x2 + deltaXnew;
737 xnew = x2 + (xmax - x2) / 2.0;
738 rfT.reasoning += (
"xval reduced to " +
fp2str(xnew) +
" because predicted xnew was above max value of " +
fp2str(xmax));
740 if (x2 == xmax || x1 == xmax) {
746 rfT.reasoning +=
"Giving up because we're at xmax and xnew point higher: " +
fp2str(xnew);
749 rfT.reasoning +=
"xval reduced from " +
fp2str(xnew) +
" to the max value, " +
fp2str(xmax);
755 fprintf(fp,
" | xlimitmax = %-11.5E", xnew);
761 if (bottomBump < 3) {
762 rfT.reasoning += (
"xnew increased from " +
fp2str(xnew) +
" to " +
fp2str(x2 - (x2 - xmin) / 2.0) +
763 " because above min value of " +
fp2str(xmin));
764 xnew = x2 - (x2 - xmin) / 2.0;
766 if (x2 == xmin || x1 == xmin) {
772 rfT.reasoning =
"Giving up because we're already at xmin and xnew points lower: " +
fp2str(xnew);
775 rfT.reasoning +=
"xval increased from " +
fp2str(xnew) +
" to the min value, " +
fp2str(xmin);
781 fprintf(fp,
" | xlimitmin = %-11.5E", xnew);
793 fprintf(fp,
"%-5d %-5d %-15.5E %-15.5E", its, 0, xnew, fnew);
827 if (! foundStraddle) {
841 }
else if (fnew < - fnoise) {
869 bool foundBetterPos =
false;
870 bool foundBetterNeg =
false;
874 foundBetterPos =
false;
879 if (foundBetterPos) {
891 foundBetterNeg =
false;
896 if (foundBetterNeg) {
910 foundBetterNeg =
false;
915 if (foundBetterNeg) {
927 foundBetterPos =
true;
932 if (foundBetterNeg) {
944 AssertThrow((f1* f2 <= 0.0),
"F1 and F2 aren't bounding");
951 rfT.deltaFConverged = fnorm *
m_rtolf;
953 rfT.delX =
std::max(fabs(deltaX2), fabs(deltaXnew));
955 rfT.delX =
std::max(fabs(deltaX2), fabs(deltaXnew));
957 rfT.delX =
std::max(rfT.delX, x2 - xmin);
959 rfT.delX =
std::max(rfT.delX, xmax - x2);
966 if ((fabs(fnew / fnorm) < m_rtolf) && foundStraddle) {
969 rfT.reasoning +=
"NormalConvergence";
973 else if (fabs(slope) > 1.0E-100) {
974 double xdels = fabs(fnew / slope);
977 rfT.reasoning +=
"NormalConvergence-SlopelimitsDelX";
989 doublereal denom = fabs(x1 - x2);
990 if (denom < 1.0E-200) {
993 rfT.reasoning +=
"ConvergenceFZero but X1X2Identical";
997 rfT.reasoning +=
" ConvergenceF and XSame";
1007 if (foundStraddle) {
1008 doublereal denom = fabs(x1 - x2);
1009 if (denom < 1.0E-200) {
1012 rfT.reasoning +=
"FNotConverged but X1X2Identical";
1018 if (
theSame(x2, x1, 1.0E-5)) {
1021 rfT.reasoning +=
"FNotConverged but XSame";
1026 }
while (! converged && its < itmax);
1034 AssertThrow((f1* f2 <= 0.0),
"F1 and F2 aren't bounding");
1042 rfT.delX = fabs(x_fpos - x_fneg);
1043 if (doFinalFuncCall || (fabs(f1) < 2.0 * fabs(f2))) {
1045 slope = (f2 - f1) / delXtmp;
1046 xnew = x2 - f2 / slope;
1050 if (fabs(xnew - x_fneg) < fabs(x_fpos - x_fneg)) {
1052 rfT.delX = fabs(xnew - x_fneg);
1055 if (fabs(xnew - x_fpos) < fabs(x_fpos - x_fneg)) {
1057 rfT.delX = fabs(xnew - x_fpos);
1061 if (fabs(fnew) < fabs(f2) && (fabs(fnew) < fabs(f1))) {
1063 if (doFinalFuncCall) {
1064 rfT.reasoning +=
"CONVERGENCE: Another Evaluation Requested";
1065 rfT.delX = fabs(xnew - x2);
1067 rfT.reasoning +=
"CONVERGENCE: Another Evaluation done because f1 < f2";
1068 rfT.delX = fabs(xnew - x1);
1074 }
else if (fabs(f1) < fabs(f2)) {
1080 rfT.reasoning +=
"CONVERGENCE: Another Evaluation not as good as Second Point ";
1087 if (fabs(fnew) < fabs(f1)) {
1088 if (f1 * fnew > 0.0) {
1089 std::swap(f1, fnew);
1090 std::swap(x1, xnew);
1097 rfT.delX = fabs(x_fpos - x_fneg);
1098 rfT.reasoning +=
"CONVERGENCE: NormalEnding -> Second point used";
1105 rfT.reasoning +=
"CONVERGENCE: Another Evaluation not as good as First Point ";
1112 rfT.delX = fabs(x_fpos - x_fneg);
1113 rfT.reasoning +=
"CONVERGENCE: NormalEnding -> Last point used";
1121 rfT.delX = fabs(x2 - x1);
1122 rfT.reasoning +=
"CONVERGENCE: NormalEnding -> Last point used";
1128 writelogf(
"RootFind success: convergence achieved\n");
1132 fprintf(fp,
" | RootFind success in %d its, fnorm = %g\n", its, fnorm);
1137 rfT.reasoning =
"FAILED CONVERGENCE ";
1142 writelogf(
"RootFind ERROR: Soln probably lies higher than xmax, %g: best guess = %g\n", xmax, *xbest);
1144 rfT.reasoning +=
"Soln probably lies higher than xmax, " +
fp2str(xmax) +
": best guess = " +
fp2str(*xbest);
1147 writelogf(
"RootFind ERROR: Soln probably lies lower than xmin, %g: best guess = %g\n", xmin, *xbest);
1149 rfT.reasoning +=
"Soln probably lies lower than xmin, " +
fp2str(xmin) +
": best guess = " +
fp2str(*xbest);
1153 writelogf(
"RootFind ERROR: maximum iterations exceeded without convergence, cause unknown\n");
1155 rfT.reasoning +=
"Maximum iterations exceeded without convergence, cause unknown";
1159 fprintf(fp,
"\nRootFind failure in %d its\n", its);
1314 printf(
"\t----------------------------------------------------------------------------------------------------------------------------------------\n");
1315 printf(
"\t RootFinder Summary table: \n");
1317 printf(
"\t Iter | xval delX deltaXConv | slope | foundP foundN| F - F_targ deltaFConv | Reasoning\n");
1318 printf(
"\t----------------------------------------------------------------------------------------------------------------------------------------\n");
1319 for (
int i = 0; i < (int)
rfHistory_.size(); i++) {
1321 printf(
"\t %3d |%- 17.11E %- 13.7E %- 13.7E |%- 13.5E| %3d %3d | %- 12.5E %- 12.5E | %s \n",
1322 rfT.its, rfT.xval, rfT.delX, rfT.deltaXConverged, rfT.slope, rfT.foundPos, rfT.foundNeg, rfT.fval,
1323 rfT.deltaFConverged, (rfT.reasoning).c_str());
1325 printf(
"\t----------------------------------------------------------------------------------------------------------------------------------------\n");