1
0
Fork 0
mirror of https://gitlab.rlp.net/mobitar/ReCo.jl.git synced 2024-12-21 00:51:21 +00:00
ReCo.jl/src/Shape.jl

136 lines
3.8 KiB
Julia
Raw Normal View History

2021-12-15 19:50:18 +00:00
module Shape
2022-01-06 23:28:40 +00:00
export center_of_mass,
gyration_tensor_eigvals_ratio, gyration_tensor_eigvecs, elliptical_distance
2021-12-15 19:50:18 +00:00
2021-12-03 13:41:01 +00:00
using StaticArrays: SVector, SMatrix
2022-01-06 23:28:40 +00:00
using LinearAlgebra: eigvals, eigvecs, Hermitian, dot
2021-12-03 13:16:35 +00:00
2022-01-14 12:26:51 +00:00
using ..ReCo: ReCo, Particle
2021-12-15 19:50:18 +00:00
2022-01-18 01:17:52 +00:00
function project_to_unit_circle(x::Real, half_box_len::Real)
2021-12-10 02:16:18 +00:00
φ = (x + half_box_len) * π / half_box_len
2021-12-08 20:53:15 +00:00
si, co = sincos(φ)
2022-01-06 23:28:40 +00:00
2021-12-08 20:53:15 +00:00
return SVector(co, si)
2021-12-03 13:16:35 +00:00
end
2022-01-18 01:17:52 +00:00
function project_back_from_unit_circle(θ::Real, half_box_len::Real)
2021-12-10 02:16:18 +00:00
x = θ * half_box_len / π - half_box_len
2022-01-06 23:28:40 +00:00
2022-01-14 12:01:14 +00:00
return ReCo.restrict_coordinate(x, half_box_len)
2021-12-03 13:16:35 +00:00
end
2021-12-28 16:13:31 +00:00
function center_of_mass_from_proj_sums(
2022-01-18 01:33:11 +00:00
x_proj_sum::SVector{2,R}, y_proj_sum::SVector{2,R}, half_box_len::R
) where {R<:Real}
2021-12-03 13:16:35 +00:00
# Prevent for example atan(1e-16, 1e-15) != 0 with rounding
digits = 5
2021-12-10 02:16:18 +00:00
# No need for 1/n_particles with atan
2021-12-03 13:16:35 +00:00
# If proj is (0, 0) then COM is 0 or L or -L. Here, 0 is choosen with θ = π
2021-12-04 15:19:14 +00:00
if round(x_proj_sum[1]; digits=digits) == round(x_proj_sum[2]; digits=digits) == 0
2021-12-03 13:16:35 +00:00
x_θ = π
else
x_θ = atan(x_proj_sum[2], x_proj_sum[1])
end
2021-12-04 15:19:14 +00:00
if round(y_proj_sum[1]; digits=digits) == round(y_proj_sum[2]; digits=digits) == 0
2021-12-03 13:16:35 +00:00
y_θ = π
else
y_θ = atan(y_proj_sum[2], y_proj_sum[1])
end
2021-12-10 02:16:18 +00:00
COM_x = project_back_from_unit_circle(x_θ, half_box_len)
COM_y = project_back_from_unit_circle(y_θ, half_box_len)
2021-12-08 20:53:15 +00:00
return SVector(COM_x, COM_y)
2021-12-03 13:41:01 +00:00
end
2022-01-18 01:33:11 +00:00
function center_of_mass(
centers::AbstractVector{SVector{2,R}}, half_box_len::R
) where {R<:Real}
2021-12-28 16:13:31 +00:00
x_proj_sum = SVector(0.0, 0.0)
y_proj_sum = SVector(0.0, 0.0)
for c in centers
x_proj_sum += project_to_unit_circle(c[1], half_box_len)
y_proj_sum += project_to_unit_circle(c[2], half_box_len)
end
return center_of_mass_from_proj_sums(x_proj_sum, y_proj_sum, half_box_len)
end
2022-01-18 01:17:52 +00:00
function center_of_mass(particles::AbstractVector{Particle}, half_box_len::Real)
2021-12-28 16:13:31 +00:00
x_proj_sum = SVector(0.0, 0.0)
y_proj_sum = SVector(0.0, 0.0)
for p in particles
x_proj_sum += project_to_unit_circle(p.c[1], half_box_len)
y_proj_sum += project_to_unit_circle(p.c[2], half_box_len)
end
return center_of_mass_from_proj_sums(x_proj_sum, y_proj_sum, half_box_len)
end
2022-01-14 12:01:14 +00:00
function gyration_tensor(
2022-01-18 01:33:11 +00:00
particles::AbstractVector{Particle}, half_box_len::R, COM::SVector{2,R}
) where {R<:Real}
2021-12-03 13:41:01 +00:00
S11 = 0.0
S12 = 0.0
S22 = 0.0
2021-12-08 20:53:15 +00:00
for p in particles
2022-01-14 12:01:14 +00:00
shifted_c = ReCo.restrict_coordinates(p.c - COM, half_box_len)
2021-12-03 13:41:01 +00:00
2021-12-08 20:53:15 +00:00
S11 += shifted_c[1]^2
S12 += shifted_c[1] * shifted_c[2]
S22 += shifted_c[2]^2
2021-12-03 13:41:01 +00:00
end
2021-12-04 15:19:14 +00:00
return Hermitian(SMatrix{2,2}(S11, S12, S12, S22))
end
2022-01-18 01:17:52 +00:00
function gyration_tensor(particles::AbstractVector{Particle}, half_box_len::Real)
2022-01-14 12:01:14 +00:00
COM = center_of_mass(particles, half_box_len)
return gyration_tensor(particles, half_box_len, COM)
end
2022-01-18 01:17:52 +00:00
function gyration_tensor_eigvals_ratio(
particles::AbstractVector{Particle}, half_box_len::Real
)
2022-01-06 23:28:40 +00:00
g_tensor = gyration_tensor(particles, half_box_len)
ev = eigvals(g_tensor) # Eigenvalues are sorted
2021-12-04 15:19:14 +00:00
return ev[1] / ev[2]
2021-12-15 19:50:18 +00:00
end
2022-01-14 12:01:14 +00:00
function gyration_tensor_eigvecs(
2022-01-18 01:33:11 +00:00
particles::AbstractVector{Particle}, half_box_len::R, COM::SVector{2,R}
) where {R<:Real}
2022-01-14 12:01:14 +00:00
g_tensor = gyration_tensor(particles, half_box_len, COM)
2022-01-06 23:28:40 +00:00
eig_vecs = eigvecs(g_tensor)
v1 = eig_vecs[:, 1]
v2 = eig_vecs[:, 2]
return (v1, v2)
end
function elliptical_distance(
2022-01-18 01:33:11 +00:00
v::SVector{2,R},
COM::SVector{2,R},
gyration_tensor_eigvec_to_smaller_eigval::SVector{2,R},
gyration_tensor_eigvec_to_bigger_eigval::SVector{2,R},
goal_gyration_tensor_eigvals_ratio::R,
half_box_len::R,
) where {R<:Real}
2022-01-14 12:01:14 +00:00
v = ReCo.minimum_image(v - COM, half_box_len)
x = dot(v, gyration_tensor_eigvec_to_bigger_eigval)
y = dot(v, gyration_tensor_eigvec_to_smaller_eigval)
2022-01-06 23:28:40 +00:00
2022-01-14 12:26:51 +00:00
return sqrt(x^2 + (y / goal_gyration_tensor_eigvals_ratio)^2)
2022-01-06 23:28:40 +00:00
end
2021-12-15 19:50:18 +00:00
end # module