51
51
electronic_temperature 300.0 Electronic temperatur for TB methods
52
52
max_iterations 250 Iterations for self-consistent evaluation
53
53
solvent "none" GBSA implicit solvent model
54
+ cache_api True Reuse generate API objects (recommended)
54
55
======================== ============ ============================================
55
56
"""
56
57
@@ -84,6 +85,7 @@ class XTB(ase_calc.Calculator):
84
85
"max_iterations" : 250 ,
85
86
"electronic_temperature" : 300.0 ,
86
87
"solvent" : "None" ,
88
+ "cache_api" : True ,
87
89
}
88
90
89
91
_res = None
@@ -96,49 +98,85 @@ def __init__(
96
98
97
99
ase_calc .Calculator .__init__ (self , atoms = atoms , ** kwargs )
98
100
99
- # loads the default parameters and updates with actual values
100
- self .parameters = self .get_default_parameters ()
101
- # now set all parameters
102
- self .set (** kwargs )
103
-
104
- def set (self , ** kwargs ):
101
+ def set (self , ** kwargs ) -> dict :
105
102
"""Set new parameters to xtb"""
106
103
107
104
changed_parameters = ase_calc .Calculator .set (self , ** kwargs )
108
105
109
- self ._check (changed_parameters )
106
+ self ._check_parameters (changed_parameters )
110
107
111
- # Always reset the xtb calculator for now
108
+ # Always reset the calculation if parameters change
112
109
if changed_parameters :
113
110
self .reset ()
114
111
112
+ # If the method is changed, invalidate the cached calculator as well
113
+ if "method" in changed_parameters :
114
+ self ._xtb = None
115
+ self ._res = None
116
+
117
+ # Minor changes can be updated in the API calculator directly
118
+ if self ._xtb is not None :
119
+ if "accuracy" in changed_parameters :
120
+ self ._xtb .set_accuracy (self .parameters .accuracy )
121
+
122
+ if "electronic_temperature" in changed_parameters :
123
+ self ._xtb .set_electronic_temperature (
124
+ self .parameters .electronic_temperature
125
+ )
126
+
127
+ if "max_iterations" in changed_parameters :
128
+ self ._xtb .set_max_iterations (self .parameters .max_iterations )
129
+
130
+ if "solvent" in changed_parameters :
131
+ self ._xtb .set_solvent (get_solvent (self .parameters .solvent ))
132
+
115
133
return changed_parameters
116
134
117
- def _check (self , parameters ) :
135
+ def _check_parameters (self , parameters : dict ) -> None :
118
136
"""Verifiy provided parameters are valid"""
119
137
120
138
if "method" in parameters and get_method (parameters ["method" ]) is None :
121
139
raise ase_calc .InputError (
122
140
"Invalid method {} provided" .format (parameters ["method" ])
123
141
)
124
142
125
- def reset (self ):
143
+ def reset (self ) -> None :
126
144
"""Clear all information from old calculation"""
127
145
ase_calc .Calculator .reset (self )
128
146
129
- self ._res = None
130
-
131
- def calculate (
132
- self ,
133
- atoms : Optional [Atoms ] = None ,
134
- properties : List [str ] = None ,
135
- system_changes : List [str ] = ase_calc .all_changes ,
136
- ):
137
- """Perform actual calculation with by calling the xtb API"""
138
-
139
- if not properties :
140
- properties = ["energy" ]
141
- ase_calc .Calculator .calculate (self , atoms , properties , system_changes )
147
+ if not self .parameters .cache_api :
148
+ self ._xtb = None
149
+ self ._res = None
150
+
151
+ def _check_api_calculator (self , system_changes : List [str ]) -> None :
152
+ """Check state of API calculator and reset if necessary"""
153
+
154
+ # Changes in positions and cell parameters can use a normal update
155
+ _reset = system_changes .copy ()
156
+ if "positions" in _reset :
157
+ _reset .remove ("positions" )
158
+ if "cell" in _reset :
159
+ _reset .remove ("cell" )
160
+
161
+ # Invalidate cached calculator and results object
162
+ if _reset :
163
+ self ._xtb = None
164
+ self ._res = None
165
+ else :
166
+ if system_changes and self ._xtb is not None :
167
+ try :
168
+ _cell = self .atoms .cell
169
+ self ._xtb .update (
170
+ self .atoms .positions / Bohr , _cell / Bohr ,
171
+ )
172
+ # An exception in this part means the geometry is bad,
173
+ # still we will give a complete reset a try as well
174
+ except XTBException :
175
+ self ._xtb = None
176
+ self ._res = None
177
+
178
+ def _create_api_calculator (self ) -> Calculator :
179
+ """Create a new API calculator object"""
142
180
143
181
_method = get_method (self .parameters .method )
144
182
if _method is None :
@@ -152,7 +190,7 @@ def calculate(
152
190
_charge = self .atoms .get_initial_charges ().sum ()
153
191
_uhf = int (self .atoms .get_initial_magnetic_moments ().sum ().round ())
154
192
155
- self . _xtb = Calculator (
193
+ calc = Calculator (
156
194
_method ,
157
195
self .atoms .numbers ,
158
196
self .atoms .positions / Bohr ,
@@ -161,15 +199,34 @@ def calculate(
161
199
_cell / Bohr ,
162
200
_periodic ,
163
201
)
164
- self . _xtb .set_verbosity (VERBOSITY_MUTED )
165
- self . _xtb .set_accuracy (self .parameters .accuracy )
166
- self . _xtb .set_electronic_temperature (self .parameters .electronic_temperature )
167
- self . _xtb .set_max_iterations (self .parameters .max_iterations )
168
- self . _xtb .set_solvent (get_solvent (self .parameters .solvent ))
202
+ calc .set_verbosity (VERBOSITY_MUTED )
203
+ calc .set_accuracy (self .parameters .accuracy )
204
+ calc .set_electronic_temperature (self .parameters .electronic_temperature )
205
+ calc .set_max_iterations (self .parameters .max_iterations )
206
+ calc .set_solvent (get_solvent (self .parameters .solvent ))
169
207
170
208
except XTBException :
171
209
raise ase_calc .InputError ("Cannot construct calculator for xtb" )
172
210
211
+ return calc
212
+
213
+ def calculate (
214
+ self ,
215
+ atoms : Optional [Atoms ] = None ,
216
+ properties : List [str ] = None ,
217
+ system_changes : List [str ] = ase_calc .all_changes ,
218
+ ) -> None :
219
+ """Perform actual calculation with by calling the xtb API"""
220
+
221
+ if not properties :
222
+ properties = ["energy" ]
223
+ ase_calc .Calculator .calculate (self , atoms , properties , system_changes )
224
+
225
+ self ._check_api_calculator (system_changes )
226
+
227
+ if self ._xtb is None :
228
+ self ._xtb = self ._create_api_calculator ()
229
+
173
230
try :
174
231
self ._res = self ._xtb .singlepoint (self ._res )
175
232
except XTBException :
0 commit comments