Coverage for /builds/debichem-team/python-ase/ase/calculators/abinit.py: 94.23%

52 statements  

« prev     ^ index     » next       coverage.py v7.5.3, created at 2025-03-06 04:00 +0000

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

2 

3http://www.abinit.org/ 

4""" 

5 

6from pathlib import Path 

7from subprocess import check_output 

8 

9import ase.io.abinit as io 

10from ase.calculators.genericfileio import ( 

11 BaseProfile, 

12 CalculatorTemplate, 

13 GenericFileIOCalculator, 

14) 

15 

16 

17class AbinitProfile(BaseProfile): 

18 configvars = {'pp_paths'} 

19 

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

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

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

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

24 # so this should be refactored. 

25 if isinstance(pp_paths, str): 

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

27 if pp_paths is None: 

28 pp_paths = [] 

29 self.pp_paths = pp_paths 

30 

31 def version(self): 

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

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

34 

35 def get_calculator_command(self, inputfile): 

36 return [str(inputfile)] 

37 

38 def socketio_argv_unix(self, socket): 

39 # XXX clean up the passing of the inputfile 

40 inputfile = AbinitTemplate().input_file 

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

42 

43 

44class AbinitTemplate(CalculatorTemplate): 

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

46 

47 def __init__(self): 

48 super().__init__( 

49 name='abinit', 

50 implemented_properties=[ 

51 'energy', 

52 'free_energy', 

53 'forces', 

54 'stress', 

55 'magmom', 

56 ], 

57 ) 

58 

59 # XXX superclass should require inputname and outputname 

60 

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

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

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

64 

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

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

67 errorfile=self.errorname) 

68 

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

70 directory = Path(directory) 

71 parameters = dict(parameters) 

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

73 assert pp_paths is not None 

74 

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

76 kw.update(parameters) 

77 

78 io.prepare_abinit_input( 

79 directory=directory, 

80 atoms=atoms, 

81 properties=properties, 

82 parameters=kw, 

83 pp_paths=pp_paths, 

84 ) 

85 

86 def read_results(self, directory): 

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

88 

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

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

91 

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

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

94 # calculators, should refactor if needed yet again 

95 if unixsocket: 

96 ipi_arg = f'{unixsocket}:UNIX' 

97 else: 

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

99 

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

101 '--ipi', 

102 ipi_arg, 

103 ] 

104 

105 def socketio_parameters(self, unixsocket, port): 

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

107 

108 

109class Abinit(GenericFileIOCalculator): 

110 """Class for doing ABINIT calculations. 

111 

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

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

114 

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

116 """ 

117 

118 def __init__( 

119 self, 

120 *, 

121 profile=None, 

122 directory='.', 

123 **kwargs, 

124 ): 

125 """Construct ABINIT-calculator object. 

126 

127 Examples 

128 ======== 

129 Use default values: 

130 

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

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

133 >>> e = h.get_potential_energy() 

134 

135 """ 

136 

137 super().__init__( 

138 template=AbinitTemplate(), 

139 profile=profile, 

140 directory=directory, 

141 parameters=kwargs, 

142 )