Skip to content

Commit

Permalink
Added power variogram fit function
Browse files Browse the repository at this point in the history
  • Loading branch information
stepanoslejsek committed Oct 22, 2024
1 parent 55af8c3 commit bc7f905
Showing 1 changed file with 85 additions and 0 deletions.
85 changes: 85 additions & 0 deletions src/fitting.jl
Original file line number Diff line number Diff line change
Expand Up @@ -192,3 +192,88 @@ function fit_impl(

γ, ϵ
end

function fit_impl(
V::Type{<:PowerVariogram},
g::EmpiricalVariogram,
algo::WeightedLeastSquares;
scale=nothing,
exponent=nothing,
nugget=nothing,
maxscale=nothing,
maxexponent=nothing,
maxnugget=nothing
)
# coordinates of empirical variogram
x = g.abscissas
y = g.ordinates
n = g.counts

# discard invalid bins
x = x[n .> 0]
y = y[n .> 0]
n = n[n .> 0]

# strip units of coordinates
ux = unit(eltype(x))
uy = unit(eltype(y))
x′ = ustrip.(x)
y′ = ustrip.(y)

# strip units of kwargs
scale′ = isnothing(scale) ? scale : ustrip(ux, scale)
exponent′ = isnothing(exponent) ? exponent : ustrip(uy, exponent)
nugget′ = isnothing(nugget) ? nugget : ustrip(uy, nugget)
maxscale′ = isnothing(maxscale) ? maxscale : ustrip(ux, maxscale)
maxexponent′ = isnothing(maxexponent) ? maxexponent : ustrip(uy, maxexponent)
maxnugget′ = isnothing(maxnugget) ? maxnugget : ustrip(uy, maxnugget)

# evaluate weights
f = algo.weightfun
w = isnothing(f) ? n / sum(n) : map(xᵢ -> ustrip(f(xᵢ)), x)

# objective function
function J(θ)
γ = V(scaling=θ[1], nugget=θ[2], exponent=θ[3])
sum(i -> w[i] * (γ(x′[i]) - y′[i])^2, eachindex(w, x′, y′))
end

# Linear constraints
# 1. scaling ≥ 0
# 2. 0 ≤ exponent ≤ 2
L(θ) = [θ[1] 0.0 ? 0.0 : -θ[1], θ[3] 0.0 ? 0.0 : -θ[3], 2.0 >= θ[3] ? 0.0 : θ[3] - 2.0]

# penalty for linear constraint (J + λL)
λ = fill(sum(yᵢ -> yᵢ^2, y′), 3)

# maximum scaling, nugget and exponent
xmax = maximum(x′)
ymax = maximum(y′)
smax = isnothing(maxscale′) ? xmax : maxscale′
emax = isnothing(maxexponent′) ? 2.0 : maxexponent′
nmax = isnothing(maxnugget′) ? ymax : maxnugget′

# initial guess
sₒ = isnothing(scale′) ? smax / 3 : scale′
eₒ = isnothing(exponent′) ? 0.95 * emax : exponent′
nₒ = isnothing(nugget′) ? 0.01 * nmax : nugget′
θₒ = [sₒ, eₒ, nₒ]

# box constraints
δ = 1e-8
sₗ, sᵤ = isnothing(scale′) ? (zero(smax), smax) : (scale′ - δ, scale′ + δ)
eₗ, eᵤ = isnothing(exponent′) ? (zero(emax), emax) : (exponent′ - δ, exponent′ + δ)
nₗ, nᵤ = isnothing(nugget′) ? (zero(nmax), nmax) : (nugget′ - δ, nugget′ + δ)
l = [sₗ, eₗ, nₗ]
u = [sᵤ, eᵤ, nᵤ]

# solve optimization problem
sol = Optim.optimize-> J(θ) + λ' * L(θ), l, u, θₒ)
ϵ = Optim.minimum(sol)
θ = Optim.minimizer(sol)

# optimal variogram (with units)
γ = V(scaling=θ[1], nugget=θ[2], exponent=θ[3])

γ, ϵ
end

0 comments on commit bc7f905

Please sign in to comment.