Skip to content

Group Construction

symel_gen

symel_gen.py — Public API for symmetry-element generation.

This module exposes a single public function, pg_to_symels(), which maps a Schoenflies point-group symbol to its list of Symel objects.

Internal logic is split across three focused sub-modules: group_algebra.py — arithmetic (_omega, _mult_iCnm, …) cyclic_dihedral.py — _Zn, _Dihn, _direct_product cubic_icosahedral.py — T/O/I family generators and precomputed tuples

pg_to_symels

pg_to_symels(PG)

Return the list of symmetry elements for the given point group.

Parameters:

  • PG (str) –

    Schoenflies point group symbol (e.g. "C2v", "D6h", "Oh").

Returns:

Source code in minimalsym/core/symel_gen.py
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
def pg_to_symels(PG):
    """
    Return the list of symmetry elements for the given point group.

    Parameters
    ----------
    PG : str
        Schoenflies point group symbol (e.g. "C2v", "D6h", "Oh").

    Returns
    -------
    List[Symel]
    """
    pg = PointGroup.from_string(PG)
    argerr = f"Invalid point group or unexpected parse result: {pg.str}"
    z = np.array([0, 0, 1])
    i = Symel("i", None, inversion_matrix(), 0, 0, "i")
    sh = Symel("sigma_h", np.array([0, 0, 1]), reflection_matrix(z), 0, 0, "sigma_h")
    if pg.is_linear:
        if pg.family == "C":
            return [Symel("C", z, None, None, None, None),
                    Symel("sigma_v", None, None, None, None, None)]
        elif pg.family == "D":
            return [Symel("C", z, None, None, None, None),
                    Symel("sigma_v", None, None, None, None, None),
                    Symel("S", z, None, None, None, None),
                    Symel("C_2'", None, None, None, None, None)]
    if pg.n is not None:
        n_is_even = (pg.n % 2 == 0)
        n_is_doubleeven = (pg.n % 4 == 0)
    if pg.family == "C":
        if pg.subfamily == "h":
            cn_symels = _Zn(pg.n, "C")
            if n_is_even:
                return _direct_product(cn_symels, i)
            else:
                return _direct_product(cn_symels, sh)
        elif pg.subfamily == "v":
            return _Dihn(pg.n, "C", "sigma_v")
        elif pg.subfamily == "s":
            return [Symel("E", None, np.eye(3), 0, None, "E"), sh]
        elif pg.subfamily == "i":
            return [Symel("E", None, np.eye(3), 0, None, "E"), i]
        elif pg.subfamily is None:
            return _Zn(pg.n, "C")
        else:
            raise Exception(argerr)
    elif pg.family == "D":
        if pg.subfamily == "h":
            dn_symels = _Dihn(pg.n, "C", "C_2'")
            if n_is_even:
                return _direct_product(dn_symels, i)
            else:
                return _direct_product(dn_symels, sh)
        elif pg.subfamily == "d":
            if n_is_even:
                return _Dihn(pg.n * 2, "S", "C_2'")
            else:
                dn_symels = _Dihn(pg.n, "C", "C_2'")
                return _direct_product(dn_symels, i)
        elif pg.subfamily is None:
            return _Dihn(pg.n, "C", "C_2'")
        else:
            raise Exception(argerr)
    elif pg.family == "S":
        if pg.subfamily is None and n_is_even:
            if n_is_doubleeven:
                return _Zn(pg.n, "S")
            else:
                cn_symels = _Zn(pg.n >> 1, "C")
                return _direct_product(cn_symels, i)
        else:
            raise Exception(argerr)
    else:
        if pg.family == "T":
            if pg.subfamily == "h":
                return TH_SYMELS
            elif pg.subfamily == "d":
                return TD_SYMELS
            else:
                return T_SYMELS
        elif pg.family == "O":
            if pg.subfamily == "h":
                return OH_SYMELS
            else:
                return O_SYMELS
        elif pg.family == "I":
            if pg.subfamily == "h":
                return IH_SYMELS
            else:
                return I_SYMELS
        else:
            raise Exception(argerr)

