BioSTEAMDevelopmentGroup / Bioindustrial-Park

BioSTEAM's Premier Repository for Biorefinery Models and Results
MIT License
38 stars 18 forks source link

Consultation about viscosity error #93

Closed zasddsgg closed 10 months ago

zasddsgg commented 11 months ago

Hello, when I run the following code, I encounter an error about viscosity. I try to find about NEGLECT_P methods in https://thermo.readthedocs.io/_modules/thermo/viscosity.html#ViscosityLiquidMixture to ensure that there is a valid NEGLECT_P method to solve the error, but I did not find a suitable way to solve the error, could I consult you how to solve the following error? Thanks for your help. Wish you a good day.

The code is as follows:

import biosteam as bst
bst.nbtutorial()
from biosteam import settings
from biosteam import units
import thermosteam as tmo

Riboflavin = bst.Chemical('Riboflavin', Hf=-55700, Tc=650+273.15, Tb=240+273.15, Hvap=70000)
Ethanol = bst.Chemical('Ethanol')

bst.settings.set_thermo([Riboflavin, Ethanol])

riboflavin = bst.Stream(
    ID='riboflavin',
    price=0.0916,  
    total_flow=1000,
    units='kg/hr',
    Riboflavin=0.2,
    Ethanol=0.8,
    T=100+273.15,
    P=750000,
)

D101 = units.BinaryDistillation('D101', riboflavin, P=101325, y_top=0.999, x_bot=0.001, k=1.2, Rmin=0.001, LHK=('Ethanol', 'riboflavin'))

Riboflavin_sys = bst.main_flowsheet.create_system('Riboflavin_sys')
Riboflavin_sys.simulate()

The error information is as follows:

RuntimeError                              Traceback (most recent call last)
Cell In[4], line 27
     24 D101 = units.BinaryDistillation('D101', riboflavin, P=101325, y_top=0.999, x_bot=0.001, k=1.2, Rmin=0.001, LHK=('Ethanol', 'riboflavin'))
     26 Riboflavin_sys = bst.main_flowsheet.create_system('Riboflavin_sys')
---> 27 Riboflavin_sys.simulate()

File D:\anaconda\envs\zddd\lib\site-packages\biosteam\_system.py:2332, in System.simulate(self, update_configuration, units, design_and_cost, **kwargs)
   2312 def simulate(self, update_configuration: Optional[bool]=None, units=None, 
   2313              design_and_cost=None, **kwargs):
   2314     """
   2315     If system is dynamic, run the system dynamically. Otherwise, converge 
   2316     the path of unit operations to steady state. After running/converging 
   (...)
   2330         
   2331     """
-> 2332     with self.flowsheet.temporary():
   2333         specifications = self._specifications
   2334         if specifications and not self._running_specifications:

File D:\anaconda\envs\zddd\lib\site-packages\biosteam\_flowsheet.py:36, in TemporaryFlowsheet.__exit__(self, type, exception, traceback)
     34 def __exit__(self, type, exception, traceback):
     35     main_flowsheet.set_flowsheet(self.original)
---> 36     if exception: raise exception

File D:\anaconda\envs\zddd\lib\site-packages\biosteam\_system.py:2388, in System.simulate(self, update_configuration, units, design_and_cost, **kwargs)
   2382         outputs = self.simulate(
   2383             update_configuration=True, 
   2384             design_and_cost=design_and_cost,
   2385             **kwargs
   2386         )
   2387     else:
-> 2388         raise error
   2389 else:
   2390     if (not update_configuration # Avoid infinite loop
   2391         and self._connections != [i.get_connection() for i in self.streams]):
   2392         # Connections has been updated within simulation.

File D:\anaconda\envs\zddd\lib\site-packages\biosteam\_system.py:2376, in System.simulate(self, update_configuration, units, design_and_cost, **kwargs)
   2374 try:
   2375     outputs = self.converge(**kwargs)
-> 2376     if design_and_cost: self._summary()
   2377 except Exception as error:
   2378     if update_configuration: raise error # Avoid infinite loop

File D:\anaconda\envs\zddd\lib\site-packages\biosteam\_system.py:2089, in System._summary(self)
   2087         if i in simulated_units: continue
   2088         simulated_units.add(i)
-> 2089     f(i, i._summary)
   2090 for i in self._facilities:
   2091     if isa(i, Unit): f(i, i.simulate)

