I’m trying to take the gradient of the Power Law Cutoff Potential using Symbolics
and ModelingToolkit
. My end goal is to define an ODESystem
with this gradient. The Power Law Cutoff Potential equation is shown below. Here, \Gamma is the gamma function, and \gamma is the lower incomplete gamma function.
How can I register numerical derivative functions, so when I take the gradient there is only one independent variable?
I can define this scalar potential with the following code.
using SpecialFunctions
"""
Computes the lower incomplete gamma function.
"""
function lowergamma(a, x)
p, q = SpecialFunctions.gamma_inc(a, x)
return p * gamma(a)
end
using Symbolics, ModelingToolkit
@register_symbolic lowergamma(x::AbstractFloat, y::AbstractFloat)
@register_symbolic SpecialFunctions.gamma(x::AbstractFloat)
@variables t
u = @variables x(t) y(t) z(t)
p = @parameters G m a α c
value = G * α * m * lowergamma(3 // 2 - α // 2, (x^2 + y^2 + z^2) / c^2) /
(2 * sqrt(x^2 + y^2 + z^2) * gamma(5 // 2 - α // 2)) -
3 * G * m * lowergamma(3 // 2 - α // 2, (x^2 + y^2 + z^2) / c^2) /
(2 * sqrt(x^2 + y^2 + z^2) * gamma(5 // 2 - α // 2)) +
G * m * lowergamma(1 - α // 2, (x^2 + y^2 + z^2) / c^2) /
(c * gamma(3 // 2 - α // 2))
I then want to register the partial derivatives of lowergamma
with respect to the two arguments a
and x
.
using FiniteDiff
function Symbolics.derivative(::typeof(lowergamma), args::NTuple{2, Any}, ::Val{1})
x, y = args
return FiniteDiff.finite_difference_derivative(x -> lowergamma(x, y), x)
end
function Symbolics.derivative(::typeof(lowergamma), args::NTuple{2, Any}, ::Val{2})
x, y = args
return FiniteDiff.finite_difference_derivative(y -> lowergamma(x, y), y)
end
Finally, I try to take the gradient, and get the following error.
dvs = map(Differential(t), u)
eqs = dvs .~ Symbolics.gradient(value, u)
ERROR: MethodError: no method matching default_relstep(::Val{:central}, ::Type{Any})
Closest candidates are:
default_relstep(::Val{fdtype}, ::Type{T}) where {fdtype, T<:Number}
@ FiniteDiff ~/.julia/packages/FiniteDiff/KKEkv/src/epsilons.jl:26
default_relstep(::Type{V}, ::Any) where V
@ FiniteDiff ~/.julia/packages/FiniteDiff/KKEkv/src/epsilons.jl:25
Stacktrace:
[1] finite_difference_derivative(f::Function, x::SymbolicUtils.BasicSymbolic{…}, fdtype::Val{…}, returntype::Type, fx::Nothing, epsilon::Nothing)
@ FiniteDiff ~/.julia/packages/FiniteDiff/KKEkv/src/derivatives.jl:103
[2] derivative(::typeof(lowergamma), args::Tuple{SymbolicUtils.BasicSymbolic{…}, SymbolicUtils.BasicSymbolic{…}}, ::Val{2})
@ Main ./REPL[11]:3
[3] derivative_idx(O::SymbolicUtils.BasicSymbolic{Real}, idx::Int64)
@ Symbolics ~/.julia/packages/Symbolics/Eas9m/src/diff.jl:337
[4] expand_derivatives(O::SymbolicUtils.BasicSymbolic{Real}, simplify::Bool; occurrences::SymbolicUtils.BasicSymbolic{Real})
@ Symbolics ~/.julia/packages/Symbolics/Eas9m/src/diff.jl:253
[5] expand_derivatives(O::SymbolicUtils.BasicSymbolic{Real}, simplify::Bool; occurrences::SymbolicUtils.BasicSymbolic{Real}) (repeats 2 times)
@ Symbolics ~/.julia/packages/Symbolics/Eas9m/src/diff.jl:245
[6] expand_derivatives(O::SymbolicUtils.BasicSymbolic{Real}, simplify::Bool; occurrences::Nothing)
@ Symbolics ~/.julia/packages/Symbolics/Eas9m/src/diff.jl:245
[7] expand_derivatives(O::SymbolicUtils.BasicSymbolic{Real}, simplify::Bool)
@ Symbolics ~/.julia/packages/Symbolics/Eas9m/src/diff.jl:171
[8] gradient(O::Num, vars::Vector{Num}; simplify::Bool)
@ Symbolics ~/.julia/packages/Symbolics/Eas9m/src/diff.jl:443
[9] gradient(O::Num, vars::Vector{Num})
@ Symbolics ~/.julia/packages/Symbolics/Eas9m/src/diff.jl:442
[10] top-level scope
@ REPL[14]:1
Some type information was truncated. Use `show(err)` to see complete types.