Git Product home page Git Product logo

calebbell / thermo Goto Github PK

View Code? Open in Web Editor NEW
592.0 47.0 112.0 40.98 MB

Thermodynamics and Phase Equilibrium component of Chemical Engineering Design Library (ChEDL)

License: MIT License

Python 100.00%
thermodynamics chemistry cheminformatics chemical-engineering mechanical-engineering viscosity density heat-capacity thermal-conductivity surface-tension combustion environmental-engineering solubility vapor-pressure equation-of-state molecule process-simulation physics

thermo's Introduction

Thermo

Version_status

Documentation

license

Coverage

Supported_versions

Join the chat at https://gitter.im/CalebBell/thermo

Zendo

What is Thermo?

Thermo is open-source software for engineers, scientists, technicians and anyone trying to understand the universe in more detail. It facilitates the retrieval of constants of chemicals, the calculation of temperature and pressure dependent chemical properties (both thermodynamic and transport), and the calculation of the same for chemical mixtures (including phase equilibria) using various models.

Thermo runs on all operating systems which support Python, is quick to install, and is free of charge. Thermo is designed to be easy to use while still providing powerful functionality. If you need to know something about a chemical or mixture, give Thermo a try.

Installation

Get the latest version of Thermo from https://pypi.python.org/pypi/thermo/

If you have an installation of Python with pip, simple install it with:

$ pip install thermo

Alternatively, if you are using conda as your package management, you can simply install Thermo in your environment from conda-forge channel with:

$ conda install -c conda-forge thermo

To get the git version, run:

$ git clone git://github.com/CalebBell/thermo.git

Documentation

Thermo's documentation is available on the web:

http://thermo.readthedocs.io/

Getting Started - Rigorous Interface

Create a pure-component flash object for the compound "decane", using the Peng-Robinson equation of state. Perform a flash calculation at 300 K and 1 bar, and obtain a variety of properties from the resulting object:

>>> from thermo import ChemicalConstantsPackage, PRMIX, CEOSLiquid, CEOSGas, FlashPureVLS
>>> # Load the constant properties and correlation properties
>>> constants, correlations = ChemicalConstantsPackage.from_IDs(['decane'])
>>> # Configure the liquid and gas phase objects
>>> eos_kwargs = dict(Tcs=constants.Tcs, Pcs=constants.Pcs, omegas=constants.omegas)
>>> liquid = CEOSLiquid(PRMIX, HeatCapacityGases=correlations.HeatCapacityGases, eos_kwargs=eos_kwargs)
>>> gas = CEOSGas(PRMIX, HeatCapacityGases=correlations.HeatCapacityGases, eos_kwargs=eos_kwargs)
>>> # Create a flash object with possible phases of 1 gas and 1 liquid
>>> flasher = FlashPureVLS(constants, correlations, gas=gas, liquids=[liquid], solids=[])
>>> # Flash at 300 K and 1 bar
>>> res = flasher.flash(T=300, P=1e5)
>>> # molar enthalpy and entropy [J/mol and J/(mol*K) respectively] and the mass enthalpy and entropy [J/kg and J/(kg*K)]
>>> res.H(), res.S(), res.H_mass(), res.S_mass()
(-48458.137745529726, -112.67831317511894, -340578.897757812, -791.9383098029132)
>>> # molar Cp and Cv [J/(mol*K)] and the mass Cp and Cv [J/(kg*K)]
>>> res.Cp(), res.Cv(), res.Cp_mass(), res.Cv_mass()
(295.17313861592686, 269.62465319082014, 2074.568831461133, 1895.0061117553582)
>>> # Molar volume [m^3/mol], molar density [mol/m^3] and mass density [kg/m^3]
>>> res.V(), res.rho(), res.rho_mass()
(0.00020989856076374984, 4764.206082982839, 677.8592453530177)
>>> # isobatic expansion coefficient [1/K], isothermal compressibility [1/Pa], Joule Thomson coefficient [K/Pa]
>>> res.isobaric_expansion(), res.kappa(), res.Joule_Thomson()
(0.0006977350520992281, 1.1999043797490713e-09, -5.622547043844744e-07)
>>> # Speed of sound in molar [m*kg^0.5/(s*mol^0.5)] and mass [m/s] units
>>> res.speed_of_sound(), res.speed_of_sound_mass()
(437.61281158744987, 1160.1537167375043)

The following example shows the retrieval of chemical properties for a two-phase system with methane, ethane, and nitrogen, using a few sample kijs:

>>> from thermo import ChemicalConstantsPackage, CEOSGas, CEOSLiquid, PRMIX, FlashVL
>>> from thermo.interaction_parameters import IPDB
>>> constants, properties = ChemicalConstantsPackage.from_IDs(['methane', 'ethane', 'nitrogen'])
>>> kijs = IPDB.get_ip_asymmetric_matrix('ChemSep PR', constants.CASs, 'kij')
>>> kijs
[[0.0, -0.0059, 0.0289], [-0.0059, 0.0, 0.0533], [0.0289, 0.0533, 0.0]]
>>> eos_kwargs = {'Pcs': constants.Pcs, 'Tcs': constants.Tcs, 'omegas': constants.omegas, 'kijs': kijs}
>>> gas = CEOSGas(PRMIX, eos_kwargs=eos_kwargs, HeatCapacityGases=properties.HeatCapacityGases)
>>> liquid = CEOSLiquid(PRMIX, eos_kwargs=eos_kwargs, HeatCapacityGases=properties.HeatCapacityGases)
>>> flasher = FlashVL(constants, properties, liquid=liquid, gas=gas)
>>> zs = [0.965, 0.018, 0.017]
>>> PT = flasher.flash(T=110.0, P=1e5, zs=zs)
>>> PT.VF, PT.gas.zs, PT.liquid0.zs
(0.10365, [0.881788, 2.6758e-05, 0.11818], [0.97462, 0.02007, 0.005298])
>>> flasher.flash(P=1e5, VF=1, zs=zs).T
133.6
>>> flasher.flash(T=133, VF=0, zs=zs).P
518367.4
>>> flasher.flash(P=PT.P, H=PT.H(), zs=zs).T
110.0
>>> flasher.flash(P=PT.P, S=PT.S(), zs=zs).T
110.0
>>> flasher.flash(T=PT.T, H=PT.H(), zs=zs).T
110.0
>>> flasher.flash(T=PT.T, S=PT.S(), zs=zs).T
110.0

