exerpy 0.0.1__py3-none-any.whl → 0.0.3__py3-none-any.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.
Files changed (39) hide show
  1. exerpy/__init__.py +2 -4
  2. exerpy/analyses.py +597 -297
  3. exerpy/components/__init__.py +3 -0
  4. exerpy/components/combustion/base.py +157 -114
  5. exerpy/components/component.py +8 -8
  6. exerpy/components/heat_exchanger/base.py +593 -256
  7. exerpy/components/heat_exchanger/condenser.py +353 -166
  8. exerpy/components/heat_exchanger/simple.py +575 -225
  9. exerpy/components/heat_exchanger/steam_generator.py +153 -123
  10. exerpy/components/helpers/cycle_closer.py +61 -34
  11. exerpy/components/helpers/power_bus.py +117 -0
  12. exerpy/components/nodes/deaerator.py +221 -102
  13. exerpy/components/nodes/drum.py +50 -39
  14. exerpy/components/nodes/flash_tank.py +218 -43
  15. exerpy/components/nodes/mixer.py +296 -115
  16. exerpy/components/nodes/splitter.py +173 -0
  17. exerpy/components/nodes/storage.py +130 -0
  18. exerpy/components/piping/valve.py +351 -139
  19. exerpy/components/power_machines/generator.py +105 -38
  20. exerpy/components/power_machines/motor.py +111 -39
  21. exerpy/components/turbomachinery/compressor.py +181 -63
  22. exerpy/components/turbomachinery/pump.py +182 -63
  23. exerpy/components/turbomachinery/turbine.py +182 -74
  24. exerpy/functions.py +388 -263
  25. exerpy/parser/from_aspen/aspen_config.py +57 -48
  26. exerpy/parser/from_aspen/aspen_parser.py +373 -280
  27. exerpy/parser/from_ebsilon/__init__.py +2 -2
  28. exerpy/parser/from_ebsilon/check_ebs_path.py +15 -19
  29. exerpy/parser/from_ebsilon/ebsilon_config.py +329 -227
  30. exerpy/parser/from_ebsilon/ebsilon_functions.py +205 -38
  31. exerpy/parser/from_ebsilon/ebsilon_parser.py +392 -255
  32. exerpy/parser/from_ebsilon/utils.py +16 -11
  33. exerpy/parser/from_tespy/tespy_config.py +32 -1
  34. exerpy/parser/from_tespy/tespy_parser.py +151 -0
  35. {exerpy-0.0.1.dist-info → exerpy-0.0.3.dist-info}/METADATA +45 -4
  36. exerpy-0.0.3.dist-info/RECORD +48 -0
  37. exerpy-0.0.1.dist-info/RECORD +0 -44
  38. {exerpy-0.0.1.dist-info → exerpy-0.0.3.dist-info}/WHEEL +0 -0
  39. {exerpy-0.0.1.dist-info → exerpy-0.0.3.dist-info}/licenses/LICENSE +0 -0
@@ -2,17 +2,16 @@ import json
2
2
  import logging
3
3
  import os
4
4
 
5
- from exerpy.functions import convert_to_SI
6
- from exerpy.functions import fluid_property_data
5
+ from exerpy.functions import convert_to_SI, fluid_property_data
7
6
 
8
- from .aspen_config import connector_mappings
9
- from .aspen_config import grouped_components
7
+ from .aspen_config import connector_mappings, grouped_components
10
8
 
11
9
 
12
10
  class AspenModelParser:
13
11
  """
14
12
  A class to parse Aspen Plus models, simulate them, extract data, and write to JSON.
15
13
  """
14
+
16
15
  def __init__(self, model_path, split_physical_exergy=True):
17
16
  """
18
17
  Initializes the parser with the given model path.
@@ -29,21 +28,21 @@ class AspenModelParser:
29
28
 
30
29
  # Dictionary to map component types to specific connector assignment functions
31
30
  self.connector_assignment_functions = {
32
- 'Mixer': self.assign_mixer_connectors,
33
- 'RStoic': self.assign_combustion_chamber_connectors,
34
- 'FSplit': self.assign_splitter_connectors,
31
+ "Mixer": self.assign_mixer_connectors,
32
+ "RStoic": self.assign_combustion_chamber_connectors,
33
+ "FSplit": self.assign_splitter_connectors,
35
34
  # Add other specific component functions here
36
35
  }
37
36
 
38
-
39
37
  def initialize_model(self):
40
38
  """
41
39
  Initializes the Aspen Plus application and opens the specified model.
42
40
  """
43
41
  from win32com.client import Dispatch
42
+
44
43
  try:
45
44
  # Start Aspen Plus application via COM Dispatch
46
- self.aspen = Dispatch('Apwn.Document')
45
+ self.aspen = Dispatch("Apwn.Document")
47
46
  # Load the Aspen model file
48
47
  self.aspen.InitFromArchive2(self.model_path)
49
48
  logging.info(f"Model opened successfully: {self.model_path}")
@@ -69,164 +68,218 @@ class AspenModelParser:
69
68
  logging.error(f"Error while parsing the model: {e}")
70
69
  raise
71
70
 
72
-
73
71
  def parse_streams(self):
74
72
  """
75
73
  Parses the streams (connections) in the Aspen model.
