Closed zasddsgg closed 1 year ago
Duties and utilities are registered through HeatUtility objects, add the following line in _design
or in _cost
to add a heat utility:
self.add_heat_utility(duty, T_operation)
For more information, checkout: https://biosteam.readthedocs.io/en/latest/tutorial/Inheriting_from_Unit.html https://biosteam.readthedocs.io/en/latest/API/Unit.html#biosteam.Unit.add_heat_utility
Thanks,
Thank you for your advice and help. The problem has been solved. Thank you again. Wish you a good day.
@zasddsgg, that's great. Something I forgot to mention, don't forget to account for heats of formation (in addition to sensible and latent heats). Unit properties like, H_in and H_out don't include heats of formation. Stream.H does not either.
For heats of formation (without sensible and latent heats), use Unit.Hf_in, Unit.Hf_out, and Stream.Hf.
Thanks!
Thanks for your reminding, but I am a little confused about net_duty and Hnet. Hnet should be H_out - H_in + Hf_out - Hf_in ((https://biosteam.readthedocs.io/en/latest/_modules/biosteam/_unit.html#Unit.show)). But how is net_duty calculated? Net_duty seems to add all duty in heat_utilities, but how is duty in heat_utilities calculated? Net_duty seems to take into account heat transfer losses, what is the coefficient of heat transfer losses by default? Or other, what's the difference between net_duty and Hnet? Is net_duty used to calculate utility flow? If so, what is Hnet used for? Besides, isn't the enthalpy of inflow calculated by the enthalpy of formation of 25 degrees plus Cp times the change in temperature (enthalpy of inflow=[Hf(25 degrees) + CpΔT]flow rate), and then times the flow? So why doesn't the enthalpy flow include Hf? Thank you for your help. Wish you a good day.
@zasddsgg, here are the answers to your questions:
Thanks
Thank you for your answer. May I confirm with you whether my understanding is correct? Unit_duty refers to Hnet. When there is no reaction, such as in heat exchanger or Boiler, Hnet is obtained by self.outs. H-self.ins. H (H includes sensible and latent heats). When reaction occurs, Hnet is obtained by self.outs.H - self.ins.H+self.outs. Hf-self.ins.Hf. After obtaining Hnet (unit_duty), then divide Hnet (or unit_duty) by heat transfer efficiency to get the duty of utility. Then add the duty of all utility to get Net_duty.
In addition, I would like to consult you whether duty in self.add_heat_utility(duty, T_operation) refers to unit_duty? Does T_operation refer to the temperature of unit outlet? When defining Boiler (https://biosteam.readthedocs.io/en/latest/tutorial/Inheriting_from_Unit.html), why does temperature of utility inlet reduce Boiler outlet flow temperature to get dT? If use utility to heat Boiler, shouldn't use temperature of utility inlet to reduce Boiler inlet flow temperature to get dT? Also in add_heat_utility tutorial (https://biosteam.readthedocs.io/en/latest/API/Unit.html), add_heat_utility(unit_duty, T_in, T_out=None, agent=None, heat_transfer_efficiency=None, hxn_ok=False), seems to define T_in. So does T_operation in self.add_heat_utility(duty, T_operation) refer to T_in(the temperature at the entry stream of the unit)? Does T_out=None means that we don't have to give T_out? If not give, is the default value adopted? Does heat_transfer_efficiency=None means that if heat_transfer_efficiency is not set, is the default value for heat_transfer_efficiency used (e.g. 0.95 for low pressure steam)?
Also, if I want to view the utility flow for R201, could you help me check that is there anything wrong in the following code. In addition, may I ask you why the utility cost is 0 with the following code? Thank you a lot for your help. The code is as follows:
import biosteam as bst
bst.nbtutorial()
from biosteam.units.decorators import cost
from biosteam import Unit
from biosteam import units
from biosteam.units.design_tools.geometry import cylinder_diameter_from_volume
from thermosteam import MultiStream
import thermosteam as tmo
from biorefineries import cellulosic
cs = cellulosic.Biorefinery('corn stover ethanol')
chemicals_cs = cs.chemicals
bst.settings.set_thermo(chemicals_cs)
bst.main_flowsheet.set_flowsheet('corn_ethanol')
Rxn = tmo.reaction.Reaction
ParallelRxn = tmo.reaction.ParallelReaction
corn = bst.Stream(
ID='corn',
price=0.0516,
units='kg/hr',
Acetate=0.0635,
O2=434.6,
Protein=0.01,
Ethanol=43.84,
Sucrose=28.31,
Arabinan=0.0476,
Mannan=0.0069,
Galactan=0.0159,
)
@cost('Dry flow rate', 'Pretreatment reactor system', units='kg/hr',
S=83333, CE=522, cost=19812400 * 0.993, n=0.6, kW=4578, BM=1.5)
class PretreatmentReactorSystem(bst.units.design_tools.PressureVessel, Unit):
_N_ins = 1
_N_outs = 2
_graphics = bst.Flash._graphics
_units = {'Residence time': 'hr',
'Reactor volume': 'm3'}
def __init__(self, ID='', ins=None, outs=(), T=120+273.15, V=0.5, thermo=None,
tau=0.166, V_wf=0.8, length_to_diameter=2,
vessel_material='Stainless steel 316',
vessel_type='Horizontal',
reactions=None,
run_vle=True):
Unit.__init__(self, ID, ins, outs, thermo)
self._load_components()
vapor, liquid = self.outs
vapor.phase = 'g'
self.T = T
self.V = V
chemicals = self.chemicals
if reactions is None:
self.reactions = ParallelRxn([
# Reaction definition Reactant Conversion
Rxn('Ethanol + 3O2 -> 2CO2 + 3H2O', 'Ethanol', 0.990),
Rxn('Sucrose + 12O2 -> 12CO2 + 11H2O', 'Sucrose', 0.30)
])
self.glucan_to_glucose = self.reactions[0]
self.glucose_to_byproducts = self.reactions[1]
else:
self.reactions = reactions
self.tau = tau
self.V_wf = V_wf
self.length_to_diameter = length_to_diameter
self.vessel_material = vessel_material
self.vessel_type = vessel_type
self.run_vle = run_vle
def _load_components(self):
thermo = self.thermo
self._multistream = MultiStream(None, thermo=thermo)
def _run(self):
feed = self.ins[0]
vapor, liquid = self.outs
liquid.copy_like(feed)
self.reactions(liquid)
if self.T:
if self.run_vle:
ms = self._multistream
ms.copy_like(liquid)
ms.vle(T=self.T, V=self.V)
vapor.mol[:] = ms.imol['g']
liquid.mol[:] = ms.imol['l']
vapor.T = liquid.T = ms.T
vapor.P = liquid.P = ms.P
else:
liquid.T = self.T
def _design(self):
Design = self.design_results
T_operation = self.ins[0].T
duty = self.H_out - self.H_in + self.Hf_out - self.Hf_in
ins_F_vol = self.F_vol_in
V_reactor = ins_F_vol * self.tau / self.V_wf
P = self.outs[0].P * 0.000145038
length_to_diameter = self.length_to_diameter
D = cylinder_diameter_from_volume(V_reactor, self.length_to_diameter)
D *= 3.28084
L = D * length_to_diameter
Design['Residence time'] = self.tau
Design['Reactor volume'] = V_reactor
Design.update(self._vessel_design(float(P), float(D), float(L)))
self._decorated_design()
self.add_heat_utility(duty, T_operation)
def _cost(self):
Design = self.design_results
self.baseline_purchase_costs.update(
self._vessel_purchase_cost(
Design['Weight'], Design['Diameter'], Design['Length']
)
)
self._decorated_cost()
R201 = PretreatmentReactorSystem('R201', corn)
corn_sys = bst.main_flowsheet.create_system('corn_sys')
corn_sys.simulate()
print(R201.results())
@zasddsgg, the assertions in your first paragraph are correct in a general sense.
Regarding add_heat_utility, yes unit_duty is given by user: https://biosteam.readthedocs.io/en/latest/API/Unit.html#biosteam.Unit.add_heat_utility
Regarding your question on calculating dT. The log-mean temperature difference (LMTD) may be a better choice for the boiler. I may fix this later. However, for CSTRs and tanks, only T_operation (your outlet temperature) matters, not the inlet. Remember that heat utilities assume countercurrent operation. For more details, please read the source code and docs: https://biosteam.readthedocs.io/en/latest/API/HeatUtility.html
You are loading the complete biorefinery in the previous code. The price of utility agents are set to zero because they are all produced on-site. Please adjust the prices of your utility agents or simply not load the biorefinery:
from biorefineries import cellulosic as cs
# Do not run this line
# cs = cellulosic.Biorefinery('corn stover ethanol')
chemicals_cs = cs.create_cellulosic_ethanol_chemicals()
Don't forget to adjust your process settings before simulation: https://biosteam.readthedocs.io/en/latest/tutorial/Getting_started.html#Process-settings
Thanks!
Thank you for your answer and reminding. For CSTRs and tanks, whether it is endothermic or exothermic, does T_operation both refer to the temperature of the outlet stream of unit (CSTRs and tanks)?
If I want to check the utility duty and flow of CSTRs and tanks, is it using the following code? duty = self.H_out - self.H_in + self.Hf_out - self.Hf_in(reaction occurs) or duty = self.H_out - self.H_in (no reaction occurs) T_operation = self.outs[0].T (CSTRs and tanks outlet stream temperature) self.add_heat_utility(duty, T_operation)
In add_heat_utility(unit_duty, T_in, T_out=None, agent=None, heat_transfer_efficiency=None, hxn_ok=False),does T_out=None means that if we don't give T_out, the default value is adopted? Also, does heat_transfer_efficiency=None means that if heat_transfer_efficiency is not set, the default value for heat_transfer_efficiency is used (e.g. 0.95 for low pressure steam)?
Additionally, in the source code (https://biosteam.readthedocs.io/en/latest/_modules/biosteam/_heat_utility.html#HeatUtility), the cost of utility is calculated using self.cost = agent._heat_transfer_price abs(duty) + agent._regeneration_price F_mol. Could I coinsult you that if I purchase the utility from external source, do I still need to set the regeneration_price, or is it enough to only set the heat_transfer_price?
Thank you a lot for your help. Wish you a good day.
@zasddsgg, for a heating/cooling jacket at a theoretical CSTR/tank, the temperature at any point is the same as the outlet. So, yes, T_operation is the outlet temperature.
That code should be fine so long as you are using a jacket (which we don't have in biosteam yet). As explained earlier, the CSTR in BioSTEAM uses an auxiliary heat exchanger so T_in is T_operation and T_out will depend on the recirculated flow rate (https://github.com/BioSTEAMDevelopmentGroup/biosteam/blob/master/biosteam/units/cstr.py).
If I understand you correctly, your assertions are correct. Please read the source code for details: https://github.com/BioSTEAMDevelopmentGroup/biosteam/blob/135410ce3512fdcb939251c0168d760cecf7c291/biosteam/_heat_utility.py#L631
If you purchase utility, literature should let you know the price basis. It may be per kg (regeneration price), per kJ (heat transfer price), or both. Just follow their instructions.
Thanks,
Thank you for your answer. If there is no jacket in BioSTEAM, is it still ok to use the following code to check utility duty and utility flow of CSTRs, or tanks, or other reactors such as pretreatment reactor, fermentation reactor. Thank you for your help. Wish you a good day.
duty = self.H_out - self.H_in + self.Hf_out - self.Hf_in(reaction occurs) or duty = self.H_out - self.H_in (no reaction occurs) T_operation = self.outs[0].T (CSTRs or tanks or other reactors outlet stream temperature) self.add_heat_utility(duty, T_operation)
@zasddsgg, if you are creating your own unit operation and neglecting capital cost of your jacket, I would assume it theoretically correct.
Thank you for your answer. I got it. Thank you for your help. Wish you a good day.
Hello, I built a reactor through class PretreatmentReactorSystem, but after the operation I found net duty of the reactor is zero. In fact, ethanol, sucrose reaction with oxygen should be exothermic reaction, but net duty shows 0. May I ask why this happened? Thank you a lot for your help. The code is as follows:
import biosteam as bst bst.nbtutorial() from biosteam.units.decorators import cost from biosteam import Unit from biosteam import units from biosteam.units.design_tools.geometry import cylinder_diameter_from_volume from thermosteam import MultiStream import thermosteam as tmo from biorefineries import cellulosic cs = cellulosic.Biorefinery('corn stover ethanol') chemicals_cs = cs.chemicals bst.settings.set_thermo(chemicals_cs)
bst.main_flowsheet.set_flowsheet('corn_ethanol') Rxn = tmo.reaction.Reaction ParallelRxn = tmo.reaction.ParallelReaction corn = bst.Stream( ID='corn', price=0.0516, units='kg/hr', Acetate=0.0635, O2=434.6, Protein=0.01, Ethanol=43.84, Sucrose=28.31, Arabinan=0.0476, Mannan=0.0069, Galactan=0.0159, )
@cost('Dry flow rate', 'Pretreatment reactor system', units='kg/hr', S=83333, CE=522, cost=19812400 * 0.993, n=0.6, kW=4578, BM=1.5) class PretreatmentReactorSystem(bst.units.design_tools.PressureVessel, Unit): _N_ins = 1 _N_outs = 2 _graphics = bst.Flash._graphics _units = {'Residence time': 'hr', 'Reactor volume': 'm3'}
R201 = PretreatmentReactorSystem('R201', corn) corn_sys = bst.main_flowsheet.create_system('corn_sys') corn_sys.simulate() R201.net_duty