psr-factory 5.0.0b69__py3-none-manylinux_2_28_x86_64.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.

Potentially problematic release.


This version of psr-factory might be problematic. Click here for more details.

@@ -0,0 +1,242 @@
1
+ """Creates SDDP 12 stages Case21 example."""
2
+ import copy
3
+ import os
4
+
5
+ import psr.factory
6
+
7
+
8
+ def _get_case_path() -> str:
9
+ return os.path.join(os.path.splitext(os.path.basename(__file__))[0], "")
10
+
11
+
12
+ def create_case21(legacy: bool = False) -> psr.factory.Study:
13
+ # Create a study object and define its basic settings.
14
+ blocks = 1
15
+ model = "SDDP" if not legacy else "SDDP17"
16
+ # A context defines the dimensions of the study and the meaning of
17
+ # its stages. You can only share or copy data from one study to another
18
+ # if they share the same context.
19
+ context = psr.factory.get_new_context()
20
+ context.set("Models", [model, ]) # Default model: Sddp
21
+ context.set("Blocks", blocks) # Default number of blocks: 3
22
+ context.set("StageType", 2) # Weekly: 1, Monthly: 2 (default)
23
+
24
+ study = psr.factory.create_study(context)
25
+ study.set("Description", "SDDP")
26
+ study.set("InitialYear", 2016)
27
+ study.set("InitialStage", 1)
28
+ study.set("NumberOfStages", 12)
29
+ study.set("NumberOfSeries", 1)
30
+
31
+ # Study options
32
+ study.set("PARModel", 2)
33
+ study.set("InitialYearOfHydrology", 2016)
34
+ study.set("NumberOfSystems", 1)
35
+ study.set("AggregateInTheOperationPolicy", 1)
36
+ study.set("DeficitSegment", [100.0, 0.0, 0.0, 0.0])
37
+ study.set("DeficitCost", [1000.0, 0.0, 0.0, 0.0])
38
+ study.set("UMON", "$")
39
+
40
+ # Study duration
41
+ study.set("FixedDurationOfBlocks(1)", 100.0)
42
+
43
+ # By default, a study comes with one system.
44
+ system = study.get("System")[0]
45
+ system.code = 1
46
+ system.id = "s1"
47
+ system.name = "S1"
48
+ # System's currency
49
+ system.set("SystemCurrency", "$")
50
+ # It's not required to add an existing object to the study.
51
+
52
+ # Set study to run with this unique system
53
+ study.set("CodesOfPowerSystems", [1, ])
54
+
55
+ # Create a demand segment - it's required to add at least
56
+ # inelastic segment to a demand object.
57
+ segment = psr.factory.create("DemandSegment", context)
58
+ # Set demand and cost data.
59
+ segment.set_at("EnergyPerBlock(:)", "01/2016", 11.7)
60
+ segment.set_at("EnergyPerBlock(:)", "02/2016", 10.8)
61
+ segment.set_at("EnergyPerBlock(:)", "03/2016", 12.5)
62
+ segment.set_at("EnergyPerBlock(:)", "04/2016", 13.7)
63
+ segment.set_at("EnergyPerBlock(:)", "05/2016", 14.6)
64
+ segment.set_at("EnergyPerBlock(:)", "06/2016", 14.8)
65
+ segment.set_at("EnergyPerBlock(:)", "07/2016", 15.8)
66
+ segment.set_at("EnergyPerBlock(:)", "08/2016", 16.2)
67
+ segment.set_at("EnergyPerBlock(:)", "09/2016", 15.3)
68
+ segment.set_at("EnergyPerBlock(:)", "10/2016", 14.5)
69
+ segment.set_at("EnergyPerBlock(:)", "11/2016", 12.9)
70
+ segment.set_at("EnergyPerBlock(:)", "12/2016", 12.5)
71
+
72
+ segment.set_at("PricePerBlock(:)", "01/2016", 0.0)
73
+ # Add segment to the study.
74
+ study.add(segment)
75
+
76
+ # Create a system demand.
77
+ demand = psr.factory.create("Demand", context)
78
+ demand.code = 1
79
+ demand.name = "S1"
80
+ # Associate it with the only system in the case.
81
+ demand.set("RefSystem", system)
82
+ # Add segment to the demand.
83
+ demand.set("RefSegments", [segment, ])
84
+ # Add demand to the study.
85
+ study.add(demand)
86
+
87
+ # Create all fuels - Thermal plants requires them.
88
+ fuel1 = psr.factory.create("Fuel", context)
89
+ fuel1.code = 1
90
+ fuel1.name = "C1"
91
+ fuel1.set("Unit", "MWh")
92
+ fuel1.set("Price", 8.0)
93
+ fuel1.set("RefSystem", system)
94
+ study.add(fuel1)
95
+
96
+ fuel2 = psr.factory.create("Fuel", context)
97
+ fuel2.code = 2
98
+ fuel2.name = "C2"
99
+ fuel2.set("Unit", "MWh")
100
+ fuel2.set("Price", 12.0)
101
+ fuel2.set("RefSystem", system)
102
+ study.add(fuel2)
103
+
104
+ fuel3 = psr.factory.create("Fuel", context)
105
+ fuel3.code = 3
106
+ fuel3.name = "C3"
107
+ fuel3.set("Unit", "MWh")
108
+ fuel3.set("Price", 14.4)
109
+ fuel3.set("RefSystem", system)
110
+ study.add(fuel3)
111
+
112
+ # Create all thermal plants.
113
+ plant1 = psr.factory.create("ThermalPlant", context)
114
+ plant1.code = 1
115
+ plant1.name = "T1"
116
+ # Set plant's properties
117
+ plant1.set("MaximumGenerationCapacity", 12.0)
118
+ plant1.set("InstalledCapacity", 12.0)
119
+ plant1.set("ThermalType", 0) # Standard operation mode.
120
+ plant1.set("Type", 0) # It's an existing plant.
121
+ plant1.set("NumberOfUnits", 1)
122
+ plant1.set("NumberOfAlternativeFuels", 0) # No alternative fuels
123
+ plant1.set("CodeOfAlternativeFuels(:)", 0)
124
+ plant1.set("O&MCost", 0.0)
125
+ plant1.set("FuelTransportationCost", 0.0)
126
+ plant1.set("SpecificConsumptionSegment(1)", 100.0)
127
+ plant1.set("SpecificConsumptionSegment(2:3)", 0.0)
128
+ plant1.set("SpecificConsumption(1:3,1)", 1.0)
129
+ plant1.set("Co2EmissionCoefficient", 1.0)
130
+ # It's required to associate a thermal plant to a fuel.
131
+ plant1.set("RefFuels", [fuel1, ])
132
+ plant1.set("RefSystem", system)
133
+ # These references are optional and can be set as None.
134
+ plant1.set("RefGasNode", None)
135
+ study.add(plant1)
136
+
137
+ plant2 = psr.factory.create("ThermalPlant", context)
138
+ plant2.code = 2
139
+ plant2.name = "T2"
140
+ plant2.set("MaximumGenerationCapacity", 8.0)
141
+ plant2.set("InstalledCapacity", 8.0)
142
+ plant2.set("ThermalType", 0)
143
+ plant2.set("Type", 0)
144
+ plant2.set("NumberOfUnits", 1)
145
+ plant2.set("NumberOfAlternativeFuels", 0)
146
+ plant2.set("CodeOfAlternativeFuels(:)", 0)
147
+ plant2.set("O&MCost", 0.0)
148
+ plant2.set("FuelTransportationCost", 0.0)
149
+ plant2.set("SpecificConsumptionSegment(1)", 100.0)
150
+ plant2.set("SpecificConsumptionSegment(2:3)", 0.0)
151
+ plant2.set("SpecificConsumption(1:3,1)", 1.0)
152
+ plant2.set("Co2EmissionCoefficient", 1.0)
153
+ plant2.set("RefFuels", [fuel2, ])
154
+ plant2.set("RefSystem", system)
155
+ study.add(plant2)
156
+
157
+ plant3 = plant2.clone()
158
+ plant3.code = 3
159
+ plant3.name = "T3"
160
+ plant3.set("MaximumGenerationCapacity", 4.0)
161
+ plant3.set("InstalledCapacity", 4.0)
162
+ plant3.set("RefFuels", [fuel3, ])
163
+ plant3.set("RefSystem", system)
164
+ study.add(plant3)
165
+
166
+ # Define gauging station for hydro plants inflows
167
+ station1 = psr.factory.create("HydroStation", context)
168
+ station1.code = 1
169
+ station1.name = "Estacion 1"
170
+
171
+ station2 = psr.factory.create("HydroStation", context)
172
+ station2.code = 2
173
+ station2.name = "Estacion 2"
174
+
175
+ for year in (2014, 2015, 2016):
176
+ station1.set_at("Inflow", f"01/{year}", 13.5)
177
+ station1.set_at("Inflow", f"02/{year}", 40.7)
178
+ station1.set_at("Inflow", f"03/{year}", 28.8)
179
+ station1.set_at("Inflow", f"04/{year}", 25.6)
180
+ station1.set_at("Inflow", f"05/{year}", 23.8)
181
+ station1.set_at("Inflow", f"06/{year}", 27.8)
182
+ station1.set_at("Inflow", f"07/{year}", 28.8)
183
+ station1.set_at("Inflow", f"08/{year}", 18.8)
184
+ station1.set_at("Inflow", f"09/{year}", 18.2)
185
+ station1.set_at("Inflow", f"10/{year}", 29.6)
186
+ station1.set_at("Inflow", f"11/{year}", 17.7)
187
+ station1.set_at("Inflow", f"12/{year}", 26.3)
188
+
189
+ for month in range(1, 12 + 1):
190
+ station2.set_at("Vazao", f"{month:02d}/{year}", 0.0)
191
+
192
+ study.add(station1)
193
+ study.add(station2)
194
+
195
+ # Define hydroplants
196
+ hydro1 = psr.factory.create("HydroPlant", context)
197
+ hydro1.code = 1
198
+ hydro1.name = "H1"
199
+ hydro1.set("Type", 0)
200
+ hydro1.set("NumberOfUnits", 1)
201
+ hydro1.set("InstalledCapacity", 5.5)
202
+ hydro1.set("MaximumTurbinedOutflow", 55.0)
203
+ hydro1.set("MeanProductionCoefficient", 0.1)
204
+ hydro1.set("MinimumStorage", 0.0)
205
+ hydro1.set("MaximumStorage", 50.0)
206
+ hydro1.set("InitialCondition", 0.2)
207
+ hydro1.set("RefSystem", system)
208
+ hydro1.set("RefStation", station1)
209
+ study.add(hydro1)
210
+
211
+ hydro2 = hydro1.clone()
212
+ hydro2.code = 2
213
+ hydro2.name = "H2"
214
+ hydro2.set("MaximumStorage", 0.0)
215
+ hydro2.set("InitialCondition", 1.0)
216
+ hydro2.set("RefSystem", system)
217
+ hydro2.set("RefStation", station2)
218
+ study.add(hydro2)
219
+
220
+ # Connect hydro plants
221
+ connection_spill = psr.factory.create("HydroPlantConnection", context)
222
+ connection_spill.set("IsVertimento", 1)
223
+ connection_spill.set("RefPlants", [hydro1, hydro2])
224
+ study.add(connection_spill)
225
+
226
+ connection_turb = psr.factory.create("HydroPlantConnection", context)
227
+ connection_turb.set("IsTurbinamento", 1)
228
+ connection_turb.set("RefPlants", [hydro1, hydro2])
229
+ study.add(connection_turb)
230
+
231
+ return study
232
+
233
+
234
+ if __name__ == "__main__":
235
+ case_path = _get_case_path()
236
+ os.makedirs(case_path, exist_ok=True)
237
+ print("Creating example case... ", end="")
238
+ study = create_case21(False)
239
+ print(" OK.")
240
+ print("Saving example case in \"{}\"... ".format(case_path), end="")
241
+ study.save(case_path)
242
+ print(" OK.")
@@ -0,0 +1,5 @@
1
+ # PSR Factory. Copyright (C) PSR, Inc - All Rights Reserved
2
+ # Unauthorized copying of this file, via any medium is strictly prohibited
3
+ # Proprietary and confidential
4
+
5
+ from .outputs import *
psr/outputs/outputs.py ADDED
@@ -0,0 +1,179 @@
1
+ # PSR Factory. Copyright (C) PSR, Inc - All Rights Reserved
2
+ # Unauthorized copying of this file, via any medium is strictly prohibited
3
+ # Proprietary and confidential
4
+
5
+ import csv
6
+ import os
7
+ from pathlib import Path
8
+ from typing import (List)
9
+ import pandas
10
+ import psr.factory
11
+
12
+
13
+ _language_dict_map = {
14
+ 0: 'ENG',
15
+ 1: 'ESP',
16
+ 2: 'POR',
17
+ }
18
+
19
+ _default_language = 0
20
+
21
+
22
+ def __rename_lang_columns(df: pandas.DataFrame) -> pandas.DataFrame:
23
+ default_language_code = _language_dict_map.get(_default_language, 'ENG')
24
+ languages = list(_language_dict_map.values())
25
+ languages.remove(default_language_code)
26
+ lang_cols = [col for col in df.columns if col.startswith(tuple(languages))]
27
+ df = df.drop(columns=lang_cols)
28
+ # Rename the default language column to remove prefix ENG-
29
+ for column in df.columns:
30
+ if column.startswith(f"{default_language_code}-"):
31
+ new_col = column[len(f"{default_language_code}-"):]
32
+ df = df.rename(columns={column: new_col})
33
+ return df
34
+
35
+
36
+ def get_available_outputs_by_model(tool_path: str) -> pandas.DataFrame:
37
+ dat_file = os.path.join(tool_path, "indexdat.fmt")
38
+ if not os.path.exists(dat_file):
39
+ raise FileNotFoundError(f"Could not find {dat_file}")
40
+ cls_file = os.path.join(tool_path, "indexcls.fmt")
41
+ if not os.path.exists(cls_file):
42
+ raise FileNotFoundError(f"Could not find {cls_file}")
43
+ typ_file = os.path.join(tool_path, "indextyp.fmt")
44
+ if not os.path.exists(typ_file):
45
+ raise FileNotFoundError(f"Could not find {typ_file}")
46
+
47
+ dat_df = pandas.read_csv(dat_file, delimiter=',', encoding='latin1', skiprows=1)
48
+ dat_df = __rename_lang_columns(dat_df)
49
+ dat_df.drop(columns=["PSRIO"], inplace=True)
50
+
51
+ cls_df = pandas.read_csv(cls_file, delimiter=',', encoding='latin1', skiprows=1)
52
+ cls_df = __rename_lang_columns(cls_df)
53
+ cls_df.rename(columns={"Name": "ClassName"}, inplace=True)
54
+ cls_df.drop(columns=["Description", "PSRIO-Class"], inplace=True)
55
+
56
+ typ_df = pandas.read_csv(typ_file, delimiter=',', encoding='latin1', skiprows=1)
57
+ typ_df = __rename_lang_columns(typ_df)
58
+ typ_df.rename(columns={"Name": "TypeName"}, inplace=True)
59
+
60
+ # merge class names and type names
61
+ dat_df = dat_df.merge(cls_df, how='left', left_on='Class', right_on='!Class')
62
+ dat_df = dat_df.merge(typ_df, how='left', left_on='Type', right_on='!Type')
63
+ dat_df.drop(columns=["!Class", "!Type"], inplace=True)
64
+ dat_df.rename(columns={"!Num": "Number", "TypeName": "Type", "ClassName": "Class"}, inplace=True)
65
+
66
+ return dat_df
67
+
68
+
69
+ class AvailableOutput:
70
+ def __init__(self):
71
+ self.filename = ""
72
+ self.file_type = ""
73
+ self.description = ""
74
+ self.unit = ""
75
+ self.attribute_class = ""
76
+ self.case_path = ""
77
+ def load_dataframe(self) -> psr.factory.DataFrame:
78
+ full_file_name = str(self)
79
+ return psr.factory.load_dataframe(full_file_name)
80
+
81
+ def __str__(self):
82
+ return os.path.join(self.case_path, f"{self.filename}.{self.file_type}")
83
+
84
+ def __repr__(self):
85
+ return f"AvailableOutput(path='{str(self)}', description='{self.description}', unit='{self.unit}', attribute_class={self.attribute_class})"
86
+
87
+
88
+ def get_available_outputs(case_path: str) -> List[AvailableOutput]:
89
+ indice_grf_path = os.path.join(case_path, "indice.grf")
90
+ outputs = []
91
+ with open(indice_grf_path, 'r', encoding='latin1') as f:
92
+ next(f) # Skip header
93
+ next(f)
94
+ reader = csv.reader(f, delimiter=',')
95
+ for row in reader:
96
+ if len(row) >= 4:
97
+ output = AvailableOutput()
98
+ full_file_name = row[0].strip()
99
+ output.filename, output.file_type = os.path.splitext(full_file_name)
100
+ output.filename = output.filename.strip()
101
+ output.file_type = output.file_type.lstrip('.').strip()
102
+ output.description = row[1].strip()
103
+ output.unit = row[2].strip()
104
+ output.attribute_class = row[3].strip()
105
+ output.case_path = case_path
106
+ outputs.append(output)
107
+ return outputs
108
+
109
+
110
+ class OutputsDataFrame(pandas.DataFrame):
111
+ def __setitem__(self, key, value):
112
+ if isinstance(value, bool):
113
+ self.loc[key, 'Active'] = value
114
+ else:
115
+ super().__setitem__(key, value)
116
+
117
+ def save(self, case_path: str) -> None:
118
+ save(self, case_path)
119
+
120
+
121
+ def save(df: pandas.DataFrame, case_path: str) -> None:
122
+ index_df = load_index_dat(case_path)
123
+
124
+ for filename, row in df.iterrows():
125
+ mask = index_df['Num'] == row['Num']
126
+ if any(mask):
127
+ index_df.loc[mask, 'YN'] = 1 if row['Active'] else 0
128
+
129
+ output_lines = ['Num Graph...........................|...Unid Type Y/N']
130
+ for _, row in index_df.iterrows():
131
+ line = f"{row['Num']:>3d} {row['Description']:<33}{row['Unit']:7} {int(row['Type']):>4d} {row['YN']:>4d}"
132
+ output_lines.append(line)
133
+
134
+ index_file = os.path.join(case_path, "index.dat")
135
+ with open(index_file, 'w', encoding='utf-8') as f:
136
+ for line in output_lines:
137
+ f.write(f"{line}\n")
138
+
139
+
140
+ def load_index_dat(case_path: str) -> pandas.DataFrame:
141
+ index_file = os.path.join(case_path, "index.dat")
142
+ if not os.path.exists(index_file):
143
+ raise FileNotFoundError(f"Could not find {index_file}")
144
+
145
+ widths = [4, 33, 8, 5, 4]
146
+ names = ['Num', 'Description', 'Unit', 'Type', 'YN']
147
+
148
+ return pandas.read_fwf(
149
+ index_file,
150
+ widths=widths,
151
+ names=names,
152
+ skiprows=1
153
+ )
154
+
155
+
156
+ def load(case_path: str) -> OutputsDataFrame:
157
+ sddp_path = Path("C:/PSR")
158
+ sddp_dirs = [d for d in sddp_path.iterdir() if d.name.startswith("Sddp")]
159
+ if not sddp_dirs:
160
+ raise FileNotFoundError("Could not find SDDP installation")
161
+ sddp_path = sorted(sddp_dirs)[-1]
162
+
163
+ fmt_file = Path(sddp_path) / "Oper" / "indexdat.fmt"
164
+ if not fmt_file.exists():
165
+ raise FileNotFoundError(f"Could not find {fmt_file}")
166
+
167
+ fmt_df = pandas.read_csv(fmt_file, delimiter=',', encoding='latin1', skiprows=1)
168
+ index_df = load_index_dat(case_path)
169
+
170
+ outputs_df = OutputsDataFrame()
171
+ for _, row in fmt_df.iterrows():
172
+ num = row['!Num']
173
+ filename = row['Filename']
174
+ index_row = index_df[index_df['Num'] == num]
175
+ if not index_row.empty:
176
+ outputs_df.loc[filename, 'Num'] = num
177
+ outputs_df.loc[filename, 'Active'] = bool(index_row['YN'].iloc[0])
178
+
179
+ return outputs_df