Utils package

pyece.utils.coordinates module

This module serves as tool to convert arrays from one type of coordinates to another.

There are basically 4 different types of coordinates (See Description):
  • Cartesian: Coordinate representation in a Euclidean space formed by orthonormal vectors. The coordinate system is independent of the lattice/unitcell. No conversion function from cartesian to fractional coordinates is implemented in this module. However, it is handled in the Lattice object from Pymatgen (see get_fractional_coords and get_cartesian_coords)

  • Fractional: Coordinate representation in a space formed by the lattice vectors. Given the lattice matrix formed by the lattice vectors \(L=[\vec{a} \; \vec{b} \; \vec{c}]\) and the cartesian coordiantes \(\vec{x}\), the fractional coordiantes \(\vec{f}\) are defined as \(\vec{x} = L \vec{f}\). Hence fractional coordinates comprised between 0 and 1 correspond to a point within the unitcell.

  • Unitcell: On-lattice coordinate representation that is defined by the cell coordinates and the basis index. Knowing that a point \(\vec{f}\) corresponds to a lattice site, it is sufficient to know the coordinates of the cell \(\vec{n}\), which is defined by a integer vector in fractional coordiantes, and the corresponding i’th basis site with fractional coordinates \(\vec{b}_i\) relative to this cell, such that \(\vec{f} = \vec{n} + \vec{b}_i\). The first 3 coordinates correspond to the cell coordinates, while the last coordinate refers to the index of the basis.

  • Affine: Coordinate representation to incorporate translation transformation in addition to unual rotation transformations. It basically consists in adding a 1 to the space coordinates. Refer to the Wikipedia page Affine transformation.

Warning

All arrays respect the row-wise convention.

fractional_to_unitcell(fractional_array: numpy.ndarray, fractional_basis: numpy.ndarray, decimals: int = 6) numpy.typing.NDArray.numpy.int_

Converts an array of fractional coordinates into an array of unitcell coordinates

Parameters:
  • fractional_array (np.ndarray) –

    Numpy array of fractional coordinates to be converted

    Warning

    The array’s innermost dimension is expected to be 3 (3 dimensional space).

  • fractional_basis (np.ndarray) –

    Numpy array of fractional coordinates of the basis positions within the unitcell.

    Warning

    The array’s innermost dimension is expected to be 3 (3 dimensional space).

    Tip

    This parameter typically corresponds to the basis attribute of Prim objects.

  • decimals (int, default: 6) – Number of decimals to be round off

Returns:

unitcell_array – Numpy array of unitcell coordinates

Note

The array’s innermost dimension is 4 (3 dimensional space + 1 basis index).

Return type:

np.ndarray[int]

Example

The following snippets illustrate several common systems:

>>> import numpy as np
>>> from pyece.utils.coordinates import fractional_to_unitcell

>>> # BCC lattice
>>> basis = np.array([[0, 0, 0]])
>>> array = np.array([[[1, 0, 0],
...                    [0, 1, 0]],
...                   [[0, 0, 1],
...                    [0, 1, 2]]])
>>> fractional_to_unitcell(array, basis)
np.array([[[1, 0, 0, 0],
           [0, 1, 0, 0]],
          [[0, 0, 1, 0],
           [0, 1, 2, 0]]])

>>> # Omega lattice
>>> basis = np.array([[0.000, 0.000, 0.000],
...                   [0.333, 0.333, 0.500],
...                   [0.667, 0.667, 0.500]])
>>> cell_coords = np.array([[ 0,  2,  0],
...                         [ 1,  0,  1],
...                         [ 0,  2, -1],
...                         [-1, -1,  1]])
>>> basis_indexes = np.array([1, 0, 2, 1])
>>> array = cell_coords + np.take(basis, basis_index, axis=0)
>>> array
np.array([[ 0.333,  2.333,  0.500],
          [ 1.000,  0.000,  1.000],
          [ 0.667,  2.667, -0.500],
          [-0.667, -0.667,  1.500]])
