Buckets:
| import scitools.std as plt | |
| #import matplotlib.pyplot as plt | |
| import sys | |
| import odespy | |
| import numpy as np | |
| class RHS: | |
| """m*u'' + b*f(u') + k*u = A_F*cos(w_F*t). Linear/quadratic f.""" | |
| def __init__(self, m=1, b=0, k=2*np.pi, A_F=0.01, w_F=1.5, | |
| I=1, V=0, damping='linear'): | |
| self.m, self.b, self.k = float(m), b, k | |
| self.A_F, self.w_F = A_F, w_F | |
| self.I, self.V = I, V | |
| self.damping = damping | |
| def __call__(self, u, t): | |
| """Right-hand side function defining the ODE.""" | |
| u, v = u # u is array of length 2 holding our [u, v] | |
| if self.damping == 'linear': | |
| b_term = self.b*v | |
| elif self.damping == 'quadratic': | |
| b_term = self.b*np.abs(v)*v | |
| else: | |
| b_term = 0 | |
| return [v, (-b_term - self.k*u + | |
| self.A_F*np.cos(self.w_F*t))/self.m] | |
| def exact(self, t): | |
| # Valid for linear s(u) | |
| k, b, m, A_F, w_F, I, V = self.k, self.b, self.m, \ | |
| self.A_F, self.w_F, self.I, self.V | |
| b_crit = 2*np.sqrt(k*m) | |
| w_e = np.sqrt(k/m) | |
| zeta = b/b_crit | |
| zeta1p = zeta + np.sqrt(zeta**2 - 1) | |
| zeta1m = zeta - np.sqrt(zeta**2 - 1) | |
| zeta2 = np.sqrt(zeta**2 - 1) | |
| if zeta > 1: | |
| # No oscillations | |
| sol1 = (V + w_e*zeta1p*I)/(2*w_e*zeta2)*np.exp(-w_e*zeta1m*t) | |
| sol2 = (V + w_e*zeta1m*I)/(2*w_e*zeta2)*np.exp(-w_e*zeta1p*t) | |
| u_h = sol1 - sol2 | |
| elif zeta == 1: | |
| u_h = (I + (V + w_e*I)*t)*np.exp(-w_e*t) | |
| else: | |
| # Oscillations | |
| A = np.sqrt(I**2 + ((V + zeta*w_e*I)/(w_e*zeta2))**2) | |
| phi = np.arctan((V + zeta*w_e*I)/(I*w_e*zeta2)) | |
| u_h = A*np.exp(-zeta*w_e*t)*np.cos(zeta2*w_e*t - phi) | |
| # Excitation: F=F_0*cos(w_F*t) | |
| # F_0 and w_F must be extracted from F......? | |
| phi_0 = np.arctan(b*w_F/(k - m*w_F**2)) | |
| A_0 = A_F/np.sqrt((k - m*w_F**2)**2 + (b*w_F)**2) | |
| u_p = A_0*np.cos(omega*t - phi_0) | |
| # Test: all special cases... | |
| return u_h + u_p | |
| # NOT FINISHED | |
| def run_solvers_and_plot(solvers, timesteps_per_period=20, | |
| num_periods=1, b=0): | |
| w = 2*np.pi # frequency of undamped free oscillations | |
| P = 2*np.pi/w # duration of one period | |
| dt = P/timesteps_per_period | |
| Nt = num_periods*timesteps_per_period | |
| T = Nt*dt | |
| t_mesh = np.linspace(0, T, Nt+1) | |
| t_fine = np.linspace(0, T, 8*Nt+1) # used for very accurate solution | |
| legends = [] | |
| solver_exact = odespy.RK4(f) | |
| for solver in solvers: | |
| solver.set_initial_condition([solver.users_f.I, 0]) | |
| u, t = solver.solve(t_mesh) | |
| solver_name = 'CrankNicolson' if solver.__class__.__name__ == \ | |
| 'MidpointImplicit' else solver.__class__.__name__ | |
| # Make plots (plot last 10 periods????) | |
| if num_periods <= 80: | |
| plt.figure(1) | |
| if len(t_mesh) <= 50: | |
| plt.plot(t, u[:,0]) # markers by default | |
| else: | |
| plt.plot(t, u[:,0], '-2') # no markers | |
| plt.hold('on') | |
| legends.append(solver_name) | |
| # Compare with exact solution plotted on a very fine mesh | |
| #t_fine = np.linspace(0, T, 10001) | |
| #u_e = solver.users_f.exact(t_fine) | |
| # Compare with RK4 on a much finer mesh | |
| solver_exact.set_initial_condition([solver.users_f.I, 0]) | |
| u_e, t_e = solver_exact.solve(t_fine) | |
| if num_periods < 80: | |
| plt.figure(1) | |
| plt.plot(t_e, u_e[:,0], '-') # avoid markers by spec. line type | |
| legends.append('exact (RK4)') | |
| plt.legend(legends, loc='upper left') | |
| plt.xlabel('t'); plt.ylabel('u') | |
| plt.title('Time step: %g' % dt) | |
| plt.savefig('vib_%d_%d_u.png' % (timesteps_per_period, num_periods)) | |
| plt.savefig('vib_%d_%d_u.pdf' % (timesteps_per_period, num_periods)) | |
| plt.savefig('vib_%d_%d_u.eps' % (timesteps_per_period, num_periods)) | |
| #f = RHS(b=0.4, A_F=1, w_F=2) | |
| f = RHS(b=0.4, A_F=0, w_F=2) | |
| f = RHS(b=0.4, A_F=1, w_F=np.pi) | |
| f = RHS(b=0.4, A_F=20, w_F=2*np.pi) # qualitatively wrong FE, almost ok BE, smaller T | |
| #f = RHS(b=0.4, A_F=20, w_F=0.5*np.pi) # cool, FE almost there, BE good | |
| # Define different sets of experiments | |
| solvers_theta = [ | |
| odespy.ForwardEuler(f), | |
| # Implicit methods must use Newton solver to converge | |
| odespy.BackwardEuler(f, nonlinear_solver='Newton'), | |
| odespy.CrankNicolson(f, nonlinear_solver='Newton'), | |
| ] | |
| solvers_RK = [odespy.RK2(f), odespy.RK4(f)] | |
| solvers_accurate = [odespy.RK4(f), | |
| odespy.CrankNicolson(f, nonlinear_solver='Newton'), | |
| odespy.DormandPrince(f, atol=0.001, rtol=0.02)] | |
| solvers_CN = [odespy.CrankNicolson(f, nonlinear_solver='Newton')] | |
| if __name__ == '__main__': | |
| timesteps_per_period = 20 | |
| solver_collection = 'theta' | |
| num_periods = 1 | |
| try: | |
| # Example: python vib_odespy.py 30 accurate 50 | |
| timesteps_per_period = int(sys.argv[1]) | |
| solver_collection = sys.argv[2] | |
| num_periods = int(sys.argv[3]) | |
| except IndexError: | |
| pass # default values are ok | |
| solvers = eval('solvers_' + solver_collection) # list of solvers | |
| run_solvers_and_plot(solvers, | |
| timesteps_per_period, | |
| num_periods) | |
| plt.show() | |
| raw_input() | |
Xet Storage Details
- Size:
- 5.41 kB
- Xet hash:
- d39e74205965abcc775dc784bf1c2e8c3d5e3139e3b8618bbb8997b80a31fbdd
·
Xet efficiently stores files, intelligently splitting them into unique chunks and accelerating uploads and downloads. More info.