1212)
1313
1414
15+ def find_upstream_flow (
16+ reservoir : Reservoir , reservoirs : dict [str , Reservoir ]
17+ ) -> pd .Series :
18+ unit_name = reservoir .name
19+ total_upstream_flow = pd .Series (
20+ 0 , index = range (1 , reservoir .sim_days + 1 ), name = "upstream_flow"
21+ )
22+ for upstream_unit in reservoir .upstream_units :
23+ upstream_reservoir = reservoirs [upstream_unit ]
24+ # Get the release and spill from the upstream reservoir
25+ total_upstream_flow += (
26+ upstream_reservoir .release + upstream_reservoir .spill
27+ ) * upstream_reservoir .downstream_flow_fracs [unit_name ]
28+ return total_upstream_flow
29+
30+
1531class ReservoirManager :
1632 def __init__ (self ):
1733 self .reservoirs : dict [str , Reservoir ] = {}
@@ -78,35 +94,21 @@ def load_reservoirs_from_csv(self, input_folder: str) -> None:
7894 #############################################################################
7995 # Process the network topology
8096 ##############################################################################
81- self .simulation_order = find_simulation_order (flow_paths )
82- # Ensure that all reservoirs are in the simulation order // The two sets must be equal
83- if set (self .simulation_order ) != set (self .reservoirs .keys ()):
84- raise ValueError (
85- "The simulation order does not include all reservoirs: "
86- f"{ set (self .simulation_order ) - set (self .reservoirs .keys ())} "
87- )
97+ self .simulation_order = find_simulation_order (
98+ reservoir_names = self .reservoirs .keys (), flow_paths = flow_paths
99+ )
88100
89101 def simulate (self ) -> None :
90102 """Simulate the reservoir operations to get hydropower time series."""
91103 for unit_name in self .simulation_order :
92104 reservoir = self .reservoirs [unit_name ]
93- # Find the upstream flow
94- total_upstream_flow = pd .Series (
95- 0 , index = range (1 , reservoir .sim_days + 1 ), name = "upstream_flow"
96- )
97-
98- for upstream_unit in reservoir .upstream_units :
99- upstream_reservoir = self .reservoirs [upstream_unit ]
100- # Get the release and spill from the upstream reservoir
101- total_upstream_flow += (
102- upstream_reservoir .release + upstream_reservoir .spill
103- ) * upstream_reservoir .downstream_flow_fracs [unit_name ]
104-
105- # Simulate
105+ total_upstream_flow = find_upstream_flow (reservoir , self .reservoirs )
106106 reservoir .set_upstream_flow (total_upstream_flow )
107107 reservoir .simulate ()
108108
109- def get_hydropower_ts (self ) -> pd .DataFrame :
109+ def get_hydropower_ts (
110+ self , unit_node_mapping : dict [str , str ] = None
111+ ) -> pd .DataFrame :
110112 """Get the hydropower time series for all reservoirs."""
111113 df = pd .DataFrame ()
112114 for unit_name in self .simulation_order :
@@ -119,10 +121,40 @@ def get_hydropower_ts(self) -> pd.DataFrame:
119121 df = pd .concat ([df , temp_df ], axis = 1 )
120122
121123 df .index = range (1 , len (df ) + 1 )
124+ # Create multi-level column index if unit_node_mapping is provided
125+ if unit_node_mapping :
126+ df .columns = pd .MultiIndex .from_tuples (
127+ [(unit , unit_node_mapping [unit ]) for unit in df .columns ]
128+ )
122129 return df
123130
124- def write_hydropower_to_csv (self , output_filepath : str ) -> None :
131+ def write_hydropower_to_csv (
132+ self , output_filepath : str , unit_node_mapping : dict [str , str ] = None
133+ ) -> None :
125134 """Write the hydropower time series to CSV files."""
126- os .makedirs (output_filepath , exist_ok = True )
127- for reservoir in self .reservoirs :
128- reservoir .hydropower .to_csv (output_filepath , index = False )
135+ hydropower_df = self .get_hydropower_ts (unit_node_mapping )
136+ hydropower_df .to_csv (output_filepath , index = False )
137+
138+ def reoperate (
139+ self , daily_dispatch : dict [(str , int ), float ], days_in_step : range
140+ ) -> dict [str , float ]:
141+ """Reoperate the reservoirs based on the daily dispatch of the power system model.
142+ Note that we don't reoperate on the first day of the simulation period.
143+ """
144+ proposed_capacity = {k : 0 for k in daily_dispatch .keys ()}
145+
146+ for unit_name in self .simulation_order :
147+ for day in days_in_step :
148+ reservoir = self .reservoirs [unit_name ]
149+ # Find the upstream flow
150+ total_upstream_flow = find_upstream_flow (reservoir , self .reservoirs )
151+
152+ # Simulate
153+ reservoir .set_upstream_flow (total_upstream_flow )
154+ proposed_capacity [unit_name , day ] = reservoir .reoperate (
155+ day = day ,
156+ daily_dispatch = daily_dispatch [unit_name , day ],
157+ upstream_flow_t = total_upstream_flow .loc [day ],
158+ )
159+
160+ return proposed_capacity
0 commit comments