-
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
Parameter Estimation for sle_solubility #224
Comments
Seems a bug on our part, let me see what i can do |
@longemen3000 you are a hero, thanks! |
Hi Samuel,
This should fix the issue. |
To address your question regarding estimating the other parameters, you can take a look at the example notebook. Since you are estimating parameters for a mixture, you'll need to specify the indices. Here is how I would code it up: using Clapeyron, BlackBoxOptim
function EXPsolubility(model::CompositeModel,T)
sol = sle_solubility(model,101325.,T,[1.,0.];solute=[solute1])
return sol[2]
end
# Defining solute and solvent, will be fetched from the database later
solute1="nicotinamide2016"
solvent1="ethanol2016"
# Defining a composite model
model = CompositeModel([solvent1,solute1];fluid=PCSAFT,solid=SolidHfus,gas=PCSAFT,gas_userlocations=["data/sle_specific"],fluid_userlocations=["data/sle_specific"],solid_userlocations=["data/sle_specific"])
# Creating the Dict for estimation
toestimate = [
Dict(
:param => segment,
:indices => 2,
:lower => 1.,
:upper => 5.,
:guess => 2.5
),
Dict(
:param => :sigma,
:indices => (2,2),
:recombine => true,
:lower => 2.8,
:upper => 3.8,
:guess => 3.3,
:factor => 1e-10
),
Dict(
:param => epsilon,
:indices => (2,2),
:recombine => true,
:lower => 250.,
:upper => 500.,
:guess => 350.
),
Dict(
:param => :epsilon_assoc,
:indices => 4,
:recombine => true,
:lower => 1000.,
:upper => 3000.,
:guess => 2500.
),
Dict(
:param => :bondvol,
:indices => 4,
:recombine => true,
:lower => 0.02,
:upper => 0.04,
:guess => 0.03
)
];
# Estimation
estimator,objective,initial,upper,lower = Estimation(model,toestimate,["data/EXPsolubility.csv"]);
# BBOptim
nparams = length(initial)
bounds = [(lower[i],upper[i]) for i in 1:nparams]
bounds
result = BlackBoxOptim.bboptimize(objective;
SearchRange = bounds,
NumDimensions = nparams,
MaxSteps=200,
PopulationSize = 1000,
TraceMode=:verbose)
params = BlackBoxOptim.best_candidate(result); I will quickly point out that fitting 5 parameters using 5 data points is very ill advised. I would recommend increasing the size of the dataset (wider temperature range or more solvents) or setting some initial values for the parameters and adjust a smaller subset of parameters (typically, people just fit segment, sigma and epsilon, setting epsilon_assoc and bondvol to be some constant). |
@longemen3000 I realised while doing an initial run of this that, in the case where recombine=true, we should also recombine the cross association parameters. If Samuel were to just estimate the self-association parameters above, it wouldn't update the cross association parameter between the solvent and solute. |
Hmmm, that requires a patch then |
@pw0908 Thanks for the very swift reply. You are right about the crossaccos values. |
Hi @samuel-zhang01, This will be a bit more challenging but should be doable within Clapeyron. The first thing youll need to do is define a model with the API you're trying to fit and the various solvents you intend to include: model = CompositeModel(["solute","solvent1","solvent2",...]) # inlcude all the messy parameters here. It is important to make sure the solute is the first component as this will mean that all the solute parameters will be index 1. To assemble your data, you will probably have separate spreadsheets for each solvent. Within Clapeyron, you can define which components are involved in which data set within the spreadsheet headers:
This means that Clapeyron will automatically reduce your model within the estimation to a binary mixture where the To keep your life simple, I recommend you don't fit the association parameters (just set them to some reasonable constant). We haven't fixed the cross association problem yet so I don't think it'll be wise to do so either way. Since I don't have the experimental data for this system, I can't write you a working example. But I do believe this should work. |
Thank you so much @pw0908, I will give it a try |
Dear Devs of Clapeyron.jl, I might need some more help regarding parameter estimation and the
# using Pkg,Clapeyron
# Pkg.activate("..")
using Clapeyron, BlackBoxOptim
function EXPsolubility(model::CompositeModel,T)
sol = sle_solubility(model,101325.,T,[1.,0.];solute=[solute1])
return sol[2]
end
# Defining solute and solvent, will be fetched from the database later
solute1="lidocaine2013"
solvent1="n-hexane2013"
solvent2="n-heptane2013"
solvent3="ethanol2013"
solvent4="acetone2013"
databasePATH="data/sle_specific"
EXPdataPATH="data/ExpData"
# Defining a composite model
model = CompositeModel([solvent1,solvent2,solvent3,solvent4,solute1];
fluid=PCSAFT,
solid=SolidHfus,
gas=PCSAFT,
gas_userlocations=[databasePATH],
fluid_userlocations=[databasePATH],
solid_userlocations=[databasePATH]
)
# Creating the Dict for estimation
toestimate = [
Dict(
:param => :segment,
:indices => 5,
:lower => 1., # 1, for segment term is a good start
:upper => 9., #
:guess => 5.
),
Dict(
:param => :sigma,
:indices => (5,5),
:recombine => false,
:lower => 1., # start from 1
:upper => 5., # around 5, never more than 5
:guess => 3.,
:factor => 1e-10
),
Dict(
:param => :epsilon,
:indices => (5,5),
:recombine => false,
:lower => 100., # start at around 100,
:upper => 500., # up to 500-600
:guess => 155. # around half way of lower bond, 150
),
];
estimator,objective,initial,upper,lower = Estimation(model,toestimate,[EXPdataPATH]);
nparams = length(initial)
bounds = [(lower[i],upper[i]) for i in 1:nparams]
result = BlackBoxOptim.bboptimize(objective;
SearchRange = bounds,
NumDimensions = nparams,
# MaxSteps=5,
MaxTime = 3600*18,
Method = :adaptive_de_rand_1_bin_radiuslimited,
PopulationSize = 1000,
TraceMode=:compact)
params = BlackBoxOptim.best_candidate(result); Questions:
ERROR: LinearAlgebra.SingularException(1)
Stacktrace:
[1] \(D::LinearAlgebra.Diagonal{Float64, Vector{Float64}}, B::Vector{Float64})
@ LinearAlgebra /USER/julia-1.9.3/share/julia/stdlib/v1.9/LinearAlgebra/src/diagonal.jl:409
[2] \(A::Matrix{Float64}, B::Vector{Float64})
@ LinearAlgebra /USER/julia-1.9.3/share/julia/stdlib/v1.9/LinearAlgebra/src/generic.jl:1107
[3] default_newton_linsolve(d::Vector{Float64}, B::Matrix{Float64}, g::Vector{Float64})
@ NLSolvers ~/.julia/packages/NLSolvers/lRxce/src/quasinewton/approximations/newton.jl:15
[4] solve(problem::NLSolvers.NEqProblem{NLSolvers.VectorObjective{Clapeyron.var"#f!#381"{CompositeModel{PCSAFT{BasicIdeal, Float64}, PCSAFT{BasicIdeal, Float64}, SolidHfus, PCSAFT{BasicIdeal, Float64}, Nothing}, Float64, Float64, Vector{Float64}, Vector{Float64}, Vector{Bool}}, Clapeyron.Solvers.var"#j!#1"{Clapeyron.var"#f!#381"{CompositeModel{PCSAFT{BasicIdeal, Float64}, PCSAFT{BasicIdeal, Float64}, SolidHfus, PCSAFT{BasicIdeal, Float64}, Nothing}, Float64, Float64, Vector{Float64}, Vector{Float64}, Vector{Bool}}, ForwardDiff.JacobianConfig{ForwardDiff.Tag{Clapeyron.var"#f!#381"{CompositeModel{PCSAFT{BasicIdeal, Float64}, PCSAFT{BasicIdeal, Float64}, SolidHfus, PCSAFT{BasicIdeal, Float64}, Nothing}, Float64, Float64, Vector{Float64}, Vector{Float64}, Vector{Bool}}, Float64}, Float64, 1, Tuple{Vector{ForwardDiff.Dual{ForwardDiff.Tag{Clapeyron.var"#f!#381"{CompositeModel{PCSAFT{BasicIdeal, Float64}, PCSAFT{BasicIdeal, Float64}, SolidHfus, PCSAFT{BasicIdeal, Float64}, Nothing}, Float64, Float64, Vector{Float64}, Vector{Float64}, Vector{Bool}}, Float64}, Float64, 1}}, Vector{ForwardDiff.Dual{ForwardDiff.Tag{Clapeyron.var"#f!#381"{CompositeModel{PCSAFT{BasicIdeal, Float64}, PCSAFT{BasicIdeal, Float64}, SolidHfus, PCSAFT{BasicIdeal, Float64}, Nothing}, Float64, Float64, Vector{Float64}, Vector{Float64}, Vector{Bool}}, Float64}, Float64, 1}}}}, Vector{Float64}}, Clapeyron.Solvers.var"#fj!#2"{Clapeyron.var"#f!#381"{CompositeModel{PCSAFT{BasicIdeal, Float64}, PCSAFT{BasicIdeal, Float64}, SolidHfus, PCSAFT{BasicIdeal, Float64}, Nothing}, Float64, Float64, Vector{Float64}, Vector{Float64}, Vector{Bool}}, ForwardDiff.JacobianConfig{ForwardDiff.Tag{Clapeyron.var"#f!#381"{CompositeModel{PCSAFT{BasicIdeal, Float64}, PCSAFT{BasicIdeal, Float64}, SolidHfus, PCSAFT{BasicIdeal, Float64}, Nothing}, Float64, Float64, Vector{Float64}, Vector{Float64}, Vector{Bool}}, Float64}, Float64, 1, Tuple{Vector{ForwardDiff.Dual{ForwardDiff.Tag{Clapeyron.var"#f!#381"{CompositeModel{PCSAFT{BasicIdeal, Float64}, PCSAFT{BasicIdeal, Float64}, SolidHfus, PCSAFT{BasicIdeal, Float64}, Nothing}, Float64, Float64, Vector{Float64}, Vector{Float64}, Vector{Bool}}, Float64}, Float64, 1}}, Vector{ForwardDiff.Dual{ForwardDiff.Tag{Clapeyron.var"#f!#381"{CompositeModel{PCSAFT{BasicIdeal, Float64}, PCSAFT{BasicIdeal, Float64}, SolidHfus, PCSAFT{BasicIdeal, Float64}, Nothing}, Float64, Float64, Vector{Float64}, Vector{Float64}, Vector{Bool}}, Float64}, Float64, 1}}}}}, Clapeyron.Solvers.var"#jv!#3"}, Nothing, NLSolvers.Euclidean{Tuple{0}}, NLSolvers.InPlace}, x::Vector{Float64}, method::NLSolvers.LineSearch{NLSolvers.Newton{NLSolvers.Direct, typeof(NLSolvers.default_newton_linsolve), Nothing, Nothing}, NLSolvers.Backtracking{Float64, Int64, NLSolvers.FixedInterp, NamedTuple{(:lower, :upper), Tuple{Int64, Float64}}}, NLSolvers.InitialScaling{NLSolvers.ShannoPhua}}, options::NLSolvers.NEqOptions{Float64, Int64, Nothing}, state::NamedTuple{(:z, :d, :Fx, :Jx), Tuple{Vector{Float64}, Vector{Float64}, Vector{Float64}, Matrix{Float64}}})
@ NLSolvers ~/.julia/packages/NLSolvers/lRxce/src/nlsolve/linesearch/newton.jl:71
[5] solve
...
[25] bboptimize(functionOrProblem::Function, parameters::Dict{Symbol, Any}; kwargs::Base.Pairs{Symbol, Any, NTuple{5, Symbol}, NamedTuple{(:SearchRange, :NumDimensions, :MaxTime, :Method, :TraceMode), Tuple{Vector{Tuple{Float64, Float64}}, Int64, Int64, Symbol, Symbol}}})
@ BlackBoxOptim ~/.julia/packages/BlackBoxOptim/I3lfp/src/bboptimize.jl:92
[26] bboptimize
@ ~/.julia/packages/BlackBoxOptim/I3lfp/src/bboptimize.jl:91 [inlined]
[27] top-level scope
@ ~/PATH_TO-SCRIPT:8
Thanks again for helping! Below are the experimental data used for my fittings. |
Ill take a look. One thing I immediately notice: the paper you refer to for the lidocaine data uses electrolyte PC-SAFT along with reactive equilibrium. This is not accounted for at all in base PC-SAFT. Are you just trying to create a simplified version of the model? Without the effect of pH? |
Hi Pierre, thanks for the quick reply! Yes you are right, i'm ignoring the ePCSAFT dependency on pH and only trying to reproduce pure PCSAFT parameters |
ExpData.zip |
Hi Samuel, sorry for the late response. I am now back from conference and have been able to take a look at your script and made some modifications in the attached zip file: Answering your questions directly:
Some brief comments about things I changed in the scripts:
|
Amazing devs of Clapeyron.jl,
Sorry to trouble you guys again. I'm exploring parameter estimation for PCSAFT of APIs. Due to the low vapour pressure of APIs, obtaining$p_{sat}$ and $\rho_{l,sat}$ experimentally is quite challanging. experimental sle_solubility data of APIs in different solutes though should be a good substitute to do parameterisation. Is there a built-in support for param estimation for
segment
,sigma
,epsilon
,epsilon_assoc
, andbondvol
?here is the error code:
I've linked the databases used for my calculation.
Thank you so much for your help!
data.zip
The text was updated successfully, but these errors were encountered: