fixed_activity not the same as bound_activity_up plus bound_activity_lo
Dear all, I am currently struggling with setting the fixed_activity for a model. What I want to do is fix the activity of the trade technologies from a global simulation to a national model. What puzzles me is, that this works well if i use bound_activity_up and bound_activity_lo (see below). It however fails if I use the same values in the fixed_activity parameter.
Definition of the scenarios
# Load Scenarios
global_scenario = message_ix.Scenario(mp, model=global_model_spec.model, scenario=global_model_spec.scenario)
country_scenario = message_ix.Scenario(mp, model=cry_model_spec.model, scenario=cry_model_spec.scenario
new_scenario = country_scenario.clone(model=new_scenario_spec.model, scenario=new_scenario_spec.scenario', keep_solution=False)
# Load Activity Parameter from the Global Model
trade_tecs = country_scenario.set('cat_tec', {'type_tec': ['Import_tecs', 'Export_tecs']})['technology'].to_list()
trade_volumes = global_scenario.var('ACT', {'node_loc': country, 'technology': trade_tecs})
trade_volumes = trade_volumes.assign(value=trade_volumes['lvl'], unit='GWa/a')
Example I - using the fixed_activity parameter (infeasible):
# Add fixed activity
new_scenario.check_out()
new_scenario.add_par('fixed_activity',trade_volumes)
new_scenario.commit(' ')
# Solve model
new_scenario.set_as_default()
new_scenario.solve()
Example II - using the bound_activity parameters (feasible-delivers expected results):
# Sum activity over all vintages
idx_columns = ['node_loc', 'technology', 'year_act', 'mode', 'time', 'unit']
trade_volumes = trade_volumes.groupby(by=idx_columns, as_index=False).sum()
# Add bound activities
new_scenario.check_out()
new_scenario.add_par('bound_activity_up', trade_volumes)
new_scenario.add_par('bound_activity_lo', trade_volumes)
new_scenario.commit(' ')
# Solve model
new_scenario.set_as_default()
new_scenario.solve()
Does someone see what I am missing? Might this be a numerical issue?
Good morning everyone! So by trial and error I found a workaround, that works so far:
new_scenario.check_out()
# Add fixed activity
new_scenario.add_par('fixed_activity',trade_volumes[~trade_volumes.technology.isin(['coal_exp'])])
# Add bound activity
idx_columns = ['node_loc', 'technology', 'year_act', 'mode', 'time', 'unit']
trade_volumes = trade_volumes.groupby(by=idx_columns, as_index=False).sum()
new_scenario.add_par('bound_activity_up', trade_volumes[trade_volumes.technology.isin(['coal_exp'])])
new_scenario.commit(' ')
# Solve model
new_scenario.set_as_default()
new_scenario.solve()
However, I'd be still very much interested in understanding what is happening here. So please let me know if you have any ideas on this. Thanks!
I didn't write this GAMS code, but here's what a search (https://github.com/iiasa/message_ix/search?q=fixed_activity) shows: https://github.com/iiasa/message_ix/blob/2759faf226e3df6296c7d52d78775afaded74905/message_ix/model/MESSAGE/model_core.gms#L173-L174
You can find the usage of bound_activity_{lo,up} in the same file. My interpretation is that these two operate differently: bound_activity_{lo,up} are inequality constraints in the LP, while fixed_activity instead causes the ACT variable to be fixed (not free) for those indices.
What I don't understand is what value ACT is fixed to. I can't see any code that copies the value of fixed_activity into it.
Also, we don't seem to have tests for this, so maybe not totally surprising that it doesn't work.
@khaeru, your summary is correct and the line you reference is the value that the variable is being fixed to - no need for any other data manipulation...
My hunch is that this is a numerical issue.
@ClaraLuisa, can you check the GDX files if you see strange values in the fixing-parameter? Or if there are other bounds that affect that particular activity, can you try fixing to a slightly higher/lower value?
Hey @khaeru and @danielhuppmann thank you for your response. It really seems to be a numerical issue as (thanks @danielhuppmann for the hint) it works perfectly fine if i set the fixed_activity to slighly lower values:
# Add fixed activity
new_scenario.check_out()
new_scenario.add_par('fixed_activity',trade_volumes.assign(value=trade_volumes['value']*0.9999999)
new_scenario.commit(' ')
# Solve model
new_scenario.set_as_default()
new_scenario.solve()