8
8
from emmet .core .vasp .calculation import StoreTrajectoryOption
9
9
from monty .dev import deprecated
10
10
from pydantic import Field
11
- from pymatgen .core import Structure
11
+ from pymatgen .core import Structure , Molecule
12
12
13
- from atomate2 .ase .schemas import AseObject , AseResult , AseStructureTaskDoc , AseTaskDoc
13
+ from atomate2 .ase .schemas import AseObject , AseResult , AseMoleculeTaskDoc , AseStructureTaskDoc , AseTaskDoc
14
+ from atomate2 .ase .schemas import _task_doc_translation_keys
14
15
from atomate2 .forcefields import MLFF
15
16
16
17
@@ -67,6 +68,79 @@ class ForceFieldStructureTaskDocument(AseStructureTaskDoc):
67
68
),
68
69
)
69
70
71
+
72
+ @property
73
+ def forcefield_objects (self ) -> Optional [dict [AseObject , Any ]]:
74
+ """Alias `objects` attr for backwards compatibility."""
75
+ return self .objects
76
+
77
+ class ForceFieldMoleculeTaskDocument (AseMoleculeTaskDoc ):
78
+ """Document containing information on structure manipulation using a force field."""
79
+
80
+ forcefield_name : Optional [str ] = Field (
81
+ None ,
82
+ description = "name of the interatomic potential used for relaxation." ,
83
+ )
84
+
85
+ forcefield_version : Optional [str ] = Field (
86
+ "Unknown" ,
87
+ description = "version of the interatomic potential used for relaxation." ,
88
+ )
89
+
90
+ dir_name : Optional [str ] = Field (
91
+ None , description = "Directory where the force field calculations are performed."
92
+ )
93
+
94
+ included_objects : Optional [list [AseObject ]] = Field (
95
+ None , description = "list of forcefield objects included with this task document"
96
+ )
97
+ objects : Optional [dict [AseObject , Any ]] = Field (
98
+ None , description = "Forcefield objects associated with this task"
99
+ )
100
+
101
+ is_force_converged : Optional [bool ] = Field (
102
+ None ,
103
+ description = (
104
+ "Whether the calculation is converged with respect to interatomic forces."
105
+ ),
106
+ )
107
+
108
+ @property
109
+ def forcefield_objects (self ) -> Optional [dict [AseObject , Any ]]:
110
+ """Alias `objects` attr for backwards compatibility."""
111
+ return self .objects
112
+
113
+ class ForceFieldTaskDocument (AseTaskDoc ):
114
+ """Document containing information on structure manipulation using a force field."""
115
+
116
+ forcefield_name : Optional [str ] = Field (
117
+ None ,
118
+ description = "name of the interatomic potential used for relaxation." ,
119
+ )
120
+
121
+ forcefield_version : Optional [str ] = Field (
122
+ "Unknown" ,
123
+ description = "version of the interatomic potential used for relaxation." ,
124
+ )
125
+
126
+ dir_name : Optional [str ] = Field (
127
+ None , description = "Directory where the force field calculations are performed."
128
+ )
129
+
130
+ included_objects : Optional [list [AseObject ]] = Field (
131
+ None , description = "list of forcefield objects included with this task document"
132
+ )
133
+ objects : Optional [dict [AseObject , Any ]] = Field (
134
+ None , description = "Forcefield objects associated with this task"
135
+ )
136
+
137
+ is_force_converged : Optional [bool ] = Field (
138
+ None ,
139
+ description = (
140
+ "Whether the calculation is converged with respect to interatomic forces."
141
+ ),
142
+ )
143
+
70
144
@classmethod
71
145
def from_ase_compatible_result (
72
146
cls ,
@@ -87,7 +161,7 @@ def from_ase_compatible_result(
87
161
store_trajectory : StoreTrajectoryOption = StoreTrajectoryOption .NO ,
88
162
tags : list [str ] | None = None ,
89
163
** task_document_kwargs ,
90
- ) -> ForceFieldStructureTaskDocument :
164
+ ) -> Union [ ForceFieldStructureTaskDocument , ForceFieldMoleculeTaskDocument ] :
91
165
"""Create an AseTaskDoc for a task that has ASE-compatible outputs.
92
166
93
167
Parameters
@@ -155,6 +229,35 @@ def from_ase_compatible_result(
155
229
156
230
return cls .from_ase_task_doc (ase_task_doc , ** ff_kwargs )
157
231
232
+ @classmethod
233
+ def from_ase_task_doc (
234
+ cls , ase_task_doc : AseTaskDoc , ** task_document_kwargs
235
+ ) -> Union [ForceFieldStructureTaskDocument , ForceFieldMoleculeTaskDocument ]:
236
+ """Create an AseStructureTaskDoc for a task that has ASE-compatible outputs.
237
+
238
+ Parameters
239
+ ----------
240
+ ase_task_doc : AseTaskDoc
241
+ Task doc for the calculation
242
+ task_document_kwargs : dict
243
+ Additional keyword args passed to :obj:`.AseStructureTaskDoc()`.
244
+ """
245
+ task_document_kwargs .update (
246
+ {k : getattr (ase_task_doc , k ) for k in _task_doc_translation_keys },
247
+ )
248
+ if isinstance (ase_task_doc .mol_or_struct , Structure ):
249
+ meta_class = ForceFieldStructureTaskDocument
250
+ k = "structure"
251
+ if relax_cell := getattr (ase_task_doc , "relax_cell" , None ):
252
+ kwargs .update ({"relax_cell" : relax_cell })
253
+ task_document_kwargs .update (structure = ase_task_doc .mol_or_struct )
254
+ elif isinstance (ase_task_doc .mol_or_struct , Molecule ):
255
+ meta_class = ForceFieldMoleculeTaskDocument
256
+ k = "molecule"
257
+ task_document_kwargs .update (molecule = ase_task_doc .mol_or_struct )
258
+ task_document_kwargs .update ({k : ase_task_doc .mol_or_struct , f"meta_{ k } " : ase_task_doc .mol_or_struct })
259
+ return getattr (meta_class , f"from_{ k } " )(** task_document_kwargs )
260
+
158
261
@property
159
262
def forcefield_objects (self ) -> Optional [dict [AseObject , Any ]]:
160
263
"""Alias `objects` attr for backwards compatibility."""
0 commit comments