Merge branch 'main' into quadrature

This commit is contained in:
Nuwan Yapa 2025-04-16 16:27:59 -04:00
commit 61979c4521
1 changed files with 33 additions and 15 deletions

View File

@ -1,4 +1,4 @@
using DifferentialEquations, Interpolations
using LinearAlgebra, DifferentialEquations, Interpolations
include("bisection.jl")
include("common.jl")
include("system.jl")
@ -39,11 +39,26 @@ function optimized_dirac_potentials(p::Bool, s::system)
return (f1, f2)
end
"Approximate boundary condition for u(r)=[g(r), f(r)] at r -> ∞ where
κ is the generalized angular momentum,
p is true for proton and false for neutron,
E is the energy in MeV,
r is the radius in fm."
function asymp_BC(κ::Int, p::Bool, E::Float64, r::Float64)
M = p ? M_p : M_n
g = 1.0
f = ħc / (E + M) * (-(M^2 - E^2) + κ/r) * g
return [g, f]
end
"Initial boundary condition for u(r)=[g(r), f(r)] at r=0"
init_BC() = [1.0, 1.0] # TODO: Why not [0.0, 1.0]?
"Solve the Dirac equation and return the wave function u(r)=[g(r), f(r)] where
the solution would be returned as a 2×mesh_size matrix,
shooting method divides the interval into two partitions at r_max/2, ensuring convergence at both r=0 and r=r_max,
the other parameters are the same from dirac!(...)."
function solveNucleonWf(κ, p::Bool, E, s::system; normalize=true, algo=Tsit5())
function solveNucleonWf(κ, p::Bool, E, s::system; normalize=true, algo=Vern9())
(f1, f2) = optimized_dirac_potentials(p, s)
# partitioning
@ -63,16 +78,19 @@ function solveNucleonWf(κ, p::Bool, E, s::system; normalize=true, algo=Tsit5())
wf_right = reverse(hcat(sol.u...); dims=2)
# join two segments
rescale_factor_g = wf_left[1, end] / wf_right[1, 1]
rescale_factor_f = wf_left[2, end] / wf_right[2, 1]
@assert isfinite(rescale_factor_g) && isfinite(rescale_factor_f) "Cannot rescale the right partition"
isapprox(rescale_factor_g, rescale_factor_f; rtol=0.03) || @warn "Discontinuity between two partitions"
wf_right_rescaled = wf_right .* ((rescale_factor_g + rescale_factor_f) / 2)
wf = hcat(wf_left[:, 1:(end - 1)], wf_right_rescaled)
u1 = wf_left[:, end]
u2 = wf_right[:, 1]
if norm(u2) < 1e-10
@warn "Right partition too small to rescale, setting to zero"
wf_right .= 0.0
else
proj = only(u1' * u2) / norm(u2)^2
wf_right .*= proj
end
wf = hcat(wf_left[:, 1:(end - 1)], wf_right)
if normalize
norm = sum(wf .* wf .* transpose(s.r_mesh.w)) # integration by Reimann sum
wf = wf ./ sqrt(norm)
wf ./= sqrt(sum(wf .* wf .* transpose(s.r_mesh.w)))
end
return wf
@ -81,11 +99,11 @@ end
"Returns a function that solves the Dirac equation in two partitions and returns
the determinant of [g_left(r) g_right(r); f_left(r) f_right(r)],
where is r is in fm."
function determinantFunc(κ, p::Bool, s::system, r::Float64=s.r_mesh.r_max/2, algo=Tsit5())
function determinantFunc(κ, p::Bool, s::system, r::Float64=s.r_mesh.r_max/2, algo=Vern9())
(f1, f2) = optimized_dirac_potentials(p, s)
prob_left = ODEProblem(dirac!, [0.0, 1.0], (0, r))
prob_right = ODEProblem(dirac!, [0.0, 1.0], (s.r_mesh.r_max, r))
prob_left = ODEProblem(dirac!, init_BC(), (0, r))
function func(E)
prob_right = ODEProblem(dirac!, asymp_BC(κ, p, E, s.r_mesh.r_max), (s.r_mesh.r_max, r))
u_left = solve(prob_left, algo, p=(κ, E, f1, f2), saveat=[r])
u_right = solve(prob_right, algo, p=(κ, E, f1, f2), saveat=[r])
return u_left[1, 1] * u_right[2, 1] - u_right[1, 1] * u_left[2, 1]