SOFI interface

class ira_mod.SOFI(shlib='')[source]

The Symmetry Operation FInder (SOFI) is an algorithm for finding point group symmetry operations of atomic structures. It solves the problem:

\[A = \theta A\]

where \(A\) is an atomic structure, and \(\theta\) is a symmetry operation in the form of 3x3 orthonormal matrix.

The main result of SOFI is a list of operations \(\theta\). This list can be post-processed to obtain the point group name, and other properties associated to each \(\theta\).

For further details see the publication:

M Gunde, N Salles, L Grisanti, L Martin-Samos, A Hemeryck: J. Chem. Phys. 2024, 161, 6, 062503 DOI: https://doi.org/10.1063/5.0215689 arXiv: https://arxiv.org/abs/2408.06131

In order to use the module, the path to this file should be added to the environment variable PYTHONPATH:

export PYTHONPATH=/your/path/to/IRA/interface

Example import:

>>> import ira_mod
>>> sofi = ira_mod.SOFI( )
compute(nat, typ_in, coords, sym_thr, origin=None, prescreen_ih=False)[source]

this is a wrapper to libira_compute_all() from library_sofi.f90 Description: This routine computes all the relevant PG symmetry data of the input structure. Unless an origin point is specified, the input structure is shifted to the geometric center by this python interface.

== input: ==

Parameters
  • nat (int) – number of atoms in the structure

  • typ_in (string or int) – atomic types of the atoms

  • coords (np.ndarray((nat,3), dtype=float)) – the atomic positions of the structure

  • sym_thr (float) – symmetry threshold value

== optional: ==

Parameters
  • origin (np.ndarray(3, dtype=float)) – if specified, it will be taken as origin point, otherwise the geometric center is the origin

  • prescreen_ih – if True, force sofi to check for Ih group already during computation.

== output: ==

instance of ira_mod.sym_data() object, which cotains the full symmetry data of the input structure. See sym_data.

object sym_data contains the full symmetry data of the input structure. To access info about symmetry element i, get the data as: sym_data.var[i], where var is one of the variables in the sym_data object:

n_sym, matrix, perm, op, n, p, axis, angle, dHausdorff, pg, prin_ax

see help( ira_mod.sym_data ) for full description of these variables.

get_symm_ops(nat, typ_in, coords, sym_thr, prescreen_ih=False)[source]

Wrapper to the libira_get_symm_ops routine from library_sofi.f90. Description: finds the symmetry operation maytices of the structure in input, which fit the threshold sym_thr.

== input: ==

Parameters
  • nat (int) – number of atoms in the structure

  • typ_in (string or int) – atomic types of the atoms

  • coords (np.ndarray((nat,3), dtype=float)) – the atomic positions of the structure

  • sym_thr (float) – symmetry threshold value

== optional ==

Parameters

prescreen_ih – if True, force sofi to check for Ih group already during computation.

== output: ==

Parameters
  • n_sym (int) – number of symmetry elements found

  • matrix (np.ndarray((n_sym, 3, 3), dtype = float)) – the list of matrices of symmetry operations

get_pg(nm_in, mat_list, verb=False)[source]

wrapper to libira_get_pg() from library_sofi.f90 Description: find the PG of input list of operations. Returns also the list of all equivalent principal axes.

== input: ==

Parameters
  • nm_in (integer) – number of matrices in the mat_list array

  • mat_list (np.ndarray( (nm_in, 3, 3), dtype = float )) – list of matrices containging symmetry operations

== optional ==

Parameters

verb (logical) – verbosity of the output, verb=True outputs a report from get_pg() routine.

== output: ==

Parameters
  • pg (string) – associated Point Group (PG)

  • n_prin_ax (integer) – number of equivalent principal axes

  • prin_ax (np.ndarray( (n_prin_ax, 3), dtype = float )) – list of principal axes of the PG

get_unique_ax_angle(nm_in, mat_list)[source]

wrapper to libira_get_unique_ax_angle() from library_sofi.f90 Description: input list of symmetry matrices, output lists of op, ax, angle for each symmetry operation in the list, such that axes are aligned, and angle has a correspoding +/- sign.

This is a wrapper to libira_unique_ax_angle() routine from library_sofi.f90

== input: ==

Parameters
  • nm_in (integer) – number of matrices in the mat_list array

  • mat_list (np.ndarray( (nm_in, 3, 3), dtype = float )) – list of matrices containging symmetry operations

== output: ==

Parameters
  • op (array of length-1 strings, nd.ndarray( nm_in, dtype = "U1" )) – Schoeflies Op name, possible values: - “E” = identity - “I” = inversion - “C” = rotation - “S” = (roto-)reflection

  • axis (nm_in x 3 vector, np.ndarray((nm_in, 3), dtype = float)) – the list of axes along each corresponding matrix acts.

  • angle (np.ndarray( nm_in, dtype = float )) – the list of angles by which each matrix rotates, in units of 1/(2pi), e.g. the value angle = 0.5 means half the circle, and angle = -1.0/6.0 means rotation about the axis in negative direction for 1/6th of the circle

