在加速器控制室里,调机任务过去都是一个个脚本:有人把某种算法接到某个问题上,把进度曲线再画一遍(这类代码枯燥,但运行时确实需要盯着看),运行起来以后又没有办法干净地暂停,到了下一个任务就再写一个脚本。2021 年我在 SLAC 开始写 Badger,目的就是把这些事都放进一个程序:选一台机器和几个旋钮(knob),指定要看的读数,挑一种算法,按下运行按钮。我主持它的开发到 2025 年,并与 DESY 和 BNL 的同事一起写了介绍它的 IPAC'22 文章。
- 7+采用它的实验室,分布在美国和欧洲
- 15 分钟ESRF 用 Badger 里的 TuRBO 调束流寿命所需的时间,约为他们逐个旋钮扫描脚本的七分之一
- 20 到 30 分钟SLAC 团队在 LCLS 和 LCLS-II 上把注入器两个方向的发射度都减半所用的时间
环境与例程
以 LCLS 为例。我在 2021 年为它写的环境(environment,Badger 里描述一台机器的对象)里有几十块可以移动的磁铁,以及 FEL 脉冲能量和束斑尺寸这样的读数,机器只在这里描述一次。例程(routine)则从环境里挑出几个旋钮和一两个读数,设好范围,加上一种算法,然后保存下来,下次就只需按一个按钮。环境之下还有一层接口(interface),它是唯一与控制系统(EPICS,DOOCS 或 Tango)打交道的代码,玩具问题(toy problem)可以没有这一层。之所以这样分层,是由于运行人员经常要对例程做一点小改动,而这种改动不应当要求任何人去打开环境的代码。
最初 Badger 有自己的算法插件,要通过一个扩展(extension)才能用到 Xopt。2023 年 12 月发布 1.0 时,我把核心重写了一遍,此后每一次运行都由 Xopt 驱动。Xopt 是 SLAC 另一些同事主导的库,算法(其中包括 TuRBO)都在它那里,下一个点也由它提出;Badger 负责把这个点送到机器上,把读数取回来,并把每一步都留在屏幕上和磁盘里。

主窗口
大多数人是通过下面这个窗口认识 Badger 的,其中有几处是我后来陆续加上的。从 2023 年起,正在运行的优化每秒写一次磁盘,程序崩溃也不会把它一起带走。2025 年初发布 1.3.0 时我重写了图形界面,并去掉了数据库:每次运行现在是一个 YAML 文件,按日期放在各自的文件夹里,用任何编辑器都能读。优化运行到一半时,也可以再加一个目标函数(objective)或约束(constraint)。

ESRF 的束流寿命
Badger 最有用的几次运行,有不少是在别的实验室的控制室里做的。ESRF 和 DESY 先在各自的储存环上试过极值搜索(extremum seeking),发现它很难调,之后才换成 Badger。用他们自己的话说,ESRF 的 Tango 接口「大部分是照抄现成的 Badger 例子」,改两行代码就能在储存环和他们的模拟器之间切换,机器时间也没有花在调试上。整个工作都是 ESRF 的团队做的,我写了他们那篇 ICALEPCS'23 文章里关于 Badger 的一节。

他们要调的是储存环的束流寿命。那里的一个旋钮会按同一种模式同时移动所有六极铁(例如让全部聚焦六极铁沿环按余弦变化),他们保留了 24 个六极铁旋钮和 4 个八极铁旋钮一起调,目标函数是环上各束损监测器的总损失。他们原来的工具是一个脚本,每次扫描一个旋钮,拟合一条抛物线,保留最好的幅度,再扫下一个。换成 Badger 之后,单纯形法(simplex)和置信上界(Upper Confidence Bound,UCB)大约半小时收敛,Xopt 的 TuRBO 收敛得更快,而且过程中束损的起伏最小。最好的一组设置给出了 41 ± 11 小时的 Touschek 寿命记录;当随机的六极铁误差把寿命降到 20 小时时,TuRBO 又把它恢复到接近运行最优值。2023 年,ESRF 把带 TuRBO 的 Badger 开放给用户供光(user service)期间的运行人员使用。