76
74
  """
77
75
  # Get the stream nodes and their names
78
- stream_nodes = self.aspen.Tree.FindNode(r'\Data\Streams').Elements
76
+ stream_nodes = self.aspen.Tree.FindNode(r"\Data\Streams").Elements
79
77
  stream_names = [stream_node.Name for stream_node in stream_nodes]
80
78
 
81
79
  # ALL ASPEN CONNECTIONS
82
80
  # Initialize connection data with the common fields
83
81
  for stream_name in stream_names:
84
- stream_node = self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}')
82
+ self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}")
85
83
  connection_data = {
86
- 'name': stream_name,
87
- 'kind': None,
88
- 'source_component': None,
89
- 'source_connector': None,
90
- 'target_component': None,
91
- 'target_connector': None,
84
+ "name": stream_name,
85
+ "kind": None,
86
+ "source_component": None,
87
+ "source_connector": None,
88
+ "target_component": None,
89
+ "target_connector": None,
92
90
  }
93
91
 
94
92
  # Find the source and target components
95
- source_port_node = self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Ports\SOURCE')
93
+ source_port_node = self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Ports\SOURCE")
96
94
  if source_port_node is not None and source_port_node.Elements.Count > 0:
97
95
  connection_data["source_component"] = source_port_node.Elements(0).Name
98
96
 
99
- destination_port_node = self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Ports\DEST')
97
+ destination_port_node = self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Ports\DEST")
100
98
  if destination_port_node is not None and destination_port_node.Elements.Count > 0:
101
99
  connection_data["target_component"] = destination_port_node.Elements(0).Name
102
100
 
103
101
  # HEAT AND POWER STREAMS
104
- if self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Input\WORK') is not None:
105
- connection_data['kind'] = 'power'
106
- connection_data['energy_flow'] = convert_to_SI(
107
- 'power',
108
- abs(self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\POWER_OUT').Value),
109
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\POWER_OUT').UnitString
110
- ) if self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\POWER_OUT') is not None else None
111
- elif self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Input\HEAT') is not None:
112
- connection_data['kind'] = 'heat'
113
- connection_data['energy_flow'] = convert_to_SI(
114
- 'power',
115
- abs(self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\QCALC').Value),
116
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\QCALC').UnitString
117
- ) if self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\QCALC') is not None else None
102
+ if self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Input\WORK") is not None:
103
+ connection_data["kind"] = "power"
104
+ connection_data["energy_flow"] = (
105
+ convert_to_SI(
106
+ "power",
107
+ abs(self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\POWER_OUT").Value),
108
+ self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\POWER_OUT").UnitString,
109
+ )
110
+ if self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\POWER_OUT") is not None
111
+ else None
112
+ )
113
+ elif self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Input\HEAT") is not None:
114
+ connection_data["kind"] = "heat"
115
+ connection_data["energy_flow"] = (
116
+ convert_to_SI(
117
+ "power",
118
+ abs(self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\QCALC").Value),
119
+ self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\QCALC").UnitString,
120
+ )
121
+ if self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\QCALC") is not None
122
+ else None
123
+ )
118
124
 
119
125
  # MATERIAL STREAMS
120
126
  else:
121
127
  # Assume it's a material stream and retrieve additional properties
122
- connection_data.update({
123
- 'kind': 'material',
124
- 'T': (
125
- convert_to_SI(
126
- 'T',
127
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\TEMP_OUT\MIXED').Value,
128
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\TEMP_OUT\MIXED').UnitString
129
- ) if self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\TEMP_OUT\MIXED') is not None else None
130
- ),
131
- 'T_unit': fluid_property_data['T']['SI_unit'],
132
- 'p': (
133
- convert_to_SI(
134
- 'p',
135
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\PRES_OUT\MIXED').Value,
136
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\PRES_OUT\MIXED').UnitString
137
- ) if self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\PRES_OUT\MIXED') is not None else None
138
- ),
139
- 'p_unit': fluid_property_data['p']['SI_unit'],
140
- 'h': (
141
- convert_to_SI(
142
- 'h',
143
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\HMX_MASS\MIXED').Value,
144
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\HMX_MASS\MIXED').UnitString
145
- ) if self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\HMX_MASS\MIXED') is not None else None
146
- ),
147
- 'h_unit': fluid_property_data['h']['SI_unit'],
148
- 's': (
149
- convert_to_SI(
150
- 's',
151
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\SMX_MASS\MIXED').Value,
152
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\SMX_MASS\MIXED').UnitString
153
- ) if self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\SMX_MASS\MIXED') is not None else None
154
- ),
155
- 's_unit': fluid_property_data['s']['SI_unit'],
156
- 'm': (
157
- convert_to_SI(
158
- 'm',
159
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\MASSFLMX\MIXED').Value,
160
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\MASSFLMX\MIXED').UnitString
161
- ) if self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\MASSFLMX\MIXED') is not None else None
162
- ),
163
- 'm_unit': fluid_property_data['m']['SI_unit'],
164
- 'energy_flow': (
165
- convert_to_SI(
166
- 'power',
167
- abs(self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\HMX_FLOW\MIXED').Value),
168
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\HMX_FLOW\MIXED').UnitString
169
- ) if self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\HMX_FLOW\MIXED') is not None else None
170
- ),
171
- 'energy_flow_unit': fluid_property_data['power']['SI_unit'],
172
- 'e_PH': (
173
- convert_to_SI(
174
- 'e',
175
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\STRM_UPP\EXERGYMS\MIXED\TOTAL').Value,
176
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\STRM_UPP\EXERGYMS\MIXED\TOTAL').UnitString
177
- ) if self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\STRM_UPP\EXERGYMS\MIXED\TOTAL') is not None else (
178
- logging.warning(f"e_PH node not found for stream {stream_name}"),
179
- None
180
- )[1]
181
- ),
182
- 'e_PH_unit': fluid_property_data['e']['SI_unit'],
183
- 'n': (
184
- convert_to_SI(
185
- 'n',
186
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\TOT_FLOW').Value,
187
- self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\TOT_FLOW').UnitString
188
- ) if self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\TOT_FLOW') is not None else None
189
- ),
190
- 'n_unit': fluid_property_data['n']['SI_unit'],
191
- 'mass_composition': {},
192
- 'molar_composition': {},
193
- })
128
+ connection_data.update(
129
+ {
130
+ "kind": "material",
131
+ "T": (
132
+ convert_to_SI(
133
+ "T",
134
+ self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\TEMP_OUT\MIXED").Value,
135
+ self.aspen.Tree.FindNode(
136
+ rf"\Data\Streams\{stream_name}\Output\TEMP_OUT\MIXED"
137
+ ).UnitString,
138
+ )
139
+ if self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\TEMP_OUT\MIXED")
140
+ is not None
141
+ else None
142
+ ),
143
+ "T_unit": fluid_property_data["T"]["SI_unit"],
144
+ "p": (
145
+ convert_to_SI(
146
+ "p",
147
+ self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\PRES_OUT\MIXED").Value,
148
+ self.aspen.Tree.FindNode(
149
+ rf"\Data\Streams\{stream_name}\Output\PRES_OUT\MIXED"
150
+ ).UnitString,
151
+ )
152
+ if self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\PRES_OUT\MIXED")
153
+ is not None
154
+ else None
155
+ ),
156
+ "p_unit": fluid_property_data["p"]["SI_unit"],
157
+ "h": (
158
+ convert_to_SI(
159
+ "h",
160
+ self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\HMX_MASS\MIXED").Value,
161
+ self.aspen.Tree.FindNode(
162
+ rf"\Data\Streams\{stream_name}\Output\HMX_MASS\MIXED"
163
+ ).UnitString,
164
+ )
165
+ if self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\HMX_MASS\MIXED")
166
+ is not None
167
+ else None
168
+ ),
169
+ "h_unit": fluid_property_data["h"]["SI_unit"],
170
+ "s": (
171
+ convert_to_SI(
172
+ "s",
173
+ self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\SMX_MASS\MIXED").Value,
174
+ self.aspen.Tree.FindNode(
175
+ rf"\Data\Streams\{stream_name}\Output\SMX_MASS\MIXED"
176
+ ).UnitString,
177
+ )
178
+ if self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\SMX_MASS\MIXED")
179
+ is not None
180
+ else None
181
+ ),
182
+ "s_unit": fluid_property_data["s"]["SI_unit"],
183
+ "m": (
184
+ convert_to_SI(
185
+ "m",
186
+ self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\MASSFLMX\MIXED").Value,
187
+ self.aspen.Tree.FindNode(
188
+ rf"\Data\Streams\{stream_name}\Output\MASSFLMX\MIXED"
189
+ ).UnitString,
190
+ )
191
+ if self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\MASSFLMX\MIXED")
192
+ is not None
193
+ else None
194
+ ),
195
+ "m_unit": fluid_property_data["m"]["SI_unit"],
196
+ "energy_flow": (
197
+ convert_to_SI(
198
+ "power",
199
+ abs(
200
+ self.aspen.Tree.FindNode(
201
+ rf"\Data\Streams\{stream_name}\Output\HMX_FLOW\MIXED"
202
+ ).Value
203
+ ),
204
+ self.aspen.Tree.FindNode(
205
+ rf"\Data\Streams\{stream_name}\Output\HMX_FLOW\MIXED"
206
+ ).UnitString,
207
+ )
208
+ if self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\HMX_FLOW\MIXED")
209
+ is not None
210
+ else None
211
+ ),
212
+ "energy_flow_unit": fluid_property_data["power"]["SI_unit"],
213
+ "e_PH": (
214
+ convert_to_SI(
215
+ "e",
216
+ self.aspen.Tree.FindNode(
217
+ rf"\Data\Streams\{stream_name}\Output\STRM_UPP\EXERGYMS\MIXED\TOTAL"
218
+ ).Value,
219
+ self.aspen.Tree.FindNode(
220
+ rf"\Data\Streams\{stream_name}\Output\STRM_UPP\EXERGYMS\MIXED\TOTAL"
221
+ ).UnitString,
222
+ )
223
+ if self.aspen.Tree.FindNode(
224
+ rf"\Data\Streams\{stream_name}\Output\STRM_UPP\EXERGYMS\MIXED\TOTAL"
225
+ )
226
+ is not None
227
+ else (logging.warning(f"e_PH node not found for stream {stream_name}"), None)[1]
228
+ ),
229
+ "e_PH_unit": fluid_property_data["e"]["SI_unit"],
230
+ "n": (
231
+ convert_to_SI(
232
+ "n",
233
+ self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\TOT_FLOW").Value,
234
+ self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\TOT_FLOW").UnitString,
235
+ )
236
+ if self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\TOT_FLOW") is not None
237
+ else None
238
+ ),
239
+ "n_unit": fluid_property_data["n"]["SI_unit"],
240
+ "mass_composition": {},
241
+ "molar_composition": {},
242
+ }
243
+ )
194
244
  # Retrieve the fluid names for the stream
195
- mole_frac_node = self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\MOLEFRAC\MIXED')
245
+ mole_frac_node = self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\MOLEFRAC\MIXED")
196
246
  if mole_frac_node is not None:
197
247
  fluid_names = [fluid.Name for fluid in mole_frac_node.Elements]
198
248
 
199
249
  # Retrieve the molar composition for each fluid
200
250
  for fluid_name in fluid_names:
201
- mole_frac = self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\MOLEFRAC\MIXED\{fluid_name}').Value
251
+ mole_frac = self.aspen.Tree.FindNode(
252
+ rf"\Data\Streams\{stream_name}\Output\MOLEFRAC\MIXED\{fluid_name}"
253
+ ).Value
202
254
  if mole_frac not in [0, None]: # Skip fluids with 0 or None as the fraction
203
255
  connection_data["molar_composition"][fluid_name] = mole_frac
204
256
 
205
- mass_frac_node = self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\MASSFRAC\MIXED')
257
+ mass_frac_node = self.aspen.Tree.FindNode(rf"\Data\Streams\{stream_name}\Output\MASSFRAC\MIXED")
206
258
  if mass_frac_node is not None:
207
259
  # Retrieve the mass composition for each fluid
208
260
  for fluid_name in [fluid.Name for fluid in mass_frac_node.Elements]:
209
- mass_frac = self.aspen.Tree.FindNode(fr'\Data\Streams\{stream_name}\Output\MASSFRAC\MIXED\{fluid_name}').Value
261
+ mass_frac = self.aspen.Tree.FindNode(
262
+ rf"\Data\Streams\{stream_name}\Output\MASSFRAC\MIXED\{fluid_name}"
263
+ ).Value
210
264
  if mass_frac not in [0, None]: # Skip fluids with 0 or None as the fraction
211
265
  connection_data["mass_composition"][fluid_name] = mass_frac
212
266
 
213
267
  # Store connection data
214
268
  self.connections_data[stream_name] = connection_data
215
269
 
216
-
217
270
  def parse_blocks(self):
218
271
  """
