Coverage for /builds/ase/ase/ase/calculators/abinit.py: 94.23%

52 statements  

« prev     ^ index     » next       coverage.py v7.5.3, created at 2025-08-02 00:12 +0000

1# fmt: off 

2 

3"""This module defines an ASE interface to ABINIT. 

4 

5http://www.abinit.org/ 

6""" 

7 

8from pathlib import Path 

9from subprocess import check_output 

10 

11import ase.io.abinit as io 

12from ase.calculators.genericfileio import ( 

13 BaseProfile, 

14 CalculatorTemplate, 

15 GenericFileIOCalculator, 

16) 

17 

18 

19class AbinitProfile(BaseProfile): 

20 configvars = {'pp_paths'} 

21 

22 def __init__(self, command, *, pp_paths=None, **kwargs): 

23 super().__init__(command, **kwargs) 

24 # XXX pp_paths is a raw configstring when it gets here. 

25 # All the config stuff should have been loaded somehow by now, 

26 # so this should be refactored. 

27 if isinstance(pp_paths, str): 

28 pp_paths = [path for path in pp_paths.splitlines() if path] 

29 if pp_paths is None: 

30 pp_paths = [] 

31 self.pp_paths = pp_paths 

32 

33 def version(self): 

34 argv = [*self._split_command, '--version'] 

35 return check_output(argv, encoding='ascii').strip() 

36 

37 def get_calculator_command(self, inputfile): 

38 return [str(inputfile)] 

39 

40 def socketio_argv_unix(self, socket): 

41 # XXX clean up the passing of the inputfile 

42 inputfile = AbinitTemplate().input_file 

43 return [inputfile, '--ipi', f'{socket}:UNIX'] 

44 

45 

46class AbinitTemplate(CalculatorTemplate): 

47 _label = 'abinit' # Controls naming of files within calculation directory 

48 

49 def __init__(self): 

50 super().__init__( 

51 name='abinit', 

52 implemented_properties=[ 

53 'energy', 

54 'free_energy', 

55 'forces', 

56 'stress', 

57 'magmom', 

58 ], 

59 ) 

60 

61 # XXX superclass should require inputname and outputname 

62 

63 self.inputname = f'{self._label}.in' 

64 self.outputname = f'{self._label}.log' 

65 self.errorname = f'{self._label}.err' 

66 

67 def execute(self, directory, profile) -> None: 

68 profile.run(directory, self.inputname, self.outputname, 

69 errorfile=self.errorname) 

70 

71 def write_input(self, profile, directory, atoms, parameters, properties): 

72 directory = Path(directory) 

73 parameters = dict(parameters) 

74 pp_paths = parameters.pop('pp_paths', profile.pp_paths) 

75 assert pp_paths is not None 

76 

77 kw = dict(xc='LDA', smearing=None, kpts=None, raw=None, pps='fhi') 

78 kw.update(parameters) 

79 

80 io.prepare_abinit_input( 

81 directory=directory, 

82 atoms=atoms, 

83 properties=properties, 

84 parameters=kw, 

85 pp_paths=pp_paths, 

86 ) 

87 

88 def read_results(self, directory): 

89 return io.read_abinit_outputs(directory, self._label) 

90 

91 def load_profile(self, cfg, **kwargs): 

92 return AbinitProfile.from_config(cfg, self.name, **kwargs) 

93 

94 def socketio_argv(self, profile, unixsocket, port): 

95 # XXX This handling of --ipi argument is used by at least two 

96 # calculators, should refactor if needed yet again 

97 if unixsocket: 

98 ipi_arg = f'{unixsocket}:UNIX' 

99 else: 

100 ipi_arg = f'localhost:{port:d}' 

101 

102 return profile.get_calculator_command(self.inputname) + [ 

103 '--ipi', 

104 ipi_arg, 

105 ] 

106 

107 def socketio_parameters(self, unixsocket, port): 

108 return dict(ionmov=28, expert_user=1, optcell=2) 

109 

110 

111class Abinit(GenericFileIOCalculator): 

112 """Class for doing ABINIT calculations. 

113 

114 The default parameters are very close to those that the ABINIT 

115 Fortran code would use. These are the exceptions:: 

116 

117 calc = Abinit(xc='LDA', ecut=400, toldfe=1e-5) 

118 """ 

119 

120 def __init__( 

121 self, 

122 *, 

123 profile=None, 

124 directory='.', 

125 **kwargs, 

126 ): 

127 """Construct ABINIT-calculator object. 

128 

129 Examples 

130 ======== 

131 Use default values: 

132 

133 >>> h = Atoms('H', calculator=Abinit(ecut=200, toldfe=0.001)) 

134 >>> h.center(vacuum=3.0) 

135 >>> e = h.get_potential_energy() 

136 

137 """ 

138 

139 super().__init__( 

140 template=AbinitTemplate(), 

141 profile=profile, 

142 directory=directory, 

143 parameters=kwargs, 

144 )