Coverage for hiphive/input_output/gpumd.py: 98%

Shortcuts 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

74 statements  

1import numpy as np 

2from itertools import permutations, product 

3 

4 

5def write_fcs_gpumd(fname_fc: str, 

6 fname_clusters: str, 

7 fcs, 

8 order: int, 

9 tol: float = 1e-10): 

10 """ 

11 Writes force constants of given order in GPUMD format. 

12 

13 Parameters 

14 ---------- 

15 fname_fc 

16 name of file which contains the lookup force constants 

17 fname_clusters 

18 name of file which contains the clusters and the force constant lookup index 

19 fcs 

20 force constants 

21 order 

22 force constants for this order will be written to file 

23 tol 

24 if the norm of a force constant term is less than this value it will be excluded 

25 from the output; 

26 if two force-constants differ by this value or less, they are considered equal. 

27 """ 

28 cluster_lookup, fc_lookup = _get_lookup_data_smart(fcs, order, tol) 

29 _write_clusters(fname_clusters, cluster_lookup, order) 

30 _write_fc_lookup(fname_fc, fc_lookup, order) 

31 

32 

33def _write_fc_lookup(fname, fc_lookup, order): 

34 """ Writes the lookup force constants to file """ 

35 fmt = '{}' + ' {}'*order 

36 with open(fname, 'w') as f: 

37 f.write(str(len(fc_lookup)) + '\n\n') 

38 for fc in fc_lookup: 

39 for xyz in product(range(3), repeat=order): 

40 f.write(fmt.format(*xyz, fc[xyz])+'\n') 

41 f.write('\n') 

42 

43 

44def _write_clusters(fname, cluster_lookup, order): 

45 """ Writes the cluster lookup to file """ 

46 fmt = '{}' + ' {}'*order 

47 with open(fname, 'w') as f: 

48 f.write(str(len(cluster_lookup)) + '\n\n') 

49 for c, i in cluster_lookup.items(): 

50 line = fmt.format(*c, i) + '\n' 

51 f.write(line) 

52 

53 

54def _get_clusters(fcs, 

55 order: int, 

56 tol: float): 

57 """ Collect all relevant clusters; for 2nd and 3rd-order force constants 

58 all permutations are included. 

59 """ 

60 if order in [2, 3]: 

61 clusters = [] 

62 for c in fcs._fc_dict.keys(): 

63 if len(c) == order and np.linalg.norm(fcs[c]) > tol: 

64 for ci in permutations(c): 

65 clusters.append(ci) 

66 clusters = list(sorted(set(clusters))) 

67 else: 

68 clusters = [c for c in fcs._fc_dict.keys() if len(c) == order and np.linalg.norm(fcs[c]) > tol] # noqa 

69 return clusters 

70 

71 

72def _get_lookup_data_naive(fcs, 

73 order: int, 

74 tol: float): 

75 """ Groups force constants for a given order into groups for which the 

76 force constant is identical. """ 

77 fc_lookup = [] 

78 cluster_lookup = dict() 

79 

80 clusters = _get_clusters(fcs, order, tol) 

81 

82 for c in clusters: 

83 fc1 = fcs[c] 

84 if np.linalg.norm(fc1) < tol: 84 ↛ 85line 84 didn't jump to line 85, because the condition on line 84 was never true

85 continue 

86 for i, fc2 in enumerate(fc_lookup): 

87 if np.linalg.norm(fc1 - fc2) < tol: 

88 cluster_lookup[c] = i 

89 break 

90 else: 

91 cluster_lookup[c] = len(fc_lookup) 

92 fc_lookup.append(fc1) 

93 return cluster_lookup, fc_lookup 

94 

95 

96def _get_lookup_data_smart(fcs, 

97 order: int, 

98 tol: float): 

99 """ Groups force constants for a given order into groups for which the 

100 force constant is identical. """ 

101 fc_lookup = [] 

102 cluster_lookup = dict() 

103 axis = tuple(range(1, order+1)) 

104 

105 clusters = _get_clusters(fcs, order, tol) 

106 fc_all = np.array([fcs[c] for c in clusters]) 

107 

108 indices = list(range(len(clusters))) 

109 while len(indices) > 0: 

110 i = indices[0] 

111 delta = fc_all[indices] - fc_all[i] 

112 delta_norm = np.sqrt(np.sum(delta**2, axis=axis)) 

113 

114 inds_to_del = [indices[x] for x in np.where(delta_norm < tol)[0]] 

115 assert i in inds_to_del 

116 

117 fc_lookup.append(fc_all[i]) 

118 for j in inds_to_del: 

119 indices.remove(j) 

120 cluster_lookup[clusters[j]] = len(fc_lookup)-1 

121 return cluster_lookup, fc_lookup 

122 

123 

124def write_fcp_txt(fname: str, 

125 path: str, 

126 n_types: int, 

127 max_order: int, 

128 heat_current_order: int = 2): 

129 """ Write driver potential file for GPUMD. 

130 

131 Parameters 

132 ---------- 

133 fname 

134 file name 

135 path 

136 path to directory with force constant file 

137 n_types 

138 number of atom types 

139 max_order 

140 maximum order of the force constant potential 

141 heat_current_order 

142 heat current order used in thermal conductivity 

143 

144 

145 Format is a simple file containing the following 

146 

147 fcp number_of_atom_types 

148 highest_force_order heat_current_order 

149 path_to_force_constant_files 

150 

151 which in practice for a binary system with a sixth order model, 

152 consider third-order heat-currents, would mean 

153 

154 fcp 2 

155 6 3 

156 /path/to/your/folder 

157 """ 

158 

159 with open(fname, 'w') as f: 

160 f.write('fcp {}\n'.format(n_types)) 

161 f.write('{} {}\n'.format(max_order, heat_current_order)) 

162 f.write('{}'.format(path.rstrip('/'))) # without a trailing '/' 

163 

164 

165def write_r0(fname, atoms): 

166 """ 

167 Write GPUMD r0 file, with reference atomic positions. 

168 

169 Parameters 

170 ---------- 

171 fname : str 

172 name of file to which to write the atomic positions 

173 atoms : ase.Atoms 

174 input structure 

175 

176 """ 

177 line = '{} {} {}\n' 

178 with open(fname, 'w') as f: 

179 for a in atoms: 

180 f.write(line.format(*a.position))