#!-/usr/bin/python
# Runge-Kutta (4th order) method of Solving the following System
# Harmonic Oscillator
# y''(t) + y(t) = 0
# y(0)=1, 	y'(0)=0

import matplotlib.pyplot as plt
import numpy as np

global y, error, t, ynew, yprev, values
y = np.array([0,0])
values = np.array([[],[]])
val_t = np.array([])
val_calc = np.array([])
error = 0	# initialize error
error_max = 0.01
error_min = 0.00001
errorEval = True

h = .1		# step size
hStep = 1.1	# step size adaptive constant
tmax = 100*np.pi	# max time


t = 0
ynew = 0
yprev = 1
k1 = 0
k2 = 0
k3 = 0
k4 = 0

def rk4_values(step, time, preVal):
	k1 = step*slope(time,preVal)
	k2 = step*slope(time+step/2, preVal+k1/2)	#looks like there will be no difference for R-K
	k3 = step*slope(time+step/2, preVal+k2/2)
	k4 = step*slope(time+step, preVal+k3)
	
	ynew = preVal + k1/6 + k2/3 + k3/3 + k4/6
	return ynew


def slope(x,y):
	return -np.sin(x)

while t < tmax :
	#check step size
	while (errorEval):
		#nominal Step
		ynom_new = rk4_values(h,t,yprev)

		#half step 1
		y_half1 = rk4_values(h/2, t, yprev)

		#half step 2
		y_half2 = rk4_values(h/2+h/2, t, y_half1)

		#check error
		errorCheck = np.absolute(ynom_new - y_half2)
		if errorCheck < error_min:
			h = h*hStep
		elif errorCheck > error_max:
			h = h*1/hStep
		else :
			h = h
			errorEval = False
		print errorCheck

	errorEval = True	#need to reset for next time step

	#now actually calculate 
	ynew = rk4_values(h, t, yprev)
	yprev = ynew


	val_t = np.append(val_t, t)
	val_calc = np.append(val_calc, ynew)
	error = error + np.absolute(np.cos(t) - ynew)
	
	t+= h

error_avg = error/len(val_t)
error_final = np.absolute(np.cos(val_t[len(val_t)-1]) - val_calc[len(val_calc)-1])

print "Step Size: %f" % h
print "average error: %f" % error_avg
print "final error: %f" % error_final
print "number of steps %d" % len(val_t) 	

print "final slope: %f" % slope(t-h, 0)
plt.plot(val_t, val_calc)
plt.show()