219
272
  Parses the blocks (components) in the Aspen model and ensures that all components, including motors created from pumps, are properly grouped.
220
273
  """
221
- block_nodes = self.aspen.Tree.FindNode(r'\Data\Blocks').Elements
274
+ block_nodes = self.aspen.Tree.FindNode(r"\Data\Blocks").Elements
222
275
  block_names = [block_node.Name for block_node in block_nodes]
223
276
 
224
277
  # Process each block
225
278
  for block_name in block_names:
226
- model_type_node = self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Input\MODEL_TYPE')
279
+ model_type_node = self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Input\MODEL_TYPE")
227
280
  model_type = model_type_node.Value if model_type_node is not None else None
228
281
 
229
- component_type_node = self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}')
282
+ component_type_node = self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}")
230
283
  if component_type_node is None:
231
284
  continue
232
285
  component_type = component_type_node.AttributeValue(6)
@@ -237,122 +290,141 @@ class AspenModelParser:
237
290
  continue
238
291
 
239
292
  component_data = {
240
- 'name': block_name,
241
- 'type': component_type,
242
- 'eta_s': (
243
- self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Output\EFF_ISEN').Value
244
- if self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Output\EFF_ISEN') is not None else None
293
+ "name": block_name,
294
+ "type": component_type,
295
+ "eta_s": (
296
+ self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Output\EFF_ISEN").Value
297
+ if self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Output\EFF_ISEN") is not None
298
+ else None
245
299
  ),
246
- 'eta_mech': (
247
- self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Output\EFF_MECH').Value
248
- if self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Output\EFF_MECH') is not None else None
300
+ "eta_mech": (
301
+ self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Output\EFF_MECH").Value
302
+ if self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Output\EFF_MECH") is not None
303
+ else None
249
304
  ),
250
- 'Q': (
305
+ "Q": (
251
306
  convert_to_SI(
252
- 'heat',
253
- self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Output\QNET').Value,
254
- self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Output\QNET').UnitString,
255
- ) if self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Output\QNET') is not None else None
307
+ "heat",
308
+ self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Output\QNET").Value,
309
+ self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Output\QNET").UnitString,
310
+ )
311
+ if self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Output\QNET") is not None
312
+ else None
256
313
  ),
257
- 'Q_unit': fluid_property_data['heat']['SI_unit'],
258
- 'P': (
314
+ "Q_unit": fluid_property_data["heat"]["SI_unit"],
315
+ "P": (
259
316
  convert_to_SI(
260
- 'power',
261
- abs(self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Output\BRAKE_POWER').Value),
262
- self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Output\BRAKE_POWER').UnitString,
263
- ) if self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Output\BRAKE_POWER') is not None else None
317
+ "power",
318
+ abs(self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Output\BRAKE_POWER").Value),
319
+ self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Output\BRAKE_POWER").UnitString,
320
+ )
321
+ if self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Output\BRAKE_POWER") is not None
322
+ else None
264
323
  ),
265
- 'P_unit': fluid_property_data['power']['SI_unit'],
324
+ "P_unit": fluid_property_data["power"]["SI_unit"],
266
325
  }
267
326
 
268
327
  # Override component type based on model_type
269
328
  if model_type is not None:
270
329
  if model_type == "COMPRESSOR":
271
- component_data['type'] = "Compressor"
330
+ component_data["type"] = "Compressor"
272
331
  elif model_type == "TURBINE":
273
- component_data['type'] = "Turbine"
274
-
332
+ component_data["type"] = "Turbine"
275
333
 
276
334
  # Handle Generators & Motors (if not in a Pump) as multiplier blocks
277
- if component_type == 'Mult':
278
- mult_value_node = self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}')
335
+ if component_type == "Mult":
336
+ mult_value_node = self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}")
279
337
  mult_value = mult_value_node.Value if mult_value_node is not None else None
280
- if mult_value == 'WORK':
281
- factor_node = self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Input\FACTOR')
338
+ if mult_value == "WORK":
339
+ factor_node = self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Input\FACTOR")
282
340
  factor = factor_node.Value if factor_node is not None else None
283
341
  if factor is not None:
284
342
  if factor < 1:
285
- component_data.update({
286
- 'eta_el': factor,
287
- 'type': 'Generator'
288
- })
343
+ component_data.update({"eta_el": factor, "type": "Generator"})
289
344
  elif factor > 1:
290
- elec_power_node = self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Ports\WS(OUT)').Elements(0)
345
+ elec_power_node = self.aspen.Tree.FindNode(
346
+ rf"\Data\Blocks\{block_name}\Ports\WS(OUT)"
347
+ ).Elements(0)
291
348
  elec_power_name = elec_power_node.Name
292
349
  if elec_power_name in self.connections_data:
293
- elec_power = abs(self.connections_data[elec_power_name]['energy_flow'])
350
+ elec_power = abs(self.connections_data[elec_power_name]["energy_flow"])
294
351
  else:
295
352
  logging.warning(f"No WS(IN) ports found for block {block_name}")
296
353
  elec_power = None
297
- brake_power_node = self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Ports\WS(IN)').Elements(0)
354
+ brake_power_node = self.aspen.Tree.FindNode(
355
+ rf"\Data\Blocks\{block_name}\Ports\WS(IN)"
356
+ ).Elements(0)
298
357
  brake_power_name = brake_power_node.Name
299
358
  if brake_power_name in self.connections_data:
300
- brake_power = abs(self.connections_data[brake_power_name]['energy_flow'])
359
+ brake_power = abs(self.connections_data[brake_power_name]["energy_flow"])
301
360
  else:
302
361
  logging.warning(f"No WS(IN) ports found for block {block_name}")
303
362
  brake_power = None
304
- component_data.update({
305
- 'eta_el': 1/factor,
306
- 'multiplier factor' : factor,
307
- 'type': 'Motor',
308
- 'P_el': elec_power,
309
- 'P_el_unit': fluid_property_data['power']['SI_unit'],
310
- 'P_mech': brake_power,
311
- 'P_mech_unit': fluid_property_data['power']['SI_unit'],
312
- })
363
+ component_data.update(
364
+ {
365
+ "eta_el": 1 / factor,
366
+ "multiplier factor": factor,
367
+ "type": "Motor",
368
+ "P_el": elec_power,
369
+ "P_el_unit": fluid_property_data["power"]["SI_unit"],
370
+ "P_mech": brake_power,
371
+ "P_mech_unit": fluid_property_data["power"]["SI_unit"],
372
+ }
373
+ )
313
374
  else: # factor == 1
314
- choice = input(f"Multiplier Block '{block_name}' has factor = 1. Enter 'G' if it is a Generator or 'M' for Motor: ").strip().upper()
315
- if choice == 'M':
316
- elec_power_node = self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Ports\WS(OUT)').Elements(0)
375
+ choice = (
376
+ input(
377
+ f"Multiplier Block '{block_name}' has factor = 1. Enter 'G' if it is a Generator or 'M' for Motor: "
378
+ )
379
+ .strip()
380
+ .upper()
381
+ )
382
+ if choice == "M":
383
+ elec_power_node = self.aspen.Tree.FindNode(
384
+ rf"\Data\Blocks\{block_name}\Ports\WS(OUT)"
385
+ ).Elements(0)
317
386
  elec_power_name = elec_power_node.Name
318
387
  if elec_power_name in self.connections_data:
319
- elec_power = abs(self.connections_data[elec_power_name]['energy_flow'])
388
+ elec_power = abs(self.connections_data[elec_power_name]["energy_flow"])
320
389
  else:
321
390
  logging.warning(f"No WS(IN) ports found for block {block_name}")
322
391
  elec_power = None
323
- brake_power_node = self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Ports\WS(IN)').Elements(0)
392
+ brake_power_node = self.aspen.Tree.FindNode(
393
+ rf"\Data\Blocks\{block_name}\Ports\WS(IN)"
394
+ ).Elements(0)
324
395
  brake_power_name = brake_power_node.Name
325
396
  if brake_power_name in self.connections_data:
326
- brake_power = abs(self.connections_data[brake_power_name]['energy_flow'])
397
+ brake_power = abs(self.connections_data[brake_power_name]["energy_flow"])
327
398
  else:
328
399
  logging.warning(f"No WS(IN) ports found for block {block_name}")
329
400
  brake_power = None
330
- component_data.update({
331
- 'eta_el': factor,
332
- 'type': 'Motor',
333
- 'P_el': elec_power,
334
- 'P_el_unit': fluid_property_data['power']['SI_unit'],
335
- 'P_mech': brake_power,
336
- 'P_mech_unit': fluid_property_data['power']['SI_unit'],
337
- })
401
+ component_data.update(
402
+ {
403
+ "eta_el": factor,
404
+ "type": "Motor",
405
+ "P_el": elec_power,
406
+ "P_el_unit": fluid_property_data["power"]["SI_unit"],
407
+ "P_mech": brake_power,
408
+ "P_mech_unit": fluid_property_data["power"]["SI_unit"],
409
+ }
410
+ )
338
411
  else:
339
- component_data.update({
340
- 'eta_el': factor,
341
- 'type': 'Generator'
342
- })
412
+ component_data.update({"eta_el": factor, "type": "Generator"})
343
413
 
344
414
  # Create a connection for the heat flows of the SimpleHeatExchanger blocks
345
- if component_type == 'Heater':
415
+ if component_type == "Heater":
346
416
  heat_connection_name = f"{block_name}_HEAT"
347
417
  heat_connection_data = {
348
- 'name': heat_connection_name,
349
- 'kind': 'heat',
350
- 'source_component': block_name,
351
- 'source_connector': 1, # 00 is reserved for the fluid streams
352
- 'target_component': None, # Heat assumed to leave the system (not relevant for exergy analysis)
353
- 'target_connector': None, # Heat assumed to leave the system (not relevant for exergy analysis)
354
- 'energy_flow': abs(component_data['Q']), # the user defines in the balances if the heat flow is positive or negative
355
- 'energy_flow_unit': fluid_property_data['heat']['SI_unit'],
418
+ "name": heat_connection_name,
419
+ "kind": "heat",
420
+ "source_component": block_name,
421
+ "source_connector": 1, # 00 is reserved for the fluid streams
422
+ "target_component": None, # Heat assumed to leave the system (not relevant for exergy analysis)
423
+ "target_connector": None, # Heat assumed to leave the system (not relevant for exergy analysis)
424
+ "energy_flow": abs(
425
+ component_data["Q"]
426
+ ), # the user defines in the balances if the heat flow is positive or negative
427
+ "energy_flow_unit": fluid_property_data["heat"]["SI_unit"],
356
428
  }
357
429
 
358
430
  # Store the heat connection
@@ -362,26 +434,43 @@ class AspenModelParser:
362
434
  self.group_component(component_data, block_name)
363
435
 
364
436
  # Handle Pumps and their associated Motors
365
- if component_type == 'Pump':
437
+ if component_type == "Pump":
366
438
  motor_name = f"{block_name}-MOTOR"
367
- elec_power_node = self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Output\ELEC_POWER')
368
- elec_power = abs(convert_to_SI('power', elec_power_node.Value, elec_power_node.UnitString,)) if elec_power_node is not None else None
369
- brake_power_node = self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Output\BRAKE_POWER')
370
- brake_power = abs(convert_to_SI('power', brake_power_node.Value, brake_power_node.UnitString,)) if brake_power_node is not None else None
371
- eff_driv_node = self.aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Output\EFF_DRIV')
439
+ elec_power_node = self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Output\ELEC_POWER")
440
+ elec_power = (
441
+ abs(
442
+ convert_to_SI(
443
+ "power",
444
+ elec_power_node.Value,
445
+ elec_power_node.UnitString,
446
+ )
447
+ )
448
+ if elec_power_node is not None
449
+ else None
450
+ )
451
+ brake_power_node = self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Output\BRAKE_POWER")
452
+ brake_power = (
453
+ abs(
454
+ convert_to_SI(
455
+ "power",
456
+ brake_power_node.Value,
457
+ brake_power_node.UnitString,
458
+ )
459
+ )
460
+ if brake_power_node is not None
461
+ else None
462
+ )
463
+ eff_driv_node = self.aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Output\EFF_DRIV")
372
464
  eff_driv = eff_driv_node.Value if eff_driv_node is not None else None
373
465
 
374
466
  motor_data = {
375
- 'name': motor_name,
376
- 'type': 'Motor',
377
- 'P_el': elec_power,
378
- 'P_el_unit': fluid_property_data['power']['SI_unit'],
379
- 'P_mech': brake_power,
380
- 'P_mech_unit': fluid_property_data['power']['SI_unit'],
381
- 'eta_el': (
382
- eff_driv
383
- if eff_driv is not None else None
384
- ),
467
+ "name": motor_name,
468
+ "type": "Motor",
469
+ "P_el": elec_power,
470
+ "P_el_unit": fluid_property_data["power"]["SI_unit"],
471
+ "P_mech": brake_power,
472
+ "P_mech_unit": fluid_property_data["power"]["SI_unit"],
473
+ "eta_el": (eff_driv if eff_driv is not None else None),
385
474
  }
386
475
 
387
476
  # Group the motor
@@ -391,26 +480,26 @@ class AspenModelParser:
391
480
  if elec_power is not None:
392
481
  electr_connection_name = f"{block_name}_ELEC"
393
482
  electr_connection_data = {
394
- 'name': electr_connection_name,
395
- 'kind': 'power',
396
- 'source_component': None, # Electrical power usually leaves the system
397
- 'source_connector': None, # Electrical power usually leaves the system
398
- 'target_component': motor_name,
399
- 'target_connector': 0,
400
- 'energy_flow': motor_data['P_el'],
401
- 'energy_flow_unit': fluid_property_data['power']['SI_unit'],
483
+ "name": electr_connection_name,
484
+ "kind": "power",
485
+ "source_component": None, # Electrical power usually leaves the system
486
+ "source_connector": None, # Electrical power usually leaves the system
487
+ "target_component": motor_name,
488
+ "target_connector": 0,
489
+ "energy_flow": motor_data["P_el"],
490
+ "energy_flow_unit": fluid_property_data["power"]["SI_unit"],
402
491
  }
403
492
 
404
493
  mech_connection_name = f"{block_name}_MECH"
405
494
  mech_connection_data = {
406
- 'name': mech_connection_name,
407
- 'kind': 'power',
408
- 'source_component': motor_name,
409
- 'source_connector': 0,
410
- 'target_component': block_name,
411
- 'target_connector': 1,
412
- 'energy_flow': motor_data['P_mech'],
413
- 'energy_flow_unit': fluid_property_data['power']['SI_unit'],
495
+ "name": mech_connection_name,
496
+ "kind": "power",
497
+ "source_component": motor_name,
498
+ "source_connector": 0,
499
+ "target_component": block_name,
500
+ "target_connector": 1,
501
+ "energy_flow": motor_data["P_mech"],
502
+ "energy_flow_unit": fluid_property_data["power"]["SI_unit"],
414
503
  }
415
504
 
416
505
  # Store the motor connection
@@ -420,12 +509,11 @@ class AspenModelParser:
420
509
  # Assign connectors
421
510
  self.assign_connectors(component_data, block_name)
422
511
 
423
-
424
512
  def assign_connectors(self, component_data, block_name):
425
513
  """