cyclic_dihedral

cyclic_dihedral.py — Generators for cyclic (Zn/Cn/Sn), dihedral, and direct-product groups.

Public functions: _Zn, _Dihn, _direct_product

_Zn

_Zn(n, generator)

Build symmetry elements for cyclic groups generated by C_n or S_n.

Parameters:

  • n (int) –

    Order of the principal axis.

  • generator (str) –

    Principal generator; either "C" for proper rotations or "S" for improper rotations.

Returns:

Source code in minimalsym/core/cyclic_dihedral.py
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
def _Zn(n, generator):
    """
    Build symmetry elements for cyclic groups generated by C_n or S_n.

    Parameters
    ----------
    n : int
        Order of the principal axis.
    generator : str
        Principal generator; either "C" for proper rotations or "S" for improper rotations.

    Returns
    -------
    List[Symel]
    """
    x, y, z = np.eye(3)
    symels = [Symel("E", None, np.eye(3, dtype=np.float64), 0, n, "E")]
    if generator == "C" and n > 1:
        cn1 = Symel(f"C_{n}", z, Cn(z, n), 1, n, "E")
        symels.append(cn1)
        for m in range(2, n):
            a, b = reduce(n, m)
            symb = f"C_{a}" if b == 1 else f"C_{a}^{b}"
            symels.append(Symel(symb, z, matrix_power(Cn(z, n), m), m, n, "E"))
    elif generator == "S":
        sn1 = Symel(f"S_{n}", z, Sn(z, n), 1, n, "E")
        symels.append(sn1)
        for m in range(2, n):
            a, b = reduce(n, m)
            symb = f"C_{a}^{b}" if m % 2 == 0 else f"S_{a}^{b}"
            if b == 1:
                symb = symb.replace("^1", "")
            symels.append(Symel(symb, z, matrix_power(Sn(z, n), m), m, n, "E"))
    return symels

_Dihn

_Dihn(n, generator, symel_tag)

Build symmetry elements for dihedral-isomorphic groups.

Parameters:

  • n (int) –

    Order of the principal axis.

  • generator (str) –

    Principal generator; either "C" for proper rotations or "S" for improper rotations.

  • symel_tag (str) –

    Secondary generator label; either "sigma_v" or "C_2'".

Returns:

