#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){
			G_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){
		G_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;
}

