double (atan2)(double y, double x) { /* compute atan(y/x) */ double z; const short errx = _Dtest(&x); const short erry = _Dtest(&y); unsigned short hex; if (errx <= 0 && erry <= 0) { /* x & y both finite or 0 */ if (y < 0.0) y = -y, hex = 0x8; else hex = 0x0; if (x < 0.0) x = -x, hex ^= 0x6; if (x < y) z = x / y, hex ^= 0x2; else if (0.0 < x) z = y / x; else return (0.0); /* atan(0, 0) */ } else if (errx == NAN || erry == NAN) { /* return one of the NaNs */ errno = EDOM; return (errx == NAN ? x : y); } else { /* at least one INF */ z = errx == erry ? 1.0 : 0.0; hex = DSIGN(y) ? 0x8 : 0x0; if (DSIGN(x)) hex ^= 0x6; if (erry == INF) hex ^= 0x2; } return (_Atan(z, hex)); }
double (exp)(double x) { /* compute exp(x) */ switch (_Dtest(&x)) { /* test for special codes */ case NAN: errno = EDOM; return (x); case INF: errno = ERANGE; return (DSIGN(x) ? 0.0 : _Inf._D); case 0: return (1.0); default: /* finite */ if (0 <= _Exp(&x, 0)) errno = ERANGE; return (x); } }
double (atan)(double x) { /* compute atan(x) */ unsigned short hex; static const double piby2 = 1.57079632679489661923; switch (_Dtest(&x)) { /* test for special codes */ case NAN: errno = EDOM; return (x); case INF: return (DSIGN(x) ? -piby2 : piby2); case 0: return (0.0); default: /* finite */ if (x < 0.0) x = -x, hex = 0x8; else hex = 0x0; if (1.0 < x) x = 1.0 / x, hex ^= 0x2; return (_Atan(x, hex)); } }
double XDSIGN( double *arg1, double *arg2 ) { //=========================================== return( DSIGN( *arg1, *arg2 ) ); }
/* * * vcs_root1d: * * * * Following is a nontrial example for vcs_root1d() where the buoyancy of a * cylinder floating on water is calculated. * * @verbatim * #include <cmath> * #include <cstdlib> * * #include "Cantera.h" * #include "kernel/vcs_internal.h" * * const double g_cgs = 980.; * const double mass_cyl = 0.066; * const double diam_cyl = 0.048; * const double rad_cyl = diam_cyl / 2.0; * const double len_cyl = 5.46; * const double vol_cyl = Pi * diam_cyl * diam_cyl / 4 * len_cyl; * const double rho_cyl = mass_cyl / vol_cyl; * const double rho_gas = 0.0; * const double rho_liq = 1.0; * const double sigma = 72.88; * // Contact angle in radians * const double alpha1 = 40.0 / 180. * Pi; * * using namespace Cantera; * using namespace VCSnonideal; * * double func_vert(double theta1, double h_2, double rho_c) { * double f_grav = - Pi * rad_cyl * rad_cyl * rho_c * g_cgs; * double tmp = rad_cyl * rad_cyl * g_cgs; * double tmp1 = theta1 + sin(theta1) * cos(theta1) - 2.0 * h_2 / rad_cyl * sin(theta1); * double f_buoy = tmp * (Pi * rho_gas + (rho_liq - rho_gas) * tmp1); * double f_sten = 2 * sigma * sin(theta1 + alpha1 - Pi); * double f_net = f_grav + f_buoy + f_sten; * return f_net; * } * double calc_h2_farfield(double theta1) { * double rhs = sigma * (1.0 + cos(alpha1 + theta1)); * rhs *= 2.0; * rhs = rhs / (rho_liq - rho_gas) / g_cgs; * double sign = -1.0; * if (alpha1 + theta1 < Pi) sign = 1.0; * double res = sign * sqrt(rhs); * double h2 = res + rad_cyl * cos(theta1); * return h2; * } * double funcZero(double xval, double Vtarget, int varID, void *fptrPassthrough, int *err) { * double theta = xval; * double h2 = calc_h2_farfield(theta); * double fv = func_vert(theta, h2, rho_cyl); * return fv; * } * * int main () { * * double thetamax = Pi; * double thetamin = 0.0; * int maxit = 1000; * int iconv; * double thetaR = Pi/2.0; * int printLvl = 4; * * iconv = VCSnonideal::vcsUtil_root1d(thetamin, thetamax, maxit, funcZero, * (void *) 0, 0.0, 0, &thetaR, printLvl); * printf("theta = %g\n", thetaR); * double h2Final = calc_h2_farfield(thetaR); * printf("h2Final = %g\n", h2Final); * return 0; * } * @endverbatim * */ int vcsUtil_root1d(double xmin, double xmax, int itmax, VCS_FUNC_PTR func, void *fptrPassthrough, double FuncTargVal, int varID, double *xbest, int printLvl) { static int callNum = 0; const char *stre = "vcs_root1d ERROR: "; const char *strw = "vcs_root1d WARNING: "; int converged = FALSE, err = FALSE; #ifdef DEBUG_MODE char fileName[80]; FILE *fp = 0; #endif double x1, x2, xnew, f1, f2, fnew, slope; int its = 0; int posStraddle = 0; int retn = VCS_SUCCESS; int foundPosF = FALSE; int foundNegF = FALSE; int foundStraddle = FALSE; double xPosF = 0.0; double xNegF = 0.0; double fnorm; /* A valid norm for the making the function value * dimensionless */ double c[9], f[3], xn1, xn2, x0 = 0.0, f0 = 0.0, root, theta, xquad; callNum++; #ifdef DEBUG_MODE if (printLvl >= 3) { sprintf(fileName, "rootfd_%d.log", callNum); fp = fopen(fileName, "w"); fprintf(fp, " Iter TP_its xval Func_val | Reasoning\n"); fprintf(fp, "-----------------------------------------------------" "-------------------------------\n"); } #else if (printLvl >= 3) { plogf("WARNING: vcsUtil_root1d: printlvl >= 3, but debug mode not turned on\n"); } #endif if (xmax <= xmin) { plogf("%sxmin and xmax are bad: %g %g\n", stre, xmin, xmax); return VCS_PUB_BAD; } x1 = *xbest; if (x1 < xmin || x1 > xmax) { x1 = (xmin + xmax) / 2.0; } f1 = func(x1, FuncTargVal, varID, fptrPassthrough, &err); #ifdef DEBUG_MODE if (printLvl >= 3) { print_funcEval(fp, x1, f1, its); fprintf(fp, "%-5d %-5d %-15.5E %-15.5E\n", -2, 0, x1, f1); } #endif if (f1 == 0.0) { *xbest = x1; return VCS_SUCCESS; } else if (f1 > 0.0) { foundPosF = TRUE; xPosF = x1; } else { foundNegF = TRUE; xNegF = x1; } x2 = x1 * 1.1; if (x2 > xmax) x2 = x1 - (xmax - xmin) / 100.; f2 = func(x2, FuncTargVal, varID, fptrPassthrough, &err); #ifdef DEBUG_MODE if (printLvl >= 3) { print_funcEval(fp, x2, f2, its); fprintf(fp, "%-5d %-5d %-15.5E %-15.5E", -1, 0, x2, f2); } #endif if (FuncTargVal != 0.0) { fnorm = fabs(FuncTargVal) + 1.0E-13; } else { fnorm = 0.5*(fabs(f1) + fabs(f2)) + fabs(FuncTargVal); } if (f2 == 0.0) return retn; else if (f2 > 0.0) { if (!foundPosF) { foundPosF = TRUE; xPosF = x2; } } else { if (!foundNegF) { foundNegF = TRUE; xNegF = x2; } } foundStraddle = foundPosF && foundNegF; if (foundStraddle) { if (xPosF > xNegF) posStraddle = TRUE; else posStraddle = FALSE; } do { /* * Find an estimate of the next point to try based on * a linear approximation. */ slope = (f2 - f1) / (x2 - x1); if (slope == 0.0) { plogf("%s functions evals produced the same result, %g, at %g and %g\n", strw, f2, x1, x2); xnew = 2*x2 - x1 + 1.0E-3; } else { xnew = x2 - f2 / slope; } #ifdef DEBUG_MODE if (printLvl >= 3) { fprintf(fp, " | xlin = %-9.4g", xnew); } #endif /* * Do a quadratic fit -> Note this algorithm seems * to work OK. The quadratic approximation doesn't kick in until * the end of the run, when it becomes reliable. */ if (its > 0) { c[0] = 1.; c[1] = 1.; c[2] = 1.; c[3] = x0; c[4] = x1; c[5] = x2; c[6] = SQUARE(x0); c[7] = SQUARE(x1); c[8] = SQUARE(x2); f[0] = - f0; f[1] = - f1; f[2] = - f2; retn = vcsUtil_mlequ(c, 3, 3, f, 1); if (retn == 1) goto QUAD_BAIL; root = f[1]* f[1] - 4.0 * f[0] * f[2]; if (root >= 0.0) { xn1 = (- f[1] + sqrt(root)) / (2.0 * f[2]); xn2 = (- f[1] - sqrt(root)) / (2.0 * f[2]); if (fabs(xn2 - x2) < fabs(xn1 - x2) && xn2 > 0.0 ) xquad = xn2; else xquad = xn1; theta = fabs(xquad - xnew) / fabs(xnew - x2); theta = MIN(1.0, theta); xnew = theta * xnew + (1.0 - theta) * xquad; #ifdef DEBUG_MODE if (printLvl >= 3) { if (theta != 1.0) { fprintf(fp, " | xquad = %-9.4g", xnew); } } #endif } else { /* * Pick out situations where the convergence may be * accelerated. */ if ((DSIGN(xnew - x2) == DSIGN(x2 - x1)) && (DSIGN(x2 - x1) == DSIGN(x1 - x0)) ) { xnew += xnew - x2; #ifdef DEBUG_MODE if (printLvl >= 3) { fprintf(fp, " | xquada = %-9.4g", xnew); } #endif } } } QUAD_BAIL: ; /* * * Put heuristic bounds on the step jump */ if ( (xnew > x1 && xnew < x2) || (xnew < x1 && xnew > x2)) { /* * * If we are doing a jump inbetween two points, make sure * the new trial is between 10% and 90% of the distance * between the old points. */ slope = fabs(x2 - x1) / 10.; if (fabs(xnew - x1) < slope) { xnew = x1 + DSIGN(xnew-x1) * slope; #ifdef DEBUG_MODE if (printLvl >= 3) { fprintf(fp, " | x10%% = %-9.4g", xnew); } #endif } if (fabs(xnew - x2) < slope) { xnew = x2 + DSIGN(xnew-x2) * slope; #ifdef DEBUG_MODE if (printLvl >= 3) { fprintf(fp, " | x10%% = %-9.4g", xnew); } #endif } } else { /* * If we are venturing into new ground, only allow the step jump * to increase by 100% at each interation */ slope = 2.0 * fabs(x2 - x1); if (fabs(slope) < fabs(xnew - x2)) { xnew = x2 + DSIGN(xnew-x2) * slope; #ifdef DEBUG_MODE if (printLvl >= 3) { fprintf(fp, " | xlimitsize = %-9.4g", xnew); } #endif } } if (xnew > xmax) { xnew = x2 + (xmax - x2) / 2.0; #ifdef DEBUG_MODE if (printLvl >= 3) { fprintf(fp, " | xlimitmax = %-9.4g", xnew); } #endif } if (xnew < xmin) { xnew = x2 + (x2 - xmin) / 2.0; #ifdef DEBUG_MODE if (printLvl >= 3) { fprintf(fp, " | xlimitmin = %-9.4g", xnew); } #endif } if (foundStraddle) { #ifdef DEBUG_MODE slope = xnew; #endif if (posStraddle) { if (f2 > 0.0) { if (xnew > x2) xnew = (xNegF + x2)/2; if (xnew < xNegF) xnew = (xNegF + x2)/2; } else { if (xnew < x2) xnew = (xPosF + x2)/2; if (xnew > xPosF) xnew = (xPosF + x2)/2; } } else { if (f2 > 0.0) { if (xnew < x2) xnew = (xNegF + x2)/2; if (xnew > xNegF) xnew = (xNegF + x2)/2; } else { if (xnew > x2) xnew = (xPosF + x2)/2; if (xnew < xPosF) xnew = (xPosF + x2)/2; } } #ifdef DEBUG_MODE if (printLvl >= 3) { if (slope != xnew) { fprintf(fp, " | xstraddle = %-9.4g", xnew); } } #endif } fnew = func(xnew, FuncTargVal, varID, fptrPassthrough, &err); #ifdef DEBUG_MODE if (printLvl >= 3) { fprintf(fp,"\n"); print_funcEval(fp, xnew, fnew, its); fprintf(fp, "%-5d %-5d %-15.5E %-15.5E", its, 0, xnew, fnew); } #endif if (foundStraddle) { if (posStraddle) { if (fnew > 0.0) { if (xnew < xPosF) xPosF = xnew; } else { if (xnew > xNegF) xNegF = xnew; } } else { if (fnew > 0.0) { if (xnew > xPosF) xPosF = xnew; } else { if (xnew < xNegF) xNegF = xnew; } } } if (! foundStraddle) { if (fnew > 0.0) { if (!foundPosF) { foundPosF = TRUE; xPosF = xnew; foundStraddle = TRUE; if (xPosF > xNegF) posStraddle = TRUE; else posStraddle = FALSE; } } else { if (!foundNegF) { foundNegF = TRUE; xNegF = xnew; foundStraddle = TRUE; if (xPosF > xNegF) posStraddle = TRUE; else posStraddle = FALSE; } } } x0 = x1; f0 = f1; x1 = x2; f1 = f2; x2 = xnew; f2 = fnew; if (fabs(fnew / fnorm) < 1.0E-5) { converged = TRUE; } its++; } while (! converged && its < itmax); if (converged) { if (printLvl >= 1) { plogf("vcs_root1d success: convergence achieved\n"); } #ifdef DEBUG_MODE if (printLvl >= 3) { fprintf(fp, " | vcs_root1d success in %d its, fnorm = %g\n", its, fnorm); } #endif } else { retn = VCS_FAILED_CONVERGENCE; if (printLvl >= 1) { plogf("vcs_root1d ERROR: maximum iterations exceeded without convergence\n"); } #ifdef DEBUG_MODE if (printLvl >= 3) { fprintf(fp, "\nvcs_root1d failure in %d its\n", its); } #endif } *xbest = x2; #ifdef DEBUG_MODE if (printLvl >= 3) { fclose(fp); } #endif return retn; }