From 1e2b690e42b052fd796051c873b8e5111cc237f2 Mon Sep 17 00:00:00 2001 From: "pierre-francois.duc" Date: Tue, 8 Oct 2024 01:03:35 +0200 Subject: [PATCH] Modify PV panel to scale with sun resource Need to warn user if the PVPanel has existing capacity, otherwise solution is unbounded. The output power does not make any sense, there must be a typo The aggragated delivered power correspond to aggregated ghi multiplied by the optimized capacity --- .../data/constraints/solar_constraints.csv | 2 + .../data/elements/dispatchable.csv | 4 +- .../wefe_pv_panel/data/elements/pv_panel.csv | 4 +- .../scenarios/wefe_pv_panel/datapackage.json | 62 +++++++++++++++++-- .../wefe/constraints/constraint_facades.py | 31 ++++++++-- .../wefe/facades/pv_panel.py | 17 ++--- 6 files changed, 98 insertions(+), 22 deletions(-) create mode 100644 examples/scenarios/wefe_pv_panel/data/constraints/solar_constraints.csv diff --git a/examples/scenarios/wefe_pv_panel/data/constraints/solar_constraints.csv b/examples/scenarios/wefe_pv_panel/data/constraints/solar_constraints.csv new file mode 100644 index 0000000..41ca0a5 --- /dev/null +++ b/examples/scenarios/wefe_pv_panel/data/constraints/solar_constraints.csv @@ -0,0 +1,2 @@ +name;type +equal_solar_resource;equal_solar_resource diff --git a/examples/scenarios/wefe_pv_panel/data/elements/dispatchable.csv b/examples/scenarios/wefe_pv_panel/data/elements/dispatchable.csv index 7a73f12..0fe552d 100644 --- a/examples/scenarios/wefe_pv_panel/data/elements/dispatchable.csv +++ b/examples/scenarios/wefe_pv_panel/data/elements/dispatchable.csv @@ -1,3 +1,3 @@ name;type;carrier;tech;capacity;capacity_cost;bus;marginal_cost;carrier_cost;profile;output_parameters;expandable -solar-radiation;dispatchable;solar-energy;source;0;0;solar-energy-bus;0.0;0;ghi-profile;{};True -back-up-elec;dispatchable;electricity;source;0;0;elec-bus;0.5;0;;{};True +solar-radiation;volatile;solar-energy;source;0;0;solar-energy-bus;0.0;0.0;ghi;{};True +back-up-elec;dispatchable;electricity;source;0;10;elec-bus;10.0;0.3;1.0;{};True diff --git a/examples/scenarios/wefe_pv_panel/data/elements/pv_panel.csv b/examples/scenarios/wefe_pv_panel/data/elements/pv_panel.csv index 4947961..560562c 100644 --- a/examples/scenarios/wefe_pv_panel/data/elements/pv_panel.csv +++ b/examples/scenarios/wefe_pv_panel/data/elements/pv_panel.csv @@ -1,2 +1,2 @@ -name;type;carrier;tech;capacity;capacity_cost;marginal_cost;carrier_cost;from_bus;to_bus;t_air;ghi;pv_type;expandable -pv-panel;pv-panel;solar-energy;pv;0;0;0;0;solar-energy-bus;elec-bus;t-air;ghi;boviet_450;False +name;type;carrier;tech;capacity;capacity_cost;marginal_cost;carrier_cost;capacity_potential;from_bus;to_bus;t_air;ghi;p_rpv;r_ref;n_t;t_c_ref;noct;expandable +pv-panel;pv-panel;solar-energy;pv;0;0;0;-0.1;100;solar-energy-bus;elec-bus;t-air;ghi;270;1000;-0.0037;25;48;True diff --git a/examples/scenarios/wefe_pv_panel/datapackage.json b/examples/scenarios/wefe_pv_panel/datapackage.json index 8e9c5c4..7f5a2ee 100644 --- a/examples/scenarios/wefe_pv_panel/datapackage.json +++ b/examples/scenarios/wefe_pv_panel/datapackage.json @@ -1,8 +1,33 @@ { "profile": "tabular-data-package", "name": "wefe_pv_panel", - "oemof_tabular_version": "0.0.5", + "oemof_tabular_version": "0.0.6dev", "resources": [ + { + "path": "data/constraints/solar_constraints.csv", + "profile": "tabular-data-resource", + "name": "solar_constraints", + "format": "csv", + "mediatype": "text/csv", + "encoding": "utf-8", + "schema": { + "fields": [ + { + "name": "name", + "type": "string", + "format": "default" + }, + { + "name": "type", + "type": "string", + "format": "default" + } + ], + "missingValues": [ + "" + ] + } + }, { "path": "data/elements/bus.csv", "profile": "tabular-data-resource", @@ -86,7 +111,7 @@ }, { "name": "carrier_cost", - "type": "integer", + "type": "number", "format": "default" }, { @@ -120,7 +145,7 @@ { "fields": "profile", "reference": { - "resource": "dispatchable_profile" + "resource": "pv_panel_profile" } } ] @@ -273,6 +298,11 @@ }, { "name": "carrier_cost", + "type": "number", + "format": "default" + }, + { + "name": "capacity_potential", "type": "integer", "format": "default" }, @@ -297,8 +327,28 @@ "format": "default" }, { - "name": "pv_type", - "type": "string", + "name": "p_rpv", + "type": "integer", + "format": "default" + }, + { + "name": "r_ref", + "type": "integer", + "format": "default" + }, + { + "name": "n_t", + "type": "number", + "format": "default" + }, + { + "name": "t_c_ref", + "type": "integer", + "format": "default" + }, + { + "name": "noct", + "type": "integer", "format": "default" }, { @@ -427,4 +477,4 @@ } } ] -} +} \ No newline at end of file diff --git a/src/oemof_tabular_plugins/wefe/constraints/constraint_facades.py b/src/oemof_tabular_plugins/wefe/constraints/constraint_facades.py index ac36e8a..67d32e4 100644 --- a/src/oemof_tabular_plugins/wefe/constraints/constraint_facades.py +++ b/src/oemof_tabular_plugins/wefe/constraints/constraint_facades.py @@ -1,5 +1,6 @@ import logging from dataclasses import dataclass +from oemof.solph.components import Source from oemof.solph.constraints import equate_variables from oemof.tabular.constraint_facades import ConstraintFacade @@ -13,19 +14,41 @@ def build_constraint(self, model): # to use the constraints in oemof.solph, we need to pass the model. # Check if there are flows with the keyword attribute - crops = [n for n in model.nodes if n.type == "crop"] + crops = [n for n in model.nodes if n.type in ("pv-panel", "crop", "mimo-crop")] for crop in crops: - harvest_bus = crop.harvest_bus - solar_bus = crop.solar_bus + if crop.type == "crop": + invest_bus = crop.harvest_bus + component_capacity = model.InvestmentFlowBlock.invest[ + crop, invest_bus, 0 + ] + solar_bus = crop.solar_bus + elif crop.type == "pv-panel": + invest_bus = crop.to_bus + component_capacity = model.InvestmentFlowBlock.invest[ + crop, invest_bus, 0 + ] + solar_bus = crop.from_bus + + elif crop.type == "mimo-crop": + if crop.expandable is True: + invest_bus = model.es.groups[crop.primary] + component_capacity = model.InvestmentFlowBlock.invest[ + invest_bus, crop, 0 + ] + else: + component_capacity = None + solar_bus = crop.solar_energy_bus + solar_nodes = [n for n in solar_bus.inputs if n.tech == "source"] + solar_radiation = solar_nodes[0] if crop.expandable is True and solar_radiation.expandable is True: try: # Add constraint to the model equate_variables( model, - model.InvestmentFlowBlock.invest[crop, harvest_bus, 0], model.InvestmentFlowBlock.invest[solar_radiation, solar_bus, 0], + component_capacity, ) except KeyError: logging.error( diff --git a/src/oemof_tabular_plugins/wefe/facades/pv_panel.py b/src/oemof_tabular_plugins/wefe/facades/pv_panel.py index 8bce71a..00f09ab 100644 --- a/src/oemof_tabular_plugins/wefe/facades/pv_panel.py +++ b/src/oemof_tabular_plugins/wefe/facades/pv_panel.py @@ -120,7 +120,7 @@ def build_solph_components(self): self.conversion_factors.update( { - self.from_bus: sequence(1), + self.from_bus: sequence(ghi_values), self.to_bus: sequence(pv_efficiency_list), } ) @@ -136,6 +136,7 @@ def build_solph_components(self): self.outputs.update( { self.to_bus: Flow( + fix=pv_tf_values, nominal_value=self._nominal_value(), variable_costs=self.marginal_cost, investment=self._investment(), @@ -144,12 +145,12 @@ def build_solph_components(self): } ) - def processing_raw_inputs(self, resource, results_df): - # function to apply on df from above + def processing_raw_inputs(self, resource, results_df): + # function to apply on df from above - return results_df + return results_df - def validate_datapackage(self, resource): - # modify the resource (datapackage.resource) - # should it return the resource? - pass + def validate_datapackage(self, resource): + # modify the resource (datapackage.resource) + # should it return the resource? + pass