Skip to content

Commit e438258

Browse files
committed
Merge remote-tracking branch 'origin/HydroCHiPPs'
2 parents e733073 + 4cb4fcc commit e438258

File tree

3 files changed

+1516
-4
lines changed

3 files changed

+1516
-4
lines changed

src/pownet/core/visualizer.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,7 @@ def plot_fuelmix_bar(
4242
fig, ax = plt.subplots(figsize=(8, 5))
4343

4444
dispatch.plot.bar(
45-
stacked=True, ax=ax, linewidth=0, color=self.fuel_color_map, legend=False
45+
stacked=True, ax=ax, linewidth=0, color=self.fuel_color_map, legend=True
4646
)
4747
ax.plot(
4848
range(0, total_timesteps),
@@ -72,6 +72,7 @@ def plot_fuelmix_bar(
7272
bbox_inches="tight",
7373
dpi=350,
7474
)
75+
plt.tight_layout()
7576
plt.show()
7677

7778
def plot_fuelmix_area(

src/pownet/input.py

Lines changed: 60 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -112,6 +112,7 @@ def __init__(
112112

113113
self.ess_hydro_units: dict[str, list[str]] = {}
114114
self.ess_daily_hydro_units: dict[str, list[str]] = {}
115+
self.ess_weekly_hydro_units: dict[str, list[str]] = {}
115116
self.ess_solar_units: dict[str, list[str]] = {}
116117
self.ess_wind_units: dict[str, list[str]] = {}
117118
self.ess_thermal_units: dict[str, list[str]] = {}
@@ -137,10 +138,13 @@ def __init__(
137138
# Hydropower (hourly and daily timeseries)
138139
self.hydro_contracted_capacity: dict[str, float] = {}
139140
self.hydro_capacity: pd.DataFrame = pd.DataFrame()
141+
self.hydro_min_capacity: pd.DataFrame = pd.DataFrame()
140142
self.hydro_max_capacity: dict[str, float] = {}
141143
self.hydro_unit_node: dict[str, str] = {}
142144
self.daily_hydro_capacity: pd.DataFrame = pd.DataFrame()
143145
self.daily_hydro_unit_node: dict[str, str] = {}
146+
self.weekly_hydro_capacity: pd.DataFrame = pd.DataFrame()
147+
self.weekly_hydro_unit_node: dict[str, str] = {}
144148

145149
self.solar_contracted_capacity: dict[str, float] = {}
146150
self.solar_capacity: pd.DataFrame = pd.DataFrame()
@@ -190,6 +194,7 @@ def __init__(
190194

191195
self.hydro_must_take_units: list[str] = []
192196
self.daily_hydro_must_take_units: list[str] = []
197+
self.weekly_hydro_must_take_units: list[str] = []
193198
self.solar_must_take_units: list[str] = []
194199
self.wind_must_take_units: list[str] = []
195200
self.import_must_take_units: list[str] = []
@@ -341,6 +346,9 @@ def load_ess_params(self):
341346
elif attached in self.daily_hydro_unit_node.keys():
342347
self.ess_daily_hydro_units[attached] = self.ess_attach_unit[attached]
343348

349+
elif attached in self.weekly_hydro_unit_node.keys():
350+
self.ess_weekly_hydro_units[attached] = self.ess_attach_unit[attached]
351+
344352
elif attached in self.solar_unit_node.keys():
345353
self.ess_solar_units[attached] = self.ess_attach_unit[attached]
346354

@@ -383,6 +391,7 @@ def _store_generators_by_node(self):
383391
self._add_units_to_node(node, self.thermal_unit_node)
384392
self._add_units_to_node(node, self.hydro_unit_node)
385393
self._add_units_to_node(node, self.daily_hydro_unit_node)
394+
self._add_units_to_node(node, self.weekly_hydro_unit_node)
386395
self._add_units_to_node(node, self.solar_unit_node)
387396
self._add_units_to_node(node, self.wind_unit_node)
388397
self._add_units_to_node(node, self.import_unit_node)
@@ -482,6 +491,17 @@ def _load_hydropower(self) -> None:
482491
daily_hydro_max_capacity = self.daily_hydro_capacity.max().to_dict()
483492
self.hydro_max_capacity.update(daily_hydro_max_capacity)
484493

494+
# Units with weekly timeseries
495+
if os.path.exists(os.path.join(self.model_dir, "hydropower_weekly.csv")):
496+
self.weekly_hydro_capacity, self.weekly_hydro_unit_node = (
497+
self._load_capacity_and_update_fuelmap_and_get_unit_node(
498+
"hydropower_weekly.csv", fuel_type="hydropower"
499+
)
500+
)
501+
502+
if os.path.exists(os.path.join(self.model_dir, "hydro_capacity_min.csv")):
503+
self.hydro_capacity_min = pd.read_csv(os.path.join(self.model_dir, "hydro_capacity_min.csv"))
504+
485505
# Check that the names do not repeat across different types
486506
repeated_units = set(self.hydro_unit_node.keys()).intersection(
487507
self.daily_hydro_unit_node.keys()
@@ -491,6 +511,24 @@ def _load_hydropower(self) -> None:
491511
f"PowNet: Found hydropower units to formulate with both hourly and daily formulations: {repeated_units}"
492512
)
493513

514+
# Check that the names do not repeat across different types
515+
repeated_units_weekly = set(self.hydro_unit_node.keys()).intersection(
516+
self.weekly_hydro_unit_node.keys()
517+
)
518+
if repeated_units_weekly:
519+
raise ValueError(
520+
f"PowNet: Found hydropower units to formulate with both hourly and weekly formulations: {repeated_units_weekly}"
521+
)
522+
523+
# Check that the names do not repeat across different types
524+
repeated_units_daily_weekly = set(self.daily_hydro_unit_node.keys()).intersection(
525+
self.weekly_hydro_unit_node.keys()
526+
)
527+
if repeated_units_daily_weekly:
528+
raise ValueError(
529+
f"PowNet: Found hydropower units to formulate with both daily and weekly formulations: {repeated_units_daily_weekly}"
530+
)
531+
494532
def _load_nondispatchable_must_take_units(self):
495533
# A system can comprise only thermal units
496534
if not os.path.exists(os.path.join(self.model_dir, "nondispatch_unit.csv")):
@@ -503,6 +541,7 @@ def _load_nondispatchable_must_take_units(self):
503541
unit_types = {
504542
"hydro": self.hydro_unit_node,
505543
"daily_hydro": self.daily_hydro_unit_node,
544+
"weekly_hydro": self.weekly_hydro_unit_node,
506545
"solar": self.solar_unit_node,
507546
"wind": self.wind_unit_node,
508547
"import": self.import_unit_node,
@@ -575,6 +614,13 @@ def _load_contracted_capacity(self) -> None:
575614
.to_dict()
576615
)
577616

617+
# Add daily hydro units to the contracted capacity under "hydro"
618+
self.hydro_contracted_capacity.update(
619+
nondispatch_df.loc[nondispatch_df["name"].isin(self.weekly_hydro_unit_node)]
620+
.set_index("name")["contracted_capacity"]
621+
.to_dict()
622+
)
623+
578624
def load_data(self):
579625
"""Load the input data for the power system model.
580626
Timeseries are loaded as dataframes with the index starting at 1.
@@ -638,6 +684,7 @@ def load_data(self):
638684
list(self.thermal_unit_node.keys())
639685
+ list(self.hydro_unit_node.keys())
640686
+ list(self.daily_hydro_unit_node.keys())
687+
+ list(self.weekly_hydro_unit_node.keys())
641688
+ list(self.solar_unit_node.keys())
642689
+ list(self.wind_unit_node.keys())
643690
+ list(self.import_unit_node.keys())
@@ -736,9 +783,9 @@ def load_data(self):
736783
# List of units
737784
#################
738785
self.thermal_units = list(self.thermal_unit_node.keys())
739-
self.hydro_units = list(self.hydro_unit_node.keys()) + list(
740-
self.daily_hydro_unit_node.keys()
741-
)
786+
self.hydro_units = (list(self.hydro_unit_node.keys())
787+
+ list(self.daily_hydro_unit_node.keys())
788+
+ list(self.weekly_hydro_unit_node.keys()))
742789
self.solar_units = list(self.solar_unit_node.keys())
743790
self.wind_units = list(self.wind_unit_node.keys())
744791
self.import_units = list(self.import_unit_node.keys())
@@ -784,6 +831,7 @@ def check_data(self):
784831
nodes_to_check = [
785832
("hydro_unit_node", "Hydropower units"),
786833
("daily_hydro_unit_node", "Daily hydropower units"),
834+
("weekly_hydro_unit_node", "Weekly hydropower units"),
787835
("solar_unit_node", "Solar units"),
788836
("wind_unit_node", "Wind units"),
789837
("import_unit_node", "Import units"),
@@ -837,6 +885,11 @@ def check_data(self):
837885
f"PowNet: Daily hydropower timeseries must be of length {self.num_sim_days}."
838886
)
839887

888+
if len(self.weekly_hydro_capacity) not in [0, self.num_sim_days]:
889+
raise ValueError(
890+
f"PowNet: Weekly hydropower timeseries must be of length {self.num_sim_days}."
891+
)
892+
840893
##################################
841894
# The derated capacities of thermal units must be above its minimum capacity
842895
##################################
@@ -872,6 +925,7 @@ def check_data(self):
872925
number_of_non_fossil_generators = len(
873926
self.hydro_unit_node
874927
| self.daily_hydro_unit_node
928+
| self.weekly_hydro_unit_node
875929
| self.solar_unit_node
876930
| self.wind_unit_node
877931
| self.import_unit_node
@@ -934,6 +988,7 @@ def check_data(self):
934988
assigned_ess = (
935989
list(self.ess_hydro_units.keys())
936990
+ list(self.ess_daily_hydro_units.keys())
991+
+ list(self.ess_weekly_hydro_units.keys())
937992
+ list(self.ess_solar_units.keys())
938993
+ list(self.ess_wind_units.keys())
939994
+ list(self.ess_thermal_units.keys())
@@ -961,13 +1016,15 @@ def print_summary(self):
9611016
---- Renewable capacities ----
9621017
{'Hydropower units':<25} = {len(self.hydro_unit_node)}
9631018
{'Daily hydropower units':<25} = {len(self.daily_hydro_unit_node)}
1019+
{'Weekly hydropower units':<25} = {len(self.weekly_hydro_unit_node)}
9641020
{'Solar units':<25} = {len(self.solar_unit_node)}
9651021
{'Wind units':<25} = {len(self.wind_unit_node)}
9661022
{'Import units':<25} = {len(self.import_unit_node)}
9671023
9681024
---- Energy storage ----
9691025
{'No. of hydropower with ESS':<25} = {len(self.ess_hydro_units)}
9701026
{'No. of daily hydropower with ESS':<25} = {len(self.ess_daily_hydro_units)}
1027+
{'No. of weekly hydropower with ESS':<25} = {len(self.ess_weekly_hydro_units)}
9711028
{'No. of Solar with ESS':<25} = {len(self.ess_solar_units)}
9721029
{'No. of Wind with ESS':<25} = {len(self.ess_wind_units)}
9731030
{'No. of Thermal units with ESS':<25} = {len(self.ess_thermal_units)}

0 commit comments

Comments
 (0)