Skip to content

Commit 5df8bc6

Browse files
Initial commit
0 parents  commit 5df8bc6

23 files changed

+1391
-0
lines changed

.gitattributes

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# Auto detect text files and perform LF normalization
2+
* text=auto

.gitignore

+24
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,24 @@
1+
# Files generated by invoking Julia with --code-coverage
2+
*.jl.cov
3+
*.jl.*.cov
4+
5+
# Files generated by invoking Julia with --track-allocation
6+
*.jl.mem
7+
8+
# System-specific files and directories generated by the BinaryProvider and BinDeps packages
9+
# They contain absolute paths specific to the host computer, and so should not be committed
10+
deps/deps.jl
11+
deps/build.log
12+
deps/downloads/
13+
deps/usr/
14+
deps/src/
15+
16+
# Build artifacts for creating documentation generated by the Documenter package
17+
docs/build/
18+
docs/site/
19+
20+
# File generated by Pkg, the package manager, based on a corresponding Project.toml
21+
# It records a fixed state of all packages used by the project. As such, it should not be
22+
# committed for packages, but should be committed for applications that require a static
23+
# environment.
24+
Manifest.toml

LICENSE

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
MIT License
2+
3+
Copyright (c) 2023 Ilian Pihlajamaa
4+
5+
Permission is hereby granted, free of charge, to any person obtaining a copy
6+
of this software and associated documentation files (the "Software"), to deal
7+
in the Software without restriction, including without limitation the rights
8+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9+
copies of the Software, and to permit persons to whom the Software is
10+
furnished to do so, subject to the following conditions:
11+
12+
The above copyright notice and this permission notice shall be included in all
13+
copies or substantial portions of the Software.
14+
15+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21+
SOFTWARE.

Project.toml

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
name = "OrnsteinZernike"
2+
uuid = "51399321-c693-48c0-994d-05e3df0250f2"
3+
authors = ["Ilian Pihlajamaa <ilian.pihlajamaa@gmail.com>"]
4+
version = "0.1.0"
5+
6+
[deps]
7+
BlockArrays = "8e7c35d0-a365-5155-bbbb-fb81a777f24e"
8+
FFTW = "7a1cc6ca-52ef-59f5-83cd-3a7055c09341"
9+
LinearAlgebra = "37e2e46d-f89d-539d-b4ee-838fcccc9c8e"
10+
Plots = "91a5bcdd-55d7-5caf-9e0b-520d859cae80"
11+
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
12+
StaticArrays = "90137ffa-7385-5640-81b9-e52037218182"

README.md

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
# OrnsteinZernike.jl
2+
A generic solver for Ornstein-Zernike equations from liquid state theory

src/Closures.jl

+46
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
abstract type Closure end
2+
3+
struct PercusYevick <: Closure end
4+
struct HypernettedChain <: Closure end
5+
struct MeanSpherical <: Closure end
6+
7+
8+
9+
# function bridge_function(::PercusYevick, γ, _, _)
10+
# oneunit = one.(γ)
11+
# B = @. log(Complex(oneunit + γ)) - γ
12+
# return B
13+
# end
14+
15+
function bridge_function(::HypernettedChain, γ, _, _)
16+
zerounit = zero.(γ)
17+
B = zerounit
18+
return B
19+
end
20+
21+
function bridge_function(::MeanSpherical, γ, u_long_range, _)
22+
oneunit = one.(γ)
23+
s = @. γ - u_long_range # temp s = γ*
24+
B = @. log(oneunit + s) - s
25+
return B
26+
end
27+
28+
function c_closure_from_γ(closure, r, mayer_f, γ, u_long_range)
29+
B = bridge_function(closure, γ, u_long_range, r)
30+
myone = one.(B)
31+
c = @. -myone - γ + (mayer_f + myone)*exp(γ)*real(exp(B))
32+
return c
33+
end
34+
35+
36+
function cmulr_closure_from_Γmulr(closure::Closure, r, mayer_f, Γmulr, u_long_range)
37+
γ = Γmulr/r
38+
return r*c_closure_from_γ(closure, r, mayer_f, γ, u_long_range)
39+
end
40+
41+
42+
function cmulr_closure_from_Γmulr(::PercusYevick, r, mayer_f::T, Γmulr::T, u_long_range::T) where T
43+
return @. mayer_f*(r + Γmulr)
44+
end
45+
46+

src/FourierTransforms.jl

