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

1import os 

2import copy 

3from collections.abc import Iterable 

4from shutil import which 

5from typing import Dict, Optional 

6 

7from ase.io import read, write 

8from ase.calculators.calculator import FileIOCalculator, EnvironmentError 

9 

10 

11class GaussianDynamics: 

12 calctype = 'optimizer' 

13 delete = ['force'] 

14 keyword: Optional[str] = None 

15 special_keywords: Dict[str, str] = dict() 

16 

17 def __init__(self, atoms, calc=None): 

18 self.atoms = atoms 

19 if calc is not None: 

20 self.calc = calc 

21 else: 

22 if self.atoms.calc is None: 

23 raise ValueError("{} requires a valid Gaussian calculator " 

24 "object!".format(self.__class__.__name__)) 

25 

26 self.calc = self.atoms.calc 

27 

28 def todict(self): 

29 return {'type': self.calctype, 

30 'optimizer': self.__class__.__name__} 

31 

32 def delete_keywords(self, kwargs): 

33 """removes list of keywords (delete) from kwargs""" 

34 for d in self.delete: 

35 kwargs.pop(d, None) 

36 

37 def set_keywords(self, kwargs): 

38 args = kwargs.pop(self.keyword, []) 

39 if isinstance(args, str): 

40 args = [args] 

41 elif isinstance(args, Iterable): 

42 args = list(args) 

43 

44 for key, template in self.special_keywords.items(): 

45 if key in kwargs: 

46 val = kwargs.pop(key) 

47 args.append(template.format(val)) 

48 

49 kwargs[self.keyword] = args 

50 

51 def run(self, **kwargs): 

52 calc_old = self.atoms.calc 

53 params_old = copy.deepcopy(self.calc.parameters) 

54 

55 self.delete_keywords(kwargs) 

56 self.delete_keywords(self.calc.parameters) 

57 self.set_keywords(kwargs) 

58 

59 self.calc.set(**kwargs) 

60 self.atoms.calc = self.calc 

61 

62 try: 

63 self.atoms.get_potential_energy() 

64 except OSError: 

65 converged = False 

66 else: 

67 converged = True 

68 

69 atoms = read(self.calc.label + '.log') 

70 self.atoms.cell = atoms.cell 

71 self.atoms.positions = atoms.positions 

72 

73 self.calc.parameters = params_old 

74 self.calc.reset() 

75 if calc_old is not None: 

76 self.atoms.calc = calc_old 

77 

78 return converged 

79 

80 

81class GaussianOptimizer(GaussianDynamics): 

82 keyword = 'opt' 

83 special_keywords = { 

84 'fmax': '{}', 

85 'steps': 'maxcycle={}', 

86 } 

87 

88 

89class GaussianIRC(GaussianDynamics): 

90 keyword = 'irc' 

91 special_keywords = { 

92 'direction': '{}', 

93 'steps': 'maxpoints={}', 

94 } 

95 

96 

97class Gaussian(FileIOCalculator): 

98 implemented_properties = ['energy', 'forces', 'dipole'] 

99 command = 'GAUSSIAN < PREFIX.com > PREFIX.log' 

100 discard_results_on_any_change = True 

101 

102 def __init__(self, *args, label='Gaussian', **kwargs): 

103 FileIOCalculator.__init__(self, *args, label=label, **kwargs) 

104 

105 def calculate(self, *args, **kwargs): 

106 gaussians = ('g16', 'g09', 'g03') 

107 if 'GAUSSIAN' in self.command: 

108 for gau in gaussians: 

109 if which(gau): 

110 self.command = self.command.replace('GAUSSIAN', gau) 

111 break 

112 else: 

113 raise EnvironmentError('Missing Gaussian executable {}' 

114 .format(gaussians)) 

115 

116 FileIOCalculator.calculate(self, *args, **kwargs) 

117 

118 def write_input(self, atoms, properties=None, system_changes=None): 

119 FileIOCalculator.write_input(self, atoms, properties, system_changes) 

120 write(self.label + '.com', atoms, properties=properties, 

121 format='gaussian-in', parallel=False, **self.parameters) 

122 

123 def read_results(self): 

124 output = read(self.label + '.log', format='gaussian-out') 

125 self.calc = output.calc 

126 self.results = output.calc.results 

127 

128 # Method(s) defined in the old calculator, added here for 

129 # backwards compatibility 

130 def clean(self): 

131 for suffix in ['.com', '.chk', '.log']: 

132 try: 

133 os.remove(os.path.join(self.directory, self.label + suffix)) 

134 except OSError: 

135 pass 

136 

137 def get_version(self): 

138 raise NotImplementedError # not sure how to do this yet