Source code for spinspg.pointgroup

"""Spin point group."""

from __future__ import annotations

from collections import deque
from typing import TYPE_CHECKING

import numpy as np
from spglib import get_pointgroup
from spgrep.pointgroup import pg_dataset
from spgrep.utils import is_integer_array, ndarray2d_to_integer_tuple

from spinspg.permutation import Permutation

if TYPE_CHECKING:
    from spinspg.utils import NDArrayFloat, NDArrayInt

# Representatives for a geometric crystal class. The first descriptions are chosen for "-42m", "32", "3m", "-3m" and "-6m2".
# Choose unique axis c for "mm2".
POINT_GROUP_REPRESENTATIVES = {
    # Triclinic
    "1": 0,
    "-1": 0,
    # Monoclinic
    "2": 1,  # unique axis-b
    "m": 1,  # unique axis-b
    "2/m": 0,
    # Orthorhombic
    "222": 0,
    "mm2": 2,  # unique axis-c
    "mmm": 0,
    # Tetragonal
    "4": 0,
    "-4": -0,
    "4/m": 0,
    "422": 0,
    "4mm": 0,
    "-42m": 0,  # -42m
    "4/mmm": 0,
    # Hexagonal
    "3": 0,
    "-3": 0,
    "32": 0,  # 312
    "3m": 0,  # 3m1
    "-3m": 0,  # -31m
    "6": 0,
    "-6": 0,
    "6/m": 0,
    "622": 0,
    "6mm": 0,
    "-6m2": 0,  # -6m2
    "6/mmm": 0,
    # Cubic
    "23": 0,
    "m-3": 0,
    "432": 0,
    "-43m": 0,
    "m-3m": 0,
}

# See Table 2.1.3.1 of ITA (2016) for symmetry directions for each crystal family.
# The first entry in equivalent symmetry directions are chosen as possible.
# Exception for tertiary axes of "432", "-43m", and "m-3m"
POINT_GROUP_GENERATORS = {
    # Triclinic
    "1": [0],  # 1
    "-1": [1],  # -1
    # Monoclinic (unique axis b): [010] [010]
    "2": [1],  # 2
    "m": [1],  # m
    "2/m": [1, 3],  # 2, m
    # Orthorhombic: [100] [010] [001]
    "222": [3, 2, 1],  # 2_100, 2_010, 2_001
    "mm2": [3, 2, 1],  # m_100, m_010, 2_001
    "mmm": [7, 6, 5],  # m_100, m_010, m_001
    # Tetragonal: [001] [100]/[010] [1-10]/[110]
    "4": [2],  # 4^+
    "-4": [2],  # -4^+
    "4/m": [2, 5],  # 4^+, m
    "422": [2, 5, 7],  # 4^+, 2_100, 2_1-10
    "4mm": [2, 5, 7],  # 4^+, m_100, m_1-10
    "-42m": [2, 5, 7],  # -4^+, 2_100, m_1-10
    "4/mmm": [2, 9, 13, 15],  # 4^+, m_001, m_100, m_1-10
    # Hexagonal: [001] [100]/[010]/[-1-10] [1-10]/[120]/[-2-10]
    "3": [1],  # 3^+
    "-3": [4],  # -3^+
    "32": [1, 3],  # 3^+, *, 2_1-10
    "3m": [1, 4],  # 3^+, m_100, *
    "-3m": [7, 9],  # -3^+, *, m_1-10
    "6": [5],  # 6^+
    "-6": [5],  # -6^+
    "6/m": [5, 9],  # 6^+, m
    "622": [5, 7, 9],  # 6^+, 2_100, 2_1-10
    "6mm": [5, 7, 9],  # 6^+, m_100, m_1-10
    "-6m2": [5, 7, 9],  # -6^+, m_100, 2_1-10
    "6/mmm": [5, 15, 19, 21],  # 6^+, m_001, m_100, m_1-10
    # Cubic: [100]/[010]/[010] [111]/[1-1-1]/[-11-1]/[-1-11] [1-10]/[110]/[01-1]/[011]/[-101]/[101]
    "23": [3, 4],  # 2_100, 3^+_111
    "m-3": [15, 16],  # m_100, -3^+_111
    "432": [19, 4, 18],  # 4^+_100, 3^+_111, 2_01-1
    "-43m": [17, 4, 16],  # -4^+_100, 3^+_111, m_01-1
    "m-3m": [27, 28, 42],  # m_100, -3^+_111, m_01-1
}

