首页 文章

实现数值求解微分方程的初始条件

提问于
浏览
4

想象一下有人在一定的角度下跳下阳台 theta 和速度 v0 (阳台的高度表示为 ystar ) . 在2D中考虑这个问题并考虑拖动,你会得到一个微分方程系统,可以用Runge-Kutta方法求解(我选择显式中点,不确定这个的屠夫 table 是什么) . 我实现了它并且它完美地工作,对于一些给定的初始条件,我得到了移动粒子的轨迹 .

我的问题是我想修复两个初始条件(x轴上的起始点为零,y轴上的起点是 ystar )并确保轨迹通过x轴上的某个点(让我们看看)叫它 xstar ) . 因此,当然存在其他两个初始条件的多种组合,在这种情况下是x方向和y方向上的速度 . 问题是我不知道如何实现它 .

到目前为止我用来解决问题的代码:

1)Runge-Kutta方法的实现

import numpy as np 
import matplotlib.pyplot as plt

def integrate(methode_step, rhs, y0, T, N):
    star = (int(N+1),y0.size)
    y= np.empty(star)
    t0, dt = 0, 1.* T/N
    y[0,...] = y0
    for i in range(0,int(N)):
        y[i+1,...]=methode_step(rhs,y[i,...], t0+i*dt, dt)
    t = np.arange(N+1) * dt
    return t,y

def explicit_midpoint_step(rhs, y0, t0, dt):
    return y0 + dt * rhs(t0+0.5*dt,y0+0.5*dt*rhs(t0,y0))

def explicit_midpoint(rhs,y0,T,N):
    return integrate(explicit_midpoint_step,rhs,y0,T,N)

2)实现微分方程的右侧和nessecery参数

A = 1.9/2.
cw = 0.78
rho = 1.293
g = 9.81

# Mass and referece length
l = 1.95
m = 118

# Position
xstar = 8*l
ystar = 4*l

def rhs(t,y):
    lam = cw * A * rho /(2 * m)
    return np.array([y[1],-lam*y[1]*np.sqrt(y[1]**2+y[3]**2),y[3],-lam*y[3]*np.sqrt(y[1]**2+y[3]**2)-g])

3)用它解决问题

# Parametrize the two dimensional velocity with an angle theta and speed v0

v0 = 30
theta = np.pi/6

v0x = v0 * np.cos(theta)
v0y = v0 * np.sin(theta)

# Initial condintions
z0 = np.array([0, v0x, ystar, v0y])

# Calculate solution
t, z = explicit_midpoint(rhs, z0, 5, 1000)

4)可视化

plt.figure()
plt.plot(0,ystar,"ro")
plt.plot(x,0,"ro")
plt.plot(z[:,0],z[:,1])
plt.grid(True)
plt.xlabel(r"$x$")
plt.ylabel(r"$y$")
plt.show()

要使问题具体化:考虑到这一点,我如何找到 v0theta 的所有可能组合,以便 z[some_element,0]==xstar

我当然尝试了一些东西,主要是蛮力的方法来固定 theta 然后尝试所有可能的速度(在一个有意义的intervall中)但最后不知道如何将得到的数组与所需的结果进行比较......

由于这主要是编码问题,我希望堆栈溢出是寻求帮助的正确位置...

编辑:这里要求的是我尝试从上面解决问题(替换3)和4)..

theta = np.pi/4.
xy = np.zeros((50,1001,2))
z1 = np.zeros((1001,2))
count=0

for v0 in range(0,50):
    v0x = v0 * np.cos(theta)
    v0y = v0 * np.sin(theta)
    z0 = np.array([0, v0x, ystar, v0y])

    # Calculate solution
    t, z = explicit_midpoint(rhs, z0, 5, 1000)    

    if np.around(z[:,0],3).any() == round(xstar,3):
        z1[:,0] = z[:,0]
        z1[:,1] = z[:,2]
        break
    else:
        xy[count,:,0] = z[:,0]
        xy[count,:,1] = z[:,2]
        count+=1


plt.figure()
plt.plot(0,ystar,"ro")
plt.plot(xstar,0,"ro")

