Coverage for backend/pinch_service/OpenPinch/src/classes/target.py: 80%
220 statements
« prev ^ index » next coverage.py v7.10.7, created at 2025-11-06 23:27 +0000
« prev ^ index » next coverage.py v7.10.7, created at 2025-11-06 23:27 +0000
1from __future__ import annotations
2from typing import TYPE_CHECKING
3import pandas as pd
4from ..lib.schema import *
5from ..lib.enums import *
6from ..lib.config import *
7from .value import Value
8from .stream_collection import StreamCollection
9from .problem_table import ProblemTable
11if TYPE_CHECKING:
12 from .zone import Zone
14class Target():
15 """Class representing energy targets."""
17 def __init__(self, name: str = "untitled", identifier: str = TargetType.DI.value, parent_zone: Zone = None, config: Optional[Configuration] = None):
19 # === Metadata ===
20 self._config = config or Configuration()
21 self._parent_zone = parent_zone
22 self._identifier = identifier
23 self._name = name
24 self._active = True
26 self._graphs = {}
28 # === Streams & Utilities ===
29 self._hot_utilities: StreamCollection = StreamCollection()
30 self._cold_utilities: StreamCollection = StreamCollection()
32 # === System Data ===
33 self._problem_table = ProblemTable({col.value: pd.Series(dtype='float64') for col in ProblemTableLabel})
34 self._problem_table_real = ProblemTable({col.value: pd.Series(dtype='float64') for col in ProblemTableLabel})
36 # === Thermal Targeting ===
37 self._hot_pinch = 0.0
38 self._cold_pinch = 0.0
39 self._heat_recovery_target = 0.0
40 self._heat_recovery_limit = 0.0
41 self._hot_utility_target = 0.0
42 self._cold_utility_target = 0.0
43 self._utility_heat_recovery_target = 0.0
44 self._degree_of_int = 100.0
45 self._num_units = 0
47 # === Exergy Targeting ===
48 self._exergy_sinks = 0.0
49 self._exergy_sources = 0.0
50 self._exergy_des_min = 0.0
51 self._exergy_req_min = 0.0
52 self._w_target = 0.0
53 self._w_eff_target = 0.0
54 self._ETE = 0.0
56 # === Cost Targeting ===
57 self._area = 0.0
58 self._capital_cost = 0.0
59 self._total_cost = 0.0
60 self._utility_cost = 0.0
62 # === Properties ===
64 @property
65 def name(self): return self._name
66 @name.setter
67 def name(self, value): self._name = value 67 ↛ exitline 67 didn't return from function 'name' because
69 @property
70 def identifier(self): return self._identifier 70 ↛ exitline 70 didn't return from function 'identifier' because the return on line 70 wasn't executed
71 @identifier.setter
72 def identifier(self, value): self._identifier = value 72 ↛ exitline 72 didn't return from function 'identifier' because
74 @property
75 def config(self): return self._config
76 @config.setter
77 def config(self, value): self._config = value 77 ↛ exitline 77 didn't return from function 'config' because
79 @property
80 def parent_zone(self): return self._parent_zone 80 ↛ exitline 80 didn't return from function 'parent_zone' because the return on line 80 wasn't executed
81 @parent_zone.setter
82 def parent_zone(self, value): self._parent_zone = value 82 ↛ exitline 82 didn't return from function 'parent_zone' because
84 @property
85 def active(self) -> bool:
86 """Whether the stream is active in analysis."""
87 if isinstance(self._active, Value):
88 return self._active.value
89 else:
90 return self._active
91 @active.setter
92 def active(self, value: bool):
93 self._active = Value(value)
95 @property
96 def pt(self): return self._problem_table 96 ↛ exitline 96 didn't return from function 'pt' because the return on line 96 wasn't executed
97 @pt.setter
98 def pt(self, data): self._problem_table = data
100 @property
101 def pt_real(self): return self._problem_table_real 101 ↛ exitline 101 didn't return from function 'pt_real' because the return on line 101 wasn't executed
102 @pt_real.setter
103 def pt_real(self, data): self._problem_table_real = data
105 @property
106 def hot_utilities(self): return self._hot_utilities
107 @hot_utilities.setter
108 def hot_utilities(self, data): self._hot_utilities = data
110 @property
111 def cold_utilities(self): return self._cold_utilities
112 @cold_utilities.setter
113 def cold_utilities(self, data): self._cold_utilities = data
115 @property
116 def graphs(self): return self._graphs
117 @graphs.setter
118 def graphs(self, data): self._graphs = data
120 @property
121 def utility_streams(self):
122 return self._hot_utilities + self._cold_utilities
125 @property
126 def area(self): return self._area 126 ↛ exitline 126 didn't return from function 'area' because the return on line 126 wasn't executed
127 @area.setter
128 def area(self, value): self._area = value 128 ↛ exitline 128 didn't return from function 'area' because
130 @property
131 def capital_cost(self): return self._capital_cost 131 ↛ exitline 131 didn't return from function 'capital_cost' because the return on line 131 wasn't executed
132 @capital_cost.setter
133 def capital_cost(self, value): self._capital_cost = value 133 ↛ exitline 133 didn't return from function 'capital_cost' because
135 @property
136 def cold_pinch(self): return self._cold_pinch
137 @cold_pinch.setter
138 def cold_pinch(self, value): self._cold_pinch = value
140 @property
141 def cold_utility_target(self): return self._cold_utility_target
142 @cold_utility_target.setter
143 def cold_utility_target(self, value): self._cold_utility_target = value
145 @property
146 def degree_of_int(self): return self._degree_of_int
147 @degree_of_int.setter
148 def degree_of_int(self, value): self._degree_of_int = value
150 @property
151 def ETE(self): return self._ETE 151 ↛ exitline 151 didn't return from function 'ETE' because the return on line 151 wasn't executed
152 @ETE.setter
153 def ETE(self, value): self._ETE = value 153 ↛ exitline 153 didn't return from function 'ETE' because
155 @property
156 def exergy_des_min(self): return self._exergy_des_min 156 ↛ exitline 156 didn't return from function 'exergy_des_min' because the return on line 156 wasn't executed
157 @exergy_des_min.setter
158 def exergy_des_min(self, value): self._exergy_des_min = value 158 ↛ exitline 158 didn't return from function 'exergy_des_min' because
160 @property
161 def exergy_req_min(self): return self._exergy_req_min 161 ↛ exitline 161 didn't return from function 'exergy_req_min' because the return on line 161 wasn't executed
162 @exergy_req_min.setter
163 def exergy_req_min(self, value): self._exergy_req_min = value 163 ↛ exitline 163 didn't return from function 'exergy_req_min' because
165 @property
166 def exergy_sinks(self): return self._exergy_sinks 166 ↛ exitline 166 didn't return from function 'exergy_sinks' because the return on line 166 wasn't executed
167 @exergy_sinks.setter
168 def exergy_sinks(self, value): self._exergy_sinks = value 168 ↛ exitline 168 didn't return from function 'exergy_sinks' because
170 @property
171 def exergy_sources(self): return self._exergy_sources 171 ↛ exitline 171 didn't return from function 'exergy_sources' because the return on line 171 wasn't executed
172 @exergy_sources.setter
173 def exergy_sources(self, value): self._exergy_sources = value 173 ↛ exitline 173 didn't return from function 'exergy_sources' because
175 @property
176 def heat_recovery_target(self): return self._heat_recovery_target
177 @heat_recovery_target.setter
178 def heat_recovery_target(self, value): self._heat_recovery_target = value
180 @property
181 def heat_recovery_limit(self): return self._heat_recovery_limit
182 @heat_recovery_limit.setter
183 def heat_recovery_limit(self, value): self._heat_recovery_limit = value
185 @property
186 def utility_heat_recovery_target(self): return self._utility_heat_recovery_target 186 ↛ exitline 186 didn't return from function 'utility_heat_recovery_target' because the return on line 186 wasn't executed
187 @utility_heat_recovery_target.setter
188 def utility_heat_recovery_target(self, value): self._utility_heat_recovery_target = value 188 ↛ exitline 188 didn't return from function 'utility_heat_recovery_target' because
190 @property
191 def hot_pinch(self): return self._hot_pinch
192 @hot_pinch.setter
193 def hot_pinch(self, value): self._hot_pinch = value
195 @property
196 def hot_utility_target(self): return self._hot_utility_target
197 @hot_utility_target.setter
198 def hot_utility_target(self, value): self._hot_utility_target = value
200 @property
201 def num_units(self): return self._num_units 201 ↛ exitline 201 didn't return from function 'num_units' because the return on line 201 wasn't executed
202 @num_units.setter
203 def num_units(self, value): self._num_units = value 203 ↛ exitline 203 didn't return from function 'num_units' because
205 @property
206 def capital_cost(self): return self._capital_cost 206 ↛ exitline 206 didn't return from function 'capital_cost' because the return on line 206 wasn't executed
207 @capital_cost.setter
208 def capital_cost(self, value): self._capital_cost = value 208 ↛ exitline 208 didn't return from function 'capital_cost' because
210 @property
211 def total_cost(self): return self._total_cost 211 ↛ exitline 211 didn't return from function 'total_cost' because the return on line 211 wasn't executed
212 @total_cost.setter
213 def total_cost(self, value): self._total_cost = value 213 ↛ exitline 213 didn't return from function 'total_cost' because
215 @property
216 def utility_cost(self): return self._utility_cost
217 @utility_cost.setter
218 def utility_cost(self, value): self._utility_cost = value 218 ↛ exitline 218 didn't return from function 'utility_cost' because
220 @property
221 def work_target(self): return self._w_target 221 ↛ exitline 221 didn't return from function 'work_target' because the return on line 221 wasn't executed
222 @work_target.setter
223 def work_target(self, value): self._w_target = value 223 ↛ exitline 223 didn't return from function 'work_target' because
225 @property
226 def turbine_efficiency_target(self): return self._w_eff_target 226 ↛ exitline 226 didn't return from function 'turbine_efficiency_target' because the return on line 226 wasn't executed
227 @turbine_efficiency_target.setter
228 def turbine_efficiency_target(self, value): self._w_eff_target = value 228 ↛ exitline 228 didn't return from function 'turbine_efficiency_target' because
230 @property
231 def target_values(self): return self._target_values 231 ↛ exitline 231 didn't return from function 'target_values' because the return on line 231 wasn't executed
232 @target_values.setter
233 def target_values(self, value_dict):
234 self._target_values = value_dict
235 for key, value in value_dict.items():
236 setattr(self, key, value)
239 # === Methods ===
240 def add_graph(self, name: str, result):
241 self._graphs[name] = result
244 def calc_utility_cost(self):
245 self._utility_cost = sum([u.ut_cost for u in self.utility_streams])
246 return self._utility_cost
249 def serialize_json(self, isTotal=False):
250 """
251 Serialize process into json for return data
252 """
254 degree_of_integration = None
255 if(self.degree_of_int): 255 ↛ 258line 255 didn't jump to line 258 because the condition on line 255 was always true
256 degree_of_integration = self.degree_of_int * 100
258 data = {
259 'name': self.name,
260 'degree_of_integration': degree_of_integration,
261 'Qh': self.hot_utility_target,
262 'Qc': self.cold_utility_target,
263 'Qr': self.heat_recovery_target,
264 'utility_cost': self.utility_cost,
265 'row_type': SummaryRowType.FOOTER.value if isTotal else SummaryRowType.CONTENT.value,
266 'hot_utilities': [],
267 'cold_utilities': [],
268 'temp_pinch': {
269 'cold_temp': None,
270 'hot_temp': None
271 }
272 }
274 if isinstance(self.cold_pinch, float) and isinstance(self.hot_pinch, float): 274 ↛ 281line 274 didn't jump to line 281 because the condition on line 274 was always true
275 if abs(self.cold_pinch - self.hot_pinch) < ZERO:
276 temp_pinch = {'cold_temp': self.cold_pinch}
277 data['temp_pinch'] = temp_pinch
278 else:
279 temp_pinch = {'cold_temp': self.cold_pinch, 'hot_temp': self.hot_pinch}
280 data['temp_pinch'] = temp_pinch
281 elif isinstance(self.cold_pinch, float):
282 temp_pinch = {'cold_temp': self.cold_pinch}
283 data['temp_pinch'] = temp_pinch
284 elif isinstance(self.hot_pinch, float):
285 temp_pinch = {'hot_temp': self.hot_pinch}
286 data['temp_pinch'] = temp_pinch
288 if self.config.TURBINE_WORK_BUTTON: 288 ↛ 289line 288 didn't jump to line 289 because the condition on line 288 was never true
289 data['work_target'] = self.work_target
290 data['turbine_efficiency_target'] = self.turbine_efficiency_target * 100
292 if self.config.AREA_BUTTON: 292 ↛ 293line 292 didn't jump to line 293 because the condition on line 292 was never true
293 data['area'] = self.area
294 data['num_units'] = self.num_units
295 data['capital_cost'] = self.capital_cost
296 data['total_cost'] = self.total_cost
298 if self.config.EXERGY_BUTTON: 298 ↛ 299line 298 didn't jump to line 299 because the condition on line 298 was never true
299 data['exergy_sources'] = self.exergy_sources
300 data['exergy_sinks'] = self.exergy_sinks
301 data['ETE'] = self.ETE * 100
302 data['exergy_req_min'] = self.exergy_req_min
303 data['exergy_des_min'] = self.exergy_des_min
305 for utility in self.hot_utilities:
306 data['hot_utilities'].append({'name': utility.name, 'heat_flow': utility.heat_flow})
307 for utility in self.cold_utilities:
308 data['cold_utilities'].append({'name': utility.name, 'heat_flow': utility.heat_flow})
310 return data