There is also a N-phase flash algorithm available, FlashVLN. There are no solid models implemented in this interface at this time.

Getting Started - Simple Interface

The library is designed around base SI units only for development convenience. All chemicals default to 298.15 K and 101325 Pa on creation, unless specified. All constant-properties are loaded on the creation of a Chemical instance.

>>> from thermo.chemical import Chemical
>>> tol = Chemical('toluene')
>>> tol.Tm, tol.Tb, tol.Tc
(179.2, 383.75, 591.75)
>>> tol.rho, tol.Cp, tol.k, tol.mu
(862.238, 1706.07, 0.13034, 0.0005522)

For pure species, the phase is easily identified, allowing for properties to be obtained without needing to specify the phase. However, the properties are also available in the hypothetical gas phase (when under the boiling point) and in the hypothetical liquid phase (when above the boiling point) as these properties are needed to evaluate mixture properties. Specify the phase of a property to be retrieved by appending 'l' or 'g' or 's' to the property.

>>> from thermo.chemical import Chemical
>>> tol = Chemical('toluene')
>>> tol.rhog, tol.Cpg, tol.kg, tol.mug
(4.0320096, 1126.553, 0.010736, 6.97332e-06)

Creating a chemical object involves identifying the appropriate chemical by name through a database, and retrieving all constant and temperature and pressure dependent coefficients from Pandas DataFrames - a ~1 ms process. To obtain properties at different conditions quickly, the method calculate has been implemented.

>>> tol.calculate(T=310, P=101325)
>>> tol.rho, tol.Cp, tol.k, tol.mu
(851.1582219886011, 1743.280497511088, 0.12705495902514785, 0.00048161578053599225)
>>> tol.calculate(310, 2E6)
>>> tol.rho, tol.Cp, tol.k, tol.mu
(852.7643604407997, 1743.280497511088, 0.12773606382684732, 0.0004894942399156052)

Each property is implemented through an independent object-oriented method, based on the classes TDependentProperty and TPDependentProperty to allow for shared methods of plotting, integrating, differentiating, solving, interpolating, sanity checking, and error handling. For example, to solve for the temperature at which the vapor pressure of toluene is 2 bar. For each property, as many methods of calculating or estimating it are included as possible. All methods can be visualized independently:

>>> Chemical('toluene').VaporPressure.solve_property(2E5)
409.5909115602903
>>> Chemical('toluene').SurfaceTension.plot_T_dependent_property()

Mixtures are supported and many mixing rules have been implemented. However, there is no error handling. Inputs as mole fractions (zs), mass fractions (ws), or volume fractions (Vfls or Vfgs) are supported. Some shortcuts are supported to predefined mixtures.

>>> from thermo.chemical import Mixture
>>> vodka = Mixture(['water', 'ethanol'], Vfls=[.6, .4], T=300, P=1E5)
>>> vodka.Prl,vodka.Prg
(35.13075699606542, 0.9822705235442692)
>>> air = Mixture('air', T=400, P=1e5)
>>> air.Cp
1013.7956176577836

Warning: The phase equilibria of Chemical and Mixture are not presently as rigorous as the other interface. The property model is not particularly consistent and uses a variety of ideal and Peng-Robinson methods together.

Latest source code

The latest development version of Thermo's sources can be obtained at

https://github.com/CalebBell/thermo

Bug reports

To report bugs, please use the Thermo's Bug Tracker at:

https://github.com/CalebBell/thermo/issues

License information

See LICENSE.txt for information on the terms & conditions for usage of this software, and a DISCLAIMER OF ALL WARRANTIES.

Although not required by the Thermo license, if it is convenient for you, please cite Thermo if used in your work. Please also consider contributing any changes you make back, and benefit the community.

Citation

To cite Thermo in publications use:

Caleb Bell and Contributors (2016-2023). Thermo: Chemical properties component of Chemical Engineering Design Library (ChEDL)
https://github.com/CalebBell/thermo.

thermo's People

Contributors

alex-s-v avatar alexchandel avatar andreasmatthias avatar calebbell avatar cintronej avatar cloasdata avatar marcosfelt avatar rorykurek avatar shimwell avatar tedhyu avatar tkeskita avatar volpatto avatar yoelcortes avatar

Stargazers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

Watchers

 avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar  avatar

thermo's Issues

Saturation pressure (& temperature) for mixtures

Dear @CalebBell ,

Thank you very much for such a great library! It makes my research work on PhD-thesis much easier!

I would like to ask you, if it is possible to calculate saturation temperature and pressure for binary mixtures using thermo? Are there any methods?
I tried to do it via 'eos_mix' module but it prints error (object has no attribute 'a') when I call 'Psat' method. I tried 'mixture' module, but it has corresponding methods for components only, but not for the mixture itself.
Thank you in advance!

Best regards,
Pavel

Thermo future development

Hello @CalebBell ,

