Optimal solution seems to ignore constraints
OngoingHello, this question comes as a kind of follow up to my previous post a couple days ago.
I have a functioning model, which returns an optimal solution, however this solution ignores some of the constraints.
I have modeled a microgrid, part of this is a battery which can discharge to serve a local load.
The battery is defined through these constraints:
def battery_test_rule2(model,t):
return model.batteryLevel[t] == model.batteryLevel[t-1]+model.batteryCharge[t-1]-model.batteryDischarge[t-1]
if t in model.t > 0:
model.battery_test_rule2 = Constraint(model.t, rule = battery_test_rule2)
else:
model.battery_test_rule2 = None
def battery_start_rule(model,t):
return model.batteryLevel[0] ==1000
model.battery_start_rule = Constraint(model.t, rule = battery_start_rule)
def battery_discharge_rule2(model,t):
return model.batteryDischarge[t] <= model.batteryLevel[t-1]
if t in model.t >0:
model.battery_discharge_rule2 = Constraint(model.t, rule = battery_discharge_rule2)
else:
model.battery_discharge_rule2 = None
The charging and discharging is also subject to some other constraints, but they seem to work fine. The problem is that the batteryLevel is 1000 for time[0], and 0 for all other timesteps, this does not seem to affect the discharge, which will continue to work even with an "empty" battery, even if this is in clear violation of the constraints defined above.
Does anyone know what might be the cause of this?
Thanks in advance
-
Hi Maximilian,
Please also not that your functions immediately return something so the following code will never be executed.
Cheers,
Matthias1 -
What do you mean exactly? These are just a part of my model, I have several constraints following this setup and they seem to work?
1 -
Hi Maximilian,
How your constraints are encoded results in only the first line after the function definition is executed. You can read more about the return statement here.
For example, whenever the method:
def battery_test_rule2(model,t):
return model.batteryLevel[t] == model.batteryLevel[t-1]+model.batteryCharge[t-1]-model.batteryDischarge[t-1]
if t in model.t > 0:
model.battery_test_rule2 = Constraint(model.t, rule = battery_test_rule2)
else:
model.battery_test_rule2 = Noneis called, only the following line:
return model.batteryLevel[t] == model.batteryLevel[t-1]+model.batteryCharge[t-1]-model.batteryDischarge[t-1]
is executed, and the next ones are not.
Is that the desired behaviour?
Moreover, I recommend you write your model to an lp file and check whether the constraints you say are violated are actually encoded in the way you wish.
We can also have a look at a minimal, reproducible example of your problematic code and help you navigate to a solution.
Best regards,
Jonasz1 -
I want it to make sure the line
return model.batteryLevel[t] == model.batteryLevel[t-1]+model.batteryCharge[t-1]-model.batteryDischarge[t-1]
is checked for every t in my model, with the exception t=0, as it results in a keyerror.
Is Gurobi then not checking the statement for every t? I have tried to write it to an lp file, but the file is massive and I am struggling a bit to understand my constraints
I will try to give a reproducible example, however the code is very interconnected, so I dont know how much I can cut.
It was not possible to paste enough code here, but I uploaded the python code to dropbox, hopefully you can take a look:
https://www.dropbox.com/scl/fo/t7hj2r8ye37jh2bf60u7a/h?dl=0&rlkey=nbjotlnaik02tsae4622nnzyz1 -
I want it to make sure the line
return model.batteryLevel[t] == model.batteryLevel[t-1]+model.batteryCharge[t-1]-model.batteryDischarge[t-1]
is checked for every t in my model, with the exception t=0, as it results in a keyerror.
What do you mean by "the line is checked"?
Is Gurobi then not checking the statement for every t? I have tried to write it to an lp file, but the file is massive and I am struggling a bit to understand my constraints
In the current shape of your scripts, Python does not check the condition for every \(t\) in your model, because the code which tells it to do so is unreachable.
It was not possible to paste enough code here, but I uploaded the python code to dropbox, hopefully you can take a look:
https://www.dropbox.com/scl/fo/t7hj2r8ye37jh2bf60u7a/h?dl=0&rlkey=nbjotlnaik02tsae4622nnzyzI would invite you to familiarize yourself with the article about minimal, reproducible examples. Normally, it is very difficult for the author to spot an error in such a large script -- let alone someone who sees the code for the first time...
Take a look at lines 159-162. I suspect that these lines should be unindented by one level, and then your code will be executed (and the constraints you miss - generated). The same holds for lines 166-169 and 181-184.
The reason for this behaviour was explained in the previous post. Right now lines 166-169 fall into the scope of the definition of the battery_test_rule2 method - since they come below the return statement, they are never executed. I guess you wanted these lines to actually generate constraints...
Such errors are usually spotted by IDEs - do you use one?
Additionally, I recommend you familiarize yourself with these two resources about organizing Python code - you could save yourself some trouble if the method definitions and method calls were separated. To illustrate with an overly simplistic example -- instead of:
def foo():
return None
foo()
def bar():
return None
bar()you should do:
def foo():
return None
def bar():
return None
foo()
bar()Hope this helps.
Best regards,
Jonasz1 -
Thank you very much, I implemented the changes you suggested, but it sadly still does not give any values for the batteryLevel model
What do you mean by "the line is checked"?
My thoughts were that gurobi would check that the equality would hold for every value of t, however it still does not do this.
1 -
Dear Maximilian
Your script is really complex and I am afraid I cannot help you further without a (really) deep dive. If you could come up with a minimal reproducible example, we could try to help you further.
Additionally, you seem to be using Pyomo (and not gurobipy) to build your model - studying its documentation could also help.
Whenever you will run into a Gurobi-specific problem, we will gladly help you.
Best regards
Jonasz0 -
Thank you, I understand. I suppose my final question would be: I have checked the lp. file, and my constraint
def battery_test_rule(model,t):
return model.batteryLevel[t] == model.batteryLevel[t-1]<+model.batteryCharge[t-1]-model.batteryDischarge[t-1]
model.battery_test_rule = Constraint(model.t1, rule = battery_test_rule)Is not listed in the lp file? I removed the if statement, and made another time model called t1:
model.t1 = Set(initialize=np.arange(1, 48), ordered=True)
This way I do not get any keyerrors, do you know why the constraint does not show up in the lp file?
0 -
Never mind! It seems like the entire model is functioning now, if anyone else has this issue the solution seemed to be to use a different time model like I showed above. After that I just fixed a small indentation error.
Thank you for all your assistance and patience0
Please sign in to leave a comment.
Comments
9 comments