Julia 模拟一个反弹的球?

Julia 模拟一个反弹的球?,julia,physics,differential-equations,differentialequations.jl,Julia,Physics,Differential Equations,Differentialequations.jl,是否可以使用Julia的方程解算器创建一个简单的反弹球模型 我从这个开始: using ODE function bb(t, f) (y, v) = f dy_dt = v dv_dt = -9.81 [dy_dt, dv_dt] end const y0 = 50.0 # height const v0 = 0.0 # velocity const startpos = [y0; v0] ts = 0.

是否可以使用Julia的方程解算器创建一个简单的反弹球模型

我从这个开始:

using ODE

function bb(t, f)
    (y, v) = f
    dy_dt = v
    dv_dt = -9.81
    [dy_dt, dv_dt]
end

const y0 =  50.0             # height
const v0 =   0.0             # velocity
const startpos = [y0; v0]

ts = 0.0:0.25:10             # time span

t, res = ode45(bb, startpos, ts)
生成有用的外观数字:

julia> t
44-element Array{Float64,1}:
  0.0
  0.0551392
  0.25
  0.5
  0.75
  1.0
  ⋮
  8.75
  9.0
  9.25
  9.5
  9.75
 10.0

julia> res
44-element Array{Array{Float64,1},1}:
 [50.0,0.0]
 [49.9851,-0.540915]
 [49.6934,-2.4525]
 [48.7738,-4.905]
 [47.2409,-7.3575]
 ⋮
 [-392.676,-93.195]
 [-416.282,-95.6475]
 [-440.5,-98.1]
但不知何故,当高度为0时,它需要介入,并反转速度。还是我走错了路?

有点老套:

function bb(t, f)
    (y, v) = f
    dy_dt = v
    dv_dt = -9.81*sign(y)
    [dy_dt, dv_dt]
end
在这里,你只需要遵循一个约定,y和-y指的是相同的高度。然后,只需绘制abs(y)即可绘制反弹球的轨迹。

。因为尽管提供了一种新的算法,但无论如何,这些算法显然是最好的选择

第一个链接是说明如何进行事件处理的文档。easy界面使用宏。我首先定义函数

f = @ode_def BallBounce begin
  dy =  v
  dv = -g
end g=9.81
在这里,我展示了如何更好地使用语法,但是您可以直接将函数定义为一个就地更新
f(t,u,du)
(比如Sundials.jl)。接下来定义确定事件发生时间的函数。它可以是任何正函数,并在事件发生时达到零。在这里,我们检查球何时落地,或者何时
y=0
,因此:

function event_f(t,u) # Event when event_f(t,u,k) == 0
  u[1]
end
接下来,您要说明事件发生时要做什么。这里我们要反转速度的符号:

function apply_event!(u,cache)
  u[2] = -u[2]
end
将这些函数放在一起,以使用宏生成回调:

callback = @ode_callback begin
  @ode_event event_f apply_event!
end
现在你像往常一样解决问题。使用
f
和初始条件定义
ODEProblem
,并在时间跨度上调用solve。唯一的额外功能是将回调与解算器一起传递:

u0 = [50.0,0.0]
prob = ODEProblem(f,u0)
tspan = [0;15]
sol = solve(prob,tspan,callback=callback)
然后,我们可以使用绘图配方自动绘制解决方案:

plot(sol)
结果是:

这里有几点需要注意:

  • Differentialsequations.jl将自动使用插值来更安全地检查事件。例如,如果事件发生在某个时间段内,但不是在结束时,Differentialsequations.jl仍会找到它。或多或少的插值点可以作为
    @ode_事件
    宏的选项包括在内

  • Differentialsequations.jl使用寻根方法来磨练事件的时刻。即使自适应解算器步过事件,通过在插值上使用寻根,它也会找到事件的确切时间,从而正确地获得不连续性。你可以在图表中看到,因为球永远不会变成负数

  • 这还可以做很多。你几乎可以用这个做任何事情。例如,让您的ODE在运行过程中改变大小,以模拟具有出生和死亡的细胞群。这是其他解算器包无法做到的

  • 即使具备所有这些功能,速度也不会受到影响


  • 如果您需要在“易用性”界面宏中添加任何额外功能,请告诉我。

    您不能在ODE中这样做,因为这需要事件处理。然而,事件处理是目前最重要的。如果你有兴趣确保Differentialsequations.jl框架能够处理你感兴趣的各种问题,请随意加入。我们心目中的API已经能够处理这一点以及更多的事情,比如改变问题的大小。我的目标是在一周左右的时间内发布。像这样的方法效果不太好,因为它假设时间步长非常小,因此事件“足够接近”时间点。否则会引入大量错误(这里会有一些负值)。这种方法可以完全忽略振荡解上的事件。这就是为什么需要插值。ODE.jl没有很好的插值,这就是为什么在没有大量工作的情况下是不可能实现的。但是,这个特殊的哈克解决方案的误差将比尝试反转速度要小得多。如果ODE解算器在这方面失败,它可能也会在实际的物理潜在问题上失败。哦,等等,我明白你在做什么了。。。但这不是很普遍。您使用的是关于0的完美对称性
    y
    about 0,这在一个简单的示例中起作用。我假设OP真的想计算更复杂的东西。对,它是物理学家的解,而不是程序员的解。这种对称性破解在计算物理中非常常见,在计算物理中,你经常被迫使用周期性边界条件来近似体条件,以获得更精确的相变预测。根据你想做什么,它们在很多情况下都非常有用。@chrisrackaukas不,不是更复杂:)-只是想用编程学点数学。(看完之后,我想知道朱莉娅会怎么做。)