Skip to content

Commit bd51330

Browse files
authored
Merge pull request #6 from JuliaXRTS/add-QEDprobing-code
added code from QEDprobing
2 parents beb5bc5 + 806bd86 commit bd51330

34 files changed

+2239
-8
lines changed

Project.toml

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,19 @@
11
name = "MatterModels"
22
uuid = "89b7eb7d-0b8d-5078-86d5-4a0f481f2984"
3-
authors = ["Uwe Hernandez Acosta <[email protected]>"]
43
version = "0.1.0"
4+
authors = ["Uwe Hernandez Acosta <[email protected]>"]
5+
6+
[deps]
7+
LogExpFunctions = "2ab3a3ac-af41-5b50-aa03-7779005ae688"
8+
QEDcore = "35dc0263-cb5f-4c33-a114-1d7f54ab753e"
9+
QuadGK = "1fd47b50-473d-5c70-9696-f719f8f3bcdc"
10+
SpecialFunctions = "276daf66-3868-5448-9aa4-cd146d93841b"
11+
Unitful = "1986cc42-f94f-5a68-af5c-568840ba703d"
512

613
[compat]
14+
LogExpFunctions = "0.3.29"
15+
QEDcore = "0.4.0"
16+
QuadGK = "2.11.2"
17+
SpecialFunctions = "2.6.1"
18+
Unitful = "1.25.1"
719
julia = "1.10"

src/MatterModels.jl

Lines changed: 73 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,77 @@
11
module MatterModels
22

3-
"""
4-
hi = hello_world()
5-
A simple function to return "Hello, World!"
6-
"""
7-
function hello_world()
8-
return "Hello, World!"
9-
end
3+
hello_world() = "Hello, World!"
4+
5+
# temperature
6+
export FiniteTemperature, ZeroTemperature
7+
8+
# matter model
9+
export AbstractMatterModel
10+
11+
# Electron system
12+
export AbstractElectronSystem
13+
export temperature, electron_density, imag_dynamic_response, real_dynamic_response
14+
export fermi_wave_vector,
15+
fermi_energy, beta, betabar, dynamic_response, dynamic_structure_factor
16+
17+
export AbstractProperElectronSystem
18+
export AbstractInteractingElectronSystem
19+
export proper_electron_system, screening
20+
21+
# screening
22+
export AbstractScreening, Screening, NoScreening
23+
export dielectric_function,
24+
pseudo_potential, local_field_correction, local_effective_potential
25+
export AbstractPseudoPotential, CoulombPseudoPotential
26+
export AbstractLocalFieldCorrection, NoLocalFieldCorrection
27+
28+
# concrete electron systems
29+
export IdealElectronSystem
30+
export AbstractResponseApproximation, NoApprox, NonDegenerated, Degenerated
31+
export response_approximation
32+
export InteractingElectronSystem
33+
34+
# constants
35+
export HBARC,
36+
HBARC_eV_ANG,
37+
ELECTRONMASS,
38+
ALPHA,
39+
ALPHA_SQUARE,
40+
ELEMENTARY_CHARGE_SQUARED,
41+
ELEMENTARY_CHARGE,
42+
HARTREE,
43+
BOHR_RADIUS_ANG
44+
45+
using QEDcore
46+
using QuadGK
47+
using Unitful
48+
using LogExpFunctions
49+
using SpecialFunctions
50+
51+
include("utils.jl")
52+
include("units.jl")
53+
include("constants.jl")
54+
include("temperature.jl")
55+
include("interface.jl")
56+
include("generic.jl")
57+
include("lookup.jl")
58+
include("data_driven/impl.jl")
59+
include("electron_system/utils.jl")
60+
include("electron_system/interface.jl")
61+
include("electron_system/generic.jl")
62+
include("electron_system/ideal/approximations/interface.jl")
63+
include("electron_system/ideal/approximations/no_approx.jl")
64+
include("electron_system/ideal/approximations/non_degenerated.jl")
65+
include("electron_system/ideal/approximations/degenerated.jl")
66+
include("electron_system/ideal/utils.jl")
67+
include("electron_system/ideal/interface.jl")
68+
include("electron_system/ideal/generic.jl")
69+
include("electron_system/ideal/impl.jl")
70+
include("electron_system/interacting/screening/interface.jl")
71+
include("electron_system/interacting/screening/generic.jl")
72+
include("electron_system/interacting/screening/impl.jl")
73+
include("electron_system/interacting/interface.jl")
74+
include("electron_system/interacting/generic.jl")
75+
include("electron_system/interacting/impl.jl")
1076

