固定边界 / 参数化建模
VEQ 手册:先建立可比较的案例,再讨论物理含义
VEQ 用参数化的固定边界模型快速生成 Grad–Shafranov 平衡、磁通面和剖面。本手册把 VEQ Studio 的界面解释为一个有限维参数化 PDE 求解器,而不是一组彼此独立的输入框:先讲模型在数学上"求什么",再讲字段、操作与诊断判读。
阅读目标:读完后,应能沿着下面的因果链解释 VEQ 的输入、求解和输出:
固定 LCFS 与源项
|
v
MXH 边界值 + 径向 Chebyshev 拓扑
|
v
内部系数打包为未知向量 x
|
v
AᵀWg(x) = 0 的非线性投影系统
|
v
求解状态、投影残差、逐点诊断与几何诊断
本手册重点回答一个常见但容易混淆的问题:"LCFS 角映射系数"与"内部 profile 优化系数数量"有什么联系,又为什么它们绝不是同一种参数?
第一部分:用途与模型原理
1. 用途与边界
1.1 适合回答的问题
- 给定 LCFS 形状与源项时,磁通面和典型剖面如何变化?
- 调整 R₀、a、κ、δ、Iₚ 或峰化参数后,方案之间是否仍具有可比性?
- 方程一致性残差主要位于芯部、边缘还是局部区域?
1.2 不能由 VEQ 单独回答
- 该位形是否满足工程约束、线圈可实现性或完整的自由边界条件?
- 该平衡是否具备 MHD 稳定性、输运可行性或与诊断数据的一致性?
- 内部归一化残差是否小到足以成为物理"通过"判据?
判读原则:"已收敛"表示本次数值迭代满足其收敛条件;"方程自洽残差"描述网格上的方程残余,不是解的误差。两者都不是实验真实性或工程可行性的证明。
2. VEQ 究竟在求什么?
2.1 固定边界 Grad–Shafranov 问题
在轴对称近似下,托卡马克横截面上的平衡可写为 Grad–Shafranov(GS)方程
$$ \Delta^*\psi \equiv R\frac{\partial}{\partial R} \left(\frac{1}{R}\frac{\partial\psi}{\partial R}\right) +\frac{\partial^2\psi}{\partial Z^2} = -\mu_0 R J_\phi(R,Z;\psi). $$
这里 $(R,Z)$ 是截面的柱坐标,$\psi$ 是极向磁通函数。右端的电流密度通常由关于磁通的若干一维源 profile 构成,因此这是一个带特定非线性结构的椭圆型 PDE。
VEQ 处理的是固定边界版本:最外层闭合磁面(last closed flux surface, LCFS)的形状先给定;求解器在这个边界内寻找嵌套磁面与通量 profile,使它们满足平衡关系。可以把任务概括为:
给定 LCFS 的几何形状和源项描述,寻找一族内部磁面及其 profile,使得到的二维构型与 GS 平衡相容。
2.2 传统离散的未知量与 VEQ 的未知量
若直接在 $(R,Z)$ 网格上离散,未知量自然是很多节点上的 $\psi$ 值;非线性迭代围绕一个高维离散场进行。VEQ 采用不同的未知量选择:先假定内部存在一族可由紧凑参数描述的嵌套磁面,再把未知量限制为这族表示中的内部径向 profile 系数。
这不是说几何被固定不动。相反,源项或输入边界改变时,求解器仍会找到另一组系数,内部磁面也会随之改变。所谓"紧凑"是指:
- 表示家族及其截断方式由用户选择;
- 每个具体平衡对应这个家族中的一组不同系数;
- 求解的有限维未知量是这些可变系数,而非一张被冻结的几何图。
因此,问题的关键变成:怎样选一套既能保持 LCFS、又能以少量系数描述内部磁面的参数化?
3. 紧凑表示:MXH 角映射加径向 Chebyshev profile
3.1 从物理平面到磁面坐标
VEQ 使用 $(\rho,\theta)$ 描述嵌套磁面:
- $\rho\in[0,1]$ 是径向标签;$\rho=0$ 对应磁轴,$\rho=1$ 对应 LCFS;
- $\theta\in[0,2\pi)$ 是沿磁面的极向参数;
- 物理坐标由映射 $(\rho,\theta)\mapsto(R,Z)$ 给出。
在这种组织下,磁通面上的 $\psi$ 只随径向标签变化,而二维几何的复杂性被放入 $R(\rho,\theta)$、$Z(\rho,\theta)$ 的参数化中。VEQ 的紧凑性来自对这张映射的结构化选择。
3.2 MXH:展开畸变角,不直接展开边界坐标
首先定义畸变极向角
$$ \bar\theta(\rho,\theta) = \theta+c_0(\rho) +\sum_{m=1}^{M}c_m(\rho)\cos(m\theta) +\sum_{n=1}^{N}s_n(\rho)\sin(n\theta). $$
再以它构造磁面:
$$ R(\rho,\theta) =R_0+a\left[h(\rho)+\rho\cos\bar\theta(\rho,\theta)\right], $$
$$ Z(\rho,\theta) =Z_0+a\left[v(\rho)-\rho\kappa(\rho)\sin\theta\right]. $$
其中 $R_0,Z_0,a$ 是 LCFS 参数化所用的参考中心和长度尺度;$h,v,\kappa,c_m,s_n$ 是随 $\rho$ 演化的 profile。注意 $Z$ 式中的负号:它遵循当前 VEQ/VEQPy 参数化的极向角约定,不能随意替换为正号。
这解释了一个术语问题。$c_m,s_n$ 虽然乘在 $\cos(m\theta),\sin(n\theta)$ 上,数学形式上属于三角展开,但它们不应被产品语义地称为"直接 Fourier 边界坐标系数":
- 标准 Fourier 边界表示直接展开 $R(\theta)$ 和 $Z(\theta)$;
- MXH 表示展开的是畸变角 $\bar\theta$,然后把它放进 $\cos\bar\theta$;
- 因而界面中的 $c/s$ 更准确的名称是 MXH 角映射系数、MXH harmonics 或 shape coefficients。
直观地说,直接 Fourier 表示是在一张不动的坐标纸上叠加许多波形来画曲线;MXH 则先扭曲角坐标,再在扭曲后的坐标中画一个简单的基准形状。它改变的是展开的对象,而不仅是"少用了几个 Fourier 项"。
3.3 径向 Chebyshev:把固定边界写进基函数
所有径向 profile 都使用以 $\rho^2$ 为变量的移位 Chebyshev 基。令
$$ \xi=2\rho^2-1, \qquad \nu_l(\rho)=(1-\rho^2)T_l(\xi), $$
其中 $T_l$ 是第一类 Chebyshev 多项式。最重要的性质是
$$ \nu_l(1)=0. $$
也就是说,任意由 $\nu_l$ 组成的内部修正项在 LCFS 自动消失。典型 profile 可写成
$$ f(\rho)=f_a+\sum_{l=0}^{N_f-1} f_l\nu_l(\rho), $$
其中 $f_a$ 是边界 offset,$N_f$ 是该 profile 所使用的内部系数数量。于是无论 $f_l$ 如何变化,始终有 $f(1)=f_a$。
真实的 MXH family 还加入了各自的边界与轴正则结构。例如
$$ h(\rho)=(1-\rho^2)\sum_l h_lT_l(\xi), \qquad v(\rho)=(1-\rho^2)\sum_l v_lT_l(\xi), $$
$$ \kappa(\rho)=\kappa_a+(1-\rho^2)\sum_l\kappa_lT_l(\xi), $$
$$ c_m(\rho)=\rho^{K_m} \left[c_{ma}+(1-\rho^2)\sum_lc_{ml}T_l(\xi)\right], \qquad s_n(\rho)=\rho^{K_n} \left[s_{na}+(1-\rho^2)\sum_ls_{nl}T_l(\xi)\right] \quad(m,n\ge1). $$
其中 $c_{ma},s_{na}$ 是 imposed LCFS values;$\rho^{K_m},\rho^{K_n}$ 使高阶谐波向磁轴规则衰减。当前 VEQ 的默认正则幂取 $K_m=m,K_n=n$。
这套构造带来两件对理解网页十分重要的事:
- 内部系数不能改动 LCFS。因子 $(1-\rho^2)$ 已经把这一点编码进表示。
- "没有内部系数"不等于"该 profile 处处为零"。如果 profile 有边界 offset,例如 $\kappa_a,c_{ma},s_{na}$,即使不让它拥有可优化的内部修正,它仍保留由 offset 和正则延拓确定的基线。
关于 count 与论文记号:网站的 count 是系数向量长度 $N_f$,对应 $l=0,\ldots,N_f-1$。若论文用 $L_f$ 表示最高多项式编号,则 $N_f=L_f+1$。因此 count 不是"多项式的最高阶数"。
3.4 十七条径向 profile
径向 profile 是一个以 $\rho\in[0,1]$ 为自变量的一维函数,描述某个几何量从磁轴($\rho=0$)到 LCFS($\rho=1$)的连续变化。$\rho$ 是径向标签——它不是物理长度,而是标记"你正在看哪一层嵌套磁面"。VEQ 不是直接离散二维 $(R,Z)$ 平面上的几万个网格点,而是把整个等离子体截面表示为一族嵌套闭合曲线;要画出整族曲线,需要知道每个 $\rho$ 处的曲线形状——这正是径向 profile 的作用。
磁面构造公式中共有 17 个径向 profile,每个都是 $\rho$ 的函数:
| Profile | 含义 | 控制什么 |
|---|---|---|
| $h(\rho)$ | 径向偏移 | 整族磁面在 $R$ 方向的整体平移随 $\rho$ 的变化 |
| $v(\rho)$ | 垂直偏移 | 整族磁面在 $Z$ 方向的整体平移随 $\rho$ 的变化 |
| $\kappa(\rho)$ | 拉长比 | 截面在 $Z$ 方向被拉伸的程度随 $\rho$ 的变化 |
| $c_0(\rho)$ | 零阶角偏移 | 极向角映射的基准相位随 $\rho$ 的变化 |
| $c_m(\rho)$,$m=1,\dots,6$ | 余弦角映射 | 第 $m$ 阶极向角扭曲随 $\rho$ 的变化 |
| $s_n(\rho)$,$n=1,\dots,6$ | 正弦角映射 | 第 $n$ 阶极向角扭曲随 $\rho$ 的变化 |
psin$(\rho)$ | 通量-标签映射 | 归一化极向磁通 $\hat\psi$ 与 $\rho$ 之间的单调映射 |
具体例子:$\kappa(\rho)$。假设 LCFS 的拉长比 $\kappa_a = 2.0$,即 $\kappa(1)=2.0$ 是固定的。如果 $\kappa(\rho)$ 从磁轴到边界一直等于 $2.0$,所有内部磁面的拉长比都和边界相同;如果 $\kappa(\rho)$ 在磁轴附近接近 $1.0$,然后向外逐渐增大到 $2.0$,说明截面从中心的近圆形逐渐被拉长。$\kappa(\rho)$ 这条曲线就描述了这种"从圆到椭圆"的过渡方式——它是一条完整的函数,不是单个数字。
4. 一个表示,两个参数层:边界值与内部拓扑
VEQ Studio 的核心输入设计可以从上面的公式直接推出。它将参数分成两类,因为它们在数学上承担的角色不同。
4.1 第一层:LCFS MXH 角映射系数是边界值
LCFS 的角映射由 c0a–c15a 与 s0a–s15a(s0a 恒为零)共 31 个浮点数描述,是 $\rho=1$ 上的边界数据,单位为 rad。a 表示 LCFS 处的实际值,例如
$$ \bar\theta(1,\theta) =\theta+c_{0a} +\sum_{m=1}^{6}c_{ma}\cos(m\theta) +\sum_{n=1}^{6}s_{na}\sin(n\theta). $$
在 $h(1)=v(1)=0$ 的约定下,LCFS 简化为
$$ R_{\rm lcfs}(\theta)=R_0+a\cos\bar\theta(1,\theta), \qquad Z_{\rm lcfs}(\theta)=Z_0-a\kappa_a\sin\theta. $$
因此这些输入是固定边界条件:它们在一次非线性求解中不会作为内部未知量被改写。服务端将其传入 Boundary(c_offsets, s_offsets)。有十六个余弦槽和十六个正弦槽(c0a–c15a、s0a–s15a);但 s0a 固定为零,因为 $\sin(0\theta)=0$,它没有可表示的几何作用。
界面的「手动设定外形曲线」是一个按钮:它在输入表单顶部的按钮行里(2026-10-12 起替代原来的「保存输入参数」),点它在中部画布上点选控制点,工具条里另有「坐标输入」面板;悬停该按钮可见完整说明——低阶系数不再有任何逐阶输入框(2026-10-08 起):它们只由「手动设定外形曲线」(含工具条里的「坐标输入」面板)或导入的输入文件给出,带进来的每一阶在参数面板底部的只读"可选变量"清单里列出,取值范围 −10 至 10 rad;这些系数仅供生成不同外形的示例算例,不能精确设定任意外形曲线,更准确的外形曲线请用「手动设定外形曲线」→「坐标输入」给出(每行一个控制点,写成 (x,y) 或 x,y)。s1a 与几何三角度 δ 联动、s0a 固定为零,两者都不在只读清单里列出。不再设置 LCFS 阶数档位:预览、保存和求解使用全部受支持的非零边界系数,不随内部参数档位或网格截断。需要 15 阶以上谐波的输入仍会被明确拒绝,不做静默截断。用「手动设定外形曲线」→「坐标输入」给出外层曲线坐标时,浏览器会按 3→6→12→15 阶分阶段拟合出全部系数(最高 15 阶),拟合得到的全部受支持系数都会生效(见第 5.2 节)。「手动设定外形曲线」按钮提供点选绘形:点击后中部预览区切换为画布(保留当前曲线作虚线描摹参考),在画布上依次点击落下几个控制点,浏览器自动用三次样条(闭合的 Catmull–Rom 曲线)把它们光滑地连成一条绕中心一周的闭合曲线——像画矢量图那样,点 1、2、3 个点即可得到光滑轮廓,三个点就是最简单的 D 形;每次点击曲线实时重绘,「重画」清空重点;「移动控制点」是一个开关——开启后画布上的点击不再新增控制点,而是选中落点附近的已有控制点并拖动它(拖动只改变该点的位置,不改变控制点之间的连接顺序,闭合曲线的走向不变;点在空处不做任何事),再点一次该按钮即回到添加模式;「保存为外层曲线」先按控制点外接框更新 R₀/Z₀/a/κ 四个几何输入(点出的就是要的形状,中心与尺寸一并采纳),再把剩余形状细节按 3→6→12→15 阶分阶拟合转成系数写回输入框;保存前会校验曲线绕自身中心单向一周,拟合结果也须绕自身中心单向一周(自交或折叠、无法求解的曲线会被明确拒收并说明原因),保存后预览曲线就是点出的曲线,可直接求解。
4.2 第二层:内部 profile count 是模型拓扑
界面以"低 / 中 / 高"三档选择各通道的内部优化参数量。D-shaped 的四个基础通道 h/k/s1/psin 每通道分别为 3/5/10 项,总量为 12/20/40。带偏滤器位形数据的装置还启用 v、c0–c6、s2–s6 共 13 个额外通道,每通道为 2/3/5 项,总量为 38/59/105;s1 已属于基础四通道,不重复计数。参数量不再按参考记录的系数行宽缩放。三档均受单 profile 上限 $16$ 与 packed 上限 $512$ 约束。档位背后对应的仍是每个 profile 的整数 count(导入/导出 JSON 中对应的键为 h、v、k、c0–c6、s1–s6,以及隐藏但必需的 psin)。它们不填某个系数的数值,而是回答:
"这个径向 profile 要分配几个可优化的 Chebyshev 系数?"
一条函数曲线包含无穷多个点。VEQ 用 Chebyshev 展开将每条 profile 压缩为有限个系数(见第 3.3 节):
$$ f(\rho) = f_a + \sum_{l=0}^{N_f-1} f_l \cdot \underbrace{(1-\rho^2)\,T_l(2\rho^2-1)}_{\nu_l(\rho)}. $$
这里 $f_a$ 是 $\rho=1$ 处的固定边界值(来自 LCFS 输入区),$f_0, f_1, \dots, f_{N_f-1}$ 是 $N_f$ 个可优化的 Chebyshev 系数,$(1-\rho^2)$ 因子使所有内部修正在边界自动归零。count 就是 $N_f$——用来表示这条曲线的可调系数个数。
以 $\kappa$ 为例,若 Nκ = 4(例如导入文件给出的 Compact counts):边界值 $\kappa_a$ 来自基本几何输入,是固定的;内部变化由 $\kappa_0, \kappa_1, \kappa_2, \kappa_3$ 四个系数描述;求解器在非线性迭代中寻找这四个数的最优值。若 Nκ = 0:$\kappa(\rho)$ 没有任何可优化的内部系数,整条曲线退化为仅由边界值和轴正则规则决定的基线延拓——用户不能主动调整它。
"count = 0"不是"该 profile 处处为零"。$h$ 和 $v$ 的边界 offset 本身就是零($h(1)=v(1)=0$),所以 count = 0 意味着 $h(\rho)\equiv 0$、$v(\rho)\equiv 0$。但 $\kappa$ 不同——即使 Nκ = 0,$\kappa(1)=\kappa_a$ 仍然存在,内部磁面仍有一条非平凡的 $\kappa(\rho)$ 基线,只是这条基线不由用户通过 count 控制,而是由表示家族的正则延拓自动确定。
完整物理图像:
rho = 1 (LCFS, boundary fixed)
+-------------------------------------
| kappa(1) = kappa_a <-- from basic geometry
| c_m(1) = c_{ma} <-- from LCFS angular mapping coefficients
| s_n(1) = s_{na} <-- from LCFS angular mapping coefficients
| h(1) = v(1) = 0 <-- by representation convention
|
| <-- interior: Chebyshev coefficients of each profile
| optimized during solve, cannot change rho=1 values
|
rho = 0 (magnetic axis)
换个说法:LCFS 区定义了每条曲线的右端点值;count 区决定每条曲线在到达右端点之前,允许用几个"调节旋钮"来改变它的内部走向。
回到实现层面——若某 profile 的 count 为 $N_f>0$,服务端创建一个长度为 $N_f$、初值为零的系数数组;这些元素会进入非线性未知向量并在求解中更新。若 count 为零,服务端构造 Profile(coeff=None),它成为 passive profile:没有可调的内部修正系数,也不占未知向量(packed vector)的位置。这是一种拓扑或模型复杂度选择,而不是对某个物理量的直接赋值。一个最有用的类比是:
- LCFS 系数值类似"多项式的已知边界常数";
- 内部 count 类似"选择给多项式留多少个待定系数"。
4.3 两层的联系与区别
| 维度 | LCFS MXH 映射系数 | 内部 profile 优化系数数量 |
|---|---|---|
| 数学对象 | 边界调和系数的值 | 径向 Chebyshev 系数的数量 |
| 界面例子 | c0a=-0.1(无逐阶输入框:由导入文件或「手动设定外形曲线」拟合给出,带出来的值显示在只读"可选变量"清单里;s1a 无独立输入,由 δ 联动) | 低/中/高 档(JSON 中为 c2=2, s1=3 这类整数) |
| 数据类型 | 浮点数,单位 rad | 整数 |
| 作用位置 | 固定在 $\rho=1$ | 决定 $0\le\rho<1$ 的可调修正空间 |
| 求解角色 | 固定输入,不进入未知向量 | 元参数,决定未知向量的块和长度 |
| 求解后 | 原值应由 provenance 回显 | count 不变;同名内部系数的值被求解 |
因此,s1a=0.52 与 s1=3 虽然名字相似,却回答两个完全不同的问题:前者说"LCFS 的一阶正弦角映射值是多少",后者说"内部 $s_1(\rho)$ profile 允许用几个系数调整"。混淆它们,就像把"多项式系数是 0.52"与"多项式保留 3 个未知系数"混为一谈。
4.4 为什么 h、v 没有 LCFS 输入,而 s0 也没有内部 count?
由第 3 节公式可知 $h(1)=v(1)=0$。LCFS 的平移基准已经由 $R_0,Z_0$ 与 $R_0+a\cos\bar\theta$ 的边界定义承担,因此 $h,v$ 只描述内部磁面的径向/垂直偏移,网站只为它们提供内部 count。相反,$\kappa,c_m,s_n$ 可以同时有边界 offset 和内部修正:k 的边界值来自基本几何输入中的 $\kappa_a$;c0a–c15a 与 s1a–s15a(s0a 恒为零)在 JSON/求解层给定 MXH family 的边界值(界面无逐阶输入框:c0a–c15a 与 s2a–s15a 由「手动设定外形曲线」拟合或导入文件给出,带出来的值显示在只读"可选变量"清单里;所有受支持的边界系数均生效,不再有 LCFS 阶数档位);无 s0 count,因为这一 sine mode 在恒等式上为零。
4.5 count 的现实约束和预设
当前 Studio 对 17 个 profile 使用以下约束:
- 每个 count 是 $0$ 到 $16$ 的整数;
psin必须严格大于 $0$;- 所有 count 之和(packed count)不超过 $512$。
三个阶梯档位(低/中/高)与完整研究档的 packed count 为:
| 档位 | active profile | packed count |
|---|---|---|
| D-shaped 低 / Low | h(3), k(3), s1(3), psin(3) | 12 |
| D-shaped 中 / Medium | h(5), k(5), s1(5), psin(5) | 20 |
| D-shaped 高 / High | h(10), k(10), s1(10), psin(10) | 40 |
| 偏滤器 低 / Low | 基础四通道各 3;其余 13 通道各 2 | 38 |
| 偏滤器 中 / Medium | 基础四通道各 5;其余 13 通道各 3 | 59 |
| 偏滤器 高 / High | 基础四通道各 10;其余 13 通道各 5 | 105 |
| 完整 / Full(研究档) | 全部 17 个 profile 按当前预设启用 | 36 |
三档只改变各通道的优化系数个数,不联动求解网格,不截断 LCFS 边界。偏滤器额外通道由发布的「有偏滤器位形数据」能力标记启用,目前为 EAST、MAST_Upgrade、ITER_ITER-FEAT;不按装置名称中的偏滤器分类或参考记录系数行宽猜测。手动导入的显式自定义 counts 保留,不强制替换为这些预设。旧档位上的精度测量不构成新档位的精度承诺。
5. δ 与 s1a:一个输入如何跨越多个语义层
delta/s1a 是最适合展示上述分层的例子。它包含至少四种不应混为一谈的量:
用户几何输入 delta
|
| 派生: s1a = asin(delta)
v
有效 LCFS MXH 系数 s1a
|
| 与其他 c/s 边界项共同定义映射;内部 profile 另行求解
v
求解得到的内部 Chebyshev 系数
|
| 后处理实际磁面
v
诊断量 delta_top, delta_bottom, delta_average
5.1 界面中的单一联动输入
界面不再提供两种模式切换:几何三角度 δ 是唯一输入,没有独立的 s1a 输入框。适配层始终令 $s_{1a}=\arcsin(\delta)$,并在提交的边界数据中带显式系数(s1_mode: "explicit")。若导入的参数文件给出显式 s1a,前端会按 $\delta=\sin(s_{1a})$ 反算回写 δ,两者保持同一自由度。
这个关系只是在简化 Miller-like 情形下的方便转换:当其他 LCFS $c/s$ harmonics 不起作用时,可以把 $\delta$ 与 $s_{1a}$ 联系起来。它不是在一般高阶 MXH 边界下都成立的几何恒等式。特别是,当高阶谐波非零时,由最终磁面极值计算的 delta_top、delta_bottom、delta_average 可以与起初输入的 delta 不同。
5.2 外形曲线拟合的实际边界(手动设定外形曲线 / 坐标输入)
网页允许把一条离散的外层曲线((R, Z) 控制点,在「手动设定外形曲线」→「坐标输入」面板内逐行键入)转成本站的 MXH 边界系数——旧的「拟合外形曲线(COO)」上传行已于 2026-10-12 退役,功能并入该入口。拟合完全在浏览器中执行:它在给定 $R_0,Z_0,a,\kappa$ 的条件下,用分阶段的 Gauss–Newton 型迭代拟合 16 个 $c$ 与 15 个非零阶 $s$(3→6→12→15 阶逐级升阶,各段 RMS 达到 $10^{-4}a$ 即提前结束),随后按 $\delta=\sin(s_{1a})$ 把拟合结果回写进联动输入。当前前端的目标函数针对 $R$ 坐标残差构造,每段最多迭代 10 次,并以小对角正则化求解正规方程。
因此它应理解为"把键入的曲线转成当前 MXH 边界输入的一种本地便利工具",而不是完整的二维边界反演,也不是对 GS 平衡精度的独立认证。坐标不会被发送到后端。
6. 从表单到有限维非线性系统
6.1 打包未知量:count 如何决定方程维数
用户提交 JSON 时,LCFS 系数作为边界数组进入 Boundary,而 topology counts 决定哪些 Profile 是 active。所有 active profile 的内部 Chebyshev 系数顺次拼成
$$ \mathbf{x}\in\mathbb{R}^{n}, \qquad n=\sum_f N_f, $$
其中 $n$ 正是 provenance 中的 packed_count。在每次残差评估中,求解器大致执行:
- 将 $\mathbf{x}$ 解包成各 profile 的 Chebyshev 系数;
- 在求解网格上评价 profile、二维几何、度量和源项;
- 组装变换后的 GS 残差密度;
- 将残差投影回 $n$ 个测试方向。
可以用下图理解数据流:
form payload
-> validated topology counts
-> Boundary offsets + active/passive Profiles
-> Problem(route="PF", coordinate="psin")
-> Operator on solve grid
-> Solver for packed vector x
-> solution, provenance, residual and shape diagnostics
前端还会比较请求的 topology/boundary 与响应中的 provenance;不一致的响应不会被当作当前输入的结果接受。
6.2 Petrov–Galerkin 投影:为什么会得到方形系统
设求解网格有 $N$ 个采样点,把每个点上的变换残差密度堆叠为 $\mathbf{g}(\mathbf{x})\in\mathbb{R}^{N}$。VEQ 的主问题不是要求每个采样点都满足 $\mathbf{g}=0$,而是构造测试矩阵 $A\in\mathbb{R}^{N\times n}$ 和积分权重 $W$,求解
$$ \boxed{A^T W\mathbf{g}(\mathbf{x})=0.} $$
即 Petrov–Galerkin 投影方程 AᵀWg = 0。结果是 $n$ 个非线性方程对应 $n$ 个 packed unknowns。拓扑 count 因而不只是页面上的"高级设置":它同时改变
- 允许哪类内部几何/profile 修正;
- 未知向量的长度;
- 投影方程组的维数;
- 模型的表达能力与求解难度。
6.3 全文最重要的残差区分
换一句不带数学的话:结果页那组「方程自洽残差」量的是解出来的 ψ 离满足 Grad–Shafranov 方程有多远——用有限个系数逼近真实的 P/F 剖面,这种偏差是必然的,不是求解器算错了;数值越小越好。
必须把下式当作解释结果的底线:
$$ \boxed{A^T W\mathbf{g}=0\ \not\Rightarrow\ \mathbf{g}=0.} $$
线性代数上,投影条件只说明 $\mathbf{g}$ 在 $A$ 的测试子空间中的加权分量为零;在其正交补中的分量并没有被这个条件直接约束。因此:
- 小的 projected residual 说明有限维投影系统被解得好;
- 它不能单独证明所有采样点上的 GS 强形式残差都小;
- 两者应被作为不同诊断并列阅读。
Studio 输出的逐点一致性诊断使用
$$ G_{\rm std}=\frac{R}{J}G, $$
其中 $G$ 是变换残差密度,$J$ 是坐标映射的 Jacobian。磁轴处坐标退化,故该统计会排除磁轴行,并只使用有限且 Jacobian 非零的样本。该量保留 VEQPy 的物理 α₁/α₂ 尺度,单位为 T;与其他代码比较时仍须对齐残差定义、坐标权重和采样规则,不能仅凭同单位直接比较。
同一逐点残差另有两种概括,各答一个问题:径向 RMS(先平方再求均方根,正负不会抵消,答「典型幅度多大」)与逐面有符号极向积分(先按极向权重求和,正负可抵消,答「每个磁面的净偏差」)。后端保留有符号 I_i = Σ_j e_ij·(2π/N_t);界面「GS平衡缺陷(对极向积分)」画的是先积分再取绝对值的 |I_i|,纵轴用对数坐标,不除以 2π,也不是 RMS 或 |e| 的积分。e 含物理 α₁/α₂ 尺度,量纲为 Wb/m² = T;极向角 θ 无量纲,因此 I 的单位仍为 T,并非无量纲归一化量。零值与无效值在对数图上留空,不添加人为正下限,详见 §10.1。
第二部分:使用指南
7. 快速使用:先从可运行基线开始
本节只回答"怎样操作工作台"。字段背后的数学含义已在第一部分说明,避免把操作步骤与模型定义混在一起。
- 载入一组可运行参数。页面顶部输入面板自带一组可直接求解的默认值;2026-10-10 起默认值是一台具名装置——ITER_ITER-FEAT,装置栏、算例卡片与档案列表从首屏就一起指明它——此前挂的是 EAST 的发布名义值(2026-09-30 起),但那套数字虽然可对照档案,界面却读作「所有装置」且卡片折叠,等于一个不肯说自己是谁的默认值,手改一步就可能滑出站点自己的求解窗口而无人察觉。首屏表单里落的数来自这台装置的 crossdev 参考记录输入(2026-10-13 起开机即载入,见 §7.3 第 5 条):R₀ = 6.1486 m、a = 2.07974 m、B₀ = 5.34431 T、κ = 1.70244、Z₀ = 0.15694、Iₚ = 15.3644 MA,不是档案发布的七轴名义值——那组 6.1983 / 2.00486 / 4.904805 / 1.84734 / 13.85955 显示在装置卡片上,要写进表单得走装置预设(连不上计算节点、装置区块不显示时,表单停在标记里的 EAST 名义值,如 R₀ = 1.79885);或者,在装置栏的装置目录里搜索或按分组挑一台装置(面板顶部有搜索框,第一层是「常见装置」与各地区),把它的七轴名义参数载入表单(见 §7.3)。两者都不必先选装置。先确认边界预览、单位与量级符合预期。
- 从默认档开始。输入区平铺为两块——上块「平衡边界(LCFS)」(六个几何标量;LCFS 系数完整保留,无阶数档位),下块是源项(剖面族、Iₚ/目标 βₜ、各族参数;2026-10-10 起不再有标题行,内容自说明);两块的控件同屏可见,不再分页。源项预览不在输入区:它随求解结果一起放在中间展示区的「位形与剖面」页(2026-10-10 起,见 §8.2 末尾)。参数拓扑区(网格分辨率、内部 profile 优化系数数量两行)直接展示在两块下方、「手动设定外形曲线 / 加载输入参数」按钮行与只读清单的上方;2026-10-19 起首屏的内部系数行落在站点默认的中档(medium,counts 按中档写入)——参考记录载入完成后不再跟随记录自己的内部基计数(见上一条);2026-10-20 起求解网格也钉回站点默认的低档 16×16(此前暂缓的网格默认随 q0/qmin 导出修复落地而拍板:修复后全档案 267 装置 × 4 网格 q0/qmin 全正,见 docs/Q0-INPUT-EDGE-PROBE-2026-10-20.md)——选装置与参考记录自动载入后都落 16×16,记录自己的导出网格仍随记录保留(16×16 求解写 32×32 记录这类细于求解网格的导出,2026-10-20 修复后健康)。要再省一步,可把系数收到最低档(网格与系数是两个独立控件,2026-10-09 起):低档与 VEQPy 示例同族,内部磁面能形成 Shafranov 位移和径向形状演化。
- 一次只改变一类变量。先锁定边界几何,再改变 Iₚ、压力份额或峰化;每个基线都保存输入 JSON,避免把多种变化混在一次比较中。
- 运行并依次查看结果。先确认磁通面闭合、平滑且无自交;再看压力、q、环向电流和形状剖面;最后结合收敛状态与逐点诊断。
- 保留可复现证据。点"导出平衡解"保存输入参数(它先写出
veq_inputs.json);仅在收敛后使用"查看报告"生成带有效输入、图表、诊断与时间戳的独立 HTML 报告。
7.1 最小比较单元
一次只记录一个明确问题,例如"在不变 LCFS 下提高 αₚ 的影响"。同时保存输入 JSON、版本/provenance、收敛状态与报告。
7.2 不要跳过的检查
绿色状态之后仍应检查有效 LCFS 数组、s1 模式、active profiles、packed count、磁面图和强形式残差空间图。
7.3 装置预设(VEQDB 档案)
输入面板顶部的装置预设区块提供第二条取值路线:来自 VEQDB 已发布档案的 267 台装置、13,291 条平衡记录。界面上可选的取值只有一类:装置自己的名义参数(选中装置即写入,档案发布的七轴名义值)。2026-10-16 起,「按 seed 生成的随机算例」暂时从界面撤下(见下方第 2 条),随机候选的完整说明留在本节第 2 条与本手册的存档记录里。轴符号与站点输入框一致:R₀ (m)、B₀ (T)、a (m)、κ、s₁ (rad)、Iₚ [MA]、βₜ;装置卡片上的数值按 4 位小数显示,而写进输入框、并据此提交求解的那一份按 5 位小数收口(2026-10-10「值和显示一起截」:框里显示的就是发送的那个数,见 §7.6)。
- 先挑装置、再载入默认值。装置栏是一个可搜索的两级目录,不再是平铺的下拉框:按钮上显示的是当前生效的装置名(未选中时显示「所有装置 (N)」,N 是整个目录的装置数),点开按钮才展开面板。面板自上而下是三样东西:搜索框、一行筛选、然后是分组列表。搜索框支持模糊匹配:不要求连续子串,匹配按「完全相同 > 前缀 > 子串 > 子序列」分级,比较前把大小写与非字母数字的分隔符都去掉,所以输入
jt60能找到 JT-60U、输入nsc能按子序列找到 FNS-ST_Kurchatov_2011、输入JT 60与jt60等价。筛选默认展开成两排四个下拉(状态 / 地区 / 偏滤器 / 截面),点一下这一行可以收起;收起时这一行会写出当前生效的条件(如「筛选:状态=运行 · 地区=中国」),列表因此变短时不会被误认为丢了装置。四个筛选项之间、以及它们与搜索框之间都是「与」的关系(全部满足才保留),任何一项没命中时列表会明说没有匹配的装置,不会静默留一张和空目录长得一样的脸。「偏滤器」这一栏还有最后一个选项「有偏滤器位形数据」:它问的不是「档案里把这个装置记成哪种偏滤器位形」,而是「VEQDB 档案里确实存在这台装置偏滤器位形的参考平衡数据」——判据是 VEQDB 的 crossdev 参考记录,当前命中 3 台(EAST、MAST_Upgrade、ITER_ITER-FEAT)。它按装置名判定,与同一栏里的类别取值互相独立(例如 EAST 的类别是「单零」,MAST_Upgrade 是「Super-X」),所以两者也可以叠加使用。注意它标的是「数据存在」,不是「本站已经能画出来」:这三条 crossdev 记录不在本站发布的档案里(VEQDB-equilibria-20260920不含data/figure-data/),所以从装置预设按钮或导入记录得到的,仍然是档案里那 50 条常规记录——七轴名义值那一族上下对称的轮廓,看不出偏滤器位形。那三条参考记录单独挂在装置卡片上(见本节最后一条),选中即把记录的输入写进表单,不走七轴预设。列表第一层是置顶的常见装置分组(十余台常用装置的手工清单,直接单列,不必先选国家),然后是各地区,每个标题后面带着该组的装置数(如「中国 (18)」),点地区才展开它下面的装置——先挑分组、再挑装置是一目了然的。常见装置里的装置不在地区里重复出现,地区标题上的数目是扣掉它们之后剩下的台数。装置数只有 1 台的地区不单列,并入「其他」(按目录实时计数判定,不是写死的地区名单;当前这一版档案有 6 个这样的地区,所以「其他」里既有本来就归在 other 的 3 台,也有这 6 台,共 9 台),并固定排在最后。已展开的分组在切换语言后保持展开;按 Esc 键或点击面板外部收起面板(若搜索框里有内容,Esc 先清空搜索)。因为第一层默认是收起的,选中装置时会把它所在的分组行标成蓝色并给该行加aria-current,收起状态下也看得出这一票选在哪里。未选中时按钮上不会显示任何装置名——按钮上的名字就是当前生效的装置;面板顶部的「所有装置」这一行会释放当前装置(表单数值保留,但卡片不再声称它们来自某个装置)。选中装置即把该装置的默认值写入表单(七轴名义参数,经与档案记录相同的写入路径)。装置栏右侧的「详情 ▸」按钮展开该装置的只读卡片:七轴「默认值 ± 半宽」表(即 /meta 的nominal_basis/tolerance_basis溯源面)、记录数与分类徽章(状态/地区/偏滤器位形/截面类型挂在徽章上,不可点击;同一批取值可以在面板顶部的「筛选」里选)。卡片默认折叠——折叠的只是卡片本身,装置目录不受影响;未选装置时按钮为禁用占位态。 - (2026-10-16 起暂时下线)用随机种子生成新算例。界面上的「种子」行——种子数字框(0–4294967295 的整数)与它右侧的「生成」按钮——已按用户要求暂时撤下:目前不太需要用户生成随机算例,真有需求可以手动调试。撤下的只是界面入口:生成逻辑、样本文件与全部相关文案仍在站点里,恢复时只需把这两行标记放回页面,不改任何脚本。此前这一行的行为是:按该装置七个轴的局部样本范围(默认内缩 5%,避免直接撞击端点)生成新的 R₀、B₀、a、κ、s₁、Iₚ 和目标 βₜ 输入,s₁ 与 δ 仍按 δ=sin(s₁) 联动;相同装置、相同 seed 与同一生成器版本得到同一组值;生成是一次完整写入,会把该区块下方由该算例决定的输入一并改写(边界几何 δ/Z₀、LCFS 系数逐阶槽)。该候选不是 VEQDB 历史记录,不会复用历史
seq_id,也不写入档案。 - 随机候选的可解性(历史说明)。随机生成只保证候选位于该装置已有样本的经验输入盒内,不保证 solver 一定收敛;生成后仍须点击「求解」,失败时应记录失败状态或更换 seed,而不是把候选误认为历史档案。历史上保存输入文件会记录
config="generated"和random_seed。这两项今天仍然生效:这样的文件照样能导入,算例来源标记跟着恢复,seed 也随状态一起保存、下次导出原样写回(只是界面不再显示它,因为种子框已撤下);手动修改输入后,页面照旧把标记解除为「自定义」。 - 之后任何手动编辑都会把装置状态释放为「自定义」,卡片状态行随之改写,避免界面继续声称一个已被替换的取值来源。
- 三条装置多一行「参考记录」,选中即载入输入。EAST、MAST_Upgrade、ITER_ITER-FEAT 这 3 台的卡片(「详情」展开后)在七轴表下面多一行参考记录:徽章写明它是实验平衡重建还是模型参考解,下面一行是这条记录的出处,再下面一个「载入参考记录」按钮。选中这 3 台之一时,记录随选中自动载入(2026-10-13 起)——不必点按钮。载入的只是输入(2026-10-13 第二次裁决:默认算例只提供输入信息):记录在页面本地经 compact→input 转换器写成表单——完整 15 阶 LCFS 谐波(含非零余弦项,轮廓上下不对称)、R₀/Z₀/a/B₀/κ、Iₚ、可恢复时还有 GAQ 剖面族与指数、以及记录自己的导出网格与内部基计数——不发任何后端请求,也不展示记录自带的平衡解;2026-10-19 起,随选中自动载入的那一次会把内部系数档钉在站点默认的中档(见 §7 第 2 条);2026-10-20 起求解网格同样钉回站点默认的低档 16×16(见 §7 第 2 条)。记录自己的导出网格与 LCFS 阶仍随记录保留,内部基计数则被中档覆盖;手动点按钮显式重载则不钉,照转换器自己的输出(细档求解、记录自己的内部基)落表单;载入成功后清除上一组输入的平衡解与诊断;旧输入求解的迟到回包也不会重新显示旧解。中间展示区回到「最外层曲线预览」(预览轮廓随记录更新,但不能据此认定物理 X 点拓扑),要平衡解按「运行平衡求解」,那是本站按这套输入自己解的。转换器没能完整恢复的部分不静默:警告(如 EAST 的剖面恢复不出 GAQ 族、记录的 βₜ 降为目标值)逐条接在状态行的「已载入参考记录输入」后面。按钮保留作显式重载;打开页面时的默认装置(ITER_ITER-FEAT)同样按一次普通选中处理(2026-10-13 第三次裁决:保持前后一致)——初始化也会异步载入记录的完整 LCFS 输入,载入成功后的状态与重新选中一致,不必再手动重选;这里不承诺网络请求完成前的首帧已经载入记录。它不经过七轴的装置预设,载入后算例标记随之变为「自定义」(记录的数不是名义行)。为什么单列:这 3 条是 VEQDB 的 crossdev 参考记录,带 15 阶的 LCFS 谐波拟合,而本站档案里的记录一律是 s_lcfs 高阶全零、余弦全零的上下对称 Miller 族,七轴名义值那一套写不出这种轮廓(本站阶数上限 2026-10-12 由 12 抬到 15,正是为它们让路)。它不等于偏滤器解:compact 记录只描述拟合的 LCFS 与等离子体内部,不含外部场、偏滤器腿与打击点,也不保证精确的 X 点拓扑守恒——卡片上那行小字就是这句。载入前会核对记录的 sha256,与发布值不符的文件在本地即被拒绝;自动载入与按钮重载都带失效检查:换台、重新选择同一台、手动改输入或导入另一份输入后,旧的未完成载入会被丢弃,不会迟来覆盖当前表单。EAST 转换后的文件同时带 Iₚ 与目标 βₜ 时,按 Iₚ 驱动,目标仅保存、不发送;要改用 βₜ 目标须主动切换驱动量。
- 其余 264 台装置多一行「VEQDB 算例复现」,按钮式。2026-10-13 起,每台装置(除上述 3 台)都在站内 vendor 了一条档案代表记录——该装置序列号最小的一条 VEQDB 记录,逐字节复制、sha256 钉住。卡片(「详情」展开后)七轴表下面多一行VEQDB 算例复现:标题下面是这条记录的自名(header 原话),再下面一个「复现这条算例」按钮。点击后记录走导入那道门(与「导入平衡解」同为 /import,见 §9.2),中间展示区从「最外层曲线预览」换成「磁通面」——复现的是档案原案:记录自带的 P/F 剖面采样、内部磁面系数行与 Nr×Nt 网格全部随行,结果是档案那条平衡本身,不是七轴名义值在站内默认剖面族下的重解。与参考记录行的两点不同:①它不随选中自动载入——这条记录的 LCFS 与七轴预览同是 Miller 族,自动载入换不来形状、只会每次选中白跑一次导入,复现的价值在剖面与内部面,由你点按钮显式触发;②边界形状不会因此出现偏滤器——档案全部记录的 c_lcfs 与 s_lcfs 高阶项均为零(卡片小字写明这一点),非 Miller 的参考 LCFS 来自那 3 台的参考记录,但不能据此保证偏滤器腿或精确的 X 点拓扑。改动表单任何参数后再求解即为站内重解,不再是档案原案。互斥规则:有参考记录的 3 台不显示此行;sha256 核对与拒收逻辑与参考记录相同。
声明(复现的边界):默认值是档案发布的七轴名义参数;档案逐条记录使用的 GAQ 剖面族指数未发表。需要剖面与派生量级的记录级复算时,用装置卡片上的「复现这条算例」(每台一条代表记录,逐位复现),或用 compact 记录导入路线复算任意一条。
求解路线能到哪一步。把一条记录转成 input.json 后走求解,与直接走导入不是同一条路线:导入采用记录自己的内部基底、不重新求解;求解用本站的求解器把内部剖面重算一遍。所以同一算例在求解路线上会落在另一组剖面上——这是「档案记录 → 本站输入 → 本站求解」的固有差,不是算例错误。232 台装置首条记录实测(267 台全库中受理范围内的子集,另有 35 台首记录越界未收;2026-10-01 测,2026-10-02 复跑逐台一致,当时回路还按记录自己的网格档求解——2026-10-04 起默认细档求解,差值普遍更小,见 §9.4)的相对差:psi_lcfs 2.9e-4–2.7e-3、betat/Wth 4.5e-4–3.7e-3、P_axis 3.0e-3–7.0e-3、q95 1.7e-3–1.8e-2、q0 1.5e-4–1.3e-1。其中 q0 的离群来自近轴两点外推(q0 = 1.067·v₁ − 0.067·v₂),不是求解器误差。要逐元素贴近档案——psi_r/psi_rr 落在末位一位内——请走导入路线。
保存的 v4 输入文件会记录所选装置与取值来源(device + config,config 取 "default" 或 "generated"(配 random_seed));历史上从记录级算例保存的文件其 config 形如 "s<四位序号>"(零基档案序号),导入时照旧恢复其选择状态。重新导入恢复的是选择状态(按钮与来源标记),不会把该装置的名义值重新盖到表单上——表单数值一律以文件里写的为准,且加载是整例替换(见 §9.2)。装置不在目录、算例序号无记录、键形不对的键都会被整体静默丢弃(表单数值照常生效)。
7.4 可选变量清单(只读)
主界面只提供常用输入;「加载输入参数」下方是一张只读清单,把导入文件(或算例库 JSON)带进来的、主界面没有直接输入框的变量列出来,用于确认「文件里写了什么」。它没有输入控件——变量下拉、值输入框、「添加」按钮都已删除(2026-10-08);清单按脚注排版、没有边框与标题,不抢视觉,没有内容时整块不显示(2026-10-10)。它不重复主界面已有的量(边界几何、Iₚ、fₚ、αₚ、αᶠ、GAQ 四指数),那些量仍在各自位置编辑。(随机种子曾在这份名单里:2026-10-16 起种子框随「生成随机算例」暂时撤下,它既不在主界面、也不进这份清单——它的家在算例状态里,见 §7.3。)
用法:清单由导入自动填充。要改其中的值(例如 c₂),请在 JSON 文件里改好再导入——清单本身不可编辑。正常生效的条目只占一个变量名的位置(2026-10-13 起):c₀ₐ 这种数学名一行排很多个、逗号加空格隔开,不再逐行给出程序变量与当前值——路径是程序细节,值在表单与输入文件里。每组连续生效的变量名前带「界面未显示的其它变量:」领语(2026-10-14);未发送或非法条目另起一行,不由这句领语引出;清单自身不再有悬停说明,说明收进「加载输入参数」按钮的悬停提示里。
清单默认只列当前生效的值;只有当某一条目没有生效时,它才独占一整行并写明状态说明(见 7.5)。
清单里的变量分两组:
- LCFS 系数:
boundary.c_coefficients[0]–[15]与boundary.s_coefficients[2]–[15],取值须在 −10…10;清单里显示数学式 c0a–c15a 与 s2a–s15a——末尾的a是 LCFS 处的值,属于名字的一部分(写在下标里)。2026-10-08 起 LCFS 系数不再有逐阶输入框:它们只由导入文件(或「手动设定外形曲线」拟合)给出,带进来的每一阶在此列出。s0a(恒为零)与s1a(由几何 δ 派生)不在清单里,边界标量亦不在此列出。 - 内部 profile 系数个数:
topology.counts.<profile>,清单里写作 Nc5 这类——根基字母 N 带剖面名下标的另一族符号(k写作 Nκ),与 LCFS 系数不是同一族。条目由所连节点发布的/meta动态生成(allowed_profiles),取值范围取自服务端发布的per_profile_count,只接受整数;psin还必须大于 0。日常调这一族的入口是参数拓扑区的档位按钮,导入文件里显式写的 count 会走原有校验。
自由变量不会被直接转发给求解。只有写入标准 boundary / topology 块、并通过服务端校验的值才会进入 /solve;清单本身不构成任意路径的透传通道。保存的输入文件会把它们记录在 free_overrides 里,作为来源与审计记录,而求解仍以标准块为准。
7.5 没生效的值会自己说出来
生效的值在列表里只显示紧凑数学变量名;程序路径、值与状态说明仅在未生效条目中展开。没生效的值一定带状态说明,因为「没生效」和「生效了但结果没变」在界面上必须能分辨——从前一个拼错的键会无声消失,使用者无法判断「没生效」是因为不支持、还是因为自己写错了位置。
会带状态说明的行有四类:
| 已识别 / 已保存但未发送 | 格式上认识并保留在输入状态里,但当前服务端不接受,不会进入求解请求。典型例子是超出服务端最高阶数的 LCFS 系数(c13、s13 及以上):数值被保留、明确标注未发送,不会被悄悄截断或归零。 |
| 当前不支持 / 未发送 | 没有可用的变量定义。加载的 input.json 里未被识别的键(顶层未知键、source.<未知名>、不在 allowed_profiles 里的 topology.counts.<名>)会以这一状态出现在列表里——不会被静默忽略。 |
| 当前剖面族未启用 | 属于另一个剖面族的参数,当前活动族不使用。例如 GAQ 的四指数出现在指数族下。 |
| 非法 / 未应用 | 类型、范围、长度或依赖关系不合法,不会应用。导入含非法字段的文件会给出提示,且非法值不写入表单。 |
两个不会再出现在列表里的状态:已生效(常态,无需标注)与已由主 UI 承载(例如边界标量、GAQ 指数,它们的编辑入口在主界面,本来就不进这个列表)。
这套标记的用途是让「输入文件里写了什么」「网站认识什么」「求解实际用了什么」三件事可以分别核对;它不改变求解语义,也不做静默夹取——/solve 始终是唯一的裁决者。
7.6 输入精度(5 位小数)
写进输入框的每一个数都按5 位小数收口(四舍五入,2026-10-10 起):手输的格子在你敲完提交(失焦或回车)时收口;装置预设、导入文件、画布画出的外形、以及页面启动时的默认值这些程序性写入在写入的那一刻收口。收口的是值和显示两者——框里显示的那个数就是提交给 /solve 的那个数,不存在「屏幕上是 0.92305、实际发 0.923047」这种两套数。已经是 ≤5 位小数的写法(0.920、5、空串)原样保留,不做无谓规整。
两处要知道的后果:
- 档案原值会在第 5 位小数上差一点。装置的档案名义值(如 EAST 的 a=0.449204、B₀=3.239735、Iₚ=0.923047)进到框里就是 0.4492 / 3.23974 / 0.92305,因此照档案原文件重跑与本页默认值重跑会在这个量级上不同。装置卡片上显示的仍是 4 位小数的原值。
- 自己存的输入文件不受影响。保存下来的就是收口后的数,再载入逐字节一致。
δ 与 s₁ 是一对联动值(δ = sin(s₁),s₁ = asin(δ)),两格必须始终满足提交时的 |δ − sin(s₁)| ≤ 1e-12 一致性校验,所以它们一起收口:屏幕上显示 δ,内部 s₁ 就取 asin(该显示值)。
8. 参数与界面参考
本节是操作字段参考;"LCFS 值"和"内部 count"在界面中相邻,但属于不同层次,不能互相替代(见第 4 节)。
| 组别 | 关键输入 | 操作含义与提示 |
|---|---|---|
| 基本几何 | R₀ [m]、a [m]、Z₀ [m]、B₀ [T]、κ、δ | R₀、a 设定位形尺度,Z₀ 是垂直偏移,κ 是拉长比。通常先通过 κ 和 δ 调整基础截面;高阶形状留给确认需要时再使用。 |
| LCFS 映射 | c0a–c15a、s2a–s15a [rad](完整含 s0a–s15a,在 JSON/求解层有效) | MXH 畸变极向角映射的边界系数。s0a 固定为 0,s1a 由 δ 派生;界面无逐阶输入框(2026-10-08 起),c0a–c15a、s2a–s15a 由「手动设定外形曲线」拟合或导入文件给出,带出来的每一阶显示在只读"可选变量"清单里,全部受支持的系数均生效,不随参数量档位截断——需要更精确外形也请在「手动设定外形曲线」里给出坐标曲线后保存,按 3→6→12→15 阶分阶段给出全部系数(最高 15 阶)。它们定义最外层曲线,不能用内部 count 来"设置"其值。 |
| s1a 来源 | 几何 δ(唯一输入) | 界面无独立 s1a 输入:s1a=asin(δ) 自动派生,提交的边界数据始终携带显式系数。导入文件中的显式 s1a 会按 δ=sin(s1a) 回写 δ。 |
| 手动设定外形曲线(含坐标输入) | 每个控制点一行,写成 (x,y) 或 x,y(面板内键入,非文件) | 浏览器本地拟合离散 LCFS(3–10,000 个控制点),按 3→6→12→15 阶分阶段拟合,每段最多 10 次 Gauss–Newton 迭代;拟合结果按 δ=sin(s1a) 回写联动输入。旧的「拟合外形曲线(COO)」上传行 2026-10-12 退役,那时的宽松格式(空格/分号分隔、#/% 注释、可选第三列)与 2 MB 文件上限一并取消。坐标不会发送到后端。 |
| 源项与约束 | Iₚ [MA]、压力份额 fₚ、剖面族(指数 / GAQ / 逐点导入)及各族形状参数(指数族 αₚ、αᶠ;GAQ 族 nₚ/mₚ/n_f/m_f;逐点导入上传 (ψₙ, g) 文件) | 峰化指数越大,profile 通常越偏芯。先在同一基线下扫参(求解网格直接选择,见下方「档位配置」两行)。三个剖面族各自只有一套参数,互不叠加。压力份额 fₚ 的物理语义按族而异——同一个 fₚ 数值在两族下对应的预算分配并不相同,跨族比较不能靠「填同一个 fₚ」来对齐。三种族的形状、参数与受理范围见 §8.2;「逐点导入」与「手动设定外形曲线」拟合的区别见 §8.4。 |
| 档位配置(参数拓扑区) | 网格分辨率、内部 profile 优化系数数量两行 | 两项独立:求解网格直接选 16×16、32×32、64×64;内部参数档位只改通道的优化系数个数。D-shaped 基础四通道各 3/5/10 项(总数 12/20/40);带偏滤器位形数据的装置另有 13 通道各 2/3/5 项(总数 38/59/105)。LCFS 不再设阶数档位,全部受支持的边界系数均生效,最高 15 阶,超域值仍明确拒绝或按能力标为未发送。手动导入的自定义 counts、求解网格和导出网格保留。粗网格与高参数量组合须做网格收敛检查;success 和小残差不保证物理解精度。旧参数档位的测量不能用作新档位的精度承诺,服务当前不发布 measured_dq。count=0 表示没有可优化修正,不是清零边界 offset。 |
8.1 选择内部自由度
| 策略 | 档位 | 适合的第一步 |
|---|---|---|
| 默认基线 | 中档:基础四通道各 5 项;D-shaped 总数 20,带偏滤器位形数据的装置总数 59 | 求解网格默认仍为 16×16,与优化系数档位独立;LCFS 完整保留。 |
| 更省一步 | 低(基础四通道各 3;总数 12,偏滤器为 38) | 把系数收到低档;网格与系数是两个独立控件(2026-10-09 起),可只收其一。 |
| 最大灵活 | 高(基础四通道各 10;总数 40,偏滤器为 105) | 需要更高表示自由度时;求解时间和不收敛风险都会增加。也可以导入自定义 count 文件;不匹配预设时三档均不选中,文件中的系数个数仍生效。 |
调整 count 的经验法则:若残差集中在芯部,先提高档位(增加 psin 的 count);若 κ(ψₙ) 的径向形态不符合目标,再导入更高的 κ count;边缘残差也可能来自边界截断、源项或网格,不能机械地持续增加 c/s family 的 count。每增加一个 count 都会增大 packed vector。
8.2 源剖面族:三种形状与各自的参数
源项区的「剖面族」下拉框(2026-10-19 三次裁决后的最终形态:「GAQ 族」是第一个一级选项,格式与指数族/逐点导入一致,标签省略「(VEQDB)」;预设不占下拉框里的位置):一级选项是GAQ 族、指数族(默认)与逐点导入(实验剖面)。二级分类默认折叠——输入框整体大小前后不变,只有选中 GAQ 族 时,同一只输入框内部靠右才分拆出一段预设选择框(其他剖面族不分拆,选族段独占整框):四个角点预设线性·温和、线性·中等、线性·峰化、凹凸·极端(按 §02 fit 表的角点组合写入四个形状指数),以及自定义(保留四个指数框中的现值不覆盖)。直接手改任一指数后,预设条目自动落到「自定义」。族决定压力与电流这两个源通道用哪套形状函数。三种族各自拥有且仅拥有一套参数,互不组合——下表列出各族真正被读到的参数与受理范围。
| 剖面族 | 参数集 | 受理范围 |
|---|---|---|
| 指数族(默认) | 压力份额 fₚ、压力峰化指数 αₚ、电流峰化指数 αᶠ | fₚ ∈ (0, 1) 开区间;αₚ、αᶠ ∈ [1e-6, 700](能力窗,2026-10-11 起;此前的 [0.2, 15] 是政策窗,会把求解器本可解的指数也拒在门外) |
| GAQ 族 | 压力份额 fₚ、四个形状指数 nₚ / mₚ(压力通道)与 n_f / m_f(电流通道) | fₚ ∈ (0, 1) 开区间;nₚ ∈ [1, 2.5]、mₚ ∈ [1, 2]、n_f ∈ [1.5, 3]、m_f ∈ [1, 1.8] |
| 逐点导入(实验剖面) | 压力份额 fₚ、上传的 (ψₙ, g) 节点序列 | fₚ ∈ (0, 1) 开区间;节点数 3–32 |
源项实时预览(2026-10-09 新增;2026-10-10 移到中间页,与求解结果同格;2026-10-11 起排成一排四格)。预览不在本节的输入栏底部:中间展示区「位形与剖面」页有一块「源项预览(解析式)与求解结果」的一排四格网格,让「两格输入侧预览」与「两格求解结果」在同一行上读。前两格是压力 P(ψₙ):源项与求解与电流源 F(ψₙ):压力那格叠着两条线——蓝实线是源项积分出的压力形状 p(ψₙ),橙虚线是本次求解得到的压力剖面(有解时才有),两条各自按自身峰值归一化后共用同一对轴,Pa 量级的幅值另在注记里用数字给出;电流那格(2026-10-21 用户裁决,改判 2026-10-19 的显示选择;同日三次改判:y 轴不钉 0、不归一)画的是物理量 F = RB_φ——把电流源项 FF′ 从边界锚定积分回去(F² = (R₀B₀)² + 2∫FF′,预览的归一化世界里边界锚取 1),纵轴不归一,直接读边界锚定单位下的原值(边界 = 1,即 R₀B₀),走默认的最小值起点(曲线下缘 = F 在边界的锚定值 1):F 恒为正、在边界锚定 R₀B₀、轴上取峰,正是物理 F 的三条读法(2026-10-19 会议「F 从正变负」的疑问,来源是旧标签把非正的 FF′ 源项标成了 F——源项本体并没有从页面上消失,它仍在预览数据里可查,求解器吃的也仍是它)。调整 αₚ / αᶠ / fₚ(或切换 GAQ 四指数与预设、上传逐点剖面)时立即重画,用的是与求解器相同的解析式(指数族与 GAQ 族逐字同源,见本节上方的形状公式;逐点导入族把上传点按分段线性连成折线),所以在还没有求解时就能看清热源 / 电流源随参数怎么变。后两格是运行后的求解结果——安全因子 q 与环向电流密度 jφ。三点必须说清:一是前两格的蓝线不是求解结果,只是源项推得的形状(标题与注记都这样标注),平衡解要看后两格与叠在压力格上的橙虚线;二是两条源项通道的符号照后端约定,在 $[0, 1)$ 上非正、在 $\psi_N = 1$ 处为零(负号是源项的本征符号:F²/2 从芯部向边界锚定值递减,压力同样向边界递减;2026-10-19 考证确认——指数族的 αᶠ·(e^{αᶠψₙ} − e^{αᶠ}) 对任何实 αᶠ 恒负,GAQ 与上传族的前置校验保证 g ≥ 0,受理范围内不存在能把电流通道变成正值的参数,负值不是算例数据错误;2026-10-21 起这一符号约定不再直接画在电流格上——那格画的是积分后的 F,恒正——但源项通道的符号本身没有变,仍在页面数据与求解请求里),且每条曲线的纵轴只跨自己的数值范围——想比较两条通道的相对大小,请看同一参数下的数值,而不是图上曲线的高度;三是逐点导入族未上传点时,前两格会临时撤下(旁边有提示),后两格求解结果不受影响。
指数族。形状为
$$ S_p(\psi_N) = \frac{p\left(e^{\,p\,\psi_N} - e^{\,p}\right)}{1 + e^{\,p}\,(p - 1)}, $$
其中 p 就是峰化指数(压力通道用 αₚ、电流通道用 αᶠ,二者相互独立)。分子在 $\psi_N = 1$ 处恒为零,所以边界条件自动满足,不需要额外施加。这个形状是按积分归一化的:对任意 p 都有
$$ \int_0^1 S_p(\psi_N)\,d\psi_N = -1 . $$
也就是说无论峰化取多少,形状的 ψₙ 积分恒为 −1;代价是轴上取值随 p 变:
| p | S_p(0) | ∫₀¹ S_p dψₙ |
|---|---|---|
| 0.2 | −1.9355 | −1 |
| 1.0 | −1.7183 | −1 |
| 5.0 | −1.2395 | −1 |
| 15.0 | −1.0714 | −1 |
可见 p 越大剖面越尖、轴上越高,而积分不变——这正是「峰化只改形状、不改总预算」的含义。
GAQ 族。形状为
$$ g(\psi_N) = \left(1 - \psi_N^{\,n}\right)^{m}, $$
压力通道用 (nₚ, mₚ)、电流通道用 (n_f, m_f),两组互不影响。只要 n、m 为正,$\psi_N = 1$ 处 $g = 0$,边界条件同样自动满足。四个形状指数有一个采样盒:nₚ ∈ [1, 2.5]、mₚ ∈ [1, 2]、n_f ∈ [1.5, 3]、m_f ∈ [1, 1.8](精确上下限见上表)。越界时请求被拒绝并返回 422,求解器侧还会再拒一次——所以即使绕过请求校验直接调用求解入口,也不存在「越界却成功」的路径。
GAQ 的形状不是按积分归一化的:$g(0) = 1$ 恒成立,但 $\int_0^1 (1-x^n)^m\,dx$ 随指数变化,在采样盒内大约从 0.33 变到 0.75,跨度超过两倍:
| 通道 | n | m | g(0) | ∫₀¹(1−xⁿ)ᵐ dx |
|---|---|---|---|---|
| 压力 | 1 | 2 | 1 | 0.3333(盒内最小) |
| 压力 | 2.5 | 1 | 1 | 0.7143 |
| 电流 | 1.5 | 1.8 | 1 | 0.4724 |
| 电流 | 3 | 1 | 1 | 0.7500(盒内最大) |
这个差别直接决定了压力份额 fₚ 在两族里的读法:
指数族:fₚ 是热源通道占总源预算的积分份额——这一条精确成立。
GAQ 族:fₚ 只是热源通道的轴上幅值份额;要得到它的积分份额,还要把各自的 $\bar g = \int_0^1 g$ 乘进去。
所以同一个 fₚ 数值在两族下对应的物理预算分配是不同的。跨族比较时不能用「填同一个 fₚ」来对齐——这一点在把两族的结果放在一起看时最容易出错。
逐点导入族。源项不再由解析公式给出,而是由你上传的一份两列文本(ψₙ 与 g,允许 # 注释行)定义。服务端按分段线性插值使用它:节点处逐点精确、段内不会过冲——你给的数就是求解器看到的数,因此这个族里不存在「拟合误差」这一概念。契约有四条:
- 节点数 3–32。上限 32 小于求解器的参考剖面采样点数 51——形状正是在这 51 点网格上被取值的,节点比采样点还密的剖面无法被忠实表示,只会在采样时被静默丢掉。所以这是一个硬上限,超出直接拒收。
- ψₙ 必须覆盖 [0, 1] 且严格递增。首末点须恰为 0 与 1。形状在 [0, 1] 上没有外推约定,两端必须显式给出。
- g ≥ 0 且不全为零。上传的是幅值形状;两个通道的负号属于族定义,不属于你写的那一列。全零源不定义平衡。
- 节点数上下限由计算节点公布,界面读它做预校验,不在前端另写一份。
「互不组合」不是风格约定,而是被两层强制执行的:请求校验会拒绝「上传了逐点文件却又指定一个解析族」这种组合(返回 422,而不是接受之后静默忽略),求解器内部再拒绝一次。理由是:一个接受了某字段、却没有任何代码读它的接口,等于对外发布了一个并不存在的能力。
8.3 目标 βₜ 与外层迭代
环向比压的定义是
$$ \beta_t = \frac{2\mu_0 \langle P \rangle}{B_0^2}, $$
其中 $\langle P \rangle$ 是压强在等离子体截面上的平均值,$B_0$ 是环向场。注意 $\beta_t$ 不是求解器的输入参数,而是解出来之后从平衡里读出的导出量。
源项区的驱动量只有一格数字框,它说的是哪个量由变量名右侧那枚↻ 小按钮切换(画的正是 ↻ 这个旋转近一圈的箭头,点一下就换):停在 Iₚ 态时这一格是等离子体电流 Iₚ,叫它「以 Iₚ 求解」;点按钮切到 βₜ 态时它变成目标 βₜ。屏上一次只显示当前那一个名字——那枚带边框的小方块就是「这里能点」的标记。两态各自记着自己的数,来回切换不搬运数值;切换也不改版面:同一个输入框、同一份高度,只有名字在换。「目标」两个字不占屏上位置,鼠标停在那一格或那枚按钮上会说明。两者的排除是字面的——同一时刻只有当前态的那个量进请求,另一个连键都不出现在载荷里。
- Iₚ 态(默认):这一格是 Iₚ。Iₚ 是求解的一维约束,随请求发出。
- βₜ 态:这一格是目标 βₜ,不提交 Iₚ——这次求解不带任何电流约束,服务端退回它自己声明的默认电流(3 MA),Iₚ 框里留的数不参与。这句话写在悬停说明里(把鼠标停在那一格或它的 ↻ 按钮上),屏上没有常驻文字:两态只差变量名,同一个输入框、同一份高度,切换不改版面(2026-10-10)。
- 留空:关掉外层迭代——只有一次普通的单次求解,不做额外求解,也没有额外开销。此时 βₜ 是结果:解出来是多少就是多少,服务端不做任何调整。
- 填写:服务端启动一层外层迭代,通过调整压力份额 fₚ,让解出来的 βₜ 命中你给的目标。此时 βₜ 变成目标,而左栏的 fₚ 输入框会被置灰:它填的数不再参与求解(外层自己搜 fₚ),真正生效的那个 fₚ 只能由结果显示——见运行诊断 → 实际压力份额 fₚ。清空目标即恢复该框可编辑。
- 受理窗口:0–1。这个窗口只是请求格式的受理范围,不是可达范围——真正能不能到,由下面说的实测裁决决定。
- 切回 Iₚ 态 = 不设目标。留在 βₜ 格里没清空的那个数不再参与提交;保存到文件时也只写当前态的那一个驱动。导入同样按字面互斥规则决定驱动:文件带目标、且不带顶层 Iₚ 时自动切到 βₜ 态;文件同时带 Iₚ 与目标时留在 Iₚ 态(电流是物理锚点),那份没被消费的目标会被列进只读的可选变量清单、状态是「已识别 / 已保存但未发送」,不会被静默丢掉;文件不带目标则落回 Iₚ 态。
为什么用 fₚ 当求根变量。fₚ 越大,注入的压强源越强,$\langle P \rangle$ 越大,βₜ 越大——这就是外层选它当旋钮的理由;而且求解器本身对 fₚ 是纯输入(fₚ 只是它的一个普通输入),所以外层可以只改这一个数、反复调用同一个求解入口,不必触碰求解器内部。加上 fₚ 本身有界(开区间 (0, 1):两端各自把热源或电流源归零,求解器会拒绝),搜索区间是有限的。
为什么用「粗扫 + 二分」而不是牛顿类方法。我们没有 $\partial\beta_t/\partial f_p$ 的解析表达式;用差分代替导数需要额外的求解,单位精度付出的代价未必比二分低。二分的每一步都把区间保证缩小一半,不需要任何光滑性假设,也不会像牛顿法那样在平坦区或拐点附近跳出去。
预算与容差。迭代预算是有限的:先在 5 个固定的 fₚ 点上各解一次(粗扫),再在跨越目标的那一对相邻点之间做最多 11 次二分,总上限 16 次完整平衡求解。另有一笔不在 16 次之内的固定开销:请求形状冷缓存时,外层先花 3 次求解快测该形状的 βt 可达包络,用于提前拒绝不可能命中的目标(其预算由 solver_gates 的 envelope_iteration_cap 发布);因此一个「全新形状 + 不可达目标」的请求最多花费 19 次求解,其中前 3 次属于可达性判定而非命中尝试。收敛判据是相对形式:|达成 − 目标| / max(|目标|, 10⁻⁹) ≤ 10⁻³。预算耗尽即判定为未命中——不会返回「最接近目标」的那个边界值来冒充成功。这一点是刻意的:一个「最接近但没到」的数一旦被当成解返回,下游读者会直接引用它。
一条必须知道的边界:求解器从不读取
target_beta_t。在它眼里这个字段只是一个随请求传递的载体——同一组输入,带目标与不带目标解出的平衡是同一个。拥有目标的是外层迭代,因此「这个平衡是照什么目标解的」由外层写进导出记录(§9.2 会展开)。
不可达是设计状态,不是故障。当目标超出当前工况实测的可达范围时,服务返回 422,详情体里给出实测可达区间与完整迭代历史。这是为了让你知道「这个工况能到多少」,而不是拿一个最接近的边界值冒充成功。要换目标时,请挑一个落在这段实测区间内的值;想改变可达范围本身,则要调整工况参数。
还有一件事值得分清:服务在可达时同样会在响应里带上同一组区间字段——你填了 0.02 并且成功了,仍然可以从中看到这个位形最多能到多少。
8.4 逐点导入剖面(uploaded 族)与「手动设定外形曲线」拟合的区别
「逐点导入」与边界外形的「手动设定外形曲线」/「坐标输入」都在引入点数据,但不在同一层:边界外形描述几何——R–Z 平面上闭合曲线的点,浏览器用截断级数把它拟合成边界谐波系数,决定等离子体边界、进而决定解的域与磁面,带有由阶数决定的截断误差;逐点导入描述内部源项剖面——归一化磁通 ψₙ 上的一维幅值形状 g(ψₙ),驱动 Grad–Shafranov 方程右端,不改变解域。一次求解里二者串联:边界先把域定下来,源项形状再在这个域上被采样——域错了,后面再准也没意义。
剖面族选为「逐点导入」时,源项不再由解析公式给出。上传两列文本(ψₙ 与 g,可含 # 注释行):g ≥ 0 是源幅值形状,服务端按分段线性插值使用(np.interp)——节点处逐点精确、节点间线性不振荡,因此不存在「拟合误差」这一概念:你给的数就是求解器看到的数(这正是当初选线性插值而非三次样条的验收理由)。随后按压力份额 fₚ 拆成两个源通道:heat = −fₚ·g、current = −(1−fₚ)·g(与 GAQ 族 g_p = g_f = g 同构)。
- 节点数 3–32(由计算节点公布):上限设在求解器 51 点参考采样网格之下——节点多于采样点的剖面无法被忠实表示,只会被欠采样静默丢掉,所以是硬上限,超出直接拒收;
- ψₙ 覆盖 [0, 1] 且严格递增:首末点须为 ψₙ = 0 与 1;形状在 [0, 1] 上无外推约定,两端必须显式给出;
- g ≥ 0 且至少一点为正:g 是幅值形状,两个通道的符号由剖面族决定,不由上传列决定;全零源不定义平衡。
由此也可见两种「给更多点就更好」的直觉方向相反:逐点导入的节点数有硬上限(超过求解器采样网格无意义),而「手动设定外形曲线」拟合一味提高阶数反而可能让拟合静默变差(样本 RMS 好看、真实误差反涨),有效阶数受采样点密度约束。前者的误差概念不存在(精确插值),后者的误差有长度量纲(截断地板,米)——「这两条曲线的误差哪个小」这一问题本身不成立。
9. 结果、保存与报告
9.1 建议的查看顺序
provenance:核对有效边界数组、s1_mode、active profiles 与 packed count;求解状态:确认投影系统是否收敛;磁通面:检查闭合、平滑、无自交;剖面:在模型假设与目标工况下阅读压力、q、jφ 以及 κ/δavg/ΔR 的径向演化。
9.2 保存、加载与报告
"导出平衡解"先导出一份输入参数 JSON(边界、源项和拓扑)——这就是原「保存输入参数」按钮的功能,2026-10-12 并入那里;"加载输入参数"恢复该基线。加载是整例替换,不是叠加:先把表单推回「文件没说」的取值,再让文件往上写——文件里写了的覆盖表单,文件没写的不留上一例的数字。分两类:服务端接受 0 的格子写 0(Z₀、δ、LCFS 系数、可选变量槽),它拒绝 0 的格子落回该字段的请求模型默认值(R₀ 1.05、a 1.05/1.85、B₀ 3、κ 2.2、Iₚ 3、fₚ 0.75、αₚ 5、αᶠ 3.32;框里按输入精度显示,a 因此是 0.56757 而不是 0.5675675675675675,见 §7.6),内部系数回「中」档、求解网格回 16×16;LCFS 不设阶数档位、剖面族回指数族、目标 βₜ 清空且驱动量回到 Iₚ 态(一个文件只定义一个驱动:文件带目标、且不带顶层 Iₚ → 驱动量切到 βₜ 态;文件同时带 Iₚ 与目标 → 留在 Iₚ 态、目标列为「已保存但未发送」;文件不带目标 → 落回 Iₚ 态,见 §8.3)。理由是一个文件要能唯一定义一个算例:只要有一格沿用了屏幕上的残留值,同一个文件在不同时刻导入就会解出不同的平衡。因此 compact 记录转出的输入文件不带 fₚ/αₚ/αᶠ 时,它们落在上面那三个默认值上,而不是上一次求解用过的数。
"导出平衡解"总是先写出输入参数 veq_inputs.json(原「保存输入参数」按钮的功能,2026-10-12 并入这里);求解收敛后,它还会同时下载:veqpy 原生类型化根 JSON 快照(可再导入本页面重建显示)、VEQDB compact JSON(扁平 31 字段交换格式,与 VEQDB 平衡解档案 `*.compact.json` 同字段、同顺序、同数字文本规则,供 VEQDB/VEQPy 批量工具读取;数组宽度由各自的求解配置决定,档案与本站不必相同),以及导出 manifest JSON(记录输入参数全集、精度档位与实际生效配置、route、Galerkin 投影残差、函数评估次数、Ip 目标与输出、βt 的目标值与被达成的值连同二者的相对误差、qmin/q95/Wth、求解器与代码版本;服务端未附带 manifest 时不下载该文件)。"导入平衡解"接受前者,从快照重建显示而不重新求解。"查看报告"会打开独立 HTML,包含提交与有效输入、求解摘要、图表、警告、方程一致性诊断、规则型数值提示和 Markdown 导出。需要离线读取这些导出文件(自己读 JSON、绘图或跑批量算例)的读者,代码与后处理工具在公开仓库:github.com/FusionAlpha/veqdb(平衡解档案与 compact 格式)和 github.com/FusionAlpha/veqpy(求解器本体);页面右栏导出按钮下方也有同一组链接。
βt 的目标落在哪一层。如果你填了「目标 βₜ」,那么“这个平衡是照什么目标解的”这句话由三样东西回答:βt 的目标值、实际被达成的值、以及二者的相对误差。相对误差记的是带符号的数——正号表示过冲(解出来的 βt 高于目标),负号表示不足(低于目标);只有带符号,读者才能区分这两种情形。它与可达裁决用的是同一个式子,所以可以只凭记录里的两个数把裁决重算一遍。
「同字段、同顺序、同数字文本规则」不是跨机器重解的承诺。逐位一致是「同一输入 + 同代码版本/同网格/同数值环境 → 同一文件」的格式性质;换一台机器、改变 BLAS 线程数或代码版本之后重解同一输入,允许出现 1e-12 量级的数值路径差(见 §9.3 的钉扎副作用)。
这三条记录落在旁车 manifest 里,不在 compact JSON 里:compact 是冻结的交换格式(当时 30 键),阶段 3 一个新键都没有加。此后唯一一次键集合变动是把档案本就有的 q0 补回(30 → 31 键,见变更报告 §4.38),那次补齐是让本站导出与 VEQDB 档案对齐,同样没有为 manifest 的内容开新键。manifest 的键集合也是恒定的——一次不带目标的求解、一次带目标的求解、一次导入的快照,三者的 manifest 键集合相同,只是不带目标时目标值与相对误差为 null(语义是“未使用”,不是“零”)。
关于 δ:δ 模式中的输入 δ 不必等于结果中的 delta_top、delta_bottom 或 delta_average。后者是由实际磁面极值后处理得到;高阶 LCFS harmonics 非零时,这种差异是预期现象。
9.3 导入 G-EQDSK(g-file):两个表达域与 8 MiB 上限
"导入 g-file"已经没有单独的按钮了(2026-10-12 用户裁决):它并进了"导入平衡解"。同一个"导入平衡解"按钮、同一个文件框,按文件内容分流——内容是合法 JSON 就走记录那条路(POST /veq/api/v1/import),解不开 JSON 的单文件就走 g-file 那条路(POST /veq/api/v1/import/gfile)。判定看内容、不看扩展名:g-file 是 EFIT/CHEASE 一类程序输出的定长文本,永远不是合法 JSON,所以记录那条按体形识别的路径在结构上认领不了它;记录那条路接的是本站自己导出过的 compact 记录(以及可选的旁车 manifest),g-file 这条则由服务端在线投影出 compact 记录并把结果显示出来,不运行平衡求解器——两条路在这一点上相同。g-file 一次只能传一个文件(它就一个部件);多选留给"记录 + 旁车 manifest"那条路,多选里混进非 JSON 会在本地被明确拒绝("一次只能上传一个 g-file")。下文说的"这条入口"指的就是这条路由。
上限有两个数,别把它们混起来用。这条入口的上限按端点定,不是全站统一值(其余端点仍是 64 KiB),而且它自己又分成两层:
- 文件上限 = 8 MiB(8,388,608 字节):你的 g-file 本体的上限。判断"我这个文件能不能传"看的是这个数,前端预检用的也是这个数(读
/meta的gfile_import.request_body.file_max_bytes)。 - 请求体上限 = 文件上限 + 8 KiB 信封余量:整个 HTTP 请求体的上限。上传走
multipart/form-data,除了文件字节还要装一段信封(--boundary、Content-Disposition、结尾的--boundary--;A-0 实测为 +189…192 B),这段信封占在同一个上限里。所以文件满额 8 MiB 时,请求体比 8 MiB 略大,仍然被接受。
为什么必须分成两个数。只发布一个数时,前端只能拿文件字节去比请求体上限:文件大小落在「请求体上限 − 信封」到「请求体上限」这一段里,本地预检会放行、服务端却回 413;而 413 的文案若报的是请求体上限,就会报出一个你的文件并没有超过的数字——一条自相矛盾的错误信息。现在文件上限独立发布,文件大小 > 8 MiB 是精确判据,这条缝不存在了。
如果部署节点还没有发布文件上限。若 /meta 只给出旧版的那个单数(gfile_import.request_body.max_bytes,没有 file_max_bytes),前端就按旧语义把它当作文件上限使用——旧版本来就是一个数管两头,此时它确实约等于文件上限,不会把两个数混用。等 file_max_bytes 出现后自动切到新语义,无需改前端。两个数都发布但缺少文件上限时,前端用体上限减去信封余量得到文件上限(服务端自己发布的减法,不是前端猜的)。
8 MiB 这个数从哪来。来自实测而不是估计:本机可达的 24 个真实 g-file 全部超过旧的 64 KiB(最小 2.91×、中位 6.57×、最大 18.76×),其中最大的 1,229,642 字节本身就是一个 257² 网格文件,语料里最大的 129² 文件为 649,848 字节。8 MiB 对实测最大文件留有约 6.8× 余量,为方言之外仍更大的文件留出空间;旧 64 KiB 对 24 案全部不足。前端会在本地先查文件上限并给出具体字节数,不会把文件白传一遍才收到 413。
这条入口是匿名的,与「导入平衡解」同级。路由 /veq/api/v1/import/gfile 已在网关的公开写入白名单里,公开面没有登录入口,你也不需要登录。白名单是精确成员匹配(path in VEQ_PUBLIC_WRITES),所以路径字符串必须逐字一致。由此可得一条判据:这条路由上出现 401 不是正常状态——它意味着网关侧的公开入口白名单没有生效(例如部署时把 VELO_VEQ_PUBLIC_WRITES 设成了更窄的集合),是服务端配置缺陷的可见信号,不是你该去解决的登录问题;遇到时请报给服务端维护者,不要去注册或登录。
记录域与求解域是两个域。本站求解拓扑的 LCFS 阶数上限是 15 阶,这个数发布在计算节点 /meta 的求解拓扑段(topology.limits.fourier_order_max),不在记录格式里。因此一条实测阶数 M > 15 的投影记录:
- 可以导入(本站接受该记录并显示它);
- 可以导出(记录仍可再导出为 compact JSON 与 manifest);
- 不能在本站求解(求解时才具名拒绝)。
这不是一次失败,也不是静默截断:投影结果面板会把实测 M、本站求解拓扑上限与超域标记三行并列显示,并在超域时给出上面这段边界声明。判据有两条且分列:服务端返回的 beyond_site_expression_domain 标记,以及实测 M 与本站上限的比较(服务端未返回标记时,面板会写明判定依据是后者)。选这条路的理由是可判的:本站自己发布过的档案里就有 121 条 M=20 的记录,把 15 阶做成入口闸会把自己发布过的记录形态一并拒掉。
保真度:本站实测,不是转述声明。投影结果面板里的保真度三元组(归一化磁通 RMS、边界 RMS、电流相对误差)是本站这次请求实测出来的——服务端从你上传的字节出发,投影、回灌记录再逐项比对,把三个数连同口径标记(fidelity_metrics,说明每个数各自是什么定义)一起返回;面板逐项显示这些返回值,服务端未返回的项明确显示"服务端未返回",本站不填任何数、也不代为声明。这一点与"导入平衡解"那条路径相反:那边记录里带的保真度是随记录而来的声明值,本站只是转述;g-file 这条路径上记录的保真度由本站自己测。三项的定义各自独立,两个不同口径测出的三元组即使数字相近也不可比,因此口径标记与数字必须一起读。
实测的参照:本机对 CHEASE.geqdsk(288,006 B,128×128)实测三元组为 8.39e-4 / 0.612 mm / 0.110 %,对 SOLOVEV.geqdsk(1,107,777 B,257×257)为 1.80e-5 / 1.335 mm / −200.04 %。第三个数的 −200% 是源文件自身朝向与本站符号约定不一致时的签名(记录里的 Ip 与源文件反号),不是本站投影失败:前两项仍然很小。这类数只有实测才看得见,也正是"本站是测量者而不是转述者"的用处。
BLAS 线程口径(机制已定,本机已生效)。g-file 路由的 BLAS 线程策略由服务端决定并在本节声明。服务端在该路由的计算区间内请求固定单线程(threadpoolctl.threadpool_limits(limits=1)),作用域只覆盖这条路由,/solve 不受影响。这不是一个无条件的承诺:固定仅在满足前置条件时生效(单求解槽 + threadpoolctl 可用),不满足时跳过固定并把原因写进这次响应,而不是假定它生效。
三臂实测(同一源、同一路由、同一 revision,只差固定是否生效):
| 臂 | pinned | threads_before/during/after | wall (s) | CPU (s) | cpu_over_wall |
|---|---|---|---|---|---|
| 未钉 | false | 未探(包缺席) | 0.349 | 9.128 | 26.12 |
| 已钉 | true | 32 / 1 / 32 | 0.146 | 0.146 | 0.999 |
负控制(VEQ_GFILE_SINGLE_THREAD_BLAS=0) | false | 32 / — / 32 | 0.232 | 6.128 | 26.40 |
即:在未生效的分支上,一次约 0.35 s 的公开请求要消耗约 9 s 的 CPU;固定生效后同一请求的 CPU 降到 0.15 s(62×)。这正是把线程口径写进公开声明的理由。threads_before/during/after 是服务端在钉扎前后实际读到的线程数,不是承诺值。
一处必须一起读的副作用:钉扎会改变数值路径。三臂的保真度三元组里,两个未钉臂逐位相同(1.090831865190669e-3),已钉臂与它们差在 1e-12 量级。这正是固定以「独占单求解槽」为前提的原因——进程级 BLAS 线程数一旦改变,并发中的另一次求解的数值路径也会被改变。
9.4 「一致性校验」:一条记录进,整条回路出
「工具 → 一致性校验」把三件本来分开的事接成一条流水线:算例生成(记录 → 输入算例)、提交求解并导出、以及把导出的记录与原记录逐字段比对。它等价于命令行工具 tools/roundtrip_compact.py——后者是运维侧的同一把尺子,两者比对的是同一组键、同一个相对误差下限,浏览器里的这份由 test_roundtrip_parity.py 钉住与命令行的一致性(键集合或阈值只要有一边动了,CI 就红,而不是让两份判据各自漂移)。
一条回路,四步。面板跑的就是这一条(走 POST /veq/api/v1/solve):
- 转:记录 → input.json。边界、Ip 照抄,记录自己的
Nr/Nt写成导出网格(记录没写这一对时按格式默认读作 32×32,并写明进文件);求解网格不是记录的那一对,而是站点最精细的一档 64×64(2026-10-12 起;此前是 128×72,见下)——两个数都写进文件,所以这份算例仍然自洽、可原样重跑;source 剖面族与四个指数从P_psi/FF_psi拟合还原;内部基底counts从各系数行的「行宽」读出。 - 解:把这份算例提交求解——内部剖面是本站重新推出来的,落在族的另一个成员上。
- 导出:把解出来的平衡导出成 compact JSON。
- 比:把导出记录与最初输入的那条记录逐字段比一遍。
中间产物不是原始输入。报告里的「查看 input.json」给出第 1 步建出的那份算例,可以预览,也可以下载(同一个弹窗里的「下载 input.json」)。要读准它:compact 记录保存的是解出来的状态,当初生成它的那份请求并不在记录里,所以这份 input.json 是还原出来的等价算例,不是原件。这条回路量的因此是「还原一个等价算例 → 解 → 导出」,拟合与重建的代价也计在差异里。
报告能带走什么:一排三个按钮。「查看 input.json」打开第 1 步建出的那份算例(弹窗内可再下载一份);「下载导出的 compact JSON」给出第 3 步导出的那条记录——它是这条回路里唯一运行前不存在的文件,也是 input.json 的另一半;「导出对比表格 (CSV)」把报告里那几张对比表逐行导出(分组, 路径, 档案值, 导出值, 绝对差, 相对差, 判定,列序与行序都照面板,带 UTF-8 BOM 以便表格软件直接双击打开)。两点写在文件里而不是靠约定:判词列每行都写、不留空,因为四张表共用一个文件,一个中途变宽变窄的表头比一列空值更难读;文件不受面板行数上限的约束,那个上限是屏幕上的排版约束(防止一个长表把近轴读出那几行挤出可视区),文件里不存在。后两个按钮只在求解成功时出现——被拒绝或导出失败的那一趟没有文件可给,与其给一个后面什么都没有的按钮,不如只留下「查看 input.json」。「下载报告 JSON」已下线(2026-10-07):它吐的是整份内部结构(输入算例、导出记录、逐字段比对结果一起),而读者要带走的是那张表。
命令行工具 tools/roundtrip_compact.py 另外还报一条导入路线(走 POST /veq/api/v1/import:不运行求解器,直接采用记录自己的内部基底构造平衡、逐元素复现)。它是对照,作用是把「求解器落到别处」与「读写丢掉东西」分开——求解路线上那些大数能被归给求解器,靠的就是它。该对照在每条测过的装置上都把记录复现到 1e-14 相对量级,结论已经成立,所以面板不再每次重报一遍它;档案级的双路线统计仍以命令行为准。
第 1 步那半张 source 块是有代价的,而且已经量过。2026-10-01 在 ADITYA 上做过反事实对照(同边界/同 Ip/同网格,只有 source 块不同):走拟合还原出的族,比把 betat 当目标反搜,在 P_psi / P_axis / q0 / psi_lcfs 上分别好 244× / 201× / 208× / 229×;反过来,在 betat 与 Wth 上旧路径好 2 倍——目标法把 betat 这一个数按住了,代价是平衡本身。报告里 betat 那一行判定写作「目标量(求解器反搜)」而不是「逐位相同」,就是这个结构在读数上的落点。
为什么求解网格不是记录自己那一对(2026-10-04 拍板)。compact 记录的 Nr/Nt 是它写出时的分辨率,而档案里的记录本身是更细的求解采样到这么多节点写出来的。把求解也钉在记录那一对上,等于拿一个 32 节点的解去对一条 32 节点采样的细网格解——两边描述的其实是同一个平衡,只是分辨率不同,差值却被读成「复现不出来」。现在回路把求解升到站点最精细的一档(2026-10-12 起为 64×64,此前为 128×72——下面这一整段实测数测的是 128×72 那条腿)、仍按记录声明的节点写回;实测(记录 …GAQ_704753991_0052):q0 7.93% → 1.39%(5.7×)、qmin 7.78% → 1.24%(6.3×)、P_axis 0.554% → 0.034%(16×)、psi_lcfs 0.236% → 0.011%(22×);受纳口径(232 台首记录中可解的 231 条——267 台全库另有 35 台首记录越界未收;同一条记录两种网格各解一次):P_axis 与 q95 是 231/231 都改善,psi_lcfs 与 q0 各只有 2 条变差,中位改善 10–16×。不是全胜:Damavand 的 psi_lcfs 反而差 8.75×、betat/Wth 差 5.4×,ST-E1_ST500_2025 的 psi_lcfs 差 2.3×,TM-2 的 q0(钉住时全库最好,1.5e-4)落到 6.4e-3(差 42×);SSST 在 128×72 不再收敛(32×32、64×64 都收敛)。所以这不是「对每条记录都更好」,而是「对 99% 的记录更好」。这一趟按哪一档解、按哪一档写回,写在转换器产出的输入文件里(topology.solve_grid / topology.export_grid,面板可打开查看)。携带字段(R0/Z0/a/B0/κ、c_lcfs/s_lcfs、Ip、Nr/Nt)仍逐位相同。内部系数行几乎不动(kappa_coeffs 中位 1.7×,个别装置还略差)——那几行是「解出来的内部」换一组基函数重写,不是分辨率效应;它们本来就只报告、不断言。
比什么、不比什么。逐字段比对不是"两个 JSON 全比":
- 被检查的字段集合来自转换器自己的报告,不是另写一份清单——转换器说它把哪些记录字段带进了算例,工具就查哪些;来源写成派生表达式(
fit(P_psi, FF_psi)、sin(s_lcfs[0]))的条目不查,它们没有可对照的记录原值。 - 结构键(Nr、Nt、K_max)单独判:它们不是数值精度问题,而是"网格有没有被重挑"。
K_max只在跑过求解的一侧存在,因此键集合比对豁免它——否则每条记录都会报"键集合变了"。Nr/Nt同样豁免:导出端总是写出这一对,取的是记录自己的Nr/Nt(即文件里的topology.export_grid,记录不写它就是 32×32),所以"记录没写、导出写了"不是键集合变化,而是同一条默认规则落到纸面上的样子;两边是否真的不一致,由结构行自己报。 - 两条边界数组(c_lcfs、s_lcfs)按公共前缀比,多出来的尾段必须全为零:尾段非零意味着一边带着另一边没有的谐波,是真差异,不是"某个写入器补齐得更长"的格式差。
- 相对误差在参照值量级 ≈ 0 处不计算(下限 1e-12):那里是噪声之比,报出来的是"两个噪声的商",不是误差。这条下限是绝对的——它按参照值自身的量级判定,而通道尺度跨了十几个数量级,所以它对
c_coeffs/v_coeffs这类整体就是舍入量级的通道不起作用:那里仍会报出接近 100% 的商。读到这类数字时,它说的是"这个通道没有信号",不是"不一致 100%"。 - 数组行的相对差按通道归一(最大差 ÷ 存档侧通道峰值),不做逐元素取最大:P_psi / FF_psi 都要经过存档值为舍入量级的节点,Chebyshev 系数行的尾部又比头部低几个量级,逐元素的"最大相对差"量的是"值碰巧在哪里小",不是"这一趟落在多远"。归一到通道峰值后,数字的含义是"占该量自身尺度的比例"——实测同一批档案记录上 P_psi / FF_psi 落到 ≈0.3%,与摘要行同量级,而不是表里吓人的 100%。
- ψ 导数(psi_r / psi_rr)不报百分数:导出端的谱微分把差异放大在边缘节点上(实测 NSF_NTT 负三角位形的一条记录:内部节点在 1% 以下,最后一个节点差到通道自身尺度的 ~230 倍),通道的"最大相对差"永远是边缘那一格的数,戴着的却是整个通道的名字。这两行只报绝对差并标注「差在边缘节点(谱微分放大)」,且独占一张表(「边缘放大(psi_r / psi_rr)」)而不是混在物理量表里——把一条复现到 0.5% 量级的测量顶到表头的是边缘放大,不是复现失败。
- 报告侧按"读法"分表,不按"数量"堆一表(2026-10-04 改版):同一批行需要的读法不同——
header是记账字段(档案写生成它的算例名、本站导出写格式标签,两边按设计就不同,永远显示「不同」且永远不进判词),近轴读出(q0 / qmin / q95)是「平衡 × 节点集」这一对的属性,边缘放大又是另一套读法。以前它们排在同一张表里,只靠间距区分,读者没法知道那行注释说的是整类还是一行;现在各占一张表、各带标题,需要解释的表在标题后挂一个「?」,点开是那张表的说明弹窗(Esc 或点背景关闭)。摘要的两行同样各挂一个「?」:两行是同一个单位(相对差 %)在量两件不同的事——「求解一致度」是平衡自身的标量,「表述一致度」是近轴读出。前者的残差下限约 3e-4,加密求解在 223–231/231 条记录上改善它,少数几条反而变差且随加密单调上升,那是分支差(重解落到了另一支等价解),再加密也压不下去;后者是(平衡, 节点集)这一对的属性,同一条解在 32 节点与 128 节点的导出网格上q0差约 7 倍,所以加密让平衡变好也可能让这一行变差(TM-2 是单条标本:同一次扫描里psi_lcfs好 53×、q0差 54×)。两行下面还写着这一趟的口径(求解档 / 导出网格):求解档是站点的、随站点默认变化,同一条记录换个默认就报不同的数,所以数字必须带着它是按什么量出来的出现——两个数都写在 input.json 里,可原样核对。header在这里尤其要紧:它和物理量同表时,一个纯粹的记账差异看起来像一次失败的比较。
「求解」是要花计算节点的。面板会在本站真实跑一次求解(并发槽只有 1)。工具按钮上写了这一条,请不要把同一条记录反复重跑当作消遣——这与站内其它求入口共用同一个限流。
被拒绝的算例:拒绝就是这次运行的终点。若记录的目标 βₜ 落在此边界上该族可达范围之外,服务端不是报错而是具名拒绝(响应体里带 beta_t_reachable 块,连同实测包络),报告卡片会把这个包络印在拒绝语旁边(目标值、可达区间),然后结束——没有数字可报,也不补跑。要不要带目标,由记录自己的内容决定——compact 工具不以「能否带目标」为题提供任何选项:转出的输入文件总是带上顶层 Iₚ(第 1 步照抄记录的 Ip),于是即使记录带 betat,文件里也是「Iₚ 与目标同时在」——按 §8.3 的字面互斥规则,算例落在 Iₚ 态(电流是物理锚点),记录自己的 βₜ 被列进只读的可选变量清单、状态为「已识别 / 已保存但未发送」,不参与这次重解;只有一份不带电流的输入文件才会落到 βₜ 态。工具不会替你二选一。P_psi / FF_psi 拟合得出源族的记录不带目标(族本身已定压强分配);拟合不出的记录才把自身的 βₜ 当作目标,而这种记录的目标若不可达,去掉目标重跑得到的平衡不满足原记录,那份数字只会穿着"复现"的名字误导人,所以工具不提供「去掉目标重跑」这条路(你要手动拨回 Iₚ 态是另一回事:那是你改了这个算例的定义,不是复现)。注意 200 也可能是"没导出":导出失败会退化成 null 加一条 warning(实测 1,068 条里 2 条,均为"求解出的平衡在轴外奇异或反向"),工具读那条 warning 并把服务端给的原因显示出来,而不是把它读成"导出是空的"。
此节不确立的。(一)工具断言的只有转换器声明携带的字段;记录里其余字段(h/v/κ/c/s 的 Chebyshev 系数、P_psi/FF_psi 通道本身)列在报告侧的「物理量:只报告,不断言」表里,它们的差异不进失败清单,也不是通过、而是没被断言——报告侧分表正是为此:这些量的读法各有各的规则(通道归一、近轴读出、边缘标注),与断言过的字段同表会把几套读法混在一起;(二)"PASS"的含义是"记录声明的网格未变(导出按记录自己的 Nr/Nt 写出)、转换器声明携带的字段逐位相同",不是"导出的记录与输入记录一致"——只报告不断言的那批量(psi_r/psi_rr 的边缘节点差异、内部系数向量)仍可能带着大差异,面板把它们列在报告侧那几张表里正是为此;(三)这份测量在浏览器里跑,与命令行 harness 的数值一致性由键集合与阈值的契约钉住(test_roundtrip_parity.py),不代表两者报的是同样几条路线——命令行的导入路线在面板上没有对应卡片;(四)档案侧的全量统计(13,291 条)来自命令行 harness 与 Python 参考实现,工具本身只跑你给的那一条。
第三部分:诊断与判读
10. 把"完成"与"可信"分开阅读
HTTP 成功、存在结果、求解器收敛、投影残差小、逐点一致性良好、几何满足任务目标,是不同层次的事实。它们必须并列检查。将返回结果分为几个层次更安全:
- HTTP 请求成功:服务接受并处理了请求,不等于数学求解成功。
- 存在结果与诊断:即便求解器未报告完全收敛,服务器仍可能返回有限状态和诊断,前端会显示警告。
- solver success / convergence:指定的有限维求解过程满足其返回判据。完整报告受
isConverged()门禁控制。 - 表示和物理适用性:还需要综合查看投影残差、逐点强形式统计、磁面几何、profile 与 warning,判断当前 topology 是否足够表达所需平衡。
目标 βₜ 的可达裁决是这一节主题的又一例。当目标不可达时服务返回 422,响应体里给出的可达区间是实测的、逐请求逐工况的——它是这一次运行、在这个位形与这个剖面族上真正测到的范围。计算节点的 /meta 端点不发布任何可达区间:它发布的只是请求的受理窗口(0–1),那回答的是“什么样的请求会被受理”,不是“哪些目标一定能达到”。把受理窗口读成可达承诺,就是又一次把某一层的“接受”当成了另一层的“结论”。
10.1 诊断指标
| 指标 | 定义或计算方式 | 应如何使用 |
|---|---|---|
| 平均残差(projected_residual_norm) | 求解器内部有限维投影方程收敛残差的每方程 RMS(L2 范数 ÷ √方程数,原始 L2 见 residual_norm_l2)。 | 判断迭代状态;口径不随系数个数档位的维数变化,跨档可比;小值不自动意味着截面每一点的残差都小。 |
| 方程自洽残差(非误差) | 在有效求解网格计算逐点诊断 e=(R/J)G;等价实现中也记作 G_std=(R/J)G。它保留 VEQPy 的物理 α₁/α₂ 尺度,单位为 T。它衡量离散解满足平衡方程的程度,不是与真解的偏离。 | 用于残差定位与收敛失败告警(RESIDUAL_GATE_L2),不要跨精度档位比较:同一网格上把 profile 系数从 27 增到 33,此值涨 19%,而同期 q 剖面相对 192²×c64 参考解的误差实际下降 2.83×。不是通过/失败评分,也不是跨模型的绝对物理阈值。 |
| 方程自洽残差(整体 / 峰值) | 口径:网格点上的无权 RMS sqrt(mean(e²)) 与 max(|e|),采样点在 Legendre 点上。已知偏置:Legendre 点向边缘聚集,无权平均使该诊断对边缘有 1.45–2.01× 偏置(实测加权/无权比,产物 output/veq_tier_metric_alternatives_20260920/mechanism_probe.json:站点三档臂 12 条=4 案 × 低/中/高 为 0.4977–0.6775;全 36 条臂 为 0.4963–0.6914,其全局最小在 nearDN_median__demo c18@96,不在任何档位臂上);实测 12.8%–41.7% 的方差来自最后一条径向行,而该行源项按指数族构造恒为零。性质:自洽性诊断,不是误差。 | RMS 概括典型幅度;最大值揭示可能被平均掩盖的局部峰值。边缘占比高是采样口径的性质,不是解的精度性质。本口径不做 Legendre 加权:门限 1e-6 是在无权口径下标定的(对照档案生产容差),换加权会静默改掉门限的含义;若将来确要加权版,它必须是一个新的、单独声明的量并带自己的门限重推。 |
| 方程自洽残差(芯部 / 边缘) | 分别在 ψₙ<0.8 与 ψₙ≥0.8 计算 RMS。 | ψₙ=0.8 是诊断分界,不是新物理边界;用来判断残差主要落点。整体与边缘两值高度同源(实测边缘/芯部 3.1×–45.1×,504 臂全表,产物 output/veq_tier_metric_alternatives_20260920/arms.jsonl;站点三档 126 臂为 3.1×–42.1×),不要当作两个独立证据。 |
| GS平衡缺陷(对极向积分) | 与径向 RMS 同一样本集(e = (R/J)·G,磁轴行与无效节点剔除)上的逐面有符号极向积分 I_i = Σ_j e_ij·w_j,其中 w_j = 2π/N_t 是与 veqpy Grid.integrate 一致的均匀周期权;剔除节点后不重新分配权重。后端保留有符号 I 与 I 对 ψₙ 的梯形累计 C,界面仅画|I| 对 ψₙ 的曲线,纵轴为对数坐标,标注 |I| [T],不除以 2π,不显示累计 C。e=(R/J)(α₁Gₙ₁+α₂Gₙ₂) 已含物理尺度:由 Ψ=2πα₂ψₙ 可知 α₂ 为磁通尺度,J 为 m²、G 为 Wb/m,所以 e 为 Wb/m² = T;θ 与 ψₙ 无量纲,因此 I 与 C 都为 T。内部源剖面归一化不等于该残差无量纲。 | 先有符号积分,再取绝对值,极向正负残差在求和时仍可抵消;不要改成 Σ|e|·w,也不要把此图读作 RMS。RMS 先平方,不发生正负抵消。相邻等距离的纵轴位置代表相同倍率变化;零值与无效值不画,线段在这些位置断开,不垫人为正下限。该图用于定位净缺陷的径向分布,不是与真解的误差,也不是跨档精度评分。 |
| 空间分解 | e_source=(R/J)α₁Gₙ₁;e_geometry=(R/J)α₂Gₙ₂;e_total=e_source+e_geometry。 | 通过总项、源项和几何项的正负及相消关系定位数值现象,不直接判定物理可接受性。 |
| 未平衡比例 | 总残差 RMS /(源项贡献 RMS + 几何贡献 RMS)。 | 比例低表示两个较大分量抵消更强;不是通过/失败评分。 |
| shape_diagnostics | κ、delta_top、delta_bottom、delta_average、Shafranov shift 等由实际磁面计算的量。 | 不要将输入 δ 自动当作输出几何诊断的 delta_average。 |
10.2 当前服务的求解与采样层次
当前 Studio 服务使用 SciPy lm 作为主变分求解方法;在同一冷启动下主方法失败时,VEQPy 会改用 hybr fallback。因此不应把每个返回结果都简化描述为"LM 成功"。服务有两类网格:求解网格由用户在「网格分辨率」直接选(2026-10-09 起;此前按档查表),绘图网格与之配对:
| 用途 | 规则 | 本站可表达范围内的实际取值 |
|---|---|---|
| solve grid(径向×极向) | 由「网格分辨率」直接选:16×16、32×32、64×64(2026-10-12 用户裁决改成这三档,原为 32×32 / 64×64 / 128×72;下限现为 16,不再是 32) | 按钮上写的就是实际网格 |
| plot grid | 与求解网格配对 | 16×16 → 64×128;32×32 → 64×128;64×64 → 96×192(旧档 96×96 / 128×72 同样映射到 128×256) |
网格由「网格分辨率」直接选(不再按档查表),下限 16 来自用户 2026-10-12 的裁决——注意它低于原来由实测误差预算给出的安全地板 32(docs/TOPOLOGY_GRID_TIERS_2026-09-09.md §11:32×32 在全部可表达输入下收敛,网格误差约 1e-4 m,不高于 ansatz 截断误差量级);16×16 在成形高阶算例上偏差 1.9e8,而残差与 success 对这种崩坏不报警。旧档表上量出的精度链(nearDN 中位 dq 沿 32²→64²→96²→128×72 为 1.4e-2 → 8.5e-4 → 4.7e-4 → 3.6e-4、只换网格 64²→96² 中位 1.44×、96² 重排为等点数的 128×72 再获 P6 中位 1.33×、只换系数 27→33 在 96² 上 1.43×、合起来中→高 2.21×)描述的是换网格之前的档表,没有重测;「系数这条杠杆只在网格够细时才兑现」(32² 上 0.96×、64² 上 1.06×、96² 上 1.43×)仍成立,因为它说的是网格的性质。求解网格用于主残差与汇总强形式诊断;较细的绘图网格用于展示磁面、profile 和空间残差场。服务返回 $\hat\psi=0.1,\ldots,1.0$ 的十条磁面,并在空间图中把残差组织为 total = source + geometry。空间图的磁轴正则化行不参与绘图,蓝色为负、红色为正,色标按当前分量绝对值第 95 百分位对称缩放。
10.3 「与前次案例对比」面板的读法
该面板比较"本次求解"与"上一次求解"(同一次会话内)。它只显示五张卡片:求解耗时、两次解之间:q 剖面相对差、自由度、方程自洽残差(整体)、未平衡比例。卡面只有数字;q 剖面卡的两条说明——本次运行观测到的网格依据与该档的声明精度(来自服务发布的 /meta,是档位自身的性质)——放在该卡的悬停说明里(其中"该档的声明精度"一行自 2026-10-12 换网格后读作「未知」,见下),跨档位时残差行的告诫同样如此。
说明里的各行是不同种的数:一行是这次算出来的移动量或其网格依据,另一行是代表案族的既有测量。它们不得相减、不得合并成一个数,也不得让声明值看起来像本次实测——声明值说的是"选这一档时它通常能到哪",不是"你这次的输入保证能到哪"。
| 卡片 | 语义 | 何时显示数值 |
|---|---|---|
| 求解耗时 | 本次 / 上次的墙钟耗时,涨跌百分比 | 总是 |
| 两次解之间:q 剖面相对差 (卡面只有数字,网格依据在悬停说明里) | 两次返回的 profiles.q 在共同 ρ 网格上的相对 RMS 差。它是两次解之间的差异,不是误差——只换档位时它是"加密带来的变化量",换了案例时它是"两个不同问题之差",后者没有意义 | 仅当案例未变;案例已变时显示"案例已变"。档位变化不抑制它——跨档加密正是它存在的理由 |
| 本档声明 dq (同一张卡的悬停说明,不占卡面) | 档位的声明精度,来自服务发布的 meta.topology.precision_tiers[*].measured_dq(求解器侧 PRECISION_TIERS)。它是 nearDN 代表案在该档自身网格上的中位 dq,是该档被选定时所依据的案族的测量——不是本次输入的保证,也不是这次算出来的数。历史值:同一档位在 42 案上的实测中位为 8.915e-3 / 8.627e-4 / 2.744e-4(低/中/高,与声明同量级、方向一致;低/中测于 2026-09-20 的 32²/64²,高档测于 2026-09-24 的 128×72,其 96² 时代对应值为 3.820e-4)——自 2026-10-12 起,这些数测在旧网格上,已随三档换网格(16×16 / 32×32 / 64×64)一并撤下,服务发布 measured_dq: null,该行改读作「本档声明精度未知(服务未发布该档的 measured_dq)」,补测之前一直如此 | 总是出现在悬停说明里(它是档位的性质,与两次解是否可比无关);有声明时印数,无声明时印「未知」。案例已变时上面的观测量被抑制,这一行仍在——两者不同种,不要相减、不要合并。2026-10-12 换网格后所有档都未重测,故当前读作「未知」 |
| 自由度 | 本次启用的 ansatz 系数个数(绝对事实,不做涨跌比较) | 总是 |
| 方程自洽残差(整体) | 离散解满足平衡方程的程度,不是精度 | 案例已变时显示"案例已变"(两个不同问题之间没有可比的距离);档位变化照常给涨跌百分比,并把系数个数的告诫放进该行的悬停说明 |
| 未平衡比例 | 总残差 RMS /(源项 + 几何贡献 RMS) | 同上 |
判读要点:不要用方程自洽残差的涨跌判断"哪一档更准"。实测(42 案,docs/project/veq-tier-metric-alternatives-20260920.md)该值与真误差负相关(Spearman ρ = −0.31;自由度与真误差为 Pearson r = −0.73,两者统计量不同,不可并列比较),而同期真误差改善 2.83×。要判断精度,看 q 剖面相对差(或对照归档参考解)。
正因为如此,跨档位时残差两行照常给出涨跌百分比(不再显示"档位已变"——那个词作为大字读起来等于"没有信息"),但该行的悬停说明会写明:残差量随成形谱系数个数变化,与精度不同调,不能读作变差。报告弹窗、保存的 HTML 与导出的 Markdown 没有悬停,这条告诫写在同一单元格里、以 | 与原始数值对分隔。案例变化仍然抑制数值:两个不同问题之间没有可比的距离。若档位与案例同时变化,按案例处理。
q 剖面卡的两行也不要混读:换案之后上一行会显示"案例已变"(因为两个不同问题之差没有意义),而下一行的档位声明值仍然在——这正是两者种类不同的直接体现。声明值的口径与限制写在该行悬停提示里:nearDN 代表案中位、42 案族、非本次输入的保证。
10.4 推荐的阅读顺序
面对一次结果,建议按下面顺序判断,而不是只看一个绿色状态或一个很小的数:
- 先核对 provenance。有效 c/s 数组是否正是自己提交的边界?δ 是否按 s1a=asin(δ) 转换成预期 s1a?topology 与 packed count 是否符合预期?
- 再看求解状态和 projected residual。它们回答"选定的有限维投影问题是否被求解器良好处理"。
- 查看方程自洽残差与空间诊断。它们回答"未被投影条件直接控制的逐点残差在何处较大",不回答"离真值多远"。
- 查看几何与 profile。尤其不要将输入 δ 自动当作输出几何诊断的 delta_average。
- 最后做任务相关判断。若要更细的内部形变,可提高档位或导入更高的对应 profile count;若增加后方程自洽残差/几何诊断仍不理想,需要判断是表示截断、源项设定、坐标可容许性,还是求解失败,而不是只把 count 继续调大。
11. 用四个小例子串起输入和输出
11.1 例 1:低档 topology
低档预设为 psin(6), h(3), k(6), s1(3)(阶梯的起点),packed vector 共 18 个分量,其余 count 全为零。此时:
- LCFS 仍由 $R_0,Z_0,a,\kappa_a$ 及
c/s边界数组规定; - 求解器优化通量映射、径向偏移、拉长比与一阶 shaping 的内部系数,内部磁面可形成 Shafranov 位移;
- 其余几何 profile($v$、$c_0$、高阶 $c/s$)没有可调内部修正;
- 这适合作为确认边界、源项和基本求解流程的基线,但它不是"已经自动达到全部形状自由度"的声明。
11.2 例 2:Compact counts(导入文件)
Compact 预设已不在界面档位中,但导入使用 psin(4), h(2), k(4), s1(2) 的参数文件时,三档均不选中,仍按文件保留这组系数个数,packed count 为 12。这意味着除了径向通量映射外,求解器还可调:
- 两个 $h$ 的内部系数,改变内部磁面的径向偏移;
- 四个 $\kappa$ 的内部修正系数,改变拉长比的径向演化;
- 两个 $s_1$ 的内部修正系数,改变一阶 MXH shaping 的径向演化。
但这些修正因 $(1-\rho^2)$ 在 LCFS 消失,不能推翻已给定的 LCFS 值。
11.3 例 3:显式 s1a 与高阶边界 harmonics
界面不再直接输入 s1a;显式 s1a 与高阶 c/s 边界项来自导入参数文件,或由「手动设定外形曲线」(含「坐标输入」)拟合一次给出。此时:
s1a是 native MXH boundary coefficient,同时按 $\delta=\sin(s_{1a})$ 回写界面上的delta;- 解后
delta_top/bottom/average由实际磁面极值计算,未必等于任何预先输入的单一delta; - 若导入文件还启用 Ns1、Ns2 等内部 count,它们控制的是这些 harmonics 如何在径向上进一步调整,不会把边界值变成"可优化变量"。
这正是边界值、内部自由度、适配层派生值和诊断输出必须分开理解的原因。
11.4 例 4:GAQ 族 + 目标 βₜ
把剖面族切到 GAQ 族(下拉框的第一个选项;选中后输入框内部靠右分拆出预设选择框,可用「自定义」直接给指数),给它四个形状指数(例如 nₚ = 2.5、mₚ = 1、n_f = 2、m_f = 1.5,都在采样盒内),再点源项区驱动量变量名右侧那枚 ↻ 小按钮切到 βₜ 目标态(那一格数字框原地不动,名字从 Iₚ 变作 βₜ),在里面填一个数。注意这次求解不提交 Iₚ——两者字面互斥,服务端按它自己声明的默认电流(3 MA)求解,屏上 Iₚ 框里留的数不参与(这句话写在悬停说明里,屏上没有常驻文字)。此时:
- 压力与电流两个源通道的形状分别由 (nₚ, mₚ) 与 (n_f, m_f) 给出,边界条件由 $\psi_N = 1$ 处 $g = 0$ 自动满足,不需要额外施加;
- 服务端启动外层迭代:先在 5 个固定的 fₚ 点上各解一次(粗扫),再看目标是否落在这些达成值之间;落在其中就继续二分,直到相对误差不超过 10⁻³,或预算(合计 16 次完整平衡求解)耗尽而判定为未命中;
- 命中的那一点会被重解一遍,所以响应里带回来的是一份完整的解(磁面、剖面、诊断、快照、manifest),而不只是迭代过程中那条只有聚合量的记录;
- 导出的 manifest 里会多出 βt 的目标值、达成值与带符号的相对误差,供事后核对;compact JSON 的键一个都没变。
若填的目标超出该工况的实测可达范围,返回的不是一份「差一点」的解,而是 422 加一段实测可达区间与完整迭代历史——先看区间,再决定是换目标,还是改工况参数去改变可达范围。
12. 常见问题与下一步
| 现象 | 可能原因 | 建议操作 |
|---|---|---|
| 求解器不收敛 | 参数组合不适合当前表示,或一次改变太多变量。 | 先回到默认输入或装置预设的「默认值」确认流程;从低档基线开始,每次只改一项,并检查求解警告。 |
| packed count 超限 | 导入文件的 count 总和超过 512(界面档位本身不会超限)。 | 减少部分 profile 的 count 后重新导入;以 Full 预设的 36 作为复杂度参考,而不是盲目接近上限。 |
| 磁通面交叉或扭曲 | 内部自由度过高、边界/源项不兼容,或求解未可靠收敛。 | 退回低档基线;确认边界预览,再逐项提高自由度。 |
| 输入 δ 与 delta_average 不同 | 高阶 LCFS c/s 系数改变实际磁面极值。 | 检查高阶系数;若需要直接控制角映射,导入显式 s1a 文件,或在「手动设定外形曲线」里给出坐标曲线后保存。不要把该差异自动视为错误。 |
| 「手动设定外形曲线」拟合 RMS 较大 | 控制点本身不自洽(回绕、重复行),或曲线不适合当前截断。 | 保存时会按点的外接框自动改写 R₀、Z₀、a、κ,所以尺度不匹配这一层已经由保存步骤兜住;剩下的多半是点集问题——检查坐标后重新保存。拟合仅是转换为当前 MXH 输入的本地便利工具,不是完整边界反演。 |
| 加载后结果不同 | 输入版本不兼容、后端版本变化或 provenance 不匹配。 | 确认使用同一 VEQ Studio 版本;保存报告并核对 provenance 中的版本、边界、模式和 topology。 |
| 提示「目标 βₜ 不可达」并返回 422 | 目标落在该工况的实测可达范围之外。 | 看响应里给出的实测可达区间,换一个落在这个区间内的目标;或者调整工况参数,改变可达范围本身。不要指望服务会返回一个「最接近」的边界值。 |
| 上传的剖面文件被拒绝 | 行列格式不对、ψₙ 未覆盖 [0, 1] 或非严格递增、g 有负值、或节点数越界。 | 对照 §8.2 中逐点导入族的四条契约逐条核对:首末点须为 ψₙ = 0 与 1、ψₙ 严格递增、g ≥ 0 且不全为零、节点数 3–32。 |
| GAQ 形状指数被拒绝 | 某个形状指数超出采样盒。 | 对照 §8.2 表中的上下限:nₚ ∈ [1, 2.5]、mₚ ∈ [1, 2]、n_f ∈ [1.5, 3]、m_f ∈ [1, 1.8]。 |
| 点击「求解」提示「节点元数据未载入」 | 本页的 /meta 没有取到(后端不可达、网关路由错误或超时)。边界系数宽度、取值上下限、拓扑上限与装置目录都来自它,缺了它下面的输入无法校验。 | 确认后端可用后刷新页面重试——这是服务/网关侧问题,不是输入问题,改参数绕不过去。页面在加载失败时也会在顶部先给出「计算服务不可用」。 |
13. 总结:四条可迁移的计算数学原则
- 将边界条件编码进表示。$(1-\rho^2)$ 使内部修正在 $\rho=1$ 消失,因此固定 LCFS 不依赖于迭代时反复强加。
- 将 topology 与 coefficient values 分开。count 是离散模型选择;真正的 Chebyshev 系数是连续未知量;LCFS MXH 系数则是固定边界数据。
- 区分弱/投影条件与逐点强形式。$A^TWg=0$ 是所选有限维问题的方程,不能替代对 $G_{\rm std}$ 的检查。
- 把诊断当作解释工具,而不是单一证书。HTTP 成功、solver convergence、projected residual 小、方程自洽残差可接受、几何满足目标,是不同层次的事实;方程自洽残差回答"离散解满足不满足方程",不回答"解离真值多远"。
如果只记住一句话:VEQ Studio 上方的 LCFS MXH 输入定义"边界长什么样";下方的内部 profile counts 决定"允许用多少个内部自由度去求解它";求解后的 shape diagnostics 与「与前次案例对比」面板里的 q 剖面相对差则回答"这种有限表示是否足以支撑当前结论";residual 只回答"离散解满足不满足方程"。
14. 理论与建模参考
界面字段、报告指标和本手册以当前 VEQ 实现为准;以下文献提供 Grad–Shafranov 平衡、托卡马克平衡、参数化位形和实验重建的理论背景。引用或比较结果时,应同时写明边界条件、归一化、topology 与数值假设。
- Grad, H.; Rubin, H. Hydromagnetic Equilibria and Force-Free Fields. Proceedings of the 2nd United Nations International Conference on the Peaceful Uses of Atomic Energy, 1958, Vol. 31, pp. 190–197.
- Shafranov, V. D. Plasma Equilibrium in a Magnetic Field. Reviews of Plasma Physics, Vol. 2, 1966, pp. 103–151.
- Freidberg, J. P. Ideal MHD. Cambridge University Press, 2014. Chapters on axisymmetric equilibrium and stability.
- Wesson, J. Tokamaks. 4th ed., Oxford University Press, 2011. Chapters 3–4.
- Lao, L. L. et al. "Reconstruction of Current Profile Parameters and Plasma Shapes in Tokamaks." Nuclear Fusion 25 (1985): 1611–1622. DOI: 10.1088/0029-5515/25/11/007.
- Miller, R. L. et al. "Noncircular, Finite Aspect Ratio, Local Equilibrium Model." Physics of Plasmas 5 (1998): 973–978. DOI: 10.1063/1.872666.
- Arseniev, A. A.; Bateev, S. V.; Kornev, V. A. "Equilibrium Configuration of Tokamaks." Plasma Physics and Controlled Fusion 40 (1998): 1045–1056. DOI: 10.1088/0741-3335/40/9/002.
- Lu, H. et al. "A Generalized Miller Equilibrium Model for Tokamak Plasma." Physics of Plasmas 31 (2024).
- Zhang et al. VEQ: a fast parametric Grad–Shafranov solver. arXiv:2606.11821 (2026).
- Xie & Li. What Is the Minimum Number of Parameters Required to Represent Solutions of the Grad–Shafranov Equation? arXiv:2601.02942 (2026).
实现层面的对应代码:products/veq-studio/veq_service/topology.py、solver_adapter.py 与 web/veq.js。