Hide keyboard shortcuts

Hot-keys on this page

r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1""" 

2This module provides a Python interface to the MatrixOfEquivalentPositions 

3class with supplementary functions. 

4""" 

5 

6from typing import List, Tuple 

7 

8import numpy as np 

9import spglib 

10 

11from ase import Atoms 

12from _icet import MatrixOfEquivalentPositions 

13from icet.core.lattice_site import LatticeSite 

14from icet.core.neighbor_list import get_neighbor_lists 

15from icet.core.structure import Structure 

16from icet.input_output.logging_tools import logger 

17from icet.tools.geometry import (ase_atoms_to_spglib_cell, 

18 get_fractional_positions_from_neighbor_list, 

19 get_primitive_structure) 

20 

21logger = logger.getChild('matrix_of_equivalent_positions') 

22 

23 

24def matrix_of_equivalent_positions_from_structure(structure: Atoms, 

25 cutoff: float, 

26 position_tolerance: float, 

27 symprec: float, 

28 find_primitive: bool = True) \ 

29 -> Tuple[np.ndarray, Structure, List]: 

30 """Sets up a list of permutation maps from an Atoms object. 

31 

32 Parameters 

33 ---------- 

34 structure 

35 input structure 

36 cutoff 

37 cutoff radius 

38 find_primitive 

39 if True the symmetries of the primitive structure will be employed 

40 symprec 

41 tolerance imposed when analyzing the symmetry using spglib 

42 position_tolerance 

43 tolerance applied when comparing positions in Cartesian coordinates 

44 

45 Returns 

46 ------- 

47 The tuple that is returned comprises the permutation matrix, the 

48 primitive structure, and the neighbor list. 

49 """ 

50 

51 structure = structure.copy() 

52 structure_prim = structure 

53 if find_primitive: 

54 structure_prim = get_primitive_structure(structure, symprec=symprec) 

55 logger.debug('Size of primitive structure: {}'.format(len(structure_prim))) 

56 

57 # get symmetry information 

58 structure_as_tuple = ase_atoms_to_spglib_cell(structure_prim) 

59 symmetry = spglib.get_symmetry(structure_as_tuple, symprec=symprec) 

60 translations = symmetry['translations'] 

61 rotations = symmetry['rotations'] 

62 

63 # set up a permutation map object 

64 matrix_of_equivalent_positions = MatrixOfEquivalentPositions(translations, rotations) 

65 

66 # create neighbor_lists from the different cutoffs 

67 prim_icet_structure = Structure.from_atoms(structure_prim) 

68 

69 neighbor_list = get_neighbor_lists(prim_icet_structure, 

70 [cutoff], 

71 position_tolerance=position_tolerance)[0] 

72 

73 # get fractional positions for neighbor_list 

74 frac_positions = get_fractional_positions_from_neighbor_list( 

75 prim_icet_structure, neighbor_list) 

76 

77 logger.debug('Number of fractional positions: {}'.format(len(frac_positions))) 

78 if frac_positions is not None: 78 ↛ 81line 78 didn't jump to line 81, because the condition on line 78 was never false

79 matrix_of_equivalent_positions.build(frac_positions) 

80 

81 return matrix_of_equivalent_positions, prim_icet_structure, neighbor_list 

82 

83 

84def _get_lattice_site_matrix_of_equivalent_positions( 

85 structure: Structure, 

86 matrix_of_equivalent_positions: MatrixOfEquivalentPositions, 

87 fractional_position_tolerance: float, 

88 prune: bool = True) -> np.ndarray: 

89 """ 

90 Returns a transformed permutation matrix with lattice sites as entries 

91 instead of fractional coordinates. 

92 

93 Parameters 

94 ---------- 

95 structure 

96 primitive atomic icet structure 

97 matrix_of_equivalent_positions 

98 permutation matrix with fractional coordinates format entries 

99 fractional_position_tolerance 

100 tolerance applied when evaluating distances in fractional coordinates 

101 prune 

102 if True the permutation matrix will be pruned 

103 

104 Returns 

105 ------- 

106 permutation matrix in a row major order with lattice site format entries 

107 """ 

108 pm_frac = matrix_of_equivalent_positions.get_equivalent_positions() 

109 

110 pm_lattice_sites = [] 

111 for row in pm_frac: 

112 positions = _fractional_to_cartesian(row, structure.cell) 

113 lattice_sites = [] 

114 if np.all(structure.pbc): 114 ↛ 118line 114 didn't jump to line 118, because the condition on line 114 was never false

115 lattice_sites = structure.find_lattice_sites_by_positions( 

116 positions=positions, fractional_position_tolerance=fractional_position_tolerance) 

117 else: 

118 for pos in positions: 

119 try: 

120 lattice_site = structure.find_lattice_site_by_position( 

121 position=pos, fractional_position_tolerance=fractional_position_tolerance) 

122 except RuntimeError: 

123 continue 

124 lattice_sites.append(lattice_site) 

125 if lattice_sites is not None: 125 ↛ 128line 125 didn't jump to line 128, because the condition on line 125 was never false

126 pm_lattice_sites.append(lattice_sites) 

127 else: 

128 logger.warning('Unable to transform any element in a column of the' 

129 ' fractional permutation matrix to lattice site') 

130 if prune: 130 ↛ 139line 130 didn't jump to line 139, because the condition on line 130 was never false

131 logger.debug('Size of columns of the permutation matrix before' 

132 ' pruning {}'.format(len(pm_lattice_sites))) 

133 

134 pm_lattice_sites = _prune_matrix_of_equivalent_positions(pm_lattice_sites) 

135 

136 logger.debug('Size of columns of the permutation matrix after' 

137 ' pruning {}'.format(len(pm_lattice_sites))) 

138 

139 return pm_lattice_sites 

140 

141 

142def _prune_matrix_of_equivalent_positions(matrix_of_equivalent_positions: List[List[LatticeSite]]): 

143 """ 

144 Prunes the matrix so that the first column only contains unique elements. 

145 

146 Parameters 

147 ---------- 

148 matrix_of_equivalent_positions 

149 permutation matrix with LatticeSite type entries 

150 """ 

151 

152 for i in range(len(matrix_of_equivalent_positions)): 

153 for j in reversed(range(len(matrix_of_equivalent_positions))): 

154 if j <= i: 

155 continue 

156 if matrix_of_equivalent_positions[i][0] == matrix_of_equivalent_positions[j][0]: 

157 matrix_of_equivalent_positions.pop(j) 

158 logger.debug('Removing duplicate in permutation matrix' 

159 'i: {} j: {}'.format(i, j)) 

160 return matrix_of_equivalent_positions 

161 

162 

163def _fractional_to_cartesian(fractional_coordinates: List[List[float]], 

164 cell: np.ndarray) -> List[float]: 

165 """ 

166 Converts cell metrics from fractional to cartesian coordinates. 

167 

168 Parameters 

169 ---------- 

170 fractional_coordinates 

171 list of fractional coordinates 

172 

173 cell 

174 cell metric 

175 """ 

176 cartesian_coordinates = [np.dot(frac, cell) 

177 for frac in fractional_coordinates] 

178 return cartesian_coordinates