示例#1
0
def test_EulerCromer_1dof():
    """Plain u'' + u = 0."""
    solver = odespy.EulerCromer(lambda v, t: [-v[1], v[0]])
    #solver = odespy.EulerCromer(lambda u, t: [-u[1], u[0]])
    solver.set_initial_condition([0, 1])
    P = 2*np.pi
    N = 60
    dt = P/N
    num_periods = 8
    T = num_periods*P
    time_points = np.linspace(0, T, num_periods*N+1)
    u, t = solver.solve(time_points)
    x = u[:,1]
    v = u[:,0]
    x_exact = lambda t: np.cos(t)
    x_e = x_exact(t)
    #plot(t, x, t, x_e, legend=('EC', 'exact'))
    print('Testing EulerCromer')
    # Test difference in final value
    if N == 60:
        diff_exact = 0.0014700112828
        diff_EC = abs(x[-1] - x_e[-1])
        tol = 1E-14
        assert abs(diff_exact - diff_EC) < tol, \
               'diff_exact=%g, diff_EulerCromer=%g' % (diff_exact, diff_EC)
        print('...ok')
示例#2
0
def simulate(
    beta=0.9,
    Theta=30,
    epsilon=0,
    num_periods=6,
    time_steps_per_period=60,
    plot=True,
    ):
    from math import sin, cos, pi
    Theta = Theta*np.pi/180 #convert to radians
    #Initial position and velocity
    #(we order the equations such that Euler-Cromer in odespy
    #can be used, i.e., vx, x, vy, y)
    ic = [0,                       #x'=vx
          (1 + epsilon)*sin(Theta),  #x
          0,                       #y'=vy
          1 - (1 + epsilon)*cos(Theta), #y
          ]

    def f(u, t, beta):
        vx, x, vy, y = u
        L = np.sqrt(x**2 + (y-1)**2)
        h = beta/(1-beta)*(1- beta/L)    #help factor
        return [-h*x, vx, -h*(y-1) - beta, vy]

    #Non-elastic pendulum (scaled similarly in the limit beta=1)
    #Solution Theta*cos(t)
    P = 2*pi
    dt = P/time_steps_per_period
    T = num_periods*P
    omega = 2*pi/P
    time_points = np.linspace(
        0, T, num_periods*time_steps_per_period+1)
    solver = odespy.EulerCromer(f, f_args=(beta,))
    solver.set_initial_condition(ic)
    u, t = solver.solve(time_points)
    x = u[:,1]
    y = u[:,3]
    theta = np.arctan(x/(1-y))

    if plot:
        plt.figure()
        plt.plot(x, y, 'b-', title='Pendulum motion',
                 daspect=[1,1,1], daspectmode='equal',
                 axis=[x.min(), x.max(), 1.3*y.min(), 1])
        plt.savefig('tmp_xy.png')
        plt.savefig('tmp_xy.pdf')
        #plot theta in degrees
        plt.figure()
        plt.plot(t, theta*180/np.pi, 'b-',
                 title='Angular displacement in degrees')
        plt.savefig('tmp_theta.png')
        plt.savefig('tmp_theta.pdf')
        if abs(Theta) < 10*pi/180:
            #compare theta and theta_e for small angles (< 10 degrees)
            theta_e = Theta*np.cos(omega*t) #non-elastic scaled sol.
            plt.figure()
            plt.plot(t, theta, t, theta_e,
                     legend=['theta elastic', 'theta non-elastic'],
                     title='Elastic vs non-elastic pendulum, '\
                            'beta=%g' % beta)
            plt.savefig('tmp_compare.png')
            plt.savefig('tmp_compare.pdf')
        #Plot y vs x (the real physical motion)
    return x, y, theta, t
示例#3
0

def f(u, t, m, k, L0):
    g = 9.81
    vx, x, vy, y = u
    # mv' = -k*s*n + m*g*j, n: normal vector along the pendulum
    L = np.sqrt(x**2 + (y - L0)**2)
    s = L - L0
    nx = x / L
    ny = (y - L0) / L
    #print 't=%g vx=%5.2f vy=%5.2f x=%5.2f, y=%5.2f, Fx=%5.2f, Fy=%5.2f' % (t, vx, vy, x, y, -k/m*s*nx, -k/m*s*ny - g)
    #print 'k=%g, s=%5.2g, ny=%5.2f, k/m*s*ny=%g, k*s*ny/m=%g' % (k,s,ny,k/m*s*ny,k*s*ny/m)
    return [-k / m * s * nx, vx, -k / m * s * ny - g, vy]


solver = odespy.EulerCromer(f, f_args=(m, k, L0))
solver.set_initial_condition([0, x0, 0, y0])
# First test: vertical pendulum doing harmonic vertical motion, first
# at rest, then slightly out of equilibrium
# k and m should balance

# For large k, this is theta'' + g/L0*sin(theta) = 0, so L0=g
# implies theta'' + theta = 0 equation with theta0*cos(t) as solution
P = 2 * np.pi
N = 60
dt = P / N
num_periods = 6
T = num_periods * P
time_points = np.linspace(0, T, num_periods * N + 1)
u, t = solver.solve(time_points)
x = u[:, 1]
示例#4
0
        plt.savefig('vib_%d_%d_a.png' % (timesteps_per_period, num_periods))

# 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')]
solvers_EC = [odespy.EulerCromer(f)]

if __name__ == '__main__':
    # Default values
    timesteps_per_period = 20
    solver_collection = 'theta'
    num_periods = 1
    # Override from command line
    try:
        # Example: python vib_undamped_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
示例#5
0
import odespy
from numpy import *
from matplotlib.pyplot import *


def f(u, t):
    omega, theta = u
    return [-c * sin(theta), omega]


c = 1
Theta0_degrees = 30

solver = odespy.EulerCromer(f)
Theta0 = Theta0_degrees * pi / 180
solver.set_initial_condition([0, Theta0])
# Solve for num_periods periods using formulas for small theta
freq = sqrt(c)  # frequency of oscillations
period = 2 * pi / freq  # one period
N = 40  # intervals per period
dt = period / N  # time step
num_periods = 10
T = num_periods * period  # total simulation time

time_points = linspace(0, T, num_periods * N + 1)
u, t = solver.solve(time_points)

# Extract components and plot theta
theta = u[:, 1]
omega = u[:, 0]
theta_linear = lambda t: Theta0 * cos(sqrt(c) * t)
示例#6
0
def run_solver_and_plot(solver,
                        timesteps_per_period=20,
                        num_periods=1,
                        I=1,
                        w=2 * np.pi):
    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)

    solver.set(f_kwargs={'w': w})
    solver.set_initial_condition([0, I])
    u, t = solver.solve(t_mesh)

    from vib_undamped import solver
    u2, t2 = solver(I, w, dt, T)

    plt.plot(t, u[:, 1], 'r-', t2, u2, 'b-')
    plt.legend(['Euler-Cromer', '2nd-order ODE'])
    plt.xlabel('t')
    plt.ylabel('u')
    plt.savefig('tmp1.png')
    plt.savefig('tmp1.pdf')


run_solver_and_plot(odespy.EulerCromer(f),
                    timesteps_per_period=20,
                    num_periods=9)
raw_input()