426
514
  Assigns connectors to streams for each component based on its type.
427
515
  """
428
- component_type = component_data['type']
516
+ component_type = component_data["type"]
429
517
 
430
518
  # Check if there is a specific assignment function for this component type
431
519
  if component_type in self.connector_assignment_functions:
@@ -433,14 +521,15 @@ class AspenModelParser:
433
521
  self.connector_assignment_functions[component_type](block_name, self.aspen, self.connections_data)
434
522
  else:
435
523
  # Fall back to the generic connector assignment logic
436
- self.assign_generic_connectors(block_name, component_type, self.aspen, self.connections_data, connector_mappings)
437
-
524
+ self.assign_generic_connectors(
525
+ block_name, component_type, self.aspen, self.connections_data, connector_mappings
526
+ )
438
527
 
439
528
  def assign_mixer_connectors(self, block_name, aspen, connections_data):
440
529
  """
441
530
  Assign connectors for a Mixer by examining connected streams and their source/target components.
442
531
  """
443
- ports_node = aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Ports')
532
+ ports_node = aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Ports")
444
533
  if ports_node is None:
445
534
  logging.warning(f"No Ports node found for Mixer block: {block_name}")
446
535
  return
@@ -450,38 +539,39 @@ class AspenModelParser:
450
539
 
451
540
  for port in ports_node.Elements:
452
541
  port_label = port.Name
453
- port_node = aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Ports\{port_label}')
542
+ port_node = aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Ports\{port_label}")
454
543
  if port_node is not None and port_node.Elements.Count > 0:
455
544
  for element in port_node.Elements:
456
545
  stream_name = element.Name
457
546
  if stream_name in connections_data:
458
547
  stream_data = connections_data[stream_name]
459
- if stream_data.get('target_component') == block_name:
548
+ if stream_data.get("target_component") == block_name:
460
549
  inlet_streams.append((port_label, stream_name))
461
- elif stream_data.get('source_component') == block_name:
550
+ elif stream_data.get("source_component") == block_name:
462
551
  outlet_streams.append((port_label, stream_name))
463
552
  else:
464
- logging.warning(f"Stream {stream_name} connected to {block_name} but source/target components do not match.")
553
+ logging.warning(
554
+ f"Stream {stream_name} connected to {block_name} but source/target components do not match."
555
+ )
465
556
 
466
557
  # Assign connectors to inlet streams
467
558
  for idx, (port_label, stream_name) in enumerate(inlet_streams):
468
- connections_data[stream_name]['target_connector'] = idx
559
+ connections_data[stream_name]["target_connector"] = idx
469
560
  logging.debug(f"Assigned connector {idx} to inlet stream: {stream_name}")
470
561
 
471
562
  # Assign connector to outlet stream
472
563
  if outlet_streams:
473
564
  for idx, (port_label, stream_name) in enumerate(outlet_streams):
474
- connections_data[stream_name]['source_connector'] = 0 # Assuming single outlet for mixer
565
+ connections_data[stream_name]["source_connector"] = 0 # Assuming single outlet for mixer
475
566
  logging.debug(f"Assigned connector 0 to outlet stream: {stream_name}")
476
567
 
477
-
478
568
  def assign_splitter_connectors(self, block_name, aspen, connections_data):
479
569
  """
