double MiscibilityLiveOil::miscible_oil(double press, const surfvol_t& surfvol,
					    int item, bool deriv) const
    {
	int section;
	double R = linearInterpolation(saturated_oil_table_[0],
					     saturated_oil_table_[3],
					     press, section);
	double maxR = (surfvol[Liquid] == 0.0) ? 0.0 : surfvol[Vapour]/surfvol[Liquid];
	if (deriv) {
	    if (R < maxR ) {  // Saturated case
		return linearInterpolationDerivative(saturated_oil_table_[0],
						saturated_oil_table_[item],
						press);
	    } else {  // Undersaturated case
		int is = tableIndex(saturated_oil_table_[3], maxR);
		double w = (maxR - saturated_oil_table_[3][is]) /
		    (saturated_oil_table_[3][is+1] - saturated_oil_table_[3][is]);
                ASSERT(undersat_oil_tables_[is][0].size() >= 2);
                ASSERT(undersat_oil_tables_[is+1][0].size() >= 2);
		double val1 =
		    linearInterpolationDerivative(undersat_oil_tables_[is][0],
					     undersat_oil_tables_[is][item],
					     press);
		double val2 = 
		    linearInterpolationDerivative(undersat_oil_tables_[is+1][0],
					     undersat_oil_tables_[is+1][item],
					     press);
		double val = val1 + w*(val2 - val1);
		return val;
	    }
	} else {
	    if (R < maxR ) {  // Saturated case
		return linearInterpolation(saturated_oil_table_[0],
						 saturated_oil_table_[item],
						 press);
	    } else {  // Undersaturated case
		// Interpolate between table sections
                int is = tableIndex(saturated_oil_table_[3], maxR);
		double w = (maxR - saturated_oil_table_[3][is]) /
		    (saturated_oil_table_[3][is+1] - saturated_oil_table_[3][is]);
                ASSERT(undersat_oil_tables_[is][0].size() >= 2);
                ASSERT(undersat_oil_tables_[is+1][0].size() >= 2);
		double val1 =
		    linearInterpolation(undersat_oil_tables_[is][0],
					      undersat_oil_tables_[is][item],
					      press);
		double val2 = 
		    linearInterpolation(undersat_oil_tables_[is+1][0],
					      undersat_oil_tables_[is+1][item],
					      press);
		double val = val1 + w*(val2 - val1);
		return val;
	    }
	}
    }
    // Vaporised oil-gas ratio derivative
    double MiscibilityLiveGas::dRdp(int /*region*/, double press, const surfvol_t& surfvol) const
    {
	double R = linearInterpolation(saturated_gas_table_[0],
					     saturated_gas_table_[3], press);
	double maxR = surfvol[Liquid]/surfvol[Vapour];
	if (R < maxR ) {  // Saturated case
	    return linearInterpolationDerivative(saturated_gas_table_[0],
					    saturated_gas_table_[3],
					    press);
	} else {
	    return 0.0;  // Undersaturated case
	}	
    }
    void MiscibilityLiveOil::evalRDeriv(const double press, const surfvol_t& surfvol,
                                        double& R, double& dRdp) const
    {
        if (surfvol[Vapour] == 0.0) {
            R = 0.0;
            dRdp = 0.0;
            return;
        }
	R = linearInterpolation(saturated_oil_table_[0],
                                      saturated_oil_table_[3], press);
	double maxR = surfvol[Vapour]/surfvol[Liquid];
	if (R < maxR ) {
            // Saturated case
	    dRdp = linearInterpolationDerivative(saturated_oil_table_[0],
					    saturated_oil_table_[3],
					    press);
	} else {
            // Undersaturated case
            R = maxR;
	    dRdp = 0.0;
	}
    }
    double MiscibilityLiveGas::miscible_gas(double press, const surfvol_t& surfvol, int item,
					    bool deriv) const
    {
	int section;
	double R = linearInterpolation(saturated_gas_table_[0],
					     saturated_gas_table_[3], press,
					     section);
	double maxR = surfvol[Liquid]/surfvol[Vapour];
	if (deriv) {
	    if (R < maxR ) {  // Saturated case
		return linearInterpolationDerivative(saturated_gas_table_[0],
						saturated_gas_table_[item],
						press);
	    } else {  // Undersaturated case
		int is = section;
		if (undersat_gas_tables_[is][0].size() < 2) {
		    double val = (saturated_gas_table_[item][is+1]
				  - saturated_gas_table_[item][is]) /
			(saturated_gas_table_[0][is+1] -
			 saturated_gas_table_[0][is]);
		    return val;
		}
		double val1 =
		    linearInterpolation(undersat_gas_tables_[is][0],
					      undersat_gas_tables_[is][item],
					      maxR);
		double val2 = 
		    linearInterpolation(undersat_gas_tables_[is+1][0],
					      undersat_gas_tables_[is+1][item],
					      maxR);
		double val = (val2 - val1)/
		    (saturated_gas_table_[0][is+1] - saturated_gas_table_[0][is]);
		return val;
	    }
	} else {
	    if (R < maxR ) {  // Saturated case
		return linearInterpolation(saturated_gas_table_[0],
						 saturated_gas_table_[item],
						 press);
	    } else {  // Undersaturated case
		int is = section;
		// Extrapolate from first table section
		if (is == 0 && press < saturated_gas_table_[0][0]) {
		    return linearInterpolation(undersat_gas_tables_[0][0],
						     undersat_gas_tables_[0][item],
						     maxR);
		}

		// Extrapolate from last table section
		int ltp = saturated_gas_table_[0].size() - 1;
		if (is+1 == ltp && press > saturated_gas_table_[0][ltp]) {
		    return linearInterpolation(undersat_gas_tables_[ltp][0],
						     undersat_gas_tables_[ltp][item],
						     maxR);
		}

		// Interpolate between table sections
		double w = (press - saturated_gas_table_[0][is]) /
		    (saturated_gas_table_[0][is+1] - 
		     saturated_gas_table_[0][is]);
		if (undersat_gas_tables_[is][0].size() < 2) {
		    double val = saturated_gas_table_[item][is] +
			w*(saturated_gas_table_[item][is+1] -
			   saturated_gas_table_[item][is]);
		    return val;
		}
		double val1 =
		    linearInterpolation(undersat_gas_tables_[is][0],
					      undersat_gas_tables_[is][item],
					      maxR);
		double val2 = 
		    linearInterpolation(undersat_gas_tables_[is+1][0],
					      undersat_gas_tables_[is+1][item],
					      maxR);
		double val = val1 + w*(val2 - val1);
		return val;
	    }
	}
    }
	inline double
	NonuniformTableLinear<T>
	::derivative(const double x) const
	{
	    return linearInterpolationDerivative(x_values_, y_values_, x);
	}