/**
 * 
 */
package pacemaker;

/**
 * Useful <code>static</code> code related to
 * <b>Phase Response Curve</b> (PRC) related to 
 * {@link Firefly#PAR_MODEL "ADAPTIVE" model} (Ermentrout, 1991) .<p> 
 * 
 * The implementation for g<sup>+</sup> and g<sup>-</sup> 
 * functions (as definited in the paper) are provided. They are really easy max/min
 * single line ops when it is recognized that they have a common core, this is 
 * implemented in <code>fcore()</code> 
 * <code>core = 1/(2*pigreco) * sin(2*pigreco*phase)</code> 
 * 
 * @author Tony Binci
 *
 */
public class AdaptiveModel {
	
	/**
	 * Evaluate the common core of g<sup>+</sup> and g<sup>-</sup> functions:<p>
	 * <code>= 1/(2*pigreco) * sin(2*pigreco*phase)</code> 
 	 * @param phase - the phase (x value) proportional to period. In range [0,1].
	 */
	public static double fcore(double phase) {
		return (1.0d/(2.0d*Math.PI)) * Math.sin(2.0d*Math.PI*phase);
	}
	
	/**
	 * Evaluates the g<sup>+</sup> function.<p>
	 * <code>g<sup>+</sup>(x) = max(fcore(x), 0)</code><p>
	 * 
	 * @param phase - the phase (x value) proportional to period. In range [0,1]. 
	 */
	public static double gplus(double phase) {
		return Math.max( fcore(phase), 0.0d);
	}
	
	/**
	 * Evaluates the g<sup>-</sup> function.<p>
	 * <code>g<sup>-</sup>(x) = max(fcore(x), 0)</code><p>
	 * 
	 * @param phase - the phase (x value) proportional to period. In range [0,1]. 
	 */
	public static double gminus(double phase) {
		return -Math.min( fcore(phase), 0.0d );
	}
	
	
	/**
	 * Evaluates the PRC for the given phase.<p>
	 * 
	 * @param phase - the phase (x value) proportional to period. In range [0,1]. 
	 * @return PRC evaluation (y value): in range [0,1].
	 */
	public static double eval_PRC(double phase, int period, int max, int min) {
		//double x = phase/period;
		if ( phase < 0.0d ) return 0.0d;
		//if ( (phase % 1.0d) == 0.0d) return 0;
		return gplus(phase) * ((1.0d/min) - (1.0d/period)) + 
		       gminus(phase)* ((1.0d/max) - (1.0d/period)); 
	}
	
	/*
	 * Evaluate the inverse function <code>f<sup>-1</sup></code> of the PRC:
	 * given the y value, you get the x value (the phase).<p>
	 * @see #eval_prc(double, int)
	 * @param y - y value, in range [0,1]
	 * @return x value - the phase. In range [0,1].
	 */
	/*public static double eval_inverse_PRC(double y, int b) {
		if ( y < 0.0d ) return 0.0d;
		if ( y > 1.0d ) return 1.0d;
		if ( b == 0 ) return y;
		return ( Math.exp( b*y ) - 1.0d)/( Math.exp(b) - 1.0d);
	}*/

	/** For testing purposes */
	public static void main(String[] args) {
		System.out.println("Testing PRC...");
		int period = 1000;
		int max = 1200;
		int min = 800;
		for (double x = -0.1d; x <= 2.0d; x += 0.05d)
			System.out.println("x="+x+" fcore="+fcore(x)+" g+="+gplus(x)+
					" g-="+gminus(x)+" PRC="+eval_PRC(x, period, max, min));
	}
}