ESRF 的注入效率与 PETRA III 的耦合
注入效率是另一轮单独的运行。最初几次运行移动的是输运线的四极铁,切割磁铁(septum),冲击磁铁(kicker)和时序,后来有一次为了动力学孔径(Dynamic Aperture,DA)移动了 17 个旋钮。每个点取十次注入的平均,以保护硬件并把储存流强控制在上限以下。与原来供光运行的设置相比,注入效率从 65% 提高到 75%。并不是每次运行都成功:有一次从随机的四极铁设置出发,停在了 60% 附近;用先前一次运行的数据热启动(warm start)TuRBO,也没有看到明显的好处。

PETRA III 上则是平手。2022 年 3 月 Badger 在那里得到一次机器研究班(machine studies),目标是把耦合降到最低。Badger 的结果与运行设置大致相当,从运行设置出发也没有找到更好的点;DESY 把它留作机器研究和 PETRA IV 升级工作的工具。
LCLS
在 SLAC,直到 2025 年夏天,Badger 在 LCLS 上的全部束线测试都由我来做,LCLS-II 的调试(commissioning)也用到了它。SLAC 团队到那时为止的工作写在我们的 ICALEPCS'25 文章里。团队用它在少数几个注入器旋钮上调注入器发射度;调 FEL 时则移动部分或全部匹配段四极铁(最多二十块左右),同时给束流损失设上限,这样团队就能常规地从冷启动状态把脉冲强度提上来。2025 年夏季停机之后,LCLS 和 LCLS-II 重启时都把用 Badger 调机写进了流程,用过的例程也存成了模板,供下一次重启使用。
其他实验室与没有解决的问题
除了 SLAC,ESRF 和 DESY,Badger 还在 BNL,Argonne,Fermilab 和 KIT 用过;KIT 把它 fork 到自己的 GitLab 里,从容器中运行。每家实验室仍然要自己写环境,这一点没有变。它正式支持的平台只有 Linux,从 1.3.0 起命令行也只有一部分能用。LCLS 有一个光束线团队想要为他们的问题专门做的图,便直接改用了 Xopt。
cli-run 分支
2025 年底以来,我一直在给 Badger 加一项功能,让另一个程序可以驱动它的窗口,因为 Otter 需要这样做。这部分代码在公开的 cli-run 分支上,还没有合并。用它可以带着一个例程启动窗口并让它自己开始运行。把新的例程文件放到被监视的路径上,窗口就停下,重新加载,在原地再次运行,同时每一次评估都作为一行 JSON 写进日志。一个停止文件可以像按下停止按钮一样结束运行,而窗口保持打开。此前从外部停止它的唯一办法是把进程连同窗口一起杀掉,因此一轮运行里的每一步都要重新启动一次图形界面。这个分支也让无界面(headless)的命令行运行重新可用,并且支持暂停和继续。
所有通信都通过文件,因此不需要开端口,也不需要登录,通过 ssh 也一样能用。有一处 Qt 的细节需要再处理一次:编辑器保存文件时往往先写一个临时文件再重命名,Qt 的文件监视器遇到这种情况会悄悄丢掉这个文件,于是窗口连文件夹一起监视,每次变化后再把文件加回来。这些功能都是可选的,不加参数时 Badger 的行为与以前完全一样。
资料来源:我们的 IPAC'22 文章(Zhang 等,2022 年),ESRF 与 DESY 的 ICALEPCS'23 文章(Liuzzo 等,CC BY 4.0 开放获取,架构图和 ESRF 的图都出自那里),我们关于 Xopt 与 Badger 的 ICALEPCS'25 文章(Roussel 等),以及 xopt-org/Badger 仓库的文档与 cli-run 分支。