480
570
  Assign connectors for a Splitter (FSplit) by examining connected streams and their source/target components.
481
571
  The inlet stream is assigned 'target_connector' = 0.
482
572
  The outlet streams are assigned 'source_connector' numbers starting from 0.
483
573
  """
484
- ports_node = aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Ports')
574
+ ports_node = aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Ports")
485
575
  if ports_node is None:
486
576
  logging.warning(f"No Ports node found for Splitter block: {block_name}")
487
577
  return
@@ -492,36 +582,37 @@ class AspenModelParser:
492
582
  # Iterate over all ports connected to the splitter
493
583
  for port in ports_node.Elements:
494
584
  port_label = port.Name
495
- port_node = aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Ports\{port_label}')
585
+ port_node = aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Ports\{port_label}")
496
586
  if port_node is not None and port_node.Elements.Count > 0:
497
587
  for element in port_node.Elements:
498
588
  stream_name = element.Name
499
589
  if stream_name in connections_data:
500
590
  stream_data = connections_data[stream_name]
501
591
  # Determine if the stream is an inlet or outlet based on source and target components
502
- if stream_data.get('target_component') == block_name:
592
+ if stream_data.get("target_component") == block_name:
503
593
  inlet_streams.append((port_label, stream_name))
504
- elif stream_data.get('source_component') == block_name:
594
+ elif stream_data.get("source_component") == block_name:
505
595
  outlet_streams.append((port_label, stream_name))
506
596
  else:
507
- logging.warning(f"Stream {stream_name} connected to {block_name} but source/target components do not match.")
597
+ logging.warning(
598
+ f"Stream {stream_name} connected to {block_name} but source/target components do not match."
599
+ )
508
600
 
509
601
  # Assign connector to inlet stream(s)
510
602
  for idx, (port_label, stream_name) in enumerate(inlet_streams):
511
- connections_data[stream_name]['target_connector'] = 0 # Assuming single inlet for splitter
603
+ connections_data[stream_name]["target_connector"] = 0 # Assuming single inlet for splitter
512
604
  logging.debug(f"Assigned connector 0 to inlet stream: {stream_name}")
513
605
 
514
606
  # Assign connectors to outlet streams
515
607
  for idx, (port_label, stream_name) in enumerate(outlet_streams):
516
- connections_data[stream_name]['source_connector'] = idx
608
+ connections_data[stream_name]["source_connector"] = idx
517
609
  logging.debug(f"Assigned connector {idx} to outlet stream: {stream_name}")
518
610
 
519
-
520
611
  def assign_combustion_chamber_connectors(self, block_name, aspen, connections_data):
521
612
  """