Source code in minimalsym/core/cyclic_dihedral.py
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
def _Dihn(n, generator, symel_tag):
    """
    Build symmetry elements for dihedral-isomorphic groups.

    Parameters
    ----------
    n : int
        Order of the principal axis.
    generator : str
        Principal generator; either "C" for proper rotations or "S" for improper rotations.
    symel_tag : str
        Secondary generator label; either "sigma_v" or "C_2'".

    Returns
    -------
    List[Symel]
    """
    x, y, z = np.eye(3)
    symels = [Symel("E", None, np.eye(3, dtype=np.float64), 0, n, "E")]
    if generator == "C":
        if symel_tag == "sigma_v":
            post = "sigma"
            on0 = Symel("sigma_v(0)", y, reflection_matrix(y), 0, n, "sigma_v")
            tag_re = ("v", "d")
        elif symel_tag == "C_2'":
            post = "C_2"
            on0 = Symel(f"C_2'(0)", x, Cn(x, 2), 0, n, "C_2'")
            tag_re = ("'", "''")
        if n % 2 == 0:
            rsymb = symel_tag.replace(tag_re[0], tag_re[1]) + "(0)"
        else:
            rsymb = symel_tag + f"({(n>>1)+1})"
        symels.append(on0)
        for m in range(1, n):
            a, b = reduce(n, m)
            symb = f"C_{a}" if b == 1 else f"C_{a}^{b}"
            rot = matrix_power(Cn(z, n), m)
            symels.insert(m, Symel(symb, z, matrix_power(Cn(z, n), m), m, n, "E"))
            rsymb = _mult_CSC2sigma(m, n, "C", post)
            new_vector = np.dot(matrix_power(Cn(z, 2*n), m), on0.vector)
            symels.append(Symel(rsymb, new_vector, rot @ on0.rrep, m, n, symel_tag))
    elif generator == "S":
        sn1 = Symel(f"S_{n}", z, Sn(z, n), 1, n, "E")
        symels.append(sn1)
        on0 = Symel("C_2'(0)", x, Cn(x, 2), 0, n, "C_2'")
        symels.append(on0)
        v = np.dot(Cn(z, 2*n), y)
        on1 = Symel("sigma_d(0)", v, reflection_matrix(v), 1, n, "C_2'")
        symels.append(on1)
        for m in range(2, n):
            a, b = reduce(n, m)
            if m % 2 == 0:
                symb = f"C_{a}^{b}"
                rsymb = f"C_2'({m>>1})"
                rot = matrix_power(Cn(z, n), m)
                vec = np.dot(matrix_power(Cn(z, n), m>>1), on0.vector)
                rrep = rot @ on0.rrep
                insert_idx = -(m>>1)
            else:
                symb = f"S_{a}^{b}"
                rsymb = f"sigma_d({m>>1})"
                rot = matrix_power(Cn(z, n), m-1)
                vec = np.dot(matrix_power(Cn(z, n), m>>1), on1.vector)
                rrep = rot @ on1.rrep
                insert_idx = len(symels)+1
            if b == 1:
                symb = symb.replace("^1", "")
            symels.insert(m, Symel(symb, z, matrix_power(Sn(z, n), m), m, n, "E"))
            symels.insert(insert_idx, Symel(rsymb, vec, rrep, m, n, symel_tag))
    else:
        raise Exception(f"Invalid generator {generator}")
    return symels

_direct_product

_direct_product(symels, dpsymel)

Extend a set of symels by taking the direct product with a group of order 2.

Parameters:

  • symels (List[Symel]) –

    Symmetry elements of the base group.

  • dpsymel (Symel) –

    The non-identity element of the order-2 factor group (i or sigma_h).

Returns:

Source code in minimalsym/core/cyclic_dihedral.py
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
def _direct_product(symels, dpsymel):
    """
    Extend a set of symels by taking the direct product with a group of order 2.

    Parameters
    ----------
    symels : List[Symel]
        Symmetry elements of the base group.
    dpsymel : Symel
        The non-identity element of the order-2 factor group (i or sigma_h).

    Returns
    -------
    List[Symel]
    """
    z = np.array([0, 0, 1], dtype=np.float64)
    newsymels = list(symels)
    for symel in symels:
        new_rrep = symel.rrep @ dpsymel.rrep
        if dpsymel.symbol == "i":
            if symel.O == "E":
                b, a = _mult_iCnm(symel.m, symel.n)
                if a == 2:
                    new_symbol, new_vector = "i", None
                elif a == 1:
                    new_symbol, new_vector = "sigma_h", z
                else:
                    new_symbol = f"S_{a}" if b == 1 else f"S_{a}^{b}"
                    new_vector = symel.vector
                new_O = dpsymel.symbol
            elif symel.O == "C_2'":
                new_symbol = _mult_CSC2sigma(symel.m, symel.n, "iC", "C_2")
                new_vector = symel.vector
                new_O = dpsymel.symbol
        elif dpsymel.symbol == "sigma_h":
            if symel.O == "E":
                new_O = "sigma_h"
                b, a = _mult_sigmahCnm(symel.m, symel.n)
                if a == 1:
                    new_symbol, new_vector = "sigma_h", z
                else:
                    new_symbol = f"S_{a}" if b == 1 else f"S_{a}^{b}"
                    new_vector = symel.vector
            elif symel.O == "C_2'":
                new_vector = normalize(np.cross(z, symel.vector))
                new_symbol = symel.symbol.replace("C_2'", "sigma_v")
                new_O = "sigma_v"
        else:
            raise Exception(f"Invalid direct product element: {dpsymel.symbol}")
        newsymels.append(Symel(new_symbol, new_vector, new_rrep, symel.m, symel.n, new_O))
    return newsymels

