r m x p   toggle line displays

j k   next/prev highlighted chunk

0   (zero) top of page

1   (one) first highlighted chunk

1from itertools import combinations, permutations

2from typing import List

4import numpy as np

5from ase import Atoms

6from ..core.orbit import Orbit

7from ..core.orbit_list import OrbitList

8from ..core.lattice_site import LatticeSite

11def _is_sites_in_orbit(orbit: Orbit, sites: List[LatticeSite]) -> bool:

12 """Checks if the list of lattice sites is found among the equivalent

13 sites for the orbit.

15 Parameters

16 ----------

17 orbit

18 orbit

19 sites

20 list of lattice sites

21 """

23 # Ensure that the number of sites matches the order of the orbit

24 if len(sites) != orbit.order: 24 ↛ 25line 24 didn't jump to line 25, because the condition on line 24 was never true

25 return False

27 equivalent_sites = orbit.equivalent_clusters

29 # Check if the set of lattice sites is found among the equivalent sites

30 if set(sites) in [set(es) for es in equivalent_sites]:

31 return True

33 # Go through all equivalent sites

34 sites_indices = [s.index for s in sites]

35 for orbit_sites in equivalent_sites:

36 orbit_sites_indices = [s.index for s in orbit_sites]

38 # Skip if the site indices do not match

39 if set(sites_indices) != set(orbit_sites_indices):

40 continue

42 # Loop over all possible ways of pairing sites from the two lists

43 for comb_sites in [list(zip(sites, pos))

44 for pos in permutations(orbit_sites)]:

46 # Skip all cases that include pairs of sites with different site

47 # indices

48 if any(cs[0].index != cs[1].index for cs in comb_sites):

49 continue

51 # If the relative offsets for all pairs of sites match, the two

52 # clusters are equivalent

53 relative_offsets = [cs[0].unitcell_offset - cs[1].unitcell_offset

54 for cs in comb_sites]

55 if all(np.array_equal(ro, relative_offsets[0])

56 for ro in relative_offsets):

57 return True

58 return False

61def get_transformation_matrix(structure: Atoms,

62 full_orbit_list: OrbitList) -> np.ndarray:

63 """

64 Determines the matrix that transforms the cluster functions in the form

65 of spin variables, (:math:\\sigma_i\\in\\{-1,1\\}), to their binary

66 equivalents, (:math:x_i\\in\\{0,1\\}). The form is obtained by

67 performing the substitution (:math:\\sigma_i=1-2x_i) in the

68 cluster expansion expression of the total energy.

70 Parameters

71 ----------

72 structure

73 atomic configuration

74 full_orbit_list

75 full orbit list

76 """

77 # Go through all clusters associated with each active orbit and

78 # determine its contribution to each orbit

79 orbit_indices = range(len(full_orbit_list))

80 transformation = np.zeros((len(orbit_indices) + 1,

81 len(orbit_indices) + 1))

82 transformation[0, 0] = 1.0

83 for i, orb_index in enumerate(orbit_indices, 1):

84 orbit = full_orbit_list.get_orbit(orb_index)

85 repr_sites = orbit.sites_of_representative_cluster

86 # add contributions to the lower order orbits to which the

87 # subclusters belong

88 for sub_order in range(orbit.order + 1):

89 n_terms_target = len(list(combinations(repr_sites, sub_order)))

90 n_terms_actual = 0

91 if sub_order == 0:

92 transformation[0, i] += 1.0

93 n_terms_actual += 1

94 if sub_order == orbit.order:

95 transformation[i, i] += (-2.0) ** (sub_order)

96 n_terms_actual += 1

97 else:

98 comb_sub_sites = combinations(repr_sites, sub_order)

99 for sub_sites in comb_sub_sites:

100 for j, sub_index in enumerate(orbit_indices, 1):

101 sub_orbit = full_orbit_list.get_orbit(sub_index)

102 if sub_orbit.order != sub_order:

103 continue

104 if _is_sites_in_orbit(sub_orbit, sub_sites):

105 transformation[j, i] += (-2.0) ** (sub_order)

106 n_terms_actual += 1

107 # check that the number of contributions matches the number

108 # of subclusters

109 assert(n_terms_actual == n_terms_target)

111 return transformation

114def transform_parameters(structure: Atoms,

115 full_orbit_list: OrbitList,

116 parameters: np.ndarray) -> np.ndarray:

117 """

118 Transforms the list of parameters, obtained using cluster functions in the

119 form of of spin variables, (:math:\\sigma_i\\in\\{-1,1\\}), to their

120 equivalents for the case of binary variables,

121 (:math:x_i\\in\\{0,1\\}).

123 Parameters

124 ----------

125 structure

126 atomic configuration

127 full_orbit_list

128 full orbit list

129 parameters

130 parameter vector (spin variables)

131 """

132 A = get_transformation_matrix(structure, full_orbit_list)

133 return np.dot(A, parameters)