thanks for your work on Thermo, Fluids and other Python chemical engineering libs! These seem to be exceptionally coherent, maintainable and good quality libraries, with literature references and nice documentation.

About roadmap: On README you mention phase equilibrium as your current main development item. Also, in the pull request #48 you mention about a development version which includes classes for Phase, Flasher and EquilibriumState.

  • What is the development status now and how are you going to continue?
  • I didn't find any development branches on github? Could you please start to use one so that it is possible to follow your progress?
  • I think there is potential to expand your libraries towards research applications, like small scale equipment simulations (starting with flash drums) and maybe minor flowsheeting. Are you interested in those?

About execution speed: I got the impression that you are concerned about speed. In my experience, access to clean but slow (hopefully also robust) methods is far better than access to no methods. Speedier alternative methods can always be provided afterwards, if there is time for development and code size remains manageable. Any comments on this?

Hope to hear about your current thoughts, thanks!

[bug] 'arsenic' has wrong Tc

Arsenic (CAS 7440-38-2) has a critical point of 1673 K, 22.3 MPa. However, thermo returns a Tc of 373 K:

import thermo
thermo.chemical.Chemical('arsenic').Tc  # == 373

Please fix this.

Add the Schmidt-Wenzel EOS

Ignoring alpha functions, this library has 3 EOS templates, VDW, RK, and PR.

The Schmidt-Wenzel equation of state improves on the fixed-Zc van der Waals, (Soave-)Redlich-Kwong, and Peng-Robinson equations, by allowing Zc to vary with Pitzer's ω. It has superior behavior near the critical point for all ω, and generally superior Tr behavior when customized with a modern alpha function.

To calculate only requires one additional step: the calculation of the molecule's β (reduced hard-ball volume) from ω, using the relation "(6ω+1)β³ + 3 β² + 3 β - 1 = 0", easily done via a cubic formula (note the root changes at (-1 + 2√2 / 3) & -1/6). From that follow the intermediate values "ζc = 1/(3 (1 + β ω)), Ωa = (1 - ζc(1 - β))³, Ωb = β ζc", and calculation proceeds as usual.

Note that SW reduces to (S)RK when ω = 0, and almost becomes PR when ω = 1/3.

Please add the Schmidt-Wenzel EOS.

EOS mix fails to calculate at different temperatures

I have been trying to play with the Nitrogen/ Methane example in your documentation. I see that changes in temperature lead to no result. Could you please help me in understanding the error and how it can be resolved. Below is the example code. It did work at T=115K, but did not work for T=200K.

import thermo as therm
crit_T = [126.2, 304.2, 373.2, 190.6]
crit_P = [3394387.5, 7376460.0, 8936865.0, 4600155.0]
w = [0.04, 0.225, 0.1, 0.008]
comp = [0.2, 0.0, 0.0, 0.8]
kij = [[0,0,0,0],[0,0,0,0],[0,0,0,0],[0,0,0,0]]
eos = therm.SRKMIX(T=200, P=1E6, Tcs=crit_T, Pcs=crit_P, omegas=w, zs=comp, kijs=kij)
print(eos.V_l, eos.fugacities_l)
print(eos.V_g, eos.fugacities_g)

Thermodynamic Properties of Solutions

First @CalebBell i'd like to thank you for this software. It's a life-saver!

How difficult would it be to update the Laliberte2009.tsv file with Glucose, Fructose and some other simple sugars? I realize that sucrose is added and that is currently what I am using but I would like to find out how much glucose and fructose there are seperately. Im not sure what the process is for adding other electrolytes or if you have a script that calculates the fitting parameters based off of some data.

I am looking at modelling glucose/fructose/ethanol/water systems and finding the density for a given concentration or more accurately use optimization to estimate the amount of glucose/fructose given a density.

Receive the following error when trying to calculate temperature from pressure and entropy

Traceback (most recent call last):
  File "/Users/RobMontgomery/Documents/Programming/workspace/ChillSeekers/Ejector.py", line 183, in <module>
    flow1, velocity_outlet = ejector.calculate_nozzle_outlet_flow(flow_throat, velocity_throat)
  File "/Users/RobMontgomery/Documents/Programming/workspace/ChillSeekers/Ejector.py", line 106, in calculate_nozzle_outlet_flow
    isoentropic_enthalpy_outlet = Chemical(self.medium, P=assumed_outlet_pressure, T=Chemical(self.medium).calculate_PS(assumed_outlet_pressure, nozzle_flow_entropy)).H
  File "/Users/RobMontgomery/anaconda3/lib/python3.6/site-packages/thermo/chemical.py", line 1107, in calculate_PS
    return newton(to_solve, self.T)
  File "/Users/RobMontgomery/anaconda3/lib/python3.6/site-packages/scipy/optimize/zeros.py", line 184, in newton
    raise RuntimeError(msg)
RuntimeError: Failed to converge after 50 iterations, value is 226.879055881

