28 # define SQUARE(x) ( (x) * (x) )
32 #define DSIGN(x) (( (x) == (0.0) ) ? (0.0) : ( ((x) > 0.0) ? 1.0 : -1.0 ))
43 static void print_funcEval(FILE* fp, doublereal xval, doublereal fval,
int its)
46 fprintf(fp,
"...............................................................\n");
47 fprintf(fp,
".................. RootFind Function Evaluation ...............\n");
48 fprintf(fp,
".................. iteration = %5d ........................\n", its);
49 fprintf(fp,
".................. value = %12.5g ......................\n", xval);
50 fprintf(fp,
".................. funct = %12.5g ......................\n", fval);
51 fprintf(fp,
"...............................................................\n");
58 m_funcTargetValue(0.0),
65 writeLogAllowed_(false),
67 specifiedDeltaXnorm_(0),
69 specifiedDeltaXMax_(0),
70 FuncIsGenerallyIncreasing_(false),
71 FuncIsGenerallyDecreasing_(false),
72 deltaXConverged_(0.0),
73 x_maxTried_(-1.0E300),
81 m_residFunc(r.m_residFunc),
82 m_funcTargetValue(0.0),
89 writeLogAllowed_(false),
91 specifiedDeltaXnorm_(0),
93 specifiedDeltaXMax_(0),
94 FuncIsGenerallyIncreasing_(false),
95 FuncIsGenerallyDecreasing_(false),
96 deltaXConverged_(0.0),
97 x_maxTried_(-1.0E300),
105 RootFind::~RootFind()
111 if (
this == &right) {
140 doublereal deltaX = 1.0E-14 * fabs(x1);
142 if (delmin > deltaX) {
159 doublereal sgnn = 1.0;
163 doublereal deltaX = x2 - x1;
164 doublereal x = fabs(x2) + fabs(x1);
166 if (fabs(deltaX) < deltaXm) {
167 deltaX = sgnn * deltaXm;
174 doublereal x = fabs(x2) + fabs(x1);
176 doublereal deltaXSmall = factor * deltaX;
177 deltaXSmall = std::max(deltaXSmall , x * 1.0E-15);
178 if (fabs(x2 - x1) < deltaXSmall) {
184 int RootFind::solve(doublereal xmin, doublereal xmax,
int itmax, doublereal& funcTargetValue, doublereal* xbest)
193 static int callNum = 0;
194 const char* stre =
"RootFind ERROR: ";
195 const char* strw =
"RootFind WARNING: ";
203 int doFinalFuncCall = 0;
204 doublereal x1, x2, xnew, f1, f2, fnew, slope;
205 doublereal deltaX2 = 0.0, deltaXnew = 0.0;
211 int foundStraddle = 0;
212 doublereal xPosF = 0.0;
213 doublereal fPosF = 1.0E300;
214 doublereal xNegF = 0.0;
215 doublereal fNegF = -1.0E300;
219 doublereal fnoise = 0.0;
223 rfT.reasoning =
"First Point: ";
228 sprintf(fileName,
"RootFind_%d.log", callNum);
229 fp = fopen(fileName,
"w");
230 fprintf(fp,
" Iter TP_its xval Func_val | Reasoning\n");
231 fprintf(fp,
"-----------------------------------------------------"
232 "-------------------------------\n");
236 writelog(
"WARNING: RootFind: printlvl >= 3, but debug mode not turned on\n");
240 writelogf(
"%sxmin and xmax are bad: %g %g\n", stre, xmin, xmax);
241 funcTargetValue =
func(*xbest);
270 writelogf(
"%s DeltaXnorm_, %g, is too small compared to tols, increasing to %g\n",
280 if (x1 < xmin || x1 > xmax) {
281 x1 = (xmin + xmax) / 2.0;
282 rfT.reasoning +=
" x1 set middle between xmin and xmax because entrance is outside bounds.";
284 rfT.reasoning +=
" x1 set to entrance x.";
295 fprintf(fp,
"%-5d %-5d %-15.5E %-15.5E\n", -2, 0, x1, f1);
303 }
else if (f1 > fnoise) {
307 }
else if (f1 < -fnoise) {
316 rfT.foundPos = foundPosF;
317 rfT.foundNeg = foundNegF;
318 rfT.deltaXConverged =
m_rtolx * (fabs(x1) + 0.001);
319 rfT.deltaFConverged = fabs(f1) *
m_rtolf;
320 rfT.delX = xmax - xmin;
329 rfT.reasoning =
"Second Point: ";
332 rfT.reasoning +=
"Set by DeltaXnorm_";
335 rfT.reasoning +=
"Set slightly higher.";
339 rfT.reasoning +=
" - But adjusted to be within bounds";
351 fprintf(fp,
"%-5d %-5d %-15.5E %-15.5E", -1, 0, x2, f2);
373 }
else if (f2 < - fnoise) {
379 }
else if (f2 == 0.0) {
387 rfT.foundPos = foundPosF;
388 rfT.foundNeg = foundNegF;
394 foundStraddle = foundPosF && foundNegF;
403 bool useNextStrat =
false;
404 bool slopePointingToHigher =
true;
414 if (fabs(x2 - x1) < 1.0E-14) {
415 printf(
" RootFind: we are here x2 = %g x1 = %g\n", x2, x1);
420 slope = (f2 - f1) / delXtmp;
425 if (fabs(slope) <= 1.0E-100) {
427 writelogf(
"%s functions evals produced the same result, %g, at %g and %g\n",
431 slopePointingToHigher =
true;
433 rfT.reasoning +=
"Slope is close to zero. ";
435 useNextStrat =
false;
436 xnew = x2 - f2 / slope;
438 slopePointingToHigher =
true;
440 slopePointingToHigher =
false;
442 rfT.reasoning +=
"Slope is good. ";
446 fprintf(fp,
" | xlin = %-11.5E", xnew);
449 deltaXnew = xnew - x2;
453 if (!foundStraddle) {
456 rfT.reasoning +=
"Too large change in xnew from slope. ";
458 if (fabs(deltaXnew) < fabs(deltaX2)) {
459 deltaXnew = 1.2 * deltaXnew;
460 xnew = x2 + deltaXnew;
467 rfT.reasoning +=
"Using DeltaXnorm, " +
fp2str(
DeltaXnorm_) +
" and FuncIsGenerallyIncreasing hints. ";
470 if (slopePointingToHigher) {
476 if (!slopePointingToHigher) {
482 if (slopePointingToHigher) {
490 if (!slopePointingToHigher) {
496 if (! slopePointingToHigher) {
502 if (slopePointingToHigher) {
516 double delta = fabs(x2 - x1);
517 if (fabs(xnew - x1) < .01 * delta) {
518 xnew = x1 + 0.01 * (x2 - x1);
519 }
else if (fabs(xnew - x2) < .01 * delta) {
520 xnew = x1 + 0.01 * (x2 - x1);
521 }
else if ((xnew > x1 && xnew < x2) || (xnew < x1 && xnew > x2)) {
522 if (fabs(xnew - x1) < fabs(x2 - xnew)) {
523 xnew = x1 + 20./19. * (xnew - x1);
525 xnew = x2 + 20./19. * (xnew - x2);
535 if ((xnew > x1 && xnew < x2) || (xnew < x1 && xnew > x2)) {
541 xDelMin = fabs(x2 - x1) / 10.;
542 if (fabs(xnew - x1) < xDelMin) {
543 xnew = x1 + DSIGN(xnew-x1) * xDelMin;
546 fprintf(fp,
" | x10%% = %-11.5E", xnew);
550 if (fabs(xnew - x2) < 0.1 * xDelMin) {
551 xnew = x2 + DSIGN(xnew-x2) * 0.1 * xDelMin;
554 fprintf(fp,
" | x10%% = %-11.5E", xnew);
564 doublereal xDelMax = 1.5 * fabs(x2 - x1);
570 if (fabs(xDelMax) < fabs(xnew - x2)) {
571 xnew = x2 + DSIGN(xnew-x2) * xDelMax;
574 fprintf(fp,
" | xlimitsize = %-11.5E", xnew);
583 xDelMin = 0.1 * fabs(x2 - x1);
584 if (fabs(xnew - x2) < xDelMin) {
585 xnew = x2 + DSIGN(xnew - x2) * xDelMin;
588 fprintf(fp,
" | x10%% = %-11.5E", xnew);
592 if (fabs(xnew - x1) < xDelMin) {
593 xnew = x1 + DSIGN(xnew - x1) * xDelMin;
596 fprintf(fp,
" | x10%% = %-11.5E", xnew);
611 xnew = (xNegF + x2)/2;
614 xnew = (xNegF + x2)/2;
618 xnew = (xPosF + x2)/2;
621 xnew = (xPosF + x2)/2;
627 xnew = (xNegF + x2)/2;
630 xnew = (xNegF + x2)/2;
634 xnew = (xPosF + x2)/2;
637 xnew = (xPosF + x2)/2;
644 fprintf(fp,
" | xstraddle = %-11.5E", xnew);
653 deltaXnew = xnew - x2;
655 if (!foundStraddle) {
661 rfT.reasoning +=
"Enforcing minimum stepsize from " +
fp2str(xnew - x2) +
662 " to " +
fp2str(deltaXnew);
663 xnew = x2 + deltaXnew;
673 xnew = x2 + (xmax - x2) / 2.0;
674 rfT.reasoning += (
"xval reduced to " +
fp2str(xnew) +
" because predicted xnew was above max value of " +
fp2str(xmax));
676 if (x2 == xmax || x1 == xmax) {
682 rfT.reasoning +=
"Giving up because we're at xmax and xnew point higher: " +
fp2str(xnew);
685 rfT.reasoning +=
"xval reduced from " +
fp2str(xnew) +
" to the max value, " +
fp2str(xmax);
691 fprintf(fp,
" | xlimitmax = %-11.5E", xnew);
697 if (bottomBump < 3) {
698 rfT.reasoning += (
"xnew increased from " +
fp2str(xnew) +
" to " +
fp2str(x2 - (x2 - xmin) / 2.0) +
699 " because above min value of " +
fp2str(xmin));
700 xnew = x2 - (x2 - xmin) / 2.0;
702 if (x2 == xmin || x1 == xmin) {
708 rfT.reasoning =
"Giving up because we're already at xmin and xnew points lower: " +
fp2str(xnew);
711 rfT.reasoning +=
"xval increased from " +
fp2str(xnew) +
" to the min value, " +
fp2str(xmin);
717 fprintf(fp,
" | xlimitmin = %-11.5E", xnew);
729 fprintf(fp,
"%-5d %-5d %-15.5E %-15.5E", its, 0, xnew, fnew);
763 if (! foundStraddle) {
777 }
else if (fnew < - fnoise) {
805 bool foundBetterPos =
false;
806 bool foundBetterNeg =
false;
810 foundBetterPos =
false;
815 if (foundBetterPos) {
827 foundBetterNeg =
false;
832 if (foundBetterNeg) {
846 foundBetterNeg =
false;
851 if (foundBetterNeg) {
863 foundBetterPos =
true;
868 if (foundBetterNeg) {
880 AssertThrow((f1* f2 <= 0.0),
"F1 and F2 aren't bounding");
887 rfT.deltaFConverged = fnorm *
m_rtolf;
889 rfT.delX = std::max(fabs(deltaX2), fabs(deltaXnew));
891 rfT.delX = std::max(fabs(deltaX2), fabs(deltaXnew));
893 rfT.delX = std::max(rfT.delX, x2 - xmin);
895 rfT.delX = std::max(rfT.delX, xmax - x2);
902 if ((fabs(fnew / fnorm) < m_rtolf) && foundStraddle) {
905 rfT.reasoning +=
"NormalConvergence";
909 else if (fabs(slope) > 1.0E-100) {
910 double xdels = fabs(fnew / slope);
913 rfT.reasoning +=
"NormalConvergence-SlopelimitsDelX";
925 doublereal denom = fabs(x1 - x2);
926 if (denom < 1.0E-200) {
929 rfT.reasoning +=
"ConvergenceFZero but X1X2Identical";
933 rfT.reasoning +=
" ConvergenceF and XSame";
944 doublereal denom = fabs(x1 - x2);
945 if (denom < 1.0E-200) {
948 rfT.reasoning +=
"FNotConverged but X1X2Identical";
957 rfT.reasoning +=
"FNotConverged but XSame";
962 }
while (! converged && its < itmax);
970 AssertThrow((f1* f2 <= 0.0),
"F1 and F2 aren't bounding");
978 rfT.delX = fabs(x_fpos - x_fneg);
979 if (doFinalFuncCall || (fabs(f1) < 2.0 * fabs(f2))) {
981 slope = (f2 - f1) / delXtmp;
982 xnew = x2 - f2 / slope;
986 if (fabs(xnew - x_fneg) < fabs(x_fpos - x_fneg)) {
988 rfT.delX = fabs(xnew - x_fneg);
991 if (fabs(xnew - x_fpos) < fabs(x_fpos - x_fneg)) {
993 rfT.delX = fabs(xnew - x_fpos);
997 if (fabs(fnew) < fabs(f2) && (fabs(fnew) < fabs(f1))) {
999 if (doFinalFuncCall) {
1000 rfT.reasoning +=
"CONVERGENCE: Another Evaluation Requested";
1001 rfT.delX = fabs(xnew - x2);
1003 rfT.reasoning +=
"CONVERGENCE: Another Evaluation done because f1 < f2";
1004 rfT.delX = fabs(xnew - x1);
1010 }
else if (fabs(f1) < fabs(f2)) {
1016 rfT.reasoning +=
"CONVERGENCE: Another Evaluation not as good as Second Point ";
1023 if (fabs(fnew) < fabs(f1)) {
1024 if (f1 * fnew > 0.0) {
1025 std::swap(f1, fnew);
1026 std::swap(x1, xnew);
1033 rfT.delX = fabs(x_fpos - x_fneg);
1034 rfT.reasoning +=
"CONVERGENCE: NormalEnding -> Second point used";
1041 rfT.reasoning +=
"CONVERGENCE: Another Evaluation not as good as First Point ";
1048 rfT.delX = fabs(x_fpos - x_fneg);
1049 rfT.reasoning +=
"CONVERGENCE: NormalEnding -> Last point used";
1057 rfT.delX = fabs(x2 - x1);
1058 rfT.reasoning +=
"CONVERGENCE: NormalEnding -> Last point used";
1064 writelogf(
"RootFind success: convergence achieved\n");
1068 fprintf(fp,
" | RootFind success in %d its, fnorm = %g\n", its, fnorm);
1073 rfT.reasoning =
"FAILED CONVERGENCE ";
1078 writelogf(
"RootFind ERROR: Soln probably lies higher than xmax, %g: best guess = %g\n", xmax, *xbest);
1080 rfT.reasoning +=
"Soln probably lies higher than xmax, " +
fp2str(xmax) +
": best guess = " +
fp2str(*xbest);
1083 writelogf(
"RootFind ERROR: Soln probably lies lower than xmin, %g: best guess = %g\n", xmin, *xbest);
1085 rfT.reasoning +=
"Soln probably lies lower than xmin, " +
fp2str(xmin) +
": best guess = " +
fp2str(*xbest);
1089 writelogf(
"RootFind ERROR: maximum iterations exceeded without convergence, cause unknown\n");
1091 rfT.reasoning +=
"Maximum iterations exceeded without convergence, cause unknown";
1095 fprintf(fp,
"\nRootFind failure in %d its\n", its);
1191 printf(
"\t----------------------------------------------------------------------------------------------------------------------------------------\n");
1192 printf(
"\t RootFinder Summary table: \n");
1194 printf(
"\t Iter | xval delX deltaXConv | slope | foundP foundN| F - F_targ deltaFConv | Reasoning\n");
1195 printf(
"\t----------------------------------------------------------------------------------------------------------------------------------------\n");
1196 for (
int i = 0; i < (int)
rfHistory_.size(); i++) {
1198 printf(
"\t %3d |%- 17.11E %- 13.7E %- 13.7E |%- 13.5E| %3d %3d | %- 12.5E %- 12.5E | %s \n",
1199 rfT.its, rfT.xval, rfT.delX, rfT.deltaXConverged, rfT.slope, rfT.foundPos, rfT.foundNeg, rfT.fval,
1200 rfT.deltaFConverged, (rfT.reasoning).c_str());
1202 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.
This file contains definitions for utility functions and text for modules, inputfiles, logs, textlogs, HTML_logs (see Input File Handling, Diagnostic Output, Writing messages to the screen and Writing HTML Logfiles).
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.
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.