I’ve ported a bit of code from R/Matlab/C++ to Julia a couple of times over the past few years and can get things to work, but I’m still not familiar with the best-practice, particularly around type declarations. My goal is improved efficiency – I already have working code in the 3 languages mentioned above –, but also learning more about Julia as a side-effect.
Here’s a sample of the code that’s giving me some doubts (if you spot other things that seem odd please let me know),
using Base.Threads
using LinearAlgebra
struct Material
wavelength::Array{Float64}
alpha::Array{Complex}
medium::Real
end
function lorentzian(λ, α_k, λ_k, µ_k)
- α_k*λ_k/µ_k * (1.0 - 1.0 / ( 1.0 - (λ_k/ λ)^2 - 1im*(λ_k^2 /(µ_k*λ))))
end
function alpha_bare(λ::Float64, α_inf::Float64=9.6e-39,
α_k::Float64=5.76e-38, λ_k::Float64=526.0, µ_k::Float64=1.0e4)
ε_0 = 8.854e-12
nm3 = 1e27
α_trace = α_inf
for kk in 1:length(α_k)
α_trace += lorentzian(λ, α_k[kk], λ_k[kk], µ_k[kk])
end
prefact = nm3/(4*pi*ε_0)
prefact * α_trace
end
function polarisation(E::Array{Complex{Float64}}, AlphaBlocks::Array{Complex})
N = size(AlphaBlocks,3)
Ni = size(E,2)
P = similar(E)
α_tmp = Array{Complex}(undef, (3,3))
# loop over N particles
for ii in 1:N
α_tmp = AlphaBlocks[:,:,ii]
ind = ((ii-1)*3 + 1):(ii*3)
P[ind,1:Ni] = α_tmp * E[ind,1:Ni];
end
return P
end
function extinction(kn, P::Array{Complex{Float64}}, Ein::Array{Complex})
Ni = size(P,2)
cext = Vector{Float64}(undef, Ni)
for jj in 1:Ni
cext[jj] = imag(dot(Ein[:,jj], P[:,jj])) # E^* P
end
return 4*pi*kn*cext
end
function euler_active(φ::Float64, θ::Float64, ψ::Float64)
R = Array{Float64}(undef,(3,3))
cosφ = cos(φ); cosψ = cos(ψ); cosθ = cos(θ)
sinφ = sin(φ); sinψ = sin(ψ); sinθ = sin(θ)
R[1,1] = cosφ*cosθ*cosψ - sinφ*sinψ
R[2,1] = sinφ*cosθ*cosψ + cosφ*sinψ
R[3,1] = -sinθ*cosψ
R[1,2] = -cosφ*cosθ*sinψ - sinφ*cosψ
R[2,2] = -sinφ*cosθ*sinψ + cosφ*cosψ
R[3,2] = sinθ*sinψ
R[1,3] = cosφ*sinθ
R[2,3] = sinφ*sinθ
R[3,3] = cosθ
return R
end
The core calculation deals with linear algebra of real and complex matrices, and I define a couple of custom types to wrap such objects in a convenient structure.
Some questions about the above: I’ve used things like Array{Float64}(undef,(3,3))
to initialise arrays, and P::Array{Complex{Float64}}
to specify complex types in function arguments. Are these the recommended types here? I thought I should switch to the most general type where the code might make sense, such as replacing Float64
with Real
throughout, but my code stopped working and I wasn’t able to identify or even locate the error. I find it all the more difficult to diagnose the problem that my custom struct
s cannot be redefined within a session (or can they?), so every time I change the types inside I need to restart.
Thanks for any pointers.