diff --git a/doc/api/tools-costs.rst b/doc/api/tools-costs.rst index d08c4fa252..4ab2c6edc9 100644 --- a/doc/api/tools-costs.rst +++ b/doc/api/tools-costs.rst @@ -48,6 +48,9 @@ Currently, :mod:`.tools.costs` supports two module :attr:`~.Config.module` setti "materials" Technologies conceived as part of the materials and industry sectors. +"cooling" + Cooling technologies for power plants. + Data and files for a particular module can refer to other modules. This allows for values or settings for "materials" and other technologies to be assumed to match the values and settings used for the referenced "energy"-module technologies. @@ -86,9 +89,9 @@ To add a new module, the following steps are required: Please note that the following assumptions are made in technology costs mapping: - If a technology is mapped to a technology in the "energy" module, then the cost reduction across scenarios is the same as the cost reduction of the mapped technology. -- If a "materials" (or any other non-"energy") technology has :py:`reg_diff_source="energy"` and the "base_year_reference_region_cost" is not empty, then the "base_year_reference_region_cost" in :file:`tech_map_[module].csv` is used as the base year cost for the technology in the reference region. +- If a non-"energy" module (such as "materials" or "cooling") technology has :py:`reg_diff_source="energy"` and the "base_year_reference_region_cost" is not empty, then the "base_year_reference_region_cost" in :file:`tech_map_[module].csv` is used as the base year cost for the technology in the reference region. If the "base_year_reference_region_cost" is empty, then the cost reduction across scenarios is the same as the cost reduction of the mapped technology. -- If using the "materials" module, if a technology that is specified in :file:`tech_map_materials.csv` already exists in :file:`tech_map_energy.csv`, then the reference region cost is taken from :file:`tech_map_materials.csv`. +- If using a non-"energy" module (such as "materials" or "cooling"), if a technology that is specified in :file:`tech_map_materials.csv` already exists in :file:`tech_map_energy.csv`, then the reference region cost is taken from :file:`tech_map_materials.csv`. - If a technology in a module is not mapped to any source of regional differentiation, then no cost reduction over the years is applied to the technology. - If a technology has a non-empty "base_year_reference_region_cost" but is not mapped to any source of regional differentiation, then assume no regional differentiation and use the reference region base year cost as the base year cost for all regions. @@ -222,7 +225,7 @@ Regional differentiation of costs (:mod:`~.costs.regional_differentiation`) get_weo_data get_intratec_data get_raw_technology_mapping - subset_materials_map + subset_module_map adjust_technology_mapping get_weo_regional_differentiation get_intratec_regional_differentiation diff --git a/doc/whatsnew.rst b/doc/whatsnew.rst index 67c6eef4fa..9879f3c371 100644 --- a/doc/whatsnew.rst +++ b/doc/whatsnew.rst @@ -9,7 +9,7 @@ Next release - Expand :doc:`repro` with sections on :ref:`repro-doc` and :ref:`versioning`, including :ref:`a list of external model names and ‘versions’ ` like “MESSAGEix-GLOBIOM 2.0” (:issue:`224`, :pull:`226`). - Update :doc:`/transport/index` (:pull:`213`). - Add "LED", "SSP4", and "SSP5" as values for the :program:`--ssp=…` option in :func:`.common_params` (:pull:`233`). -- Fix and update :doc:`/api/tools-costs` (:pull:`219`, :pull:`206`, :pull:`221`, :pull:`227`) +- Fix and update :doc:`/api/tools-costs` (:pull:`219`, :pull:`206`, :pull:`221`, :pull:`227`, :pull:`222`) - Fix naming of GDP and population columns in SSP data aggregation (:pull:`219`). - Edit inputs for storage, CSP, hydrogen, and industry technologies (:pull:`206`). @@ -17,6 +17,7 @@ Next release - Reorganize input files and incorporate `first_year.csv` data into `tech_map.csv` (:pull:`221`). - Reconfigure use and implementation of technology variants/modules to be more agnostic (:pull:`221`). - Change cost decay to reach reduction percentage specified on the year 2100 (:pull:`227`). + - Add `cooling` technology variant/module (:pull:`222`). v2024.8.6 ========= diff --git a/message_ix_models/data/costs/cooling/tech_map.csv b/message_ix_models/data/costs/cooling/tech_map.csv new file mode 100644 index 0000000000..8b44a2053a --- /dev/null +++ b/message_ix_models/data/costs/cooling/tech_map.csv @@ -0,0 +1,93 @@ +message_technology,reg_diff_source,reg_diff_technology,base_year_reference_region_cost,fix_ratio,first_year_original +bio_hpl__air,energy,bio_hpl,220,0,2015 +bio_hpl__cl_fresh,energy,bio_hpl,100,0,2015 +bio_hpl__ot_fresh,energy,bio_hpl,0.4,0,2015 +bio_hpl__ot_saline,energy,bio_hpl,0.3,0,2015 +bio_istig__air,energy,bio_istig,220,0,2015 +bio_istig__cl_fresh,energy,bio_istig,100,0,2015 +bio_istig__ot_fresh,energy,bio_istig,0.4,0,2015 +bio_istig__ot_saline,energy,bio_istig,0.3,0,2015 +bio_istig_ccs__air,energy,bio_istig_ccs,220,0,2015 +bio_istig_ccs__cl_fresh,energy,bio_istig_ccs,100,0,2015 +bio_istig_ccs__ot_fresh,energy,bio_istig_ccs,0.4,0,2015 +bio_istig_ccs__ot_saline,energy,bio_istig_ccs,0.3,0,2015 +bio_ppl__air,energy,bio_ppl,220,0,2015 +bio_ppl__cl_fresh,energy,bio_ppl,100,0,2015 +bio_ppl__ot_fresh,energy,bio_ppl,0.4,0,2015 +bio_ppl__ot_saline,energy,bio_ppl,0.3,0,2015 +coal_adv__air,energy,coal_adv,220,0,2015 +coal_adv__cl_fresh,energy,coal_adv,100,0,2015 +coal_adv__ot_fresh,energy,coal_adv,0.4,0,2015 +coal_adv__ot_saline,energy,coal_adv,0.3,0,2015 +coal_adv_ccs__air,energy,coal_adv_ccs,220,0,2015 +coal_adv_ccs__cl_fresh,energy,coal_adv_ccs,160,0,2015 +coal_adv_ccs__ot_fresh,energy,coal_adv_ccs,0.4,0,2015 +coal_adv_ccs__ot_saline,energy,coal_adv_ccs,0.3,0,2015 +coal_ppl__air,energy,coal_ppl,220,0,2015 +coal_ppl__cl_fresh,energy,coal_ppl,100,0,2015 +coal_ppl__ot_fresh,energy,coal_ppl,0.4,0,2015 +coal_ppl__ot_saline,energy,coal_ppl,0.3,0,2015 +coal_ppl_u__air,energy,coal_ppl_u,220,0,2015 +coal_ppl_u__cl_fresh,energy,coal_ppl_u,160,0,2015 +coal_ppl_u__ot_fresh,energy,coal_ppl_u,0.4,0,2015 +coal_ppl_u__ot_saline,energy,coal_ppl_u,0.3,0,2015 +foil_hpl__air,energy,foil_hpl,220,0,2015 +foil_hpl__cl_fresh,energy,foil_hpl,100,0,2015 +foil_hpl__ot_fresh,energy,foil_hpl,0.4,0,2015 +foil_hpl__ot_saline,energy,foil_hpl,0.3,0,2015 +foil_ppl__air,energy,foil_ppl,220,0,2015 +foil_ppl__cl_fresh,energy,foil_ppl,100,0,2015 +foil_ppl__ot_fresh,energy,foil_ppl,0.4,0,2015 +foil_ppl__ot_saline,energy,foil_ppl,0.3,0,2015 +gas_cc__air,energy,gas_cc,140,0,2015 +gas_cc__cl_fresh,energy,gas_cc,50,0,2015 +gas_cc__ot_fresh,energy,gas_cc,0.2,0,2015 +gas_cc__ot_saline,energy,gas_cc,0.15,0,2015 +gas_cc_ccs__air,energy,gas_cc_ccs,220,0,2015 +gas_cc_ccs__cl_fresh,energy,gas_cc_ccs,160,0,2015 +gas_cc_ccs__ot_fresh,energy,gas_cc_ccs,0.4,0,2015 +gas_cc_ccs__ot_saline,energy,gas_cc_ccs,0.3,0,2015 +gas_hpl__air,energy,gas_hpl,220,0,2015 +gas_hpl__cl_fresh,energy,gas_hpl,100,0,2015 +gas_hpl__ot_fresh,energy,gas_hpl,0.4,0,2015 +gas_hpl__ot_saline,energy,gas_hpl,0.3,0,2015 +gas_ppl__air,energy,gas_ppl,220,0,2015 +gas_ppl__cl_fresh,energy,gas_ppl,100,0,2015 +gas_ppl__ot_fresh,energy,gas_ppl,0.4,0,2015 +gas_ppl__ot_saline,energy,gas_ppl,0.3,0,2015 +geo_hpl__air,energy,geo_hpl,220,0,2015 +geo_hpl__cl_fresh,energy,geo_hpl,100,0,2015 +geo_hpl__ot_fresh,energy,geo_hpl,0.4,0,2015 +geo_hpl__ot_saline,energy,geo_hpl,0.3,0,2015 +geo_ppl__air,energy,geo_ppl,220,0,2015 +geo_ppl__cl_fresh,energy,geo_ppl,100,0,2015 +geo_ppl__ot_fresh,energy,geo_ppl,0.4,0,2015 +geo_ppl__ot_saline,energy,geo_ppl,0.3,0,2015 +igcc__air,energy,igcc,140,0,2015 +igcc__cl_fresh,energy,igcc,50,0,2015 +igcc__ot_fresh,energy,igcc,0.4,0,2015 +igcc__ot_saline,energy,igcc,0.3,0,2015 +igcc_ccs__air,energy,igcc_ccs,220,0,2015 +igcc_ccs__cl_fresh,energy,igcc_ccs,100,0,2015 +igcc_ccs__ot_fresh,energy,igcc_ccs,0.4,0,2015 +igcc_ccs__ot_saline,energy,igcc_ccs,0.3,0,2015 +loil_cc__air,energy,loil_cc,140,0,2015 +loil_cc__cl_fresh,energy,loil_cc,50,0,2015 +loil_cc__ot_fresh,energy,loil_cc,0.2,0,2015 +loil_cc__ot_saline,energy,loil_cc,0.3,0,2015 +loil_ppl__air,energy,loil_ppl,220,0,2015 +loil_ppl__cl_fresh,energy,loil_ppl,100,0,2015 +loil_ppl__ot_fresh,energy,loil_ppl,0.4,0,2015 +loil_ppl__ot_saline,energy,loil_ppl,0.3,0,2015 +nuc_hc__air,energy,nuc_hc,220,0,2015 +nuc_hc__cl_fresh,energy,nuc_hc,100,0,2015 +nuc_hc__ot_fresh,energy,nuc_hc,0.4,0,2015 +nuc_hc__ot_saline,energy,nuc_hc,0.3,0,2015 +nuc_lc__air,energy,nuc_lc,220,0,2015 +nuc_lc__cl_fresh,energy,nuc_lc,160,0,2015 +nuc_lc__ot_fresh,energy,nuc_lc,0.8,0,2015 +nuc_lc__ot_saline,energy,nuc_lc,0.6,0,2015 +solar_th_ppl__air,energy,solar_th_ppl,220,0,2015 +solar_th_ppl__cl_fresh,energy,solar_th_ppl,100,0,2015 +solar_th_ppl__ot_fresh,energy,solar_th_ppl,0.4,0,2015 +solar_th_ppl__ot_saline,energy,solar_th_ppl,0.3,0,2015 diff --git a/message_ix_models/tests/tools/costs/test_decay.py b/message_ix_models/tests/tools/costs/test_decay.py index d720f1d28d..2ae706e3a3 100644 --- a/message_ix_models/tests/tools/costs/test_decay.py +++ b/message_ix_models/tests/tools/costs/test_decay.py @@ -18,6 +18,7 @@ ( ("energy", {"coal_ppl", "gas_ppl", "gas_cc", "solar_res1"}), ("materials", {"biomass_NH3", "MTO_petro", "furnace_foil_steel"}), + ("cooling", {"coal_ppl__cl_fresh", "gas_cc__air", "nuc_lc__ot_fresh"}), ), ) def test_get_cost_reduction_data(module: str, t_exp) -> None: @@ -32,7 +33,7 @@ def test_get_cost_reduction_data(module: str, t_exp) -> None: assert 0 <= stats["min"] and stats["max"] <= 1 -@pytest.mark.parametrize("module", ("energy", "materials")) +@pytest.mark.parametrize("module", ("energy", "materials", "cooling")) def test_get_technology_reduction_scenarios_data(module: str) -> None: config = Config() # The function runs without error @@ -57,10 +58,11 @@ def test_get_technology_reduction_scenarios_data(module: str) -> None: {"biomass_NH3"}, ), ("materials", {"biomass_NH3", "MTO_petro", "furnace_foil_steel"}, set()), + ("cooling", {"coal_ppl__cl_fresh", "gas_cc__air", "nuc_lc__ot_fresh"}, set()), ), ) def test_project_ref_region_inv_costs_using_reduction_rates( - module: Literal["energy", "materials"], t_exp, t_excluded + module: Literal["energy", "materials", "cooling"], t_exp, t_excluded ) -> None: # Set up config = Config(module=module) diff --git a/message_ix_models/tests/tools/costs/test_gdp.py b/message_ix_models/tests/tools/costs/test_gdp.py index 5e9cdf385d..07f177c230 100644 --- a/message_ix_models/tests/tools/costs/test_gdp.py +++ b/message_ix_models/tests/tools/costs/test_gdp.py @@ -52,7 +52,7 @@ def test_process_raw_ssp_data(test_context, node) -> None: assert scens == set(result.scenario.unique()) -@pytest.mark.parametrize("module", ("energy", "materials")) +@pytest.mark.parametrize("module", ("energy", "materials", "cooling")) def test_adjust_cost_ratios_with_gdp(test_context, module) -> None: # Set parameters test_context.model.regions = "R12" diff --git a/message_ix_models/tests/tools/costs/test_projections.py b/message_ix_models/tests/tools/costs/test_projections.py index 1b4f507c2a..99005d1244 100644 --- a/message_ix_models/tests/tools/costs/test_projections.py +++ b/message_ix_models/tests/tools/costs/test_projections.py @@ -34,6 +34,11 @@ } }, ), + ( + Config(module="cooling", method="gdp", node="R12", scenario="SSP5"), + {"technology": {"coal_ppl__cl_fresh", "gas_cc__air", "nuc_lc__ot_fresh"}}, + {"technology": {"coal_ppl__cl_fresh", "gas_cc__air", "nuc_lc__ot_fresh"}}, + ), pytest.param( Config(node="R20"), set(), diff --git a/message_ix_models/tests/tools/costs/test_regional_differentiation.py b/message_ix_models/tests/tools/costs/test_regional_differentiation.py index c8656fb9a3..486776eb0d 100644 --- a/message_ix_models/tests/tools/costs/test_regional_differentiation.py +++ b/message_ix_models/tests/tools/costs/test_regional_differentiation.py @@ -74,6 +74,11 @@ def test_get_intratec_data() -> None: ( ("energy", {"coal_ppl", "gas_ppl", "gas_cc", "solar_res1"}, {"weo"}), ("materials", {"biomass_NH3", "meth_h2", "furnace_foil_steel"}, {"energy"}), + ( + "cooling", + {"coal_ppl__cl_fresh", "gas_cc__air", "nuc_lc__ot_fresh"}, + {"energy"}, + ), ), ) def test_get_raw_technology_mapping(module, t_exp, rds_exp) -> None: @@ -87,7 +92,7 @@ def test_get_raw_technology_mapping(module, t_exp, rds_exp) -> None: assert rds_exp <= set(result.reg_diff_source.unique()) -@pytest.mark.parametrize("module", ("energy", "materials")) +@pytest.mark.parametrize("module", ("energy", "materials", "cooling")) def test_adjust_technology_mapping(module) -> None: energy_raw = get_raw_technology_mapping("energy") @@ -110,6 +115,7 @@ def test_adjust_technology_mapping(module) -> None: ( ("energy", {"coal_ppl", "gas_ppl", "gas_cc", "solar_res1"}), ("materials", {"biomass_NH3", "meth_h2", "furnace_foil_steel"}), + ("cooling", {"coal_ppl__cl_fresh", "gas_cc__air", "nuc_lc__ot_fresh"}), ), ) def test_apply_regional_differentiation(module, t_exp) -> None: diff --git a/message_ix_models/tools/costs/config.py b/message_ix_models/tools/costs/config.py index 548941b326..d4023469a3 100644 --- a/message_ix_models/tools/costs/config.py +++ b/message_ix_models/tools/costs/config.py @@ -53,7 +53,7 @@ class Config: method: Literal["constant", "convergence", "gdp"] = "gdp" #: Model variant for which to project costs. - module: Literal["energy", "materials"] = "energy" + module: Literal["energy", "materials", "cooling"] = "energy" #: Use vintages. #: diff --git a/message_ix_models/tools/costs/regional_differentiation.py b/message_ix_models/tools/costs/regional_differentiation.py index c181492594..40bc85b7b6 100644 --- a/message_ix_models/tools/costs/regional_differentiation.py +++ b/message_ix_models/tools/costs/regional_differentiation.py @@ -171,7 +171,7 @@ def get_intratec_data() -> pd.DataFrame: def get_raw_technology_mapping( - module: Literal["energy", "materials"], + module: Literal["energy", "materials", "cooling"], ) -> pd.DataFrame: """Retrieve a technology mapping for `module`. @@ -234,7 +234,7 @@ def subset_module_map(raw_map): def adjust_technology_mapping( - module: Literal["energy", "materials"], + module: Literal["energy", "materials", "cooling"], ) -> pd.DataFrame: """Adjust technology mapping based on sources and assumptions.