diff --git a/changelog.rst b/changelog.rst index e92d7ec4a..0bb821c02 100644 --- a/changelog.rst +++ b/changelog.rst @@ -16,6 +16,16 @@ User-facing changes |new| Files containing user-defined mathematical formulations can be referenced in the model configuration. User-defined mathematical formulations must follow the new Calliope YAML math syntax (see "Internal changes" below). +|changed| |backwards-incompatible| Flow efficiencies are now split into inflow (`flow_in_eff`) and outflow (`flow_out_eff`) efficiencies. This enables different storage charge/discharge efficiencies to be applied. + +|changed| |backwards-incompatible| Mass parameter and decision variable renaming for increased clarity: + * `energy`/`carrier` → `flow`, e.g. `energy_cap` is now `flow_cap`. + * `prod`/`con` → `out`/`in`, e.g., `carrier_prod` is now `flow_out`. + * `resource` has been split into `source` (for things entering the model) and `sink` (for things leaving the model). + * `resource_area` is now `area_use`. + * `energy_cap_min_use` is now `flow_out_min_relative` (i.e., the value is relative to `flow_cap`). + * `parasitic_eff` is now `flow_out_parasitic_eff`. + |changed| |backwards-incompatible| Time masking and clustering capabilities have been severely reduced. Time resampling and clustering are now accessible by top-level configuration keys: e.g., `config.init.time_resample: 2H`, `config.init.time_cluster: cluster_file.csv`. Clustering is simplified to only matching model dates to representative days, with those representative days being in the clustered timeseries. Masking/clustering data should now be undertaken by the user prior to initialising a Calliope model. |changed| |backwards-incompatible| `Locations` (abbreviated to `locs`) are now referred to as `nodes` (no abbreviation). For users, this requires updating the top-level YAML key "locations" to "nodes" and accessing data in `model.inputs` and `model.results` on the set "nodes" rather than "locs". diff --git a/src/calliope/config/defaults.yaml b/src/calliope/config/defaults.yaml index b7ea0dbf8..874ec01cc 100644 --- a/src/calliope/config/defaults.yaml +++ b/src/calliope/config/defaults.yaml @@ -69,11 +69,11 @@ tech_groups: "flow_cap_per_unit", "flow_in_eff", "flow_out_eff", + "flow_out_parasitic_eff", "flow_ramping", "export_max", "export_carrier", "lifetime", - "parasitic_eff", "units_min_systemwide", "units_max", "units_max_systemwide", @@ -167,12 +167,12 @@ tech_groups: "flow_cap_per_unit", "flow_in_eff", "flow_out_eff", + "flow_out_parasitic_eff", "flow_ramping", "export_max", "export_carrier", "force_async_flow", "lifetime", - "parasitic_eff", "storage_cap_max", "storage_cap_min", "storage_cap_per_unit", @@ -219,11 +219,11 @@ tech_groups: "flow_cap_per_unit", "flow_in_eff", "flow_out_eff", + "flow_out_parasitic_eff", "flow_ramping", "export_max", "export_carrier", "lifetime", - "parasitic_eff", "area_use_max", "area_use_min", "area_use_per_flow_cap", @@ -273,11 +273,11 @@ tech_groups: "flow_cap_per_unit", "flow_in_eff", "flow_out_eff", + "flow_out_parasitic_eff", "flow_ramping", "export_max", "export_carrier", "lifetime", - "parasitic_eff", "area_use_max", "area_use_min", "area_use_per_flow_cap", @@ -343,12 +343,12 @@ tech_groups: "flow_cap_per_unit", "flow_in_eff", "flow_out_eff", + "flow_out_parasitic_eff", "flow_in_eff_per_distance", "flow_out_eff_per_distance", "force_async_flow", "lifetime", "one_way", - "parasitic_eff", ] allowed_costs: [ @@ -418,7 +418,7 @@ techs: export_max: .inf # name: Maximum allowed export ¦ unit: kW ¦ Maximum allowed export of produced carrier for a technology. export_carrier: null # name: Export carrier ¦ unit: N/A ¦ Name of carrier to be exported. Must be an output carrier of the technology lifetime: null # name: Technology lifetime ¦ unit: years ¦ Must be defined if fixed capital costs are defined. A reasonable value for many technologies is around 20-25 years. - parasitic_eff: 1.0 # name: Plant parasitic efficiency ¦ unit: fraction ¦ Additional losses as flow gets transferred from the plant to the carrier (static, or from file as timeseries), e.g. due to plant parasitic consumption + flow_out_parasitic_eff: 1.0 # name: Plant parasitic efficiency ¦ unit: fraction ¦ Additional losses as flow gets transferred from the plant to the carrier (static, or from file as timeseries), e.g. due to plant parasitic consumption sink_min: 0 # name: Minimum bound on sink to remove a carrier from the system (e.g., electricity demand, transport distance) ¦ unit: kWh | kWh/m\ :sup:`2` | kWh/kW ¦ Minimum sink use (static, or from file as timeseries). Unit dictated by ``source_unit``. sink_max: .inf # name: Maximum bound on sink to remove a carrier from the system (e.g., electricity demand, transport distance) ¦ unit: kWh | kWh/m\ :sup:`2` | kWh/kW ¦ Maximum sink use (static, or from file as timeseries). Unit dictated by ``source_unit``. sink_equals: null # name: Required amount removal of a carrier from the system through a sink (e.g., electricity demand, transport distance) ¦ unit: kWh | kWh/m\ :sup:`2` | kWh/kW ¦ Required sink (static, or from file as timeseries). Unit dictated by ``source_unit``. diff --git a/src/calliope/example_models/national_scale/model_config/techs.yaml b/src/calliope/example_models/national_scale/model_config/techs.yaml index c79aa6b12..48325363b 100644 --- a/src/calliope/example_models/national_scale/model_config/techs.yaml +++ b/src/calliope/example_models/national_scale/model_config/techs.yaml @@ -46,7 +46,7 @@ techs: storage_loss: 0.002 source_max: file=csp_resource.csv flow_out_eff: 0.4 - parasitic_eff: 0.9 + flow_out_parasitic_eff: 0.9 area_use_max: inf flow_cap_max: 10000 lifetime: 25 diff --git a/src/calliope/example_models/urban_scale/model_config/techs.yaml b/src/calliope/example_models/urban_scale/model_config/techs.yaml index 5b7415109..cfe4c842a 100644 --- a/src/calliope/example_models/urban_scale/model_config/techs.yaml +++ b/src/calliope/example_models/urban_scale/model_config/techs.yaml @@ -62,7 +62,7 @@ techs: area_use_per_flow_cap: 7 # 7m2 of panels needed to fit 1kWp of panels export_carrier: electricity source_equals: file=pv_resource.csv:per_area # Already accounts for panel efficiency - kWh/m2. Source: Renewables.ninja Solar PV Power - Version: 1.1 - License: https://creativecommons.org/licenses/by-nc/4.0/ - Reference: https://doi.org/10.1016/j.energy.2016.08.060 - parasitic_eff: 0.85 # inverter losses + flow_out_parasitic_eff: 0.85 # inverter losses flow_cap_max: 250 area_use_max: 1500 lifetime: 25 diff --git a/src/calliope/math/base.yaml b/src/calliope/math/base.yaml index b5c91ce0c..aa2b5c9cf 100644 --- a/src/calliope/math/base.yaml +++ b/src/calliope/math/base.yaml @@ -116,14 +116,14 @@ constraints: foreach: [nodes, techs, timesteps] where: "inheritance(conversion)" equations: - - expression: reduce_carrier_dim(flow_out, carrier_tier=out) == reduce_carrier_dim(flow_in, carrier_tier=in) * flow_in_eff * (flow_out_eff * parasitic_eff) + - expression: reduce_carrier_dim(flow_out, carrier_tier=out) == reduce_carrier_dim(flow_in, carrier_tier=in) * flow_in_eff * (flow_out_eff * flow_out_parasitic_eff) flow_out_max: description: "Set the upper bound of a non-`conversion_plus` technology's outflow." foreach: [nodes, techs, carriers, timesteps] where: "NOT inheritance(conversion_plus) AND NOT operating_units AND allowed_flow_out=True AND [out] in carrier_tiers" equations: - - expression: flow_out <= flow_cap * timestep_resolution * parasitic_eff + - expression: flow_out <= flow_cap * timestep_resolution * flow_out_parasitic_eff flow_out_min: description: "Set the lower bound of a non-`conversion_plus` technology's outflow." @@ -183,9 +183,9 @@ constraints: where: "(source_equals OR source_max) AND inheritance(supply)" equations: - where: "source_equals" - expression: "flow_out == source_equals * $source_scaler * flow_out_eff * parasitic_eff" + expression: "flow_out == source_equals * $source_scaler * flow_out_eff * flow_out_parasitic_eff" - where: "(NOT source_equals) AND sink_max" - expression: "flow_out <= source_max * $source_scaler * flow_out_eff * parasitic_eff" + expression: "flow_out <= source_max * $source_scaler * flow_out_eff * flow_out_parasitic_eff" sub_expressions: source_scaler: &source_scaler - where: "source_unit=per_area" @@ -200,7 +200,7 @@ constraints: foreach: [nodes, techs, carriers, timesteps] where: "source_min AND NOT source_equals AND inheritance(supply)" equations: - - expression: "flow_out / (flow_out_eff * parasitic_eff) >= source_min * $source_scaler" + - expression: "flow_out / (flow_out_eff * flow_out_parasitic_eff) >= source_min * $source_scaler" sub_expressions: source_scaler: *source_scaler @@ -235,14 +235,14 @@ constraints: foreach: [nodes, techs, carriers, timesteps] where: "inheritance(supply_plus) AND NOT include_storage=True" equations: - - expression: flow_out == source_use * source_eff * flow_out_eff * parasitic_eff + - expression: flow_out == source_use * source_eff * flow_out_eff * flow_out_parasitic_eff balance_supply_plus_with_storage: description: "Set the upper bound on, or a fixed total of, a `supply_plus` (with storage) technology's ability to produce flow based on the quantity of consumed resource and available stored carrier." foreach: [nodes, techs, carriers, timesteps] where: "storage AND inheritance(supply_plus)" equations: - - expression: storage == $storage_previous_step + source_use * source_eff - flow_out / (flow_out_eff * parasitic_eff) + - expression: storage == $storage_previous_step + source_use * source_eff - flow_out / (flow_out_eff * flow_out_parasitic_eff) sub_expressions: storage_previous_step: &storage_previous_step - where: timesteps=get_val_at_index(timesteps=0) AND NOT config.cyclic_storage=True @@ -269,7 +269,7 @@ constraints: foreach: [nodes, techs, timesteps] where: "inheritance(storage)" equations: - - expression: storage == $storage_previous_step - reduce_carrier_dim(flow_out, carrier_tier=out) / (flow_out_eff * parasitic_eff) + reduce_carrier_dim(flow_in, carrier_tier=in) * flow_in_eff + - expression: storage == $storage_previous_step - reduce_carrier_dim(flow_out, carrier_tier=out) / (flow_out_eff * flow_out_parasitic_eff) + reduce_carrier_dim(flow_in, carrier_tier=in) * flow_in_eff sub_expressions: storage_previous_step: *storage_previous_step @@ -288,7 +288,7 @@ constraints: foreach: [nodes, techs, carriers, timesteps] where: "inheritance(transmission) AND allowed_flow_out=True" equations: - - expression: "flow_out == select_from_lookup_arrays(flow_in * flow_in_eff * $distance_flow_in_eff, techs=link_remote_techs, nodes=link_remote_nodes) * (flow_out_eff * parasitic_eff * $distance_flow_out_eff)" + - expression: "flow_out == select_from_lookup_arrays(flow_in * flow_in_eff * $distance_flow_in_eff, techs=link_remote_techs, nodes=link_remote_nodes) * (flow_out_eff * flow_out_parasitic_eff * $distance_flow_out_eff)" sub_expressions: distance_flow_out_eff: - where: flow_out_eff_per_distance AND distance @@ -337,7 +337,7 @@ constraints: foreach: [nodes, techs, carriers, timesteps] where: "operating_units AND NOT inheritance(conversion_plus) AND allowed_flow_out=True" equations: - - expression: flow_out <= operating_units * timestep_resolution * flow_cap_per_unit * parasitic_eff + - expression: flow_out <= operating_units * timestep_resolution * flow_cap_per_unit * flow_out_parasitic_eff flow_out_max_conversion_plus_milp: description: "Set the upper bound of a `conversion_plus` technology's ability to outflow across all of its `out` carriers, if it uses integer units to define its capacity." diff --git a/tests/test_backend_pyomo.py b/tests/test_backend_pyomo.py index 386da7cfc..70e6cf8c1 100755 --- a/tests/test_backend_pyomo.py +++ b/tests/test_backend_pyomo.py @@ -44,7 +44,9 @@ def test_operate_cyclic_storage(self, on): assert not check_warn assert m._model_data.attrs["config"].build.cyclic_storage is False - @pytest.mark.parametrize("param", [("flow_eff"), ("source_eff"), ("parasitic_eff")]) + @pytest.mark.parametrize( + "param", [("flow_eff"), ("source_eff"), ("flow_out_parasitic_eff")] + ) def test_loading_timeseries_operate_efficiencies(self, param): m = build_model( {