File D:\anaconda\envs\zddd\lib\site-packages\thermosteam\exceptions.py:90, in try_method_with_object_stamp(object, method, args)
     88     raise StampedKeyError(message_with_object_stamp(object, repr(error.args[0])))
     89 except Exception as error:
---> 90     raise_error_with_object_stamp(object, error)

File D:\anaconda\envs\zddd\lib\site-packages\thermosteam\exceptions.py:80, in raise_error_with_object_stamp(object, error)
     78     error.args = (message_with_object_stamp(object, msg), *args)
     79 except: pass
---> 80 raise error

File D:\anaconda\envs\zddd\lib\site-packages\thermosteam\exceptions.py:84, in try_method_with_object_stamp(object, method, args)
     82 def try_method_with_object_stamp(object, method, args=()):
     83     try:
---> 84         return method(*args)
     85     except StampedKeyError as error:
     86         raise StampedKeyError(message_with_object_stamp(object, error.args[0]))

File D:\anaconda\envs\zddd\lib\site-packages\biosteam\_unit.py:1507, in Unit._summary(self, design_kwargs, cost_kwargs, lca_kwargs)
   1505 if not (self._design or self._cost): return
   1506 if not self._skip_simulation_when_inlets_are_empty or not all([i.isempty() for i in self._ins]): 
-> 1507     self._design(**design_kwargs) if design_kwargs else self._design()
   1508     self._cost(**cost_kwargs) if cost_kwargs else self._cost()
   1509     self._lca(**lca_kwargs) if lca_kwargs else self._lca()

File D:\anaconda\envs\zddd\lib\site-packages\biosteam\units\distillation.py:1372, in BinaryDistillation._design(self)
   1370 def _design(self):
   1371     self._run_McCabeThiele()
-> 1372     self._run_condenser_and_reboiler()
   1373     self._complete_distillation_column_design()

File D:\anaconda\envs\zddd\lib\site-packages\biosteam\units\distillation.py:809, in Distillation._run_condenser_and_reboiler(self)
    807 liq.T = liq_T
    808 self.pump.ins[0].copy_like(liq)
--> 809 self.pump.simulate()
    810 self.bottoms_split.simulate()
    811 if self._partial_condenser:

File D:\anaconda\envs\zddd\lib\site-packages\biosteam\_unit.py:1774, in Unit.simulate(self, run, design_kwargs, cost_kwargs)
   1772     self._load_stream_links()
   1773     self.run()
-> 1774 self._summary(design_kwargs, cost_kwargs)

File D:\anaconda\envs\zddd\lib\site-packages\biosteam\_unit.py:1507, in Unit._summary(self, design_kwargs, cost_kwargs, lca_kwargs)
   1505 if not (self._design or self._cost): return
   1506 if not self._skip_simulation_when_inlets_are_empty or not all([i.isempty() for i in self._ins]): 
-> 1507     self._design(**design_kwargs) if design_kwargs else self._design()
   1508     self._cost(**cost_kwargs) if cost_kwargs else self._cost()
   1509     self._lca(**lca_kwargs) if lca_kwargs else self._lca()

File D:\anaconda\envs\zddd\lib\site-packages\biosteam\units\_pump.py:175, in Pump._design(self)
    173 Qi = si.F_vol
    174 mass = si.F_mass
--> 175 nu = si.nu
    176 dP = Po - Pi
    177 if dP < 1: dP = self.dP_design

File D:\anaconda\envs\zddd\lib\site-packages\thermosteam\_stream.py:1236, in Stream.nu(self)
   1233 @property
   1234 def nu(self) -> float:
   1235     """Kinematic viscosity [m^2/s]."""
-> 1236     return fn.mu_to_nu(self.mu, self.rho)

File D:\anaconda\envs\zddd\lib\site-packages\thermosteam\_stream.py:1210, in Stream.mu(self)
   1207 @property
   1208 def mu(self) -> float:
   1209     """Hydrolic viscosity [Pa*s]."""
-> 1210     return self._get_property('mu')

File D:\anaconda\envs\zddd\lib\site-packages\thermosteam\_stream.py:1150, in Stream._get_property(self, name, flow, nophase)
   1146     property_cache[name] = value = calculate(
   1147         composition, *self._thermal_condition
   1148     )
   1149 else:
-> 1150     property_cache[name] = value = calculate(
   1151         phase, composition, *self._thermal_condition
   1152     )
   1153 return value * total if flow else value

