横向场求解器
概念介绍
PASS.commands.solver 提供 SpaceCharge 使用的数值计算层。它刻意不依赖
Simulation 或 PASS 粒子类:PIC 调用者提供横向粒子数组、切片 ID、均匀网格和
单个宏粒子的电荷;解析求场则直接使用坐标、电荷与分布参数。因此同一套接口可以用于命令执行、自动测试和独立场计算。
代码位置:
PASS/commands/solver/PIC 入口:
PASS/commands/solver/pic.py底层 PIC 求解器标识:
fd、dst_rectangle、fft_free_space解析跟踪入口:
PASS/commands/solver/analytic.py数组顺序:批量网格数据使用
(slice, y, x)计算后端:CPU 上的 NumPy/SciPy
数值层只负责横向场问题,不读取作用长度、束流磁刚度、相对论踢因子或模拟圈数; 这些属于 空间电荷效应(SpaceCharge) 的职责。
公开配置使用 Method 和 Solver。Method="pic" 时,
fd_dirichlet、dst_dirichlet、fft_free_space 分别分派到底层
fd、dst_rectangle、fft_free_space。下文数值 API 中的标识是
build_pic_resources 的底层参数。其中 fft_free_space 与公开 JSON 的
Solver 值相同;FD 和 DST 在这两个接口中的标识不同。
frozen 和 quasi-frozen 使用后文介绍的解析分布。
PIC 数据流
一次调用依次执行:
粒子的 x、y、tag 和 slice_id
|
v
CIC 或 TSC 电荷沉积
|
v
Sigma[slice, y, x],单位 C/m^2
|
v
批量 Poisson 场求解
|
v
Psi 单位 V m,积分 Ex/Ey 单位 V
|
v
使用配对的 CIC 或 TSC 权重回插
全部纵向切片作为前导右端项一起求解。几何 mask、稀疏矩阵分解、谱特征值或 FFT
核在 PICResources 中只构建一次,之后重复使用。
网格与源项
均匀节点网格
GridGeometry 描述均匀的节点型矩形网格。顶层空间电荷输入通过全宽
\(W_x\) 和 \(W_y\) 定义
Nx 和 Ny 是节点数而不是网格单元数,且都必须至少为 3。配置和
build_grid_geometry 均只接受完整全宽或 Grid Half Width X/Y (m) 半宽
输入,半宽满足 \(W_x=2H_x,W_y=2H_y\)。两组不能混用;拒绝 Dx/Dy
间距或显式上下界映射输入。数值代码仍可直接构造 GridGeometry(...)。
电荷沉积
对每个切片 ID 有效的存活粒子,沉积方法把带符号电荷分配到有效场节点:
方法 |
每粒子节点数 |
配对回插 |
特点 |
|---|---|---|---|
|
2 x 2 |
双线性 |
根据粒子所在网格单元使用分段线性权重。 |
|
3 x 3 |
二次 |
使用更宽的二次权重,粒子—网格耦合更平滑。 |
沉积 stencil 会去除导体和边界节点,再逐粒子归一化剩余权重,从而守恒该粒子的 沉积电荷;回插过程使用相同的有效节点归一化。边界修改 stencil 时会记录 warning。 如果区域内粒子找不到任何有效节点,本次 PIC 调用将忽略它并回插零场,但不会修改 PASS 粒子 tag。
tag <= 0、切片 ID 无效,或位于网格/物理孔径之外的粒子也会被忽略。因此网格
和孔径尺寸应覆盖需要跟踪的粒子分布。
这些独立 PIC 函数不修改粒子 tag。SpaceCharge 先调用共享孔径损失函数,
在沉积前将命令孔径上和孔径外的粒子标记为损失。此后存活的参与粒子若超出网格,
或没有有效 stencil 节点,则报错。初始化校验和命令约定见 空间电荷效应(SpaceCharge)。
Poisson 方程与单位
每个求解器读取单位为 C/m2 的沉积面密度 \(\Sigma_k\),并求解
由于切片电荷已沿纵向积分,\(\Psi\) 的单位是 V m,
\(\mathcal E_x,\mathcal E_y\) 的单位是 V。这里返回的是积分场而不是 V/m
单位的平均场;SpaceCharge 在计算踢之前用回插场除以该切片的 delta_z。
场求解器选择
底层 |
边界模型 |
支持的孔径 |
数值方法与适用场景 |
|---|---|---|---|
|
零 Dirichlet 导体 |
完整网格矩形或任意受支持的连续孔径 |
缓存稀疏 LU 分解。完整矩形使用规则五点差分;曲线或斜边界附近使用 Shortley–Weller 距离。 |
|
零 Dirichlet 导体 |
仅完整且与网格对齐的矩形 |
使用缓存特征值的 I 型离散正弦变换,是 |
|
开放自由空间 |
仅完整网格,不允许导体孔径 |
使用缓存 Green 函数核的零填充 Hockney 线性卷积;适用于不考虑导体镜像 电荷的情况。 |
有限差分:fd
完整矩形区域使用规则五点差分:
外层网格节点固定为 \(\Psi=0\)。显式孔径与完整网格相同时仍使用矩形求解器。 其他连续孔径使用 Shortley–Weller 求解器。如果相邻节点位于孔径外,规则步长会替换为有效节点沿 网格线到物理壁交点的实际距离,因此物理边界不是简单的阶梯状节点 mask。
稀疏矩阵和 LU 分解只构建一次;所有切片作为多列右端项交给同一个分解求解。
正弦变换:dst_rectangle
dst_rectangle 在四条外网格边界上施加零电势。I 型离散正弦变换将同一个矩形
有限差分算子对角化。水平模 \(m\) 和垂直模 \(n\) 的特征值为
变换只作用于两个横向轴,保留前导切片轴。该求解器无法表示曲线导体或网格内部的 较小导体边界。
自由空间 Green 函数:fft_free_space
fft_free_space 进行零填充线性卷积,从而避免未填充 FFT 的周期回绕。除自单元外,
卷积核为
自单元的核值设为零。电势采用核参考,只在加性常数意义下确定;横向场才是主要 物理输出。该求解器描述开放自由空间,不描述接地束流管。
源电荷做一次正向实数 FFT;每个请求的输出做一次逆变换,因此只计算电场需要
两次逆变换,再计算电势则需要第三次。FFTFreeSpaceSolver.solve 默认返回全部
三个输出;设置 compute_potential=False 时返回 potential=None 并跳过
电势变换。电势核仅在首次请求电势时建立并缓存。逆变换共用一个频谱工作数组;
返回数组只保留实际网格,释放较大的补零数组。
solve_pic、pic_cpu 和 solve_poisson_fft_free_space 也提供这个可选参数。
FD 和 DST 仍计算电势,因为其电场需要电势梯度。SpaceCharge 命令只在启用
Save potential 且当前圈被选中输出时,请求 FFT 电势。
场梯度
完整矩形 fd 和 dst_rectangle 通过网格有限差分计算
E = -grad(Psi)。Shortley–Weller fd 在壁面附近的有效节点使用不等距导数
系数;fft_free_space 则直接与解析场核卷积。
孔径接口
SC 命令定义损失孔径,并在 FD/DST 中同时定义导体壁,配置不再包含 Chamber。
例如在命令内填写:
"Aperture type": "ellipse",
"Aperture value": [0.04, 0.02]
内部转换为 {"Type": "ellipse", "Value": [0.04, 0.02]} 传给 FD 的
aperture 参数。FFT 不接收导体孔径,命令孔径仅用于粒子损失。下表描述共享
底层几何构造器,尺寸单位均为 m。通用 default 与 SC 不同:SC 调用构造器前
将 default 解析为实际网格矩形,并禁止 Dirichlet 使用 off。
类型 |
|
几何定义 |
|---|---|---|
|
省略 |
不设置独立物理孔径;对 |
|
省略 |
跟踪默认矩形 \(|x|\leq1\)、\(|y|\leq1\)。 |
|
|
半径为 \(R\) 的圆。 |
|
|
\(|x|\leq A\)、\(|y|\leq B\) 的矩形。 |
|
|
椭圆 \(x^2/A^2+y^2/B^2\leq1\)。 |
|
|
半宽/半高为 \((W,H)\) 的矩形与半径 \(R\) 的圆的交集。 |
|
|
矩形 \((W,H)\) 与椭圆 \((A,B)\) 的交集。 |
|
|
中央半宽/半高为 \((W,H)\),两侧为半轴 \((A,B)\) 的水平 椭圆端帽。 |
|
|
满足 \(|x|\leq W\)、\(|y|\leq H\) 和 \(|x|+|y|\leq W+H-D\) 的对称八边形。 |
|
|
至少三个有限顶点且面积非零的多边形。 |
底层还接受 circular、elliptic 和 rectangular 别名。Python 孔径
构造器也支持命名参数,但生成的输入文件建议使用上表格式。
对 dst_rectangle 和 fft_free_space,孔径必须精确等价于完整且与网格对齐的
矩形,通常应设置为 null。对 fd,物理孔径应在所选网格中得到充分表示;
SC 初始化器会拒绝超出网格的有限 PIC 孔径,并拒绝与完整矩形不同的 DST 孔径,
因此不会将过大的命令孔径静默截断为网格导体。
Python 接口
网格与 PIC 流水线
接口 |
主要参数 |
返回值与行为 |
|---|---|---|
|
|
不可变均匀网格描述,提供 |
|
节点数,加完整全宽或半宽输入 |
构建中心为零的 |
|
网格和连续孔径映射 |
返回节点是否属于孔径的布尔 mask。 |
|
|
返回可复用 |
|
particles、 |
分派到 CIC 或 TSC,返回 |
|
particles、 |
沉积并批量求解全部切片,返回 |
|
场、粒子、网格、资源、 |
使用 CIC 权重回插一个或多个场。 |
|
场、粒子、网格、资源、 |
使用 TSC 权重回插一个或多个场。 |
|
数组 |
|
particles 可以是映射,也可以是具有同形 x、y 数组及可选 tag
的对象。charge_per_macro 可以是有限标量或可广播到粒子形状的数组。
slice_id 必须是每粒子一个元素的整数数组。显式提供 num_slices 可在结果中
保留尾部空切片。
求解器构建器与一次性封装
构建器 |
可复用求解器 |
一次性封装 |
|---|---|---|
|
|
|
|
|
|
|
|
调用 |
|
|
|
重复计算时应优先使用构建器加 solver.solve,以便复用缓存资源。
结果对象
对象 / 字段 |
形状 |
单位 |
说明 |
|---|---|---|---|
|
|
C/m2 |
沉积电荷密度。 |
|
|
C |
每个切片保留的电荷。 |
|
|
每个切片成功沉积的宏粒子数。 |
|
|
二维、三维或 |
V m |
积分电势;FFT 只求电场而省略电势时为 |
|
二维或三维 |
V |
横向积分场; |
|
批量 |
混合 |
汇总密度、电势、场、网格、沉积电荷及沉积诊断。 |
场求解器接受 (ny, nx) 单切片数组,或 (n_slice, ny, nx) 批量数组。
所有值必须有限,末两维必须与求解器网格一致。
解析跟踪与参考场
formula_* 模块提供自由空间解析积分场,用于 frozen、quasi-frozen
跟踪,同时保留参考计算用途。公开 solver 名称为 gaussian_round_free_space、
gaussian_ellipse_free_space、uniform_round_free_space、
uniform_ellipse_free_space。直接在粒子位置计算,不经过 PIC 流水线。
源电荷、坐标与单位
四种分布都求解单个带电切片的横向自由空间问题。以 Q 表示切片带符号总电荷(C), (u, v) 表示源分布主轴坐标。命令先处理孔径损失,由当前存活且已分配到切片的粒子 计算 Q,再进行中心平移和旋转:
其中 R 为 bunch.ratio,Z 为带符号电荷数,N_k 为切片存活宏粒子数。
下列密度均为纵向积分后的面电荷密度,单位 C/m2,在整个横向平面的积分
等于 Q。场是单位为 V 的积分场;SpaceCharge 除以 delta_z 得到 V/m,
再单独施加相对论踢。公式函数本身不包含 delta_z 或 1/gamma² 因子。
分布中心和尺寸描述束流,不是管壁。自由空间公式不包含导体镜像场;命令孔径仅判断 粒子损失,缺省值为网格矩形。诊断采样不会截断或重新归一化解析模型。即使发生损失, frozen 高斯仍使用指定的完整高斯形状与更新后的 Q,并非孔径截断高斯的精确场。
圆高斯:gaussian_round_free_space
formula_gaussian_round.gaussian_round_field 使用单轴 RMS 尺寸 sigma,
对应 frozen 配置的 Sigma (m):
原点处两个场分量均为零;乘在 (u, v) 前的标量因子极限为
Q/(4 pi epsilon_0 sigma²),因此束心附近场为线性。实现使用
-expm1(-r²/(2 sigma²)) 避免相近数相减。远场按 1/r 衰减,径向场趋于
Q/(2 pi epsilon_0 r),方向由 Q 的符号决定。
椭圆高斯:gaussian_ellipse_free_space
formula_gaussian_ellipse.gaussian_elliptic_field 使用两个主轴方向的单轴
RMS 尺寸 sigma_u、sigma_v,对应 frozen 的 Sigma X/Y (m):
当 sigma_u > sigma_v 时,PASS 在第一象限计算 Bassetti–Erskine 公式,
其中 Faddeeva 函数使用 scipy.special.wofz:
sigma_u < sigma_v 时交换坐标、尺寸及返回的场分量;尺寸相等时退化为圆高斯,
数值上使用 np.isclose(sigma_u, sigma_v, rtol=const.eps, atol=0) 判断。
束心附近的一阶项为
实现还包含束心附近的三次修正;数值稳定性处理见下方 Python 接口表后的说明。
均匀圆盘:uniform_round_free_space
formula_uniform_round.uniform_round_field 的 R_b 是束流外半径,
对应 Radius (m),不是 RMS 尺寸:
束内场为线性,束外场按 1/r 衰减,在 r=R_b 处连续。该均匀圆盘的单轴 RMS 尺寸为 R_b/2。源分布边缘与命令物理孔径壁是不同概念;公式在分布边缘求值本身 不会将粒子标记为损失。
均匀椭圆:uniform_ellipse_free_space
formula_uniform_ellipse.uniform_elliptic_field 使用束流半轴 a、b,
对应 Semi-axis A/B (m),单轴 RMS 尺寸分别为 a/2、b/2:
束内 A=a、B=b,场为线性;束外 lambda 为共焦椭圆方程的正根。 实现使用避免相消的二次方程求根表达式,并采用上述有理化场表达式,保证 a、b 接近时的数值稳定性。场在分布边缘连续,a=b 时退化为均匀圆盘。
frozen 与 quasi-frozen 的参数选择
frozen 中,引用同一配置的全部切片共用固定中心、方向和尺寸;中心与角度
缺省为零,对应 solver 的尺寸必须填写。Q 和 delta_z 始终采用当前值,
所以冻结横向形状不等于冻结场强。
quasi-frozen 在每次 kick 时重新计算各切片的总体矩:
特征值满足 nu_1 >= nu_2,nu_1 对应的特征向量确定长轴角度。统计分母使用 N_k 而非 N_k-1。圆化规则保留径向二阶矩,非圆粒子也可采用,但不会精确重建 非圆源的场。均匀模型近似均匀横向投影密度,并不把实际粒子变成 KV 分布。
空切片返回零场。非空 quasi-frozen 圆切片至少需要两个粒子且径向方差为正;
椭圆切片至少需要三个粒子,且 nu_2 > 64 * float64_epsilon * nu_1。
无效统计量会报错。切片编号与宽度由用户独立提供,不检查 Slicer 执行或圈数历史。
直接调用公式示例
下例先计算积分场,再换算切片平均场。输入坐标已位于源分布坐标系:
import numpy as np
from PASS.commands.solver.formula_gaussian_ellipse import gaussian_elliptic_field
x = np.linspace(-0.02, 0.02, 201) # m, relative to the source center
ex_integrated, ey_integrated = gaussian_elliptic_field(
x, np.zeros_like(x), slice_charge=1e-9,
sigma_x=0.003, sigma_y=0.002,
)
delta_z = 0.01 # m
ex_average = ex_integrated / delta_z # V/m
用于追踪时,以 Method="frozen" 或 "quasi-frozen" 配合对应公开
Solver;JSON 示例及命令孔径默认值见 空间电荷效应(SpaceCharge)。
tests/integration/space_charge/test_analytic_free_space_tracking.py 使用
独立场积分核对真实粒子踢量。运行
python -m tests.integration.space_charge analytic 可执行这些比较和重复 kick
参数演化检查,并生成对应图片。
Python 接口与数值稳定性
solve_analytic(x, y, slice_id, valid, num_slices, charge_per_macro,
configuration) 按切片组织已分配且存活的粒子。frozen 参数来自配置,
quasi-frozen 参数来自各切片当前总体矩。AnalyticResult 包含粒子长度的
integrated_ex/integrated_ey、切片电荷与计数,以及 (n_slice, 5)
参数数组;列依次为中心 x、中心 y、尺寸 x、尺寸 y、角度。
尺寸是高斯 RMS 或均匀分布半轴。空切片参数为 NaN,场和电荷为零。
不读取模拟圈数或 Slicer 执行元数据。具体矩匹配规则见 空间电荷效应(SpaceCharge)。
sample_analytic_grid(result, configuration, geometry) 在粒子场计算完成后,
采样诊断网格上的密度和场,返回 potential=None 的网格结果;当前命令拒绝解析
电势输出。采样网格不决定粒子 kick,也不截断解析电荷分布。
函数 |
分布参数 |
返回值 |
|---|---|---|
|
|
圆高斯分布的积分 |
|
|
Bassetti–Erskine 积分场,单位 V;
|
|
|
均匀圆切片束内外的积分场。 |
|
|
均匀椭圆切片束内外的积分场。 |
|
真实粒子数、带符号电荷数 |
带符号物理电荷,单位 C。 |
所有解析函数都支持标量或可广播坐标数组,尺寸参数必须为正有限值;未显式覆盖时
使用 PASS 常量中的 epsilon_0。
均匀椭圆场使用共焦半轴 \(A=\sqrt{a^2+\lambda}\)、 \(B=\sqrt{b^2+\lambda}\),按等价表达式 \(\mathcal E_x=Qx/[\pi\epsilon_0 A(A+B)]\)、 \(\mathcal E_y=Qy/[\pi\epsilon_0 B(A+B)]\) 计算。 椭圆内部 lambda 为零,外部使用非负共焦参数。这一有理化形式避免两半轴趋于相等时 的相消误差,也适用于 quasi-frozen 中接近各向同性的切片。
椭圆高斯公式在第一象限计算,再利用反射对称性恢复场分量符号,以避免下半平面
Faddeeva 函数的指数增长及大数相减,近圆束尤其需要这一处理。宽度平方差写为
(sigma_x - sigma_y) * (sigma_x + sigma_y),保留已有圆束极限及坐标轴交换约定。
在束心附近,稳定半平面的两项仍可能几乎抵消;当
(x/sigma_x)**2 + (y/sigma_y)**2 <= 1e-6 时使用场的三次展开,其相对截断误差
为该归一化半径平方的平方量级。
高效网格数建议
这里 N 是包含两端点的节点数,宽度 W 对应间距 h = W/(N-1)。
首先确定物理范围和所需分辨率。下表是在各个规模附近便于选择的起点,并非所有
硬件上的绝对最快值;两个方向分别应用相应规则。
目标规模 |
FD 基准 |
DST 节点数 |
FFT 节点数 |
FFT 补零尺寸 |
|---|---|---|---|---|
128 |
约 128 |
129 |
128 |
256 |
256 |
约 256 |
257 |
256 |
512 |
512 |
约 512 |
513 |
512 |
1024 |
1024 |
约 1024 |
1025 |
1024 |
2048 |
2048 |
约 2048 |
2049 |
2048 |
4096 |
DST-I 的内部长度为 N-2,对应逻辑变换长度 2*(N-1),因此
N = 2**k + 1 是便利的取值系列。更一般地,N-1 只有较小质因子时通常
更有利;二次幂不是唯一的快速长度。
FFT 格林函数卷积对每个方向补零至
P = scipy.fft.next_fast_len(2*N-1)。在表中规模下,选择 N = 2**k
对应 P = 2**(k+1)。邻近节点数也可能较快,应在分辨率相近时实测比较。
补零用于避免循环卷积回绕,不扩大物理网格范围。
FD 使用稀疏矩阵分解,没有二次幂尺寸的特殊优势。应选择满足几何与收敛要求的
最小节点数,例如 N >= ceil(W/h_max) + 1;需要中心线上恰好有节点时可选
奇数。表中的 FD 列只是分辨率基准,2048×2048 的稀疏分解可能需要很大内存。
对于完整的接地矩形,DST 求解相同的离散泊松系统,且无需稀疏 LU 因子。
PASS 保留用户显式配置的节点数。
选择建议与限制
接地导体腔体使用
fd,曲线、多边形或复合孔径尤其应选此方法。完整矩形网格恰好就是接地导体腔体时,可使用
dst_rectangle。不需要导体镜像电荷的开放边界近似使用
fft_free_space。开放边界计算应增加网格范围,直到场对截断不敏感;所有求解器都应增加分辨率, 直到场和踢的观测量收敛。
CIC 更局部、计算量较小;TSC 使用更宽 stencil,耦合更平滑。沉积与回插方法 必须配对。
当前 solver 包仅支持 CPU;GPU 后端不能执行非零且已启用的
SpaceCharge。