Skip to content

Commit ccb46cf

Browse files
peleshkswirydonkoukpaizan
authored
Port sparse inequality constraint Jacobian to GPU (#40)
* I am not going to lie, Cursor agent heavily helped me with this. Replace PETSc-based inequality Jacobian with GPU RAJA kernels Move the inequality constraint Jacobian computation for the HiOp sparse GPU solver entirely to the device, eliminating the per-iteration host back and forth (copy to host, PETSc compute, MatGetRow extraction, values copy back to device). Elimiate PETSc use from this part of the code. Three RAJA kernels now compute directly into device memory: - Generator set-point constraints (AGC) - Voltage-reactive-power bounds (FIXED_WITHIN_QBOUNDS) - Line flow limits (Sf^2/St^2 derivatives + slack variables) Supporting changes: - Analytical NNZ counting replaces PETSc MatGetInfo at solver setup - New device-side parameter fields (apf, vs, xpdevidx, xslackidx, bus-to-gen mapping) added to *ParamsRajaHiop structs - Sparse position indices assigned at model setup for all three contribution types Includes validation test (test_ineqjac_gpu) that solves with IPOPT, then compares PETSc and GPU Jacobian values at the converged solution. Optional -benchmark flag for performance comparison. Made-with: Cursor --------- Co-authored-by: kswirydo <kasia.swirydowicz@gmail.com> Co-authored-by: pelesh <pelesh@users.noreply.github.com> Co-authored-by: Nicholson Koukpaizan <koukpaizannk@ornl.gov>
1 parent d2efd8f commit ccb46cf

11 files changed

Lines changed: 895 additions & 187 deletions

File tree

src/opflow/CMakeLists.txt

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -20,6 +20,7 @@ if(EXAGO_ENABLE_RAJA)
2020
set(OPFLOW_FORM_SRC
2121
${OPFLOW_FORM_SRC} model/power_bal_hiop/pbpolrajahiopsparse.cpp
2222
model/power_bal_hiop/pbpolrajahiopsparsekernels.cpp
23+
model/power_bal_hiop/pbpolrajahiopsparse_gpu.cpp
2324
)
2425
endif()
2526
endif()
@@ -39,8 +40,8 @@ set_source_files_properties(${OPFLOW_SRC} PROPERTIES LANGUAGE CXX)
3940
if(EXAGO_ENABLE_RAJA AND EXAGO_ENABLE_CUDA)
4041
set_source_files_properties(
4142
model/power_bal_hiop/pbpolrajahiopkernels.cpp
42-
model/power_bal_hiop/pbpolrajahiopsparsekernels.cpp PROPERTIES LANGUAGE
43-
CUDA
43+
model/power_bal_hiop/pbpolrajahiopsparsekernels.cpp
44+
model/power_bal_hiop/pbpolrajahiopsparse_gpu.cpp PROPERTIES LANGUAGE CUDA
4445
)
4546
endif()
4647

src/opflow/model/power_bal_hiop/paramsrajahiop.cpp

Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -27,6 +27,11 @@ int BUSParamsRajaHiop::destroy(OPFLOW opflow) {
2727
h_allocator_.deallocate(jacsp_idx);
2828
h_allocator_.deallocate(jacsq_idx);
2929
}
30+
h_allocator_.deallocate(ispv);
31+
h_allocator_.deallocate(gineqidx);
32+
h_allocator_.deallocate(ineqjacsp_idx);
33+
h_allocator_.deallocate(genoffset);
34+
h_allocator_.deallocate(ngenONbus);
3035

3136
#ifdef EXAGO_ENABLE_GPU
3237
d_allocator_.deallocate(isref_dev_);
@@ -46,6 +51,11 @@ int BUSParamsRajaHiop::destroy(OPFLOW opflow) {
4651
d_allocator_.deallocate(jacsp_idx_dev_);
4752
d_allocator_.deallocate(jacsq_idx_dev_);
4853
}
54+
d_allocator_.deallocate(ispv_dev_);
55+
d_allocator_.deallocate(gineqidx_dev_);
56+
d_allocator_.deallocate(ineqjacsp_idx_dev_);
57+
d_allocator_.deallocate(genoffset_dev_);
58+
d_allocator_.deallocate(ngenONbus_dev_);
4959
#endif
5060

5161
return 0;
@@ -80,6 +90,11 @@ int BUSParamsRajaHiop::copy(OPFLOW opflow) {
8090
resmgr.copy(jacsq_idx_dev_, jacsq_idx);
8191
resmgr.copy(powerimbalance_penalty_dev_, powerimbalance_penalty);
8292
}
93+
resmgr.copy(ispv_dev_, ispv);
94+
resmgr.copy(gineqidx_dev_, gineqidx);
95+
resmgr.copy(ineqjacsp_idx_dev_, ineqjacsp_idx);
96+
resmgr.copy(genoffset_dev_, genoffset);
97+
resmgr.copy(ngenONbus_dev_, ngenONbus);
8398
#else
8499
isref_dev_ = isref;
85100
isisolated_dev_ = isisolated;
@@ -96,6 +111,11 @@ int BUSParamsRajaHiop::copy(OPFLOW opflow) {
96111
jacsp_idx_dev_ = jacsp_idx;
97112
jacsq_idx_dev_ = jacsq_idx;
98113
powerimbalance_penalty_dev_ = powerimbalance_penalty;
114+
ispv_dev_ = ispv;
115+
gineqidx_dev_ = gineqidx;
116+
ineqjacsp_idx_dev_ = ineqjacsp_idx;
117+
genoffset_dev_ = genoffset;
118+
ngenONbus_dev_ = ngenONbus;
99119
#endif
100120
return 0;
101121
}
@@ -132,18 +152,31 @@ int BUSParamsRajaHiop::allocate(OPFLOW opflow) {
132152
jacsp_idx = paramAlloc<int>(h_allocator_, nbus);
133153
jacsq_idx = paramAlloc<int>(h_allocator_, nbus);
134154
}
155+
ispv = paramAlloc<int>(h_allocator_, nbus);
156+
gineqidx = paramAlloc<int>(h_allocator_, nbus);
157+
ineqjacsp_idx = paramAlloc<int>(h_allocator_, nbus);
158+
genoffset = paramAlloc<int>(h_allocator_, nbus);
159+
ngenONbus = paramAlloc<int>(h_allocator_, nbus);
135160

136161
/* Memzero arrays */
137162
resmgr.memset(isref, 0, nbus * sizeof(int));
138163
resmgr.memset(ispvpq, 0, nbus * sizeof(int));
139164
resmgr.memset(isisolated, 0, nbus * sizeof(int));
165+
resmgr.memset(ispv, 0, nbus * sizeof(int));
166+
resmgr.memset(gineqidx, 0, nbus * sizeof(int));
167+
resmgr.memset(ineqjacsp_idx, 0, nbus * sizeof(int));
168+
resmgr.memset(genoffset, 0, nbus * sizeof(int));
169+
resmgr.memset(ngenONbus, 0, nbus * sizeof(int));
140170

171+
int genoff = 0;
141172
for (int i = 0; i < nbus; i++) {
142173
bus = &ps->bus[i];
143174
loc = bus->startxVloc;
144175

145176
xidx[i] = opflow->idxn2sd_map[loc];
146177
gidx[i] = bus->starteqloc;
178+
genoffset[i] = genoff;
179+
genoff += bus->ngenON;
147180

148181
if (bus->ide == REF_BUS)
149182
isref[i] = 1;
@@ -152,6 +185,12 @@ int BUSParamsRajaHiop::allocate(OPFLOW opflow) {
152185
else
153186
ispvpq[i] = 1;
154187

188+
if (bus->ide == PV_BUS)
189+
ispv[i] = 1;
190+
191+
ngenONbus[i] = bus->ngenON;
192+
gineqidx[i] = bus->startineqloc;
193+
155194
if (opflow->genbusvoltagetype == FIXED_AT_SETPOINT) {
156195
if (bus->ide == REF_BUS || bus->ide == PV_BUS) {
157196
/* Hold voltage at reference and PV buses */
@@ -200,6 +239,11 @@ int BUSParamsRajaHiop::allocate(OPFLOW opflow) {
200239
jacsp_idx_dev_ = paramAlloc<int>(d_allocator_, nbus);
201240
jacsq_idx_dev_ = paramAlloc<int>(d_allocator_, nbus);
202241
}
242+
ispv_dev_ = paramAlloc<int>(d_allocator_, nbus);
243+
gineqidx_dev_ = paramAlloc<int>(d_allocator_, nbus);
244+
ineqjacsp_idx_dev_ = paramAlloc<int>(d_allocator_, nbus);
245+
genoffset_dev_ = paramAlloc<int>(d_allocator_, nbus);
246+
ngenONbus_dev_ = paramAlloc<int>(d_allocator_, nbus);
203247
#endif
204248
return 0;
205249
}
@@ -231,6 +275,8 @@ int LINEParamsRajaHiop::copy(OPFLOW opflow) {
231275
resmgr.copy(gineqidx_dev_, gineqidx);
232276
resmgr.copy(gbineqidx_dev_, gbineqidx);
233277
resmgr.copy(linelimidx_dev_, linelimidx);
278+
resmgr.copy(ineqjacsp_idx_dev_, ineqjacsp_idx);
279+
resmgr.copy(xslackidx_dev_, xslackidx);
234280
}
235281
#else
236282
Gff_dev_ = Gff;
@@ -250,6 +296,8 @@ int LINEParamsRajaHiop::copy(OPFLOW opflow) {
250296
gineqidx_dev_ = gineqidx;
251297
gbineqidx_dev_ = gbineqidx;
252298
linelimidx_dev_ = linelimidx;
299+
ineqjacsp_idx_dev_ = ineqjacsp_idx;
300+
xslackidx_dev_ = xslackidx;
253301
}
254302
#endif
255303
return 0;
@@ -277,6 +325,8 @@ int LINEParamsRajaHiop::destroy(OPFLOW opflow) {
277325
h_allocator_.deallocate(gineqidx);
278326
h_allocator_.deallocate(gbineqidx);
279327
h_allocator_.deallocate(linelimidx);
328+
h_allocator_.deallocate(ineqjacsp_idx);
329+
h_allocator_.deallocate(xslackidx);
280330
}
281331

282332
#ifdef EXAGO_ENABLE_GPU
@@ -301,6 +351,8 @@ int LINEParamsRajaHiop::destroy(OPFLOW opflow) {
301351
d_allocator_.deallocate(gineqidx_dev_);
302352
d_allocator_.deallocate(gbineqidx_dev_);
303353
d_allocator_.deallocate(linelimidx_dev_);
354+
d_allocator_.deallocate(ineqjacsp_idx_dev_);
355+
d_allocator_.deallocate(xslackidx_dev_);
304356
}
305357
#endif
306358

@@ -348,6 +400,8 @@ int LINEParamsRajaHiop::allocate(OPFLOW opflow) {
348400
linelimidx = paramAlloc<int>(h_allocator_, nlinelim);
349401
gineqidx = paramAlloc<int>(h_allocator_, nlinelim);
350402
gbineqidx = paramAlloc<int>(h_allocator_, nlinelim);
403+
ineqjacsp_idx = paramAlloc<int>(h_allocator_, nlinelim);
404+
xslackidx = paramAlloc<int>(h_allocator_, nlinelim);
351405
}
352406

353407
PetscInt j = 0;
@@ -391,6 +445,9 @@ int LINEParamsRajaHiop::allocate(OPFLOW opflow) {
391445
gbineqidx[j] = opflow->nconeq + line->startineqloc;
392446
gineqidx[j] = line->startineqloc;
393447
linelimidx[j] = linei;
448+
if (opflow->allow_lineflow_violation) {
449+
xslackidx[j] = opflow->idxn2sd_map[line->startxslackloc];
450+
}
394451
j++;
395452
}
396453

@@ -420,6 +477,8 @@ int LINEParamsRajaHiop::allocate(OPFLOW opflow) {
420477
gineqidx_dev_ = paramAlloc<int>(d_allocator_, nlinelim);
421478
gbineqidx_dev_ = paramAlloc<int>(d_allocator_, nlinelim);
422479
linelimidx_dev_ = paramAlloc<int>(d_allocator_, nlinelim);
480+
ineqjacsp_idx_dev_ = paramAlloc<int>(d_allocator_, nlinelim);
481+
xslackidx_dev_ = paramAlloc<int>(d_allocator_, nlinelim);
423482
}
424483
#endif
425484
return 0;
@@ -558,7 +617,10 @@ int GENParamsRajaHiop::destroy(OPFLOW opflow) {
558617
h_allocator_.deallocate(qt);
559618
h_allocator_.deallocate(qb);
560619
h_allocator_.deallocate(isrenewable);
620+
h_allocator_.deallocate(apf);
621+
h_allocator_.deallocate(vs);
561622
h_allocator_.deallocate(xidx);
623+
h_allocator_.deallocate(xpdevidx);
562624
h_allocator_.deallocate(gidxbus);
563625
h_allocator_.deallocate(eqjacspbus_idx);
564626
h_allocator_.deallocate(eqjacsqbus_idx);
@@ -581,7 +643,10 @@ int GENParamsRajaHiop::destroy(OPFLOW opflow) {
581643
d_allocator_.deallocate(qt_dev_);
582644
d_allocator_.deallocate(qb_dev_);
583645
d_allocator_.deallocate(isrenewable_dev_);
646+
d_allocator_.deallocate(apf_dev_);
647+
d_allocator_.deallocate(vs_dev_);
584648
d_allocator_.deallocate(xidx_dev_);
649+
d_allocator_.deallocate(xpdevidx_dev_);
585650
d_allocator_.deallocate(gidxbus_dev_);
586651
d_allocator_.deallocate(eqjacspbus_idx_dev_);
587652
d_allocator_.deallocate(eqjacsqbus_idx_dev_);
@@ -615,8 +680,11 @@ int GENParamsRajaHiop::copy(OPFLOW opflow) {
615680
resmgr.copy(qt_dev_, qt);
616681
resmgr.copy(qb_dev_, qb);
617682
resmgr.copy(isrenewable_dev_, isrenewable);
683+
resmgr.copy(apf_dev_, apf);
684+
resmgr.copy(vs_dev_, vs);
618685

619686
resmgr.copy(xidx_dev_, xidx);
687+
resmgr.copy(xpdevidx_dev_, xpdevidx);
620688
resmgr.copy(gidxbus_dev_, gidxbus);
621689

622690
resmgr.copy(eqjacspbus_idx_dev_, eqjacspbus_idx);
@@ -639,7 +707,10 @@ int GENParamsRajaHiop::copy(OPFLOW opflow) {
639707
qt_dev_ = qt;
640708
qb_dev_ = qb;
641709
isrenewable_dev_ = isrenewable;
710+
apf_dev_ = apf;
711+
vs_dev_ = vs;
642712
xidx_dev_ = xidx;
713+
xpdevidx_dev_ = xpdevidx;
643714
gidxbus_dev_ = gidxbus;
644715
eqjacspbus_idx_dev_ = eqjacspbus_idx;
645716
eqjacsqbus_idx_dev_ = eqjacsqbus_idx;
@@ -682,8 +753,11 @@ int GENParamsRajaHiop::allocate(OPFLOW opflow) {
682753
qt = paramAlloc<double>(h_allocator_, ngenON);
683754
qb = paramAlloc<double>(h_allocator_, ngenON);
684755
isrenewable = paramAlloc<int>(h_allocator_, ngenON);
756+
apf = paramAlloc<double>(h_allocator_, ngenON);
757+
vs = paramAlloc<double>(h_allocator_, ngenON);
685758

686759
xidx = paramAlloc<int>(h_allocator_, ngenON);
760+
xpdevidx = paramAlloc<int>(h_allocator_, ngenON);
687761
gidxbus = paramAlloc<int>(h_allocator_, ngenON);
688762

689763
eqjacspbus_idx = paramAlloc<int>(h_allocator_, ngenON);
@@ -720,11 +794,16 @@ int GENParamsRajaHiop::allocate(OPFLOW opflow) {
720794
qt[geni] = gen->qt;
721795
qb[geni] = gen->qb;
722796
isrenewable[geni] = (int)gen->isrenewable;
797+
apf[geni] = gen->apf;
798+
vs[geni] = gen->vs;
723799
if (opflow->has_gensetpoint) {
724800
pgs[geni] = gen->pgs;
725801
}
726802

727803
xidx[geni] = opflow->idxn2sd_map[loc];
804+
xpdevidx[geni] = (opflow->has_gensetpoint && !gen->isrenewable)
805+
? opflow->idxn2sd_map[gen->startxpdevloc]
806+
: -1;
728807
gidxbus[geni] = gloc;
729808
if (opflow->has_gensetpoint) {
730809
geqidxgen[geni] = gen->starteqloc;
@@ -748,8 +827,11 @@ int GENParamsRajaHiop::allocate(OPFLOW opflow) {
748827
qt_dev_ = paramAlloc<double>(d_allocator_, ngenON);
749828
qb_dev_ = paramAlloc<double>(d_allocator_, ngenON);
750829
isrenewable_dev_ = paramAlloc<int>(d_allocator_, ngenON);
830+
apf_dev_ = paramAlloc<double>(d_allocator_, ngenON);
831+
vs_dev_ = paramAlloc<double>(d_allocator_, ngenON);
751832

752833
xidx_dev_ = paramAlloc<int>(d_allocator_, ngenON);
834+
xpdevidx_dev_ = paramAlloc<int>(d_allocator_, ngenON);
753835
gidxbus_dev_ = paramAlloc<int>(d_allocator_, ngenON);
754836

755837
eqjacspbus_idx_dev_ = paramAlloc<int>(d_allocator_, ngenON);

src/opflow/model/power_bal_hiop/paramsrajahiop.h

Lines changed: 32 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -28,7 +28,12 @@ struct BUSParamsRajaHiop {
2828
vector */
2929
int *jacsp_idx; /* Location number in the sparse Jacobian for Pimb */
3030
int *jacsq_idx; /* Location number in the sparse Jacobian for Qimb */
31-
int *hesssp_idx; /* Location number in the Hessian */
31+
int *hesssp_idx; /* KS: Hessian indices */
32+
int *ispv; /* KS: ispv[i] = 1 if bus is PV bus */
33+
int *gineqidx; /* KS: starting position of bus ineq constraints */
34+
int *ineqjacsp_idx; /* KS: index in flat sparse ineq Jacobian array */
35+
int *genoffset; /* KS: Offset into flattened gen array for this bus */
36+
int *ngenONbus; /* KS: Number of ON generators on this bus */
3237

3338
// Device data
3439
int *isref_dev_; /* isref[i] = 1 if bus is reference bus */
@@ -46,9 +51,14 @@ struct BUSParamsRajaHiop {
4651
X vector */
4752
int *gidx_dev_; /* starting locations for bus balance equations in constraint
4853
vector */
49-
int *jacsp_idx_dev_; /* Location number in the sparse Jacobian for Pimb */
50-
int *jacsq_idx_dev_; /* Location number in the sparse Jacobian for Qimb */
51-
int *hesssp_idx_dev_; /* Location number in the Hessian */
54+
int *jacsp_idx_dev_; /* Location number in the sparse Jacobian for Pimb */
55+
int *jacsq_idx_dev_; /* Location number in the sparse Jacobian for Qimb */
56+
int *hesssp_idx_dev_; /* Location number in the Hessian */
57+
int *ispv_dev_; /* KS: dev counterpart of ispv */
58+
int *gineqidx_dev_; /* KS: dev counterpart of gineqidx */
59+
int *ineqjacsp_idx_dev_; /* KS: device counterpart of ineqjacsp_idx_ */
60+
int *genoffset_dev_; /* KS: dev counterpart of genoffset */
61+
int *ngenONbus_dev_; /* KS: dev counterpart of ngenONbus */
5262

5363
int allocate(OPFLOW);
5464
int destroy(OPFLOW);
@@ -72,9 +82,12 @@ struct GENParamsRajaHiop {
7282
double *qt; /* min. reactive power gen. limits */
7383
double *qb; /* max. reactive power gen. limits */
7484
double *pgs; /* real power output setpoint */
85+
double *apf; /* generator AGC participation factor */
86+
double *vs; /* voltage setpoint */
7587
int *isrenewable; /* Is renewable generator? */
7688

77-
int *xidx; /* starting locations in X vector */
89+
int *xidx; /* starting locations in X vector */
90+
int *xpdevidx; /* KS: tarting locations of deviation variables in X vector */
7891
int *
7992
gidxbus; /* starting locations in constraint vector for bus constraints */
8093
int *geqidxgen; /* starting locations in equality constraint vector for gen
@@ -104,9 +117,12 @@ struct GENParamsRajaHiop {
104117
double *qt_dev_; /* min. reactive power gen. limits */
105118
double *qb_dev_; /* max. reactive power gen. limits */
106119
double *pgs_dev_; /* real power output setpoint */
120+
double *apf_dev_; /* KS: device counterpart of apf */
121+
double *vs_dev_; /* KS: device counterpart of vs */
107122
int *isrenewable_dev_; /* Is renewable generator? */
108123

109124
int *xidx_dev_; /* starting locations in X vector */
125+
int *xpdevidx_dev_; /* KS: device coutnerpart of xpdevidx*/
110126
int *gidxbus_dev_; /* starting locations in constraint vector for bus
111127
constraints */
112128
int *geqidxgen_dev_; /* starting locations in equality constraint vector for
@@ -143,7 +159,7 @@ struct LOADParamsRajaHiop {
143159
double *pl; /* active power demand */
144160
double *ql; /* reactive power demand */
145161
double *loadloss_penalty; /* Penalty for load loss */
146-
int *xidx; /* starting location in X vector */
162+
int *xidx; /* KS: starting location in X vector */
147163
int *gidx; /* starting location in constraint vector */
148164

149165
/* The following members are only used with HIOP */
@@ -192,9 +208,11 @@ struct LINEParamsRajaHiop {
192208
contribution in constraints vector */
193209
int *gineqidx; /* Starting location to insert contribution to inequality
194210
constraint */
195-
int *gbineqidx; /* Starting location to insert contribution to inequality
196-
constraint bound */
197-
int *linelimidx; /* Indices for subset of lines that have finite limits */
211+
int *gbineqidx; /* Starting location to insert contribution to inequality
212+
constraint bound */
213+
int *linelimidx; /* Indices for subset of lines that have finite limits */
214+
int *ineqjacsp_idx; /* KS: Position in flat sparse ineq Jacobian array */
215+
int *xslackidx; /* Starting location of slack variables in X vector */
198216

199217
// Device data
200218
double *Gff_dev_; /* From side self conductance */
@@ -218,6 +236,8 @@ struct LINEParamsRajaHiop {
218236
constraint bound */
219237
int *
220238
linelimidx_dev_; /* Indices for subset of lines that have finite limits */
239+
int *ineqjacsp_idx_dev_; /* KS: Position in flat sparse ineq Jacobian array */
240+
int *xslackidx_dev_; /* Starting location of slack variables in X vector */
221241

222242
int allocate(OPFLOW);
223243
int destroy(OPFLOW);
@@ -248,6 +268,9 @@ struct PbpolModelRajaHiop : public _p_FormPBPOLRAJAHIOP {
248268
LINEParamsRajaHiop lineparams;
249269
BUSParamsRajaHiop busparams;
250270

271+
int agc_xidx; /* KS: X-vector index for the AGC delta-P variable
272+
(ps->startxloc) */
273+
251274
// Arrays to store Jacobian and Hessian indices and entries on CPU (used with
252275
// GPU sparse model)
253276
int *i_jaceq,

0 commit comments

Comments
 (0)