AI4OPT / OPFGenerator

Instance generator for OPF problems
MIT License
2 stars 3 forks source link

Avoid re-building models #49

Closed klamike closed 5 months ago

klamike commented 7 months ago

In sampler.jl, we build a new JuMP model for each formulation for each seed. Instead, we should build one model per formulation and use POI to change the loads for each seed. This should reduce build times substantially after the first one.

In the package code, this will also require updating all of the formulations to make the loads parameters, wrapping the optimizer with POI.Optimizer, and adding ParametricOptInterface to the dependencies. Since we add the dependency, the code for changing the parameter values can go in the package as well.

In the SLURM pipeline, this would still build one model per formulation per minibatch. There may be a way to create each formulation's model once in the make_sysimage or ref job, then reuse it in each minibatch.

mtanneau commented 7 months ago

I fully agree that we should improve the current data-generation pipeline, but I would like to have a deeper discussion about this before we merge such changes.

A few notes:

mtanneau commented 7 months ago

An intermediate step (which would probably need to happen anyway) would be to define an interface for updating an existing OPF model, given new input data. We can have an agnostic interface like, e.g., update!(opf::OPFModel, data), the internals of which we can always modify in the future

klamike commented 7 months ago

Agreed. I'll see if I can get an update! working without POI...

mtanneau commented 7 months ago

For the loads, we should be able to use something like set_normalized_rhs

klamike commented 7 months ago

With the normalization, I think it would be cleaner to delete+unregister the old constraints and add new ones

(though the docs do explicitly recommend against doing this...)

mtanneau commented 7 months ago

Normalization?

Is that related to the fact that, the active/reactive power balance constraints will have -pd / -qd on the right-hand side?

For instance, on the 14-ieee system, bus #2 has a load with +0.217p.u. but... in the ACPPowerModel problem the power balance constraint at that node will have -0.217 as RHS

julia> using PGLib, Ipopt, PowerModels, JuMP
julia> data = make_basic_network(pglib("14_ieee"));
julia> data["load"]["1"]["load_bus"]
2
julia> data["load"]["1"]["pd"]
0.217
julia> opf = OPFGenerator.build_opf(ACPPowerModel, data, Ipopt.Optimizer);
julia> opf.model[:kirchhoff_active][2];
kirchhoff_active[2] : -pg[2] + pf[(5, 2, 5)] + pf[(3, 2, 3)] + pf[(4, 2, 4)] + pf[(1, 2, 1)] = -0.217
julia> normalized_rhs(opf.model[:kirchhoff_active][2])
-0.217

This is because the original code for active/reactive power balance https://github.com/AI4OPT/OPFGenerator/blob/f7364bc04d2d075ac4999ff1025b9dc4a38a885f/src/opf/acp.jl#L57-L71 has variables on both sides of the equation. JuMP automatically moves all the variables to the same side and all the constants to the other side... but we don't fully control which side is left and which is right.

We can fix this by writing all the variables on the same side of the equation, when declaring those constraints. I've been hesitant to do that, because it would effectively negate the corresponding dual variable, and I didn't want to mess up our existing datasets.

BTW, we have the same issue with DC and SOC. Easy fix, I just want to make sure our code / formulation / data / etc. are all in sync.