OpenPinch 0.0.1__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.
@@ -0,0 +1,17 @@
1
+ Metadata-Version: 2.4
2
+ Name: OpenPinch
3
+ Version: 0.0.1
4
+ Summary: Package for performing Pinch Analysis on stream data
5
+ Project-URL: Homepage, https://github.com/waikato-ahuora-smart-energy-systems/OpenPinch
6
+ Project-URL: Issues, https://github.com/waikato-ahuora-smart-energy-systems/OpenPinch/issues
7
+ Author-email: Tim Walmsley <tim.walmsley@waikato.ac.nz>
8
+ License-Expression: MIT
9
+ License-File: LICENSE
10
+ Classifier: Operating System :: OS Independent
11
+ Classifier: Programming Language :: Python :: 3
12
+ Requires-Python: >=3.11
13
+ Description-Content-Type: text/markdown
14
+
15
+ # OpenPinch
16
+ OpenPinch is a Python package for pinch analysis and total site integration studies. OpenPinch incorperates advanced methods, including multi-scale targeting, multiple utility targeting for isothermal and non-isothermal utility, assisted heat integration, grand composite curve manipulation, and more. Many of the concepts are also embedded in an Excel workbook through VBA macros--the original development. OpenPinch began as part of Tim Walmsley's PhD study at the University of Waikato. Over the subsquent years, OpenPinch has grew into the form it is today.
17
+ More details to follow.
@@ -0,0 +1,32 @@
1
+ src/__init__.py,sha256=Px_6IhyfVHFHL2XOnU1vSSKeQqjsVsvsOMN7wYbTrx4,36
2
+ src/main.py,sha256=l9yEWcdsSyjGrl81g_LoZuKXqKJtc4mnPXC0RdGSBEI,3371
3
+ src/analysis/__init__.py,sha256=5Vg0dtLFCm-GU5IPwpBMKCIW6iYKBSyA6dHIy7lLZrU,664
4
+ src/analysis/additional_analysis.py,sha256=FLEvRaWNROSeRTAcWbP5u1QE-3gHk5GvxHdFQisdNkk,15311
5
+ src/analysis/data_preparation.py,sha256=T2QQSnuzaSq9xDs-rOTv9kNrweHLIu3XYP4y6DzYEUk,17212
6
+ src/analysis/graphs.py,sha256=lTbepR6knBQknGzCDrmdB_z2duIxWwre5futSCTVMlI,22349
7
+ src/analysis/operation_analysis.py,sha256=ukMwShlV9RIn7uWXxAF0jLGyBEO7V6W3t00CRyYhHGM,19196
8
+ src/analysis/power_cogeneration_analysis.py,sha256=CCCphvvo2g3b9O9RWos1NPQXbv4KeN7Uj0g_Id124kg,17324
9
+ src/analysis/problem_table_analysis.py,sha256=TTlzMpa21qNrtICBwMZzxRE4Vte8kVt_5HWhmAV6IkY,10209
10
+ src/analysis/process_analysis.py,sha256=Orgs0RpKb26zOrbSw_GcOMx-PVTw7kttOF0MTVneTko,6885
11
+ src/analysis/region_analysis.py,sha256=uwA9uPMFB-ZVfmoymNDHs3jLMpd47X30y1pBzUcOdRY,797
12
+ src/analysis/response.py,sha256=E-_F4O8FfzKMo26By39mlllTqGjXTwXmurOHMO-5HtY,1732
13
+ src/analysis/site_analysis.py,sha256=L5lNbIORkbT9UdrocXJgqYkiiWpYLSljmKARlvGhY5s,7032
14
+ src/analysis/support_methods.py,sha256=2jzHvCCikh5PizOg4ocNtZl9Z_xp5GnQSystLm_6h8s,7409
15
+ src/analysis/utility_targeting.py,sha256=BgKSx-GGYPB0QjH4MmNtH7AnOVvsLo6b6jIa3J1ipJQ,13143
16
+ src/classes/__init__.py,sha256=Wjwr1kQwdikR4SaMe9PK7iPrGiktaB3yq2wcz2L40Cc,190
17
+ src/classes/problem_table.py,sha256=V_CK9sX2ZDM-SAkd15XNpoS_rYHxqmTfyoYUkV_P-jA,9236
18
+ src/classes/stream.py,sha256=aw9XtTRdK42DnsLM8wK6B2PvbYRpJhphOiDQehYTVcs,7970
19
+ src/classes/stream_collection.py,sha256=I9G_S-eswVfJpF1-6umb9S4J2jbjAm7Kj2IdZG0Euiw,5017
20
+ src/classes/target.py,sha256=DA0FqzV16OfvHxazLyqk-pIjGyqORyd4_dp9CwXf0IM,10277
21
+ src/classes/value.py,sha256=RO6uuljbClX4fWMEfsBlMvTnNc7lNt4qV6tG3ZBX3XQ,3400
22
+ src/classes/zone.py,sha256=pWkXDs8pmSg5PYuVRMJH-_LxklPBO45VY0SBZEh_EXY,8429
23
+ src/classes/parentClasses/__init__.py,sha256=daEdpEyAJIa8b2VkCqSKcw8PaExcB6Qro80XNes_sHA,2
24
+ src/classes/parentClasses/unit_operation.py,sha256=L-sqzsOPrEXBoCQDoAeSfw5p5wcbSd4tIayVZtosrxo,1015
25
+ src/utils/__init__.py,sha256=U31STGKAgVs5YBIrQ_BTfjKFzBGBn85c2lTLBk3sKgo,106
26
+ src/utils/decorators.py,sha256=GFbyBaV7DoSfiv3a-CzqoM4AmR2kTSKpWDrMvuucP6g,1912
27
+ src/utils/heat_exchanger_eq.py,sha256=34b6Qjn-agi7lTrn9Zzbvuo8irROeORuKl1w0JxtJzg,7328
28
+ src/utils/water_properties.py,sha256=pGEctrFG4r2ISMY_xvTXuOp1GnjwIb3K0RxdVNa_toc,1894
29
+ openpinch-0.0.1.dist-info/METADATA,sha256=HmWtv4xUveKuHYDWryppvqzQd8gt0Pkd5q21bdj3Zgg,1158
30
+ openpinch-0.0.1.dist-info/WHEEL,sha256=qtCwoSJWgHk21S1Kb4ihdzI2rlJ1ZKaIurTj_ngOhyQ,87
31
+ openpinch-0.0.1.dist-info/licenses/LICENSE,sha256=-_wSPDS49w9xOa0uyB9WWmHa3iduYMbVNhKtvhJrBT8,1061
32
+ openpinch-0.0.1.dist-info/RECORD,,
@@ -0,0 +1,4 @@
1
+ Wheel-Version: 1.0
2
+ Generator: hatchling 1.27.0
3
+ Root-Is-Purelib: true
4
+ Tag: py3-none-any
@@ -0,0 +1,8 @@
1
+ Copyright 2025 Tim Walmsley
2
+
3
+ Permission is hereby granted, free of charge, to any person obtaining a copy of this software and associated documentation files (the “Software”), to deal in the Software without restriction, including without limitation the rights to use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons to whom the Software is furnished to do so, subject to the following conditions:
4
+
5
+ The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
6
+
7
+ THE SOFTWARE IS PROVIDED “AS IS”, WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
8
+
src/__init__.py ADDED
@@ -0,0 +1 @@
1
+ from .main import target, visualise
@@ -0,0 +1,13 @@
1
+ from .graphs import visualise_graphs
2
+ from .response import output_response
3
+ from .data_preparation import prepare_problem_struture
4
+ from .operation_analysis import get_energy_transfer_retrofit_analysis
5
+ from .problem_table_analysis import problem_table_algorithm, calc_problem_table
6
+ from .process_analysis import get_process_pinch_targets
7
+ from .power_cogeneration_analysis import get_power_cogeneration_above_pinch
8
+ from .site_analysis import get_site_targets
9
+ from .region_analysis import get_regional_targets
10
+ from .utility_targeting import get_zonal_utility_targets, target_utility, calc_GGC_utility
11
+ from .support_methods import *
12
+ from .additional_analysis import *
13
+
@@ -0,0 +1,421 @@
1
+ import pandas as pd
2
+ import numpy as np
3
+ from ..utils import *
4
+ from ..lib.enums import *
5
+ from ..classes import *
6
+ from .support_methods import *
7
+ from .power_cogeneration_analysis import get_power_cogeneration_above_pinch
8
+
9
+ __all__ = ["get_additional_zonal_pinch_analysis"]
10
+
11
+ #######################################################################################################
12
+ # Public API --- TODO
13
+ #######################################################################################################
14
+
15
+ def get_additional_zonal_pinch_analysis(pt: ProblemTable, pt_real: ProblemTable, config: Configuration):
16
+ """Calculates additional graphs and targets."""
17
+
18
+ # Target heat transfer area and number of exchanger units based on Balanced CC
19
+ area = target_area(pt_real)
20
+ num_units = min_number_hx(pt)
21
+ capital_cost = num_units * config.FC + num_units * config.VC * (area / num_units) ** config.EXP
22
+ annual_capital_cost = capital_cost * capital_recovery_factor(config.DISCOUNT_RATE, config.SERV_LIFE)
23
+
24
+
25
+ # # Target exergy supply, rejection, and destruction
26
+ # gcc_x = _calc_exergy_gcc(z, pt_real, bcc, z.graphs[GT.GCC_Act.value])
27
+ # z.add_graph(GT.GCC_X.value, gcc_x)
28
+
29
+ # # Requires review and comparision to previous Excel implementation
30
+ # GCC_AI = None
31
+ # if z.config.AHT_BUTTON_SELECTED:
32
+ # z.add_graph('GCC_AI', GCC_AI)
33
+
34
+ # # Target co-generation of heat and power
35
+ # if z.config.TURBINE_WORK_BUTTON:
36
+ # z = get_power_cogeneration_above_pinch(z)
37
+
38
+ # # Save data for TS profiles based on HT direction
39
+
40
+ return {
41
+ "area": area,
42
+ "num_units": num_units,
43
+ "capital_cost": capital_cost,
44
+ "annual_capital_cost": annual_capital_cost,
45
+ }
46
+
47
+
48
+ #######################################################################################################
49
+ # Helper functions
50
+ #######################################################################################################
51
+
52
+ def target_area(z, pt: ProblemTable) -> float:
53
+ """Estimates a heat transfer area target based on counter-current heat transfer using vectorized pandas operations."""
54
+ if abs(pt['HCC'].iloc[0] - pt['CCC'].iloc[0]) > ZERO:
55
+ raise ValueError("Balanced Composite Curves are imbalanced.")
56
+
57
+ # Collect H_val intervals and sort
58
+ h_vals = pd.Series(pt['HCC'].iloc[:-1].tolist() + pt['CCC'].iloc[:-1].tolist()).sort_values().reset_index(drop=True)
59
+ h_start = h_vals[:-1].values
60
+ h_end = h_vals[1:].values
61
+ dh = h_start - h_end
62
+
63
+ # Interpolate temperatures for each H at both ends
64
+ t_h1 = np.interp(h_start, pt['HCC'], pt['T'])
65
+ t_h2 = np.interp(h_end, pt['HCC'], pt['T'])
66
+ t_c1 = np.interp(h_start, pt['CCC'], pt['T'])
67
+ t_c2 = np.interp(h_end, pt['CCC'], pt['T'])
68
+
69
+ delta_T1 = t_h1 - t_c1
70
+ delta_T2 = t_h2 - t_c2
71
+
72
+ t_lmtd = np.where(
73
+ abs(delta_T1 - delta_T2) < 1e-6,
74
+ (delta_T1 + delta_T2) / 2,
75
+ (delta_T1 - delta_T2) / np.log(delta_T1 / delta_T2)
76
+ )
77
+
78
+ cp_hot = dh / (t_h1 - t_h2)
79
+ cp_cold = dh / (t_c1 - t_c2)
80
+ cp_min = np.minimum(cp_hot, cp_cold)
81
+ cp_max = np.maximum(cp_hot, cp_cold)
82
+
83
+ eff = dh / (cp_min * (t_h1 - t_c2))
84
+ cp_star = cp_min / cp_max
85
+
86
+ if z.config.CF_SELECTED:
87
+ arrangement = HX.CF.value
88
+ elif z.config.PF_SELECTED:
89
+ arrangement = HX.PF.value
90
+ else:
91
+ arrangement = HX.ShellTube.value
92
+
93
+ ntu = np.vectorize(HX_NTU)(arrangement, eff, cp_star)
94
+
95
+ r_hot = np.interp(h_end, pt['HCC'], pt['RH'])
96
+ r_cold = np.interp(h_end, pt['CCC'], pt['RC'])
97
+ u_o = 1 / (r_hot + r_cold)
98
+
99
+ area_segments = ntu * cp_min / u_o
100
+ total_area = np.sum(area_segments)
101
+
102
+ return float(total_area)
103
+
104
+
105
+ def min_number_hx(z, pt_df: ProblemTable, bcc_star_df: ProblemTable) -> int:
106
+ """
107
+ Estimates the minimum number of heat exchangers required for the pinch problem using vectorized interval logic.
108
+
109
+ Args:
110
+ z: Zone with hot/cold streams and utilities.
111
+ pt_df (ProblemTable): Problem table DataFrame with temperature column.
112
+ bcc_star_df (ProblemTable): Balanced Composite Curve data with 'CCC' and 'HCC'.
113
+
114
+ Returns:
115
+ int: Minimum number of exchangers.
116
+ """
117
+ T_vals = pt_df.iloc[:, 0].values
118
+ CCC = bcc_star_df['CCC'].values
119
+ HCC = bcc_star_df['HCC'].values
120
+
121
+ num_hx = 0
122
+ i = 0
123
+ while i < len(T_vals) - 1:
124
+ if abs(CCC[i + 1] - HCC[i + 1]) > ZERO:
125
+ break
126
+ i += 1
127
+
128
+ i_1 = i
129
+ i += 1
130
+
131
+ while i < len(T_vals):
132
+ i_0 = i_1
133
+ if abs(CCC[i] - HCC[i]) < ZERO or i == len(T_vals) - 1:
134
+ i_1 = i
135
+ T_high, T_low = T_vals[i_0], T_vals[i_1]
136
+
137
+ def count_crossing(streams):
138
+ t_max = np.array([s.t_max_star for s in streams])
139
+ t_min = np.array([s.t_min_star for s in streams])
140
+ return np.sum(
141
+ ((t_max > T_low + ZERO) & (t_max <= T_high + ZERO)) |
142
+ ((t_min >= T_low - ZERO) & (t_min < T_high - ZERO)) |
143
+ ((t_min < T_low - ZERO) & (t_max > T_high + ZERO))
144
+ )
145
+
146
+ num_hx += count_crossing(z.hot_streams)
147
+ num_hx += count_crossing(z.cold_streams)
148
+
149
+ def count_utility_crossing(utilities):
150
+ t_max = np.array([u.t_max_star for u in utilities])
151
+ t_min = np.array([u.t_min_star for u in utilities])
152
+ return np.sum(
153
+ (t_max > T_low + ZERO) & (t_max <= T_high + ZERO) |
154
+ (t_min >= T_low - ZERO) & (t_min < T_high - ZERO)
155
+ )
156
+
157
+ num_hx += count_utility_crossing(z.hot_utilities)
158
+ num_hx += count_utility_crossing(z.cold_utilities)
159
+ num_hx -= 1
160
+
161
+ j = i_1
162
+ while j < len(T_vals) - 1:
163
+ if abs(CCC[j + 1] - HCC[j + 1]) > ZERO:
164
+ break
165
+ j += 1
166
+
167
+ i = j
168
+ i_1 = j
169
+
170
+ i += 1
171
+
172
+ return int(num_hx)
173
+
174
+
175
+ ############# Review and testing needed!!!!!!!!!!!!!!
176
+
177
+
178
+ ############# Review and testing needed!!!!!!!!!!!!!!
179
+ # def _calc_exergy_gcc(z, pt_real, BCC, GCC_Act):
180
+ # """Determine Exergy Transfer Effectiveness including process and utility streams.
181
+ # """
182
+ # # Exergy Transfer Effectiveness proposed by Marmolejo-Correa, D., Gundersen, T., 2012.
183
+ # # A comparison of exergy efficiency definitions with focus on low temperature processes.
184
+ # # Energy 44, 477–489. https://doi.org/10.1016/j.energy.2012.06.001
185
+ # x_source, x_sink, n_ETE = _calc_total_exergy(BCC)
186
+ # z.exergy_sources = x_source
187
+ # z.exergy_sinks = x_sink
188
+ # z.ETE = n_ETE
189
+
190
+ # GCC_X = z.Calc_ExGCC(GCC_Act)
191
+ # x_source, x_sink, n_ETE = _calc_total_exergy(pt_real, Col_T=0, Col_HCC=4, Col_CCC=7)
192
+
193
+ # z.exergy_req_min = GCC_X[1][1]
194
+ # z.exergy_des_min = GCC_X[1][-1]
195
+
196
+ # return GCC_X
197
+
198
+ ############# Review and testing needed!!!!!!!!!!!!!!
199
+ # def _calc_total_exergy(z: Zone, CC, x_source=0, x_sink=0, n_ETE=0, Col_T=0, Col_HCC=2, Col_CCC=4):
200
+ # """Determines the source and sink exergy of a balanced CC."""
201
+ # for i in range(1, len(CC[0])):
202
+ # T_ex1 = compute_exergetic_temperature(CC[Col_T][i - 1], T_ref=z.config.TEMP_REF)
203
+ # T_ex2 = compute_exergetic_temperature(CC[Col_T][i], T_ref=z.config.TEMP_REF)
204
+ # CP_hot = (CC[Col_HCC][i - 1] - CC[Col_HCC][i]) / (CC[Col_T][i - 1] - CC[Col_T][i])
205
+ # CP_cold = (CC[Col_CCC][i - 1] - CC[Col_CCC][i]) / (CC[Col_T][i - 1] - CC[Col_T][i])
206
+
207
+ # if T_ex1 > 0:
208
+ # x_source = x_source + CP_hot * T_ex1
209
+ # x_sink = x_sink + CP_cold * T_ex1
210
+ # else:
211
+ # x_source = x_source + CP_cold * T_ex1
212
+ # x_sink = x_sink + CP_hot * T_ex1
213
+
214
+ # if T_ex2 > 0:
215
+ # x_source = x_source - CP_hot * T_ex2
216
+ # x_sink = x_sink - CP_cold * T_ex2
217
+ # else:
218
+ # x_source = x_source - CP_cold * T_ex2
219
+ # x_sink = x_sink - CP_hot * T_ex2
220
+
221
+ # n_ETE = x_sink / x_source if x_source > ZERO else 0
222
+
223
+ # return x_source, x_sink, n_ETE
224
+
225
+ ############# Review and testing needed!!!!!!!!!!!!!!
226
+ def Target_Area(z, BCC):
227
+ """Estimates a heat transfer area target for a z based on counter-current heat transfer.
228
+ """
229
+ Area = 0
230
+
231
+ # Calculates the area table
232
+ H_val = [0 for i in range(len(BCC[0]) * 2)]
233
+
234
+ ColT = 0
235
+ ColRH = 1
236
+ ColHCC = 2
237
+ ColRC = 3
238
+ ColCCC = 4
239
+
240
+ # Check the BCC is balanced, if not stop the calculation and return an error
241
+ if abs(BCC[ColHCC][0] - BCC[ColCCC][0]) > ZERO:
242
+ raise Exception('Balanced Composite Curves are imbalanced...')
243
+
244
+ # Collate all H intervals
245
+ for i in range(1, len(BCC[0])):
246
+ H_val[i * 2 - 2] = BCC[ColHCC][i - 1]
247
+ H_val[i * 2 - 1] = BCC[ColCCC][i - 1]
248
+
249
+ H_val = H_val.sort(reverse=True)
250
+
251
+ CalcTable = [ [None for j in range(len(H_val) - 1)] for i in range(10)]
252
+
253
+ for i in range(len(H_val) - 1):
254
+ CalcTable[0][i] = H_val[i]
255
+ CalcTable[1][i] = H_val[i + 1]
256
+
257
+ r_h = 0
258
+ r_c = 0
259
+ for i in range(len(CalcTable[0])):
260
+ while (CalcTable[0][i] - BCC[ColHCC][r_h + 1]) <= ZERO and r_h + 2 <= len(BCC[0]):
261
+ r_h += 1
262
+ while (CalcTable[0][i] - BCC[ColCCC][r_c + 1]) <= ZERO and r_c + 2 <= len(BCC[0]):
263
+ r_c += 1
264
+
265
+ if (CalcTable[0][i] - BCC[ColHCC][r_h + 1] <= ZERO or CalcTable[0][i] - BCC[ColCCC][r_c + 1] <= ZERO) \
266
+ and (r_h + 1 == len(BCC[0]) or r_c + 1 == len(BCC[0])):
267
+ break
268
+
269
+ T_h1 = linear_interpolation(CalcTable[0][i], BCC[ColHCC][r_h], BCC[ColHCC][r_h + 1], BCC[ColT][r_h], BCC[ColT][r_h + 1])
270
+ T_h2 = linear_interpolation(CalcTable[1][i], BCC[ColHCC][r_h], BCC[ColHCC][r_h + 1], BCC[ColT][r_h], BCC[ColT][r_h + 1])
271
+ T_c1 = linear_interpolation(CalcTable[0][i], BCC[ColCCC][r_c], BCC[ColCCC][r_c + 1], BCC[ColT][r_c], BCC[ColT][r_c + 1])
272
+ T_c2 = linear_interpolation(CalcTable[1][i], BCC[ColCCC][r_c], BCC[ColCCC][r_c + 1], BCC[ColT][r_c], BCC[ColT][r_c + 1])
273
+
274
+ dh = CalcTable[0][i] - CalcTable[1][i]
275
+
276
+ T_LMTD = find_LMTD(T_h1, T_h2, T_c1, T_c2)
277
+ CalcTable[2][i] = T_LMTD
278
+
279
+ CP_hot = dh / (T_h1 - T_h2)
280
+ CP_cold = dh / (T_c1 - T_c2)
281
+
282
+ CP_min = min(CP_hot, CP_cold)
283
+ CP_max = max(CP_hot, CP_cold)
284
+ eff = dh / (CP_min * (T_h1 - T_c2))
285
+ CP_star = CP_min / CP_max
286
+
287
+ Arrangement = None
288
+ if z.config.CF_SELECTED:
289
+ Arrangement = HX.CF.value
290
+ elif z.config.PF_SELECTED:
291
+ Arrangement = HX.PF.value
292
+ else:
293
+ Arrangement = HX.ShellTube.value
294
+
295
+ Ntu = HX_NTU(Arrangement, eff, CP_star)
296
+
297
+ # Heat transfer resistance and coefficient
298
+ R_hot = BCC[ColRH][r_h + 1]
299
+ R_cold = BCC[ColRC][r_c + 1]
300
+ U_o = 1 / (R_hot + R_cold)
301
+
302
+ CalcTable[3][i] = Ntu * CP_min / U_o
303
+ CalcTable[4][i] = dh / (U_o * T_LMTD)
304
+
305
+ Area = Area + CalcTable[3][i]
306
+
307
+ return Area
308
+
309
+ def MinNumberHX(z, pt, BCC_star):
310
+ """Estimates the minimum number of heat exchanger units for a given Pinch problem.
311
+ """
312
+ Num_HX = 0
313
+ i = 0
314
+ while i < len(pt[0]) - 1:
315
+ if abs(BCC_star[4][i + 1] - BCC_star[2][i + 1]) > ZERO:
316
+ break
317
+ i += 1
318
+
319
+ i_1 = i
320
+ i = i + 1
321
+ while i < len(pt[0]):
322
+ i_0 = i_1
323
+
324
+ if abs(BCC_star[4][i] - BCC_star[2][i]) < ZERO or i == len(pt[0]) - 1:
325
+ i_1 = i
326
+ T_high = pt[0][i_0]
327
+ T_low = pt[0][i_1]
328
+
329
+ for s in z.hot_streams:
330
+ T_max = s.t_max_star
331
+ T_min = s.t_min_star
332
+ if (T_max > T_low + ZERO and T_max <= T_high + ZERO) or (T_min >= T_low - ZERO \
333
+ and T_min < T_high - ZERO) or (T_min < T_low - ZERO and T_max > T_high + ZERO):
334
+ Num_HX += 1
335
+
336
+ for s in z.cold_streams:
337
+ T_max = s.t_max_star
338
+ T_min = s.t_min_star
339
+ if (T_max > T_low + ZERO and T_max <= T_high + ZERO) or (T_min >= T_low - ZERO \
340
+ and T_min < T_high - ZERO) or (T_min < T_low - ZERO and T_max > T_high + ZERO):
341
+ Num_HX += 1
342
+
343
+ for utility_k in z.hot_utilities:
344
+ T_max = utility_k.t_max_star
345
+ T_min = utility_k.t_min_star
346
+ if (T_max > T_low + ZERO and T_max <= T_high + ZERO) or (T_min >= T_low - ZERO and T_min < T_high - ZERO):
347
+ Num_HX += 1
348
+
349
+ for utility_k in z.cold_utilities:
350
+ T_max = utility_k.t_max_star
351
+ T_min = utility_k.t_min_star
352
+ if (T_max > T_low + ZERO and T_max <= T_high + ZERO) or (T_min >= T_low - ZERO and T_min < T_high - ZERO):
353
+ Num_HX += 1
354
+
355
+ Num_HX -= 1
356
+
357
+ j = i_1
358
+ while j < len(pt[0]) - 1:
359
+ if abs(BCC_star[4][j + 1] - BCC_star[2][j + 1]) > ZERO:
360
+ break
361
+ j += 1
362
+
363
+ i = j
364
+ i_1 = j
365
+
366
+ i += 1
367
+
368
+ return Num_HX
369
+
370
+ # def Calc_ExGCC(z, GCC_Act):
371
+ # """Transposes a normal GCC (T-h) into a exergy GCC (Tx-X).
372
+ # """
373
+ # GCC_X = copy.deepcopy(GCC_Act)
374
+ # Min_X = 0
375
+ # AbovePT = True
376
+ # GCC_X[0][0] = compute_exergetic_temperature(GCC_Act[0][0] + z.config.DTCONT / 2, T_ref=z.config.TEMP_REF)
377
+ # GCC_X[1][0] = 0
378
+ # i_upper = len(GCC_X[0]) + 1
379
+
380
+ # # Transpose to exergetic temperature and exergy flow
381
+ # i = 1
382
+ # gcc_act_i = 1
383
+ # while i <= i_upper and gcc_act_i < len(GCC_Act[0]):
384
+ # if AbovePT:
385
+ # GCC_X[0][i] = compute_exergetic_temperature(GCC_Act[0][gcc_act_i] + z.config.DTCONT / 2, T_ref=z.config.TEMP_REF)
386
+ # GCC_X[1][i] = (GCC_Act[1][gcc_act_i - 1] - GCC_Act[1][gcc_act_i]) / (GCC_Act[0][gcc_act_i - 1] - GCC_Act[0][gcc_act_i])
387
+ # GCC_X[1][i] = GCC_X[1][i - 1] - GCC_X[1][i] * (GCC_X[0][i - 1] - GCC_X[0][i])
388
+ # if GCC_Act[1][gcc_act_i] < ZERO:
389
+ # Min_X = GCC_X[1][i]
390
+ # for row in GCC_X:
391
+ # row += [0, 0]
392
+ # i += 2
393
+ # gcc_act_i += 1
394
+ # GCC_X[0][i] = compute_exergetic_temperature(GCC_Act[0][gcc_act_i - 1] - z.config.DTCONT / 2, T_ref=z.config.TEMP_REF)
395
+ # GCC_X[1][i] = GCC_X[1][i - 1]
396
+ # AbovePT = False
397
+ # else:
398
+ # GCC_X[0][i] = compute_exergetic_temperature(GCC_Act[0][gcc_act_i - 1] - z.config.DTCONT / 2, T_ref=z.config.TEMP_REF)
399
+ # GCC_X[1][i] = (GCC_Act[1][gcc_act_i - 2] - GCC_Act[1][gcc_act_i - 1]) / (GCC_Act[0][gcc_act_i - 2] - GCC_Act[0][gcc_act_i - 1])
400
+ # GCC_X[1][i] = GCC_X[1][i - 1] - GCC_X[1][i] * (GCC_X[0][i - 1] - GCC_X[0][i])
401
+ # i += 1
402
+ # gcc_act_i += 1
403
+
404
+ # # Shift Exergy GCC appropriately
405
+ # for i in range(1, len(GCC_X[0])):
406
+ # GCC_X[1][i] = GCC_X[1][i] + abs(Min_X)
407
+ # if abs(GCC_X[1][i]) < ZERO:
408
+ # GCC_X[1][i] = 0
409
+
410
+ # return GCC_X
411
+
412
+
413
+
414
+ # def Calc_GCC_AI(z, pt_real, gcc_np):
415
+ # """Returns a simplified array for the assisted integration GCC.
416
+ # """
417
+ # GCC_AI = [ [ None for j in range(len(pt_real[0]))] for i in range(2)]
418
+ # for i in range(len(pt_real[0])):
419
+ # GCC_AI[0][i] = pt_real[0][i]
420
+ # GCC_AI[1][i] = pt_real[PT.H_NET.value][i] - gcc_np[1][i]
421
+ # return GCC_AI