25
25
from emmet .core .vasp .calculation import Calculation , VaspObject
26
26
from emmet .core .vasp .task_valid import TaskState
27
27
28
+
28
29
class NebMethod (ValueEnum ):
29
30
"""Common methods for NEB calculations.
30
31
@@ -35,6 +36,7 @@ class NebMethod(ValueEnum):
35
36
CLIMBING_IMAGE = "climbing_image"
36
37
APPROX = "approxNEB"
37
38
39
+
38
40
class HopFailureReason (ValueEnum ):
39
41
"""Define failure modes for ApproxNEB calculations."""
40
42
@@ -46,20 +48,34 @@ class HopFailureReason(ValueEnum):
46
48
class BarrierAnalysis (BaseModel ):
47
49
"""Define analysis schema for barrier calculations."""
48
50
49
- energies : list [float ] = Field (description = "The energies of each frame along the reaction coordinate." )
50
- frame_index : list [float ] | None = Field (None , description = "The fractional index along the reaction coordinate, between 0 and 1." )
51
- cubic_spline_pars : list [list [float ]] | None = Field (None , description = "Parameters of the cubic spline used to fit the energies." )
52
- ts_frame_index : float | None = Field (None , description = "The fractional index of the reaction coordinate." )
53
- ts_energy : float | None = Field (None ,description = "The energy at the transition state." )
54
- ts_in_frames : bool | None = Field (None , description = "Whether the transition state is one of the computed snapshots." )
55
- forward_barrier : float | None = Field (None ,description = "The forwards barrier." )
56
- reverse_barrier : float | None = Field (None ,description = "The reverse barrier." )
51
+ energies : list [float ] = Field (
52
+ description = "The energies of each frame along the reaction coordinate."
53
+ )
54
+ frame_index : list [float ] | None = Field (
55
+ None ,
56
+ description = "The fractional index along the reaction coordinate, between 0 and 1." ,
57
+ )
58
+ cubic_spline_pars : list [list [float ]] | None = Field (
59
+ None , description = "Parameters of the cubic spline used to fit the energies."
60
+ )
61
+ ts_frame_index : float | None = Field (
62
+ None , description = "The fractional index of the reaction coordinate."
63
+ )
64
+ ts_energy : float | None = Field (
65
+ None , description = "The energy at the transition state."
66
+ )
67
+ ts_in_frames : bool | None = Field (
68
+ None ,
69
+ description = "Whether the transition state is one of the computed snapshots." ,
70
+ )
71
+ forward_barrier : float | None = Field (None , description = "The forwards barrier." )
72
+ reverse_barrier : float | None = Field (None , description = "The reverse barrier." )
57
73
58
74
@classmethod
59
75
def from_energies (
60
76
cls ,
61
77
energies : Sequence [float ],
62
- spline_kwargs : dict [str ,Any ] | None = None ,
78
+ spline_kwargs : dict [str , Any ] | None = None ,
63
79
frame_match_tol : float = 1.0e-6 ,
64
80
) -> Self :
65
81
"""
@@ -91,9 +107,9 @@ def from_energies(
91
107
analysis ["ts_frame_index" ] = - 1
92
108
analysis ["ts_energy" ] = - np .inf
93
109
for crit_point in crit_points :
94
- if (energy := spline_fit (crit_point )) > analysis ["ts_energy" ] and spline_fit (
95
- crit_point , 2
96
- ) <= 0.0 :
110
+ if (energy := spline_fit (crit_point )) > analysis [
111
+ "ts_energy"
112
+ ] and spline_fit ( crit_point , 2 ) <= 0.0 :
97
113
analysis ["ts_frame_index" ] = crit_point
98
114
analysis ["ts_energy" ] = float (energy )
99
115
@@ -107,9 +123,10 @@ def from_energies(
107
123
108
124
return cls (** analysis )
109
125
126
+
110
127
class NebResult (BaseModel ):
111
128
"""Container class to store high-level NEB calculation info.
112
-
129
+
113
130
This is intended to be code-agnostic, whereas NebTaskDoc
114
131
is VASP-specific.
115
132
"""
@@ -170,9 +187,13 @@ def set_barriers(self) -> Self:
170
187
):
171
188
self .barrier_analysis = BarrierAnalysis .from_energies (self .energies )
172
189
for k in ("forward" , "reverse" ):
173
- setattr (self , f"{ k } _barrier" , getattr (self .barrier_analysis ,f"{ k } _barrier" ,None ))
190
+ setattr (
191
+ self ,
192
+ f"{ k } _barrier" ,
193
+ getattr (self .barrier_analysis , f"{ k } _barrier" , None ),
194
+ )
174
195
return self
175
-
196
+
176
197
177
198
class NebTaskDoc (NebResult ):
178
199
"""Define schema for VASP NEB tasks."""
@@ -187,7 +208,7 @@ class NebTaskDoc(NebResult):
187
208
endpoint_calculations : list [Calculation ] | None = Field (
188
209
None , description = "Calculation information for the endpoint structures"
189
210
)
190
- endpoint_objects : list [dict [VaspObject ,Any ]] | None = Field (
211
+ endpoint_objects : list [dict [VaspObject , Any ]] | None = Field (
191
212
None , description = "VASP objects for each endpoint calculation."
192
213
)
193
214
endpoint_directories : list [str ] | None = Field (
@@ -235,13 +256,13 @@ class NebTaskDoc(NebResult):
235
256
None , description = "Timestamp for when this task was completed"
236
257
)
237
258
238
- task_label : str | None = Field (
239
- None , description = "Label for the NEB calculation(s)."
259
+ task_label : str | None = Field (
260
+ None , description = "Label for the NEB calculation(s)."
240
261
)
241
262
242
- def model_post_init (self , __context : Any ) -> None :
263
+ def model_post_init (self , __context : Any ) -> None :
243
264
"""Ensure base model fields are populated for analysis."""
244
-
265
+
245
266
if self .energies is None :
246
267
if self .endpoint_energies is not None :
247
268
self .energies = [ # type: ignore[misc]
@@ -272,7 +293,11 @@ def model_post_init(self, __context : Any) -> None:
272
293
calc .input .structure for calc in self .image_calculations
273
294
]
274
295
275
- self .initial_images = [ep_structures [0 ], * intermed_structs , ep_structures [1 ]]
296
+ self .initial_images = [
297
+ ep_structures [0 ],
298
+ * intermed_structs ,
299
+ ep_structures [1 ],
300
+ ]
276
301
277
302
@classmethod
278
303
def from_directory (
@@ -439,6 +464,7 @@ def from_directories(
439
464
** neb_task_doc_kwargs ,
440
465
)
441
466
467
+
442
468
class NebPathwayResult (BaseModel ): # type: ignore[call-arg]
443
469
"""Class for containing multiple NEB calculations, as along a reaction pathway."""
444
470
0 commit comments