1177
end

src/constants.jl

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,9 @@
1+
const HBARC = 197.3269718 # MeV fm
2+
const HBARC_eV_ANG = HBARC * 1.0e6 * 1.0e-5 # eV Ang
3+
const ELECTRONMASS = 0.5109989461e6 # eV
4+
const ALPHA = 1 / (137.035999074)
5+
const ALPHA_SQUARE = ALPHA^2
6+
const ELEMENTARY_CHARGE_SQUARED = 4 * pi * ALPHA
7+
const ELEMENTARY_CHARGE = sqrt(ELEMENTARY_CHARGE_SQUARED)
8+
const BOHR_RADIUS_ANG = 0.529177210544 # Ang
9+
const HARTREE = 27.211386245981

src/data_driven/impl.jl

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
# TODO
2+
# - rename the type (adopt MCSS)
3+
# - build a better interface of data informed matter models
4+
# - update lookup function (signature)
5+
struct DataDrivenMatterModel <: AbstractMatterModel
6+
lt::GridLookupTable
7+
method::AbstractLookupMethod
8+
end
9+
lookup_table(dsf::DataDrivenMatterModel) = dsf.lt
10+
lookup_method(dsf::DataDrivenMatterModel) = dsf.method
11+
12+
function DataDrivenMatterModel(datadict::Dict, method::AbstractLookupMethod = InterpolExtrapol())
13+
lt = GridLookupTable(
14+
datadict["omega_me"],
15+
datadict["q_me"],
16+
datadict["dsf"]',
17+
)
18+
return DataDrivenMatterModel(lt, method)
19+
end
20+
21+
function dynamic_structure_factor(
22+
sys::DataDrivenMatterModel,
23+
om_q::NTuple{2, T},
24+
) where {T <: Real}
25+
om, q = @inbounds om_q
26+
27+
return lookup(lookup_method(sys), om, q, lookup_table(sys))
28+
end

