17 #undef DEBUG_MODE_ENABLED
18 #define DEBUG_MODE_ENABLED 1
35 static void print_funcEval(FILE* fp, doublereal xval, doublereal fval,
int its)
38 fprintf(fp,
"...............................................................\n");
39 fprintf(fp,
".................. RootFind Function Evaluation ...............\n");
40 fprintf(fp,
".................. iteration = %5d ........................\n", its);
41 fprintf(fp,
".................. value = %12.5g ......................\n", xval);
42 fprintf(fp,
".................. funct = %12.5g ......................\n", fval);
43 fprintf(fp,
"...............................................................\n");
49 m_funcTargetValue(0.0),
56 writeLogAllowed_(false),
58 specifiedDeltaXnorm_(0),
60 specifiedDeltaXMax_(0),
61 FuncIsGenerallyIncreasing_(false),
62 FuncIsGenerallyDecreasing_(false),
63 deltaXConverged_(0.0),
64 x_maxTried_(-1.0E300),
72 m_residFunc(r.m_residFunc),
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),
127 doublereal deltaX = 1.0E-14 * fabs(x1);
129 if (delmin > deltaX) {
146 doublereal sgnn = 1.0;
150 doublereal deltaX = x2 - x1;
151 doublereal x = fabs(x2) + fabs(x1);
153 if (fabs(deltaX) < deltaXm) {
154 deltaX = sgnn * deltaXm;
161 doublereal x = fabs(x2) + fabs(x1);
163 doublereal deltaXSmall = factor * deltaX;
164 deltaXSmall = std::max(deltaXSmall , x * 1.0E-15);
165 if (fabs(x2 - x1) < deltaXSmall) {
171 int RootFind::solve(doublereal xmin, doublereal xmax,
int itmax, doublereal& funcTargetValue, doublereal* xbest)
180 static int callNum = 0;
181 const char* stre =
"RootFind ERROR: ";
182 const char* strw =
"RootFind WARNING: ";
187 int doFinalFuncCall = 0;
188 doublereal x1, x2, xnew, f1, f2, fnew, slope;
189 doublereal deltaX2 = 0.0, deltaXnew = 0.0;
195 int foundStraddle = 0;
196 doublereal xPosF = 0.0;
197 doublereal fPosF = 1.0E300;
198 doublereal xNegF = 0.0;
199 doublereal fNegF = -1.0E300;
203 doublereal fnoise = 0.0;
207 rfT.reasoning =
"First Point: ";
212 sprintf(fileName,
"RootFind_%d.log", callNum);
213 fp = fopen(fileName,
"w");
214 fprintf(fp,
" Iter TP_its xval Func_val | Reasoning\n");
215 fprintf(fp,
"-----------------------------------------------------"
216 "-------------------------------\n");
218 writelog(
"WARNING: RootFind: printlvl >= 3, but debug mode not turned on\n");
221 writelogf(
"%sxmin and xmax are bad: %g %g\n", stre, xmin, xmax);
222 funcTargetValue =
func(*xbest);
251 writelogf(
"%s DeltaXnorm_, %g, is too small compared to tols, increasing to %g\n",
261 if (x1 < xmin || x1 > xmax) {
262 x1 = (xmin + xmax) / 2.0;
263 rfT.reasoning +=
" x1 set middle between xmin and xmax because entrance is outside bounds.";
265 rfT.reasoning +=
" x1 set to entrance x.";
275 fprintf(fp,
"%-5d %-5d %-15.5E %-15.5E\n", -2, 0, x1, f1);
281 }
else if (f1 > fnoise) {
285 }
else if (f1 < -fnoise) {
294 rfT.foundPos = foundPosF;
295 rfT.foundNeg = foundNegF;
296 rfT.deltaXConverged =
m_rtolx * (fabs(x1) + 0.001);
297 rfT.deltaFConverged = fabs(f1) *
m_rtolf;
298 rfT.delX = xmax - xmin;
307 rfT.reasoning =
"Second Point: ";
310 rfT.reasoning +=
"Set by DeltaXnorm_";
313 rfT.reasoning +=
"Set slightly higher.";
317 rfT.reasoning +=
" - But adjusted to be within bounds";
328 fprintf(fp,
"%-5d %-5d %-15.5E %-15.5E", -1, 0, x2, f2);
349 }
else if (f2 < - fnoise) {
355 }
else if (f2 == 0.0) {
363 rfT.foundPos = foundPosF;
364 rfT.foundNeg = foundNegF;
370 foundStraddle = foundPosF && foundNegF;
379 bool useNextStrat =
false;
380 bool slopePointingToHigher =
true;
389 if (DEBUG_MODE_ENABLED && fabs(x2 - x1) < 1.0E-14) {
390 printf(
" RootFind: we are here x2 = %g x1 = %g\n", x2, x1);
393 slope = (f2 - f1) / delXtmp;
398 if (fabs(slope) <= 1.0E-100) {
400 writelogf(
"%s functions evals produced the same result, %g, at %g and %g\n",
404 slopePointingToHigher =
true;
406 rfT.reasoning +=
"Slope is close to zero. ";
408 useNextStrat =
false;
409 xnew = x2 - f2 / slope;
411 slopePointingToHigher =
true;
413 slopePointingToHigher =
false;
415 rfT.reasoning +=
"Slope is good. ";
418 fprintf(fp,
" | xlin = %-11.5E", xnew);
420 deltaXnew = xnew - x2;
424 if (!foundStraddle) {
427 rfT.reasoning +=
"Too large change in xnew from slope. ";
429 if (fabs(deltaXnew) < fabs(deltaX2)) {
430 deltaXnew = 1.2 * deltaXnew;
431 xnew = x2 + deltaXnew;
438 rfT.reasoning +=
"Using DeltaXnorm, " +
fp2str(
DeltaXnorm_) +
" and FuncIsGenerallyIncreasing hints. ";
441 if (slopePointingToHigher) {
447 if (!slopePointingToHigher) {
453 if (slopePointingToHigher) {
461 if (!slopePointingToHigher) {
467 if (! slopePointingToHigher) {
473 if (slopePointingToHigher) {
487 double delta = fabs(x2 - x1);
488 if (fabs(xnew - x1) < .01 * delta) {
489 xnew = x1 + 0.01 * (x2 - x1);
490 }
else if (fabs(xnew - x2) < .01 * delta) {
491 xnew = x1 + 0.01 * (x2 - x1);
492 }
else if ((xnew > x1 && xnew < x2) || (xnew < x1 && xnew > x2)) {
493 if (fabs(xnew - x1) < fabs(x2 - xnew)) {
494 xnew = x1 + 20./19. * (xnew - x1);
496 xnew = x2 + 20./19. * (xnew - x2);
506 if ((xnew > x1 && xnew < x2) || (xnew < x1 && xnew > x2)) {
512 xDelMin = fabs(x2 - x1) / 10.;
513 if (fabs(xnew - x1) < xDelMin) {
514 xnew = x1 +
sign(xnew-x1) * xDelMin;
516 fprintf(fp,
" | x10%% = %-11.5E", xnew);
519 if (fabs(xnew - x2) < 0.1 * xDelMin) {
520 xnew = x2 +
sign(xnew-x2) * 0.1 * xDelMin;
522 fprintf(fp,
" | x10%% = %-11.5E", xnew);
531 doublereal xDelMax = 1.5 * fabs(x2 - x1);
537 if (fabs(xDelMax) < fabs(xnew - x2)) {
538 xnew = x2 +
sign(xnew-x2) * xDelMax;
540 fprintf(fp,
" | xlimitsize = %-11.5E", xnew);
548 xDelMin = 0.1 * fabs(x2 - x1);
549 if (fabs(xnew - x2) < xDelMin) {
550 xnew = x2 +
sign(xnew - x2) * xDelMin;
552 fprintf(fp,
" | x10%% = %-11.5E", xnew);
555 if (fabs(xnew - x1) < xDelMin) {
556 xnew = x1 +
sign(xnew - x1) * xDelMin;
558 fprintf(fp,
" | x10%% = %-11.5E", xnew);
570 xnew = (xNegF + x2)/2;
573 xnew = (xNegF + x2)/2;
577 xnew = (xPosF + x2)/2;
580 xnew = (xPosF + x2)/2;
586 xnew = (xNegF + x2)/2;
589 xnew = (xNegF + x2)/2;
593 xnew = (xPosF + x2)/2;
596 xnew = (xPosF + x2)/2;
602 fprintf(fp,
" | xstraddle = %-11.5E", xnew);
610 deltaXnew = xnew - x2;
612 if (!foundStraddle) {
618 rfT.reasoning +=
"Enforcing minimum stepsize from " +
fp2str(xnew - x2) +
619 " to " +
fp2str(deltaXnew);
620 xnew = x2 + deltaXnew;
630 xnew = x2 + (xmax - x2) / 2.0;
631 rfT.reasoning += (
"xval reduced to " +
fp2str(xnew) +
" because predicted xnew was above max value of " +
fp2str(xmax));
633 if (x2 == xmax || x1 == xmax) {
639 rfT.reasoning +=
"Giving up because we're at xmax and xnew point higher: " +
fp2str(xnew);
642 rfT.reasoning +=
"xval reduced from " +
fp2str(xnew) +
" to the max value, " +
fp2str(xmax);
647 fprintf(fp,
" | xlimitmax = %-11.5E", xnew);
652 if (bottomBump < 3) {
653 rfT.reasoning += (
"xnew increased from " +
fp2str(xnew) +
" to " +
fp2str(x2 - (x2 - xmin) / 2.0) +
654 " because above min value of " +
fp2str(xmin));
655 xnew = x2 - (x2 - xmin) / 2.0;
657 if (x2 == xmin || x1 == xmin) {
663 rfT.reasoning =
"Giving up because we're already at xmin and xnew points lower: " +
fp2str(xnew);
666 rfT.reasoning +=
"xval increased from " +
fp2str(xnew) +
" to the min value, " +
fp2str(xmin);
671 fprintf(fp,
" | xlimitmin = %-11.5E", xnew);
681 fprintf(fp,
"%-5d %-5d %-15.5E %-15.5E", its, 0, xnew, fnew);
714 if (! foundStraddle) {
728 }
else if (fnew < - fnoise) {
756 bool foundBetterPos =
false;
757 bool foundBetterNeg =
false;
761 foundBetterPos =
false;
766 if (foundBetterPos) {
778 foundBetterNeg =
false;
783 if (foundBetterNeg) {
797 foundBetterNeg =
false;
802 if (foundBetterNeg) {
814 foundBetterPos =
true;
819 if (foundBetterNeg) {
831 AssertThrow((f1* f2 <= 0.0),
"F1 and F2 aren't bounding");
838 rfT.deltaFConverged = fnorm *
m_rtolf;
840 rfT.delX = std::max(fabs(deltaX2), fabs(deltaXnew));
842 rfT.delX = std::max(fabs(deltaX2), fabs(deltaXnew));
844 rfT.delX = std::max(rfT.delX, x2 - xmin);
846 rfT.delX = std::max(rfT.delX, xmax - x2);
853 if ((fabs(fnew / fnorm) < m_rtolf) && foundStraddle) {
856 rfT.reasoning +=
"NormalConvergence";
860 else if (fabs(slope) > 1.0E-100) {
861 double xdels = fabs(fnew / slope);
864 rfT.reasoning +=
"NormalConvergence-SlopelimitsDelX";
876 doublereal denom = fabs(x1 - x2);
877 if (denom < 1.0E-200) {
880 rfT.reasoning +=
"ConvergenceFZero but X1X2Identical";
884 rfT.reasoning +=
" ConvergenceF and XSame";
895 doublereal denom = fabs(x1 - x2);
896 if (denom < 1.0E-200) {
899 rfT.reasoning +=
"FNotConverged but X1X2Identical";
908 rfT.reasoning +=
"FNotConverged but XSame";
913 }
while (! converged && its < itmax);
921 AssertThrow((f1* f2 <= 0.0),
"F1 and F2 aren't bounding");
929 rfT.delX = fabs(x_fpos - x_fneg);
930 if (doFinalFuncCall || (fabs(f1) < 2.0 * fabs(f2))) {
932 slope = (f2 - f1) / delXtmp;
933 xnew = x2 - f2 / slope;
937 if (fabs(xnew - x_fneg) < fabs(x_fpos - x_fneg)) {
939 rfT.delX = fabs(xnew - x_fneg);
942 if (fabs(xnew - x_fpos) < fabs(x_fpos - x_fneg)) {
944 rfT.delX = fabs(xnew - x_fpos);
948 if (fabs(fnew) < fabs(f2) && (fabs(fnew) < fabs(f1))) {
950 if (doFinalFuncCall) {
951 rfT.reasoning +=
"CONVERGENCE: Another Evaluation Requested";
952 rfT.delX = fabs(xnew - x2);
954 rfT.reasoning +=
"CONVERGENCE: Another Evaluation done because f1 < f2";
955 rfT.delX = fabs(xnew - x1);
961 }
else if (fabs(f1) < fabs(f2)) {
967 rfT.reasoning +=
"CONVERGENCE: Another Evaluation not as good as Second Point ";
974 if (fabs(fnew) < fabs(f1)) {
975 if (f1 * fnew > 0.0) {
984 rfT.delX = fabs(x_fpos - x_fneg);
985 rfT.reasoning +=
"CONVERGENCE: NormalEnding -> Second point used";
992 rfT.reasoning +=
"CONVERGENCE: Another Evaluation not as good as First Point ";
999 rfT.delX = fabs(x_fpos - x_fneg);
1000 rfT.reasoning +=
"CONVERGENCE: NormalEnding -> Last point used";
1008 rfT.delX = fabs(x2 - x1);
1009 rfT.reasoning +=
"CONVERGENCE: NormalEnding -> Last point used";
1015 writelogf(
"RootFind success: convergence achieved\n");
1018 fprintf(fp,
" | RootFind success in %d its, fnorm = %g\n", its, fnorm);
1022 rfT.reasoning =
"FAILED CONVERGENCE ";
1027 writelogf(
"RootFind ERROR: Soln probably lies higher than xmax, %g: best guess = %g\n", xmax, *xbest);
1029 rfT.reasoning +=
"Soln probably lies higher than xmax, " +
fp2str(xmax) +
": best guess = " +
fp2str(*xbest);
1032 writelogf(
"RootFind ERROR: Soln probably lies lower than xmin, %g: best guess = %g\n", xmin, *xbest);
1034 rfT.reasoning +=
"Soln probably lies lower than xmin, " +
fp2str(xmin) +
": best guess = " +
fp2str(*xbest);
1038 writelogf(
"RootFind ERROR: maximum iterations exceeded without convergence, cause unknown\n");
1040 rfT.reasoning +=
"Maximum iterations exceeded without convergence, cause unknown";
1043 fprintf(fp,
"\nRootFind failure in %d its\n", its);
1066 if (DEBUG_MODE_ENABLED) {
1070 if (DEBUG_MODE_ENABLED) {
1136 printf(
"\t----------------------------------------------------------------------------------------------------------------------------------------\n");
1137 printf(
"\t RootFinder Summary table: \n");
1139 printf(
"\t Iter | xval delX deltaXConv | slope | foundP foundN| F - F_targ deltaFConv | Reasoning\n");
1140 printf(
"\t----------------------------------------------------------------------------------------------------------------------------------------\n");
1141 for (
int i = 0; i < (int)
rfHistory_.size(); i++) {
1143 printf(
"\t %3d |%- 17.11E %- 13.7E %- 13.7E |%- 13.5E| %3d %3d | %- 12.5E %- 12.5E | %s \n",
1144 rfT.its, rfT.xval, rfT.delX, rfT.deltaXConverged, rfT.slope, rfT.foundPos, rfT.foundNeg, rfT.fval,
1145 rfT.deltaFConverged, (rfT.reasoning).c_str());
1147 printf(
"\t----------------------------------------------------------------------------------------------------------------------------------------\n");
void checkFinite(const double tmp)
Check to see that a number is finite (not NaN, +Inf or -Inf)
void setDeltaX(doublereal deltaXNorm)
Set the minimum value of deltaX.
Various templated functions that carry out common vector operations (see Templated Utility Functions)...
#define ROOTFIND_FAILEDCONVERGENCE
This means that the root solver failed to achieve convergence.
doublereal DeltaXnorm_
Delta X norm. This is the nominal value of deltaX that will be used by the program.
#define ROOTFIND_SUCCESS_XCONVERGENCEONLY
This return value means that the root finder resolved a solution in the x coordinate However...
doublereal fx_minTried_
Internal variable tracking f(x) of smallest x tried.
bool FuncIsGenerallyDecreasing_
Boolean indicating whether the function is decreasing with x.
doublereal x_maxTried_
Internal variable tracking largest x tried.
Header file for implicit nonlinear solver of a one dimensional function (see Numerical Utilities with...
std::vector< struct rfTable > rfHistory_
Vector of iteration histories.
void setFuncIsGenerallyDecreasing(bool value)
Set the function behavior flag.
Structure containing the iteration history.
int specifiedDeltaXnorm_
Boolean indicating whether DeltaXnorm_ has been specified by the user or not.
RootFind & operator=(const RootFind &right)
Assignment operator.
void printTable()
Print the iteration history table.
doublereal delXNonzero(doublereal x1) const
Calculate a deltaX from an input value of x.
doublereal m_atolx
Absolute tolerance for the value of x.
int sign(T x)
Sign of a number. Returns -1 if x < 0, 1 if x > 0 and 0 if x == 0.
doublereal m_rtolx
Relative tolerance for the value of x.
bool writeLogAllowed_
Boolean to turn on the possibility of writing a log file.
doublereal m_rtolf
Relative tolerance for the value of f and x.
doublereal DeltaXMax_
Delta X Max. This is the maximum value of deltaX that will be used by the program.
doublereal x_minTried_
Internal variable tracking smallest x tried.
void setTol(doublereal rtolf, doublereal atolf, doublereal rtolx=0.0, doublereal atolx=0.0)
Set the tolerance parameters for the rootfinder.
void writelogf(const char *fmt,...)
Write a formatted message to the screen.
doublereal deltaXControlled(doublereal x2, doublereal x1) const
Calculate a controlled, nonzero delta between two numbers.
Root finder for 1D problems.
void setFuncIsGenerallyIncreasing(bool value)
Set the function behavior flag.
Virtual base class for DAE residual function evaluators.
static void print_funcEval(FILE *fp, doublereal xval, doublereal fval, int its)
Print out a form for the current function evaluation.
doublereal m_funcTargetValue
Target value for the function. We seek the value of f that is equal to this value.
std::string fp2str(const double x, const std::string &fmt)
Convert a double into a c++ string.
bool FuncIsGenerallyIncreasing_
Boolean indicating whether the function is an increasing with x.
#define AssertThrow(expr, procedure)
Assertion must be true or an error is thrown.
doublereal fx_maxTried_
Internal variable tracking f(x) of largest x tried.
#define ROOTFIND_SOLNHIGHERTHANXMAX
This means that the rootfinder believes the solution is higher than xmax.
ResidEval * m_residFunc
Pointer to the residual function evaluator.
int solve(doublereal xmin, doublereal xmax, int itmax, doublereal &funcTargetValue, doublereal *xbest)
Using a line search method, find the root of a 1D function.
void setDeltaXMax(doublereal deltaX)
Set the maximum value of deltaX.
#define ROOTFIND_SOLNLOWERTHANXMIN
This means that the rootfinder believes the solution is lower than xmin.
#define ROOTFIND_BADINPUT
This means that the input to the root solver was defective.
doublereal m_maxstep
Maximum number of step sizes.
Contains declarations for string manipulation functions within Cantera.
doublereal delXMeaningful(doublereal x1) const
Calculate a deltaX from an input value of x.
doublereal deltaXConverged_
Value of delta X that is needed for convergence.
void writelog(const std::string &msg)
Write a message to the screen.
RootFind(ResidEval *resid)
Constructor for the object.
void setPrintLvl(int printLvl)
Set the print level from the rootfinder.
doublereal m_atolf
Absolute tolerance for the value of f.
int specifiedDeltaXMax_
Boolean indicating whether DeltaXMax_ has been specified by the user or not.
#define ROOTFIND_SUCCESS
This means that the root solver was a success.
bool theSame(doublereal x2, doublereal x1, doublereal factor=1.0) const
Function to decide whether two real numbers are the same or not.
doublereal func(doublereal x)
Return the function value.