@@ -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