Skip to content

Commit ed829ea

Browse files
committed
add docs, allow passing salt pairs to ISElecrolyteWrapper
1 parent b59d118 commit ed829ea

File tree

7 files changed

+54
-86
lines changed

7 files changed

+54
-86
lines changed

docs/src/eos/electrolytes.md

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8,10 +8,23 @@ CurrentModule = Clapeyron
88
Pages = ["electrolytes.md"]
99
```
1010

11-
## Main model
11+
## Explicit vs. Implicit Solvent Models
12+
13+
Electrolyte equations of state model mixtures containing charged species (ions). For such a mixture to be in thermodynamic equilibrium, a fundamental constraint must be imposed: the total electrical charge must sum to zero. This is the condition of **electroneutrality**.
14+
15+
How a model handles charged species defines its approach:
16+
17+
- **Explicit Solvent Models:** These models work directly with individual ions as components (e.g., Na⁺, Cl⁻). While conceptually straightforward at the model level—ions are uniquely defined—performing phase equilibrium calculations requires explicitly satisfying the electroneutrality constraint alongside all other equilibrium conditions (like equality of chemical potentials). This adds a layer of complexity to equilibrium calculations.
18+
19+
- **Implicit Solvent Models:** To circumvent the complexity of the electroneutrality constraint, this approach groups ions into electrically neutral pairs, representing them as a single **salt component** (e.g., NaCl). The remaining components (like water) are implicitly treated as the solvent for these salts. Consequently, models that work with salt components are known as implicit solvent models.
20+
21+
In Clapeyron.jl, our primary implementation uses the **explicit solvent** approach. However, to provide flexibility and connect the two methodologies, we offer the `ISElectrolyteWrapper`, which can transform an explicit solvent model into an equivalent implicit solvent representation.
22+
23+
## Main models
1224

1325
```@docs
1426
Clapeyron.ESElectrolyte
27+
Clapeyron.ISElectrolyteWrapper
1528
```
1629

1730
## Ion Models
@@ -41,4 +54,4 @@ Clapeyron.ConstRSP
4154
Clapeyron.LinMixRSP
4255
Clapeyron.Schreckenberg
4356
Clapeyron.ZuoFurst
44-
```
57+
```

docs/src/properties/electrolytes.md

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -28,4 +28,4 @@ Clapeyron.molality_to_composition
2828

2929
```@docs
3030
Clapeyron.dielectric_constant
31-
```
31+
```

src/methods/property_solvers/stability/tpd.jl

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -383,7 +383,6 @@ function tpd_plan(model,z,is_liquidz,lle,id_test,K_test,pure_test)
383383
end
384384
end
385385

386-
387386
return plan
388387
end
389388

src/models/Electrolytes/ISElectrolyte.jl

Lines changed: 29 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -1,15 +1,30 @@
1-
2-
3-
4-
struct ISElectrolite{T<:IdealModel,c<:EoSModel,i<:IonModel} <: ISElectrolyteModel
5-
components::Array{String,1}
6-
idealmodel::T
7-
neutralmodel::c
8-
ionmodel::i
9-
references::Array{String,1}
10-
end
11-
12-
1+
"""
2+
ISElectrolyteWrapper(model::ESElectrolyteModel;salts = nothing)
3+
4+
5+
Given en explicit solvent model, returns an implicit solvent model, where are the charged components are paired to form binary salts.
6+
If no `salts` argument is specified, the salt pairings will be created via [`Clapeyron.auto_binary_salts`](@ref).
7+
## Example
8+
9+
´´´julia-repl
10+
julia> system = ePCSAFT(["water","acetonitrile"],["sodium","chloride"])
11+
Explicit Electrolyte Model with 4 components:
12+
"water"
13+
"acetonitrile"
14+
"sodium" (+1)
15+
"chloride" (-1)
16+
Neutral Model: pharmaPCSAFT{BasicIdeal, Float64}
17+
Ion Model: hsdDH{ConstRSP}
18+
RSP Model: ConstRSP
19+
20+
julia> salt_system = ISElectrolyteWrapper(system)
21+
ISElectrolyteWrapper{ePCSAFT{BasicIdeal, pharmaPCSAFT{BasicIdeal, Float64}, hsdDH{ConstRSP}}} with 3 components:
22+
"water"
23+
"acetonitrile"
24+
"sodium.chloride"
25+
´´´
26+
27+
"""
1328
struct ISElectrolyteWrapper{M} <: ISElectrolyteModel
1429
components::Vector{String}
1530
model::M
@@ -22,8 +37,8 @@ struct ISElectrolyteIdealWrapper{M} <: IdealModel
2237
salt::SaltParam
2338
end
2439

25-
function ISElectrolyteWrapper(model::ESElectrolyteModel)
26-
salt = SaltParam(model)
40+
function ISElectrolyteWrapper(model::ESElectrolyteModel;salts = nothing)
41+
salt = SaltParam(model,salts)
2742
components = salt.implicit_components
2843
return ISElectrolyteWrapper(components,model,salt)
2944
end