cubic_icosahedral

cubic_icosahedral.py — Generators for cubic (T, O) and icosahedral (I) point groups.

Precomputed tuples T_SYMELS, TD_SYMELS, TH_SYMELS, O_SYMELS, OH_SYMELS, I_SYMELS, IH_SYMELS are built once at import time and reused by symel_gen.py.

_icosahedron_vectors

_icosahedron_vectors()

Vectors defining the faces, vertices, and edge centers of a regular icosahedron/dodecahedron.

Returns:

  • tuple(List[array], List[array], List[array])

    Face axes (6), vertex axes (10), and edge-center axes (15).

Source code in minimalsym/core/cubic_icosahedral.py
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
def _icosahedron_vectors():
    """
    Vectors defining the faces, vertices, and edge centers of a regular icosahedron/dodecahedron.

    Returns
    -------
    : tuple(List[np.array], List[np.array], List[np.array])
        Face axes (6), vertex axes (10), and edge-center axes (15).
    """
    s5   = np.sqrt(5)
    phi  = (1 + s5) / 2           # golden ratio phi = (1+sqrt(5))/2

    r5   = 1 / s5                 # 1/sqrt(5), appears 7 times
    r3   = 1 / np.sqrt(3)         # 1/sqrt(3), appears 4 times

    sp10 = np.sqrt((5 + s5) / 10) # sqrt((5+sqrt(5))/10), appears 10 times
    sm10 = np.sqrt((5 - s5) / 10) # sqrt((5-sqrt(5))/10), appears 10 times
    vp   = np.sqrt((5 + 2*s5) / 15) # sqrt((5+2*sqrt(5))/15), appears 5 times
    vm   = np.sqrt((5 - 2*s5) / 15) # sqrt((5-2*sqrt(5))/15), appears 5 times
    sp30 = np.sqrt((5 + s5) / 30) # sqrt((5+sqrt(5))/30), appears 2 times
    sm30 = np.sqrt((5 - s5) / 30) # sqrt((5-sqrt(5))/30), appears 2 times
    t3p  = np.sqrt((3*s5 + 5) / (6*s5)) # sqrt((3*sqrt(5)+5)/(6*sqrt(5))), appears 2 times
    t3m  = np.sqrt((3*s5 - 5) / (6*s5)) # sqrt((3*sqrt(5)-5)/(6*sqrt(5))), appears 2 times

    phim = 1 / (2*phi)            # (sqrt(5)-1)/4, appears 4 times
    phip = phi / 2                # (sqrt(5)+1)/4, appears 4 times
    sp2h = np.sqrt((5 + s5) / 2) / 2  # sqrt((5+sqrt(5))/2)/2, appears 2 times
    sm2h = np.sqrt((5 - s5) / 2) / 2  # sqrt((5-sqrt(5))/2)/2, appears 2 times
    a1p  = np.sqrt(1 + 2*r5) / 2 # sqrt(1+2/sqrt(5))/2, appears 2 times
    a1m  = np.sqrt(1 - 2*r5) / 2 # sqrt(1-2/sqrt(5))/2, appears 2 times

    faces = [
        np.array([0.0,   0.0,        1.0  ]),
        np.array([0.0,   2*r5,       r5   ]),
        np.array([-sp10, (5-s5)/10,  r5   ]),
        np.array([ sp10, (5-s5)/10,  r5   ]),
        np.array([-sm10, -(5+s5)/10, r5   ]),
        np.array([ sm10, -(5+s5)/10, r5   ]),
    ]
    vertices = [
        np.array([0.0,  -np.sqrt(2*(5+s5)/15), vm  ]),
        np.array([0.0,  -np.sqrt(2*(5-s5)/15), vp  ]),
        np.array([-r3,   vp,                   vm  ]),
        np.array([-r3,  -vm,                   vp  ]),
        np.array([ r3,   vp,                   vm  ]),
        np.array([ r3,  -vm,                   vp  ]),
        np.array([-t3p, -sm30,                 vm  ]),
        np.array([ t3m,  sp30,                 vp  ]),
        np.array([-t3m,  sp30,                 vp  ]),
        np.array([ t3p, -sm30,                 vm  ]),
    ]
    edgecenters = [
        np.array([0.0,   sp10,  -sm10]),
        np.array([0.0,   sm10,   sp10]),
        np.array([0.5,  -a1p,   -sm10]),
        np.array([0.5,   a1m,    sp10]),
        np.array([0.5,  -a1m,   -sp10]),
        np.array([0.5,   a1p,    sm10]),
        np.array([1.0,   0.0,    0.0 ]),
        np.array([phim, -sp10/2, sp10]),
        np.array([phim,  sp10/2,-sp10]),
        np.array([phim, -sp2h,   0.0 ]),
        np.array([phim,  sp2h,   0.0 ]),
        np.array([phip, -sm10/2, sm10]),
        np.array([phip,  sm10/2,-sm10]),
        np.array([phip, -sm2h,   0.0 ]),
        np.array([phip,  sm2h,   0.0 ]),
    ]
    return faces, vertices, edgecenters

