#include "global.h" /* The Green-and-Ampt Model */ double get_f(double t, double R) { static double cumf = 0.0, f_ = 0.0; static char ponding = 0; double f, f1, f2, fc, R2, cnst, pt, psi_dtheta, sum; int factorial; int i, j; /* reset if there is no rainfall */ if (R <= 0.0) { cumf = 0.0; f_ = 0.0; ponding = 0; return 0.0; } f1 = cnst = pt = 0.0; psi_dtheta = params.psi * params.dtheta; if (!ponding) { if (cumf) { f1 = cumf; R2 = -params.K0 / params.m * (psi_dtheta + f1) / (1 - exp(f1 / params.m)); /* rainfall intensity is greater than infiltration * rate, so ponding starts */ if (R2 < R) { f_ = cumf; pt = t - input.dt; ponding = 1; goto cont1; } } f2 = cumf + R * input.dt; R2 = -params.K0 / params.m * (psi_dtheta + f2) / (1 - exp(f2 / params.m)); /* rainfall intensity is less than infiltration rate. all * rainfall will be infiltrated. */ if (f2 == 0.0 || R2 > R) { f = R; cumf += f * input.dt; ponding = 0; return f; } /* rainfall intensity is greater than infiltration rate. */ f_ = cumf + R2 * input.dt; for (i = 0; i < MAXITER; i++) { R2 = -params.K0 / params.m * (psi_dtheta + f_) / (1 - exp(f_ / params.m)); if (R2 > R) { f1 = f_; f_ = (f_ + f2) / 2.0; f = f_ - f1; } else { f2 = f_; f_ = (f_ + f1) / 2.0; f = f_ - f2; } if (fabs(f) < TOLERANCE) break; } if (i == MAXITER) { Rast_set_d_null_value(&f, 1); return f; } pt = t - input.dt + (f_ - cumf) / R; if (pt > t) { f = R; cumf += f * input.dt; ponding = 0; return f; } cont1: cnst = 0.0; factorial = 1; fc = (f_ + psi_dtheta); for (j = 1; j <= NTERMS; j++) { factorial *= j; cnst += pow(fc / params.m, (double)j) / (double)(j * factorial); } cnst = log(fc) - (log(fc) + cnst) / exp(psi_dtheta / params.m); f_ += R * (t - pt) / 2.0; ponding = 1; } /* Newton-Raphson */ for (i = 0; i < MAXITER; i++) { fc = f_ + psi_dtheta; sum = 0.0; factorial = 1; for (j = 1; j <= NTERMS; j++) { factorial *= j; sum += pow(fc / params.m, (double)j) / (double)(j * factorial); } f1 = -(log(fc) - (log(fc) + sum) / exp(psi_dtheta / params.m) - cnst) / (params.K0 / params.m) - (t - pt); f2 = (exp(f_ / params.m) - 1.0) / (fc * params.K0 / params.m); f = -f1 / f2; f_ += f; if (fabs(f) < TOLERANCE) break; } if (i == MAXITER) { Rast_set_d_null_value(&f, 1); return f; } if (f_ < cumf + R * input.dt) { f = (f_ - cumf) / input.dt; cumf = f_; /* initial guess for next time step */ f_ += f * input.dt; } return f; }