analmat(rmat)[source]

Description: analyse the input matrix, output the Schoenflies notation: Op n^p, the axis, and angle. The notation can be transformed into an angle in radians, or degree:

angle_radian = p / n * 2pi angle_degree = p / n * 360

e.g. C 8^3 corresponds to 3/8th of full circle = 135 degress = 2.3563 radian, p/n = 0.375

This is a wrapper to libira_analmat() routine from library_sofi.f90

== input: ==

Parameters

rmat (np.ndarray((3, 3), dtype = float )) – input matrix

== output: ==

Parameters
  • op (string) – Schoeflies Op name, possible values: - “E” = identity - “I” = inversion - “C” = rotation - “S” = (roto-)reflection

  • n (integer) – the n value from Op n^p, gives the angle 2pi/n

  • p (integer) – the p value from Op n^p, gives the “multiplicity” of 1/n operation

  • ax (3D vector, np.ndarray(3, dtype = float)) – axis along which the matrix rmat operates, in case of rotation is the axis of rotation, in case of (roto-)reflection is the normal of the plane of reflection.

  • angle (np.float32) – the angle of rotation of matrix rmat, in units of 1/2pi, is the ratio p/n

ext_Bfield(n_mat, mat_list, b_field)[source]

wrapper to libira_ext_Bfield() from library_sofi.f90 Description: Impose a constraint on the relevant symmetry operations, in the form of an external magnetic field as arbitrary vector.

Implementation of the functionality proposed in:

Ansgar Pausch, Melanie Gebele, Wim Klopper; Molecular point groups and symmetry in external magnetic fields. J. Chem. Phys. 28 November 2021; 155 (20): 201101. DOI: https://doi.org/10.1063/5.0069859

The magnetic field acts as an “external constraint” on the symmetry matrices, and can thus be seen as a post-processing of the unconstrained (full) PG of a structure.

== Input: ==

Parameters
  • n_mat (integer) – number of matrices in the input mat_list

  • mat_list (np.ndarray((n_mat, 3, 3), dtype = float )) – list of 3x3 matrices of symmetry operations in input

  • b_field (3d vector, np.ndarray(3, dtype = float )) – direction of magnetic field

== output: ==

Parameters
  • n_op (integer) – number of operations that fulfill the constraint of the desired magnetic field

  • matrix (np.ndarray( (n_op, 3, 3), dtype = float )) – the list of matrices that act on the system constrained by the desired magnetic field

get_perm(nat, typ_in, coords, nm_in, mat_list)[source]

Description: Obtain the list of permutations and maximal distances for each matrix in input.

This is a wrapper to libira_get_perm() from library_sofi.f90

== Input: ==

Parameters
  • nat (integer) – number of atoms in the structure

  • typ_in (np.ndarray( nat, dtype = integer or string )) – atomic types of the structure

  • coords (np.ndarray((nat, 3), dtype = float )) – atomic positions in the structure

  • nm_in (integer) – number of matrices in the mat_list input

  • mat_list (np.ndarray( (nm_in, 3, 3), dtype = float )) – list of input matrices

== Output: ==

Parameters
  • perm (np.ndarray( (nm_in, nat), dtype = integer )) – list of permutations corresponding to each matrix operation in input

  • dHausdorff (np.ndarray( nm_in, dtype = float )) – maximal distance (Hausdorff distance) corresponding to the application off each matrix in the mat_list to the structure. Can be seen as “score” of each symmetry

get_combos(nat, typ_in, coords, nm_in, mat_list)[source]

Description: Obtain all unique combinations of input matrices, which are symmetry operations of given structure.

This is a wrapper to the routine libira_get_combos() from library_sofi.f90

== Input: ==

Parameters
  • nat (integer) – number of atoms in the structure

  • typ_in (np.ndarray( nat, dtype = integer or string )) – atomic types of the structure

  • coords (np.ndarray((nat, 3), dtype = float )) – atomic positions in the structure

  • nm_in (integer) – number of matrices in the mat_list input

  • mat_list (np.ndarray( (nm_in, 3, 3), dtype = float )) – list of input matrices

== Output: ==

Parameters
  • nm_out (integer) – number of matrices in the output list mat_out

  • mat_out (np.ndarray( (nm_out, 3, 3), dtype = float )) – list of output matrices

try_mat(nat, typ_in, coords, theta)[source]

Description: Apply a given matrix theta to the structure, and compute the distance between the transformed and original structure. If the distance is small, then theta is a symmetry operation (or close to). The distance is computed in a permutationally invariant way, using the CShDA algorithm, which imposes a one-to-one assignment of the atoms. The value of distance corresponds to the maximal value of distances between all assigned atomic pairs, which is the Hausdorff distance.