_checked_normalize

_checked_normalize(vec, label)

Normalize vec and raise ValueError if the result is a zero vector.

Source code in minimalsym/core/cubic_icosahedral.py
88
89
90
91
92
93
def _checked_normalize(vec, label):
    """Normalize *vec* and raise ValueError if the result is a zero vector."""
    result = normalize(vec)
    if result is None or (result == np.zeros(3)).all():
        raise ValueError(f"Normalization of axis '{label}' produced a zero vector: {vec}")
    return result

_generate_T

_generate_T()

Generate symmetry elements for the T point group. Assumes a tetrahedron contained in a cube.

Returns:

Source code in minimalsym/core/cubic_icosahedral.py
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
def _generate_T():
    """
    Generate symmetry elements for the T point group.
    Assumes a tetrahedron contained in a cube.

    Returns
    -------
    List[Symel]
    """
    symels = [Symel("E", None, np.eye(3))]
    C3_1v = _checked_normalize(np.array([1.0, 1.0, 1.0]),  "C3(alpha)")
    C3_2v = _checked_normalize(np.array([-1.0, 1.0, -1.0]), "C3(beta)")
    C3_3v = _checked_normalize(np.array([-1.0, -1.0, 1.0]), "C3(gamma)")
    C3_4v = _checked_normalize(np.array([1.0, -1.0, -1.0]), "C3(delta)")
    C3list = [C3_1v, C3_2v, C3_3v, C3_4v]
    namelist = ("alpha", "beta", "gamma", "delta")
    for i in range(4):
        C3 = Cn(C3list[i], 3)
        C3s = matrix_power(C3, 2)
        symels.append(Symel(f"C_3({namelist[i]})", C3list[i], C3))
        symels.append(Symel(f"C_3^2({namelist[i]})", C3list[i], C3s))
    C2list = np.eye(3)
    namelist = ["x", "y", "z"]
    for i in range(3):
        C2 = Cn(C2list[i], 2)
        symels.append(Symel(f"C_2({namelist[i]})", C2list[i], C2))
    return symels

_generate_Td

_generate_Td()

Generate symmetry elements for the Td point group. Assumes a tetrahedron contained in a cube.

Returns:

Source code in minimalsym/core/cubic_icosahedral.py
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
def _generate_Td():
    """
    Generate symmetry elements for the Td point group.
    Assumes a tetrahedron contained in a cube.

    Returns
    -------
    List[Symel]
    """
    symels = _generate_T()
    sigmas = [
        normalize(np.array([1.0, 1.0, 0.0])), normalize(np.array([1.0, -1.0, 0.0])),
        normalize(np.array([1.0, 0.0, 1.0])), normalize(np.array([1.0, 0.0, -1.0])),
        normalize(np.array([0.0, 1.0, 1.0])), normalize(np.array([0.0, 1.0, -1.0])),
    ]
    namelist = ["xyp", "xym", "xzp", "xzm", "yzp", "yzm"]
    for i in range(6):
        symels.append(Symel(f"sigma_d({namelist[i]})", sigmas[i], reflection_matrix(sigmas[i])))
    S4list = np.eye(3)
    namelist = ["x", "y", "z"]
    for i in range(3):
        S4 = Sn(S4list[i], 4)
        symels.append(Symel(f"S_4({namelist[i]})", S4list[i], S4))
        symels.append(Symel(f"S_4^3({namelist[i]})", S4list[i], matrix_power(S4, 3)))
    return symels

_generate_Th

_generate_Th()

Generate symmetry elements for the Th point group. Assumes a tetrahedron contained in a cube.

Returns:

Source code in minimalsym/core/cubic_icosahedral.py
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
def _generate_Th():
    """
    Generate symmetry elements for the Th point group.
    Assumes a tetrahedron contained in a cube.

    Returns
    -------
    List[Symel]
    """
    symels = _generate_T()
    symels.append(Symel("i", None, inversion_matrix()))
    S6list = [
        normalize(np.array([1.0, 1.0, 1.0])), normalize(np.array([-1.0, 1.0, -1.0])),
        normalize(np.array([-1.0, -1.0, 1.0])), normalize(np.array([1.0, -1.0, -1.0])),
    ]
    namelist = ["alpha", "beta", "gamma", "delta"]
    for i in range(4):
        S6 = Sn(S6list[i], 6)
        symels.append(Symel(f"S_6({namelist[i]})", S6list[i], S6))
        symels.append(Symel(f"S_6^5({namelist[i]})", S6list[i], matrix_power(S6, 5)))
    sigma_list = np.eye(3)
    namelist = ["x", "y", "z"]
    for i in range(3):
        symels.append(Symel(f"sigma_h({namelist[i]})", sigma_list[i], reflection_matrix(sigma_list[i])))
    return symels

_generate_O

_generate_O()

Generate symmetry elements for the O point group. Assumes operations on a cube.

Returns:

Source code in minimalsym/core/cubic_icosahedral.py
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
def _generate_O():
    """
    Generate symmetry elements for the O point group.
    Assumes operations on a cube.

    Returns
    -------
    List[Symel]
    """
    symels = [Symel("E", None, np.eye(3))]
    C4list = np.eye(3)
    namelist = ["x", "y", "z"]
    for i in range(3):
        C4 = Cn(C4list[i], 4)
        symels.append(Symel(f"C_4({namelist[i]})", C4list[i], C4))
        symels.append(Symel(f"C_2({namelist[i]})", C4list[i], matrix_power(C4, 2)))
        symels.append(Symel(f"C_4^3({namelist[i]})", C4list[i], matrix_power(C4, 3)))
    C3list = [
        normalize(np.array([1.0, 1.0, 1.0])), normalize(np.array([1.0, -1.0, 1.0])),
        normalize(np.array([1.0, 1.0, -1.0])), normalize(np.array([1.0, -1.0, -1.0])),
    ]
    namelist = ["alpha", "beta", "gamma", "delta"]
    for i in range(4):
        C3 = Cn(C3list[i], 3)
        symels.append(Symel(f"C_3({namelist[i]})", C3list[i], C3))
        symels.append(Symel(f"C_3^2({namelist[i]})", C3list[i], matrix_power(C3, 2)))
    C2list = [
        normalize(np.array([1.0, 0.0, 1.0])), normalize(np.array([1.0, 0.0, -1.0])),
        normalize(np.array([1.0, 1.0, 0.0])), normalize(np.array([1.0, -1.0, 0.0])),
        normalize(np.array([0.0, 1.0, 1.0])), normalize(np.array([0.0, -1.0, 1.0])),
    ]
    namelist = ["xzp", "xzm", "xyp", "xym", "yzp", "yzm"]
    for i in range(6):
        symels.append(Symel(f"C_2({namelist[i]})", C2list[i], Cn(C2list[i], 2)))
    return symels