522
613
  Assign connectors for a combustion chamber (RStoic), based on stream types (air, fuel, etc.).
523
614
  """
524
- ports_node = aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Ports')
615
+ ports_node = aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Ports")
525
616
  if ports_node is None:
526
617
  logging.warning(f"No Ports node found for combustion chamber block: {block_name}")
527
618
  return
@@ -531,33 +622,32 @@ class AspenModelParser:
531
622
  port_label = port.Name
532
623
 
533
624
  # Handle inlet ports
534
- if '(IN)' in port_label:
535
- port_node = aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Ports\{port_label}')
625
+ if "(IN)" in port_label:
626
+ port_node = aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Ports\{port_label}")
536
627
  if port_node is not None and port_node.Elements.Count > 0:
537
628
  for element in port_node.Elements:
538
629
  stream_name = element.Name
539
630
  if stream_name in connections_data:
540
- molar_composition = connections_data[stream_name].get('molar_composition', {})
541
- if molar_composition.get('O2', 0) > 0.15:
542
- connections_data[stream_name]['target_connector'] = 0 # Air inlet
631
+ molar_composition = connections_data[stream_name].get("molar_composition", {})
632
+ if molar_composition.get("O2", 0) > 0.15:
633
+ connections_data[stream_name]["target_connector"] = 0 # Air inlet
543
634
  logging.debug(f"Assigned connector 0 to air inlet stream: {stream_name}")
544
- elif molar_composition.get('CH4', 0) > 0.15:
545
- connections_data[stream_name]['target_connector'] = 1 # Fuel inlet
635
+ elif molar_composition.get("CH4", 0) > 0.15:
636
+ connections_data[stream_name]["target_connector"] = 1 # Fuel inlet
546
637
  logging.debug(f"Assigned connector 1 to fuel inlet stream: {stream_name}")
547
638
  else:
548
639
  logging.warning(f"Stream {stream_name} in {block_name} has ambiguous composition.")
549
640
 
550
641
  # Handle outlet ports
551
- elif '(OUT)' in port_label:
552
- port_node = aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Ports\{port_label}')
642
+ elif "(OUT)" in port_label:
643
+ port_node = aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Ports\{port_label}")
553
644
  if port_node is not None and port_node.Elements.Count > 0:
554
645
  for element in port_node.Elements:
555
646
  stream_name = element.Name
556
647
  if stream_name in connections_data:
557
- connections_data[stream_name]['source_connector'] = 0 # Outlet stream
648
+ connections_data[stream_name]["source_connector"] = 0 # Outlet stream
558
649
  logging.info(f"Assigned connector 0 to outlet stream: {stream_name}")
559
650
 
560
-
561
651
  def assign_generic_connectors(self, block_name, component_type, aspen, connections_data, connector_mappings):
562
652
  """
