You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

Julia微分方程求解器中时间跨度百分比的监测方法

在DifferentialEquations.jl中跟踪模拟进度

核心思路:使用回调函数(Callbacks)

不要在dydt函数内添加打印逻辑——自适应步长求解器会频繁调用dydt,导致输出爆炸。DifferentialEquations.jl提供的回调机制,可以在特定时间点或满足条件时执行自定义逻辑,完美适配进度提示需求。

方法1:预设时间点触发(PresetTimeCallback)

适合固定百分比间隔的场景,提前计算所有进度节点的时间,到达时触发提示:

using DifferentialEquations

# 定义模拟参数
t_start, t_end = 0.0, 10e4
total_duration = t_end - t_start
# 生成1%到100%的进度时间点(跳过0%)
progress_times = range(t_start, t_end, length=101)[2:end]

# 定义进度回调函数
function progress_notify(u, t, integrator)
    progress_percent = round((t - t_start)/total_duration * 100, digits=1)
    println("完成进度:$progress_percent% | 当前时间:$t")
    return nothing
end

# 创建预设时间回调
progress_cb = PresetTimeCallback(progress_times, progress_notify)

# 定义你的ODE问题(示例)
function dydt(du, u, p, t)
    du[1] = -0.1 * u[1]  # 示例微分方程
end

u0 = [1.0]
prob = ODEProblem(dydt, u0, (t_start, t_end))

# 带回调求解
sol = solve(prob, Tsit5(), callback=progress_cb)

方法2:动态条件触发(DiscreteCallback)

更灵活,适合自适应步长下避免跳过进度节点的场景,动态跟踪下一个进度目标:

using DifferentialEquations

# 定义进度跟踪器(用mutable struct保存状态)
mutable struct ProgressTracker
    next_target_percent::Float64
    total_duration::Float64
end

# 回调触发条件:当前进度达到下一个目标百分比
function progress_condition(u, t, integrator)
    tracker = integrator.p.progress_tracker
    current_percent = (t - integrator.tspan[1])/tracker.total_duration * 100
    return current_percent >= tracker.next_target_percent
end

# 触发后的动作:打印进度,更新下一个目标
function progress_action!(integrator)
    tracker = integrator.p.progress_tracker
    println("完成进度:$(tracker.next_target_percent)% | 当前时间:$(integrator.t)")
    tracker.next_target_percent += 1.0
    # 进度到100%后停止触发
    if tracker.next_target_percent > 100.0
        remove_callback!(integrator, integrator.callback)
    end
    return nothing
end

# 初始化参数(包含进度跟踪器)
t_start, t_end = 0.0, 10e4
p = (
    # 你的其他模型参数
    model_param=0.1,
    progress_tracker=ProgressTracker(1.0, t_end - t_start)
)

# 创建离散回调
progress_cb = DiscreteCallback(progress_condition, progress_action!)

# 定义ODE问题
function dydt(du, u, p, t)
    du[1] = -p.model_param * u[1]
end

u0 = [1.0]
prob = ODEProblem(dydt, u0, (t_start, t_end), p)

# 求解
sol = solve(prob, Tsit5(), callback=progress_cb)

方法3:美观进度条(搭配ProgressMeter.jl)

如果不想打印大量文本,可以用ProgressMeter.jl生成动态进度条,更整洁:

using DifferentialEquations, ProgressMeter

t_start, t_end = 0.0, 10e4
total_duration = t_end - t_start

# 初始化进度条
progress_bar = Progress(100, "模拟进行中:")

# 进度更新函数
function update_progress!(integrator)
    current_percent = (integrator.t - t_start)/total_duration * 100
    update!(progress_bar, round(Int, current_percent))
    return nothing
end

# 用PeriodicCallback定期更新(比如每100时间单位更新一次)
progress_cb = PeriodicCallback(update_progress!, 100.0)

# 定义并求解问题
function dydt(du, u, p, t)
    du[1] = -0.1 * u[1]
end

u0 = [1.0]
prob = ODEProblem(dydt, u0, (t_start, t_end))
sol = solve(prob, Tsit5(), callback=progress_cb)

关键优势

  • 避免dydt函数内的冗余输出:回调仅在满足条件时执行,不会随求解器的内部调用频繁触发
  • 适配自适应步长:无论是固定时间点还是动态条件,都能准确跟踪进度
  • 可扩展性:回调逻辑可以轻松修改,比如写入日志、保存中间结果等

内容的提问来源于stack exchange,提问作者Prometeu

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.17 18:55:23