From b9a4f7983a8bac45a2d4013115bd4a147f0a5a45 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Stefanos=20Carlstr=C3=B6m?= Date: Wed, 24 Mar 2021 08:18:11 +0100 Subject: [PATCH] Support Unicode subscripts when parsing spin-{orbitals,configurations} (#41) --- src/AtomicLevels.jl | 1 + src/spin_orbitals.jl | 16 +++++++++++++--- src/unicode.jl | 17 +++++++++++++++++ test/orbitals.jl | 20 ++++++++++++++++++++ test/runtests.jl | 5 +++++ 5 files changed, 56 insertions(+), 3 deletions(-) create mode 100644 src/unicode.jl diff --git a/src/AtomicLevels.jl b/src/AtomicLevels.jl index de40060..cfa72fc 100644 --- a/src/AtomicLevels.jl +++ b/src/AtomicLevels.jl @@ -9,6 +9,7 @@ using HalfIntegers using Combinatorics include("common.jl") +include("unicode.jl") include("parity.jl") include("orbitals.jl") include("relativistic_orbitals.jl") diff --git a/src/spin_orbitals.jl b/src/spin_orbitals.jl index fe73bb1..e0dd96e 100644 --- a/src/spin_orbitals.jl +++ b/src/spin_orbitals.jl @@ -132,9 +132,19 @@ end function Base.parse(::Type{O}, orb_str) where {OO<:AbstractOrbital,O<:SpinOrbital{OO}} m = match(r"^(.*)\((.*)\)$", orb_str) - m === nothing && throw(ArgumentError("Invalid spin-orbital string: $(orb_str)")) - o = parse(OO, m[1]) - SpinOrbital(o, (split(m[2], ",")...,)) + # For non-relativistic spin-orbitals, we also support specifying + # the m_ℓ quantum number using Unicode subscripts and the spin + # label using α/β + m2 = match(r"^(.*?)([₋]{0,1}[₁₂₃₄₅₆₇₈₉₀]+)([αβ])$", orb_str) + if !isnothing(m) + o = parse(OO, m[1]) + SpinOrbital(o, (split(m[2], ",")...,)) + elseif !isnothing(m2) && OO <: Orbital + o = parse(OO, m2[1]) + SpinOrbital(o, from_subscript(m2[2]), m2[3]) + else + throw(ArgumentError("Invalid spin-orbital string: $(orb_str)")) + end end """ diff --git a/src/unicode.jl b/src/unicode.jl new file mode 100644 index 0000000..d956f84 --- /dev/null +++ b/src/unicode.jl @@ -0,0 +1,17 @@ +function from_subscript(s) + inverse_subscript_map = Dict('₋' => '-', '₊' => '+', '₀' => '0', + '₁' => '1', '₂' => '2', '₃' => '3', + '₄' => '4', '₅' => '5', '₆' => '6', + '₇' => '7', '₈' => '8', '₉' => '9', + '₀' => '0') + map(Base.Fix1(getindex, inverse_subscript_map), s) +end + +function from_superscript(s) + inverse_superscript_map = Dict('⁻' => '-', '⁺' => '+', '⁰' => '0', + '¹' => '1', '²' => '2', '³' => '3', + '⁴' => '4', '⁵' => '5', '⁶' => '6', + '⁷' => '7', '⁸' => '8', '⁹' => '9', + '⁰' => '0') + map(Base.Fix1(getindex, inverse_superscript_map), s) +end diff --git a/test/orbitals.jl b/test/orbitals.jl index c9eb33e..b4fb548 100644 --- a/test/orbitals.jl +++ b/test/orbitals.jl @@ -311,6 +311,26 @@ using Random @test parse(SpinOrbital{Orbital}, "1s(0,α)") == SpinOrbital(Orbital(1, 0), (0, up)) @test parse(SpinOrbital{Orbital{Int}}, "1s(0,α)") == SpinOrbital(Orbital(1, 0), (0, up)) @test parse(SpinOrbital{Orbital{Symbol}}, "ks(0,α)") == SpinOrbital(Orbital(:k, 0), (0, up)) + + @test so"1s₀β" == so"1s(0,β)" + @test so"2p₋₁α" == so"2p(-1,α)" + @test so"k[31]₋₁₃α" == so"k[31](-13,α)" + + for o in [SpinOrbital(o"1s", (0,-1/2)), + SpinOrbital(o"1s", (0,1/2)), + SpinOrbital(o"2p", (1,-1/2)), + SpinOrbital(ro"1s", (1/2)), + SpinOrbital(ro"2p", (3/2)), + SpinOrbital(ro"3d", (5/2)), + SpinOrbital(ro"3d-", (-3/2)), + SpinOrbital(ro"3p", (-1/2)), + SpinOrbital(ro"3p", (-3/2)), + SpinOrbital(ro"3p", (1/2)), + SpinOrbital(ro"3p-", (-1/2)), + SpinOrbital(ro"3p-", (1/2))] + O = typeof(o.orb) + @test parse(SpinOrbital{O}, string(o)) == o + end end end diff --git a/test/runtests.jl b/test/runtests.jl index 9db9814..dcb8f52 100644 --- a/test/runtests.jl +++ b/test/runtests.jl @@ -3,6 +3,11 @@ using WignerSymbols using HalfIntegers using Test +@testset "Unicode super-/subscripts" begin + @test AtomicLevels.from_subscript("₋₊₁₂₃₄₅₆₇₈₉₀") == "-+1234567890" + @test AtomicLevels.from_superscript("⁻⁺¹²³⁴⁵⁶⁷⁸⁹⁰") == "-+1234567890" +end + include("parity.jl") include("orbitals.jl") include("configurations.jl")