src/models/Electrolytes/SaltParam.jl

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -49,10 +49,16 @@ function explicit_salt_param(comps,salts,Z)
4949
return SaltParam(explicit_solvent,explicit_components,implicit_components,isalts,mat,lu(mat))
5050
end
5151

52-
function SaltParam(model::ESElectrolyteModel)
52+
SaltParam(model::ESElectrolyteModel) = SaltParam(model,nothing)
53+
54+
function SaltParam(model::ESElectrolyteModel,::Nothing)
5355
explicit_salt_param(component_list(model),auto_binary_salts(model),model.charge)
5456
end
5557

58+
function SaltParam(model::ESElectrolyteModel,salts)
59+
explicit_salt_param(component_list(model),salts,model.charge)
60+
end
61+
5662
function component_list(m::SaltParam)
5763
if m.explicit_solvent
5864
return m.explicit_components

src/models/Electrolytes/electrolytes.jl

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@ abstract type ISElectrolyteModel <: ElectrolyteModel end
77
88
Obtains the stoichiometry matrix of `salts` made up of ions stored in the `model`.
99
This will also check that the salt is electroneutral and that all ions are involved in the salts.
10-
If no `salts` argument is specified, it will be created via `Clapeyron.auto_binary_salts(model)`
10+
If no `salts` argument is specified, the salt pairings will be created via [`Clapeyron.auto_binary_salts`](@ref).
1111
1212
"""
1313
function salt_stoichiometry(model::ElectrolyteModel,salts = auto_binary_salts(model))
@@ -66,7 +66,7 @@ end
6666
molality_to_composition(model::ElectrolyteModel,m,zsolv = SA[1.0])
6767
6868
Convert molality (mol/kg) to composition for a given model, salts, molality, and solvent composition.
69-
If no `salts` argument is specified, it will be created via `Clapeyron.auto_binary_salts(model)`
69+
If no `salts` argument is specified, the salt pairings will be created via [`Clapeyron.auto_binary_salts`](@ref).
7070
`zsolv` is the mole fraction of solvent components (in a salt-free basis)
7171
"""
7272
function molality_to_composition(model::ElectrolyteModel,salts::Union{AbstractVector,GroupParam},m,zsolv=SA[1.],ν = salt_stoichiometry(model,salts))

src/models/Electrolytes/stability.jl

Lines changed: 0 additions & 65 deletions
Original file line numberDiff line numberDiff line change
@@ -41,68 +41,3 @@ function tpd_plan(model::ISElectrolyteModel,z,is_liquidz,lle,id_test,K_test,pure
4141
end
4242
return plan
4343
end
44-
45-
#=
46-
function tpd_plan(model::ESElectrolyteModel,z,is_liquidz,lle,id_test,K_test,pure_test)
47-
plan = Tuple{Symbol,Symbol,NTuple{3,Int}}[]
48-
49-
if is_liquidz && id_test && !lle
50-
push!(plan,(:ideal_gas,:vapour,0))
51-
end
52-
53-
#=
54-
if K_test
55-
if is_liquidz
56-
lle || push!(plan,(:K,:vapour,1))
57-
push!(plan,(:K,:liquid,1))
58-
push!(plan,(:K,:liquid,-1))
59-
lle || push!(plan,(:K,:vapour,-1))
60-
else
61-
push!(plan,(:K,:liquid,1))
62-
push!(plan,(:K,:liquid,-1))
63-
end
64-
end =#
65-
Z = model.charge
66-
_,i_elec_pivot = findmax(Z)
67-
if pure_test
68-
ids = sortperm(z)
69-
ZZ = @view Z[ids]
70-
if is_liquidz
71-
for i in 1:length(z)
72-
if iszero(ZZ[i])
73-
idx_solvent = ids[i]
74-
push!(plan,(:pure,:liquid,(idx_solvent,0,0)))
75-
for j in 1:length(z)
76-
if !iszero(ZZ[j])
77-
idx_elec = ids[j]
78-
xx = (idx_solvent,idx_elec,i_elec_pivot)
79-
i_elec_pivot != idx_elec && push!(plan,(:electrolyte_balanced,:liquid,xx))
80-
81-
end
82-
end
83-
end
84-
end
85-
if !lle
86-
for i in 1:length(z)
87-
!iszero(ZZ[i]) && push!(plan,(:pure,:vapour,ids[i]))
88-
end
89-
end
90-
else
91-
for i in 1:length(z)
92-
if iszero(ZZ[i])
93-
idx_solvent = ids[i]
94-
push!(plan,(:pure,:liquid,(idx_solvent,0,0)))
95-
for j in 1:length(z)
96-
if !iszero(ZZ[j])
97-
idx_elec = ids[j]
98-
xx = (idx_solvent,idx_elec,i_elec_pivot)
99-
i_elec_pivot != idx_elec && push!(plan,(:electrolyte_balanced,:liquid,xx))
100-
end
101-
end
102-
end
103-
end
104-
end
105-
end
106-
return plan
107-
end
108-
=#

0 commit comments

Comments
 (0)