src/electron_system/generic.jl

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
function dynamic_response(esys::AbstractElectronSystem, om_q::NTuple{2, T}) where {T <: Real}
2+
return real_dynamic_response(esys, om_q) + 1im * imag_dynamic_response(esys, om_q)
3+
end
4+
5+
6+
@inline function _dynamic_structure_factor_pos_om(
7+
esys::AbstractElectronSystem,
8+
om_q::NTuple{2, T},
9+
) where {T <: Real}
10+
_fac = pi * electron_density(esys)
11+
imag_rf = imag_dynamic_response(esys, om_q)
12+
13+
om = @inbounds om_q[1]
14+
if iszero(temperature(esys))
15+
return -imag_rf / _fac
16+
end
17+
18+
return -imag_rf / ((one(T) - exp(-beta(esys) * om)) * _fac)
19+
end
20+
21+
function dynamic_structure_factor(
22+
esys::AbstractElectronSystem,
23+
om_q::NTuple{2, T},
24+
) where {T <: Real}
25+
om, q = @inbounds om_q
26+
if om < zero(om)
27+
return exp(om * beta(esys)) * _dynamic_structure_factor_pos_om(esys, (-om, q))
28+
else
29+
return _dynamic_structure_factor_pos_om(esys, om_q)
30+
end
31+
end
32+
33+
function static_response(esys::AbstractElectronSystem, q::T) where {T <: Real}
34+
35+
end
36+
37+
function static_structure_factor(esys::AbstractElectronSystem, q::T) where {T <: Real}
38+
39+
end
Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,68 @@
1+
### real part
2+
3+
# TODO: refactor this!
4+
function _deg_integral(x::Real)
5+
if abs(x) < 0.95
6+
# Numerically stable atanh version
7+
return (1 - x^2) * atanh(x)
8+
elseif abs(x - 1) < 1.0e-4
9+
# Taylor expansion around x = 1
10+
δ = x - 1
11+
return^2) / 3 + (2δ^3) / 5 -^4) / 7
12+
elseif abs(x + 1) < 1.0e-4
13+
# Taylor expansion around x = -1
14+
δ = x + 1
15+
return^2) / 3 - (2δ^3) / 5 +^4) / 7
16+
else
17+
# Use log1p if safe, otherwise fall back to log(abs(...))
18+
log_term = if (1 + x > 0) && (1 - x > 0)
19+
log1p(x) - log1p(-x)
20+
else
21+
log(abs(1 + x)) - log(abs(1 - x))
22+
end
23+
return 0.5 * (1 - x^2) * log_term
24+
end
25+
end
26+
27+
function _real_lindhard_nonzero_temperature(::Degenerated, ombar::T, qbar::T, bbar::T) where {T <: Real}
28+
29+
prefac = inv(qbar)
30+
num = _nu_minus(ombar, qbar)
31+
nup = _nu_plus(ombar, qbar)
32+
33+
34+
if qbar < 1.0e-2 * ombar
35+
# limiting case for large ombar
36+
# source: AB84, table 1, (4,2)
37+
prefac2 = -32.0 * qbar^2 * pi / (3 * ombar^2)
38+
return prefac2 * (
39+
1 + qbar^4 / ombar^2 + 6 * qbar^2 / (bbar * ombar^2) + 60 * qbar^4 / (bbar^2 * ombar^4)
40+
)
41+
end
42+
if ombar < 1.0e-4 * qbar
43+
# fallback on no-approx
44+
# TODO: find an improved formula for this case!
45+
return _real_lindhard_zero_temperature(NoApprox(), ombar, qbar)
46+
end
47+
48+
# general degenerated case
49+
# source: AB84, eq. 10a
50+
return -prefac * (qbar + _deg_integral(nup) - _deg_integral(num))
51+
end
52+
53+
### imaginary part
54+
55+
# general degenerated case
56+
# source: AB84, eq. 26
57+
function _imag_lindhard_nonzero_temperature(::Degenerated, ombar::T, qbar::T, bbar::T) where {T <: Real}
58+
prefac = -pi / (2 * qbar * bbar)
59+
60+
num = _nu_minus(ombar, qbar)
61+
nup = _nu_plus(ombar, qbar)
62+
mubar = _chemical_potential_normalized(bbar)
63+
64+
term1 = bbar * (one(num) - num^2)
65+
term2 = bbar * (one(nup) - nup^2)
66+
67+
return prefac * (log1pexp(term1) - log1pexp(term2))
68+
end
Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
abstract type AbstractApproximation end
2+
Base.broadcastable(approx::AbstractApproximation) = Ref(approx)
3+
4+
abstract type AbstractResponseApproximation <: AbstractApproximation end
5+
6+
# most naive implementation
7+
struct NoApprox <: AbstractResponseApproximation end
8+
9+
# using integral transforms and identities to make integration more stable
10+
struct TransformedIntegral <: AbstractResponseApproximation end
11+
12+
# using the limit for non-degenerated electron gases (betabar << 1)
13+
struct NonDegenerated <: AbstractResponseApproximation end
14+
15+
# using the limit for degenerated electron gases (betabar >> 1)
16+
struct Degenerated <: AbstractResponseApproximation end
17+
18+
const AbstractZeroTemperatureApproximation = Union{NoApprox}
19+
const AbstractFiniteTemperatureApproximation = Union{NoApprox, NonDegenerated, Degenerated}
Lines changed: 83 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,83 @@
1+
# zero temperature Lindhard, without any further approximation
2+
3+
function _imag_lindhardDSF_zeroT_minus(omb::T, qb::T) where {T <: Real}
4+
num = _nu_minus(omb, qb)
5+
6+
if abs(num) >= one(T)
7+
return zero(T)
8+
end
9+
return one(omb) - num^2
10+
11+
end
12+
13+
function _imag_lindhardDSF_zeroT_plus(omb::T, qb::T) where {T <: Real}
14+
nup = _nu_plus(omb, qb)
15+
if abs(nup) >= one(T)
16+
return zero(T)
17+
end
18+
return one(omb) - nup^2
19+
20+
end
21+
22+
function _imag_lindhard_zero_temperature(::NoApprox, ombar::T, qbar::T) where {T <: Real}
23+
return -pi / (2 * qbar) *
24+
(_imag_lindhardDSF_zeroT_minus(ombar, qbar) - _imag_lindhardDSF_zeroT_plus(ombar, qbar))
25+
end
26+
27+
function _real_lindhard_zero_temperature(::NoApprox, ombar::T, qbar::T) where {T <: Real}
28+
num = _nu_minus(ombar, qbar)
29+
nup = _nu_plus(ombar, qbar)
30+
31+
term1 = (1 - num^2) / 4 * _stable_log_term(num)
32+
term2 = (1 - nup^2) / 4 * _stable_log_term(nup)
33+
34+
return -2 * (qbar / 2 - term1 + term2) / qbar
35+
end
36+
37+
# finite temperature Lindhard, without any further approximation
38+
39+
## Real part
40+
41+
function _general_fermi(x, beta)
42+
mu = _chemical_potential_normalized(beta)
43+
denom = exp(beta * (x^2 - mu)) + one(beta)
44+
return inv(denom)
45+
end
46+
47+
function _general_integrand(x, nu, beta)
48+
return x * _general_fermi(x, beta) * log(abs(x - nu) / abs(x + nu))
49+
end
50+
51+
function _general_integal(nu, beta)
52+
res, _ = quadgk(x -> _general_integrand(x, nu, beta), 0.0, nu, Inf)
53+
54+
return res
55+
end
56+
57+
function _real_lindhard_nonzero_temperature(::NoApprox, ombar, qbar, bbar)
58+
num = _nu_minus(ombar, qbar)
59+
nup = _nu_plus(ombar, qbar)
60+
61+
prefac = inv(qbar)
62+
63+
res = -prefac * (_general_integal(num, bbar) - _general_integal(nup, bbar))
64+
65+
return res
66+
end
67+
68+
## Imaginary part
69+
70+
function _imag_lindhard_nonzero_temperature(::NoApprox, ombar::T, qbar::T, bbar::T) where {T <: Real}
71+
72+
prefac = -pi / (2 * qbar)
73+
74+
num = _nu_minus(ombar, qbar)
75+
nup = _nu_plus(ombar, qbar)
76+
mubar = _chemical_potential_normalized(bbar)
77+
78+
term1 = log1pexp(bbar * (mubar - num^2))
79+
term2 = log1pexp(bbar * (mubar - nup^2))
80+
81+
return prefac * (term1 - term2) / bbar
82+
83+
end
Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,28 @@
1+
function _non_deg_integal(nu, beta)
2+
mu = _chemical_potential_normalized(beta)
3+
prefac = -exp(mu * beta) / beta
4+
5+
return prefac * dawson(nu * sqrt(beta)) * sqrt(pi)
6+
end
7+
8+
function _real_lindhard_nonzero_temperature(::NonDegenerated, ombar::T, qbar::T, bbar::T) where {T <: Real}
9+
num = _nu_minus(ombar, qbar)
10+
nup = _nu_plus(ombar, qbar)
11+
12+
prefac = inv(qbar)
13+
return -prefac * (_non_deg_integal(num, bbar) - _non_deg_integal(nup, bbar))
14+
end
15+
16+
17+
function _imag_lindhard_nonzero_temperature(::NonDegenerated, ombar::T, qbar::T, bbar::T) where {T <: Real}
18+
prefac = -pi / (2 * qbar * bbar)
19+
20+
num = _nu_minus(ombar, qbar)
21+
nup = _nu_plus(ombar, qbar)
22+
mubar = _chemical_potential_normalized(bbar)
23+
24+
term1 = bbar * (mubar - num^2)
25+
term2 = bbar * (mubar - nup^2)
26+
27+
return prefac * (exp(term1) - exp(term2))
28+
end

0 commit comments

Comments
 (0)