# R -> r -> B -> spin point group types
# Litvin (1977) used Cartesian coordinates for spin rotations while our tabulation uses crystallographic axes.
# - Litvin (1977) seems to use "-4m2" as a representative of "-42m"
SPIN_POINT_GROUP_TYPES = {
    "1": {
        "1": {
            "1": [
                (1, [0]),
            ],
        },
    },
    "-1": {
        "-1": {
            "1": [
                (2, [0]),
            ],
        },
        "1": {
            "2": [
                (3, [1]),
            ],
            "m": [
                (4, [1]),
            ],
            "-1": [
                (5, [1]),
            ],
        },
    },
    "2": {
        "2": {
            "1": [
                (6, [0]),
            ]
        },
        "1": {
            "2": [
                (7, [1]),
            ],
            "m": [
                (8, [1]),
            ],
            "-1": [
                (9, [1]),
            ],
        },
    },
    "m": {
        "m": {
            "1": [
                (10, [0]),
            ],
        },
        "1": {
            "2": [
                (11, [1]),
            ],
            "m": [
                (12, [1]),
            ],
            "-1": [
                (13, [1]),
            ],
        },
    },
    "2/m": {
        "2/m": {
            "1": [
                (14, [0, 0]),
            ],
        },
        "2": {
            "2": [
                (15, [0, 1]),
            ],
            "m": [
                (16, [0, 1]),
            ],
            "-1": [
                (17, [0, 1]),
            ],
        },
        "m": {
            "2": [
                (18, [1, 0]),
            ],
            "m": [
                (19, [1, 0]),
            ],
            "-1": [
                (20, [1, 0]),
            ],
        },
        "-1": {
            "2": [
                (21, [1, 1]),
            ],
            "m": [
                (22, [1, 1]),
            ],
            "-1": [
                (23, [1, 1]),
            ],
        },
        "1": {
            "222": [
                (24, [3, 2]),  # Changed(24): 2_100, 2_010
            ],
            "mm2": [
                (25, [1, 3]),
                (26, [3, 2]),
                (27, [3, 1]),
            ],
            "2/m": [
                (28, [1, 3]),
                (29, [1, 2]),
                (30, [2, 3]),
                (31, [2, 1]),
                (32, [3, 2]),
                (33, [3, 1]),
            ],
        },
    },
    "mm2": {
        "mm2": {
            "1": [(34, [0, 0, 0])],
        },
        "2": {
            "2": [(35, [1, 1, 0])],
            "m": [(36, [1, 1, 0])],
            "-1": [(37, [1, 1, 0])],
        },
        "m": {
            "2": [(38, [0, 1, 1])],
            "m": [(39, [0, 1, 1])],
            "-1": [(40, [0, 1, 1])],
        },
        "1": {
            "222": [(41, [3, 2, 1])],  # Changed(41): 2_100, 2_010, 2_001
            "mm2": [
                (42, [3, 2, 1]),
                (43, [3, 1, 2]),
            ],
            "2/m": [
                (44, [3, 2, 1]),
                (45, [3, 1, 2]),
                (46, [2, 1, 3]),
            ],
        },
    },
    "222": {
        "222": {
            "1": [(47, [0, 0, 0])],
        },
        "2": {
            "2": [(48, [0, 1, 1])],
            "m": [(49, [0, 1, 1])],
            "-1": [(50, [0, 1, 1])],
        },
        "1": {
            "222": [
                (51, [3, 2, 1]),  # Changed(51): 2_100, 2_010, 2_001
            ],
            "mm2": [(52, [3, 2, 1])],
            "2/m": [(53, [1, 2, 3])],
        },
    },
    "mmm": {
        "mmm": {
            "1": [(54, [0, 0, 0])],
        },
        "2/m": {
            "2": [(55, [0, 1, 1])],
            "m": [(56, [0, 1, 1])],
            "-1": [(57, [0, 1, 1])],
        },
        "mm2": {
            "2": [(58, [0, 0, 1])],
            "m": [(59, [0, 0, 1])],
            "-1": [(60, [0, 0, 1])],
        },
        "222": {
            "2": [(61, [1, 1, 1])],
            "m": [(62, [1, 1, 1])],
            "-1": [(63, [1, 1, 1])],
        },
        "2": {
            "222": [(64, [1, 1, 3])],
            "mm2": [
                (65, [3, 3, 2]),  # Changed(65): m_100, m_100, m_010
                (66, [3, 3, 1]),  # Changed(66): m_100, m_100, 2
                (67, [1, 1, 3]),  # Changed(67): 2, 2, m_100
            ],
            "2/m": [
                (68, [3, 3, 2]),
                (69, [3, 3, 1]),
                (70, [1, 1, 2]),
                (71, [1, 1, 3]),
                (72, [2, 2, 1]),
                (73, [2, 2, 3]),
            ],
        },
        "m": {
            "222": [
                (74, [3, 2, 0]),
            ],
            "mm2": [
                (75, [3, 2, 0]),
                (76, [2, 1, 0]),
            ],
            "2/m": [
                (77, [3, 2, 0]),
                (78, [3, 1, 0]),
                (79, [2, 1, 0]),
            ],
        },
        "-1": {
            "222": [(80, [3, 2, 1])],
            "mm2": [(81, [3, 2, 1])],
            "2/m": [(82, [1, 2, 3])],
        },
        "1": {
            "mmm": [
                (83, [7, 6, 5]),
                (84, [7, 2, 1]),
                (85, [5, 3, 1]),
                (86, [1, 7, 5]),
                (87, [1, 4, 7]),
                (88, [1, 4, 3]),
                (89, [4, 5, 7]),
            ],
        },
    },
    "4": {
        "4": {
            "1": [(90, [0])],
        },
        "2": {
            "2": [(91, [1])],
            "m": [(92, [1])],
            "-1": [(93, [1])],
        },
        "1": {
            "4": [(94, [2])],
            "-4": [(95, [2])],
        },
    },
    "-4": {
        "-4": {
            "1": [(96, [0])],
        },
        "2": {
            "2": [(97, [1])],
            "m": [(98, [1])],
            "-1": [(99, [1])],
        },
        "1": {
            "4": [(100, [2])],
            "-4": [(101, [2])],
        },
    },
    "4/m": {
        "4/m": {
            "1": [
                (102, [0, 0]),
            ],
        },
        "2/m": {
            "2": [
                (103, [1, 0]),
            ],
            "m": [
                (104, [1, 0]),
            ],
            "-1": [
                (105, [1, 0]),
            ],
        },
        "-4": {
            "2": [(106, [1, 1])],
            "m": [(107, [1, 1])],
            "-1": [(108, [1, 1])],
        },
        "4": {
            "2": [(109, [0, 1])],
            "m": [(110, [0, 1])],
            "-1": [(111, [0, 1])],
        },
        "-1": {
            "4": [(112, [2, 1])],
            "-4": [(113, [2, 1])],
        },
        "m": {
            "4": [(114, [2, 0])],
            "-4": [(115, [2, 0])],
        },
        "2": {
            "222": [(116, [1, 3])],
            "mm2": [
                (117, [1, 3]),
                (118, [3, 1]),
                (119, [3, 2]),
            ],
            "2/m": [
                (120, [1, 2]),
                (121, [1, 3]),
                (122, [2, 1]),
                (123, [2, 3]),
                (124, [3, 1]),
                (125, [3, 2]),
            ],
        },
        "1": {
            "4/m": [
                (126, [2, 5]),
                (127, [2, 4]),
                (128, [6, 5]),
                (129, [6, 4]),
            ],
        },
    },
    "422": {
        "422": {
            "1": [
                (130, [0, 0, 0]),
            ],
        },
        "4": {
            "2": [
                (131, [0, 1, 1]),
            ],
            "m": [
                (132, [0, 1, 1]),
            ],
            "-1": [
                (133, [0, 1, 1]),
            ],
        },
        "222": {
            "2": [
                (134, [1, 0, 1]),
            ],
            "m": [
                (135, [1, 0, 1]),
            ],
            "-1": [
                (136, [1, 0, 1]),
            ],
        },
        "2": {
            "222": [
                (137, [3, 2, 1]),
            ],
            "mm2": [
                (138, [1, 3, 2]),
                (139, [3, 1, 2]),
            ],
            "2/m": [
                (140, [1, 2, 3]),
                (141, [2, 1, 3]),
                (142, [3, 2, 1]),
            ],
        },
        "1": {
            "422": [
                (143, [2, 5, 7]),
            ],
            "4mm": [
                (144, [2, 5, 7]),
            ],
            "-42m": [
                (145, [2, 5, 7]),
            ],
        },
    },
    "4mm": {
        "4mm": {
            "1": [(146, [0, 0, 0])],
        },
        "4": {
            "2": [(147, [0, 1, 1])],
            "m": [(148, [0, 1, 1])],
            "-1": [(149, [0, 1, 1])],
        },
        "mm2": {
            "2": [(150, [1, 0, 1])],
            "m": [(151, [1, 0, 1])],
            "-1": [(152, [1, 0, 1])],
        },
        "2": {
            "222": [(153, [3, 2, 1])],
            "mm2": [
                (154, [1, 3, 2]),
                (155, [3, 1, 2]),
            ],
            "2/m": [
                (156, [1, 2, 3]),
                (157, [2, 1, 3]),
                (158, [3, 1, 2]),
            ],
        },
        "1": {
            "422": [(159, [2, 5, 7])],
            "4mm": [(160, [2, 5, 7])],
            "-42m": [(161, [2, 7, 4])],  # Changed(161): -4, m_1-10, 2_010
        },
    },
    "-42m": {
        "-42m": {
            "1": [(162, [0, 0, 0])],
        },
        "-4": {
            "2": [(163, [0, 1, 1])],
            "m": [(164, [0, 1, 1])],
            "-1": [(165, [0, 1, 1])],
        },
        "mm2": {
            "2": [(166, [1, 1, 0])],
            "m": [(167, [1, 1, 0])],
            "-1": [(168, [1, 1, 0])],
        },
        "222": {
            "2": [(169, [1, 0, 1])],
            "m": [(170, [1, 0, 1])],
            "-1": [(171, [1, 0, 1])],
        },
        "2": {
            "222": [(172, [3, 2, 1])],
            "mm2": [
                (173, [1, 3, 2]),
                (174, [3, 1, 2]),
                (175, [3, 2, 1]),
            ],
            "2/m": [
                (176, [1, 2, 3]),
                (177, [1, 3, 2]),
                (178, [2, 1, 3]),
                (179, [2, 3, 1]),
                (180, [3, 1, 2]),
                (181, [3, 2, 1]),
            ],
        },
        "1": {
            "422": [
                (182, [2, 5, 7]),
            ],
            "4mm": [
                (183, [2, 5, 7]),
            ],
            "-42m": [
                (184, [2, 5, 7]),
                (185, [2, 7, 4]),  # Changed(185): -4, m_1-10, 2_010
            ],
        },
    },
    "4/mmm": {
        "4/mmm": {
            "1": [(186, [0, 0, 0, 0])],
        },
        "-42m": {
            "2": [(187, [1, 1, 1, 0])],
            "m": [(188, [1, 1, 1, 0])],
            "-1": [(189, [1, 1, 1, 0])],
        },
        "4mm": {
            "2": [(190, [0, 1, 0, 0])],
            "m": [(191, [0, 1, 0, 0])],
            "-1": [(192, [0, 1, 0, 0])],
        },
        "mmm": {
            "2": [
                (193, [1, 0, 0, 1]),
            ],
            "m": [
                (194, [1, 0, 0, 1]),
            ],
            "-1": [(195, [1, 0, 0, 1])],
        },
        "4/m": {
            "2": [(196, [0, 0, 1, 1])],
            "m": [(197, [0, 0, 1, 1])],
            "-1": [(198, [0, 0, 1, 1])],
        },
        "422": {
            "2": [(199, [0, 1, 1, 1])],
            "m": [(200, [0, 1, 1, 1])],
            "-1": [(201, [0, 1, 1, 1])],
        },
        "-4": {
            "222": [(202, [1, 1, 3, 2])],
            "mm2": [(203, [1, 1, 3, 2]), (204, [3, 3, 1, 2])],
            "2/m": [
                (205, [1, 1, 2, 3]),
                (206, [2, 2, 1, 3]),
                (207, [3, 3, 1, 2]),
            ],
        },
        "4": {
            "222": [(208, [0, 3, 2, 2])],
            "mm2": [
                (209, [0, 1, 3, 3]),
                (210, [0, 3, 1, 1]),
                (211, [0, 3, 2, 2]),
            ],
            "2/m": [
                (212, [0, 1, 2, 2]),
                (213, [0, 1, 3, 3]),
                (214, [0, 2, 1, 1]),
                (215, [0, 2, 3, 3]),
                (216, [0, 3, 1, 1]),
                (217, [0, 3, 2, 2]),
            ],
        },
        "2/m": {
            "222": [(218, [1, 0, 3, 2])],
            "mm2": [
                (219, [1, 0, 3, 2]),
                (220, [3, 0, 1, 2]),
            ],
            "2/m": [
                (221, [1, 0, 2, 3]),
                (222, [2, 0, 1, 3]),
                (223, [3, 0, 1, 2]),
            ],
        },
        "mm2": {
            "222": [(224, [1, 3, 0, 1])],
            "mm2": [
                (225, [1, 3, 0, 1]),
                (226, [3, 1, 0, 3]),
                (227, [3, 2, 0, 3]),
            ],
            "2/m": [
                (228, [1, 2, 0, 1]),
                (229, [1, 3, 0, 1]),
                (230, [2, 1, 0, 2]),
                (231, [2, 3, 0, 2]),
                (232, [3, 1, 0, 3]),
                (233, [3, 2, 0, 3]),
            ],
        },
        "222": {
            "222": [
                (234, [1, 3, 3, 2]),
            ],
            "mm2": [
                (235, [1, 3, 3, 2]),
                (236, [3, 1, 1, 2]),
                (237, [3, 2, 2, 1]),
            ],
            "2/m": [
                (238, [1, 2, 2, 3]),
                (239, [1, 3, 3, 2]),
                (240, [2, 1, 1, 3]),
                (241, [2, 3, 3, 1]),
                (242, [3, 1, 1, 2]),
                (243, [3, 2, 2, 1]),
            ],
        },
        "m": {
            "422": [(244, [2, 0, 5, 7])],
            "4mm": [(245, [2, 0, 5, 7])],
            "-42m": [(246, [2, 0, 5, 7])],
        },
        "-1": {
            "422": [(247, [2, 1, 5, 7])],
            "4mm": [(248, [2, 1, 5, 7])],
            "-42m": [(249, [2, 1, 7, 4])],  # Changed(249): -4, 2_001, m_1-10, 2_010
        },
        "2": {
            "mmm": [
                (250, [5, 3, 7, 2]),
                (251, [5, 7, 3, 6]),
                (252, [1, 7, 3, 2]),
                (253, [5, 1, 3, 6]),
                (254, [1, 5, 3, 2]),
                (255, [1, 5, 7, 6]),
                (256, [5, 3, 1, 4]),
                (257, [5, 7, 4, 1]),
                (258, [5, 4, 7, 2]),
                (259, [1, 3, 7, 6]),
                (260, [1, 3, 4, 5]),
                (261, [1, 4, 7, 6]),
                (262, [1, 7, 4, 5]),
                (263, [1, 4, 3, 2]),
                (264, [4, 3, 1, 5]),
                (265, [4, 7, 5, 1]),
            ],
        },
        "1": {
            "4/mmm": [
                (266, [2, 9, 13, 15]),
                (267, [2, 8, 13, 15]),
                (268, [2, 9, 5, 7]),
                (269, [2, 8, 5, 7]),
                (270, [10, 9, 13, 7]),
                (271, [10, 8, 13, 7]),
            ],
        },
    },
    "3": {
        "3": {
            "1": [(272, [0])],
        },
        "1": {
            "3": [(273, [1])],
        },
    },
    "-3": {
        "-3": {
            "1": [(274, [0])],
        },
        "3": {
            "2": [(275, [1])],
            "m": [(276, [1])],
            "-1": [(277, [1])],
        },
        "-1": {
            "3": [(278, [1])],
        },
        "1": {
            "6": [(279, [5])],
            "-3": [(280, [4])],
            "-6": [(281, [5])],
        },
    },
    "32": {
        "32": {
            "1": [(282, [0, 0])],
        },
        "3": {
            "2": [(283, [0, 1])],
            "m": [(284, [0, 1])],
            "-1": [(285, [0, 1])],
        },
        "1": {
            "32": [(286, [1, 3])],  # Changed(286): 3, 2_1-10
            "3m": [(287, [1, 4])],
        },
    },
    "3m": {
        "3m": {
            "1": [(288, [0, 0])],
        },
        "3": {
            "2": [(289, [0, 1])],
            "m": [(290, [0, 1])],
            "-1": [(291, [0, 1])],
        },
        "1": {
            "32": [(292, [1, 3])],  # Changed(292): 3, 2_1-10
            "3m": [(293, [1, 4])],
        },
    },
    "-3m": {
        "-3m": {
            "1": [(294, [0, 0])],
        },
        "-3": {
            "2": [(295, [0, 1])],
            "m": [(296, [0, 1])],
            "-1": [(297, [0, 1])],
        },
        "3m": {
            "2": [(298, [1, 0])],
            "m": [(299, [1, 0])],
            "-1": [(300, [1, 0])],
        },
        "32": {
            "2": [(301, [1, 1])],
            "m": [(302, [1, 1])],
            "-1": [(303, [1, 1])],
        },
        "3": {
            "222": [(304, [3, 1])],
            "mm2": [
                (305, [1, 3]),
                (306, [3, 2]),
                (307, [3, 1]),
            ],
            "2/m": [
                (308, [1, 3]),
                (309, [1, 2]),
                (310, [2, 3]),
                (311, [2, 1]),
                (312, [3, 2]),
                (313, [3, 1]),
            ],
        },
        "-1": {
            "32": [(314, [1, 3])],  # Changed(314): 3, 2_1-10
            "3m": [(315, [1, 4])],
        },
        "1": {
            "622": [(316, [5, 7])],
            "-3m": [
                (317, [7, 9]),  # Changed(317): -3, m_1-10
                (318, [7, 3]),
            ],
            "6mm": [(319, [5, 7])],
            "-6m2": [
                (320, [5, 7]),
                (321, [5, 9]),  # Changed(321): -6, 2_1-10
            ],
        },
    },
    "-6": {
        "-6": {
            "1": [(322, [0])],
        },
        "3": {
            "2": [(323, [1])],
            "m": [(324, [1])],
            "-1": [(325, [1])],
        },
        "m": {
            "3": [(326, [1])],
        },
        "1": {
            "6": [(327, [5])],
            "-3": [(328, [4])],
            "-6": [(329, [5])],
        },
    },
    "6": {
        "6": {
            "1": [(330, [0])],
        },
        "3": {
            "2": [(331, [1])],
            "m": [(332, [1])],
            "-1": [(333, [1])],
        },
        "2": {
            "3": [(334, [1])],
        },
        "1": {
            "6": [(335, [5])],
            "-3": [(336, [4])],
            "-6": [(337, [5])],
        },
    },
    "622": {
        "622": {
            "1": [(338, [0, 0, 0])],
        },
        "6": {
            "2": [(339, [0, 1, 1])],
            "m": [(340, [0, 1, 1])],
            "-1": [(341, [0, 1, 1])],
        },
        "32": {
            "2": [(342, [1, 0, 1])],
            "m": [(343, [1, 0, 1])],
            "-1": [(344, [1, 0, 1])],
        },
        "3": {
            "222": [(345, [3, 2, 1])],
            "mm2": [
                (346, [1, 3, 2]),
                (347, [3, 1, 2]),
            ],
            "2/m": [
                (348, [1, 2, 3]),
                (349, [2, 1, 3]),
                (350, [3, 1, 2]),
            ],
        },
        "2": {
            "32": [(351, [1, 3, 4])],  # Changed(351): 3, 2_1-10, 2_120
            "3m": [(352, [1, 4, 5])],  # Changed(352): 3, m_100, m_010
        },
        "1": {
            "622": [(353, [5, 7, 9])],  # Changed(353): 6, 2_100, 2_1-10
            "-3m": [(354, [7, 3, 10])],  # Changed(354): 3, 2_1-10, m_120
            "6mm": [(355, [5, 7, 9])],  # Changed(355): 3, m_100, m_1-10
            "-6m2": [(356, [5, 7, 9])],  # Changed(356): -6, m_100, 2_1-10
        },
    },
    "6/m": {
        "6/m": {
            "1": [(357, [0, 0])],
        },
        "-3": {
            "2": [(358, [1, 1])],
            "m": [(359, [1, 1])],
            "-1": [(360, [1, 1])],
        },
        "-6": {
            "2": [(361, [1, 0])],
            "m": [(362, [1, 0])],
            "-1": [(363, [1, 0])],
        },
        "6": {
            "2": [(364, [0, 1])],
            "m": [(365, [0, 1])],
            "-1": [(366, [0, 1])],
        },
        "2/m": {
            "3": [(367, [1, 0])],
        },
        "3": {
            "222": [(368, [1, 3])],
            "mm2": [
                (369, [1, 3]),
                (370, [3, 1]),
                (371, [3, 2]),
            ],
            "2/m": [
                (372, [1, 2]),
                (373, [1, 3]),
                (374, [2, 1]),
                (375, [2, 3]),
                (376, [3, 1]),
                (377, [3, 2]),
            ],
        },
        "2": {
            "6": [(378, [1, 3])],
            "-3": [(379, [1, 3])],
            "-6": [(380, [1, 3])],
        },
        "m": {
            "6": [(381, [5, 0])],
            "-3": [(382, [4, 0])],
            "-6": [(383, [5, 0])],
        },
        "-1": {
            "6": [(384, [5, 3])],
            "-3": [(385, [4, 3])],
            "-6": [(386, [5, 3])],
        },
        "1": {
            "6/m": [
                (387, [5, 9]),
                (388, [5, 6]),
                (389, [7, 9]),
                (390, [7, 3]),
                (391, [11, 6]),
                (392, [11, 3]),
            ],
        },
    },
    "6mm": {
        "6mm": {"1": [(393, [0, 0, 0])]},
        "6": {
            "2": [(394, [0, 1, 1])],
            "m": [(395, [0, 1, 1])],
            "-1": [(396, [0, 1, 1])],
        },
        "3m": {
            "2": [(397, [1, 0, 1])],
            "m": [(398, [1, 0, 1])],
            "-1": [(399, [1, 0, 1])],
        },
        "3": {
            "222": [(400, [3, 2, 1])],
            "mm2": [
                (401, [1, 3, 2]),
                (402, [3, 1, 2]),
            ],
            "2/m": [
                (403, [1, 2, 3]),
                (404, [2, 1, 3]),
                (405, [3, 1, 2]),
            ],
        },
        "2": {
            "32": [(406, [1, 3, 4])],  # Changed(406): 3, 2_1-10, 2_120
            "3m": [(407, [1, 4, 5])],  # Changed(407): 3, m_100, m_010
        },
        "1": {
            "622": [(408, [5, 7, 9])],  # Changed(408): 6, 2_100, 2_1-10
            "-3m": [(409, [7, 3, 10])],  # Changed(409): -3, 2_1-10, m_010
            "6mm": [(410, [5, 7, 9])],  # Changed(410): 6, m_100, m_xy
            "-6m2": [(411, [5, 7, 9])],  # Changed(411): -6, m_100, 2_1-10
        },
    },
    "-6m2": {
        "-6m2": {
            "1": [(412, [0, 0, 0])],
        },
        "-6": {
            "2": [(413, [0, 1, 1])],
            "m": [(414, [0, 1, 1])],
            "-1": [(415, [0, 1, 1])],
        },
        "3m": {
            "2": [(416, [1, 0, 1])],
            "m": [(417, [1, 0, 1])],
            "-1": [(418, [1, 0, 1])],
        },
        "32": {
            "2": [(419, [1, 1, 0])],
            "m": [(420, [1, 1, 0])],
            "-1": [(421, [1, 1, 0])],
        },
        "3": {
            "222": [(422, [1, 3, 2])],
            "mm2": [
                (423, [1, 3, 2]),
                (424, [3, 2, 1]),
                (425, [3, 1, 2]),
            ],
            "2/m": [
                (426, [1, 3, 2]),
                (427, [1, 2, 3]),
                (428, [2, 3, 1]),
                (429, [2, 1, 3]),
                (430, [3, 2, 1]),
                (431, [3, 1, 2]),
            ],
        },
        "m": {
            "32": [
                (432, [1, 3, 4]),  # Changed(432): 3, 2_1-10, 2_120
            ],
            "3m": [(433, [1, 4, 5])],  # Changed(433): 3, m_100, m_010
        },
        "1": {
            "622": [(434, [5, 7, 9])],  # Changed(434): 6, 2_100, 2_1-10
            "-3m": [
                (435, [7, 9, 4]),  # Changed(435): -3, m_1-10, 2_120
                (436, [7, 3, 10]),  # Changed(436): -3, 2_1-10, m_120
            ],
            "6mm": [(437, [5, 7, 9])],  # Changed(437): 6, m_100, m_1-10
            "-6m2": [
                (438, [5, 7, 9]),  # Changed(438): -6, m_100, 2_1-10
                (439, [5, 9, 8]),  # Changed(439): -6, 2_1-10, m_010
            ],
        },
    },
    "6/mmm": {
        "6/mmm": {
            "1": [(440, [0, 0, 0, 0])],
        },
        "-3m": {
            "2": [(441, [1, 1, 0, 1])],
            "m": [(442, [1, 1, 0, 1])],
            "-1": [(443, [1, 1, 0, 1])],
        },
        "-6m2": {
            "2": [(444, [1, 0, 1, 0])],
            "m": [(445, [1, 0, 1, 0])],
            "-1": [(446, [1, 0, 1, 0])],
        },
        "6/m": {
            "2": [(447, [0, 0, 1, 1])],
            "m": [(448, [0, 0, 1, 1])],
            "-1": [(449, [0, 0, 1, 1])],
        },
        "6mm": {
            "2": [(450, [0, 1, 0, 0])],
            "m": [(451, [0, 1, 0, 0])],
            "-1": [(452, [0, 1, 0, 0])],
        },
        "622": {
            "2": [(453, [0, 1, 1, 1])],
            "m": [(454, [0, 1, 1, 1])],
            "-1": [(455, [0, 1, 1, 1])],
        },
        "-3": {
            "222": [(456, [1, 1, 3, 2])],
            "mm2": [(457, [1, 1, 3, 2]), (458, [3, 3, 1, 2])],
            "2/m": [
                (459, [1, 1, 2, 3]),
                (460, [2, 2, 1, 3]),
                (461, [3, 3, 1, 2]),
            ],
        },
        "-6": {
            "222": [(462, [1, 0, 3, 2])],
            "mm2": [(463, [1, 0, 3, 2]), (464, [3, 0, 1, 2])],
            "2/m": [
                (465, [1, 0, 2, 3]),
                (466, [2, 0, 1, 3]),
                (467, [3, 0, 1, 2]),
            ],
        },
        "6": {
            "222": [(468, [0, 1, 3, 3])],
            "mm2": [
                (469, [0, 1, 3, 3]),
                (470, [0, 3, 2, 2]),
                (471, [0, 3, 1, 1]),
            ],
            "2/m": [
                (472, [0, 1, 3, 3]),
                (473, [0, 1, 2, 2]),
                (474, [0, 2, 3, 3]),
                (475, [0, 2, 1, 1]),
                (476, [0, 3, 2, 2]),
                (477, [0, 3, 1, 1]),
            ],
        },
        "3m": {
            "222": [
                (478, [1, 3, 0, 1]),
            ],
            "mm2": [
                (479, [3, 2, 0, 3]),
                (480, [3, 1, 0, 3]),
                (481, [1, 3, 0, 1]),
            ],
            "2/m": [
                (482, [3, 2, 0, 3]),
                (483, [2, 3, 0, 2]),
                (484, [3, 1, 0, 3]),
                (485, [1, 3, 0, 1]),
                (486, [2, 1, 0, 2]),
                (487, [1, 2, 0, 1]),
            ],
        },
        "32": {
            "222": [(488, [1, 3, 2, 3])],
            "mm2": [
                (489, [3, 1, 2, 1]),  # Changed(489): m_100, 2, m_100, 2
                (490, [3, 2, 1, 2]),  # Changed(490): m_100, m_010, 2, m_010
                (491, [1, 3, 2, 3]),
            ],
            "2/m": [
                (492, [3, 1, 2, 1]),
                (493, [2, 1, 3, 1]),
                (494, [3, 2, 1, 2]),
                (495, [1, 2, 3, 2]),
                (496, [2, 3, 1, 3]),
                (497, [1, 3, 2, 3]),
            ],
        },
        "2/m": {
            "32": [(498, [1, 0, 3, 4])],  # Changed(498): 3, 1, 2_1-10, 2_120
            "3m": [(499, [1, 0, 4, 5])],  # Changed(499): 3, 1, m_100, m_010
        },
        "3": {
            "mmm": [
                (500, [5, 1, 7, 2]),
                (501, [1, 5, 7, 6]),
                (502, [1, 5, 3, 2]),
                (503, [5, 7, 3, 6]),
                (504, [5, 3, 2, 7]),  # Corrected?(504): m_001, 2_100, 2_010, m_100
                (505, [1, 3, 6, 7]),
                (506, [1, 7, 2, 3]),
                (507, [5, 3, 4, 1]),
                (508, [5, 7, 1, 4]),
                (509, [5, 4, 3, 6]),
                (510, [1, 7, 5, 4]),
                (511, [1, 3, 5, 4]),
                (512, [1, 4, 7, 6]),
                (513, [1, 4, 3, 2]),
                (514, [4, 7, 1, 5]),
                (515, [4, 3, 5, 1]),
            ],
        },
        "-1": {
            "622": [
                (516, [5, 3, 7, 9]),  # Changed(516): 6, 2_001, 2_100, 2_1-10
            ],
            "-3m": [(517, [7, 6, 3, 10])],  # Changed(517): -3, -1, 2_1-10, m_120
            "6mm": [
                (518, [5, 3, 7, 9]),
            ],
            "-6m2": [(519, [5, 3, 7, 9])],  # Changed(519): -6, m_001, m_100, 2_1-10
        },
        "m": {
            "622": [(520, [5, 0, 7, 9])],  # Changed(520): 6, 1, 2_100, 2_1-10
            "-3m": [(521, [7, 0, 9, 4])],  # Changed(521): -3, 1, m_1-10, 2_120
            "6mm": [(522, [5, 0, 7, 9])],  # Changed(522): 6, 1, m_100, m_1-10
            "-6m2": [(523, [5, 0, 9, 8])],  # Changed(523): -6, 1, 2_1-10, m_010
        },
        "2": {
            "622": [
                (524, [1, 3, 7, 8]),  # Changed(524): 3, 2_001, 2_100, 2_010
            ],
            "-3m": [
                (525, [1, 6, 9, 10]),  # Changed(525): 3, -1, m_1-10, m_120
                (526, [1, 6, 3, 4]),  # Changed(526): 3, -1, 2_1-10, 2_120
            ],
            "6mm": [(527, [1, 3, 7, 8])],  # Changed(527): 3, 2_001, m_100, m_010
            "-6m2": [
                (528, [1, 3, 7, 8]),  # Changed(528): 3, m_001, m_100, m_010
                (529, [1, 3, 9, 10]),  # Changed(529): 3, m_001, 2_1-10, 2_120
            ],
        },
        "1": {
            "6/mmm": [
                (530, [5, 12, 19, 21]),  # Changed(530): 6, -1, m_100, m_1-10
                (531, [5, 15, 19, 21]),  # Changed(531): 6, m_001, m_100, m_1-10
                (532, [5, 12, 7, 9]),  # Changed(532): 6, -1, 2_100, 2_1-10
                (533, [5, 15, 7, 9]),  # Changed(533): 6, m_001, 2_100, 2_1-10
                (534, [13, 15, 7, 20]),  # Changed(534): -3, m_001, 2_100, m_010
                (535, [13, 3, 19, 8]),  # Changed(535): -3, 2_001, m_100, 2_010
                (536, [17, 12, 7, 21]),  # Changed(536): -6, -1, 2_100, m_1-10
                (537, [17, 3, 19, 9]),  # Changed(537): -6, 2_001, m_100, 2_1-10
            ],
        },
    },
    "23": {
        "23": {
            "1": [(538, [0, 0])],
        },
        "222": {
            "3": [(539, [0, 1])],
        },
        "1": {
            "23": [(540, [1, 4])],
        },
    },
    "m-3": {
        "m-3": {
            "1": [(541, [0, 0])],
        },
        "23": {
            "2": [(542, [1, 1])],
            "m": [(543, [1, 1])],
            "-1": [(544, [1, 1])],
        },
        "mmm": {
            "3": [(545, [0, 1])],
        },
        "222": {
            "6": [(546, [3, 5])],
            "-3": [(547, [3, 4])],
            "-6": [(548, [3, 5])],
        },
        "-1": {
            "23": [(549, [1, 4])],
        },
        "1": {
            "m-3": [(550, [13, 16])],
        },
    },
    "-43m": {
        "-43m": {
            "1": [(551, [0, 0, 0])],
        },
        "23": {
            "2": [(552, [1, 0, 1])],
            "m": [(553, [1, 0, 1])],
            "-1": [(554, [1, 0, 1])],
        },
        "222": {
            "32": [(555, [3, 1, 3])],  # Changed(555): 2_1-10, 3, 2_1-10
            "3m": [(556, [4, 1, 4])],
        },
        "1": {
            "432": [(557, [15, 4, 13])],
            "-43m": [(558, [14, 4, 12])],
        },
    },
    "432": {
        "432": {
            "1": [(559, [0, 0, 0])],
        },
        "23": {
            "2": [(560, [1, 0, 1])],
            "m": [(561, [1, 0, 1])],
            "-1": [(562, [1, 0, 1])],
        },
        "222": {
            "32": [(563, [3, 1, 3])],
            "3m": [(564, [4, 1, 4])],
        },
        "1": {
            "432": [(565, [19, 4, 18])],  # Changed(565): 4_100, 3_111, 2_01-1
            "-43m": [(566, [14, 4, 12])],  # Changed(566): -4_001, 3_111, m_1-10
        },
    },
    "m-3m": {
        "m-3m": {
            "1": [(567, [0, 0, 0])],
        },
        "m-3": {
            "2": [(568, [0, 0, 1])],
            "m": [(569, [0, 0, 1])],
            "-1": [(570, [0, 0, 1])],
        },
        "-43m": {
            "2": [(571, [1, 1, 0])],
            "m": [(572, [1, 1, 0])],
            "-1": [(573, [1, 1, 0])],
        },
        "432": {
            "2": [(574, [1, 1, 1])],
            "m": [(575, [1, 1, 1])],
            "-1": [(576, [1, 1, 1])],
        },
        "23": {
            "222": [(577, [2, 2, 1])],
            "mm2": [
                (578, [3, 3, 2]),
                (579, [1, 1, 2]),
                (580, [2, 2, 1]),
            ],
            "2/m": [
                (581, [2, 2, 3]),
                (582, [3, 3, 2]),
                (583, [1, 1, 3]),
                (584, [3, 3, 1]),
                (585, [1, 1, 2]),
                (586, [2, 2, 1]),
            ],
        },
        "mmm": {
            "32": [(587, [0, 1, 3])],  # Changed(587): 1, 3, 2_1-10
            "3m": [(588, [0, 1, 4])],
        },
        "222": {
            "622": [
                (589, [3, 5, 7]),
            ],
            "-3m": [
                (590, [6, 7, 10]),
                (591, [6, 7, 4]),
            ],
            "6mm": [(592, [3, 5, 7])],
            "-6m2": [
                (593, [3, 5, 9]),  # Changed(593): m_001, -6, 2_1-10
                (594, [3, 5, 7]),
            ],
        },
        "-1": {
            "432": [
                (595, [3, 4, 18]),  # Changed(595): 2_100, 3_111, 2_01-1
            ],
            "-43m": [(596, [3, 4, 16])],  # Changed(596): 2_100, 3_111, m_01-1
        },
        "1": {
            "m-3m": [
                (597, [27, 28, 42]),  # Changed(597): m_100, -3_111, m_01-1
                (598, [27, 28, 18]),  # Changed(598): m_100, -3_111, 2_01-1
            ],
        },
    },
}


