Implement rolling horizon with linopy model including hourly constraints

194 views
Skip to first unread message

gktho...@gmail.com

unread,
Apr 17, 2023, 9:54:25 AM4/17/23
to pypsa
Hi everyone,

I built a model with 8760h an implemented hourly constraints for flow based market coupling. Now I would like to solve the model with a rolling horizon.

With the underlying pypsa model, this is no problem, as I can just specify the snapshots over which the model should be solved. Can I do something similar with the custom constraints in linopy? I.e. build the constraints for all 8760h and then just filter the ones that apply to the selected hours? Or do I need to build the constraint everytime, only for the hours that will be solved in the respective horizon?

Thanks a lot in advance!

Best,
Georg 

Fabian Neumann

unread,
Apr 18, 2023, 2:23:58 AM4/18/23
to pypsa
Hi Georg,

I am unsure if I fully understood the question, but it sounds like you could use the snapshots that are passed to the extra_functionality function.

def my_extra_functionality(n, sns):
    print("some extra functionality")

n.optimize(snapshots=n.snapshots[:24], extra_functionality=my_extra_functionality)

Best wishes,

Fabian

Georg Thomassen

unread,
Apr 18, 2023, 8:01:12 AM4/18/23
to Fabian Neumann, pypsa
Hi Fabian,

This would indeed work if I used the extra_functionality. I, however, built the model directly with linopy, i.e. by using m = n.optimize.create_model() and then adding the constraints.

But I get that that might then not be the smartest way to do it. Maybe I need to look into how I can do the same thing directly with extra_functionality. At least in the case of the rolling horizon, it is of course a big plus if the model directly parses the right snapshots for the constraints.

Thanks for yet another helpful nudge in the right direction :-)

Best,
Georg


--
You received this message because you are subscribed to the Google Groups "pypsa" group.
To unsubscribe from this group and stop receiving emails from it, send an email to pypsa+un...@googlegroups.com.
To view this discussion on the web, visit https://groups.google.com/d/msgid/pypsa/4e13f896-caba-4dfe-8015-4eb8ae7eb889n%40googlegroups.com.

Georg Thomassen

unread,
Apr 18, 2023, 8:25:27 AM4/18/23
to Fabian Neumann, pypsa
I thought I would have to use the functionality you used for the conversion of the old linopt constraints to linopy, but then I noticed you can simply include the same linopy code I used to build the model, by going m = n.model etc. directly in the extra_cuntionality. Very elegant, chapeau! :-)

Matthew Smith

unread,
Feb 26, 2025, 11:59:36 AMFeb 26
to pypsa
Hi all,

Sorry to ressurect an old thread. 

Does anyone have any examples of how you can directly reference the m = n.model in extra functionality? I have set up my constraints directly in the linopy model and but now want to use a rolling horizon.

Thanks,
Matt

Georg Thomassen

unread,
Feb 26, 2025, 1:35:19 PMFeb 26
to Matthew Smith, pypsa
Hi Matt,

Let’s say you first built a linopy model:

m = n.optimize.create_model()

And add your constraints

m.add_constraints(……


Then you can simply write your extra_functionality as:

def custom_constraints(n, snapshots):
       m = n.model

       m.add_constraints(…….

And

n.optimize.optimize_with_rolling_horizon(extra_functionality=custom_constraints, solver_name=…..)

Hope it is understandable :-)

Best,
Georg

Matthew Smith

unread,
Mar 1, 2025, 4:23:26 AMMar 1
to pypsa
Hi George,

That's clear, thanks. I'll share a code snippet example once I test it out.

Best regards,
Matt

Matthew Smith

unread,
Mar 4, 2025, 4:17:47 PMMar 4
to pypsa
Thanks George, it worked well. For posterity:

def custom_constraints(network, control_f,buy_perc):

    #add custom constraints
    m = network.optimize.create_model()
    m = constrain_annual_CUF(m, network, control_f)
    m = constrain_merchant_buy(m, network, buy_perc, control_f)

network.optimize.optimize_with_rolling_horizon(snapshots=network.snapshots, horizon=48, extra_functionality=custom_constraints(network, control_f,buy_perc), solver_name='highs')

Sebastian Wurm

unread,
Mar 31, 2025, 4:09:04 AMMar 31
to pypsa
I am having similar issues with rolling horizon optimization and correctly implementing custom constraints

I tried following Georg's advice:
def define_cons_max_curtailment(model,network, generator_name):
    """
    Define the constraint for the maximum curtailment rate of a specified generator.

    Args:
    network (Network): The network object containing generators and other components.
    generator_name (str): The name of the generator for which the constraint is to be defined.

    The function adds a constraint to the network model that limits the maximum curtailment rate
    for the specified generator. The curtailment rate is taken from the 'curtailment_rate_max' column
    in the network's generator DataFrame.
    """
    m = model
    c_rate_max = network.generators.loc[generator_name, "curtailment_rate_max"]
    m.add_constraints(
        m.variables["Generator-p"].sel(Generator=generator_name).sum()
        >= (
            (1 - c_rate_max)
            * network.generators_t.p_max_pu[generator_name].sum()
            * m.variables["Generator-p_nom"][generator_name].to_linexpr()
        ),
        name=f"{generator_name}_max_curtailment",
    )
    return(m)

#  Add Custom Constraints
def custom_constraints(network,generator_name):
    m = network.optimize.create_model()
    m = define_cons_max_curtailment(m, network, generator_name)

network.optimize.optimize_with_rolling_horizon(snapshots=network.snapshots, horizon=100, overlap=0, extra_functionality=custom_constraints(network, generator_name="pv_generator"), solver_name='highs')


The simulation runs but does not apply my custom constraint "define_cons_max_curtailment"
What am I doing wrong here?

Matthew Smith

unread,
Apr 1, 2025, 9:59:26 AMApr 1
to pypsa
Hi,

Please see this thread. We don't need to reference the model variable.


Best regards,
Matt

Reply all
Reply to author
Forward
0 new messages