563
653
  Generic function for components with predefined connector mappings.
@@ -567,24 +657,27 @@ class AspenModelParser:
567
657
 
568
658
  # Access the ports of the component to find the connected streams
569
659
  for port_label, connector_num in mapping.items():
570
- port_node = aspen.Tree.FindNode(fr'\Data\Blocks\{block_name}\Ports\{port_label}')
660
+ port_node = aspen.Tree.FindNode(rf"\Data\Blocks\{block_name}\Ports\{port_label}")
571
661
  if port_node is not None and port_node.Elements.Count > 0:
572
662
  for element in port_node.Elements:
573
663
  stream_name = element.Name
574
664
  # Assign the connector number to the appropriate stream in the connection data
575
665
  if stream_name in connections_data:
576
- if 'source_component' in connections_data[stream_name] and \
577
- connections_data[stream_name]['source_component'] == block_name:
578
- connections_data[stream_name]['source_connector'] = connector_num
666
+ if (
667
+ "source_component" in connections_data[stream_name]
668
+ and connections_data[stream_name]["source_component"] == block_name
669
+ ):
670
+ connections_data[stream_name]["source_connector"] = connector_num
579
671
  logging.debug(f"Assigned connector {connector_num} to source stream: {stream_name}")
580
- elif 'target_component' in connections_data[stream_name] and \
581
- connections_data[stream_name]['target_component'] == block_name:
582
- connections_data[stream_name]['target_connector'] = connector_num
672
+ elif (
673
+ "target_component" in connections_data[stream_name]
674
+ and connections_data[stream_name]["target_component"] == block_name
675
+ ):
676
+ connections_data[stream_name]["target_connector"] = connector_num
583
677
  logging.debug(f"Assigned connector {connector_num} to target stream: {stream_name}")