[docs] def get_pointgroup_representative_from_symbol( symbol: str, ) -> list[tuple[tuple[int, ...], ...]]: """Return a representative of a given geometric crystal class. Parameters ---------- symbol: symbol for geometric crystal class Returns ------- group: (order, 3, 3) """ index = POINT_GROUP_REPRESENTATIVES[symbol] group = pg_dataset[symbol][index] return group
[docs] def get_pointgroup_representative( prim_rotations: NDArrayInt, ) -> tuple[str, NDArrayFloat, list[int]]: """Return representative of crystallographic point group. Parameters ---------- prim_rotations: array[int], (order, 3, 3) Integer rotation matrices Returns ------- symbol: str Point group type P: array, (3, 3) transformation matrix. Let `std_rotations` be a representative of a crystallographic point group. The transformation `P` and mapping `mapping` satisfy `np.linalg.inv(P) @ prim_rotations[mapping[i]] @ P == std_rotations[i]` mapping: list[int] """ # P0^-1 @ prim_rotations @ P0 = matched symbol, _, P0 = get_pointgroup(prim_rotations) P0inv = np.linalg.inv(P0) def _match(symbol, matched): """Match given crystallographic point group with standardized ones in primitive basis.""" order = len(matched) for idx, std_rotations in enumerate(pg_dataset[symbol]): success = True mapping = [-1 for _ in range(order)] # s.t. matched[mapping[i]] == std_rotations[i] for i, ri in enumerate(std_rotations): try: j = matched.index(ri) # type: ignore except ValueError: success = False break mapping[i] = j if success: return idx, mapping matched = [ndarray2d_to_integer_tuple(P0inv @ r @ P0) for r in prim_rotations] idx, mapping = _match(symbol, matched) # spglib.get_pointgroup does not return a transformation matrix to a unique matrix group # for mm2, -42m, 32, 3m, -3m, and -6m2. # See https://github.com/spglib/spglib/issues/164 std_idx = POINT_GROUP_REPRESENTATIVES[symbol] if idx == std_idx: return symbol, P0, mapping if symbol == "mm2": # 90-degree rotation in orthorhombic if idx == 0: # unique axis a: bca -> abc P1 = np.array( [ [0, 0, 1], [1, 0, 0], [0, 1, 0], ] ) elif idx == 1: # unique axis b: a-cb -> abc P1 = np.array( [ [1, 0, 0], [0, 0, -1], [0, 1, 0], ] ) else: ValueError("Unreachable here!") elif symbol == "-42m": # 45-degree rotation in tetragonal P1 = np.array( [ [1 / np.sqrt(2), 1 / np.sqrt(2), 0], [-1 / np.sqrt(2), 1 / np.sqrt(2), 0], [0, 0, 1], ] ) # Indices of two-fold rotations and mirrors are interchanged in -42m and -4m2 perm = Permutation(mapping) * Permutation([0, 1, 2, 3, 6, 7, 5, 4]) mapping = perm.permutation elif symbol in ["32", "3m", "-3m", "-6m2"]: # 90 degree rotation in rhombohedral (hexagonal axis) and hexagonal P1 = np.array( [ [1 / np.sqrt(3), -2 / np.sqrt(3), 0], [2 / np.sqrt(3), -1 / np.sqrt(3), 0], [0, 0, 1], ] ) if symbol == "-6m2": # Indices of two-fold rotations and mirrors are interchanged in -6m2 and -62m perm = Permutation(mapping) * Permutation([0, 1, 2, 3, 4, 5, 9, 10, 11, 6, 7, 8]) mapping = perm.permutation else: raise ValueError("Unknown point group representative.") return symbol, P0 @ P1, mapping
POINT_GROUP_TABLES = { # Laue: -1 "1": ([0, 0, 0, 0, 0, 1, 0, 0, 0, 0], "-1"), "-1": ([0, 0, 0, 0, 1, 1, 0, 0, 0, 0], "-1"), # Laue: 2/m "2": ([0, 0, 0, 0, 0, 1, 1, 0, 0, 0], "2/m"), "m": ([0, 0, 0, 1, 0, 1, 0, 0, 0, 0], "2/m"), "2/m": ([0, 0, 0, 1, 1, 1, 1, 0, 0, 0], "2/m"), # Laue: mmm "222": ([0, 0, 0, 0, 0, 1, 3, 0, 0, 0], "mmm"), "mm2": ([0, 0, 0, 2, 0, 1, 1, 0, 0, 0], "mmm"), "mmm": ([0, 0, 0, 3, 1, 1, 3, 0, 0, 0], "mmm"), # Laue: 4/m "4": ([0, 0, 0, 0, 0, 1, 1, 0, 2, 0], "4/m"), "-4": ([0, 2, 0, 0, 0, 1, 1, 0, 0, 0], "4/m"), "4/m": ([0, 2, 0, 1, 1, 1, 1, 0, 2, 0], "4/m"), # Laue: 4/mmm "422": ([0, 0, 0, 0, 0, 1, 5, 0, 2, 0], "4/mmm"), "4mm": ([0, 0, 0, 4, 0, 1, 1, 0, 2, 0], "4/mmm"), "-42m": ([0, 2, 0, 2, 0, 1, 3, 0, 0, 0], "4/mmm"), "4/mmm": ([0, 2, 0, 5, 1, 1, 5, 0, 2, 0], "4/mmm"), # Laue: -3 "3": ([0, 0, 0, 0, 0, 1, 0, 2, 0, 0], "-3"), "-3": ([0, 0, 2, 0, 1, 1, 0, 2, 0, 0], "-3"), # Laue: -3m "32": ([0, 0, 0, 0, 0, 1, 3, 2, 0, 0], "-3m"), "3m": ([0, 0, 0, 3, 0, 1, 0, 2, 0, 0], "-3m"), "-3m": ([0, 0, 2, 3, 1, 1, 3, 2, 0, 0], "-3m"), # Laue: 6/m "6": ([0, 0, 0, 0, 0, 1, 1, 2, 0, 2], "6/m"), "-6": ([2, 0, 0, 1, 0, 1, 0, 2, 0, 0], "6/m"), "6/m": ([2, 0, 2, 1, 1, 1, 1, 2, 0, 2], "6/m"), # Laue: 6/mmm "622": ([0, 0, 0, 0, 0, 1, 7, 2, 0, 2], "6/mmm"), "6mm": ([0, 0, 0, 6, 0, 1, 1, 2, 0, 2], "6/mmm"), "-6m2": ([2, 0, 0, 4, 0, 1, 3, 2, 0, 0], "6/mmm"), "6/mmm": ([2, 0, 2, 7, 1, 1, 7, 2, 0, 2], "6/mmm"), # Laue: m-3 "23": ([0, 0, 0, 0, 0, 1, 3, 8, 0, 0], "m-3"), "m-3": ([0, 0, 8, 3, 1, 1, 3, 8, 0, 0], "m-3"), # Laue: m-3m "432": ([0, 0, 0, 0, 0, 1, 9, 8, 6, 0], "m-3m"), "-43m": ([0, 6, 0, 6, 0, 1, 3, 8, 0, 0], "m-3m"), "m-3m": ([0, 6, 8, 9, 1, 1, 9, 8, 6, 0], "m-3m"), } def get_integer_point_group(prim_rotations: NDArrayFloat) -> tuple[NDArrayFloat, NDArrayInt]: """Transform subgroup of orthgonal group O(3) to integer matrices. Implement algorithm presented in "R. W. Grosse-Kunstleve. Algorithms for deriving crystallographic space-group information. Acta Cryst. A, 55, 383-395 (1999)". Parameters ---------- prim_rotations: array, (order, 3, 3) Orthogonal matrices, that is ``np.allclose(prim_rotations[i] @ prim_rotations[i].T, np.eye(3))`` Returns ------- P: array, (3, 3) Transformation matrix ``np.linalg.inv(P) @ prim_rotations[i] @ P == rotations[i]`` rotations: array[int], (order, 3, 3) """ rotation_types = [_get_rotation_type(rot) for rot in prim_rotations] lookup_table = [0 for _ in range(10)] mapping = { -6: 0, -4: 1, -3: 2, -2: 3, -1: 4, 1: 5, 2: 6, 3: 7, 4: 8, 6: 9, } for rotation_type in rotation_types: lookup_table[mapping[rotation_type]] += 1 laue_class = None for _, (std_table, std_laue) in POINT_GROUP_TABLES.items(): if lookup_table == std_table: laue_class = std_laue break def _get_parallel_axes(proper_rotation_type: int) -> list[tuple[NDArrayFloat, NDArrayFloat]]: axes = [] for rot, rotation_type in zip(prim_rotations, rotation_types): if np.abs(rotation_type) != proper_rotation_type: continue rot_prop = np.linalg.det(rot) * rot # Proper rotation s = np.zeros((3, 3)) tmp = np.eye(3) for _ in range(proper_rotation_type): tmp = tmp @ rot_prop s += tmp for basis in [np.array([1, 0, 0]), np.array([0, 1, 0]), np.array([0, 0, 1])]: axis = s @ basis if np.allclose(axis, 0): continue axes.append((axis, rot_prop)) break distinct_axes = [] # type: ignore for axis, rot_prop in axes: unique = True for other, _ in distinct_axes: if np.allclose(np.cross(axis, other), 0): unique = False break if unique: distinct_axes.append((axis / np.linalg.norm(axis), rot_prop)) return distinct_axes def _get_perpendicular_axes(rot, rotation_type) -> list[NDArrayFloat]: s = np.zeros((3, 3)) tmp = np.eye(3) for _ in range(rotation_type): tmp = tmp @ rot s += tmp eigvals, eigvecs = np.linalg.eig(s.T) axes = [] for i, eigval in enumerate(eigvals): axis = eigvecs[:, i] if np.isclose(eigval, 0): axes.append(np.real(axis)) axes.append(np.imag(axis)) distinct_axes = [] # type: ignore for axis in axes: if np.allclose(axis, 0): continue unique = True for other in distinct_axes: if np.allclose(np.cross(axis, other), 0): unique = False break if unique: distinct_axes.append(axis / np.linalg.norm(axis)) return distinct_axes if laue_class == "-1": primary = np.array([1.0, 0.0, 0.0]) secondary = np.array([0.0, 1.0, 0.0]) tertiary = np.array([0.0, 0.0, 1.0]) elif laue_class == "2/m": primaries = _get_parallel_axes(2) primary, rot_primary = primaries[0] axes = _get_perpendicular_axes(rot_primary, 2) secondary, tertiary = axes[:2] elif laue_class == "mmm": primaries = _get_parallel_axes(2) primary, _ = primaries[0] secondary, _ = primaries[1] tertiary, _ = primaries[2] elif laue_class == "4/m": primaries = _get_parallel_axes(4) primary, rot_primary = primaries[0] axes = _get_perpendicular_axes(rot_primary, 4) secondary = axes[0] tertiary = rot_primary @ secondary elif laue_class == "4/mmm": primaries = _get_parallel_axes(4) primary, rot_primary = primaries[0] secondary = None for axis, _ in _get_parallel_axes(2): if np.isclose(np.inner(axis, primary), 0): secondary = axis break tertiary = rot_primary @ secondary elif laue_class in ["-3", "6/m"]: primaries = _get_parallel_axes(3) primary, rot_primary = primaries[0] axes = _get_perpendicular_axes(rot_primary, 3) secondary = axes[0] tertiary = rot_primary @ secondary elif laue_class in ["-3m", "6/mmm"]: primaries = _get_parallel_axes(3) primary, rot_primary = primaries[0] secondary = None for axis, _ in _get_parallel_axes(2): if np.isclose(np.inner(axis, primary), 0): secondary = axis break tertiary = rot_primary @ secondary elif laue_class == "m-3": primaries = _get_parallel_axes(3) primary, rot_primary = primaries[0] # Secondary: two-fold axis axes = _get_parallel_axes(2) secondary, _ = axes[0] # Tertiary: two-fold axis perpendicular to secondary tertiary = None for axis, _ in axes[1:]: if np.isclose(np.inner(axis, secondary), 0): tertiary = axis break elif laue_class == "m-3m": primaries = _get_parallel_axes(4) primary, _ = primaries[0] secondary, _ = primaries[1] tertiary, _ = primaries[2] else: raise ValueError("Fail to detect Laue class:", laue_class) P = np.array([primary, secondary, tertiary]).T if np.linalg.det(P) < 0: P = -P # Correction matrix for m-3 if laue_class == "m-3": # Transform axes to (3_111, 2_010, 2_001) correction = np.array( [ [1 / np.sqrt(3), 0, 0], [1 / np.sqrt(3), 1, 0], [1 / np.sqrt(3), 0, 1], ] ) P = P @ np.linalg.inv(correction) Pinv = np.linalg.inv(P) rotations = [] for cart_rot in prim_rotations: rot = Pinv @ cart_rot @ P assert is_integer_array(rot) rotations.append(np.around(rot).astype(int)) return P, rotations def _get_rotation_type(rotation: NDArrayFloat) -> int: trace = np.around(np.trace(rotation)).astype(int) det = np.around(np.linalg.det(rotation)).astype(int) lookup_table = { (-2, -1): -6, (-1, -1): -4, (0, -1): -3, (1, -1): -2, (-3, -1): -1, (3, 1): 1, (-1, 1): 2, (0, 1): 3, (1, 1): 4, (2, 1): 6, } for key, rotation_type in lookup_table.items(): if (trace, det) == key: return rotation_type raise ValueError("Unreachable!") def traverse_spin_operations(generators): """Construct a spin point group from given generators.""" que = deque() founds = set() for g in generators: que.append(g) while len(que) > 0: g = que.pop() if g in founds: continue founds.add(g) for h in founds: gh = ( ndarray2d_to_integer_tuple(np.array(g[0]) @ np.array(h[0])), ndarray2d_to_integer_tuple(np.array(g[1]) @ np.array(h[1])), ) if gh in founds: continue que.append(gh) return tuple(founds)