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.
- psr/apps/__init__.py +7 -0
- psr/apps/apps.py +225 -0
- psr/apps/version.py +5 -0
- psr/execqueue/client.py +126 -0
- psr/execqueue/config.py +52 -0
- psr/execqueue/db.py +286 -0
- psr/execqueue/server.py +689 -0
- psr/execqueue/watcher.py +146 -0
- psr/factory/__init__.py +7 -0
- psr/factory/api.py +2745 -0
- psr/factory/factory.pmd +7322 -0
- psr/factory/factory.pmk +19461 -0
- psr/factory/factorylib.py +410 -0
- psr/factory/libfactory.so +0 -0
- psr/factory/py.typed +0 -0
- psr/factory/samples/__init__.py +2 -0
- psr/factory/samples/sddp_case01.py +166 -0
- psr/factory/samples/sddp_case21.py +242 -0
- psr/outputs/__init__.py +5 -0
- psr/outputs/outputs.py +179 -0
- psr/outputs/resample.py +289 -0
- psr/psrfcommon/__init__.py +6 -0
- psr/psrfcommon/psrfcommon.py +57 -0
- psr/psrfcommon/tempfile.py +118 -0
- psr/runner/__init__.py +7 -0
- psr/runner/runner.py +743 -0
- psr/runner/version.py +5 -0
- psr_factory-5.0.0b69.dist-info/METADATA +47 -0
- psr_factory-5.0.0b69.dist-info/RECORD +32 -0
- psr_factory-5.0.0b69.dist-info/WHEEL +5 -0
- psr_factory-5.0.0b69.dist-info/licenses/LICENSE.txt +21 -0
- psr_factory-5.0.0b69.dist-info/top_level.txt +1 -0
|
@@ -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.")
|
psr/outputs/__init__.py
ADDED
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
|