This is a wrapper to libira_try_mat() routine from library_sofi.f90

== Input: ==

Parameters
  • nat (integer) – number of atoms in the structure

  • typ_in (np.ndarray( nat, dtype = integer or string )) – atomic types of the structure

  • coords (np.ndarray((nat, 3), dtype = float )) – atomic positions in the structure

  • theta (np.ndarray((3,3), dtype = float)) – the input matrix of an orthonormal operation to be tested on structure

== Output: ==

Parameters
  • dh (float) – the Hausdorff distance value

  • perm (np.ndarray((nat), dtype = int )) – permutations of atoms which were assignmed by CShDA upon application of theta

construct_operation(op, axis, angle)[source]

Description: Construct the 3x3 matrix corresponding to operation encoded by the Schoenflies Op, such that it acts along the desired axis, and given angle.

This is a wrapper to libira_construct_operation() routine from library_sofi.f90

== Input: ==

Parameters
  • op (string) – Schoeflies Op name, possible values: - “E” = identity - “I” = inversion - “C” = rotation - “S” = (roto-)reflection

  • axis (3D vector, np.ndarray(3, dtype = float)) – the axis along which the desired operation should act

  • angle (float) – the angle by which the desired operation should rotate, in units of 1/(2pi), e.g. the value angle = 0.5 means half the circle, and angle = -1.0/6.0 means rotation about the axis in negative direction for 1/6th of the circle

== Output: ==

Parameters

matrix (3x3 matrix, np.ndarray((3, 3), dtype = float )) – the matrix representation of desired operation

Note

The operation “E” is equivalent to “C” about any axis for angle=0.0; and similarly the operation “I” is equivalent to “S” with angle=0.5 about any axis. The operation “S” with angle=0.0 is a reflection.

mat_combos(nm_in, mat_list)[source]

Description: Obtain all unique combinations of matrices in input, without checking them against any specific structure.

This is a wrapper to routine libira_mat_combos() from library_sofi.f90

== Input: ==

Parameters
  • nm_in (integer) – number of matrices in the mat_list input

  • mat_list (np.ndarray( (nm_in, 3, 3), dtype = float )) – list of input matrices

== Output: ==

Parameters
  • nm_out (integer) – number of matrices in the output list mat_out

  • mat_out (np.ndarray( (nm_out, 3, 3), dtype = float )) – list of output matrices

matrix_distance(m1, m2)[source]

Compute the distance between two matrices using the matrix_distance function. This function is used internally in SOFI to determine if two matrices are equal or not, if the value of distance is below m_thr, then the matrices are considered equal. By default, m_thr = 0.73 which should be enough to distinguish matrices separated by operation equivalent to C 12^1. These values can be found in sofi_tools.f90

== input ==

Parameters
  • m1 (np.ndarray( [3, 3], dtype = float)) – matrix 1

  • m2 (np.ndarray( [3, 3], dtype = float)) – matrix 2

== output ==

Parameters

d (float) – distance value

check_collinear(nat, coords)[source]

Check if the input structure is collinear or not.

== input ==

Parameters
  • nat (int) – number of atoms in the structure

  • coords (np.ndarray((nat,3), dtype=float)) – the atomic positions of the structure

== output ==

Parameters
  • collinear (bool) – true if structure is collinear

  • ax (np.ndarray(3, dtype=float)) – axis of collinearity, if structure is collinear

class ira_mod.sym_data[source]

Definition of the object, which is returned by ira_mod.SOFI.compute()

Members of the object:

Parameters
  • n_sym (int) – number of symmetry elements found

  • matrix (np.ndarray((n_sym, 3, 3), dtype = float)) – the list of matrices of symmetry operations

  • perm (np.ndarray((n_sym, nat), dtype = int)) – the atomic permutation corresponding to application of that symmetry, start by index 0

  • op (np.ndarray((n_sym), type="U1"); size-1 strings) – Schoenflies notation: Op n^p; E=identity, I=inversion, C=rotation, S=(roto-)inversion

  • n (np.ndarray(n_sym, dtype = int )) – Schoenflies notation n

  • p (np.ndarray(n_sym, dtype = int )) – Schoenflies notation p

  • axis (np.ndarray((n_sym, 3), dtype = float )) – the axis over which a symmetry element operates (for S: normal vector to plane)

  • angle (np.ndarray(n_sym, dtype = float )) – angle of rotation of a symmetry element, in units of 1/2pi, e.g. angle=0.25 is 1/4 circle

  • dHausdorff (np.ndarray(n_sym, dtype = float )) – maximal displacement of any atom upon transformation by that symmetry matrix

  • pg (str) – point group of the structure

  • prin_ax (np.ndarray( 3, dtype = float )) – principal axis of the PG

Function print

prints the full data of the sym_data object

print()[source]

print the members of sym_data() instance