+82
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
function get_forward_and_backward_plan(::SimpleLiquid{3, species, T1, T2, P}, F) where {species, T1, T2, P}
2+
return find_fourier_plans_3d(F)
3+
end
4+
5+
function get_forward_and_backward_plan(::SimpleLiquid{2, species, T1, T2, P}, F) where {species, T1, T2, P}
6+
return find_fourier_plans_2d(F)
7+
end
8+
9+
function find_fourier_plans_3d(F::Vector{T}) where T
10+
if T <: Number
11+
forward = FFTW.plan_r2r!(copy(F), FFTW.RODFT00; flags=FFTW.ESTIMATE)
12+
backward = FFTW.plan_r2r!(copy(F), FFTW.RODFT00; flags=FFTW.ESTIMATE)
13+
return forward, backward
14+
elseif T <: AbstractArray
15+
F2 = copy(F)
16+
Nspecies = size(F2[1], 1)
17+
elT = eltype(T)
18+
F2 = reinterpret(reshape, elT, F2)
19+
if Nspecies == 1
20+
forward = FFTW.plan_r2r!(F2, FFTW.RODFT00; flags=FFTW.ESTIMATE)
21+
backward = FFTW.plan_r2r!(F2, FFTW.RODFT00; flags=FFTW.ESTIMATE)
22+
return forward, backward
23+
else
24+
forward = FFTW.plan_r2r!(F2, FFTW.RODFT00, 2, flags=FFTW.ESTIMATE)
25+
backward = FFTW.plan_r2r!(F2, FFTW.RODFT00, 2, flags=FFTW.ESTIMATE)
26+
return forward, backward
27+
end
28+
end
29+
end
30+
31+
function inverse_radial_fourier_transform_3d(F̂, r, k)
32+
M = length(r)
33+
@assert length(k) == length(F̂) == M
34+
dk = k[2] - k[1]
35+
dr = r[2] - r[1]
36+
# @assert dk*dr ≈ π/(M+1)
37+
F = FFTW.r2r(F̂, FFTW.RODFT00)*dk/(4π^2)
38+
return F
39+
end
40+
41+
function radial_fourier_transform_3d(F, r, k)
42+
M = length(r)
43+
@assert length(k) == length(F) == M
44+
dk = k[2] - k[1]
45+
dr = r[2] - r[1]
46+
# @assert dk*dr ≈ π/(M+1)
47+
= FFTW.r2r(F, FFTW.RODFT00)*2π*dr
48+
return
49+
end
50+
51+
52+
"""
53+
fourier!(F̂, F, plan, equation::OZEquation{3, T1, T2, T3}) where {T1, T2, T3}
54+
55+
computes the three dimensional radial fourier transform of F = r*f(r), returning F̂ = k*f̂(k), where f̂ is the fourier transform of f.
56+
it uses the discrete sine tranform provided by the r2r function of FFTW internally.
57+
"""
58+
function fourier!(F̂::Vector{T}, F::Vector{T}, plan::FFTW.r2rFFTWPlan, dr) where T
59+
@.= F*2π*dr
60+
if T <: Number
61+
plan*
62+
elseif T<:AbstractMatrix
63+
F̂2 = reinterpret(reshape, eltype(T), F̂)
64+
plan*F̂2
65+
end
66+
end
67+
68+
"""
69+
inverse_fourier!(F, F̂, plan, equation::OZEquation{3, T1, T2, T3}) where {T1, T2, T3}
70+
71+
computes the three dimensional radial fourier transform of F̂ = k*f̂(k), returning F = r*f(r), where f̂ is the fourier transform of f.
72+
it uses the discrete sine tranform provided by the r2r function of FFTW internally.
73+
"""
74+
function inverse_fourier!(F::AbstractVector{T}, F̂::AbstractVector{T}, plan::FFTW.r2rFFTWPlan, dk) where T
75+
@. F =* dk/(4π^2)
76+
if T <: Number
77+
plan*F
78+
elseif T<:AbstractMatrix
79+
F2 = reinterpret(reshape, eltype(T), F)
80+
plan*F2
81+
end
82+
end

src/OrnsteinZernike.jl

+12
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
module OrnsteinZernike
2+
using FFTW, QuadGK, StaticArrays, LinearAlgebra, Plots, BlockArrays
3+
4+
include("Systems.jl")
5+
include("Potentials.jl")
6+
include("Closures.jl")
7+
include("FourierTransforms.jl")
8+
include("Solutions.jl")
9+
include("Solvers.jl")
10+
include("Thermodynamics.jl")
11+
12+
end # module OrnsteinZernike