File D:\anaconda\envs\zddd\lib\site-packages\thermosteam\mixture\ideal_mixture_model.py:62, in IdealTPMixtureModel.__call__(self, phase, mol, T, P)
     60 if mol.__class__ is not SparseVector: mol = SparseVector(mol)
     61 models = self.models
---> 62 return sum([j * models[i](phase, T, P) for i, j in mol.dct.items()])

File D:\anaconda\envs\zddd\lib\site-packages\thermosteam\mixture\ideal_mixture_model.py:62, in <listcomp>(.0)
     60 if mol.__class__ is not SparseVector: mol = SparseVector(mol)
     61 models = self.models
---> 62 return sum([j * models[i](phase, T, P) for i, j in mol.dct.items()])

File D:\anaconda\envs\zddd\lib\site-packages\thermosteam\base\phase_handle.py:117, in PhaseTPHandle.__call__(self, phase, T, P)
    115 def __call__(self, phase, T, P=None):
    116     if self.force_gas_critical_phase and T > self.Tc: phase = 'g'
--> 117     return getattr(self, phase)(T, P)

File D:\anaconda\envs\zddd\lib\site-packages\thermosteam\thermo\tp_dependent_property.py:42, in __call__(self, T, P)
     40 def __call__(self, T, P):
     41     if self._method_P:
---> 42         return self.TP_dependent_property(T, P)
     43     else:
     44         return self.T_dependent_property(T)

File D:\anaconda\envs\zddd\lib\site-packages\thermo\utils\tp_dependent_property.py:288, in TPDependentProperty.TP_dependent_property(self, T, P)
    286             raise RuntimeError(f"{self.name} method '{method_P}' computed an invalid value of {prop} {self.units} for component with CASRN '{self.CASRN}'")
    287 elif self.RAISE_PROPERTY_CALCULATION_ERROR:
--> 288     raise RuntimeError(f"{self.name} method '{method_P}' is not valid at T={T} K and P={P} Pa for component with CASRN '{self.CASRN}'")

RuntimeError: <BinaryDistillation: D101> liquid viscosity method 'NEGLECT_P' is not valid at T=435.20313250283334 K and P=101325.0 Pa for component with CASRN '83-88-5'
zasddsgg commented 11 months ago

According to https://thermo.readthedocs.io/thermo.viscosity.html#:~:text=thermo.viscosity.viscosity_liquid_methods_P%20%3D%20%5B%27COOLPROP%27%2C%20%27LUCAS%27%2C%20%27NEGLECT_P%27%5D, NEGLECT_P is the method used to calculate the viscosity at high pressure, so I tried to change the feed stream pressure to low pressure, but I still encountered the same error as above, could I trouble you help to have a look at this problem? Thanks for your help. Wish you a good day.

The modified code is as follows:

import biosteam as bst
bst.nbtutorial()
from biosteam import settings
from biosteam import units
import thermosteam as tmo

Riboflavin = bst.Chemical('Riboflavin', Hf=-55700, Tc=650+273.15, Tb=240+273.15, Hvap=70000)
Ethanol = bst.Chemical('Ethanol')

bst.settings.set_thermo([Riboflavin, Ethanol])

riboflavin = bst.Stream(
    ID='riboflavin',
    price=0.0916,  
    total_flow=1000,
    units='kg/hr',
    Riboflavin=0.2,
    Ethanol=0.8,
    T=100+273.15,
    P=101325*1.5, # change the 750000 to 101325*1.5
)

D101 = units.BinaryDistillation('D101', riboflavin, P=101325, y_top=0.999, x_bot=0.001, k=1.2, Rmin=0.001, LHK=('Ethanol', 'riboflavin'))

Riboflavin_sys = bst.main_flowsheet.create_system('Riboflavin_sys')
Riboflavin_sys.simulate()
zasddsgg commented 11 months ago

Hello, I have tried some methods and read some materials about viscosity calculation, but still did not solve the problem, could I trouble you have a look at it when you are free. Thanks for your help. Wish you a good day.

yalinli2 commented 11 months ago

The error is because you don't have a valid viscosity calculation method at the given condition Riboflavin.mu(phase='l', T=100+273.15, P=750000)

There is not really any usable pressure-depending viscosity modeling methods for Riboflavin in liquid phase Riboflavin.mu.l.all_methods_P

