Skip to content

Commit 31c300b

Browse files
committed
2.53.5 release; improved repr of utility agents
1 parent ecbbd70 commit 31c300b

5 files changed

Lines changed: 240 additions & 98 deletions

File tree

biosteam/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@
1313
1414
"""
1515
from __future__ import annotations
16-
__version__ = '2.53.4'
16+
__version__ = '2.53.5'
1717

1818
#: Chemical engineering plant cost index (defaults to 567.5 at 2017).
1919
CE: float = 567.5

biosteam/_heat_utility.py

Lines changed: 137 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -12,12 +12,14 @@
1212
convert, DisplayUnits, UnitsOfMeasure, get_dimensionality,
1313
heat_utility_units_of_measure
1414
)
15+
from thermosteam._phase import valid_phases
1516
from thermosteam.utils import unregistered, define_units_of_measure, infer_variable_assignment
1617
from thermosteam import Thermo, Stream, ThermalCondition, settings
1718
from .exceptions import DimensionError
1819
from math import copysign
1920
from collections import deque
2021
from typing import Optional, TYPE_CHECKING, Iterable, Literal, Sequence
22+
import pandas as pd
2123
if TYPE_CHECKING: from biosteam import Unit
2224

2325
__all__ = ('HeatUtility', 'UtilityAgent')
@@ -92,7 +94,7 @@ def __init__(self,
9294
heat_transfer_efficiency: float=1.,
9395
isfuel: bool=False,
9496
dT: Optional[float]=0,
95-
**chemical_flows: float):
97+
**chemical_flows: float,):
9698
self._thermal_condition = ThermalCondition(T, P)
9799
thermo = self._load_thermo(thermo)
98100
self._init_indexer(None, phase, thermo.chemicals, chemical_flows)
@@ -104,7 +106,7 @@ def __init__(self,
104106
self.mol.read_only = True # Flow rate cannot change anymore
105107
self._sink = self._source = None
106108
self.reset_cache()
107-
if settings.ID_magic and ID == '': ID = infer_variable_assignment(self.__class__, '-')
109+
if settings.ID_magic and ID == '': ID = infer_variable_assignment(self.__class__)
108110
self._register(ID)
109111
self.T_limit = T_limit
110112
self.heat_transfer_price = heat_transfer_price
@@ -212,33 +214,148 @@ def regeneration_price(self) -> float:
212214
def regeneration_price(self, price: float):
213215
assert price >= 0, "regeneration price cannot be negative"
214216
self._regeneration_price = price
215-
216-
def _info_phaseTP(self, phase, units, notation):
217+
218+
def _info_df(self, units, notation, composition, N_max, all_IDs, indexer, factor):
219+
if not all_IDs:
220+
return pd.DataFrame(
221+
[0],
222+
columns=[self.ID.replace('_', ' ')],
223+
index=['Flow']
224+
)
225+
226+
T_units = units['T']
227+
P_units = units['P']
228+
flow_units = units['flow']
217229
T_notation = notation['T']
218230
P_notation = notation['P']
231+
flow_notation = notation['flow']
232+
233+
T = convert(self.T, 'K', T_units)
234+
P = convert(self.P, 'Pa', P_units)
235+
236+
data = []
237+
index = []
238+
239+
index.append('Heat transfer price [USD/kJ]')
240+
data.append(f"{self.heat_transfer_price:.3g}")
241+
242+
index.append('Regeneration price [USD/kmol]')
243+
data.append(f"{self.regeneration_price:.3g}")
244+
245+
index.append('Heat transfer efficiency [%]')
246+
data.append(f"{int(100 * self.heat_transfer_efficiency)}")
247+
248+
if self.T_limit is not None:
249+
index.append(f'Temperature limit [{T_units}]')
250+
data.append(f"{self.T_limit:{T_notation}}")
251+
252+
index.append(f'Temperature [{T_units}]')
253+
data.append(f"{T:{T_notation}}")
254+
255+
index.append(f'Pressure [{P_units}]')
256+
data.append(f"{P:{P_notation}}")
257+
258+
for phase in self.phases:
259+
if indexer.data.ndim == 2:
260+
flow_array = factor * indexer[phase, all_IDs]
261+
else:
262+
flow_array = factor * indexer[all_IDs]
263+
264+
phase = valid_phases[phase]
265+
if phase.islower():
266+
phase = phase.capitalize()
267+
268+
total_flow = flow_array.sum()
269+
270+
index.append(f"{phase} flow rate [{flow_units}]")
271+
data.append(f"{total_flow:{flow_notation}}")
272+
273+
if total_flow == 0:
274+
comp_array = flow_array
275+
else:
276+
comp_array = 100 * flow_array / total_flow
277+
278+
for i, (ID, comp) in enumerate(zip(all_IDs, comp_array)):
279+
if not comp:
280+
continue
281+
282+
if i >= N_max:
283+
index.append('Remainder [%]')
284+
data.append(f"{comp_array[N_max:].sum():{flow_notation}}")
285+
break
286+
287+
index.append(f'{ID} [%]')
288+
data.append(f"{comp:{flow_notation}}")
289+
290+
return pd.DataFrame(
291+
data,
292+
columns=[self.ID.replace('_', ' ')],
293+
index=index,
294+
)
295+
296+
def _info_phaseTP(self, phase, units, notation):
219297
T_units = units['T']
220298
P_units = units['P']
221-
if self.T_limit is None:
222-
T_limit = "None"
223-
else:
224-
T_limit = convert(self.T_limit, 'K', T_units)
225-
T_limit = f"{T_limit:.3g} K" if T_limit else "None"
226299
T = convert(self.T, 'K', T_units)
227300
P = convert(self.P, 'Pa', P_units)
228-
s = '' if isinstance(phase, str) else 's'
301+
if self.T_limit is None:
302+
return f"phase: {repr(phase)}, T: {T:{notation['T']}} {T_units}, P: {P:{notation['P']}} {P_units}\n"
303+
else:
304+
return f"phase: {repr(phase)}, T: {T:{notation['T']}} up to {self.T_limit:{notation['T']}} {T_units}, P: {P:{notation['P']}} {P_units}\n"
305+
306+
def _info_str(self, units, notation, composition, N_max, all_IDs, indexer, factor):
229307
ht_price = self.heat_transfer_price
230308
rg_price = self.regeneration_price
231309
ht_eff = self.heat_transfer_efficiency
232-
return (f"heat_transfer_efficiency: {ht_eff:.3f}\n"
233-
f"heat_transfer_price: {ht_price:.3g} USD/kJ\n"
234-
f"regeneration_price: {rg_price:.3g} USD/kmol\n"
235-
f"T_limit: {T_limit}\n"
236-
f"phase{s}: {repr(phase)}\n"
237-
f"T: {T:{T_notation}} {T_units}\n"
238-
f"P: {P:{P_notation}} {P_units}\n"
239-
)
240-
def __repr__(self):
241-
return f"<{type(self).__name__}: {self.ID}>"
310+
if ht_price and not rg_price:
311+
price = f"price: {ht_price:.3g} USD/kJ at {ht_eff:.0%} efficiency\n"
312+
elif rg_price and not ht_price:
313+
price = f"price: {rg_price:.3g} USD/kmol at {ht_eff:.0%} efficiency\n"
314+
elif ht_price and rg_price:
315+
price = f"price: {rg_price:.3g} USD/kmol + {ht_price:.3g} USD/kJ at {ht_eff:.0%} efficiency\n"
316+
else:
317+
price = f"price: 0 at {ht_eff:.0%} efficiency\n"
318+
basic_info = self._basic_info()
319+
TP_info = self._info_phaseTP(self.phase, units, notation)
320+
flow_units = units['flow']
321+
flow_notation = notation['flow']
322+
if N_max == 0:
323+
return basic_info[:-1]
324+
N_IDs = len(all_IDs)
325+
if N_IDs == 1:
326+
beginning = ''
327+
flow_rates = f'composition: 100% {all_IDs[0]}'
328+
else:
329+
# Remaining lines (all flow rates)
330+
flow_array = factor * indexer[all_IDs]
331+
total_flow = flow_array.sum()
332+
beginning = "composition (%): "
333+
new_line = '\n' + len(beginning) * ' '
334+
flow_array = 100 * flow_array/total_flow
335+
flow_rates = ''
336+
too_many_chemicals = N_IDs > N_max
337+
if not too_many_chemicals: N_max = N_IDs
338+
lengths = [len(i) for i in all_IDs[:N_max]]
339+
maxlen = max(lengths) + 2
340+
for i in range(N_max):
341+
spaces = ' ' * (maxlen - lengths[i])
342+
if i:
343+
flow_rates += new_line
344+
flow_rates += all_IDs[i] + spaces + \
345+
f'{flow_array[i]:{flow_notation}}'
346+
if too_many_chemicals:
347+
spaces = ' ' * (maxlen - 3)
348+
flow_rates += new_line + '...' + spaces + \
349+
f'{flow_array[N_max:].sum():{flow_notation}}'
350+
dashes = '-' * (maxlen - 2)
351+
flow_rates += f"{new_line}{dashes} {total_flow:{flow_notation}} {flow_units}"
352+
return (basic_info
353+
+ price
354+
+ TP_info
355+
+ beginning
356+
+ flow_rates)
357+
358+
242359

243360

244361
# %%

0 commit comments

Comments
 (0)