584
678
  else:
585
679
  logging.warning(f"No connector mapping defined for component type {component_type}.")
586
680
 
587
-
588
681
  def group_component(self, component_data, component_name):
589
682
  """
590
683
  Group the component based on its type into the correct group within components_data.
@@ -596,13 +689,13 @@ class AspenModelParser:
596
689
  # Determine the group for the component based on its type
597
690
  group = None
598
691
  for group_name, type_list in grouped_components.items():
599
- if component_data['type'] in type_list:
692
+ if component_data["type"] in type_list:
600
693
  group = group_name
601
694
  break
602
695
 
603
696
  # If the component doesn't belong to any predefined group, use its type name
604
697
  if not group:
605
- group = component_data['type']
698
+ group = component_data["type"]
606
699
 
607
700
  # Initialize the group in the components_data dictionary if not already present
608
701
  if group not in self.components_data:
@@ -611,7 +704,6 @@ class AspenModelParser:
611
704
  # Store the component data in the appropriate group
612
705
  self.components_data[group][component_name] = component_data
613
706
 
614
-
615
707
  def parse_ambient_conditions(self):
616
708
  """
617
709
  Parses the ambient conditions from the Aspen model and stores them as class attributes.
@@ -620,25 +712,21 @@ class AspenModelParser:
620
712
  try:
621
713
  # Parse ambient temperature (Tamb)
622
714
  temp_node = self.aspen.Tree.FindNode(r"\Data\Setup\Sim-Options\Input\REF_TEMP")
623
- self.Tamb = convert_to_SI(
624
- 'T',
625
- temp_node.Value,
626
- temp_node.UnitString
627
- ) if temp_node is not None else None
715
+ self.Tamb = convert_to_SI("T", temp_node.Value, temp_node.UnitString) if temp_node is not None else None
628
716
 
629
717
  if self.Tamb is None:
630
- raise ValueError("Ambient temperature (Tamb) not found in the Aspen model. Please set it in Setup > Calculation Options.")
718
+ raise ValueError(
719
+ "Ambient temperature (Tamb) not found in the Aspen model. Please set it in Setup > Calculation Options."
720
+ )
631
721
 
632
722
  # Parse ambient pressure (pamb)
633
723
  pres_node = self.aspen.Tree.FindNode(r"\Data\Setup\Sim-Options\Input\REF_PRES")
634
- self.pamb = convert_to_SI(
635
- 'p',
636
- pres_node.Value,
637
- pres_node.UnitString
638
- ) if pres_node is not None else None
724
+ self.pamb = convert_to_SI("p", pres_node.Value, pres_node.UnitString) if pres_node is not None else None
639
725
 
640
726
  if self.pamb is None:
641
- raise ValueError("Ambient pressure (pamb) not found in the Aspen model. Please set it in Setup > Calculation Options.")
727
+ raise ValueError(
728
+ "Ambient pressure (pamb) not found in the Aspen model. Please set it in Setup > Calculation Options."
729
+ )
642
730
 
643
731
  logging.info(f"Parsed ambient conditions: Tamb = {self.Tamb} K, pamb = {self.pamb} Pa")
644
732
 
@@ -654,15 +742,20 @@ class AspenModelParser:
654
742
  dict: A dictionary containing sorted 'components', 'connections', and ambient conditions data.
655
743
  """
656
744
  sorted_components = {comp_name: self.components_data[comp_name] for comp_name in sorted(self.components_data)}
657
- sorted_connections = {conn_name: self.connections_data[conn_name] for conn_name in sorted(self.connections_data)}
745
+ sorted_connections = {
746
+ conn_name: self.connections_data[conn_name] for conn_name in sorted(self.connections_data)
747
+ }
658
748
  ambient_conditions = {
659
- 'Tamb': self.Tamb,
660
- 'Tamb_unit': fluid_property_data['T']['SI_unit'],
661
- 'pamb': self.pamb,
662
- 'pamb_unit': fluid_property_data['p']['SI_unit']
749
+ "Tamb": self.Tamb,
750
+ "Tamb_unit": fluid_property_data["T"]["SI_unit"],
751
+ "pamb": self.pamb,
752
+ "pamb_unit": fluid_property_data["p"]["SI_unit"],
753
+ }
754
+ return {
755
+ "components": sorted_components,
756
+ "connections": sorted_connections,
757
+ "ambient_conditions": ambient_conditions,
663
758
  }
664
- return {'components': sorted_components, 'connections': sorted_connections, 'ambient_conditions': ambient_conditions}
665
-
666
759
 
667
760
  def write_to_json(self, output_path):
668
761
  """
@@ -674,7 +767,7 @@ class AspenModelParser:
674
767
  data = self.get_sorted_data()
675
768
 
676
769
  try:
677
- with open(output_path, 'w') as json_file:
770
+ with open(output_path, "w") as json_file:
678
771
  json.dump(data, json_file, indent=4)
679
772
  logging.info(f"Data successfully written to {output_path}")
680
773
  except Exception as e: