1212 convert , DisplayUnits , UnitsOfMeasure , get_dimensionality ,
1313 heat_utility_units_of_measure
1414)
15+ from thermosteam ._phase import valid_phases
1516from thermosteam .utils import unregistered , define_units_of_measure , infer_variable_assignment
1617from thermosteam import Thermo , Stream , ThermalCondition , settings
1718from .exceptions import DimensionError
1819from math import copysign
1920from collections import deque
2021from typing import Optional , TYPE_CHECKING , Iterable , Literal , Sequence
22+ import pandas as pd
2123if 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