You can add method by (here I'm just setting it to a constant) Riboflavin.mu.l.add_method(f=lambda: 0.0003259750718128194)

But that only adds to all_methods, not all_methods_P, @yoelcortes I'm not sure what'll be the correct way to fix this? Thanks!

zasddsgg commented 11 months ago

Thanks for your answer. Viscosity seems to be related to both pressure and temperature. If I want to add the calculation method of viscosity related to temperature and pressure through add_method() or all_methods_P, could I consult you how should I add it? Thanks for your help. Wish you a good day.

zasddsgg commented 10 months ago

Could I consult you how to get 0.0003259750718128194? Is the unit of 0.0003259750718128194 in Riboflavin.mu.l.add_method(f=lambda: 0.0003259750718128194) Pa s or mPa s?

Does method 'NEGLECT_P' assume that viscosity is only related to temperature? If I want to get the relationship between viscosity and temperature pressure, may I ask if you have any recommended materials? If the viscosity is set to a constant, does it affect the result, in the case of riboflavin being the main product?

Thanks for your help. Wish you a good day.

yalinli2 commented 10 months ago

That value is just a random value... you could put in whatever you think makes sense for the chemical. Sorry I'm really not familiar with the viscosity calculation. @sarangbhagwat any thoughts on this?

zasddsgg commented 10 months ago

I try to add Riboflavin.mu.l.add_method(f=lambda: 0.0003259750718128194) in the following code, but error RuntimeError: <BinaryDistillation: D101> Failed to evaluate liquid viscosity method 'NEGLECT_P' at T=435.20313250283334 K and P=101325.0 Pa for component with CASRN '83-88-5' was still reported.

The code is as follows:

import biosteam as bst
bst.nbtutorial()
from biosteam import settings
from biosteam import units
import thermosteam as tmo

Riboflavin = bst.Chemical('Riboflavin', Hf=-55700, Tc=650+273.15, Tb=240+273.15, Hvap=70000)
Riboflavin.mu.l.add_method(f=lambda: 0.0003259750718128194)
Ethanol = bst.Chemical('Ethanol')

bst.settings.set_thermo([Riboflavin, Ethanol])

riboflavin = bst.Stream(
    ID='riboflavin',
    price=0.0916,  
    total_flow=1000,
    units='kg/hr',
    Riboflavin=0.2,
    Ethanol=0.8,
    T=100+273.15,
    P=750000,
)

D101 = units.BinaryDistillation('D101', riboflavin, P=101325, y_top=0.999, x_bot=0.001, k=1.2, Rmin=0.001, LHK=('Ethanol', 'riboflavin'))

Riboflavin_sys = bst.main_flowsheet.create_system('Riboflavin_sys')
Riboflavin_sys.simulate()
zasddsgg commented 10 months ago

Could someone help figure out how to fix this error, which hasn't been solved for a long time. Thanks for your help. Wish you a good day.

sarangbhagwat commented 10 months ago

@zasddsgg, instead of Riboflavin.mu.l.add_method(f=lambda: 0.0003259750718128194), you can use either of the following: Riboflavin.mu.l.add_method(f=lambda T: 0.0003259750718128194) or Riboflavin.mu.l.add_method(f=0.0003259750718128194)

If you're not sure about what model or value to use for liquid viscosity, a good interim assumption would be using existing models for other, similar chemicals. As an arbitrary example, if you wanted to use existing liquid viscosity models for Retinol, you could replace the above code with the following: Riboflavin.copy_models_from(tmo.Chemical('Retinol'), ['mu'])

Finally, it looks like your distillation column specifications require temperatures that cannot be achieved by default steam utilities; if you need that y_top and x_bot, I'd suggest reducing the pressure to, say, 10132.5 Pa.

D101 = units.BinaryDistillation('D101', riboflavin, P=101325/10, y_top=0.999, x_bot=0.001, k=1.2, Rmin=0.001, LHK=('Ethanol', 'riboflavin'))

Any of the above simulate successfully on my end -- give it a try and let me know if you have any other questions.

Best, Sarang

yoelcortes commented 10 months ago

@zasddsgg, mu.l is a LiquidViscosity object from the thermo library. If you need further help, please check thermo's documentation/code base or ask Caleb on github. He is a tremendous open-source programmer who creates chemical engineering tools in his leisure. He usually replies within a couple of weeks, but he might be busy:

https://github.com/CalebBell/thermo https://thermo.readthedocs.io/thermo.viscosity.html#pure-liquid-viscosity

@sarangbhagwat, @yalinli2, thanks so much for helping out with github issues! These last couple of weeks have been busy with the AICHE conference

Thanks!

zasddsgg commented 10 months ago

Thanks for your advice and help, the problem has been solved. Thanks again to all of you. Wish you a good day.