Replies: 25 comments
-
Hi Bernt, happy to see you using Clapeyron! That's a lot of questions which I'll try to answer. One thing I'll mention is that we have more-detailed docs which can be found here: https://clapeyronthermo.github.io/Clapeyron.jl/dev/
where Sorry these replies are brief. Let me know if there's anything you'd like to follow-up on. |
Beta Was this translation helpful? Give feedback.
-
I'm not sure this will not work in the case of chemical reactions. OK -- it may work, but then I have to manually add a "heat of reaction". I tried to look at the |
Beta Was this translation helpful? Give feedback.
-
@pw0908 and @longemen3000 In practice, I know:
First thing, I want to know the pressure using Clapeyron
model_a_pr = PR(["water", "oxygen"])
V_a = 1 # m3
T = 273.15 + 60 # K
p_a = 1.2e5 # Pa, 1.2 bar
n_H2O_a = 1.85e4 # mol H2O
n_O2_a = 24.08 # mol O2 I have indicated an "intended pressure" of 1.2 bar. Here is what I find using julia> pressure(model_a_pr, V_a, T, [n_H2O_a, n_O2_a])
-1.237421762869517e8 This is, of course, a physically impossible pressure. My suspicion is that the data I gave are not realistic/compatible with the PR EoS. The amounts I have specified are based on steady state assumptions of a dynamic model where I have assumed that water is pure liquid and oxygen is an ideal gas. If I reduce the amounts to 19.135% of what I specify above, I get more or less the assumed pressure... OK -- if I don't care about computing the pressure (not doable in practice, but let me assume so). Then I get: julia> sol_fl = tp_flash(model_a_pr, p_a, T, [n_H2O_a,n_O2_a]);
julia> sol_fl[1]
2×2 Matrix{Float64}:
0.999994 5.93641e-6
0.151313 0.848687 Here, I understand the first column is for the first component, i.e., water, and the second column is for oxygen. Furthermore, the first row must be liquid phase, and the second must be vapor/gas phase? Next, julia> sol_fl[2]
2×2 Matrix{Float64}:
18495.7 0.109799
4.27365 23.9702
julia> sum(sol_fl[2], dims=1)
1×2 Matrix{Float64}:
18500.0 24.08 OK -- summing over the rows gives back the amounts I provide, which is reassuring. Question: Is there (or is it possible to create) a flash algorithm which uses:
Would this be "VT flash"? See https://link.springer.com/chapter/10.1007/978-3-031-49432-1_5 for some work on this with Julia. See also https://www.sciencedirect.com/science/article/pii/S0021999122003370 . |
Beta Was this translation helpful? Give feedback.
-
Yes, this corresponds to a Volume-Temperature flash. I've been developing an algorithm for general flashes (any combination of P-V-T-H-S-U-gas fraction). In particular, the flash in volume-temperature specification can be used via the model_a_pr = PR(["water", "oxygen"])
V_a = 1 # m3
T = 273.15 + 60 # K
p_a = 1.2e5 # Pa, 1.2 bar
n_H2O_a = 1.85e4 # mol H2O
n_O2_a = 24.08 # mol O2
sol_fl = vt_flash(model_a_pr, V_a, T, [n_H2O_a, n_O2_a])
volume(sol_fl) - V_a #to test if the result is correct that should result in the following: julia> sol_fl = vt_flash(model_a_pr, V_a, T, [n_H2O_a, n_O2_a])
Flash result at T = 333.15, p = 1.29611e5 with 2 phases:
(x = [0.999994, 6.4949e-6], β = 18496.2, v = 2.19268e-5)
(x = [0.140186, 0.859814], β = 27.8663, v = 0.0213318)
julia> volume(sol_fl) - V_a
9.818812429784884e-13
julia> pressure(sol_fl)
129610.55274230446 |
Beta Was this translation helpful? Give feedback.
-
Looks great! A question...
Reason for my question: a PhD student will take a course in the spring of 2025 where one possibility is to use VT flash. She will do it within a dynamic model, so she may have to develop a surrogate/proxy model to avoid costly implicit computations. |
Beta Was this translation helpful? Give feedback.
-
One more comment on partial molar properties... I've given it some thought. Essentially, you already compute the chemical potential, which is equal to the partial molar Gibb's energy. What about the other ones? In wikipedia (https://en.wikipedia.org/wiki/Partial_molar_property) I found the following relations between partial molar properties, which are linear if These three relations relate 6 partial molar properties: partial molar Gibbs energy We already know partial molar Gibbs energy = chemical potential. So we need two more partial molar properties in order to compute all of them. I found a book by Reinhard Hentschke where it is referred to a Gibbs-Helmholtz relation: Similarly, the book suggests that: Thus, to find partial molar enthalpy, if Computing partial internal energy is perhaps more tricky, because that one assumes that the chemical potential is a function of V,T. But perhaps do-able? If both partial molar enthalpy and partial molar internal energy can computed -- in addition to partial molar Gibbs energy = chemical potential, then all 6 partial molar properties should be available. OK -- a big caveat: I am no thermo expert, so I may be wrong :-o . |
Beta Was this translation helpful? Give feedback.
-
We can release a new version with partial properties and the fixed VT flash sometime next week. on testing, we always welcome tests submitted as issues with an MVE. for example, all the reported errors in #325 were added as tests. On partial properties, in fact, we have the opposite problem, all our inner problems are in V-T space, so we have to transform all partial problems into a V-T formulation first. in particular, for a particular function That relation is general (for example, one can calculate partial isobaric heat capacities), but takes more evaluations (two gradients + 1 dpdV + 1 dFdV), so alternative, faster forms are always good to add |
Beta Was this translation helpful? Give feedback.
-
This sounds great!! Ah yes. You base the computations on the Helmholtz energy with variables V,T. [My understanding is that the reason for this is that the involved integrals are much simpler with V,T as variables -- e.g., with cubic EoS, the model is explicit in p with V,T as variables, while they are implicit cubic in V with p,T as variables.] I look forward to the release!!! and will check it out [I have a research report due on January 31, 2025, so perhaps a little slow prior to that]. A few things I'm curious about:
OK -- I'll try to figure out how to use the functions with ModelingToolkit.jl, too. I'm trying to get in touch with the ProcessSimulator.jl people (whom I know a little bit), to learn how they are doing things. Computation time is an issue, of course. Some 25 years ago, I did some work on water-ethanol distillation, with an implicit equilibrium model (azeotropic) which I solved for each time step using a Newton solver. I also tried to solve the equilibrium conditions off-line, and fitted an explicit polynomial function to the data. Using the explicit polynomial to do the equilibrium computations speeded up the simulation time by a factor of 100. Conceptually, I could do something similar here, but it is much more demanding to fit an explicit function when multiple components (water, oxygen, etc.) are involved because the space is much larger. |
Beta Was this translation helpful? Give feedback.
-
@longemen3000 I'm curious as to how wrong results I get... NOTE: I assumed water is spread with substantial amounts in liquid and gas phases (Antoine's law), but that the ideal gases essentially are found in the gas phase. I would need to add some Henry's law constants to compute the (assumed) minor fraction of the ideal gases in the liquid phase... Here is my code: # Water saturation pressure
function p_H2O_sat(T)
A_H2O = 5.11564
B_H2O = 1687.537
C_H2O = 230.17
p_o = 1e5 # Pa
p_sat = p_o*10^(A_H2O - B_H2O/(C_H2O + T - 273.15))
return p_sat
end
#
function my_VT_flash(V,T,n)
R = 8.31 # J/K/mol
ρ_H2O_ℓ = 1e3 # kg/m3
M_H2O = 18e-3 # kg/mol
#
p_H2O = p_H2O_sat(T)
n_H2O = n[1]
n_ig = n[2:end]
#
V_ℓ = (n_H2O - p_H2O*V/(R*T))/(ρ_H2O_ℓ/M_H2O - p_H2O/(R*T))
V_g = V - V_ℓ
p_ig = n_ig*R*T/V_g
p = p_H2O + sum(p_ig)
n_H2O_ℓ = V_ℓ*ρ_H2O_ℓ/M_H2O
n_H2O_g = n_H2O - n_H2O_ℓ
return V_ℓ, V_g, [p_H2O;p_ig], p, n_H2O_ℓ, n_H2O_g
end My case is the following: V = 1 # m3
T = 70 + 273.15 # K
n_H2O = 1.85e4
n_O2 = 24.08 When running the code, I get: julia> V_L, V_G, p_vec, p, n_H2O_L, n_H2O_G = my_VT_flash(V, T, [n_H2O,n_O2]);
julia> V_L, V_G, V_L+V_G
(0.33286874943117706, 0.6671312505688229, 1.0)
julia> p_vec, sum(p_vec), p
([31167.53323759674, 102927.21568874586], 134094.74892634258, 134094.74892634258)
julia> n_H2O_L, n_H2O_G, n_H2O_L + n_H2O_G, n_H2O
(18492.70830173206, 7.291698267941683, 18500.0, 18500.0)
julia> p_vec/p
2-element Vector{Float64}:
0.23242918523764772
0.7675708147623524 Let me know when I can compare my results with a proper VT flash algorithm :-) |
Beta Was this translation helpful? Give feedback.
-
curiously, i got really close results if i use the GERG-2008 reference equation (for natural gas):
|
Beta Was this translation helpful? Give feedback.
-
Interesting. Looking forward to test your code more fully and comparing it to mine!! (I know mine is crude, but there is no iteration involved) |
Beta Was this translation helpful? Give feedback.
-
It does make sense, in those combinations of temperature-pressure, a really good approximation is supposing there is no dissolved gas. |
Beta Was this translation helpful? Give feedback.
-
In developing my code, I assumed partial pressure of water given by Antoine's law. All other gases were assumed to follow ideal gas law. I then assumed that, by definition, partial pressures are given as mole fraction multiplied by total pressure (is this a definition, or does it assume ideal solution?). To my surprise, it follows that water vapor also behaves like ideal gas... Is that because all other gases are ideal gases, or is it because my definition of partial pressure only is valid for ideal gas?? Just curious... |
Beta Was this translation helpful? Give feedback.
-
I'm trying to guess the interpretation of the result...
Apart from this, any particular recommendation about which EoS to use? Did you choose |
Beta Was this translation helpful? Give feedback.
-
Yes, you are correct. there are a lot of convenience functions to access the result ( On the model selection, i selected GERG2008 just for their good reproduction of water properties (volume + saturation pressures) in conjunction with good properties for the gases + adequate extrapolation at moderate conditions (i could be wrong in this last one, but weak interactions between water + gases don't require additional parameters). the main disadvantage of the model is that it takes more time to solve than a cubic (around 10x). so there are tradeoff between model accuracy and computational time. Of course, model selection is a whole area of research of its own. If i understand correctly, for this particular application, you require good reproductions of saturation pressures + volumes, so probably a SAFT could be a good option if you want predictive properties. In particular, |
Beta Was this translation helpful? Give feedback.
-
I have tried MissingException: Missing values exist ∈ single parameter groups: ["oxygen"].
Stacktrace:
[1] SingleMissingError(param::Clapeyron.SingleParameter; all::Any)
@ Clapeyron C:\Users\Bernt\.julia\packages\Clapeyron\2fEkA\src\database\database_rawparam.jl:360
[2] SingleMissingError(param::Clapeyron.SingleParameter)
@ Clapeyron C:\Users\Bernt\.julia\packages\Clapeyron\2fEkA\src\database\database_rawparam.jl:353
[3] is_valid_param(param::Clapeyron.SingleParameter, options::Any)
.... It seems like |
Beta Was this translation helpful? Give feedback.
-
VTPR does have translation, but it also requires UNIFAC parameters. For this particular case, i was thinking along the lines of |
Beta Was this translation helpful? Give feedback.
-
... gives error The two other SAFT models took much longer time to solve than the cubic equations. I'll try to do the computations for various EoS over a range of temperatures tomorrow + compare them + compare to my crude algorithm tomorrow, and report back. |
Beta Was this translation helpful? Give feedback.
-
Some results... Models I tested: Here, It is interesting to see how long time it takes to solve flash the first time (including JIT compilation): My simple function is by far the fastest initially (can be further improved). Cubics and GERG2008 are similar. The SAFT models are quite slow. However, when I do flash for 72 temperatures between 15-95 C, things change and flash time is much more similar. One observation: GERG2008 fails for most temperatures (either computing one phase, or getting NaN). Cubic EoS fails for some temperatures. Some results (I skipped GERG2008 because it failed a lot): Note that PCSAFT and pharmaPCSAFT give identical (seemingly) results. I'm curious as to what conclusions can be drawn wrt. which method is best... Not my simple algorithm, I think, although in many of the plots it gives a result quite similar to PCPSAFT. I can probably speed my simple algorithm up a little bit, but I'm not a super programmer... |
Beta Was this translation helpful? Give feedback.
-
Interesting observations indeed, some notes:
|
Beta Was this translation helpful? Give feedback.
-
OK. I can test For my own routine, I returned the results in an array -- I didn't spend time trying to figure out the data structure of Clapeyron -- essentially, I made the call as similar as possible to Clapeyron's |
Beta Was this translation helpful? Give feedback.
-
OK... I added the Here is one result: With this way of measuring computational time, my simple-minded algorithm really is much faster than iterative flash -- which is what I would have expected. I don't know which of the methods is the faster one, but I could probably tune my model as follows:
So -- I'm curious of your thoughts. [Btw: I measure Gerg2008 to be 23_000 times slower than my simple-minded algorithm.] |
Beta Was this translation helpful? Give feedback.
-
In those conditions, i think the best model is a combination of:
|
Beta Was this translation helpful? Give feedback.
-
Thanks a lot for quick responses and constructive inputs. I am super impressed by Clapeyron.jl and the work you guys are doing. I'm sure Clapeyron.jl could be a backbone for a Thermodynamics course, and make such courses much more concrete than they typically are. Also, for me -- even if I may end up using my super simple flash algorithm in my particular case (dynamic models solution via ModelingToolkit.jl), I could not have felt confident in it had it not been that Clapeyron.jl gives similar results for much more rigorous models. And I will, of course, also see if I can make the dynamic simulations work also with, say, one of the Clapeyron.jl routines. One more question + a final comment for now.
|
Beta Was this translation helpful? Give feedback.
-
Hello, The sources i checked (Perry, Abbott & Van Ness) define partial pressure as yᵢ*p. This definition follows the criteria of sum(p_i) = p only for the case of ideal gases (dalton's law). I couldn't find any working equation to define partial pressures on real gases using the definition of partial property (a partial property is defined at constant pressure, making dp/dn |p = p0 a constant with zero derivative). There are some alternative definitions, but none convince me for the specific context of partial properties. Just to note, i'm looking at a partial pressure strictly as a definition of partial property, that is:
For equilibria in general, the correct way is to work in terms of fugacities. partial pressures only appear when supposing that one of the phases is an ideal gas. |
Beta Was this translation helpful? Give feedback.
-
OK -- I'm not a thermodynamics expert, and perhaps my questions are "stupid". But I'm genuinely considering how I can use
Clapeyron.jl
in my work. So I hope the questions are not too out-of-place.0. Preliminaries: two models
Water, Peng-Robinson, and a mixture of hydrogen, oxygen and water appearing in Fuel Cell models and Water electrolysis.
First tests:
Question: Why is the volume not found to be
30e-3
???OK -- what if I do:
Observations:
:liquid
, the volume is the same as with the default phase.:gas
, the volume is the same (more or less) as the volume specified when computing the pressure:liquid
for a 5 times larger pressure, the (liquid) volume barely changes.Questions: I'm confused. The "base case" is more or less water at 100C and 1 atm pressure.
:gas
, where I do get back the volume that was used to compute the pressure?1. Flash
In electrolysis of water to produce hydrogen, it is necessary to have two separation tanks: one for separating water and oxygen, and one for separating water and hydrogen. Both tanks will also be "cross-polluted", thus the tank with water and oxygen also contains traces of hydrogen, and the one with water and hydrogen contains traces of oxygen.
In a first attempt, I assume that the water is completely in water phase (temperature ca. 80C, pressures > 1 bar), and that there is no dissolution of the gases + they obey the ideal gas law. This allows me to compute the water volume, and then the gas volume in the tank. The partial pressures of the gases can be computed from the ideal gas law. I then "cheat" and add the saturation pressure of water ("cheat" in the sense that that probably means that there is water in the gas volume).
I need a more accurate model where I take into account dissolved gases in the liquid phase. At the outset, I know:
Question: How can I compute the flash using
Clapeyron.jl
so that I can find:First ideas
pressure()
,2. Reaction equilibrium
I need to compute Gibb's (partial?/molar?) energy in order to find the so-called Nernst (equilibrium) voltage for a water Fuel Cell (or: water Electrolysis, which is the reverse).
Consider the reaction [preview doesn't work for LaTeX math...]:
H2 + 0.5 O2 -> H2O
Assuming water is the product, the stoichiometric vector is
nu = [-1, -1/2, +1]
where the components are ordered as ["hydrogen", "oxygen", "water"].
In Fuel Cell applications, hydrogen and oxygen are available at two different electrodes (anode and cathode, respectively) separated by a membrane. Water is produced at the oxygen side (cathode), and thus is present in a mixture of oxygen and water.
On the hydrogen side (anode), water vapor is also normally added to ensure that the membrane doesn't become dry. But water does not participate in the reaction on the anode side.
Gibb's (molar) energy of reaction is:
where in my notation, G with tilde on top and subscript j is partial (or: molar?) Gibbs' (free) energy, which equals chemical potential mu_j [when p and T are input arguments].
In electro-chemistry, it is common to write:
where circle superscript indicates standard state, and the left-hand side symbol is (partial/molar) Gibb's energy at standard state (i.e., pressure equals
1 atm
or sometimes1 bar
), while a_j is activity.For hydrogen and oxygen, it is common to set activity equal to partial pressure divided by standard pressure$p^\circ$ , $a_j = p_j/p^\circ$ (assuming ideal gas). For water, it is common to set activity either equal to saturation pressure of water divided by standard pressure at the given temperature, $a_\mathrm{H_2O} = p_\mathrm{H_2O}^\mathrm{sat}/p^\circ$ [assuming water is produced as vapor], or equal to the model fraction of water $a_\mathrm{H_2O} = x_\mathrm{H_2O} \approx 1$ [assuming water is produced as liquid]. The choice of activity for water has ramification for how Gibb's energy for water is computed [choice of heat capacity...].
A simple expression for Gibb's energy at the standard state is:
where the two first term on the RHS are Gibbs energy of formation, and entropy of formation, respectively. These formation energies are critical in thermodynamics of reactions.
Questions:
Clapeyron.jl
?chemical_potential
function to computechemical_potential
function? Sum partial pressures to find total pressure, and scale amount of the different components to unity?Note: using
chemical_potential
requires that the Gibbs energy of formation and the entropy of formation are used inClapeyron.jl
.3. Enthalpy flow rate?
In the energy balance used to compute the temperature, there will be enthalpy flows in and out of the system. Using decoration "dot" to indicate flow rate, enthalpy flow is$\dot{H}$ .
In a simple description, assuming ideal solution, one can write$\dot{H} = \sum \dot{H}_j$ where $\dot{H}_j = \dot{n}_j \cdot \tilde{H}_j$ where $\tilde{H}_j$ is the molar enthalpy of pure component $j$ .
Questions:
Clapeyron.jl
?Clapeyron.jl
function for computing this partial molar enthalpy? (Similar tochemical_potential()
, which I think is the partial molar Gibbs energy whenNote: just like for partial molar Gibbs energy for reactions, a partial molar enthalpy must include enthalpy of formation (either directly, or via Gibbs energy/entropy of formation) in hold necessary information about reaction enthalpy.
Beta Was this translation helpful? Give feedback.
All reactions