The code

	def calculate_nozzle_outlet_flow(self, nozzle_flow, velocity_throat):
		assumed_outlet_pressure = .2e6
	
		# Calculate Primary Flow Characteristics
		nozzle_flow_entropy = nozzle_flow.S
		nozzle_flow_enthalpy = nozzle_flow.H
		
		#Calculate flow rate
		mass_flow_nozzle = nozzle_flow.rho * self.nozzle_throat_area * velocity_throat
	
		iterator = 0
		primary_outlet_flow = None
		while True:
			# Calculate isoentropic enthalpies
			isoentropic_enthalpy_outlet = Chemical(self.medium, P=assumed_outlet_pressure, T=Chemical(self.medium).calculate_PS(assumed_outlet_pressure, nozzle_flow_entropy)).H
			# Determine real enthropy at nozzle
			real_enthalpy_outlet = nozzle_flow_enthalpy - (self.isoentropic_nozzle_efficiency * (nozzle_flow_enthalpy - isoentropic_enthalpy_outlet))
			# Calculate estimated speed of sound
			calculated_mach_velocity = (2 * (nozzle_flow_enthalpy - real_enthalpy_outlet + (velocity_throat ** 2) / 2)) ** 0.5
	
			# Calculate speed at outlet of nozzle based on known mass flow rate
			primary_outlet_temp = Chemical(self.medium).calculate_PH(assumed_outlet_pressure, real_enthalpy_outlet)
			primary_outlet_flow = Chemical(self.medium, T=primary_outlet_temp, P=assumed_outlet_pressure)
			pof = primary_outlet_flow
			
			assumed_outlet_rho = pof.rho
			thermo_velocity = mass_flow_nozzle / (self.nozzle_outlet_area * assumed_outlet_rho)
			
	
			print('Outlet thermodynamic speed is ', thermo_velocity)
			print('Outlet calculated speed is ', calculated_mach_velocity)
			if math.fabs(thermo_velocity - calculated_mach_velocity) <= 0.1:
				return primary_outlet_flow,thermo_velocity
				break
			else:
				assumed_outlet_pressure = assumed_outlet_pressure - 1000
				iterator += 1
				print(assumed_outlet_pressure)

Any clue what's going on here? I'm trying to perform an iterative conversion for use in a thermodynamic cycle. Thanks.

Enthaply and entropy for water

Hello,

I am struggling to retrieve enthalpy and entropy for water at a specific temperature + pressure. The image below is an example of the values I want.

image

Running the following code returns values that are different. Am I misunderstanding something?

from thermo.chemical import Chemical

w = Chemical('water')
w.calculate(T=300+273.15, P=300000)
print(w.H, w.S)

Returns
2965116.5084832604 7339.656559980439

how to define pseudo components ?

Is there any way to define the pseudo components in thermo? By pseduo components, I mean the petroleum cuts such as naphtha , gasoline , or c8 aromatics . Is there any way to define them based on boiling point . How to obtain their thermodynamic properties ? I appreciate any help very much.

Exteding the UNIFAC method to work with solid-liquid interactions?

Sorry if this sounds wonky, but I've found interaction parameters and r's and q's for cation anion interactions with themselves and Dortmund (https://www.sciencedirect.com/science/article/pii/S0378381212004426), and added them locally to work with some of the compounds i'm trying to explore for possible eutectic points (mostly ionic halides) and I was wondering if I would also need to modify the underlying equations to account for this because from what I read around, i'm not quite sure from what I see around the web (and my formal background doesn't extend much past E&M, some organic chem, and matsci)? I guess that what I'm asking amounts to what would the error bars would look like by excluding the middle range and long range interaction components used LIFAC?

Thank you

results for viscosity and density of water/glycol mix

1st off let me say thank you for working on this tool. This package adds huge functionality to the python library....

I was using the thermo package to evaluate solution properties of several water/glycol mixes, and the density, dynamic viscosity, and kinematic viscosity values seemed pretty far off.

here are the 3 solutions:

  • 30/70 [glycerol/water]
  • 50/50 [glycerol/water]
  • 70/30 [glycerol/water]

her is my code
`import numpy as np
import scipy.stats as st
import scipy as sp
import math
from thermo.chemical import Mixture
Mix1=Mixture(['glycerol','water'],ws=[0.3,0.7],T=20+273,P=101325)
Mix2=Mixture(['glycerol','water'],ws=[0.5,0.5],T=20+273,P=101325)
Mix3=Mixture(['glycerol','water'],ws=[0.7,0.3],T=20+273,P=101325)

print('''30/70 Solution\n Density={:.5}\n Viscosity={:.5}\n KinematicViscosity={:.5}
\n50/50 Solution\n Density={:.5}\n Viscosity={:.5}\n KinematicViscosity={:.5}
\n70/30 Solution\n Density={:.5}\n Viscosity={:.5}\n KinematicViscosity={:.5}\n\n'''.format(
Mix1.rho,Mix1.mu,Mix1.mu/Mix1.rho,
Mix2.rho,Mix2.mu,Mix2.mu/Mix2.rho,
Mix3.rho,Mix3.mu,Mix3.mu/Mix3.rho))`

however i think the values should be pretty different than the ones I'm getting. For example a 30/70 glycerol/water mix should have a much smaller density than a 70/30 glyceral water mix.

image

request for updated pypi package

The last release of thermo via the PyPi package manager pip was back in 2017 but I notice there have been another 15 or so commits since then.

Any chance the package on the pypi repository can be updated?

Henry's law constant

Hi,

I wonder if I can use your package to get Henry's law constant for gaseous species in water (or other systems).

Best,
Amin

Multi component enthalpic curve calculation

Hi,
I would like to generate enthalpic curves for a multi component mixture.

  1. My mixture is the mixing of a liquid flow and a gaz flow for which I know the composition, flow rate, temperature and pressure.
    -> can I get the mixing temperature + the vapor ratio at a given pressure of these two flows ?
  2. I managed to calculate the common properties and the latent heat for a set of températures and pressures with thermo.mixture but I need zs (mole fraction of all the components) as inlet parameters separately for the liquid part and for the gas part (they change with the temperature and pressure as the mixture is vaporized)
    -> how can I calculate these zs from the composition of my mixture and the T, P ?
    Last question : is it possible to evaluate the dew point of the mixture ?

If someone can drive me to a solution or even to a beginning of a track, it would be great…

Regards

Error on import

When importing thermo an rnning my program it works fine, however when I use pytest to test some of the functionality of my program it breaks while trying to import thermo.

