PV Overproduction within a linear cost factor optimization

So I am currently trying to optimize the costs for energy in a household. The optimization is based on a cost factor function which I am trying to minimize.

model = ConcreteModel()
model.t = RangeSet(0, 8759)

def costs(model, t):
    return sum(model.cost_factor[t] * model.elec_grid[t] for t in model.t)
model.costs = Objective(rule = costs, sense = minimize)

Due to pv overproduction being a thing I try to negate by using these functions:

model.elec_consumption = Param(model.t, initialize = df['Consumption'])
model.pv = Param(model.t, initialize = df['PV'])
model.excess_pv = Var(model.t, within = NonNegativeReals, initialize = 0)
model.demand = Var(model.t, initialize = 0, within = NonNegativeReals)

def pv_overproduction(model, t):
    return model.excess_pv[t] >= model.pv[t] - model.demand[t]
model.pv_overproduction = Constraint(model.t, rule = pv_overproduction)
def lastdeckung(model, t):
    return (model.pv[t] - model.excess_pv[t]) + model.elec_grid[t] == model.demand[t]
model.lastdeckung = Constraint(model.t, rule = lastdeckung)

The problem is when the cost factor is negative the optimizer puts model.excess_pv very high so he can crank up the model.elec_grid variable in an effort to minimize the cost factor. That is obviously not the intention but so far I wasnt able to find a better way to calculate the excess pv. An easy fix would technically be to just have a cost factor which is constantly positive but sadly thats not an option.

I'd appreciate if someone had an idea how to fix this.

The basics are that I want to maximize the usage of the pv electricity in order to reduce costs. At some points there is to mooch pv in the system so in order for that optimization to still work I need to get rid of the excess.

    return model.demand[t] == model.elec_consumption[t]
model.demand_rule = Constraint(model.t, rule = demand_rule)

This is the demand. Technically there are more functions but for the the problem solving that is irrelevant. The main problem is that this function doesnt work due to the cost factor being negative sometimes model.excess_pv[t] >= model.pv[t] - model.demand[t] Excess_pv aswell as model.demand are variables wheres model.pv is a parameter.

So as far as I got in my problemsearching I need to change my overproduction function in a way that it uses the value from pv - excess_pv if the value is > 0 and should the value be < = 0 its supposed to be zero.


Solution 1:

I think the easiest way to do this is to probably just penalize excess production to a greater extent than the maximally negative cost factor.

Why can't you...

excess_pentalty = max(-min(cost) + epsilon, 0)  # use maximin to prevent odd behavior if there is no negative cost, which might lead to a negative penalty...

# make obj from components, so we can inspect true cost (w/o penalty) later...
cost = sum(model.cost_factor[t] * model.elec_grid[t] for t in model.t)
overproduction_pentaly = sum(excess_penalty * model.excess_pv[t] for t in model.t)

model.obj = Objective(expr= cost + overproduction_penalty, sense = minimize)

and later if you want the cost independently, you can just check the value of cost, which is a legal pyomo expression.

value(cost)

I think you could also add the expression as a model component, if that is important...

model.cost = ...
model.overproduction_penalty = ...