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"""Quantum ESPRESSO Calculator 

2 

3Run pw.x jobs. 

4""" 

5 

6 

7import os 

8from ase.calculators.genericfileio import ( 

9 GenericFileIOCalculator, CalculatorTemplate, read_stdout) 

10from ase.io import read, write 

11 

12 

13compatibility_msg = ( 

14 'Espresso calculator is being restructured. Please use e.g. ' 

15 'Espresso(profile=EspressoProfile(argv=[\'mpiexec\', \'pw.x\'])) ' 

16 'to customize command-line arguments.') 

17 

18 

19# XXX We should find a way to display this warning. 

20# warn_template = 'Property "%s" is None. Typically, this is because the ' \ 

21# 'required information has not been printed by Quantum ' \ 

22# 'Espresso at a "low" verbosity level (the default). ' \ 

23# 'Please try running Quantum Espresso with "high" verbosity.' 

24 

25 

26class EspressoProfile: 

27 def __init__(self, argv): 

28 self.argv = tuple(argv) 

29 

30 @staticmethod 

31 def parse_version(stdout): 

32 import re 

33 match = re.match(r'\s*Program PWSCF\s*v\.(\S+)', stdout, re.M) 

34 assert match is not None 

35 return match.group(1) 

36 

37 def version(self): 

38 stdout = read_stdout(self.argv) 

39 return self.parse_version(stdout) 

40 

41 def run(self, directory, inputfile, outputfile): 

42 from subprocess import check_call 

43 import os 

44 argv = list(self.argv) + ['-in', str(inputfile)] 

45 with open(directory / outputfile, 'wb') as fd: 

46 check_call(argv, cwd=directory, stdout=fd, env=os.environ) 

47 

48 def socketio_argv_unix(self, socket): 

49 template = EspressoTemplate() 

50 # It makes sense to know the template for this kind of choices, 

51 # but is there a better way? 

52 return list(self.argv) + ['--ipi', f'{socket}:UNIX', '-in', 

53 template.inputname] 

54 

55 

56class EspressoTemplate(CalculatorTemplate): 

57 def __init__(self): 

58 super().__init__( 

59 'espresso', 

60 ['energy', 'free_energy', 'forces', 'stress', 'magmoms']) 

61 self.inputname = 'espresso.pwi' 

62 self.outputname = 'espresso.pwo' 

63 

64 def write_input(self, directory, atoms, parameters, properties): 

65 dst = directory / self.inputname 

66 write(dst, atoms, format='espresso-in', properties=properties, 

67 **parameters) 

68 

69 def execute(self, directory, profile): 

70 profile.run(directory, 

71 self.inputname, 

72 self.outputname) 

73 

74 def read_results(self, directory): 

75 path = directory / self.outputname 

76 atoms = read(path, format='espresso-out') 

77 return dict(atoms.calc.properties()) 

78 

79 

80class Espresso(GenericFileIOCalculator): 

81 def __init__(self, *, profile=None, 

82 command=GenericFileIOCalculator._deprecated, 

83 label=GenericFileIOCalculator._deprecated, 

84 directory='.', 

85 **kwargs): 

86 """ 

87 All options for pw.x are copied verbatim to the input file, and put 

88 into the correct section. Use ``input_data`` for parameters that are 

89 already in a dict, all other ``kwargs`` are passed as parameters. 

90 

91 Accepts all the options for pw.x as given in the QE docs, plus some 

92 additional options: 

93 

94 input_data: dict 

95 A flat or nested dictionary with input parameters for pw.x 

96 pseudopotentials: dict 

97 A filename for each atomic species, e.g. 

98 ``{'O': 'O.pbe-rrkjus.UPF', 'H': 'H.pbe-rrkjus.UPF'}``. 

99 A dummy name will be used if none are given. 

100 kspacing: float 

101 Generate a grid of k-points with this as the minimum distance, 

102 in A^-1 between them in reciprocal space. If set to None, kpts 

103 will be used instead. 

104 kpts: (int, int, int), dict, or BandPath 

105 If kpts is a tuple (or list) of 3 integers, it is interpreted 

106 as the dimensions of a Monkhorst-Pack grid. 

107 If ``kpts`` is set to ``None``, only the Γ-point will be included 

108 and QE will use routines optimized for Γ-point-only calculations. 

109 Compared to Γ-point-only calculations without this optimization 

110 (i.e. with ``kpts=(1, 1, 1)``), the memory and CPU requirements 

111 are typically reduced by half. 

112 If kpts is a dict, it will either be interpreted as a path 

113 in the Brillouin zone (*) if it contains the 'path' keyword, 

114 otherwise it is converted to a Monkhorst-Pack grid (**). 

115 (*) see ase.dft.kpoints.bandpath 

116 (**) see ase.calculators.calculator.kpts2sizeandoffsets 

117 koffset: (int, int, int) 

118 Offset of kpoints in each direction. Must be 0 (no offset) or 

119 1 (half grid offset). Setting to True is equivalent to (1, 1, 1). 

120 

121 

122 .. note:: 

123 Set ``tprnfor=True`` and ``tstress=True`` to calculate forces and 

124 stresses. 

125 

126 .. note:: 

127 Band structure plots can be made as follows: 

128 

129 

130 1. Perform a regular self-consistent calculation, 

131 saving the wave functions at the end, as well as 

132 getting the Fermi energy: 

133 

134 >>> input_data = {<your input data>} 

135 >>> calc = Espresso(input_data=input_data, ...) 

136 >>> atoms.calc = calc 

137 >>> atoms.get_potential_energy() 

138 >>> fermi_level = calc.get_fermi_level() 

139 

140 2. Perform a non-self-consistent 'band structure' run 

141 after updating your input_data and kpts keywords: 

142 

143 >>> input_data['control'].update({'calculation':'bands', 

144 >>> 'restart_mode':'restart', 

145 >>> 'verbosity':'high'}) 

146 >>> calc.set(kpts={<your Brillouin zone path>}, 

147 >>> input_data=input_data) 

148 >>> calc.calculate(atoms) 

149 

150 3. Make the plot using the BandStructure functionality, 

151 after setting the Fermi level to that of the prior 

152 self-consistent calculation: 

153 

154 >>> bs = calc.band_structure() 

155 >>> bs.reference = fermi_energy 

156 >>> bs.plot() 

157 

158 """ 

159 

160 if command is not self._deprecated: 

161 raise RuntimeError(compatibility_msg) 

162 

163 if label is not self._deprecated: 

164 import warnings 

165 warnings.warn('Ignoring label, please use directory instead', 

166 FutureWarning) 

167 

168 if 'ASE_ESPRESSO_COMMAND' in os.environ and profile is None: 

169 import warnings 

170 warnings.warn(compatibility_msg, FutureWarning) 

171 

172 template = EspressoTemplate() 

173 if profile is None: 

174 profile = EspressoProfile(argv=['pw.x']) 

175 super().__init__(profile=profile, template=template, 

176 directory=directory, 

177 parameters=kwargs)