Does anyone else have this problem

Screenshot from 2020-02-13 18-02-19

Water properties at low temperatures

Thank you very much for this package! I'm finding it very useful, but I'm seeing some unexpected results in the properties of water at low temperatures. In particular, fresh water at 1 atm is known to have a density maximum around 4C, with its density decreasing at both lower and higher temperatures. However, if I plot something like [thermo.Chemical('water', T=Ti).rhol for Ti in np.linspace(273.15, 373.15, 1000)], the returned density seems to be monotonically decreasing at all temperatures. Any thoughts?

how to find properties of industrial common mixtures

Mr. @CalebBell, good morning.
First I'd like to thank You for the very accurate libraries that you shared in these repositories. When I knew about "fluids" I immediately tried to use it because me too have my own "itches to scratch": in fact now, inside the workbench for FreeCAD that I'm developing, there is a small utility to calculate pressure losses of pipes drawn with that same tool (up to now: only for tubes+elbows and only for liquid water).
Beside that, my question is related to the properties of some very common fluids used in industry like kerosene or hydraulic oils (HLP or CLP for instance) which I didn't find neither in Chemical() nor in Mixture().
Is there a way to define a custom fluid table (.csv) so that I can create an object simply with kerosene=thermo.Mixture("kerosene") or oil=thermo.Chemical('HLP68')?
Thank You

Insufficient warning when an estimation method with low accuracy is used

Currently the library provides no warning when an estimation method is used to calculate a chemical property. This was exemplified in #3 , where glycerol has no accurate viscosity data at the time and the estimation methods Letsou_Stiel and Przedziecki_Sridhar worked terribly but without any warning.

It might be a good idea to provide a warning when an inaccurate estimation method is used, or to provide an overall description of the quality of the data for a chemical, or to attempt to quantify the error of a property.

It would be straightforward to generate a warning, using the warnings module, whenever a low-accuracy estimation method is called. However, how often should they be generated? If a plotting command is used and the estimation method is used repeatedly, generating a warning for each calculation would not be desirable. Furthermore, some caching is used to store chemical properties for future use. The caching layer does not know what method was used, and if it is accurate or not.

One more pain point - Many of the VDI PPDS coefficients are regressed from estimated data using the same methods used in the library. The same applies for what DIPPR data are available. Even the TRC ideal gas heat capacity database contains plenty of estimated data using the Benson method. None of these sources state which chemicals have estimated data and which do not. Some coefficient sources, such as the VDI PPDS coefficients, do not even have a temperature range specified, and definitely stop working at very low and very temperatures - some crude measurements based on properties derivatives are currently used to limit these coefficients.

The long-term solution is to do what NIST's Thermodynamics Research Center does - collect experimental data, regress coefficients, and estimate uncertainties based on that.

Considering the above, there is no obvious path for when to generate warnings. Please share any thoughts - use cases, issues when you were surprised by a low-accuracy datum, or other suggestions about providing warnings to the user here.

Data Loading/Storage

After reading #53, I couldn't agree with you more @CalebBell - this project is huge (in a great "lots of functionality" way but also definitely a pain to maintain way).

One thought as I was working on #60 was that loading the data with Pandas using text files might be slower than another storage option. A drop-in replacement would be to use pd.HDFStore - which can be compressed with several different options. A single compressed file could store native Pandas DataFrames (which is what you end up with after running pd.read_csv() anyway).

