1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
use nalgebra_sparse::CscMatrix;
use num_complex::Complex64;
pub struct JacobianPattern {
pub nnz_j: usize,
pub j_col_ptrs: Vec<usize>, // 长度: n_active + npq + 1
pub j_row_indices: Vec<usize>, // 长度: nnz_j
// Ybus 拓扑切刀缓存 (热循环的“路标”,消灭运行时计算)
pub pv_ends: Vec<usize>, // 长度: npv + npq
pub pq_ends: Vec<usize>, // 长度: npv + npq
// 区块一维内存绝对起点
pub j11_starts: Vec<usize>, // 长度: npv + npq
pub j21_starts: Vec<usize>, // 长度: npv + npq
pub j12_starts: Vec<usize>, // 长度: npq (极度压缩,仅PQ)
pub j22_starts: Vec<usize>, // 长度: npq (极度压缩,仅PQ)
// 对角线元素在 Ybus 原始 values 数组中的绝对指针
pub diag_ptrs: Vec<usize>, // 长度: npv + npq
}
impl JacobianPattern {
pub fn build_from_permuted(
y_col_ptrs: &[usize],
y_row_indices: &[usize],
npv: usize,
npq: usize,
) -> Self {
let n_active = npv + npq;
let n_j_cols = n_active + npq; // 相角列 (PV+PQ) + 幅值列 (仅PQ)
let mut j_col_ptrs = Vec::with_capacity(n_j_cols + 1);
let mut j_row_indices = Vec::new();
j_col_ptrs.push(0);
let mut pv_ends = vec![0; n_active];
let mut pq_ends = vec![0; n_active];
let mut j11_starts = vec![0; n_active];
let mut j21_starts = vec![0; n_active];
// 绝杀:内存严格对齐物理语义,拒绝浪费!
let mut j12_starts = vec![0; npq];
let mut j22_starts = vec![0; npq];
let mut diag_ptrs = vec![0; n_active];
let pq_boundary = npv + npq;
let mut current_nnz = 0;
// ==========================================
// 阶段 1: 推演所有的 相角(θ) 列 (共 n_active 列)
// ==========================================
for k in 0..n_active {
let start = y_col_ptrs[k];
let end = y_col_ptrs[k + 1];
let row_slice = &y_row_indices[start..end];
// 你的绝技:利用预排列,二分直接切出物理边界!
let idx_pv_end = row_slice.partition_point(|&r| r < npv);
let idx_pq_end = row_slice.partition_point(|&r| r < pq_boundary);
pv_ends[k] = idx_pv_end;
pq_ends[k] = idx_pq_end;
// O(log N) 顺手锁定对角线指针
if let Ok(diag_idx) = row_slice.binary_search(&k) {
diag_ptrs[k] = start + diag_idx;
}
// --- 写入 J11 结构 (对应 P 方程,涵盖 PV 和 PQ 目标行) ---
j11_starts[k] = current_nnz;
for offset in 0..idx_pq_end {
// 行号不变,P 方程的行索引就是 0..n_active
j_row_indices.push(row_slice[offset]);
}
current_nnz += idx_pq_end;
// --- 写入 J21 结构 (对应 Q 方程,仅涵盖 PQ 目标行) ---
j21_starts[k] = current_nnz;
for offset in idx_pv_end..idx_pq_end {
let r = row_slice[offset];
// 核心映射:Q 方程所在的行被统一推移到了 P 方程下方
j_row_indices.push(n_active + r - npv);
}
current_nnz += idx_pq_end - idx_pv_end;
j_col_ptrs.push(current_nnz);
}
// ==========================================
// 阶段 2: 推演所有的 幅值(Vm) 列 (仅 npq 列)
// ==========================================
for k in npv..n_active {
let pq_idx = k - npv; // 压缩寻址坐标
let start = y_col_ptrs[k];
let row_slice = &y_row_indices[start..y_col_ptrs[k + 1]];
// 直接复用阶段 1 切好的物理边界,极致压榨算力!
let idx_pv_end = pv_ends[k];
let idx_pq_end = pq_ends[k];
// --- 写入 J12 结构 ---
j12_starts[pq_idx] = current_nnz;
for offset in 0..idx_pq_end {
j_row_indices.push(row_slice[offset]);
}
current_nnz += idx_pq_end;
// --- 写入 J22 结构 ---
j22_starts[pq_idx] = current_nnz;
for offset in idx_pv_end..idx_pq_end {
let r = row_slice[offset];
j_row_indices.push(n_active + r - npv);
}
current_nnz += idx_pq_end - idx_pv_end;
j_col_ptrs.push(current_nnz);
}
Self {
nnz_j: current_nnz,
j_col_ptrs,
j_row_indices,
pv_ends,
pq_ends,
j11_starts,
j21_starts,
j12_starts,
j22_starts,
diag_ptrs,
}
}
}
#[allow(non_snake_case)]
#[inline(never)] // 保持独立函数,方便 LLVM 专注优化硬件寄存器分配与 AVX 向量化
pub fn fill_jacobian_ultimate(
Ybus: &CscMatrix<Complex64>,
v: &[Complex64],
Vnorm: &[Complex64],
ibus: &[Complex64],
pattern: &JacobianPattern,
npv: usize,
npq: usize,
j_values: &mut [f64],
) {
let y_col_offsets = Ybus.col_offsets();
let y_row_indices = Ybus.row_indices();
let y_vals = Ybus.values();
let n_active = npv + npq;
// 彻底重置目标数组(保证未触及区域如 PV 的 Q 项物理清零)
//j_values.fill(0.0);
for k in 0..n_active {
let y_start = y_col_offsets[k];
let pv_end = pattern.pv_ends[k];
let pq_end = pattern.pq_ends[k];
// --- 循环不变量外提:解包当前列节点 k 的电学状态到寄存器 ---
let ek = v[k].re;
let fk = v[k].im;
let enk = Vnorm[k].re;
let fnk = Vnorm[k].im;
let Ire_k = ibus[k].re;
let Iim_k = ibus[k].im;
// 静态锁定对角线元在当前列一维 Ybus values 中的相对偏移量
let diag_offset = pattern.diag_ptrs[k] - y_start;
// =====================================================================
// 第一幕:相角 (Va) 导数盲填流 —— 覆盖 0..pq_end (所有活跃行)
// =====================================================================
// 直接用裸指针切片,避开借用检查器,保证不出界即可
let j_ptr = j_values.as_mut_ptr();
let out_j11 =
unsafe { std::slice::from_raw_parts_mut(j_ptr.add(pattern.j11_starts[k]), pq_end) };
let out_j21 = unsafe {
std::slice::from_raw_parts_mut(j_ptr.add(pattern.j21_starts[k]), pq_end - pv_end)
};
// 核心劈裂 1A:只命中 PV 目标行 (0..pv_end)
for offset in 0..pv_end {
let y_ptr = y_start + offset;
let i = y_row_indices[y_ptr];
let Y_ik = y_vals[y_ptr];
let Va_re = Y_ik.re * ek - Y_ik.im * fk;
let Va_im = Y_ik.re * fk + Y_ik.im * ek;
out_j11[offset] = v[i].im * Va_re - v[i].re * Va_im;
}
// 核心劈裂 1B:命中 PQ 目标行 (pv_end..pq_end) -> 双路并发直写
for offset in pv_end..pq_end {
let y_ptr = y_start + offset;
let i = y_row_indices[y_ptr];
let Y_ik = y_vals[y_ptr];
let Va_re = Y_ik.re * ek - Y_ik.im * fk;
let Va_im = Y_ik.re * fk + Y_ik.im * ek;
let ei = v[i].re;
let fi = v[i].im;
out_j11[offset] = fi * Va_re - ei * Va_im;
out_j21[offset - pv_end] = -(ei * Va_re + fi * Va_im);
}
// =====================================================================
// 第二幕:电压幅值 (Vm) 导数盲填流 —— 仅当源节点 k 拥有 Vm 变量 (k >= npv) 时触发
// =====================================================================
if k >= npv {
let pq_idx = k - npv;
let start_12 = pattern.j12_starts[pq_idx];
let start_22 = pattern.j22_starts[pq_idx];
let j_ptr = j_values.as_mut_ptr();
let out_j12 = unsafe { std::slice::from_raw_parts_mut(j_ptr.add(start_12), pq_end) };
let out_j22 =
unsafe { std::slice::from_raw_parts_mut(j_ptr.add(start_22), pq_end - pv_end) };
// 核心劈裂 2A:只命中 PV 目标行 (0..pv_end)
for offset in 0..pv_end {
let y_ptr = y_start + offset;
let i = y_row_indices[y_ptr];
let Y_ik = y_vals[y_ptr];
let Vm_re = Y_ik.re * enk - Y_ik.im * fnk;
let Vm_im = Y_ik.re * fnk + Y_ik.im * enk;
out_j12[offset] = v[i].re * Vm_re + v[i].im * Vm_im;
}
// 核心劈裂 2B:命中 PQ 目标行 (pv_end..pq_end) -> 双路并发直写
for offset in pv_end..pq_end {
let y_ptr = y_start + offset;
let i = y_row_indices[y_ptr];
let Y_ik = y_vals[y_ptr];
let Vm_re = Y_ik.re * enk - Y_ik.im * fnk;
let Vm_im = Y_ik.re * fnk + Y_ik.im * enk;
let ei = v[i].re;
let fi = v[i].im;
out_j12[offset] = ei * Vm_re + fi * Vm_im;
out_j22[offset - pv_end] = fi * Vm_re - ei * Vm_im;
}
}
// =====================================================================
// 第三幕:对角线单点爆破修正 (O(1) 寄存器级增量追加)
// =====================================================================
unsafe {
// 修正 J11 对角线: 显式追加 -Q_k = ek * Iim_k - fk * Ire_k
*j_values.get_unchecked_mut(pattern.j11_starts[k] + diag_offset) +=
ek * Iim_k - fk * Ire_k;
if k >= npv {
let pq_idx = k - npv;
let start_21 = pattern.j21_starts[k];
let start_12 = pattern.j12_starts[pq_idx];
let start_22 = pattern.j22_starts[pq_idx];
// 修正 J21 对角线: 显式追加 +P_k = ek * Ire_k + fk * Iim_k
*j_values.get_unchecked_mut(start_21 + diag_offset - pv_end) +=
ek * Ire_k + fk * Iim_k;
// 修正 J12 对角线: 显式追加 +enk * Ire_k + fnk * Iim_k (上一版已正确)
*j_values.get_unchecked_mut(start_12 + diag_offset) += enk * Ire_k + fnk * Iim_k;
// 修正 J22 对角线: 显式追加 +fnk * Ire_k - enk * Iim_k (上一版已正确)
*j_values.get_unchecked_mut(start_22 + diag_offset - pv_end) +=
fnk * Ire_k - enk * Iim_k;
}
}
}
}