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