Defining time-slices for balancing energy market

Hi everyone,

I am currently modeling an electrolyser that will participate in the balancing energy market alongside normal hydrogen production.
By defining a minimum_downtime variable in my power source, I ensure that when balancing energy is offered, this happens over 4 hours.

es2 = solph.EnergySystem(timeindex=solph.create_time_index(year=2023, number=num_tsteps), infer_last_interval=False)

source_pos_affr = solph.components.Source(
    "electricity pos affr",
    outputs={
        b_el_pos_affr: solph.Flow(
            nominal_value=20,
            min=0.25,
            nonconvex=solph.NonConvex(
                minimum_downtime=4
            )
        )
    }
)

However, I still have two problems:

  1. Currently it is possible to offer balancing energy for more than 4 hours without ensuring that it is then 4 hours in a row again

  2. control energy is offered in 6 fixed time slices per day: 0-4h, 4-8h… Does anyone know how I can specify that the decision is always made at 0, 4, 8, 12, 16 and 20 o’clock as to whether or not I offer balancing energy for 4 hours?

I think it is possible that the first problem could be solved by solving the second one.

Kind regards
Luca

Hi @dhorschi,

What you want to do, is rather “adding a slow time axis” (one action every four hours) than having a minimum. As you mentioned, e.g. 5 >= 4, so the minimum_downtime does not really help. I’d do something like:

myblock = po.Block()
om.add_component("MyBlock", myblock)

def first_step_of_time_slice(time):
    return time - (time % 4)

def same_status_rule(m, t):
    return = (
        om.NonConvexFlowBlock.status[source_pos_affr, b_el_pos_affr, first_step_of_time_slice(t)]
        == om.NonConvexFlowBlock.status[source_pos_affr, b_el_pos_affr, t]
    )

myblock.same_status = po.Constraint(om.TIMESTEPS, rule=same_status_rule)

Note that this will create some constraints that are trivially fulfilled. You do not need to drop the cases where first_step_of_time_slice(t) == t, but depending on the solver, it might improve the performance. (I didn’t really look into performance optimisation of this aspect, though. A constraint on the set of every time step with first_step_of_time_slice(t) < t should be faster, but testing everything using if might be slower then presolve.)