_generate_Oh

_generate_Oh()

Generate symmetry elements for the Oh point group. Assumes operations on a cube.

Returns:

Source code in minimalsym/core/cubic_icosahedral.py
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
def _generate_Oh():
    """
    Generate symmetry elements for the Oh point group.
    Assumes operations on a cube.

    Returns
    -------
    List[Symel]
    """
    symels = _generate_O()
    symels.append(Symel("i", None, inversion_matrix()))
    S4list = np.eye(3)
    namelist = ["x", "y", "z"]
    for i in range(3):
        S4 = Sn(S4list[i], 4)
        symels.append(Symel(f"S_4({namelist[i]})", S4list[i], S4))
        symels.append(Symel(f"sigma_h({namelist[i]})", S4list[i], reflection_matrix(S4list[i])))
        symels.append(Symel(f"S_4^3({namelist[i]})", S4list[i], matrix_power(S4, 3)))
    S6list = [
        normalize(np.array([1.0, 1.0, 1.0])), normalize(np.array([1.0, -1.0, 1.0])),
        normalize(np.array([1.0, 1.0, -1.0])), normalize(np.array([1.0, -1.0, -1.0])),
    ]
    namelist = ["alpha", "beta", "gamma", "delta"]
    for i in range(4):
        S6 = Sn(S6list[i], 6)
        symels.append(Symel(f"S_6({namelist[i]})", S6list[i], S6))
        symels.append(Symel(f"S_6^5({namelist[i]})", S6list[i], matrix_power(S6, 5)))
    sigma_dlist = [
        normalize(np.array([1.0, 0.0, 1.0])), normalize(np.array([1.0, 0.0, -1.0])),
        normalize(np.array([1.0, 1.0, 0.0])), normalize(np.array([1.0, -1.0, 0.0])),
        normalize(np.array([0.0, 1.0, 1.0])), normalize(np.array([0.0, -1.0, 1.0])),
    ]
    namelist = ["xzp", "xzm", "xyp", "xym", "yzp", "yzm"]
    for i in range(6):
        symels.append(Symel(f"sigma_d({namelist[i]})", sigma_dlist[i], reflection_matrix(sigma_dlist[i])))
    return symels

_generate_I

_generate_I()

Generate symmetry elements for the I point group.

Returns:

Source code in minimalsym/core/cubic_icosahedral.py
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
def _generate_I():
    """
    Generate symmetry elements for the I point group.

    Returns
    -------
    List[Symel]
    """
    symels = [Symel("E", None, np.eye(3))]
    faces, vertices, edgecenters = FACE_VEC, VERTEX_VEC, EDGE_VEC
    for i in range(6):
        C5 = Cn(faces[i], 5)
        symels.append(Symel(f"C_5({i})", faces[i], C5))
        symels.append(Symel(f"C_5^2({i})", faces[i], matrix_power(C5, 2)))
        symels.append(Symel(f"C_5^3({i})", faces[i], matrix_power(C5, 3)))
        symels.append(Symel(f"C_5^4({i})", faces[i], matrix_power(C5, 4)))
    for i in range(10):
        C3 = Cn(vertices[i], 3)
        symels.append(Symel(f"C_3({i})", vertices[i], C3))
        symels.append(Symel(f"C_3^2({i})", vertices[i], matrix_power(C3, 2)))
    for i in range(15):
        symels.append(Symel(f"C_2({i})", edgecenters[i], Cn(edgecenters[i], 2)))
    return symels

_generate_Ih

_generate_Ih()

Generate symmetry elements for the Ih point group.

Returns:

Source code in minimalsym/core/cubic_icosahedral.py
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
def _generate_Ih():
    """
    Generate symmetry elements for the Ih point group.

    Returns
    -------
    List[Symel]
    """
    symels = _generate_I()
    faces, vertices, edgecenters = FACE_VEC, VERTEX_VEC, EDGE_VEC
    symels.append(Symel("i", None, inversion_matrix()))
    for i in range(6):
        S10 = Sn(faces[i], 10)
        symels.append(Symel(f"S_10({i})", faces[i], S10))
        symels.append(Symel(f"S_10^3({i})", faces[i], matrix_power(S10, 3)))
        symels.append(Symel(f"S_10^7({i})", faces[i], matrix_power(S10, 7)))
        symels.append(Symel(f"S_10^9({i})", faces[i], matrix_power(S10, 9)))
    for i in range(10):
        S6 = Sn(vertices[i], 6)
        symels.append(Symel(f"S_6({i})", vertices[i], S6))
        symels.append(Symel(f"S_6^5({i})", vertices[i], matrix_power(S6, 5)))
    for i in range(15):
        symels.append(Symel(f"sigma({i})", edgecenters[i], reflection_matrix(edgecenters[i])))
    return symels

group_algebra

group_algebra.py — Pure arithmetic for point-group element products.

Functions here have no side effects and depend only on integer arithmetic and numba JIT. They are used by cyclic_dihedral.py and symel_gen.py.

_omega

_omega(m, n)

Reduce the power m of an S_n element to its canonical symbol index and axis order.

Source code in minimalsym/core/group_algebra.py
12
13
14
15
16
17
@njit
def _omega(m, n):
    """Reduce the power m of an S_n element to its canonical symbol index and axis order."""
    gcd_val = _gcd(m, n)
    l = (m // gcd_val) + (n // gcd_val) * (1 - ((m // gcd_val) % 2))
    return int(l), int(n // gcd_val)

_mult_iCnm

_mult_iCnm(m, n)

Return the canonical power and axis order of i * C_n^m.

Source code in minimalsym/core/group_algebra.py
20
21
22
23
24
@njit
def _mult_iCnm(m, n):
    """Return the canonical power and axis order of i * C_n^m."""
    a = (2 * m + n) % (2 * n)
    return _omega(a, 2 * n)

_mult_sigmahCnm

_mult_sigmahCnm(m, n)

Return the canonical power and axis order of sigma_h * C_n^m.

Source code in minimalsym/core/group_algebra.py
27
28
29
30
@njit
def _mult_sigmahCnm(m, n):
    """Return the canonical power and axis order of sigma_h * C_n^m."""
    return _omega(m, n)

_mult_CSC2sigma

_mult_CSC2sigma(m, n, pre, post)

Return the symbol of the product of a principal-axis element with a C_2' or sigma element.

Source code in minimalsym/core/group_algebra.py
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
@njit
def _mult_CSC2sigma(m, n, pre, post):
    """Return the symbol of the product of a principal-axis element with a C_2' or sigma element."""
    if pre == "C":
        even_odd = ["'", "''"] if post == "C_2" else ["_v", "_d"]
    else:
        if post == "C_2":
            post = "sigma"
        even_odd = ["_v", "_d"]
    if n % 2 == 0:
        if pre == "iC":
            if n % 4 == 0:
                label = even_odd[m % 2]
                a = ((n >> 2) + (m >> 1)) % (n >> 1)
            else:
                label = even_odd[(m + 1) % 2]
                a = ((n >> 2) + ((m + 1) >> 1)) % (n >> 1)
            return post + label + f"({a})"
        else:
            label = even_odd[m % 2]
            a = (m >> 1) % (n >> 1)
            return post + label + f"({a})"
    else:
        if pre == "iC":
            label = "_d"
            a = ((n >> 1) + m) % n
        else:
            label = even_odd[0]
            a = ((((n >> 1) + 1) * (m % 2)) + (m >> 1)) % n
        return post + label + f"({a})"