Skip to content

Commit 724adfa

Browse files
committed
parse magnetic space groups from ISOTROPY text copy of Litvin's data
1 parent cf00fea commit 724adfa

File tree

2 files changed

+61108
-0
lines changed

2 files changed

+61108
-0
lines changed
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
#module ParseMSG
2+
3+
using Crystalline
4+
# --- definitions ---
5+
# to be transferred to Crystalline's definitions
6+
using Crystalline: AbstractGroup
7+
using StaticArrays
8+
9+
struct MSymOperation{D}
10+
op :: SymOperation{D}
11+
tr :: Bool
12+
end
13+
Base.show(io::IO, mop::MSymOperation) = (show(io, mop.op); print(io, mop.tr ? "" : ""))
14+
function Crystalline.compose(
15+
mop₁::MSymOperation{D},
16+
mop₂::MSymOperation{D},
17+
modτ::Bool=true) where D
18+
return MSymOperation{D}(compose(mop₁.op, mop₂.op, modτ), xor(mop₁.tr, mop₂.tr))
19+
end
20+
Base.:*(mop₁::MSymOperation{D}, mop₂::MSymOperation{D}) where D = compose(mop₁, mop₂)
21+
function Base.isapprox(mop₁::MSymOperation{D}, mop₂::MSymOperation{D}, vs...; kws...) where D
22+
isapprox(mop₁.op, mop₂.op, vs...; kws...) && mop₁.tr == mop₂.tr
23+
end
24+
struct MSpaceGroup{D} <: AbstractGroup{D}
25+
# Note: we use BNS numbers, not OG numbers (see Sec. 4, Acta Cryst. A78, 99 (2022))
26+
# BNS number: `num[1]`: F space-group associated number
27+
# `num[2]`: crystal-system sequential number
28+
num :: Tuple{Int, Int}
29+
operations :: Vector{MSymOperation{D}}
30+
end
31+
Crystalline.label(msg::MSpaceGroup) = MSG_BNS_LABELs_D[msg.num]::String
32+
# --- parsing ---
33+
#cd(@__DIR__)
34+
io = open((@__DIR__)*"/../data/operations/msgs/iso-magnetic_table_bns.txt")
35+
36+
# --- read dictionary of operations ---
37+
function read_ops!(io, ops_d, stop_string)
38+
while (str=readline(io); str stop_string)
39+
parts = split(str, isspace; keepempty=false)
40+
code, xyz = parts[1], parts[2]
41+
op = SymOperation(xyz)
42+
ops_d[code] = op
43+
end
44+
return ops_d
45+
end
46+
47+
readuntil(io, "Non-hexagonal groups:"); readline(io)
48+
nonhex_ops_d = Dict{String, SymOperation{3}}()
49+
read_ops!(io, nonhex_ops_d, "Hexagonal groups:")
50+
hex_ops_d = Dict{String, SymOperation{3}}()
51+
read_ops!(io, hex_ops_d, "----------")
52+
53+
# --- read individual groups ---
54+
function parse_opstr(str::AbstractString, ops_d)
55+
str′ = strip(str, ['(', ')','\''])
56+
code, translation_str = split(str′, '|')::Vector{SubString{String}}
57+
translation_parts = split(translation_str, ',')
58+
translation_tup = ntuple(Val(3)) do i
59+
Crystalline.parsefraction(translation_parts[i])
60+
end
61+
translation = SVector{3, Float64}(translation_tup)
62+
op = SymOperation{3}(ops_d[code].rotation, translation)
63+
tr = last(str) == '\''
64+
return MSymOperation(op, tr)
65+
end
66+
67+
function read_group!(io)
68+
# BNS: number & label
69+
readuntil(io, "BNS: ")
70+
num_str = readuntil(io, " ") # numbering in format `sgnum.cnum`
71+
sgnum, cnum = parse.(Int, split(num_str, "."))::Vector{Int}
72+
bns_label = replace(readuntil(io, " "), '\''=>'') # BNS label in IUC-style
73+
74+
# OG: number and label
75+
readuntil(io, "OG: ")
76+
N₁N₂N₃_str = readuntil(io, " ") # numbering in format `N₁.N₂.N₃`
77+
N₁, N₂, N₃ = parse.(Int, split(N₁N₂N₃_str, "."))::Vector{Int}
78+
og_label = replace(readuntil(io, '\n'), '\''=>'') # OG label in IUC-style
79+
80+
# operator strings
81+
is_hex = crystalsystem(sgnum) ("hexagonal" , "trigonal")
82+
readuntil(io, "Operators")
83+
c = read(io, Char)
84+
if c == ' '
85+
readuntil(io, "(BNS):")
86+
elseif c ':'
87+
error("unexpected parsing failure")
88+
end
89+
ops_str = readuntil(io, "Wyckoff")
90+
op_strs = split(ops_str, isspace; keepempty=false)
91+
92+
# parse operator strings to operations
93+
g = Vector{MSymOperation{3}}(undef, length(op_strs))
94+
for (i, str) in enumerate(op_strs)
95+
g[i] = parse_opstr(str, is_hex ? hex_ops_d : nonhex_ops_d)
96+
isdone = str[end] == '\n'
97+
isdone && break
98+
end
99+
100+
return MSpaceGroup{3}((sgnum, cnum), g), bns_label, og_label, (N₁, N₂, N₃)
101+
end
102+
msgs = MSpaceGroup{3}[]
103+
MSG_BNS_LABELs_D = Dict{Tuple{Int, Int}, String}()
104+
MSG_OG_LABELs_D = Dict{Tuple{Int, Int, Int}, String}()
105+
MSG_BNS2OG_NUMs_D = Dict{Tuple{Int, Int}, Tuple{Int, Int, Int}}()
106+
for i in 1:1651
107+
msg, bns_label, og_label, (N₁, N₂, N₃) = read_group!(io)
108+
push!(msgs, msg)
109+
MSG_BNS_LABELs_D[msg.num] = bns_label
110+
MSG_OG_LABELs_D[(N₁, N₂, N₃)] = og_label
111+
MSG_BNS2OG_NUMs_D[msg.num] = (N₁, N₂, N₃)
112+
end
113+
114+
#end # module ParseMSG

0 commit comments

Comments
 (0)