def test_add_spatial_multiple(test_mp): scen = Scenario(test_mp, *msg_args, version='new') data = {'country': ['Austria', 'Germany']} scen.add_spatial_sets(data) exp = ['World', 'Austria', 'Germany'] obs = scen.set('node') npt.assert_array_equal(obs, exp) exp = ['World', 'global', 'country'] obs = scen.set('lvl_spatial') npt.assert_array_equal(obs, exp) exp = [['country', 'Austria', 'World'], ['country', 'Germany', 'World']] obs = scen.set('map_spatial_hierarchy') npt.assert_array_equal(obs, exp)
def test_add_spatial_multiple(test_mp): scen = Scenario(test_mp, **SCENARIO["dantzig"], version="new") data = {"country": ["Austria", "Germany"]} scen.add_spatial_sets(data) exp = ["World", "Austria", "Germany"] obs = scen.set("node") npt.assert_array_equal(obs, exp) exp = ["World", "global", "country"] obs = scen.set("lvl_spatial") npt.assert_array_equal(obs, exp) exp = [["country", "Austria", "World"], ["country", "Germany", "World"]] obs = scen.set("map_spatial_hierarchy") npt.assert_array_equal(obs, exp)
def test_add_spatial_single(test_mp): scen = Scenario(test_mp, **SCENARIO['dantzig'], version='new') data = {'country': 'Austria'} scen.add_spatial_sets(data) exp = ['World', 'Austria'] obs = scen.set('node') npt.assert_array_equal(obs, exp) exp = ['World', 'global', 'country'] obs = scen.set('lvl_spatial') npt.assert_array_equal(obs, exp) exp = [['country', 'Austria', 'World']] obs = scen.set('map_spatial_hierarchy') npt.assert_array_equal(obs, exp)
def test_add_spatial_hierarchy(test_mp): scen = Scenario(test_mp, *msg_args, version='new') data = {'country': {'Austria': {'state': ['Vienna', 'Lower Austria']}}} scen.add_spatial_sets(data) exp = ['World', 'Vienna', 'Lower Austria', 'Austria'] obs = scen.set('node') npt.assert_array_equal(obs, exp) exp = ['World', 'global', 'state', 'country'] obs = scen.set('lvl_spatial') npt.assert_array_equal(obs, exp) exp = [ ['state', 'Vienna', 'Austria'], ['state', 'Lower Austria', 'Austria'], ['country', 'Austria', 'World'], ] obs = scen.set('map_spatial_hierarchy') npt.assert_array_equal(obs, exp)
def test_add_spatial_hierarchy(test_mp): scen = Scenario(test_mp, **SCENARIO["dantzig"], version="new") data = {"country": {"Austria": {"state": ["Vienna", "Lower Austria"]}}} scen.add_spatial_sets(data) exp = ["World", "Vienna", "Lower Austria", "Austria"] obs = scen.set("node") npt.assert_array_equal(obs, exp) exp = ["World", "global", "state", "country"] obs = scen.set("lvl_spatial") npt.assert_array_equal(obs, exp) exp = [ ["state", "Vienna", "Austria"], ["state", "Lower Austria", "Austria"], ["country", "Austria", "World"], ] obs = scen.set("map_spatial_hierarchy") npt.assert_array_equal(obs, exp)
def test_clone(tmpdir): # Two local platforms mp1 = ixmp.Platform(tmpdir / 'mp1', dbtype='HSQLDB') mp2 = ixmp.Platform(tmpdir / 'mp2', dbtype='HSQLDB') # A minimal scenario scen1 = Scenario(mp1, model='model', scenario='scenario', version='new') scen1.add_spatial_sets({'country': 'Austria'}) scen1.add_set('technology', 'bar') scen1.add_horizon({'year': [2010, 2020]}) scen1.commit('add minimal sets for testing') assert len(mp1.scenario_list(default=False)) == 1 # Clone scen2 = scen1.clone(platform=mp2) # Return type of ixmp.Scenario.clone is message_ix.Scenario assert isinstance(scen2, Scenario) # Close and re-open both databases mp1.close_db() # TODO this should be done automatically on del mp2.close_db() # TODO this should be done automatically on del del mp1, mp2 mp1 = ixmp.Platform(tmpdir / 'mp1', dbtype='HSQLDB') mp2 = ixmp.Platform(tmpdir / 'mp2', dbtype='HSQLDB') # Same scenarios present in each database assert all( mp1.scenario_list(default=False) == mp2.scenario_list(default=False)) # Load both scenarios scen1 = Scenario(mp1, 'model', 'scenario') scen2 = Scenario(mp2, 'model', 'scenario') # Contents are identical assert all(scen1.set('node') == scen2.set('node')) assert all(scen1.set('year') == scen2.set('year'))
def test_clone(tmpdir): # Two local platforms mp1 = ixmp.Platform(driver="hsqldb", path=tmpdir / "mp1") mp2 = ixmp.Platform(driver="hsqldb", path=tmpdir / "mp2") # A minimal scenario scen1 = Scenario(mp1, model="model", scenario="scenario", version="new") scen1.add_spatial_sets({"country": "Austria"}) scen1.add_set("technology", "bar") scen1.add_horizon(year=[2010, 2020]) scen1.commit("add minimal sets for testing") assert len(mp1.scenario_list(default=False)) == 1 # Clone scen2 = scen1.clone(platform=mp2) # Return type of ixmp.Scenario.clone is message_ix.Scenario assert isinstance(scen2, Scenario) # Close and re-open both databases mp1.close_db() # TODO this should be done automatically on del mp2.close_db() # TODO this should be done automatically on del del mp1, mp2 mp1 = ixmp.Platform(driver="hsqldb", path=tmpdir / "mp1") mp2 = ixmp.Platform(driver="hsqldb", path=tmpdir / "mp2") # Same scenarios present in each database assert all( mp1.scenario_list(default=False) == mp2.scenario_list(default=False)) # Load both scenarios scen1 = Scenario(mp1, "model", "scenario") scen2 = Scenario(mp2, "model", "scenario") # Contents are identical assert all(scen1.set("node") == scen2.set("node")) assert all(scen1.set("year") == scen2.set("year"))
def make_westeros(mp, emissions=False, solve=False): """Return an :class:`message_ix.Scenario` for the Westeros model. This is the same model used in the ``westeros_baseline.ipynb`` tutorial. Parameters ---------- mp : ixmp.Platform Platform on which to create the scenario. emissions : bool, optional If True, the ``emissions_factor`` parameter is also populated for CO2. solve : bool, optional If True, the scenario is solved. """ scen = Scenario(mp, version='new', **SCENARIO['westeros']) # Sets history = [690] model_horizon = [700, 710, 720] scen.add_horizon({ 'year': history + model_horizon, 'firstmodelyear': model_horizon[0] }) country = 'Westeros' scen.add_spatial_sets({'country': country}) sets = { 'technology': 'coal_ppl wind_ppl grid bulb'.split(), 'mode': ['standard'], 'level': 'secondary final useful'.split(), 'commodity': 'electricity light'.split(), } for name, values in sets.items(): scen.add_set(name, values) # Parameters — copy & paste from the tutorial notebook gdp_profile = pd.Series([1., 1.5, 1.9], index=pd.Index(model_horizon, name='Time')) demand_per_year = 40 * 12 * 1000 / 8760 light_demand = pd.DataFrame({ 'node': country, 'commodity': 'light', 'level': 'useful', 'year': model_horizon, 'time': 'year', 'value': (100 * gdp_profile).round(), 'unit': 'GWa', }) scen.add_par("demand", light_demand) year_df = scen.vintage_and_active_years() vintage_years, act_years = year_df['year_vtg'], year_df['year_act'] base = { 'node_loc': country, 'year_vtg': vintage_years, 'year_act': act_years, 'mode': 'standard', 'time': 'year', 'unit': '-', } base_input = make_df(base, node_origin=country, time_origin='year') base_output = make_df(base, node_dest=country, time_dest='year') bulb_out = make_df(base_output, technology='bulb', commodity='light', level='useful', value=1.0) scen.add_par('output', bulb_out) bulb_in = make_df(base_input, technology='bulb', commodity='electricity', level='final', value=1.0) scen.add_par('input', bulb_in) grid_efficiency = 0.9 grid_out = make_df(base_output, technology='grid', commodity='electricity', level='final', value=grid_efficiency) scen.add_par('output', grid_out) grid_in = make_df(base_input, technology='grid', commodity='electricity', level='secondary', value=1.0) scen.add_par('input', grid_in) coal_out = make_df(base_output, technology='coal_ppl', commodity='electricity', level='secondary', value=1.) scen.add_par('output', coal_out) wind_out = make_df(base_output, technology='wind_ppl', commodity='electricity', level='secondary', value=1.) scen.add_par('output', wind_out) base_capacity_factor = { 'node_loc': country, 'year_vtg': vintage_years, 'year_act': act_years, 'time': 'year', 'unit': '-', } capacity_factor = { 'coal_ppl': 1, 'wind_ppl': 1, 'bulb': 1, } for tec, val in capacity_factor.items(): df = make_df(base_capacity_factor, technology=tec, value=val) scen.add_par('capacity_factor', df) base_technical_lifetime = { 'node_loc': country, 'year_vtg': model_horizon, 'unit': 'y', } lifetime = { 'coal_ppl': 20, 'wind_ppl': 20, 'bulb': 1, } for tec, val in lifetime.items(): df = make_df(base_technical_lifetime, technology=tec, value=val) scen.add_par('technical_lifetime', df) base_growth = { 'node_loc': country, 'year_act': model_horizon, 'time': 'year', 'unit': '-', } growth_technologies = [ "coal_ppl", "wind_ppl", ] for tec in growth_technologies: df = make_df(base_growth, technology=tec, value=0.1) scen.add_par('growth_activity_up', df) historic_demand = 0.85 * demand_per_year historic_generation = historic_demand / grid_efficiency coal_fraction = 0.6 base_capacity = { 'node_loc': country, 'year_vtg': history, 'unit': 'GWa', } base_activity = { 'node_loc': country, 'year_act': history, 'mode': 'standard', 'time': 'year', 'unit': 'GWa', } old_activity = { 'coal_ppl': coal_fraction * historic_generation, 'wind_ppl': (1 - coal_fraction) * historic_generation, } for tec, val in old_activity.items(): df = make_df(base_activity, technology=tec, value=val) scen.add_par('historical_activity', df) act_to_cap = { # 20 year lifetime 'coal_ppl': 1 / 10 / capacity_factor['coal_ppl'] / 2, 'wind_ppl': 1 / 10 / capacity_factor['wind_ppl'] / 2, } for tec in act_to_cap: value = old_activity[tec] * act_to_cap[tec] df = make_df(base_capacity, technology=tec, value=value) scen.add_par('historical_new_capacity', df) rate = [0.05] * len(model_horizon) unit = ['-'] * len(model_horizon) scen.add_par("interestrate", model_horizon, rate, unit) base_inv_cost = { 'node_loc': country, 'year_vtg': model_horizon, 'unit': 'USD/GWa', } # in $ / kW costs = { 'coal_ppl': 500, 'wind_ppl': 1500, 'bulb': 5, } for tec, val in costs.items(): df = make_df(base_inv_cost, technology=tec, value=val) scen.add_par('inv_cost', df) base_fix_cost = { 'node_loc': country, 'year_vtg': vintage_years, 'year_act': act_years, 'unit': 'USD/GWa', } # in $ / kW costs = { 'coal_ppl': 30, 'wind_ppl': 10, } for tec, val in costs.items(): df = make_df(base_fix_cost, technology=tec, value=val) scen.add_par('fix_cost', df) base_var_cost = { 'node_loc': country, 'year_vtg': vintage_years, 'year_act': act_years, 'mode': 'standard', 'time': 'year', 'unit': 'USD/GWa', } # in $ / MWh costs = { 'coal_ppl': 30, 'grid': 50, } for tec, val in costs.items(): df = make_df(base_var_cost, technology=tec, value=val) scen.add_par('var_cost', df) scen.commit('basic model of Westerosi electrification') scen.set_as_default() if emissions: scen.check_out() # Introduce the emission species CO2 and the emission category GHG scen.add_set('emission', 'CO2') scen.add_cat('emission', 'GHG', 'CO2') # we now add CO2 emissions to the coal powerplant base_emission_factor = { 'node_loc': country, 'year_vtg': vintage_years, 'year_act': act_years, 'mode': 'standard', 'unit': 'USD/GWa', } emission_factor = make_df(base_emission_factor, technology='coal_ppl', emission='CO2', value=100.) scen.add_par('emission_factor', emission_factor) scen.commit('Added emissions sets/params to Westeros model.') if solve: scen.solve() return scen
def make_austria(mp, solve=False, quiet=True): """Return an :class:`message_ix.Scenario` for the Austrian energy system. This is the same model used in the ``austria.ipynb`` tutorial. Parameters ---------- mp : ixmp.Platform Platform on which to create the scenario. solve : bool, optional If True, the scenario is solved. """ mp.add_unit("USD/kW") mp.add_unit("MtCO2") mp.add_unit("tCO2/kWa") scen = Scenario( mp, version="new", **SCENARIO["austria"], annotation= "A stylized energy system model for illustration and testing", ) # Structure year = dict(all=list(range(2010, 2041, 10))) scen.add_horizon(year=year["all"]) year_df = scen.vintage_and_active_years() year["vtg"] = year_df["year_vtg"] year["act"] = year_df["year_act"] country = "Austria" scen.add_spatial_sets({"country": country}) sets = dict( commodity=["electricity", "light", "other_electricity"], emission=["CO2"], level=["secondary", "final", "useful"], mode=["standard"], ) sets["technology"] = AUSTRIA_TECH.index.to_list() plants = sets["technology"][:7] lights = sets["technology"][10:] for name, values in sets.items(): scen.add_set(name, values) scen.add_cat("emission", "GHGs", "CO2") # Parameters name = "interestrate" scen.add_par(name, make_df(name, year=year["all"], value=0.05, unit="-")) common = dict( mode="standard", node_dest=country, node_loc=country, node_origin=country, node=country, time_dest="year", time_origin="year", time="year", year_act=year["act"], year_vtg=year["vtg"], year=year["all"], ) gdp_profile = np.array([1.0, 1.21631, 1.4108, 1.63746]) beta = 0.7 demand_profile = gdp_profile**beta # From IEA statistics, in GW·h, converted to GW·a base_annual_demand = dict(other_electricity=55209.0 / 8760, light=6134.0 / 8760) name = "demand" common.update(level="useful", unit="GWa") for c, base in base_annual_demand.items(): scen.add_par( name, make_df(name, **common, commodity=c, value=base * demand_profile)) common.pop("level") # input, output common.update(unit="-") for name, (tec, info) in product(("input", "output"), AUSTRIA_TECH.iterrows()): value = info[f"{name}_value"] if np.isnan(value): continue scen.add_par( name, make_df( name, **common, technology=tec, commodity=info[f"{name}_commodity"], level=info[f"{name}_level"], value=value, ), ) data = AUSTRIA_PAR # Convert GW·h to GW·a data["activity"] = data["activity"] / 8760.0 # Convert USD / MW·h to USD / GW·a data["var_cost"] = data["var_cost"] * 8760.0 / 1e3 # Convert t / MW·h to t / kw·a data["emission_factor"] = data["emission_factor"] * 8760.0 / 1e3 def _add(): """Add using values from the calling scope.""" scen.add_par(name, make_df(name, **common, technology=tec, value=value)) name = "capacity_factor" for tec, value in data[name].dropna().items(): _add() name = "technical_lifetime" common.update(year_vtg=year["all"], unit="y") for tec, value in data[name].dropna().items(): _add() name = "growth_activity_up" common.update(year_act=year["all"][1:], unit="%") value = 0.05 for tec in plants + lights: _add() name = "initial_activity_up" common.update(year_act=year["all"][1:], unit="%") value = 0.01 * base_annual_demand["light"] * demand_profile[1:] for tec in lights: _add() # bound_activity_lo, bound_activity_up common.update(year_act=year["all"][0], unit="GWa") for (tec, value), kind in product(data["activity"].dropna().items(), ("up", "lo")): name = f"bound_activity_{kind}" _add() name = "bound_activity_up" common.update(year_act=year["all"][1:]) for tec in ("bio_ppl", "hydro_ppl", "import"): value = data.loc[tec, "activity"] _add() name = "bound_new_capacity_up" common.update(year_vtg=year["all"][0], unit="GW") for tec, value in (data["activity"] / data["capacity_factor"]).dropna().items(): _add() name = "inv_cost" common.update(dict(year_vtg=year["all"], unit="USD/kW")) for tec, value in data[name].dropna().items(): _add() # fix_cost, var_cost common.update( dict(year_vtg=year["vtg"], year_act=year["act"], unit="USD/kWa")) for name in ("fix_cost", "var_cost"): for tec, value in data[name].dropna().items(): _add() name = "emission_factor" common.update(year_vtg=year["vtg"], year_act=year["act"], unit="tCO2/kWa", emission="CO2") for tec, value in data[name].dropna().items(): _add() scen.commit("Initial commit for Austria model") scen.set_as_default() if solve: scen.solve(quiet=quiet) return scen
def make_westeros(mp, emissions=False, solve=False, quiet=True): """Return an :class:`message_ix.Scenario` for the Westeros model. This is the same model used in the ``westeros_baseline.ipynb`` tutorial. Parameters ---------- mp : ixmp.Platform Platform on which to create the scenario. emissions : bool, optional If True, the ``emissions_factor`` parameter is also populated for CO2. solve : bool, optional If True, the scenario is solved. """ mp.add_unit("USD/kW") mp.add_unit("tCO2/kWa") scen = Scenario(mp, version="new", **SCENARIO["westeros"]) # Sets history = [690] model_horizon = [700, 710, 720] scen.add_horizon(year=history + model_horizon, firstmodelyear=model_horizon[0]) year_df = scen.vintage_and_active_years() vintage_years, act_years = year_df["year_vtg"], year_df["year_act"] country = "Westeros" scen.add_spatial_sets({"country": country}) for name, values in ( ("technology", ["coal_ppl", "wind_ppl", "grid", "bulb"]), ("mode", ["standard"]), ("level", ["secondary", "final", "useful"]), ("commodity", ["electricity", "light"]), ): scen.add_set(name, values) # Parameters — copy & paste from the tutorial notebook common = dict( mode="standard", node_dest=country, node_loc=country, node_origin=country, node=country, time_dest="year", time_origin="year", time="year", year_act=act_years, year_vtg=vintage_years, year=model_horizon, ) gdp_profile = np.array([1.0, 1.5, 1.9]) demand_per_year = 40 * 12 * 1000 / 8760 scen.add_par( "demand", make_df( "demand", **common, commodity="light", level="useful", # FIXME should use demand_per_year; requires adjustments elsewhere. value=(100 * gdp_profile).round(), unit="GWa", ), ) grid_efficiency = 0.9 common.update(unit="-") for name, tec, c, l, value in [ ("input", "bulb", "electricity", "final", 1.0), ("output", "bulb", "light", "useful", 1.0), ("input", "grid", "electricity", "secondary", 1.0), ("output", "grid", "electricity", "final", grid_efficiency), ("output", "coal_ppl", "electricity", "secondary", 1.0), ("output", "wind_ppl", "electricity", "secondary", 1.0), ]: scen.add_par( name, make_df(name, **common, technology=tec, commodity=c, level=l, value=value), ) # FIXME the value for wind_ppl should be 0.36; requires adjusting other tests. name = "capacity_factor" capacity_factor = dict(coal_ppl=1.0, wind_ppl=1.0, bulb=1.0) for tec, value in capacity_factor.items(): scen.add_par(name, make_df(name, **common, technology=tec, value=value)) name = "technical_lifetime" common.update(year_vtg=model_horizon, unit="y") for tec, value in dict(coal_ppl=20, wind_ppl=20, bulb=1).items(): scen.add_par(name, make_df(name, **common, technology=tec, value=value)) name = "growth_activity_up" common.update(year_act=model_horizon, unit="-") for tec in "coal_ppl", "wind_ppl": scen.add_par(name, make_df(name, **common, technology=tec, value=0.1)) historic_demand = 0.85 * demand_per_year historic_generation = historic_demand / grid_efficiency coal_fraction = 0.6 common.update(year_act=history, year_vtg=history, unit="GWa") for tec, value in ( ("coal_ppl", coal_fraction * historic_generation), ("wind_ppl", (1 - coal_fraction) * historic_generation), ): name = "historical_activity" scen.add_par(name, make_df(name, **common, technology=tec, value=value)) # 20 year lifetime name = "historical_new_capacity" scen.add_par( name, make_df( name, **common, technology=tec, value=value / (2 * 10 * capacity_factor[tec]), ), ) name = "interestrate" scen.add_par(name, make_df(name, year=model_horizon, value=0.05, unit="-")) for name, tec, value in [ ("inv_cost", "coal_ppl", 500), ("inv_cost", "wind_ppl", 1500), ("inv_cost", "bulb", 5), ("fix_cost", "coal_ppl", 30), ("fix_cost", "wind_ppl", 10), ("var_cost", "coal_ppl", 30), ("var_cost", "grid", 50), ]: common.update( dict(year_vtg=model_horizon, unit="USD/kW") if name == "inv_cost" else dict( year_vtg=vintage_years, year_act=act_years, unit="USD/kWa")) scen.add_par(name, make_df(name, **common, technology=tec, value=value)) scen.commit("basic model of Westerosi electrification") scen.set_as_default() if emissions: scen.check_out() # Introduce the emission species CO2 and the emission category GHG scen.add_set("emission", "CO2") scen.add_cat("emission", "GHG", "CO2") # we now add CO2 emissions to the coal powerplant name = "emission_factor" common.update(year_vtg=vintage_years, year_act=act_years, unit="tCO2/kWa") scen.add_par( name, make_df(name, **common, technology="coal_ppl", emission="CO2", value=100.0), ) scen.commit("Added emissions sets/params to Westeros model.") if solve: scen.solve(quiet=quiet) return scen