for k in range(0,50):    
    plt.plot(xy[k,:,0],xy[k,:,1])

plt.plot(z[:,0],z[:,1])
plt.grid(True)
plt.xlabel(r"$x$")
plt.ylabel(r"$y$")
plt.show()

我'm sure that I' m使用 .any() 函数错误,想法是将 z[:,0] 的值舍入为三位数,然后将它们与 xstar 进行比较,如果匹配则循环应终止并重新启动当前的 z ,如果不是,则应将其保存在另一个中数组然后增加 v0 .

3 回答

  • 1

    编辑2018-07-16

    在这里,我发布了一个纠正的答案,考虑到空中阻力 .

    下面是一个python脚本,用于计算 (v0,theta) 值的集合,以便空气拖动的轨迹在某个时间 t=tstar 通过 (x,y) = (xstar,0) . 我使用没有空气拖曳的轨迹作为初始猜测,并且还猜测 x(tstar)v0 的依赖性进行了第一次改进 . 到达正确 v0 所需的迭代次数通常为3到4.脚本在我的笔记本电脑上以0.99秒结束,包括生成数字的时间 .

    该脚本生成两个图形和一个文本文件 .

    • fig_xdrop_v0_theta.png

    • 黑点表示解决方案集 (v0,theta)

    • 黄线表示参考 (v0,theta) ,如果没有空气阻力,这将是一个解决方案 .

    • fig_traj_sample.png

    • 当从解决方案集中采样 (v0,theta) 时,检查轨迹(蓝色实线)是否通过 (x,y)=(xstar,0) .

    • 黑色虚线表示没有空气阻力作为参考的轨迹 .

    • output.dat

    • 包含 (v0,theta) 的数值数据以及着陆时间 tstar 和查找 v0 所需的迭代次数 .

    这里开始脚本 .

    #!/usr/bin/env python3
    
    import numpy as np
    import scipy.integrate
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    import matplotlib.image as img
    
    mpl.rcParams['lines.linewidth'] = 2
    mpl.rcParams['lines.markeredgewidth'] = 1.0
    mpl.rcParams['axes.formatter.limits'] = (-4,4)
    #mpl.rcParams['axes.formatter.limits'] = (-2,2)
    mpl.rcParams['axes.labelsize'] = 'large'
    mpl.rcParams['xtick.labelsize'] = 'large'
    mpl.rcParams['ytick.labelsize'] = 'large'
    mpl.rcParams['xtick.direction'] = 'out'
    mpl.rcParams['ytick.direction'] = 'out'
    
    
    
    ############################################
    len_ref = 1.95
    xstar = 8.0*len_ref
    ystar = 4.0*len_ref
    g_earth = 9.81
    #
    mass = 118
    area = 1.9/2.
    cw = 0.78
    rho = 1.293
    lam = cw * area * rho /(2.0 * mass)
    ############################################
    ngtheta=51
    theta_min = -0.1*np.pi
    theta_max =  0.4*np.pi
    theta_grid = np.linspace(theta_min, theta_max, ngtheta)
    #
    ngv0=100
    v0min =6.0
    v0max =18.0
    v0_grid=np.linspace(v0min, v0max, ngv0)
    # .. this grid is used for the initial coarse scan by reference trajecotry
    ############################################
    outf=open('output.dat','w')
    print('data file generated: output.dat')
    ###########################################
    
    
    def calc_tstar_ref_and_x_ref_at_tstar_ref(v0, theta, ystar, g_earth):
        '''return the drop time t* and drop point x(t*) of a reference trajectory
        without air drag.
        '''
    
        vx = v0*np.cos(theta)
        vy = v0*np.sin(theta)
        ts_ref = (vy+np.sqrt(vy**2+2.0*g_earth*ystar))/g_earth
        x_ref  = vx*ts_ref 
        return (ts_ref, x_ref)
    
    
    def rhs_drag(yvec, time, g_eath, lamb):
        '''
        dx/dt = v_x
        dy/dt = v_y
        du_x/dt = -lambda v_x sqrt(u_x^2 + u_y^2)
        du_y/dt = -lambda v_y sqrt(u_x^2 + u_y^2) -g
    
        yvec[0] .. x
        yvec[1] .. y
        yvec[2] .. v_x
        yvec[3] .. v_y
        '''
    
        vnorm = (yvec[2]**2+yvec[3]**2)**0.5
        return  [ yvec[2], yvec[3], -lamb*yvec[2]*vnorm, -lamb*yvec[3]*vnorm -g_earth]
    
    
    def try_tstar_drag(v0, theta, ystar, g_earth, lamb, tstar_search_grid):
        '''one trial run to find the drop point x(t*), y(t*) of a trajectory 
        under the air drag.
        '''
    
        tinit=0.0
        tgrid = [tinit]+list(tstar_search_grid)
        yvec_list = scipy.integrate.odeint(rhs_drag,
                                           [0.0, ystar, v0*np.cos(theta), v0*np.sin(theta)],
                                           tgrid, args=(g_earth, lam))
        y_drag = [yvec[1] for yvec in yvec_list]
        x_drag = [yvec[0] for yvec in yvec_list]
    
        if y_drag[0]<0.0:
            ierr=-1
            jtstar=0
            tstar_braket=None
        elif y_drag[-1]>0.0:
            ierr=1
            jtstar=len(y_drag)-1
            tstar_braket=None
        else:
            ierr=0
            for jt in range(len(y_drag)-1):
                if y_drag[jt+1]*y_drag[jt]<=0.0:
                    tstar_braket=[tgrid[jt],tgrid[jt+1]]
                    if abs(y_drag[jt+1])<abs(y_drag[jt]):
                        jtstar = jt+1
                    else:
                        jtstar = jt
                    break
    
        tstar_est = tgrid[jtstar]
        x_drag_at_tstar_est = x_drag[jtstar]
        y_drag_at_tstar_est = y_drag[jtstar]
        return (tstar_est, x_drag_at_tstar_est, y_drag_at_tstar_est, ierr, tstar_braket)
    
    
    def calc_x_drag_at_tstar(v0, theta, ystar, g_earth, lamb, tstar_est,
                             eps_y=1.0e-3, ngt_search=20,
                             rel_range_lower=0.8, rel_range_upper=1.2,
                             num_try=5):
        '''compute the dop point x(t*) of a trajectory under the air drag.
        '''
    
        flg_success=False
        tstar_est_lower=tstar_est*rel_range_lower
        tstar_est_upper=tstar_est*rel_range_upper
        for jtry in range(num_try):
            tstar_search_grid = np.linspace(tstar_est_lower, tstar_est_upper, ngt_search)
            tstar_est, x_drag_at_tstar_est, y_drag_at_tstar_est, ierr, tstar_braket \
                = try_tstar_drag(v0, theta, ystar, g_earth, lamb, tstar_search_grid)
            if ierr==-1:
                tstar_est_upper = tstar_est_lower
                tstar_est_lower = tstar_est_lower*rel_range_lower
            elif ierr==1:
                tstar_est_lower = tstar_est_upper
                tstar_est_upper = tstar_est_upper*rel_range_upper
            else:
                if abs(y_drag_at_tstar_est)<eps_y:
                    flg_success=True
                    break
                else:
                    tstar_est_lower=tstar_braket[0]
                    tstar_est_upper=tstar_braket[1]
    
        return (tstar_est, x_drag_at_tstar_est, y_drag_at_tstar_est, flg_success)
    
    
    def find_v0(xstar, v0_est, theta, ystar, g_earth, lamb, tstar_est,
                eps_x=1.0e-3, num_try=6):
       '''solve for v0 so that x(t*)==x*.
       '''
    
       flg_success=False
       v0_hist=[]
       x_drag_at_tstar_hist=[]
       jtry_end=None
       for jtry in range(num_try):
           tstar_est, x_drag_at_tstar_est, y_drag_at_tstar_est, flg_success_x_drag \
               = calc_x_drag_at_tstar(v0_est, theta, ystar, g_earth, lamb, tstar_est)
           v0_hist.append(v0_est)
           x_drag_at_tstar_hist.append(x_drag_at_tstar_est)
           if not flg_success_x_drag:
               break
           elif abs(x_drag_at_tstar_est-xstar)<eps_x: 
               flg_success=True
               jtry_end=jtry
               break
           else:
               # adjust v0
               # better if tstar_est is also adjusted, but maybe that is too much.
               if len(v0_hist)<2:
                   # This is the first run. Use the analytical expression of
                   # dx(tstar)/dv0 of  the refernece trajectory
                   dx = xstar - x_drag_at_tstar_est
                   dv0 = dx/(tstar_est*np.cos(theta))
                   v0_est += dv0
               else:
                   # use linear interpolation
                   v0_est = v0_hist[-2] \
                            + (v0_hist[-1]-v0_hist[-2]) \
                            *(xstar                 -x_drag_at_tstar_hist[-2])\
                            /(x_drag_at_tstar_hist[-1]-x_drag_at_tstar_hist[-2])
    
       return (v0_est, tstar_est, flg_success, jtry_end)        
    
    
    # make a reference table of t* and x(t*) of a trajectory without air drag
    # as a function of v0 and theta.
    tstar_ref=np.empty((ngtheta,ngv0))
    xdrop_ref=np.empty((ngtheta,ngv0))
    for j1 in range(ngtheta):
        for j2 in range(ngv0):
            tt, xx = calc_tstar_ref_and_x_ref_at_tstar_ref(v0_grid[j2], theta_grid[j1], ystar, g_earth)
            tstar_ref[j1,j2] = tt
            xdrop_ref[j1,j2] = xx
    
    # make an estimate of v0 and t* of a dragged trajectory for each theta 
    # based on the reference trajectroy's landing position xdrop_ref.
    tstar_est=np.empty((ngtheta,))
    v0_est=np.empty((ngtheta,))
    v0_est[:]=-1.0
    # .. null value
    for j1 in range(ngtheta):
        for j2 in range(ngv0-1):
            if (xdrop_ref[j1,j2+1]-xstar)*(xdrop_ref[j1,j2]-xstar)<=0.0:
                tstar_est[j1] = tstar_ref[j1,j2]
                # .. lazy
                v0_est[j1] \
                    = v0_grid[j2] \
                    + (v0_grid[j2+1]-v0_grid[j2])\
                    *(xstar-xdrop_ref[j1,j2])/(xdrop_ref[j1,j2+1]-xdrop_ref[j1,j2])
                # .. linear interpolation
                break
    
    print('compute v0 for each theta under air drag..')
    # compute v0 for each theta under air drag
    theta_sol_list=[]
    tstar_sol_list=[]
    v0_sol_list=[]
    outf.write('#  theta  v0  tstar  numiter_v0\n')
    for j1 in range(ngtheta):
        if v0_est[j1]>0.0:
            v0, tstar, flg_success, jtry_end \
                = find_v0(xstar, v0_est[j1], theta_grid[j1], ystar, g_earth, lam, tstar_est[j1])
            if flg_success:
                theta_sol_list.append(theta_grid[j1])
                v0_sol_list.append(v0)
                tstar_sol_list.append(tstar)
                outf.write('%26.16e  %26.16e %26.16e %10i\n'
                           %(theta_grid[j1], v0, tstar, jtry_end+1))
    
    theta_sol = np.array(theta_sol_list)            
    v0_sol    = np.array(v0_sol_list)            
    tstar_sol = np.array(tstar_sol_list)            
    
    
    
    ### Check a sample 
    jsample=np.size(v0_sol)//3
    theta_sol_sample= theta_sol[jsample]
    v0_sol_sample   = v0_sol[jsample]
    tstar_sol_sample= tstar_sol[jsample]
    
    ngt_chk = 50
    tgrid  = np.linspace(0.0, tstar_sol_sample, ngt_chk)
    
    yvec_list = scipy.integrate.odeint(rhs_drag,
                                       [0.0, ystar,
                                        v0_sol_sample*np.cos(theta_sol_sample),
                                        v0_sol_sample*np.sin(theta_sol_sample)],
                                       tgrid, args=(g_earth, lam))
    y_drag_sol_sample = [yvec[1] for yvec in yvec_list]
    x_drag_sol_sample = [yvec[0] for yvec in yvec_list]
    
    # compute also the trajectory without drag starting form the same initial
    # condiiton by setting lambda=0.
    yvec_list = scipy.integrate.odeint(rhs_drag,
                                       [0.0, ystar,
                                        v0_sol_sample*np.cos(theta_sol_sample),
                                        v0_sol_sample*np.sin(theta_sol_sample)],
                                       tgrid, args=(g_earth, 0.0))
    y_ref_sample = [yvec[1] for yvec in yvec_list]
    x_ref_sample = [yvec[0] for yvec in yvec_list]
    
    
    #######################################################################
    # canvas setting 
    #######################################################################
    f_size   = (8,5)
    #
    a1_left   = 0.15
    a1_bottom  = 0.15
    a1_width  = 0.65
    a1_height = 0.80
    #
    hspace=0.02
    #
    ac_left   = a1_left+a1_width+hspace
    ac_bottom = a1_bottom
    ac_width  = 0.03
    ac_height = a1_height
    ###########################################
    
    
    
    ############################################
    # plot 
    ############################################
    
    #------------------------------------------------
    print('plotting the solution..')
    fig1=plt.figure(figsize=f_size)
    ax1 =plt.axes([a1_left, a1_bottom, a1_width, a1_height], axisbg='w')
    
    im1=img.NonUniformImage(ax1,
                                interpolation='bilinear', \
                                cmap=mpl.cm.Blues, \
                                norm=mpl.colors.Normalize(vmin=0.0,
                                                              vmax=np.max(xdrop_ref), clip=True)) 
    im1.set_data(v0_grid, theta_grid/np.pi, xdrop_ref )
    ax1.images.append(im1)
    plt.contour(v0_grid, theta_grid/np.pi, xdrop_ref, [xstar], colors='y')
    plt.plot(v0_sol, theta_sol/np.pi, 'ok', lw=4, label='Init Cond with Drag')
    plt.legend(loc='lower left')
    
    plt.xlabel(r'Initial Velocity $v_0$', fontsize=18)
    plt.ylabel(r'Angle of Projection $\theta/\pi$', fontsize=18)
    plt.yticks([-0.50, -0.25, 0.0, 0.25, 0.50])
    ax1.set_xlim([v0min, v0max])
    ax1.set_ylim([theta_min/np.pi, theta_max/np.pi])
    
    axc =plt.axes([ac_left, ac_bottom, ac_width, ac_height], axisbg='w')
    mpl.colorbar.Colorbar(axc,im1)
    axc.set_ylabel('Distance from Blacony without Drag')
    # 'Distance from Blacony $x(t^*)$'
    
    plt.savefig('fig_xdrop_v0_theta.png')
    print('figure file genereated: fig_xdrop_v0_theta.png')
    plt.close()
    
    
    #------------------------------------------------
    print('plotting a sample trajectory..')
    fig1=plt.figure(figsize=f_size)
    ax1 =plt.axes([a1_left, a1_bottom, a1_width, a1_height], axisbg='w')
    plt.plot(x_drag_sol_sample, y_drag_sol_sample, '-b', lw=2, label='with drag')
    plt.plot(x_ref_sample, y_ref_sample, '--k', lw=2, label='without drag')
    plt.axvline(x=xstar, color=[0.3, 0.3, 0.3], lw=1.0)
    plt.axhline(y=0.0, color=[0.3, 0.3, 0.3], lw=1.0)
    plt.legend()
    plt.text(0.1*xstar, 0.6*ystar,
             r'$v_0=%5.2f$'%(v0_sol_sample)+'\n'+r'$\theta=%5.2f \pi$'%(theta_sol_sample/np.pi),
             fontsize=18)
    plt.text(xstar, 0.5*ystar, 'xstar', fontsize=18)
    
    plt.xlabel(r'Horizontal Distance $x$', fontsize=18)
    plt.ylabel(r'Height $y$', fontsize=18)
    ax1.set_xlim([0.0,        1.5*xstar])
    ax1.set_ylim([-0.1*ystar, 1.5*ystar])
    
    plt.savefig('fig_traj_sample.png')
    print('figure file genereated: fig_traj_sample.png')
    plt.close()
    
    outf.close()
    

    这是图 fig_xdrop_v0_theta.png .

    fig_xdrop_v0_theta.png

    这是图 fig_traj_sample.png .

    fig_traj_sample.png


    编辑2018-07-15

    我意识到我忽略了这个问题考虑了空气阻力 . 真可惜我 . 所以,我的答案不正确 . 我担心自己删除我的答案看起来像隐瞒了一个错误,我暂时将其留在下面 . 如果人们认为这是一个令人讨厌的错误答案,我就是O.K.有人删除它 .


    微分方程实际上可以手工求解,并且它不需要太多的计算资源来绘制人从地面上的阳台到达的距离作为初始速度 v0 和角度 theta 的函数 . 然后,您可以从此数据表中选择 (v0,theta) 条件 distance_from_balcony_on_the_ground(v0,theta) = xstar .

    让我们分别在 tx(t)y(t) 写下人的水平坐标和垂直坐标 . 我觉得你带了 x=0 建筑物的墙壁和 y=0 作为地面,我也在这里这样做 . 假设人在 t 时的水平和垂直速度分别为 v_x(t)v_y(t) . t=0 的初始条件为

    x(0) = 0
    y(0) = ystar
    v_x(0) = v0 cos theta
    v_y(0) = v0 sin theta
    

    你正在解决的牛顿公式是,

    dx/dt = v_x  .. (1)
    dy/dt = v_y  .. (2)
    m d v_x /dt = 0  .. (3)
    m d v_y /dt = -m g  .. (4)
    

    其中 m 是该人的质量, g 是我不知道英文名称的常数,但我们都知道它是什么 .

    来自eq . (3),

    v_x(t) = v_x(0) = v0 cos theta.
    

    与eq . 一起使用(1),

    x(t) = x(0) + \int_0^t dt' v_x(t') = t v0 cos theta,
    

    我们也使用了初始条件 . \int_0^t 表示从 0t 的积分 .

    来自eq . (4),

    v_y(t)
    = v_y (0) + \int_0^t dt' (-g) 
    = v0 sin theta -g t,
    

    我们在哪里使用了初始条件 . 与eq . 一起使用(3)并且还使用初始条件,

    y(t)
    = y(0) + \int_0^t dt' v_y(t')
    = ystar + t v0 sin theta -t^2 (g/2).
    

    其中 t^2 表示 t 平方 . 从 y(t) 的表达式中,我们可以得到该人撞击地面的时间 tstar . 也就是说, y(tstar) =0 . 该等式可以通过二次公式(或类似的名称)来解决

    tstar = (v0 sin theta + sqrt((v0 sin theta)^2 + 2g ystar)/g,
    

    我在哪里使用了一个条件 tstar>0 . 现在我们知道当他撞到地面时所达到的阳台的距离为 x(tstar) . 使用上面的 x(t) 表达式,

    x(tstar) = (v0 cos theta) (v0 sin theta + sqrt((v0 sin theta)^2 + 2g ystar))/g.
      .. (5)
    

    实际上 x(tstar) 取决于 v0theta 以及 gystar . 您将 gystar 作为常量,并且您希望找到所有 (v0,theta) ,使 x(tstar) = xstar 为给定的 xstar 值 .

    由于方程式的右侧(5)可以廉价计算,你可以在这个2D网格上为 v0theta 设置网格并计算 xstar . 然后,您可以看到 (v0,theta) 谎言的解决方案集的大致位置 . 如果您需要精确的解决方案,您可以从该数据表中选取一个包含解决方案的段 .

    下面是一个演示这个想法的python脚本 .

    我还附上了这个脚本生成的图形 . 黄色曲线是解决方案集 (v0,theta) ,这样当你设置 xstar = 8.0*1.95ystar=4.0*1.95 时,该人在墙上 xstar 处于地面 . 蓝色坐标表示 x(tstar) ,即人们从阳台水平跳跃的距离 . 请注意,在给定的 v0 (高于阈值aruond v0=9.9 )时,有两个 theta 值(人物投射自己的两个方向)到达目标点 (x,y) = (xstar,0) . theta 值的较小分支可以是负的,这意味着只要初始速度足够高,人就可以向下跳到达目标点 .

    该脚本还会生成一个数据文件 output.dat ,其中包含解决方案封闭的段 .

    #!/usr/bin/python3
    
    import numpy as np
    import matplotlib as mpl
    import matplotlib.pyplot as plt
    import matplotlib.image as img
    
    mpl.rcParams['lines.linewidth'] = 2
    mpl.rcParams['lines.markeredgewidth'] = 1.0
    mpl.rcParams['axes.formatter.limits'] = (-4,4)
    #mpl.rcParams['axes.formatter.limits'] = (-2,2)
    mpl.rcParams['axes.labelsize'] = 'large'
    mpl.rcParams['xtick.labelsize'] = 'large'
    mpl.rcParams['ytick.labelsize'] = 'large'
    mpl.rcParams['xtick.direction'] = 'out'
    mpl.rcParams['ytick.direction'] = 'out'
    
    
    ############################################
    len_ref = 1.95
    xstar = 8.0*len_ref
    ystar = 4.0*len_ref
    g_earth = 9.81
    ############################################
    ngv0=100
    v0min =0.0
    v0max =20.0
    v0_grid=np.linspace(v0min, v0max, ngv0)
    ############################################
    outf=open('output.dat','w')
    print('data file generated: output.dat')
    ###########################################
    
    def x_at_tstar(v0, theta, ystar, g_earth):
        vx = v0*np.cos(theta)
        vy = v0*np.sin(theta)
        return (vy+np.sqrt(vy**2+2.0*g_earth*ystar))*vx/g_earth
    
    ngtheta=100
    theta_min = -0.5*np.pi
    theta_max =  0.5*np.pi
    theta_grid = np.linspace(theta_min, theta_max, ngtheta)
    xdrop=np.empty((ngv0,ngtheta))
    # x(t*) as a function of v0 and theta.
    for j1 in range(ngv0):
        for j2 in range(ngtheta):
            xdrop[j1,j2] = x_at_tstar(v0_grid[j1], theta_grid[j2], ystar, g_earth)
    
    outf.write('# domain [theta_lower, theta_upper] that encloses the solution\n')        
    outf.write('# theta such that x_at_tstart(v0,theta, ystart, g_earth)=xstar\n')        
    outf.write('# v0  theta_lower  theta_upper  x_lower  x_upper\n')
    for j1 in range(ngv0):
        for j2 in range(ngtheta-1):
           if (xdrop[j1,j2+1]-xstar)*(xdrop[j1,j2]-xstar)<=0.0:
               outf.write('%26.16e %26.16e %26.16e %26.16e %26.16e\n'
                              %(v0_grid[j1], theta_grid[j2], theta_grid[j2+1],
                                    xdrop[j1,j2], xdrop[j1,j2+1]))
    print('See output.dat for the segments enclosing solutions.')
    print('You can hunt further for precise solutions using this data.')
    
    
    
    #######################################################################
    # canvas setting 
    #######################################################################
    f_size   = (8,5)
    #
    a1_left   = 0.15
    a1_bottom  = 0.15
    a1_width  = 0.65
    a1_height = 0.80
    #
    hspace=0.02
    #
    ac_left   = a1_left+a1_width+hspace
    ac_bottom = a1_bottom
    ac_width  = 0.03
    ac_height = a1_height
    ###########################################
    
    
    
    ############################################
    # plot 
    ############################################
    
    print('plotting..')
    fig1=plt.figure(figsize=f_size)
    ax1 =plt.axes([a1_left, a1_bottom, a1_width, a1_height], axisbg='w')
    
    im1=img.NonUniformImage(ax1,
                                interpolation='bilinear', \
                                cmap=mpl.cm.Blues, \
                                norm=mpl.colors.Normalize(vmin=0.0,
                                                              vmax=np.max(xdrop), clip=True)) 
    im1.set_data(v0_grid, theta_grid/np.pi, np.transpose(xdrop))
    ax1.images.append(im1)
    plt.contour(v0_grid, theta_grid/np.pi, np.transpose(xdrop), [xstar], colors='y')
    
    plt.xlabel(r'Initial Velocity $v_0$', fontsize=18)
    plt.ylabel(r'Angle of Projection $\theta/\pi$', fontsize=18)
    plt.yticks([-0.50, -0.25, 0.0, 0.25, 0.50])
    ax1.set_xlim([v0min, v0max])
    ax1.set_ylim([theta_min/np.pi, theta_max/np.pi])
    
    axc =plt.axes([ac_left, ac_bottom, ac_width, ac_height], axisbg='w')
    mpl.colorbar.Colorbar(axc,im1)
    # 'Distance from Blacony $x(t^*)$'
    
    plt.savefig('fig_xdrop_v0_theta.png')
    print('figure file genereated: fig_xdrop_v0_theta.png')
    plt.close()
    
    
    
    outf.close()
    

    fig_xdrop_v0_theta.png

  • 1

    所以经过一些尝试后,我找到了一种方法来实现我想要的......这是我在首发帖子中提到的蛮力方法,但至少现在它有效......

    这个想法很简单:定义一个函数 find_v0 ,它找到给定的 theta a v0 . 在这个函数中,你取一个 v0 的起始值(我选择8但这只是我的猜测),然后取起始值并检查 difference 函数与 (xstar,0) 有多远的距离 . 在这种情况下的有趣点可以通过将x轴上大于 xstar 的所有点设置为零(及其相应的y值),然后使用 trim_zeros 修剪所有零来确定,现在是对应的最后一个元素期望的输出 . 如果差函数的输出小于临界值(在我的情况下为0.1),则传递当前 v0 ,如果不是,则将其增加 0.01 并再次执行相同的操作 .

    这个代码看起来像这样(再次替换3)和4)):

    th = np.linspace(0,np.pi/3,100)
    
    def find_v0(theta):
        v0=8
        while(True):
            v0x = v0 * np.cos(theta)
            v0y = v0 * np.sin(theta)
            z0 = np.array([0, v0x, ystar, v0y])
    
            # Calculate solution
            t, z = explicit_midpoint(rhs, z0, 5, 1000)    
    
            for k in range(1001):
                if z[k,0] > xstar: 
                    z[k,0] = 0
                    z[k,2] = 0
    
            x = np.trim_zeros(z[:,0])
            y = np.trim_zeros(z[:,2])
    
            diff = difference(x[-1],y[-1])
    
            if diff < 0.1:
                break
            else: v0+=0.01
        return v0#,x,y[0:]
    
    v0 = np.zeros_like(th)
    
    from tqdm import tqdm
    
    count=0
    for k in tqdm(th):
        v0[count] = find_v0(k)
        count+=1
    
    v0_interp = interpolate.interp1d(th,v0)
    
    plt.figure()
    plt.plot(th,v0_interp(th),"g")
    plt.grid(True)
    plt.xlabel(r"$\theta$")
    plt.ylabel(r"$v_0$")
    plt.show()
    

    这件事的问题在于它需要永远计算(当前设置大约5-6分钟) . 如果有人有一些提示如何改进代码以获得更快或有不同的方法,它仍然会受到赞赏 .

  • 1

    假设x方向的速度永远不会降到零,你可以将x作为独立参数而不是时间 . 然后状态向量是时间,位置,速度,并且该状态空间中的向量场被缩放,使得vx分量始终为1.然后从零到xstar进行积分以计算轨迹符合xstar的状态(近似),如x-值 .

    def derivs(u,x):
        t,x,y,vx,vy = u
        v = hypot(vx,vy)
        ax = -lam*v*vx
        ay = -lam*v*vy - g
        return [ 1/vx, 1, vy/vx, ax/vx, ay/vx ]
    
    odeint(derivs, [0, x0, y0, vx0, vy0], [0, xstar])
    

    或者使用您自己的集成方法 . 我使用odeint作为显示的文档界面如何在集成中使用此衍生函数 .

    得到的时间和y值可能是极端的

相关问题