def test_price_duality(test_mp): years = [2020, 2025, 2030, 2040, 2050] for c in [0.25, 0.5, 0.75]: # set up a scenario for cumulative constraints scen = Scenario(test_mp, MODEL, 'cum_many_tecs', version='new') model_setup(scen, years, simple_tecs=False) scen.add_cat('year', 'cumulative', years) scen.add_par('bound_emission', ['World', 'ghg', 'all', 'cumulative'], 0.5, 'tCO2') scen.commit('initialize test scenario') scen.solve() # set up a new scenario with emissions taxes tax_scen = Scenario(test_mp, MODEL, 'tax_many_tecs', version='new') model_setup(tax_scen, years, simple_tecs=False) for y in years: tax_scen.add_cat('year', y, y) # use emission prices from cumulative-constraint scenario as taxes taxes = scen.var('PRICE_EMISSION')\ .rename(columns={'year': 'type_year', 'lvl': 'value'}) taxes['unit'] = 'USD/tCO2' tax_scen.add_par('tax_emission', taxes) tax_scen.commit('initialize test scenario for taxes') tax_scen.solve() # check that emissions are close between cumulative and tax scenario filters = {'node': 'World'} emiss = scen.var('EMISS', filters).set_index('year').lvl emiss_tax = tax_scen.var('EMISS', filters).set_index('year').lvl npt.assert_allclose(emiss, emiss_tax, rtol=0.20)
def test_price_duality(test_mp): years = [2020, 2025, 2030, 2040, 2050] for c in [0.25, 0.5, 0.75]: # set up a scenario for cumulative constraints scen = Scenario(test_mp, MODEL, "cum_many_tecs", version="new") model_setup(scen, years, simple_tecs=False) scen.add_cat("year", "cumulative", years) scen.add_par("bound_emission", ["World", "ghg", "all", "cumulative"], 0.5, "tCO2") scen.commit("initialize test scenario") scen.solve() # set up a new scenario with emissions taxes tax_scen = Scenario(test_mp, MODEL, "tax_many_tecs", version="new") model_setup(tax_scen, years, simple_tecs=False) for y in years: tax_scen.add_cat("year", y, y) # use emission prices from cumulative-constraint scenario as taxes taxes = scen.var("PRICE_EMISSION").rename(columns={ "year": "type_year", "lvl": "value" }) taxes["unit"] = "USD/tCO2" tax_scen.add_par("tax_emission", taxes) tax_scen.commit("initialize test scenario for taxes") tax_scen.solve() # check that emissions are close between cumulative and tax scenario filters = {"node": "World"} emiss = scen.var("EMISS", filters).set_index("year").lvl emiss_tax = tax_scen.var("EMISS", filters).set_index("year").lvl npt.assert_allclose(emiss, emiss_tax, rtol=0.20)
def test_bound_emission_year(test_mp): scen = Scenario(test_mp, "test_bound_emission", "standard", version="new") model_setup(scen, [2020, 2030]) scen.commit("initialize test model") add_bound_emission(scen, bound=1.250, year=2020) scen.solve(case="bound_emission_year") assert_function(scen, year=2020)
def test_add_bound_activity_up(test_mp): scen = Scenario(test_mp, *msg_args) scen.solve() # data for act bound exp = 0.5 * calculate_activity(scen).sum() data = pd.DataFrame({ 'node_loc': 'seattle', 'technology': 'transport_from_seattle', 'year_act': 2010, 'time': 'year', 'unit': 'cases', 'mode': 'to_chicago', 'value': exp, }, index=[0]) # test limiting one mode clone = scen.clone('foo', 'bar', keep_solution=False) clone.check_out() clone.add_par('bound_activity_up', data) clone.commit('foo') clone.solve() obs = calculate_activity(clone).loc['to_chicago'] assert np.isclose(obs, exp) orig_obj = scen.var('OBJ')['lvl'] new_obj = clone.var('OBJ')['lvl'] assert new_obj >= orig_obj
def test_add_bound_activity_up_all_modes(message_test_mp): scen = Scenario(message_test_mp, **SCENARIO['dantzig']).clone() scen.solve() # data for act bound exp = 0.95 * calculate_activity(scen).sum() data = pd.DataFrame( { 'node_loc': 'seattle', 'technology': 'transport_from_seattle', 'year_act': _year, 'time': 'year', 'unit': 'cases', 'mode': 'all', 'value': exp, }, index=[0]) # test limiting all modes clone = scen.clone('foo', 'baz', keep_solution=False) clone.check_out() clone.add_par('bound_activity_up', data) clone.commit('foo') clone.solve() obs = calculate_activity(clone).sum() assert np.isclose(obs, exp) orig_obj = scen.var('OBJ')['lvl'] new_obj = clone.var('OBJ')['lvl'] assert new_obj >= orig_obj
def test_solve_modified(caplog, message_test_mp): base = Scenario(message_test_mp, **SCENARIO["dantzig"]) # Base objective value base.solve() base_obj = base.var("OBJ")["lvl"] with solve_modified(base, "new scenario name") as scenario: # Scenario is not yet solved assert not scenario.has_solution() # Scenario has the indicated new name assert "new scenario name" == scenario.scenario # Change one demand parameter from 325 to 326 scenario.add_par( "demand", make_df( "demand", node=["new-york"], commodity=["cases"], level="consumption", year=1963, time="year", value=326, unit="case", ), ) # Scenario is solved at the end of the with: statement assert scenario.has_solution() assert scenario.var("OBJ")["lvl"] != base_obj
def test_bound_emission_5y(test_mp): scen = Scenario(test_mp, "test_bound_emission", "standard", version="new") model_setup(scen, [2020, 2025, 2030, 2040]) scen.commit("initialize test model") add_bound_emission(scen, bound=1.250) scen.solve(case="bound_emission_5y", quiet=True) assert_function(scen, year="cumulative")
def test_years_active_extend3(test_mp): test_mp.add_unit("year") scen = Scenario(test_mp, **SCENARIO["dantzig"], version="new") scen.add_set("node", "foo") scen.add_set("technology", "bar") # Periods of uneven length years = [1990, 1995, 2000, 2005, 2010, 2020, 2030] scen.add_horizon(year=years, firstmodelyear=2010) scen.add_set("year", [1992]) scen.add_par("duration_period", "1992", 2, "y") scen.add_par("duration_period", "1995", 3, "y") scen.add_par( "technical_lifetime", pd.DataFrame( dict( node_loc="foo", technology="bar", unit="year", value=[20], year_vtg=1990, ), ), ) obs = scen.years_active("foo", "bar", 1990) assert obs == [1990, 1992, 1995, 2000, 2005]
def test_add_bound_activity_up_all_modes(message_test_mp): scen = Scenario(message_test_mp, **SCENARIO["dantzig"]).clone() scen.solve(quiet=True) # data for act bound exp = 0.95 * calculate_activity(scen).sum() data = pd.DataFrame( { "node_loc": "seattle", "technology": "transport_from_seattle", "year_act": _year, "time": "year", "unit": "cases", "mode": "all", "value": exp, }, index=[0], ) # test limiting all modes clone = scen.clone("foo", "baz", keep_solution=False) clone.check_out() clone.add_par("bound_activity_up", data) clone.commit("foo") clone.solve() obs = calculate_activity(clone).sum() assert np.isclose(obs, exp) orig_obj = scen.var("OBJ")["lvl"] new_obj = clone.var("OBJ")["lvl"] assert new_obj >= orig_obj
def test_new_timeseries_long_name64plus(message_test_mp): scen = Scenario(message_test_mp, **SCENARIO["dantzig multi-year"]) scen = scen.clone(keep_solution=False) scen.check_out(timeseries_only=True) df = pd.DataFrame( { "region": [ "India", ], "variable": [ ( "Emissions|CO2|Energy|Demand|Transportation|Aviation|" "Domestic|Freight|Oil" ), ], "unit": [ "Mt CO2/yr", ], "2012": [ 0.257009, ], } ) scen.add_timeseries(df) scen.commit("importing a testing timeseries")
def test_bound_emission_5y(test_mp): scen = Scenario(test_mp, 'test_bound_emission', 'standard', version='new') model_setup(scen, [2020, 2025, 2030, 2040]) scen.commit('initialize test model') add_bound_emission(scen, bound=1.250) scen.solve(case='bound_emission_5y') assert_function(scen, year='cumulative')
def test_years_active(test_mp): test_mp.add_unit('year') scen = Scenario(test_mp, *msg_args, version='new') scen.add_set('node', 'foo') scen.add_set('technology', 'bar') # Periods of uneven length years = [1990, 1995, 2000, 2005, 2010, 2020, 2030] # First period length is immaterial duration = [1900, 5, 5, 5, 5, 10, 10] scen.add_horizon({'year': years, 'firstmodelyear': years[-1]}) scen.add_par('duration_period', pd.DataFrame(zip(years, duration), columns=['year', 'value'])) # 'bar' built in period '1995' with 25-year lifetime: # - is constructed in 1991-01-01. # - by 1995-12-31, has operated 5 years. # - operates until 2015-12-31. This is within the period '2020'. scen.add_par('technical_lifetime', pd.DataFrame(dict( node_loc='foo', technology='bar', unit='year', value=25, year_vtg=years[1]), index=[0])) result = scen.years_active('foo', 'bar', years[1]) # Correct return type assert isinstance(years, list) assert isinstance(years[0], int) # Years 1995 through 2020 npt.assert_array_equal(result, years[1:-1])
def base_scen_mp(test_mp): scen = Scenario(test_mp, "model", "standard", version="new") data = {2020: 1, 2030: 2, 2040: 3} years = sorted(list(set(data.keys()))) scen.add_set("node", "node") scen.add_set("commodity", "comm") scen.add_set("level", "level") scen.add_set("year", years) scen.add_set("technology", "tec") scen.add_set("mode", "mode") output_specs = ["node", "comm", "level", "year", "year"] for (yr, value) in data.items(): scen.add_par("demand", ["node", "comm", "level", yr, "year"], 1, "GWa") scen.add_par("technical_lifetime", ["node", "tec", yr], 10, "y") tec_specs = ["node", "tec", yr, yr, "mode"] scen.add_par("output", tec_specs + output_specs, 1, "-") scen.add_par("var_cost", tec_specs + ["year"], value, "USD/GWa") scen.commit("initialize test model") scen.solve(case="original_years", quiet=True) yield scen, test_mp
def base_scen_mp(test_mp): scen = Scenario(test_mp, 'model', 'standard', version='new') data = {2020: 1, 2030: 2, 2040: 3} years = sorted(list(set(data.keys()))) scen.add_set('node', 'node') scen.add_set('commodity', 'comm') scen.add_set('level', 'level') scen.add_set('year', years) scen.add_set('technology', 'tec') scen.add_set('mode', 'mode') output_specs = ['node', 'comm', 'level', 'year', 'year'] for (yr, value) in data.items(): scen.add_par('demand', ['node', 'comm', 'level', yr, 'year'], 1, 'GWa') scen.add_par('technical_lifetime', ['node', 'tec', yr], 10, 'y') tec_specs = ['node', 'tec', yr, yr, 'mode'] scen.add_par('output', tec_specs + output_specs, 1, '-') scen.add_par('var_cost', tec_specs + ['year'], value, 'USD/GWa') scen.commit('initialize test model') scen.solve(case='original_years') yield scen, test_mp
def test_add_year_cli(message_ix_cli, base_scen_mp): scen_ref, test_mp = base_scen_mp # Information about the base Scenario platform_name = test_mp.name model = scen_ref.model scenario = scen_ref.scenario cmd = [ "--platform", platform_name, "--model", model, "--scenario", scenario, "add-years", "--years_new", repr(YEARS_NEW), "--model_new", "add_year", "--scen_new", "standard", ] # Delete the objects so that the database connection is closed del test_mp, scen_ref r = message_ix_cli(*cmd) print(r.output, r.exception) assert r.exit_code == 0 # Re-load the base Scenario mp = Platform(name=platform_name) scen_ref = Scenario(mp, model=model, scenario=scenario) # Load the created Scenario scen_new = Scenario(mp, model="add_year", scenario="standard") assert_function(scen_ref, scen_new, YEARS_NEW, yr_test=2025) # Same, except with --dry-run r = message_ix_cli(*cmd, "--dry-run") assert r.exit_code == 0 # Bad usage: not giving the base scenario info r = message_ix_cli(*cmd[6:], "--dry-run") assert r.exit_code == 2
def adding_years(test_mp, scen_ref, years_new): scen_new = Scenario(test_mp, model="add_year", scenario="standard", version="new", annotation=" ") add_year(scen_ref, scen_new, years_new) return scen_new
def test_commodity_price(test_mp): scen = Scenario(test_mp, "test_commodity_price", "standard", version="new") model_setup(scen) scen.commit("initialize test model") scen.solve(case="price_commodity_standard") assert scen.var("OBJ")["lvl"] == 1 assert scen.var("PRICE_COMMODITY")["lvl"][0] == 1
def test_solve_legacy_scenario(test_legacy_mp): scen = Scenario(test_legacy_mp, *msg_args) exp = scen.var('OBJ')['lvl'] # solve scenario, assert that the new objective value is close to previous scen.remove_solution() scen.solve() assert np.isclose(exp, scen.var('OBJ')['lvl'])
def test_commodity_price(test_mp): scen = Scenario(test_mp, 'test_commodity_price', 'standard', version='new') model_setup(scen) scen.commit('initialize test model') scen.solve(case='price_commodity_standard') assert scen.var('OBJ')['lvl'] == 1 assert scen.var('PRICE_COMMODITY')['lvl'][0] == 1
def adding_years(test_mp, scen_ref, years_new): scen_new = Scenario(test_mp, model='add_year', scenario='standard', version='new', annotation=' ') add_year(scen_ref, scen_new, years_new) return scen_new
def test_vintage_and_active_years(test_mp): scen = Scenario(test_mp, *msg_args, version='new') scen.add_horizon({'year': ['2000', '2010', '2020'], 'firstmodelyear': '2010'}) obs = scen.vintage_and_active_years() exp = pd.DataFrame({'year_vtg': (2000, 2000, 2010, 2010, 2020), 'year_act': (2010, 2020, 2010, 2020, 2020)}) pdt.assert_frame_equal(exp, obs, check_like=True) # ignore col order
def test_add_cat_unique(test_mp): scen = Scenario(test_mp, *msg_multiyear_args) scen2 = scen.clone(keep_solution=False) scen2.check_out() scen2.add_cat('year', 'firstmodelyear', 2020, True) df = scen2.cat('year', 'firstmodelyear') npt.assert_array_equal(df, ['2020']) scen2.discard_changes()
def test_share_commodity_lo(test_mp): scen = Scenario(test_mp, *msg_args) scen.solve() # data for share bound def calc_share(s): a = calculate_activity( s, tec='transport_from_seattle').loc['to_new-york'] b = calculate_activity( s, tec='transport_from_san-diego').loc['to_new-york'] return a / (a + b) exp = 1. * calc_share(scen) # add share constraints clone = scen.clone(scenario='share_commodity_lo', keep_solution=False) clone.check_out() clone.add_cat('technology', 'share', 'transport_from_seattle') clone.add_cat('technology', 'total', ['transport_from_seattle', 'transport_from_san-diego']) clone.add_set('shares', 'test-share') clone.add_set('map_shares_commodity_share', pd.DataFrame({ 'shares': 'test-share', 'node_share': 'new-york', 'node': 'new-york', 'type_tec': 'share', 'mode': 'all', 'commodity': 'cases', 'level': 'consumption', }, index=[0])) clone.add_set('map_shares_commodity_total', pd.DataFrame({ 'shares': 'test-share', 'node_share': 'new-york', 'node': 'new-york', 'type_tec': 'total', 'mode': 'all', 'commodity': 'cases', 'level': 'consumption', }, index=[0])) clone.add_par('share_commodity_lo', pd.DataFrame({ 'shares': 'test-share', 'node_share': 'new-york', 'year_act': 2010, 'time': 'year', 'unit': 'cases', 'value': exp, }, index=[0])) clone.commit('foo') clone.solve() obs = calc_share(clone) assert np.isclose(obs, exp) orig_obj = scen.var('OBJ')['lvl'] new_obj = clone.var('OBJ')['lvl'] assert new_obj >= orig_obj
def test_excel_read_write(test_mp): fname = 'test_excel_read_write.xlsx' scen1 = Scenario(test_mp, *msg_args) scen1.to_excel(fname) scen2 = Scenario(test_mp, model='foo', scenario='bar', version='new') scen2.read_excel(fname) exp = scen1.par('input') obs = scen2.par('input') pdt.assert_frame_equal(exp, obs) scen2.commit('foo') # must be checked in scen2.solve() assert np.isclose(scen2.var('OBJ')['lvl'], 153.675) os.remove(fname)
def test_excel_read_write(message_test_mp, tmp_path): # Path to temporary file tmp_path /= 'excel_read_write.xlsx' # Convert to string to ensure this can be handled fname = str(tmp_path) scen1 = Scenario(message_test_mp, **SCENARIO['dantzig']) scen1 = scen1.clone(keep_solution=False) scen1.check_out() scen1.init_set('new_set') scen1.add_set('new_set', 'member') scen1.init_par('new_par', idx_sets=['new_set']) scen1.add_par('new_par', 'member', 2, '-') scen1.commit('new set and parameter added.') # Writing to Excel without solving scen1.to_excel(fname) # Writing to Excel when scenario has a solution scen1.solve() scen1.to_excel(fname) scen2 = Scenario(message_test_mp, model='foo', scenario='bar', version='new') # Fails without init_items=True with pytest.raises(ValueError, match="no set 'new_set'"): scen2.read_excel(fname) # Succeeds with init_items=True scen2.read_excel(fname, init_items=True, commit_steps=True) exp = scen1.par('input') obs = scen2.par('input') pdt.assert_frame_equal(exp, obs) assert scen2.has_par('new_par') assert float(scen2.par('new_par')['value']) == 2 scen2.commit('foo') # must be checked in scen2.solve() assert np.isclose(scen2.var('OBJ')['lvl'], scen1.var('OBJ')['lvl'])
def test_reporter(test_mp): scen = Scenario(test_mp, 'canning problem (MESSAGE scheme)', 'standard') # Varies between local & CI contexts # DEBUG may be due to reuse of test_mp in a non-deterministic order if not scen.has_solution(): scen.solve() # IXMPReporter can be initialized on a MESSAGE Scenario rep_ix = ixmp_Reporter.from_scenario(scen) # message_ix.Reporter can also be initialized rep = Reporter.from_scenario(scen) # Number of quantities available in a rudimentary MESSAGEix Scenario assert len(rep.graph['all']) == 120 # Quantities have short dimension names assert 'demand:n-c-l-y-h' in rep.graph # Aggregates are available assert 'demand:n-l-h' in rep.graph # Quantities contain expected data dims = dict(coords=['chicago new-york topeka'.split()], dims=['n']) demand = xr.DataArray([300, 325, 275], **dims) # NB the call to squeeze() drops the length-1 dimensions c-l-y-h obs = rep.get('demand:n-c-l-y-h').squeeze(drop=True) # TODO: Squeeze on AttrSeries still returns full index, whereas xarray # drops everything except node obs = obs.reset_index(['c', 'l', 'y', 'h'], drop=True) # check_dtype is false because of casting in pd.Series to float # check_attrsis false because we don't get the unit addition in bare xarray assert_qty_equal(obs.sort_index(), demand, check_attrs=False, check_dtype=False) # ixmp.Reporter pre-populated with only model quantities and aggregates assert len(rep_ix.graph) == 5088 # message_ix.Reporter pre-populated with additional, derived quantities assert len(rep.graph) == 7975 # Derived quantities have expected dimensions vom_key = rep.full_key('vom') assert vom_key not in rep_ix assert vom_key == 'vom:nl-t-yv-ya-m-h' # …and expected values vom = ( rep.get(rep.full_key('ACT')) * rep.get(rep.full_key('var_cost')) ).dropna() # check_attrs false because `vom` multiply above does not add units assert_qty_equal(vom, rep.get(vom_key), check_attrs=False)
def test_years_active_extend(test_mp): scen = Scenario(test_mp, *msg_multiyear_args) scen = scen.clone(keep_solution=False) scen.check_out() scen.add_set('year', ['2040', '2050']) scen.add_par('duration_period', '2040', 10, 'y') scen.add_par('duration_period', '2050', 10, 'y') df = scen.years_active('seattle', 'canning_plant', '2020') npt.assert_array_equal(df, [2020, 2030, 2040]) scen.discard_changes()
def test_add_cat(test_mp): scen = Scenario(test_mp, *msg_args) scen2 = scen.clone(keep_solution=False) scen2.check_out() scen2.add_cat('technology', 'trade', ['transport_from_san-diego', 'transport_from_seattle']) df = scen2.cat('technology', 'trade') npt.assert_array_equal( df, ['transport_from_san-diego', 'transport_from_seattle']) scen2.discard_changes()
def test_rename_technology(test_mp): scen = Scenario(test_mp, *msg_args) assert scen.par('output')['technology'].isin(['canning_plant']).any() clone = scen.clone('foo', 'bar') clone.rename('technology', {'canning_plant': 'foo_bar'}) assert not clone.par('output')['technology'].isin(['canning_plant']).any() assert clone.par('output')['technology'].isin(['foo_bar']).any() clone.solve() assert np.isclose(clone.var('OBJ')['lvl'], 153.675)
def test_no_constraint(test_mp): scen = Scenario(test_mp, MODEL, "no_constraint", version="new") model_setup(scen, [2020, 2030]) scen.commit("initialize test scenario") scen.solve(quiet=True) # without emissions constraint, the zero-cost technology satisfies demand assert scen.var("OBJ")["lvl"] == 0 # without emissions constraint, there are no emission prices assert scen.var("PRICE_EMISSION").empty