Source code for pythmpg.pg_elements

"""
Define crystallographic proper rotations and build their
multiplication tables.

Provides tools to construct lists of proper rotations belonging
to cubic and hexagonal crystallographic groups, and to construct
their multiplication tables.  Functions :func:`get_hex_table`
and :func:`get_cub_table` are intended to be accessed from outside
this module.

Notes
-----
In the context of this module, all point group operations are proper
rotations (determinant +1).
"""

import numpy as np


[docs] def get_hex_table(if_print=False): """ Build a dictionary of proper rotations for hexagonal group 622 and compute its multiplication table. Parameters ---------- if_print : bool, optional If ``True``, print the rotation list and multiplication table to stdout. Default is ``False``. Returns ------- rot_dict : dict Dictionary mapping rotation names (str) to rotation matrices (numpy 3x3 float array). table_dict : dict Dictionary embodying the multiplication table; keys are tuples of two rotation names and values are the resulting rotation name. """ rot_dict = get_hex_rot_dict() table_dict = get_mult_table(rot_dict) if if_print: print_dict("hex_info", rot_dict, table_dict) return rot_dict, table_dict
[docs] def get_cub_table(if_print=False): """ Build a dictionary of proper rotations for cubic group 432 and compute its multiplication table. Parameters ---------- if_print : bool, optional If ``True``, print the rotation list and multiplication table to stdout. Default is ``False``. Returns ------- rot_dict : dict Dictionary mapping rotation names (str) to rotation matrices (numpy 3x3 float array). table_dict : dict Dictionary embodying the multiplication table; keys are tuples of two rotation names and values are the resulting rotation name. """ rot_dict = get_cub_rot_dict() table_dict = get_mult_table(rot_dict) if if_print: print_dict("cub_info", rot_dict, table_dict) return rot_dict, table_dict
# ---------------------------------------------------------------- # The remaining functions are tools internal to this module # ----------------------------------------------------------------
[docs] def get_hex_rot_dict(): """ Construct the rotation dictionary for hexagonal group 622. Returns ------- rot_dict : dict Dictionary mapping rotation names (str of 1 or 2 characters) to rotation matrices (numpy 3x3 float array). """ rot_dict = {} rot_dict["1"] = rot_mat([0, 0, 1], 0, 1) rot_dict["2z"] = rot_mat([0, 0, 1], 1, 2) rot_dict["3z"] = rot_mat([0, 0, 1], 1, 3) rot_dict["3Z"] = rot_mat([0, 0, 1], 2, 3) rot_dict["6z"] = rot_mat([0, 0, 1], 1, 6) rot_dict["6Z"] = rot_mat([0, 0, 1], 5, 6) half = 1 / 2 r32 = np.sqrt(3) / 2 rot_dict["2r"] = rot_mat([1, 0, 0], 1, 2) rot_dict["2s"] = rot_mat([r32, half, 0], 1, 2) rot_dict["2t"] = rot_mat([half, r32, 0], 1, 2) rot_dict["2u"] = rot_mat([0, 1, 0], 1, 2) rot_dict["2v"] = rot_mat([-half, r32, 0], 1, 2) rot_dict["2w"] = rot_mat([-r32, half, 0], 1, 2) # Dictionary contains 12 hexagonal point operations return rot_dict
[docs] def get_cub_rot_dict(): """ Construct the rotation dictionary for cubic group 432. Returns ------- rot_dict : dict Dictionary mapping rotation names (str of 1 or 2 characters) to rotation matrices (numpy 3x3 float array). """ rot_dict = {} rot_dict["1"] = rot_mat([0, 0, 1], 0, 1) rot_dict["2x"] = rot_mat([1, 0, 0], 1, 2) rot_dict["2y"] = rot_mat([0, 1, 0], 1, 2) rot_dict["2z"] = rot_mat([0, 0, 1], 1, 2) rot_dict["4x"] = rot_mat([1, 0, 0], 1, 4) rot_dict["4X"] = rot_mat([1, 0, 0], 3, 4) rot_dict["4y"] = rot_mat([0, 1, 0], 1, 4) rot_dict["4Y"] = rot_mat([0, 1, 0], 3, 4) rot_dict["4z"] = rot_mat([0, 0, 1], 1, 4) rot_dict["4Z"] = rot_mat([0, 0, 1], 3, 4) rot_dict["2a"] = rot_mat([0, 1, 1], 1, 2) rot_dict["2b"] = rot_mat([0, 1, -1], 1, 2) rot_dict["2c"] = rot_mat([1, 0, 1], 1, 2) rot_dict["2d"] = rot_mat([-1, 0, 1], 1, 2) rot_dict["2e"] = rot_mat([1, 1, 0], 1, 2) rot_dict["2f"] = rot_mat([1, -1, 0], 1, 2) rot_dict["3a"] = rot_mat([1, 1, 1], 1, 3) rot_dict["3A"] = rot_mat([1, 1, 1], 2, 3) rot_dict["3b"] = rot_mat([1, -1, -1], 1, 3) rot_dict["3B"] = rot_mat([1, -1, -1], 2, 3) rot_dict["3c"] = rot_mat([-1, 1, -1], 1, 3) rot_dict["3C"] = rot_mat([-1, 1, -1], 2, 3) rot_dict["3d"] = rot_mat([-1, -1, 1], 1, 3) rot_dict["3D"] = rot_mat([-1, -1, 1], 2, 3) # Dictionary contains 24 cubic point operations return rot_dict
[docs] def rot_mat(axis, m, n): """ Construct a rotation matrix using the Rodrigues formula. Parameters ---------- axis : array-like of length 3 Rotation axis vector; need not be normalized. m : int Numerator of the rotation angle fraction. n : int Denominator of the rotation angle fraction; the rotation angle is ``2 * pi * m / n``. Returns ------- rot : numpy.ndarray, shape (3, 3) Rotation matrix corresponding to the specified axis and angle. """ r_axis = np.array(axis) r_axis = r_axis / np.linalg.norm(r_axis) # In case not normalized angle = m * 2 * np.pi / n iden = np.identity(3) skew = np.cross(iden, r_axis) # Rodriguez formula for rotation matrix rot = iden + np.sin(angle) * skew + (1 - np.cos(angle)) * skew @ skew return rot
[docs] def get_mult_table(rot_dict): """ Compute the multiplication table for a set of rotation matrices. Parameters ---------- rot_dict : dict Dictionary mapping rotation names (str) to 3x3 rotation matrices (numpy float arrays). Returns ------- table_dict : dict Dictionary embodying the multiplication table. Keys are 2-tuples of rotation names ``(rot1, rot2)`` and values are the name of the rotation equal to the matrix product ``mat1 @ mat2``. Raises ------ ValueError If the product of any two rotations has no match in ``rot_dict`` (group not closed) or more than one match (internal inconsistency). """ table_dict = {} for rot1, mat1 in rot_dict.items(): for rot2, mat2 in rot_dict.items(): rmat = mat1 @ mat2 # numpy matrix product match_list = [] for rot3, mat3 in rot_dict.items(): if np.linalg.norm(rmat - mat3) < 0.0001: match_list.append(rot3) matches = len(match_list) # check for closure and uniqueness if matches == 1: table_dict[(rot1, rot2)] = match_list[0] elif matches == 0: raise ValueError( f"No match found for {rot1}, {rot2};" + " group is not closed" ) else: raise ValueError( f"{matches} matches found for {rot1}, {rot2};" + " something is wrong" ) return table_dict