def shoot(f, a, b, z1, z2, t, tol): """Implements the shooting method to solve second order BVPs USAGE: y = shoot(f, a, b, z1, z2, t, tol) INPUT: f - function dy/dt = f(y,t). Since we are solving a second- order boundary-value problem that has been transformed into a first order system, this function should return a 1x2 array with the first entry equal to y and the second entry equal to y'. a - solution value at the left boundary: a = y(t[0]). b - solution value at the right boundary: b = y(t[n-1]). z1 - first initial estimate of y'(t[0]). z1 - second initial estimate of y'(t[0]). t - array of n time values to determine y at. tol - allowable tolerance on right boundary: | b - y[n-1] | < tol OUTPUT: y - array of solution function values corresponding to the values in the supplied array t. NOTE: This function assumes that the second order BVP has been converted to a first order system of two equations. The secant method is used to refine the initial values of y' used for the initial value problems. """ from diffeq import rk4 max_iter = 25 # Maximum number of shooting iterations n = len(t) # Determine the size of the arrays we will generate # Compute solution to first initial value problem (IVP) with y'(a) = z1. # Because we are using the secant method to refine our estimates of z = # y', we don't really need all the solution of the IVP, just the last # point of it -- this is saved in w1. y = rk4(f, [a, z1], t) w1 = y[n - 1, 0] print "%2d: z = %10.3e, error = %10.3e" % (0, z1, b - w1) # Begin the main loop. We will compute the solution of a second IVP and # then use the both solutions to refine our estimate of y'(a). This # second solution then replaces the first and a new "second" solution is # generated. This process continues until we either solve the problem to # within the specified tolerance or we exceed the maximum number of # allowable iterations. for i in xrange(max_iter): # Solve second initial value problem, using y'(a) = z2. We need to # retain the entire solution vector y since if y(t(n)) is close enough # to b for us to stop then the first column of y becomes our solution # vector. y = rk4(f, [a, z2], t) w2 = y[n - 1, 0] print "%2d: z = %10.3e, error = %10.3e" % (i + 1, z2, b - w2) # Check to see if we are done... if abs(b - w2) < tol: break # Compute the new approximations to the initial value of the first # derivative. We compute z2 using a linear fit through (z1,w1) and # (z2,w2) where w1 and w2 are the estimates at t=b of the initial # value problems solved above with y1'(a) = z1 and y2'(a) = z2. The # new value for z1 is the old value of z2. #z1, z2 = ( z2, z1 + ( z2 - z1 ) / ( w2 - w1 ) * ( b - w1 ) ) z1, z2 = (z2, z2 + (z2 - z1) / (w2 - w1) * (b - w2)) w1 = w2 # All done. Check to see if we really solved the problem, and then return # the solution. if abs(b - w2) >= tol: print "\a**** ERROR ****" print "Maximum number of iterations (%d) exceeded" % max_iter print "Returned values may not have desired accuracy" print "Error estimate of returned solution is %e" % (b - w2) return y[:, 0]
""" Created on Sat Sep 29 18:38:09 2018 @author: Ben """ import numpy as np from matplotlib import pyplot as pyl from diffeq import rk4 f = lambda T, t: -r * (T - Ts) tmax = 60. T0 = 10. r = 0.1 Ts = 83. n = 5 dt = np.zeros(n) temp = np.zeros(n) for j in range(0, n): dt[j] = 1 / (j + 1) nsteps = int( tmax / dt[j]) #the arrays will have different size for different time steps T = T0 my_temp, my_time = rk4(f, 0, tmax, nsteps) temp[j] = my_temp[10 * (j + 1)] pyl.plot(dt, temp, 'o') pyl.xlabel('dt') pyl.ylabel('Temp.')
for j in range(0, 20): #arbitrarily increase the size deltatarr.append(dt) nsteps = int( tmax / dt) #the arrays will have different size for different time steps my_time = np.linspace(dt, tmax, nsteps) my_temp = np.zeros(nsteps) T = T0 for i in range(1, nsteps): T = euler(T, -r * (T - Ts), dt) my_temp[i] = T if dt * i == 10: t10.append(T) pyplot.plot(my_time, my_temp, ls='-', lw=0.5) dt = dt / 2. print(t10) print(deltatarr) pyplot.xlabel('time') pyplot.ylabel('temperature') pyplot.xlim(8, 10) pyplot.ylim(48, 58) fig2 = pyplot.figure(2) ax2 = fig2.add_subplot(111) ax2.scatter(deltatarr, t10) m = diffeq.rk4(-r * (T - Ts))
def shoot( f, a, b, z1, z2, t, tol ): """Implements the shooting method to solve second order BVPs USAGE: y = shoot(f, a, b, z1, z2, t, tol) INPUT: f - function dy/dt = f(y,t). Since we are solving a second- order boundary-value problem that has been transformed into a first order system, this function should return a 1x2 array with the first entry equal to y and the second entry equal to y'. a - solution value at the left boundary: a = y(t[0]). b - solution value at the right boundary: b = y(t[n-1]). z1 - first initial estimate of y'(t[0]). z1 - second initial estimate of y'(t[0]). t - array of n time values to determine y at. tol - allowable tolerance on right boundary: | b - y[n-1] | < tol OUTPUT: y - array of solution function values corresponding to the values in the supplied array t. NOTE: This function assumes that the second order BVP has been converted to a first order system of two equations. The secant method is used to refine the initial values of y' used for the initial value problems. """ from diffeq import rk4 max_iter = 25 # Maximum number of shooting iterations n = len( t ) # Determine the size of the arrays we will generate # Compute solution to first initial value problem (IVP) with y'(a) = z1. # Because we are using the secant method to refine our estimates of z = # y', we don't really need all the solution of the IVP, just the last # point of it -- this is saved in w1. y = rk4( f, [a,z1], t ) w1 = y[n-1,0] print "%2d: z = %10.3e, error = %10.3e" % ( 0, z1, b - w1 ) # Begin the main loop. We will compute the solution of a second IVP and # then use the both solutions to refine our estimate of y'(a). This # second solution then replaces the first and a new "second" solution is # generated. This process continues until we either solve the problem to # within the specified tolerance or we exceed the maximum number of # allowable iterations. for i in xrange( max_iter ): # Solve second initial value problem, using y'(a) = z2. We need to # retain the entire solution vector y since if y(t(n)) is close enough # to b for us to stop then the first column of y becomes our solution # vector. y = rk4( f, [a,z2], t ) w2 = y[n-1,0] print "%2d: z = %10.3e, error = %10.3e" % ( i+1, z2, b - w2 ) # Check to see if we are done... if abs( b - w2 ) < tol: break # Compute the new approximations to the initial value of the first # derivative. We compute z2 using a linear fit through (z1,w1) and # (z2,w2) where w1 and w2 are the estimates at t=b of the initial # value problems solved above with y1'(a) = z1 and y2'(a) = z2. The # new value for z1 is the old value of z2. #z1, z2 = ( z2, z1 + ( z2 - z1 ) / ( w2 - w1 ) * ( b - w1 ) ) z1, z2 = ( z2, z2 + ( z2 - z1 ) / ( w2 - w1 ) * ( b - w2 ) ) w1 = w2 # All done. Check to see if we really solved the problem, and then return # the solution. if abs( b - w2 ) >= tol: print "\a**** ERROR ****" print "Maximum number of iterations (%d) exceeded" % max_iter print "Returned values may not have desired accuracy" print "Error estimate of returned solution is %e" % ( b - w2 ) return y[:,0]
plt.figure(figsize = (6.75,5)) plt.xlabel('Time', fontsize = 14) plt.xticks(fontsize = 14) plt.yticks(fontsize = 14) plt.title('Huen Method (rk2)') plt.plot(t, theta2, label = 'Theta') plt.plot([],[], label = f"R^2 = {format(r2_theta,'.5')}") plt.plot(t, omega2,'--', label = 'Omega') plt.plot([],[], label = f"R^2 = {format(r2_omega,'.5')}") plt.tight_layout() plt.legend(fontsize = 12) plt.savefig('huen1.pdf') # Testing RK4 method, plotting theta3, omega3, time3 = df.rk4(pend, y0, t) r3_theta = np.corrcoef(sol1[:,0], theta3)[0,1] r3_omega = np.corrcoef(sol1[:,1], omega3)[0,1] plt.figure(figsize = (6.75,5)) plt.xlabel('Time', fontsize = 14) plt.xticks(fontsize = 14) plt.yticks(fontsize = 14) plt.title('RK4 method') plt.plot(t, theta3, label = 'Theta') plt.plot([],[], label = f"R^2 = {format(r3_theta,'.5')}") plt.plot(t, omega3, '--', label = 'Omega') plt.plot([],[], label = f"R^2 = {format(r3_omega,'.5')}") plt.tight_layout() plt.legend(fontsize = 12) plt.savefig('rk41.pdf')