src/Potentials.jl

+81
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
abstract type Potential end
2+
3+
struct SingleComponentHardSpheres <: Potential end
4+
5+
function evaluate_potential(::SingleComponentHardSpheres, r::Number)
6+
return ifelse(r < oneunit(r), Inf64, 0.0)*oneunit(r)
7+
end
8+
9+
struct MultiComponentHardSpheres{N_components, T} <: Potential
10+
D::SVector{N_components, T}
11+
end
12+
13+
function MultiComponentHardSpheres(D::AbstractVector{T}) where T<:Number
14+
N = length(D)
15+
return MultiComponentHardSpheres{N,T}(SVector{N,T}(D))
16+
end
17+
18+
function evaluate_potential(potential::MultiComponentHardSpheres{N,T}, r::Number) where {N,T}
19+
pot = MMatrix{N, N, T, N*N}(undef)
20+
D = potential.D
21+
for species1 = 1:N
22+
for species2 = 1:N
23+
pot[species2, species1] = ifelse(r < (D[species1]+D[species2])/2, Inf64, 0.0)*oneunit(r)
24+
end
25+
end
26+
return SMatrix(pot)
27+
end
28+
29+
"""
30+
exp(- beta * u) - 1.
31+
"""
32+
function find_mayer_f_function(system::SimpleLiquid{dims, species, T1, T2, P}, r::Number, β::Number) where {dims, species, T1, T2, P}
33+
U = evaluate_potential(system.potential, r)
34+
return @. exp(-β*U) - 1.0
35+
end
36+
37+
function find_mayer_f_function(system::SimpleLiquid{dims, species, T1, T2, P}, r::AbstractArray, β::Number) where {dims, species, T1, T2, P}
38+
return find_mayer_f_function.((system, ), r, β)
39+
end
40+
41+
evaluate_potential_derivative(potential::SingleComponentHardSpheres, r) = 0.0
42+
43+
function evaluate_potential_derivative(potential::Potential, r)
44+
#check for discontinuities
45+
ϵ = sqrt(eps(r))
46+
47+
48+
discs = discontinuities(potential)
49+
for discontinuity in discs
50+
if any(abs.(discontinuity .- r) .< ϵ)
51+
error("Trying to evaluate the derivative of the potential at the discontinuity. To fix, define a specialized method for `evaluate_potential_derivative(potential::MyPotential, r)`")
52+
end
53+
end
54+
55+
u2 = evaluate_potential(potential, r+ϵ)
56+
u1 = evaluate_potential(potential, r-ϵ)
57+
if isinf(u2) && isinf(u1)
58+
return zero(u2)
59+
end
60+
return (u2-u1)/(2ϵ)
61+
end
62+
63+
function discontinuities(::Potential)
64+
return Float64[]
65+
end
66+
67+
function discontinuities(::SingleComponentHardSpheres)
68+
return [1.0]
69+
end
70+
71+
function discontinuities(potential::MultiComponentHardSpheres)
72+
D = potential.D
73+
T = eltype(D)
74+
disc = MMatrix{N, N, T, N*N}(undef)
75+
for species1 = 1:N
76+
for species2 = 1:N
77+
disc[species2, species1] = (D[species1]+D[species2])/2
78+
end
79+
end
80+
return [SMatrix(disc)]
81+
end

src/Solutions.jl

+27
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,27 @@
1+
struct OZSolution{T1, T2}
2+
r::T1
3+
k::T1
4+
gr::T2
5+
Sk::T2
6+
Ck::T2
7+
Cr::T2
8+
end
9+
10+
function convert_vecofmat_to_3darr(a)
11+
elT = eltype(eltype(a))
12+
Ns1, Ns2 = size(a[1])
13+
Nr = length(a)
14+
a = reinterpret(reshape, elT, a)
15+
a = reshape(a, Ns1, Ns2, Nr)
16+
a = permutedims(a, (3,1,2))
17+
return a
18+
end
19+
20+
21+
function OZSolution(r::T1, k::T1, gr::T, Sk::T, Ck::T, Cr::T) where {T1,T<:Vector{<:AbstractMatrix}}
22+
gr = convert_vecofmat_to_3darr(gr)
23+
Sk = convert_vecofmat_to_3darr(Sk)
24+
Ck = convert_vecofmat_to_3darr(Ck)
25+
Cr = convert_vecofmat_to_3darr(Cr)
26+
OZSolution(r, k, gr, Sk, Ck, Cr)
27+
end

0 commit comments

Comments
 (0)