>>> fractional_to_unitcell(array, basis)
np.array([[[ 0,  2,  0,  1],
           [ 1,  0,  1,  0],
           [ 0,  2, -1,  2],
           [-1, -1,  1,  1]])
from_affine(affine_array: numpy.ndarray) numpy.ndarray

Transform an affine array to non-affine by removing the column of 1

Parameters:

affine_array (np.ndarray) –

Numpy array to be transformed. The coordinates can be of cartesian or fractional type.

Warning

The last entry of the innermost dimension is expected to be 1.

Returns:

array – Numpy array

Return type:

np.ndarray

Example

Example of an array of coordinates converted from affine:

>>> import numpy as np
>>> from pyece.utils.coordinates import from_affine

>>> array = np.array([[[  0.000,  0.000,  0.000,  1.000],
...                    [  0.333, -0.200, -0.700,  1.000]],
...                   [[  0.600,  0.167, -0.500,  1.000],
...                    [ -1.300,  0.666,  0.700,  1.000]]])
>>> from_affine(array)
np.array([[[  0.000,  0.000,  0.000],
           [  0.333, -0.200, -0.700],
          [[  0.600,  0.167, -0.500],
           [ -1.300,  0.666,  0.700]]])
to_affine(array: numpy.ndarray) numpy.ndarray

Transform an array to affine by adding a column of 1

Parameters:

array (np.ndarray) – Numpy array to be transformed. The coordinates can be of cartesian or fractional type.

Returns:

affine_array – Numpy array

Return type:

np.ndarray

Example

Example of an array of coordinates converted to affine:

>>> import numpy as np
>>> from pyece.utils.coordinates import to_affine

>>> array = np.array([[[  0.000,  0.000,  0.000],
...                    [  0.333, -0.200, -0.700]],
...                   [[  0.600,  0.167, -0.500],
...                    [ -1.300,  0.666,  0.700]]])
>>> to_affine(array)
np.array([[[  0.000,  0.000,  0.000,  1.000],
           [  0.333, -0.200, -0.700,  1.000]],
          [[  0.600,  0.167, -0.500,  1.000],
           [ -1.300,  0.666,  0.700,  1.000]]])
unitcell_to_fractional(unitcell_array: numpy.typing.NDArray.numpy.int_, fractional_basis: numpy.ndarray) numpy.ndarray

Converts an array of unitcell coordinates into an array of fractional coordinates

Parameters:
  • unitcell_array (np.ndarray[int]) –

    Numpy array of unitcell coordinates to be converted

    Warning

    The array’s innermost dimension is expected to be 4 (3 dimensional space + 1 basis index).

  • fractional_basis (np.ndarray) –

    Numpy array of fractional coordinates of the basis positions within the unitcell.

    Warning

    The array’s innermost dimension is expected to be 3 (3 dimensional space).

    Tip

    This parameter typically corresponds to the basis attribute of Prim objects.

Returns:

fractional_array – Numpy array of fractional coordinates

Note

The array’s innermost dimension is 3 (3 dimensional space).

Return type:

np.ndarray

Example

The following snippets illustrate several common systems:

>>> import numpy as np
>>> from pyece.utils.coordinates import unitcell_to_fractional

>>> # BCC lattice
>>> basis = np.array([[0, 0, 0]])
>>> array = np.array([[[1, 0, 0, 0],
...                    [0, 1, 0, 0]],
...                   [[0, 0, 1, 0],
...                    [0, 1, 2, 0]]])
>>> unitcell_to_fractional(array, basis)
np.array([[[1, 0, 0],
           [0, 1, 0]],
          [[0, 0, 1],
           [0, 1, 2]]])

>>> # Omega lattice
>>> basis = np.array([[0.000, 0.000, 0.000],
...                   [0.333, 0.333, 0.500],
...                   [0.667, 0.667, 0.500]])
>>> cell_coords = np.array([[ 0,  2,  0],
...                         [ 1,  0,  1],
...                         [ 0,  2, -1],
...                         [-1, -1,  1]])
>>> basis_indexes = np.array([1, 0, 2, 1])
>>> array = np.hstack([cell_coords, basis_indexes.reshape(-1, 1)])
>>> array
np.array([[[ 0,  2,  0,  1],
           [ 1,  0,  1,  0],
           [ 0,  2, -1,  2],
           [-1, -1,  1,  1]])
>>> unitcell_to_fractional(array, basis)
np.array([[ 0.333,  2.333,  0.500],
          [ 1.000,  0.000,  1.000],
          [ 0.667,  2.667, -0.500],
          [-0.667, -0.667,  1.500]])

pyece.utils.mapping module

pyece.utils.symmetry module

generate_rotation_matrices(structure: pymatgen.core.structure.Structure, cartesian: bool = False, symprec: float = 0.01, angle_tolerance: float = 0.1)

Obtain all rotation matrices from the primitive structure using space group analyzer from pymatgen (see SpacegroupAnalyzer).

Parameters:
  • parent_structure (Structure) – Pymatgen structure

  • cartesian (bool, default: False) – Boolean structure to set to True if one desires the rotation matrices in cartesian coordinates, or set it to False if fractional coordinates is desired.

  • symprec (float, default: 0.01) – Tolerance for symmetry finding used in Pymatgen SpaceGroupAnalyzer.

  • angle_tolerance (float, default: 0.1) –

    Angle tolerance (in degrees) for symmetry finding used in Pymatgen SpaceGroupAnalyzer.

Returns:

Numpy array of rotation matrices obatined from the primitive strucutre.

Return type:

np.ndarray

Warning

All matrices respect the row-wise convention (row vectors).

generate_spacegroup_matrices(structure: pymatgen.core.structure.Structure, cartesian: bool = False, symprec: float = 0.01, angle_tolerance: float = 0.1)

Obtain all affine symmetry operation matrices from the primitive structure using space group analyzer from pymatgen (see SpacegroupAnalyzer).

Parameters:
  • parent_structure (Structure) – Pymatgen structure

  • cartesian (bool, default: False) – Boolean structure to set to True if one desires the symmetry operation matrices in cartesian coordinates, or set it to False if fractional coordinates is desired.

  • symprec (float, default: 0.01) –

    Tolerance for symmetry finding used in Pymatgen SpaceGroupAnalyzer.

  • angle_tolerance (float, default: 0.1) –

    Angle tolerance (in degrees) for symmetry finding used in Pymatgen SpaceGroupAnalyzer.

Returns:

Numpy array of affine symmetry matrices, defined up to lattice translation, obtained from the primitive strucutre.

Return type:

np.ndarray

Warning

All matrices respect the row-wise convention (row vectors).

get_cosets(multiplication_table: numpy.typing.NDArray.numpy.int_, subgroup_indexes: numpy.typing.NDArray.numpy.int_) numpy.typing.NDArray.numpy.int_

Construct the left cosets out of a multiplication table and the indexes of the operation belonging to the subgroup.

Parameters:
  • multiplication_table (np.ndarray[int]) – Integer numpy array of the indexes of the resulting matrix of the multiplication of the matrices i and j.

  • subgroup_indexes (np.ndarray[int]) – Integer numpy array with the indexes of the symmetry operation belonging in the subgroup.

Returns:

cosets – Integer numpy array of the indexes of symmetry operations where each row correponds to a coset.

Return type:

np.ndarray[int]

get_multiplication_table(group: numpy.ndarray, decimals: int = 6) numpy.typing.NDArray.numpy.int_

Construct the multiplication table (Cayley table) of an array containing the spacegroup symmetry operations.

Parameters:
  • group (np.ndarray) – Nx4x4 numpy array of the spacegroup operation matrices, defined up to lattice translation, in fractional affine format, where N is the group order.

  • decimals (int, default: 6) – Number of decimals to be round off.

Returns:

multiplication_table – Integer numpy array of the indexes of the resulting matrix of the multiplication of the matrices i and j.

Return type:

np.ndarray[int]

group_action(group: numpy.ndarray, set_points: numpy.ndarray) numpy.ndarray

Apply all symmetry operations of a spacegroup to a set of points (See Description).

Parameters:
  • group (np.ndarray) – Nx4x4 numpy array of the spacegroup operation matrices, defined up to lattice translation, in fractional affine format, where N is the group order (number of elements in the group).

  • set_points (np.ndarray) – Mx3 numpy array of a set of points in fractional coordinates, defined up to lattice translation, where M is the set order (number of points in the set).

Returns:

Numpy array of unicell coordinates of all points in the set applied to all group symmetry operations (group.shape + set_points.shape)

Return type:

np.ndarray

Examples

The following example illustrate the unique set of points (orbit) of the group action of a set of points corresponding to the nearest neighbor pair cluster of a BCC structure:

>>> import numpy as np
>>> from pymatgen.core import Structure
>>> from pyece.utils.symmetry import generate_spacegroup_matrices, group_action

>>> bcc = Structure([[-1, 1, 1], [1, -1, 1], [1, 1, -1]],
...                       ["Fe"],
...                       [[0, 0, 0]])
>>> sg = generate_spacegroup_matrices(bcc)
>>> len(sg)
48
>>> ga = group_action(sg, NN_pair)
>>> len(ga)
48
>>> np.unique(ga)
np.array([[[ 0.  0.  0.],
           [-1. -1. -1.]],
          [[ 0.  0.  0.],
           [-1.  0.  0.]],
          [[ 0.  0.  0.],
           [ 0. -1.  0.]],
          [[ 0.  0.  0.],
           [ 0.  0. -1.]],
          [[ 0.  0.  0.],
           [ 0.  0.  1.]],
          [[ 0.  0.  0.],
           [ 0.  1.  0.]],
          [[ 0.  0.  0.],
           [ 1.  0.  0.]],
          [[ 0.  0.  0.],
           [ 1.  1.  1.]]])

pyece.utils.toolbox module

find(array: numpy.ndarray, x: numpy.ndarray, tolerance: float = 1e-06) tuple

Find the indexes of all elements in array equal to the search element x, given a tolerance. The search element x must correspond to the innermost dimensions of the array.

Parameters:
  • array (np.ndarray) – Numpy array to search the search element x within. The innermost dimensions must be the same as the dimensions of x

  • x (np.ndarray) – Numpy array of the element x to be searched

  • tolerance (float, default: 1e-6) – Tolerance in the equality

Returns:

Indices of elements in array that are equal to x.

Return type:

tuple

Example

Various examples of searches of elements of different ranks (from rank 0 to rank 2):

>>> import numpy as np
>>> from pyece.utils.toolbox import find

>>> # x = rank 0; array = rank 2
>>> array = np.array([[0.111, -0.300, 0.123, 0.873, 0.631],
...                   [0.324, 0.873, -0.540, 0.173, 0.305]])
>>> x = np.array(0.873)
>>> find(array, x)
(array([0, 1]), array([3, 1]))

>>> # x = rank 1; array = rank 3
>>> array = np.array([[[1, 0, 3], [-1, 2, 3]],
...                   [[1, 2, 3], [-1, 2, 1]],
...                   [[3, 2, 1], [ 3, 1, 2]],
...                   [[1, 0, 3], [ 1, 2, 3]]])
>>> x = np.array([1, 2, 3])
>>> find(array, x)
(array([1, 3]), array([0, 1]))

>>> # x = rank 2; array = rank 3
>>> array = np.array([[[0.1, -0.2, 0.1], [ 0.4,  1.3, -0.9]],
...                   [[0.9,  0.1, 0.2], [-0.3, -0.3,  1.0]],
...                   [[0.2, -0.1, 0.6], [-0.1, -0.8,  2.4]],
...                   [[0.9,  0.1, 0.2], [-0.3, -0.3,  1.0]]])
>>> x = np.array([[0.9, 0.1, 0.2], [-0.3, -0.3, 1.0]])
>>> find(array, x)
(array([1, 3]),)
is_integer(array: numpy.ndarray) numpy.bool_

Checks if the array is composed of integers

Parameters:

array (np.ndarray) – Numpy array to be checked

Returns:

Boolean value being True if the array is entirely made of integers.

Return type:

bool

merge_dict(base_dict: dict, dict_to_add: dict) dict

Merges two dictionaries together, keys present in both dictionaries are gathered as lists.

Parameters:
  • base_dict (dict) – Base dictionary.

  • dict_to_add (dict) – Dictionary to be added to the base dictionary.

Returns:

Merged dictionary

Return type:

dict

segment(src: torch.Tensor, ptr: torch.Tensor, reduce: str = 'sum') torch.Tensor

Reduces all values in the last dimension of a source tensor within the ranges specified in a pointer tensor.

Parameters:
  • src (Tensor) – Pytorch tensor with the source tensor

  • ptr (Tensor) – Integer pytorch tensor of a monotonically increasing pointer tensor that refers to the boundaries of segments such that ptr[0] = 0 and ptr[-1] = src.size(0) (see Compressed Sparse Row (CSR)).

  • reduce (str, default = 'sum') – String with the reduction method to be chosen between ‘sum’ and ‘mean’.

Example

An example of the segment reduction of a rank 2 tensor:

>>> from torch import tensor
>>> from pyece.utils.toolbox import segment

>>> src = tensor([[ 1,  2,  3,  4,  5,  6,  7,  8],
...               [ 1, -3,  4,  6, -8,  2,  5,  5],
...               [ 0,  3, -1, -5,  9, -7,  3,  2]]).float()
>>> ptr = tensor([0, 3, 4, 7])
>>> segment(src, ptr)
tensor([[ 6.,  4., 18.],
        [ 2.,  6., -1.],
        [ 2., -5.,  5.]])
>>> segment(src, ptr, reduce="mean")
tensor([[ 2.0000,  4.0000,  6.0000],
        [ 0.6667,  6.0000, -0.3333],
        [ 0.6667, -5.0000,  1.6667]])
within(array: numpy.ndarray, decimals: int = 6) numpy.ndarray

Wrap the values of an array within [0,1[.

Parameters:
  • array (np.ndarray) – Numpy array to be modified

  • decimals (int, default: 6) – Number of decimals to be round off.

Returns:

Numpy array with values within [0,1[.

Return type:

np.ndarray