# Term symbols

AtomicLevels provides types and methods to work and determine term symbols. The "Term symbol" and "Angular momentum coupling" Wikipedia articles give a good basic overview of the terminology.

For term symbols in LS coupling, AtomicLevels provides the Term type.

AtomicLevels.TermType
struct Term

Represents a term symbol with specific parity in LS-coupling.

Only the $L$, $S$ and parity values of the symbol ${}^{2S+1}L_{J}$ are specified. To specify a level, the $J$ value would have to be specified separately. The valid $J$ values corresponding to given $L$ and $S$ fall in the following range:

$$$|L - S| \leq J \leq L+S$$$

Constructors

Term(L::Real, S::Real, parity::Union{Parity,Integer})

Constructs a Term object with the given $L$ and $S$ quantum numbers and parity. L and S both have to be convertible to HalfIntegers and parity must be of type Parity or ±1.

See also: @T_str

Properties

To access the quantum number values, you can use the .L, .S and .parity properties to access the $L$, $S$ and parity values (represented with Parity), respectively. E.g.:

julia> t = Term(2, 1//2, p"odd")
²Dᵒ

julia> t.L, t.S, t.parity
(2, 1/2, odd)
source

The Term objects can also be constructed with the @T_str string macro.

AtomicLevels.@T_strMacro
@T_str -> Term

Constructs a Term object out of its canonical string representation.

julia> T"1S"
¹S

julia> T"4Po"
⁴Pᵒ

julia> T"⁴Pᵒ"
⁴Pᵒ

julia> T"2[3/2]o" # jK coupling, common in noble gases
²[3/2]ᵒ
source

The terms function can be used to generate all possible term symbols. In the case of relativistic orbitals, the term symbols are simply the valid $J$ values, represented using the HalfInteger type.

AtomicLevels.termsFunction
terms(orb::Orbital, w::Int=one(Int))

Returns a list of valid LS term symbols for the orbital orb with w occupancy.

Examples

julia> terms(o"3d", 3)
8-element Vector{Term}:
²P
²D
²D
²F
²G
²H
⁴P
⁴F
source
terms(config)

Generate all final $LS$ terms for config.

Examples

julia> terms(c"1s")
1-element Vector{Term}:
²S

julia> terms(c"1s 2p")
2-element Vector{Term}:
¹Pᵒ
³Pᵒ

julia> terms(c"[Ne] 3d3")
7-element Vector{Term}:
²P
²D
²F
²G
²H
⁴P
⁴F
source
terms(o::RelativisticOrbital, w = 1) -> Vector{HalfInt}

Returns a sorted list of valid $J$ values of w equivalent $jj$-coupled particles on orbital o (i.e. oʷ).

When there are degeneracies (i.e. multiple states with the same $J$ and $M$ quantum numbers), the corresponding $J$ value is repeated in the output array.

Examples

julia> terms(ro"3d", 3)
3-element Vector{HalfIntegers.Half{Int64}}:
3/2
5/2
9/2

julia> terms(ro"3d-", 3)
1-element Vector{HalfIntegers.Half{Int64}}:
3/2

julia> terms(ro"4f", 4)
8-element Vector{HalfIntegers.Half{Int64}}:
0
2
2
4
4
5
6
8
source
AtomicLevels.count_termsFunction
count_terms(orbital, occupation, term)

Count how many times term occurs among the valid terms of orbital^occupation.

julia> count_terms(o"1s", 2, T"1S")
1

julia> count_terms(ro"6h", 4, 8)
4
source
AtomicLevels.multiplicityMethod
multiplicity(t::Term)

Returns the spin multiplicity of the Term t, i.e. the number of possible values of $J$ for a given value of $L$ and $S$.

Examples

julia> multiplicity(T"¹S")
1

julia> multiplicity(T"²S")
2

julia> multiplicity(T"³P")
3
source
AtomicLevels.weightMethod
weight(t::Term)

Returns the statistical weight of the Term t, i.e. the number of possible microstates: $(2S+1)(2L+1)$.

Examples

julia> weight(T"¹S")
1

julia> weight(T"²S")
2

julia> weight(T"³P")
9
source

## Term multiplicity and intermediate terms

For subshells starting with d³, a term symbol can occur multiple times, each occurrence corresponding to a different physical state (multiplicity higher than one). This happens when there are distinct ways of coupling the electrons, but they yield the same total angular momentum. E.g. a d³ subshell can be coupled in 8 different ways, two of which are both described by the ²D term symbol:

julia> terms(o"3d", 3)
8-element Vector{Term}:
²P
²D
²D
²F
²G
²H
⁴P
⁴F

julia> count_terms(o"3d", 3, T"2D")
2

The multiplicity can be even higher if more electrons and higher angular momenta are involved:

julia> count_terms(o"4f", 5, T"2Do")
5

To distinguish these subshells, extra quantum numbers must be specified. In AtomicLevels, that can be done with the IntermediateTerm type. This is primarily used when specifying the subshell couplings in CSFs.

AtomicLevels.IntermediateTermType
struct IntermediateTerm{T,S}

Represents a term together with its extra disambiguating quantum number(s), labelled by ν.

The term symbol (::T) can either be a Term (for $LS$-coupling) or a HalfInteger (for $jj$-coupling).

The disambiguating quantum number(s) (::S) can be anything as long as they are sortable (i.e. implementing isless). It is up to the user to pick a scheme that is suitable for their application. See "Disambiguating quantum numbers" in the manual for discussion on how it is used in AtomicLevels.

See also: Term, Seniority

Constructors

IntermediateTerm(term, ν)

Constructs an intermediate term with the term symbol term and disambiguating quantum number(s) ν.

Properties

To access the term symbol and the disambiguating quantum number(s), you can use the .term :: T and .ν :: S (or .nu :: S) properties, respectively. E.g.:

julia> it = IntermediateTerm(T"2D", 2)
₍₂₎²D

julia> it.term, it.ν
(²D, 2)

julia> it = IntermediateTerm(5//2, Seniority(2))
₂5/2

julia> it.term, it.nu
(5/2, ₂)
source
AtomicLevels.intermediate_termsFunction
intermediate_terms(orb::Orbital, w::Int=one(Int))

Generates all IntermediateTerm for a given non-relativstic orbital orb and occupation w.

Examples

julia> intermediate_terms(o"2p", 2)
3-element Vector{IntermediateTerm{Term, Seniority}}:
₀¹S
₂¹D
₂³P

The preceding subscript is the seniority number, which indicates at which occupancy a certain term is first seen, cf.

julia> intermediate_terms(o"3d", 1)
1-element Vector{IntermediateTerm{Term, Seniority}}:
₁²D

julia> intermediate_terms(o"3d", 3)
8-element Vector{IntermediateTerm{Term, Seniority}}:
₁²D
₃²P
₃²D
₃²F
₃²G
₃²H
₃⁴P
₃⁴F

In the second case, we see both ₁²D and ₃²D, since there are two ways of coupling 3 d electrons to a ²D symmetry.

source
intermediate_terms(config)

Generate the intermediate terms for each subshell of config.

Examples

julia> intermediate_terms(c"1s 2p3")
2-element Vector{Vector{IntermediateTerm{Term, Seniority}}}:
[₁²S]
[₁²Pᵒ, ₃²Dᵒ, ₃⁴Sᵒ]

julia> intermediate_terms(rc"3d2 5g3")
2-element Vector{Vector{IntermediateTerm{HalfIntegers.Half{Int64}, Seniority}}}:
[₀0, ₂2, ₂4]
[₁9/2, ₃3/2, ₃5/2, ₃7/2, ₃9/2, ₃11/2, ₃13/2, ₃15/2, ₃17/2, ₃21/2]
source

### Disambiguating quantum numbers

The IntermediateTerm type does not specify how to interpret the disambiguating quantum number(s) $ν$, or even what the type of it should be. In AtomicLevels, we use two different types, depending on the situation:

• A simple Integer. In this case, the quantum number $\nu$ must be in the range $1 \leq \nu \leq N_{\rm{terms}}$, where $N_{\rm{terms}}$ is the multiplicity of the term symbol (i.e. the number of times this term symbol appears for this subshell $\ell^w$ or $\ell_j^w$).

AtomicLevels does not prescribe any further interpretation for the quantum number. It can be used as a simple counter to distinguish the different terms, or the user can define their own mapping from the set of integers to physical states.

• Seniority. In this case the number is interpreted to be Racah's seniority number. This gives the intermediate term a specific physical interpretation, but only works for certain subshells. See the Seniority type for more information.

AtomicLevels.SeniorityType
Seniority(ν)

Seniority is an extra quantum number introduced by Giulio Racah (1943) to disambiguate between terms belonging to a subshell with a specific occupancy, that are assigned the same term symbols. For partially filled f-shells (in $LS$ coupling) or partially filled $9/2$ shells (in $jj$ coupling), seniority alone is not enough to disambiguate all the arising terms.

The seniority number is defined as the minimum occupancy number ν ∈ n:-2:0 for which the term first appears, e.g. the ²D term first occurs in the d¹ configuration, then twice in the d³ configuration (which will then have the terms ₁²D and ₃²D).

source

## Term couplings

The angular momentum coupling method is based on the vector model, where two angular momenta can be combined via vector addition to form a total angular momentum:

$$$\vec{J} = \vec{L} + \vec{S},$$$

where the length of the resultant momentum $\vec{J}$ obeys

$$$|L-S| \leq J \leq L+S.$$$

Relations such as these are used to couple the term symbols in both $LS$ and $jj$ coupling; however, not all values of $J$ predicted by the vector model are valid physical states, see couple_terms.

To generate the possible terms of a configuration, all the possible terms of the individual subshells, have to be coupled together to form the final terms; this is done from left-to-right. When generating all possible CSFs from a configuration, it is also necessary to find the intermediate couplings of the individual subshells. As an example, if we want to find the possible terms of 3p² 4s 5p², we first find the possible terms of the individual subshells:

julia> its = intermediate_terms(c"3p2 4s 5p2")
3-element Vector{Vector{IntermediateTerm{Term, Seniority}}}:
[₀¹S, ₂¹D, ₂³P]
[₁²S]
[₀¹S, ₂¹D, ₂³P]

where the seniority numbers are indicated as preceding subscripts. We then need to couple each intermediate term of the first subshell with each of the second subshell, and couple each of the resulting terms with each of the third subshell, and so on. E.g. coupling the ₂³P intermediate term with ₁²S produces two terms:

julia> couple_terms(T"3P", T"2S")
2-element Vector{Term}:
²P
⁴P

each of which need to be coupled with e.g. ₂¹D:

julia> couple_terms(T"2P", T"1D")
3-element Vector{Term}:
²P
²D
²F

julia> couple_terms(T"4P", T"1D")
3-element Vector{Term}:
⁴P
⁴D
⁴F

terms uses couple_terms (through AtomicLevels.final_terms) to produce all possible terms coupling trees, folding from left-to-right:

julia> a = couple_terms([T"1S", T"1D", T"3P"], [T"2S"])
4-element Vector{Term}:
²S
²P
²D
⁴P

julia> couple_terms(a, [T"1S", T"1D", T"3P"])
12-element Vector{Term}:
²S
²P
²D
²F
²G
⁴S
⁴P
⁴D
⁴F
⁶S
⁶P
⁶D

which gives the same result as

julia> terms(c"3p2 4s 5p2")
12-element Vector{Term}:
²S
²P
²D
²F
²G
⁴S
⁴P
⁴D
⁴F
⁶S
⁶P
⁶D

Note that for the generation of final terms, the intermediate terms need not be kept (and their seniority is not important). However, for the generation of CSFs, we need to form all possible combinations of intermediate terms for each subshell, and couple them, again left-to-right, to form all possible coupling chains (each one corresponding to a unique physical state). E.g. for the last term of each subshell of 3p² 4s 5p²

julia> last.(its)
3-element Vector{IntermediateTerm{Term, Seniority}}:
₂³P
₁²S
₂³P

we find the following chains:

julia> intermediate_couplings(last.(its))
15-element Vector{Vector{Term}}:
[¹S, ³P, ²P, ²S]
[¹S, ³P, ²P, ²P]
[¹S, ³P, ²P, ²D]
[¹S, ³P, ²P, ⁴S]
[¹S, ³P, ²P, ⁴P]
[¹S, ³P, ²P, ⁴D]
[¹S, ³P, ⁴P, ²S]
[¹S, ³P, ⁴P, ²P]
[¹S, ³P, ⁴P, ²D]
[¹S, ³P, ⁴P, ⁴S]
[¹S, ³P, ⁴P, ⁴P]
[¹S, ³P, ⁴P, ⁴D]
[¹S, ³P, ⁴P, ⁶S]
[¹S, ³P, ⁴P, ⁶P]
[¹S, ³P, ⁴P, ⁶D]
AtomicLevels.couple_termsFunction
couple_terms(t1, t2)

Generate all possible coupling terms between t1 and t2. It is assumed that t1 and t2 originate from non-equivalent electrons (i.e. from different subshells), since the vector model does not predict correct term couplings for equivalent electrons; some of the generated terms would violate the Pauli principle; cf. Cowan p. 108–109.

Examples

julia> couple_terms(T"1Po", T"2Se")
1-element Vector{Term}:
²Pᵒ

julia> couple_terms(T"3Po", T"2Se")
2-element Vector{Term}:
²Pᵒ
⁴Pᵒ

julia> couple_terms(T"3Po", T"2De")
6-element Vector{Term}:
²Pᵒ
²Dᵒ
²Fᵒ
⁴Pᵒ
⁴Dᵒ
⁴Fᵒ
source
couple_terms(t1s, t2s)

Generate all coupling between all terms in t1s and all terms in t2s.

source
AtomicLevels.final_termsFunction
final_terms(ts::Vector{<:Vector{<:Union{Term,Real}}})

Generate all possible final terms from the vector of vectors of individual subshell terms by coupling from left to right.

Examples

julia> ts = [[T"1S", T"3S"], [T"2P", T"2D"]]
2-element Vector{Vector{Term}}:
[¹S, ³S]
[²P, ²D]

julia> AtomicLevels.final_terms(ts)
4-element Vector{Term}:
²P
²D
⁴P
⁴D
source
AtomicLevels.intermediate_couplingsFunction
intermediate_couplings(its::Vector{IntermediateTerm,Integer,HalfInteger}, t₀ = T"1S")

Generate all intermediate coupling trees from the vector of intermediate terms its, starting from the initial term t₀.

Examples

julia> intermediate_couplings([IntermediateTerm(T"2S", 1), IntermediateTerm(T"2D", 1)])
2-element Vector{Vector{Term}}:
[¹S, ²S, ¹D]
[¹S, ²S, ³D]
source
intermediate_couplings(J::Vector{<:Real}, j₀ = 0)

Examples

julia> intermediate_couplings([1//2, 3//2])
2-element Vector{Vector{HalfIntegers.Half{Int64}}}:
[0, 1/2, 1]
[0, 1/2, 2]
source

## Levels & States

Coupling $L$ and $S$ to a total $J$, as discussed under Term couplings above, yields a Level; in $jj$ coupling, final term of the CSF already has its final $J$ given. In both coupling schemes, the same values of final $J$ will result, but via different intermediate couplings. As an example, we will consider the configuration $1s\;2p$, which in the $LS$ and $jj$ coupling schemes has the following CSFs:

julia> csls = csfs(c"1s 2p")
2-element Vector{NonRelativisticCSF{Orbital{Int64}, Seniority}}:
1s(₁²S|²S) 2p(₁²Pᵒ|¹Pᵒ)-
1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-

julia> csjj = vcat(csfs(rc"1s 2p"), csfs(rc"1s 2p-"))
4-element Vector{RelativisticCSF{RelativisticOrbital{Int64}, Seniority}}:
1s(₁1/2|1/2) 2p(₁3/2|1)-
1s(₁1/2|1/2) 2p(₁3/2|2)-
1s(₁1/2|1/2) 2p-(₁1/2|0)-
1s(₁1/2|1/2) 2p-(₁1/2|1)-

If we now generate the permissible Levels, we find the valid values of $J$, i.e. $0$, $2\times 1$, and $2$:

julia> levels.(csls)
2-element Vector{Vector{Level{Orbital{Int64}, Term, Seniority}}}:
[|1s(₁²S|²S) 2p(₁²Pᵒ|¹Pᵒ)-, J = 1⟩]
[|1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-, J = 0⟩, |1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-, J = 1⟩, |1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-, J = 2⟩]

julia> levels.(csjj)
4-element Vector{Vector{Level{RelativisticOrbital{Int64}, HalfIntegers.Half{Int64}, Seniority}}}:
[|1s(₁1/2|1/2) 2p(₁3/2|1)-, J = 1⟩]
[|1s(₁1/2|1/2) 2p(₁3/2|2)-, J = 2⟩]
[|1s(₁1/2|1/2) 2p-(₁1/2|0)-, J = 0⟩]
[|1s(₁1/2|1/2) 2p-(₁1/2|1)-, J = 1⟩]
AtomicLevels.weightMethod
weight(l::Level)

Returns the statistical weight of the Level l, i.e. the number of possible microstates: $2J+1$.

Example

julia> l = Level(first(csfs(c"1s 2p")), 1)
|1s(₁²S|²S) 2p(₁²Pᵒ|¹Pᵒ)-, J = 1⟩

julia> weight(l)
3
source
AtomicLevels.J_rangeFunction
J_range(term::Term)

List the permissible values of the total angular momentum $J$ for term.

Examples

julia> J_range(T"¹S")
0:0

julia> J_range(T"²S")
1/2:1/2

julia> J_range(T"³P")
0:2

julia> J_range(T"²D")
3/2:5/2
source
J_range(J)

The permissible range of the total angular momentum $J$ in $jj$ coupling is simply the value of $J$ for the final term.

source
AtomicLevels.levelsFunction
levels(csf)

Generate all permissible Levels given csf.

Examples

julia> levels.(csfs(c"1s 2p"))
2-element Vector{Vector{Level{Orbital{Int64}, Term, Seniority}}}:
[|1s(₁²S|²S) 2p(₁²Pᵒ|¹Pᵒ)-, J = 1⟩]
[|1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-, J = 0⟩, |1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-, J = 1⟩, |1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-, J = 2⟩]

julia> levels.(csfs(rc"1s 2p"))
2-element Vector{Vector{Level{RelativisticOrbital{Int64}, HalfIntegers.Half{Int64}, Seniority}}}:
[|1s(₁1/2|1/2) 2p(₁3/2|1)-, J = 1⟩]
[|1s(₁1/2|1/2) 2p(₁3/2|2)-, J = 2⟩]

julia> levels.(csfs(rc"1s 2p-"))
2-element Vector{Vector{Level{RelativisticOrbital{Int64}, HalfIntegers.Half{Int64}, Seniority}}}:
[|1s(₁1/2|1/2) 2p-(₁1/2|0)-, J = 0⟩]
[|1s(₁1/2|1/2) 2p-(₁1/2|1)-, J = 1⟩]
source

Similarly, by additionally specifying the projection quantum number $M_J$, we get a fully quantified State. In the same way, the permissible values of $M_J$ must agree between the coupling schemes, sorting by $M_J$ for clarity:

julia> sort(reduce(vcat, reduce(vcat, states.(csls))), by=s->s.M_J)
12-element Vector{State{Orbital{Int64}, Term, Seniority}}:
|1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-, J = 2, M_J = -2⟩
|1s(₁²S|²S) 2p(₁²Pᵒ|¹Pᵒ)-, J = 1, M_J = -1⟩
|1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-, J = 1, M_J = -1⟩
|1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-, J = 2, M_J = -1⟩
|1s(₁²S|²S) 2p(₁²Pᵒ|¹Pᵒ)-, J = 1, M_J = 0⟩
|1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-, J = 0, M_J = 0⟩
|1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-, J = 1, M_J = 0⟩
|1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-, J = 2, M_J = 0⟩
|1s(₁²S|²S) 2p(₁²Pᵒ|¹Pᵒ)-, J = 1, M_J = 1⟩
|1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-, J = 1, M_J = 1⟩
|1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-, J = 2, M_J = 1⟩
|1s(₁²S|²S) 2p(₁²Pᵒ|³Pᵒ)-, J = 2, M_J = 2⟩

julia> sort(reduce(vcat, reduce(vcat, states.(csjj))), by=s->s.M_J)
12-element Vector{State{RelativisticOrbital{Int64}, HalfIntegers.Half{Int64}, Seniority}}:
|1s(₁1/2|1/2) 2p(₁3/2|2)-, J = 2, M_J = -2⟩
|1s(₁1/2|1/2) 2p(₁3/2|1)-, J = 1, M_J = -1⟩
|1s(₁1/2|1/2) 2p(₁3/2|2)-, J = 2, M_J = -1⟩
|1s(₁1/2|1/2) 2p-(₁1/2|1)-, J = 1, M_J = -1⟩
|1s(₁1/2|1/2) 2p(₁3/2|1)-, J = 1, M_J = 0⟩
|1s(₁1/2|1/2) 2p(₁3/2|2)-, J = 2, M_J = 0⟩
|1s(₁1/2|1/2) 2p-(₁1/2|0)-, J = 0, M_J = 0⟩
|1s(₁1/2|1/2) 2p-(₁1/2|1)-, J = 1, M_J = 0⟩
|1s(₁1/2|1/2) 2p(₁3/2|1)-, J = 1, M_J = 1⟩
|1s(₁1/2|1/2) 2p(₁3/2|2)-, J = 2, M_J = 1⟩
|1s(₁1/2|1/2) 2p-(₁1/2|1)-, J = 1, M_J = 1⟩
|1s(₁1/2|1/2) 2p(₁3/2|2)-, J = 2, M_J = 2⟩
AtomicLevels.StateType
State(level, M_J)

A states defines, in addition to the total angular momentum $J$ of level, its projection $M_J\in -J..J$.

source
AtomicLevels.statesFunction

states(level)

Generate all permissible State given level.

Example

julia> l = Level(first(csfs(c"1s 2p")), 1)
|1s(₁²S|²S) 2p(₁²Pᵒ|¹Pᵒ)-, J = 1⟩

julia> states(l)
3-element Vector{State{Orbital{Int64}, Term, Seniority}}:
|1s(₁²S|²S) 2p(₁²Pᵒ|¹Pᵒ)-, J = 1, M_J = -1⟩
|1s(₁²S|²S) 2p(₁²Pᵒ|¹Pᵒ)-, J = 1, M_J = 0⟩
|1s(₁²S|²S) 2p(₁²Pᵒ|¹Pᵒ)-, J = 1, M_J = 1⟩
source
states(csf)

Directly generate all permissible States for csf.

Example

julia> c = first(csfs(c"1s 2p"))
1s(₁²S|²S) 2p(₁²Pᵒ|¹Pᵒ)-

julia> states(c)
1-element Vector{Vector{State{Orbital{Int64}, Term, Seniority}}}:
[|1s(₁²S|²S) 2p(₁²Pᵒ|¹Pᵒ)-, J = 1, M_J = -1⟩, |1s(₁²S|²S) 2p(₁²Pᵒ|¹Pᵒ)-, J = 1, M_J = 0⟩, |1s(₁²S|²S) 2p(₁²Pᵒ|¹Pᵒ)-, J = 1, M_J = 1⟩]
source