This would be relatively easy:

  • Pull the pd.read_csv() statements out into a "Make HDF" script
  • Write the HDF compressed datastore
  • Open the HDF store (preferably once, although I'm not entirely sure about the best way to share one instance across multiple modules....)
  • Access the data you want by the key set when you created it... (HDF has groups and can kinda simulate directory structure so the keys could be the stored filenames...

So, for example:

Tm_ON_data = pd.read_csv(os.path.join(folder, 'OpenNotebook Melting Points.tsv'),
sep='\t', index_col=0)

Would get moved to a make HDF script (see below) and replaced with something like:

#Preferably share this 
hdf = pd.HDFStore('data.h5', mode='r')
#..........

TM_ON_Data = hdf['/Phase_Change/OpenNotebook_Melting_Points']
# TM_ON_Data is now a pandas dataframe just like what's returned from pd.read_csv()

This would be a particularly good improvement if any data transformation/calculation can be/needs to be done after the data is read in by read_csv: that extra calculation/processing can be moved to the "make HDF" script and then only the useful/ready dataframe needs to be stored.

Making the HDF5 file is as simple as:

#multiple compressors available for complib
hdf = pd.HDFStore('hdfname.h5', mode='w', complib='blosc:zstd', complevel=9)

df = pd.read_csv(...)
#optional transformation
df = df.reindex(xyz)
hdf.append('/Phase/CRCPhaseTable1', df)

hdf.flush()
hdf.close()

I'm not 100% sure that it would be faster - intuitively it seems like yes (the decompression speeds are really high) ... it would for sure be smaller and easier to manage deployment (potentially one data file instead of many small ones). And if there's any post-read processing that can be done ... definitely would improve the load time on that step.

There could also be other ways to store the data - however, since you're already using Pandas, this would be a 1:1 swapout since pd.HDFStore stores native Pandas DataFrames 😁

Creating instance of Chemical('helium') throws error

>>> thermo.chemical.Chemical('helium')
Traceback (most recent call last):
  File "<stdin>", line 1, in <module>
  File "/home/kurt/.anaconda3/lib/python3.5/site-packages/thermo/chemical.py", line 122, in __init__
    self.set_ref()
  File "/home/kurt/.anaconda3/lib/python3.5/site-packages/thermo/chemical.py", line 503, in set_ref
    self.H_int_l_Tm_to_Tb = integrators['l'](self.Tm, self.Tb)
  File "/home/kurt/.anaconda3/lib/python3.5/site-packages/thermo/utils.py", line 1630, in T_dependent_property_integral
    sorted_valid_methods = self.select_valid_methods(T1)
  File "/home/kurt/.anaconda3/lib/python3.5/site-packages/thermo/utils.py", line 1186, in select_valid_methods
    if self.test_method_validity(T, method):
  File "/home/kurt/.anaconda3/lib/python3.5/site-packages/thermo/heat_capacity.py", line 1253, in test_method_validity
    if T <= self.CP_f.Tt or T >= self.CP_f.Tc:
TypeError: unorderable types: NoneType() <= float()

Error in mixture properties

Caleb
Your efforts in producing Thermo is much appreciated. However, it appears that there is an error in your method for calculating the properties of a gas mixture. If I use a mixture and N2 & H2O of 0.9 & 0.1 as mol fractions and a total pressure of 100kPa then I find that there a dramatic drop in enthalpy at approx. 100degC to a level which is somewhat higher than N2 only. Dalton's law of partial pressures says that water should start to condense at 45.8C. Further cooling would reduce the vapour fraction of H2O along the saturation line.

Kind regards
Allan

tabulate_solid generates an exception

import thermo
from thermo.chemical import Chemical

H2 = Chemical('hydrogen')
thermo.datasheet.tabulate_solid(H2.CAS)

generates an exception


Exception Traceback (most recent call last)
in ()
3
4 H2 = Chemical('hydrogen')
----> 5 thermo.datasheet.tabulate_solid(H2.CAS)

2 frames
/usr/local/lib/python3.6/dist-packages/thermo/datasheet.py in tabulate_solid(chemical, Tmin, Tmax, pts)
49 Ts = np.linspace(Tmin, Tmax, pts)
50 for T in Ts:
---> 51 chem = Chemical(chemical, T=T)
52 rhos.append(chem.rhos)
53 Cps.append(chem.Cps)

/usr/local/lib/python3.6/dist-packages/thermo/chemical.py in init(self, ID, T, P)
554 if self.CAS in _chemical_cache and caching:
555 self.dict.update(_chemical_cache[self.CAS].dict)
--> 556 self.calculate(T, P)
557 else:
558 if not isinstance(ID, dict):

/usr/local/lib/python3.6/dist-packages/thermo/chemical.py in calculate(self, T, P)
587 if T:
588 if T < 0:
--> 589 raise Exception('Negative value specified for Chemical temperature - aborting!')
590 self.T = T
591 if P:

Exception: Negative value specified for Chemical temperature - aborting!

Incorrect Prandtl numbers

I'm not sure if this is worthy of an issue or not; however, as I'm comparing the results to numerous chemicals, I'm presented with incorrect Prandtl number values. For example:

co2 = Chemical('carbon dioxide')
co2.calculate(T=50+273, P=101325)
co2.Pr
0.6482332387082907
Expected to get 0.7520
co = Chemical('carbon monoxide')
co.calculate(T=50+273, P=101325)
co.Pr
0.696779328644075
Expected to get 0.7328
h2 = Chemical('hydrogen')
h2.calculate(T=50+273, P=101325)
h2.Pr
0.7689021940555787
Expected to get 0.7191
n2 = Chemical('nitrogen')
n2.calculate(T=50+273, P=101325)
n2.Pr
0.6687213666959588
Expected to get 0.7114
o2 = Chemical('oxygen')
o2.calculate(T=50+273, P=101325)
o2.Pr
0.6781361087948815
Expected to get 0.7053

... and, so on. I'm curious of the expected accuracy of these values. I admit, I'm simply looking these Prandtl numbers in textbook tables; however, several textbooks all show nearly the same values. Thanks for any input/insight you may provide.

Calculate_PH

Caleb

Are you able to give an example of how to calculate T given P & H?

Regards

Allan

Missing solid properties of normally gaseous elements

Hydrogen freezes at 13.99 K, oxygen at 54.36 K. However, thermo.chemical.Chemical('Hydrogen', 13).Vms or thermo.chemical.Chemical('Oxygen', 54).Vms produce no values.

Although nonmetals have multiple solid allotropes, thermo could give properties for at least the lowest-pressure molecular solids, from correlations and more phase data.

Add adiabatic flash calculation

thermo's mixture class must be constructed with a known T & P.

However, an extremely common problem is to calculate a vapor-liquid mixture's properties after an adiabatic flash. That is, beginning with a known initial vessel volume, temperature, & out-of-equilibrium vapor & liquid numbers, calculate the equilibrium point by flashing or condensing material & lowering or raising the temperature accordingly.

The is the most common VLE problem is dynamic processes. thermo should have a "vessel" class to perform this. (As a flash calculation requires looping & inversion, it would benefit enormously from numpy & scipy, and could be provided in a numpy extension package to thermo.

Error calculating Joule-Thomson coef for mixture class

Hello everyone, I've attempted to use thermo to do some calculation on gas mixtures. And apparently it does work correctly for the Mixture.JT. Even if I type in the example code, it still returns None, e.g. Mixture(['water'], ws=[1]).JT
Mixture(['dodecane'], ws=[1], T=400, P=1000).JTg.

python setup.py develop not working

Just wanted to put this out there in case anyone else wants to install the package using "develop" mode which is useful when making changes to the source code and not having to reinstall it to see the impact on the package.

python setup.py develop

currently returns an error

Screenshot from 2020-02-14 10-26-24

There is an easy to fix if you want to use it in this way.

In setup.py replace the line

from distutils.core import setup

with

from setuptools import setup

This is the recommended solution for another package with the same issue from django-extensions/django-extensions#92 (comment)

Error in water Cp

There seems to be an error in class-handling as instances are clearly not independent. When repeating calculation of Cp of water for example, the same command gives different results:

image

The first is correct, the second and third clearly not!

Data Issue CAS 13465-78-6

Hi, how can i fix data issue for chlorosilane's atoms and MW?
Actual chemical formula is SiH3Cl, but I got

Chemical('13465-78-6').atoms
{'Cl': 1, 'Si': 1}
it should be {'Cl': 1, 'Si': 1, 'H': 3}
Chemical('13465-78-6').MW
63.5385
but it should be 66.56 (three hydrogens are lost)
Chemical('13465-78-6').Tb
242.75
this is right

And another question. What is the best way to inject missing property to thermo?
Is this the right way?

Chemical('13465-78-6').H_ref = value

Chemical('CO') returns Methanol instead of Carbon Monoxide

Hello there,
First of all, thanks for your great work, I just stumbled over this great package recently.
Unfortunately I observed some strange behaviour, when I tried to create a Chemical object for Carbon Monoxide.

minimal example to reproduce the bug:

from thermo import Chemical

CO = Chemical('CO')
print(CO.name)

From my observations the wrong chemical is picked in the module identifiers.py in the smiles lookup (Line 487):

    # Try the smiles lookup anyway
    # Parsing SMILES is an option, but this is faster
    # Pybel API also prints messages to console on failure
    smiles_lookup = pubchem_db.search_smiles(ID, autoload)
    if smiles_lookup:
        return smiles_lookup.CASs

This returns Methanol instead of Carbon Monoxide.

Strange Cp values for Helium

When trying to calculate Cp for helium near STP, I'm getting 1.5931 J/(Kg), which conflicts with several tabulated values of about 5.193 J/(Kg). Here's the code I'm using:

N2 = therm.Chemical('n2',T=293.15)
He = therm.Chemical('helium',T=293.15)
Ar = therm.Chemical('argon',T=293.15)
Cp = np.array([N2.Cpg/1000,He.Cpg/1000,Ar.Cpg/1000])

Gas mixture properties

Hi
I trying to work out how to calculate thermodynamic and transport properties of a gas mixture and am struggling to understand how to do this. The main properties required and h in kJ/kg, Cp in kJ/kgK, mu in Pa.s and k in W/m.K. Are you able to present an example?

Regards

[bug] "bromine" resolves to wrong CAS

Bromine's critical point is 588 K, 10.34 MPa. However the following returns None and None:

import thermo
b = thermo.chemical.Chemical('Bromine')
b.Tc
b.Pc

This is because Chemical('Bromine') seems to resolve to CAS 10097-32-2, the bromine radical. However the CAS number for dibromine is 7726-95-6.

The problem even exists in thermo's periodic table:

thermo.elements.element_list[35 - 1].CAS  # == '10097-32-2'

Please update this name resolution.

Thermodynamic data missing for Fe2O3 chemical

I am trying to use Fe2O3 in some of my thermodynamic calculations using 'thermo.chemical', but was unable to call it from the chemical database. I have used both methods shown below:

from thermo.chemical import Chemical
Fe2O3 = Chemical("Fe2O3") # Using chemical formula name
# OR
Fe2O3 = Chemical("1317-60-8") # Using the CAS ID from PubChem

Method 1 returned the following error:

---------------------------------------------------------------------------
KeyError                                  Traceback (most recent call last)
<ipython-input-12-872c9ccce381> in <module>()
----> 1 Fe2O3 = Chemical("Fe2O3")

C:\ProgramData\Anaconda3\lib\site-packages\thermo\chemical.py in __init__(self, ID, T, P)
    392             self.calculate(T, P)
    393         else:
--> 394             self.PubChem = PubChem(self.CAS)
    395             self.MW = MW(self.CAS)
    396             self.formula = formula(self.CAS)

C:\ProgramData\Anaconda3\lib\site-packages\thermo\identifiers.py in PubChem(CASRN)
    239 
    240     '''
--> 241     pubchem = pubchem_dict[CASRN]['Pubchem ID']
    242     return pubchem
    243 

KeyError: None

Method 2 returned a "none" for every property I tried.
Please, will you help me?

Incompatibility with Scipy 1.0.0

Hi,

For some reason the thermo package doesn't work when the Scipy library is upgraded. In my case I tried to upgrade it from 0.18.1 to 1.0.0; causing thermo to crash.

Here I paste the error I'm getting:

from thermo import chemical /Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/matplotlib/font_manager.py:273: UserWarning: Matplotlib is building the font cache using fc-list. This may take a moment. warnings.warn('Matplotlib is building the font cache using fc-list. This may take a moment.') Traceback (most recent call last): File "<stdin>", line 1, in <module> File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/thermo/__init__.py", line 25, in <module> from . import chemical File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/thermo/chemical.py", line 42, in <module> from thermo.viscosity import ViscosityLiquid, ViscosityGas, ViscosityLiquidMixture, ViscosityGasMixture, viscosity_index File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/thermo/viscosity.py", line 2359, in <module> viscosity_converters_to_nu[key] = UnivariateSpline(values, nus, k=3, s=0) File "/Library/Frameworks/Python.framework/Versions/2.7/lib/python2.7/site-packages/scipy/interpolate/fitpack2.py", line 176, in __init__ raise ValueError('x must be strictly increasing') ValueError: x must be strictly increasing

I solved the error by using pip and reinstalling Scipy 0.18.1:

pip install scipy==0.18.1

Does anyone know a better solution than using an old version of the library?

Thank you in advance,
Andreu

Heat capacity calculations "get stuck" after phase change

Hi

I'm likely missing something. It seems that even though a new Chemical object is created each time, as soon as the relevant chemical undergoes a phase change, heat capacity calculations get "stuck".

In [1]: from thermo import Chemical

In [2]: Chemical('water', T=320).Cpl
Out[2]: 4177.518996988284

In [3]: Chemical('water', T=-2+273.15).Cpl  # Cpl is a bit nonsensical at this T, but so what
Out[3]: 1687.9369348841108

In [4]: Chemical('water', T=320).Cpl  # now Cpl is different compared to the first calculation
Out[4]: 1891.2006096310665

I did not expect the second calculation at T=320 to give that answer, since each Chemical is a new object?

Where I can find the binary interaction parameters

Hi CalebBell,

Where is your binary interaction parameters databank, I just found this in your code, are they generated by the code? I know Aspen and ProII have a lot binary parameters, so just confused about this.

if kijs is None: kijs = [[0]*self.N for i in range(self.N)] self.kijs = kijs

adding atoms labels to draw_3d function

to draw_3d function, add one variable, atomlabel, which defaults to true.

def draw_3d(self, width=300, height=500, style='stick', Hs=True, atomlabel=True):

then just before p.zoomTo(), add this code

            if atomlabel:
                p.addPropertyLabels("atom","","")

Atoms labels will then display, which is nice for people like me which are not chemical engineers!
This works with latest (python 3.7.3) conda installed version of thermo and py3Dmol from conda-forge.
xylene

Licenses/copyright status for data sources

Hi Caleb,

I was wondering if there's a specific way you've documented the license or copyright status of the various tables in thermo? Looking through the modules, there's a lot of tsvs that get imported, but I'm not clear on what's required of me if I duplicate those in other projects (or if I'm allowed to in the first place).

Thanks,

Adam

Data issue: CAS# 16949-15-8

Hi,

It looks like the data for CAS# 16949-15-8 is not correct. As this shows, CAS# 16949-15-8 is LiBH4, but I got the following output. It looks like the hydrogens are dropped incorrectly.

>>> a=thermo.chemical.Chemical('16949-15-8')
>>> a.smiles
'[Li+].[B-]'
>>> a.rho
537.840616966581

Thanks

Chemical don't import heat of formation

Chemical don't import heat of formation . Can it be a bug? Can someone, please, help me?

thermo==0.1.39

from thermo.chemical import Chemical
thermo.datasheet.tabulate_constants('NH3',full=True)

or

NH3 = Chemical("7664-41-7")
print NH3.Hf

answer > None

This happens for other cases like N2, H2!

But in local/lib/python2.7/site-packages/thermo/Heat\ Capacity/TRC\ Thermodynamics\ of\ Organic\ Compounds\ in\ the\ Gas\ State.tsv

we can see:

"CAS Chemical Hfc Gfc Sc Cpc Hfl Gfl Sfl Cpl Hfg Gfg Sfg Cpg"
"7664-41-7 Ammonia -45900 -16400 192.8 35.1"

For instance
Chemical('Toluene').Hf
answer > 50170.0

That is quite correct because NIST Webbook lists
ΔfH°gas | 50.1 ± 1.1 | kJ/mol | Review | Roux, Temprado, et al., 2008 | There are sufficient high-quality literature values to make a good evaluation with a high degree of confidence. In general, the evaluated uncertainty limits are on the order of (0.5 to 2.5) kJ/mol.;D.R. Burgess.

But in local/lib/python2.7/site-packages/thermo/Heat\ Capacity/TRC\ Thermodynamics\ of\ Organic\ Compounds\ in\ the\ Gas\ State.tsv
"CASRN Chemical Tmin Tmax a0 a1 a2 a3 a4 a5 a6 a7 I J Hf"
"108-88-3 Toluene 12400 157.3 50500"

and in local/lib/python2.7/site-packages/thermo/Heat\ Capacity/CRC\ Standard\ Thermodynamic\ Properties\ of\ Chemical\ Substances.tsv
"CAS Chemical Hfc Gfc Sc Cpc Hfl Gfl Sfl Cpl Hfg Gfg Sfg Cpg"
"108-88-3 Methylbenzene 50 1500 4 87000 204 34.095 17.743 -35740000 209 71 15.7 10.67 73300"

Filipe Gama Freire

Recommend Projects

  • React photo React

    A declarative, efficient, and flexible JavaScript library for building user interfaces.

  • Vue.js photo Vue.js

    🖖 Vue.js is a progressive, incrementally-adoptable JavaScript framework for building UI on the web.

  • Typescript photo Typescript

    TypeScript is a superset of JavaScript that compiles to clean JavaScript output.

  • TensorFlow photo TensorFlow

    An Open Source Machine Learning Framework for Everyone

  • Django photo Django

    The Web framework for perfectionists with deadlines.

  • D3 photo D3

    Bring data to life with SVG, Canvas and HTML. 📊📈🎉

Recommend Topics

  • javascript

    JavaScript (JS) is a lightweight interpreted programming language with first-class functions.

  • web

    Some thing interesting about web. New door for the world.

  • server

    A server is a program made to process requests and deliver data to clients.

  • Machine learning

    Machine learning is a way of modeling and interpreting data that allows a piece of software to respond intelligently.

  • Game

    Some thing interesting about game, make everyone happy.

Recommend Org

  • Facebook photo Facebook

    We are working to build community through open source technology. NB: members must have two-factor auth.

  • Microsoft photo Microsoft

    Open source projects and samples from Microsoft.

  • Google photo Google

    Google ❤️ Open Source for everyone.

  • D3 photo D3

    Data-Driven Documents codes.