Solver sees default parameter value instead of updated parameter value

88 views
Skip to first unread message

Emily Fertig

unread,
Apr 6, 2017, 10:42:47 PM4/6/17
to Pyomo Forum

I'm trying to solve a unit commitment/economic dispatch problem for a power system (an MILP with binary unit commitment

variables) and am having trouble with a constraint.

I'm solving the problem with an hourly time resolution, where each optimization problem is for a single day. The values of

certain variables at the solution for one day are passed into constraints for the next day (which is a separate

optimization problem). I formulate the model as an AbstractModel with mutable parameters, then instantiate it, then

overwrite parameter values if they change from one day to the next.


The constraint where the problem arises is enforcing the minimum number of hours a generator must remain off (such that the

binary unit_commitment variable == 0 each hour), across days. For example, if a generator has to be off for a minimum of 5

hours once it's turned off, and it's off for 2 hours at the end of the current day, it has to be off for at least 3 hours

at the beginning of the next day.


I've attached an example (which solves two successive 6-hour problems) where the solver terminates, but the

constraint is not satisfied (solve_case is the main function). If I put a breakpoint after line 69 and look at 'inst_with_solutions' (the current model

instance with results inserted), the 'init_time_periods_offline' value for the Wind generator is 3 hours (which is correct

- Wind should be off for the first 3 hours, given the initial conditions I've fed it). However, the values of the

unit_commitment variable show that the Wind generator is on for the first 3 hours (unit_commitment['Wind',t] = 1 for t in

{1,2,3}). The constraint defined by minimum_downtime_initial_rule (starting line 336) is what should enforce this, but it

appears the constraint is being skipped.


If I define a different default for init_time_periods_offline (using default=default_test in line 226 instead of

default=0), it enforces the constraint with the new default values. It appears the model is picking up the

default parameter value no matter what. The correct (non-default) parameter value appears in the model instance when I look

at it in the debugger, but it seems the problem is solved with the default value instead. That is, the updated instance of

the model ignores the new parameter values that result from the solution to the initial instance of the model (or the

assumed parameter value, if it's the first optimization problem of the sequence). I update other mutable parameters - in

this example, the hourly electricity demand - and that works fine.


Any insight into what's going on here would be much appreciated!
model_definition_minimal_bug.py

Gabriel Hackebeil

unread,
Apr 6, 2017, 10:57:37 PM4/6/17
to pyomo...@googlegroups.com
One part of the problem is a rule function such as this:

def minimum_downtime_initial_rule(model, g):
    if value(model.init_time_periods_offline[g]) == 0.0:
        return Constraint.Skip
    else:
        return sum(model.unit_commitment[g, t] for t in model.timeperiods if t <= value(model.init_time_periods_offline[g])) == 0

This rule only gets called during the initial construction of the instance, and the line 'if value(model.init_time_periods_offline[g]) == 0.0’ only ever gets executed when that constraint rule is called. Thus, when you update the value of `init_time_periods_offline[g]` on the instance, it does not affect the structure of the constraint as you intended.

I think the easiest workaround would be to just call a function that re-adds this constraint onto the instance after you update those parameter values each time.

Gabe

--
You received this message because you are subscribed to the Google Groups "Pyomo Forum" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pyomo-forum...@googlegroups.com.
For more options, visit https://groups.google.com/d/optout.
<model_definition_minimal_bug.py>

Siirola, John D

unread,
Apr 6, 2017, 11:12:13 PM4/6/17
to pyomo...@googlegroups.com
A simpler approach might be just to fix the appropriate number of unit_committment[g,t] to 0 when you are copying over the solution (thereby avoiding the constraint entirely). 

Your constraint is effectively doing that (just relying on the solver's presolve step to do it for you). 

John

Emily Fertig

unread,
Apr 8, 2017, 4:19:51 PM4/8/17
to Pyomo Forum
Gabe,

Thank you! I re-added the constraint to each successive problem and it works. (Earlier I had tried re-adding the parameter instead of the constraint, and couldn't get that to work.)

Your explanation that the rule only gets called during the initial construction of the instance had crossed my mind as a possibility. If this is the case, do you know why my energy supply >= demand constraint (beginning line 344) works? I overwrite the hourly electricity demand data (mdl.lod_power) in the same way I had overwritten mdl.init_time_periods_offline - while the default was always being passed to the solver for mdl.init_time_periods_offline, the overwritten (correct) values are being passed for mdl.load_power.

I suspect that this has to do with the fact that my constraints refer to value(mdl.init_time_periods_offline) but to mdl.load_power (the parameter itself -  not the value). I tried referring to mdl.init_time_periods_offline and not its value in the constraint rule, but it returned an error. Is that on the right track, or is there a different explanation? (And more broadly, can anyone point me towards a thorough explanation of when to use my_param vs. my_param.value? I haven't been able to find one).

Thanks again!

Emily

Emily Fertig

unread,
Apr 8, 2017, 4:20:55 PM4/8/17
to Pyomo Forum
John,

Thanks - I implemented this solution too, and ended up dropping/adding the constraint instead since in the full model (as opposed to the example I posted) there are other dependencies from one optimization problem to the next that make the fixed-variable approach not as practical. That approach hadn't occurred to me though, and I appreciate knowing about it.

Emily

Gabriel Hackebeil

unread,
Apr 9, 2017, 1:06:42 PM4/9/17
to Pyomo Forum
I suspect that this has to do with the fact that my constraints refer to value(mdl.init_time_periods_offline) but to mdl.load_power (the parameter itself -  not the value). I tried referring to mdl.init_time_periods_offline and not its value in the constraint rule, but it returned an error. Is that on the right track, or is there a different explanation? (And more broadly, can anyone point me towards a thorough explanation of when to use my_param vs. my_param.value? I haven't been able to find one).

param.value (or value(param)) is just a number, but if the param itself is used in the expression, as long as it is mutable, you can update the value property of the param and it will cause any expression that references the param to be updated.

The other difference between those two rules is that one uses if-else logic outside of the constraint expression that it returns. It is a common misconception that constraint rules are like callbacks and that this “external" if-else logic is imbedded into the constraint, but it is not. The constraint is only defined by what is returned from the rule. This is why you get an error if you try to use a param or variable in if-else logic outside of the expression that gets returned. You need to cast those objects to a simple number in places like that.

Hope that clears it up.

Gabe

Emily Fertig

unread,
Apr 10, 2017, 1:46:41 AM4/10/17
to Pyomo Forum
That does clear it up - thanks for your help.

Emily
Reply all
Reply to author
Forward
0 new messages