-
Notifications
You must be signed in to change notification settings - Fork 52
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Ternary LLE #201
Comments
It is a problem on how our current activity models are defined, try using |
Just to add to this, the
I named this file julia> model = NRTL(["water","ethanol","chloroform"];pure_userlocations=["example.csv"])
NRTL{PR{BasicIdeal, PRAlpha, NoTranslation, vdW1fRule}} with 3 components:
"water"
"ethanol"
"chloroform"
Contains parameters: a, b, c, Mw With this, you can now perform a flash calculation to obtain the LLE split: julia> (x,n,G) = tp_flash(model,1e5,298.15,[0.4,0.2,0.4],RRTPFlash(equilibrium=:lle))
([0.8297322420540518 0.15921199667918248 0.011055761266765664; 0.03308014486558528 0.23482617035706146 0.7320936847773533], [0.3821558182414502 0.07332942819501094 0.005092032440156436; 0.0178441817585497 0.12667057180498906 0.39490796755984364], -13.173873832905187) where I hope this helps! |
This looks great. One question: where should I locate the "example.csv" file relative to my Julia installation? I am new to Julia, and I cannot find the Clapeyron.jl installation, so I assume its tucked away inside my Julia installation somewhere, but since I can't find it, it is not obvious to me where I should put files that Clapeyron needs to use during computation. |
If you start julia from your command line, the file just needs to be in the directory in which you started julia (similarly if you're using Jupyter notebook). If you start julia from the app, I think the file will have to be in your root directory. |
Thank you, I was able to get it to work using an absolute directory address for the example file. I am sorry to continue to be a bother, but I have a couple more questions: |
In this case, it means the default initial guesses we use didn't converge to the correct solution. In julia> model = NRTL(["water","acetic acid","chloroform"];pure_userlocations=["example.csv"])
NRTL{PR{BasicIdeal, PRAlpha, NoTranslation, vdW1fRule}} with 3 components:
"water"
"acetic acid"
"chloroform"
Contains parameters: a, b, c, Mw
julia> (x,n,G) = tp_flash(model,1e5,298.15,[0.417380784546791, 0.248249161677283, 0.334370053775926],RRTPFlash(equilibrium=:lle,K0=[1000.,10.,0.0001]))
([0.7375268155374085 0.24461033837441734 0.017862846088174216; 0.031865826087897405 0.25263097709477483 0.7155031968173279], [0.4029238173928658 0.13363491229775057 0.009758785692563492; 0.01445696715392478 0.11461424937953242 0.324611268083363], -13.054544125517769) As for checking if the solution is consistent, you can just verify using the julia> activity_coefficient(model,1e5,298.15,x[1,:]).*x[1,:]
3-element Vector{Float64}:
0.7664098218637342
0.21940560040722923
0.7558330974181812
julia> activity_coefficient(model,1e5,298.15,x[2,:]).*x[2,:]
3-element Vector{Float64}:
0.7664098218400759
0.21940560040458024
0.7558330973962782 As for stability, we do have the julia> Clapeyron.tpd(model,1e5,298.15,x[1,:])
(Vector{Float64}[], Float64[], Symbol[], Symbol[])
julia> Clapeyron.tpd(model,1e5,298.15,x[2,:])
(Vector{Float64}[], Float64[], Symbol[], Symbol[]) So long as these solutions are empty, we can safely assume the phases are stable. |
I am getting the hang of it. However, I have a new question: where do you get the info for the compounds? I have no trouble finding Tc, Pc, Vc, etc., but the DIPPR numbers I can find (DIPPR IDs from the DIPPR Database) don't match the ones in the data block you gave me above. Also, it turns out you do have an entry for Trichloromethane, but its values don't match the data block you gave me for chloroform (they are similar, but different – including the DIPPR Number). Which values matter and which do not? |
For chloroform, I honestly just took the first result from NIST. They gave a range of values, but since LLE calculations do not depend on those calculations, I just picked a random one. The database we have from Clapeyron comes from a large database where they have averaged across a range of experimental values. As such, those are more reliable. As for why the DIPPR numbers don't line up: I just copied the first row of our database file and only replaced the parameters. The DIPPR value here corresponds to methane. You don't actually have to include the DIPPR number within your custom parameters. We initially had the DIPPR number there to avoid issues like this where one species can have two names. Thankfully, @longemen3000 is working on an update where this shouldn't be a problem anymore. |
OK, that makes sense. If I want to select a different mixing rule (such as HV, for example), how do I format that option? It seems, having looked into the code itself, that mixing rules are options for the EoS, but for NTRL the EoS is an option for NRTL. I did figure out how to change the EoS that NRTL uses, but not how to pass options to said EoS. |
when using advanced mixing rules, the main EoS is the cubic. that is:
that will use the PR model, using the Huron-Vidal rule (That itself calls the NRTL model for obtaining gE). When using cubics with advanced mixing rules (or any EoS in general defined in terms of helmoltz energy), the LLE problem is solved by solving the equality of chemical potentials ( When using activity models, it always use the activity model for the liquid phase (or phases) and the pure model for saturation and properties of the gas phase. in LLE this is just you can also just prebuild the model before passing it as an option:
|
So, just to be clear, |
There seems to be a bit of a mix up here. The two models you describe here are different. For context:
To best visualise this, take a look at the Txy diagram in this example notebook: https://github.com/ClapeyronThermo/Clapeyron.jl/blob/master/examples/activity_models.ipynb. You can see that, while the end points of the VLE envelopes may be the same, the bubble and dew curves are not. If you'd like to learn more on this, we have an introductory course: https://github.com/ClapeyronThermo/introduction-to-computational-thermodynamics. Part 2 is most-relevant here. |
As an aside, I've made some example notebooks for plotting ternary phase diagrams on a separate branch: https://github.com/ClapeyronThermo/Clapeyron.jl/blob/docs-update/examples/ternary_phase_diagrams.ipynb. |
Those posts were helpful. I am, unfortunately, stuck with an optimization problem. I am trying to use NRTL to model water-acetone-chloroform (which works just fine) and water-acetone-dichloromethane (which fails at every bulk mole fraction vector I try, no matter what K0 vector I start RRTP with). My models are:
and
The command I run is
|
A few things to note:
julia> model.params.a
3×3 PairParam{Float64}(["water", "acetone", "dichloromethane"]) with values:
0.0 0.054 0.0
6.398 0.0 0.0
0.0 0.0 0.0 Since a 0 parameter implies that the two species have almost ideal interactions, you're not going to get a phase split. The way to resolve this would be to add the parameters manually just like you did for the cubic. In the case of activity coefficient models, the binary parameters are not symmetric. As such, if you provide parameter a_ij, you also need to provide a_ji. An example of how this file should look is shown below:
There might be some NRTL parameters for your system online. Bear in mind that
|
If you're stuck looking for parameters, there is also UNIFAC you could consider (all the groups seem to be present here) or SPTNRTL.jl which @longemen3000 is developing. |
I may need to use another method, since I can't seem to find coefficients for dichloromethane. I guess there is an opportunity for someone to do some research... There are a (very) few ternary systems with dichloromethane and one or the other of my desired components, so I could attempt to compute a_ij and a_ji, b_ij and b_ji, c_ij and c_ji from the data. If I were to do that, does "i" refer to the row in model.params.a (etc.) or does it refer to the columns? |
looking at spt-NTRL and it's supplementary info (that is technically a normal NRTL, but the parameters were generated via a transformer neural network, paper: https://doi.org/10.1016/j.fluid.2023.113731),it seems that the training data includes those three molecules, so i suppose that the predictions for this specific system are good enough. sm = ["O", "CC(C)=O", "ClCCl"] #smiles for water, acetone, dicloromethane
#a0,a1,t0,t1,t2,t3 = SPTNRTL.spt_NRTL_params(sm) #TODO on my part, better api for this that don't require smiles
a0,a1,t0,t1,t2,t3 = ([0.0 0.228632 0.257017; 0.228632 0.0 0.244773; 0.257017 0.244773 0.0], [0.0 0.000136 0.000187; 0.000136 0.0 0.000193; 0.000187 0.000193 0.0], [0.0 13.374756 13.426971; 16.081848 0.0 18.17276; 13.804535 19.355072 0.0], [0.0 -415.527344 583.285156; -88.8125 0.0 -926.445312; 1163.712891 -579.439453 0.0], [0.0 -1.913689 -2.213547; -2.930901 0.0 -2.844528; -2.846214 -3.284027 0.0], [0.0 0.00153 0.004608; 0.005305 0.0 0.001674; 0.004722 0.004792 0.0])
model = aspenNRTL(["water", "acetone", "dichloromethane"],puremodel = BasicIdeal)
model.params.a0 .= a0
model.params.a1 .= a1
model.params.t0 .= t0
model.params.t1 .= t1
model.params.t2 .= t2
model.params.t3 .= t3 |
Thank you. I was going to try (and would still like to try) regressing my data set to obtain the necessary values; I'm going to have to work my way up to that, though, as I don't immediately see what the appropriate estimator object would be. |
A few recommendations, if you'd like to do this in Clapeyron:
If your work is time-sensitive, I do recommend you consider using either SPT-NRTL or UNIFAC. Parameter estimation can be time consuming on its own. |
Yes, I had already looked at that notebook and I follow it pretty well, having used similar systems in Python for other applications. I also intended to switch to fitting two-component systems (at least at first) so they would be more computationally tractable. However, for DCM-water, the available binary data is mutual solubility and I'm not sure how to set that up with respect to the estimator function. I suppose that the DCM-acetone binary would be easier since there I would be looking at bubble and dew points. |
New issue: I am attempting to use UNIFAC, but the group parameter for water seems to be missing. I tried |
Also, using the spt-NTRL model and parameters you so kindly provided, I am getting the error |
A lot to answer here:
julia> model = UNIFAC(["water",("acetone",["CH3CO"=>1,"CH3"=>1]),("dichloromethane",["CH2CL2"=>1])];pure_userlocations=["example.csv"])
UNIFAC{PR{BasicIdeal, PRAlpha, NoTranslation, vdW1fRule}} with 3 components:
"water": "H2O" => 1
"acetone": "CH3CO" => 1, "CH3" => 1
"dichloromethane": "CH2CL2" => 1
Group Type: UNIFACDortmund
Contains parameters: A, B, C, R, Q
|
The |
@longemen3000 How do I find out? I have been unable to find the actual package location and I don't know how to request a version number in Julia. I installed it last week, so it should be pretty current. |
The bug is unrelated to your Clapeyron version. The fixed I mentioned previously should work? If you want to check the Clapeyron version youre using, paste this command into Julia: ] status Clapeyron |
@pw0908 I am working through correlating my data with UNIFAC. It is going well, but I chanced upon a discovery that you might want to be aware of: the existing tests (as you noted for me above) for stability of the solution in an LLE are not foolproof. For example, if you use
you will get the following test results:
However, if you run
you get the following test results:
The only way I could tell the second set was inconsistent was the sudden discontinuity in my phase diagram; there are an entire set of solutions similar to the second that exist in that region, but they are not continuous with the low-acetone tie-lines and they have higher (less negative) excess energies of mixing. |
This behaviour has more to do with the fact that the Rachford-Rice algorithm ( Algorithms like My only recommendation for this case is to find one globally stable solution and then re-use this solution as the initial guess for the next iteration. You can see examples of this in the notebooks I shared for the ternary phase diagrams. |
Wow, you weren't kidding about DETPFlash. I ran it time-unrestricted and 24 hours later it still hadn't finished. I will try rerunning it with a time limit just to see what it does, but I guess I will be using RRTPFlash and human judgement. |
I find that I am unable to get near the plait point with RRTPFlash; the closer I get, the more it wants to diverge into alternate solutions and I cannot tell which, if any, are legitimate. I had been slightly varying the feed composition to improve convergence (since any feed composition along a tie line will give the same endpoints), but this alters the overall excess free energy of mixing so I can't tell if the solution is better, worse, or the same (by that criterion). The only criterion I have is consistency with previous results, and I am now worried that if I followed a suboptimal solution branch early on, I am just perpetuating that error by choosing solutions that are consistent with it. Is this a common problem with LLE, or is my system uniquely ill-conditioned? |
@pw0908 Am I doing this wrong: |
@pw0908 is likely a symptom of the bug we were talking earlier?
It works on the master version of Clapeyron (so maybe something is wrong in the current version). i'm adding a test
This requires a fix on our part. i think you are the first on trying LLE with Differential evolution. on MichelsenTPFlash we cache a lot of things when activity models are involved. such caching is not done in I will try to address all those concerns ASAP, and release a new version. then i will ask you to update and try again with in the meantime, i will add a testsuite just with the errors reported in this issue. feel free to write any code that you should expect to work but it doesn't |
It shouldn't matter, but I am working on a MacBook Pro; I installed Julia specifically to run Clapeyron, so the Julia installation should be up-to-date. |
In terms of actually tracing the LLE region using
I went ahead an adapted my code for your system: model = UNIFAC(["water",("dichloromethane",["CH2CL2"=>1]),("acetone",["CH3"=>1,"CH3CO"=>1])])
# Define initial conditions
T = 298.15
p = 1e5
z0 = [0.5,0.5,1e-10]
# Using the phase fraction to 'aim' for the plait point
ϕ = 0.75
# Give a decent initial guess
K0 = [1000.,0.0001,0.001]
# Define the tracing step size
dz = 1e-3
# initialise an empty vector which will store all of our points
x_LLE = zeros(500,6)
idxend = 500
for i in 1:500
# Solve the flash
(x,n,G) = tp_flash(model,p,T,z0,RRTPFlash(K0=K0,equilibrium=:lle))
# Store the values
x_LLE[i,1:3] = x[1,:]
x_LLE[i,4:6] = x[2,:]
# Use them as initial guesses in the next iteration
K0 = [x[1,1]/x[2,1],x[1,2]/x[2,2],x[1,3]/x[2,3]]
# Adapt your starting composition to be within the two-phase region
z0[1:2] = x[1,1:2]*ϕ+x[2,1:2]*(1-ϕ)
# Take a step further in the direction of the component that will close the two-phase region
z0[3] = z0[3] + dz
if x[1,1]-x[2,1] < 1e-3
# If the two-phase region closes, give the index at which it closes and stop the loop
idxend=i-1
break
end
end
# Store all the values into a single vector for plotting
x_LLE = vcat(x_LLE[1:idxend,1:3],reverse(x_LLE[1:idxend,4:6],dims=1)); |
The figure looks great; if I am reading the code correctly, tie lines would connect x[n,1:3] and x[n,4:6]. This is essentially what I tried to do, including predicting the next K0 from the previous round, stepping the acetone gradually, and so forth. The one thing I didn't do (and it seems to have made all the difference) is use the method you used to predict the next z0 values. Also, I didn't go down to 0.001-sized steps until I ran into trouble. |
There aren't any integrated plotting functions in Clapeyron (yet) but you call PyPlot directly in Julia ( |
So I copied your script into a file and ran it in Julia (using Clapeyron) and it is throwing two warnings and an error:
The warnings I'm not too worried about, since I think that treating the variables as local is correct. However, I can't figure out why it says that K0 isn't defined, especially since (if I am counting code lines correctly) it is claiming it isn't defined the third time K0 appears! I'm not sure what to do... |
try wrapping all that code in a function:
that error is basically julia telling us that we really shouldn't use globals for everything, you can read more of that here: https://docs.julialang.org/en/v1/manual/variables-and-scoping/#on-soft-scope |
Answering your questions:
model = UNIFAC(["water",("dichloromethane",["CH2CL2"=>1]),("acetone",["CH3"=>1,"CH3CO"=>1])])
N = 500
T = 298.15
p = 1e5
z0 = [0.5,0.5,1e-10]
K0 = [1000.,0.0001,0.001]
x_LLE = zeros(N,6)
idxend = N
(x,n,G) = tp_flash(model,p,T,z0,RRTPFlash(K0=K0,equilibrium=:lle))
x_LLE[1,1:3] = x[1,:]
x_LLE[1,4:6] = x[2,:]
K0 = x[1,:]./x[2,:]
z0[1:2] = x[1,1:2]/2+x[2,1:2]/2
z0[3] += 2/N
for i in 2:N
global z0, K0, x_LLE, idxend
(x,n,G) = tp_flash(model,p,T,z0,RRTPFlash(K0=K0,equilibrium=:lle))
x_LLE[i,1:3] = x[1,:]
x_LLE[i,4:6] = x[2,:]
K0 = x[1,:]./x[2,:]
z0 = (x_LLE[i,1:3]+x_LLE[i,4:6])-(x_LLE[i-1,1:3]+x_LLE[i-1,4:6])/2
if abs(x[1,1]-x[2,1]) < 1e-3
idxend=i-1
break
end
end
x_LLE = vcat(x_LLE[1:idxend,1:3],reverse(x_LLE[1:idxend,4:6],dims=1)); |
@tlorance sorry about that, we should've probably communicated before answering at the same time 😆. Either solution is fine. |
What is the format for supplementing UNIQUAC parameters? I have found parameters for dichloromethane, but I can't quite figure out the syntax required to supply them to the model. |
I have the same question about COSMO-SAC, although I'm having a harder time finding those parameters (and, in that case, acetone is also missing). |
As a general tip, the parameters for each equation of state is described in the docs; if you wish to input custom parameters, you can either feed them in through CSVs using the naming conventions described in the docs or directly within the code. Nevertheless, for your specific case:
For the unlike parameters (
For the like parameters (
q and q_p should be the same unless you are using a special variant of UNIQUAC. With this, you can build the model like you did before (although now, you specify model = UNIQUAC(["methanol","benzene"]; userlocations=["like.csv","unlike.csv"]) As an aside, why are you looking at UNIQUAC? UNIFAC already has the parameters for dichloromethane. The approaches will be identical for species represented as a single group.
This is a bit convoluted but there is a copyright on those parameters meaning that we cannot store them locally in Clapeyron (the files are also massive, which would unnecessarily increase the size of Clapeyron). We do have some ideas on how to streamline the process using special parsers, but these are not high priority right now. Finally, as this thread has now evolved beyond a single issue and the fact that it is now getting very long, would you be open to switching to email? Our addresses can be found in the docs (Pierre and Andrés). |
I thought that UNIFAC used group-contribution methods to estimate the UNIQUAC parameters, so I had assumed there was probably a difference between the UNIFAC-estimated parameters and the fitted parameters used in base UNIQUAC. |
|
Conversation has moved to email so I'll close the issue |
I am interested in using Clapeyron.jl to correlate experimental ternary LLE data. I can figure out how to construct a model (at least in some cases*), but I cannot figure out how to call "LLE" with three or more components: I don't think this is a bug, just a lack of documentation. Could someone please help?
*I did try to set up a NRTL model for water, acetone, and chloroform, but an error was thrown:
ERROR: Missing values exist ∈ single parameter Tc: Union{Missing, Float64}[647.13, 508.2, missing].
I assume that this means that the critical temperature of some component (chloroform, since it is last?) is missing, but I am suspicious I have misinterpreted this as the critical temperature of all of these compounds are well known. If it is simply missing from the code database, can I add it so that I can use NRTL?
The text was updated successfully, but these errors were encountered: