@@ -56,7 +56,8 @@ class ForceFieldManager:
5656 path_cwd (str): Current working directory for the project
5757 path_master (str): Path to external dependencies
5858 path_moltemplatesrc (str): Path to Moltemplate source
59- force_field (str): Force field type ("oplsaa", "gaff", "gaff2", or "lopls")
59+ force_field (str): Force field type ("oplsaa", "gaff", "gaff2", "lopls",
60+ "dreiding", "compass", or "openff")
6061 ff_modify_dihedral (np.ndarray): Modified dihedral parameters
6162 path_oplsaaprm (str): Path to OPLS-AA force field parameters
6263 gaff_analyzer (GAFFAnalyzer): GAFF analyzer instance (for GAFF/GAFF2 force field)
@@ -87,12 +88,20 @@ def __init__(self, path_cwd: str, path_master: str, path_moltemplatesrc: str,
8788
8889 # Set force field parameter path based on force_field type
8990 # All force fields now use .lt files from moltemplate/force_fields/
91+ # (openff excepted: its per-system openff.lt is generated at typing
92+ # time, so no bundled file exists under force_fields/)
9093 self .path_oplsaaprm = str (
9194 Path (self .path_master ) / "moltemplate" / "force_fields"
9295 / FORCE_FIELD_REGISTRY [force_field ]["lt_file" ]
9396 )
9497
95- logger .info (f"\n 'you are now using parameter set of { self .path_oplsaaprm } \n " )
98+ if force_field == "openff" :
99+ logger .info (
100+ "\n 'you are now using a generated SMIRNOFF parameter set "
101+ "(openff.lt from the typing stage)\n "
102+ )
103+ else :
104+ logger .info (f"\n 'you are now using parameter set of { self .path_oplsaaprm } \n " )
96105
97106 # Initialize GAFF analyzer if using GAFF/GAFF2 force field
98107 self .gaff_analyzer = None
@@ -123,6 +132,8 @@ def make_force_field_lt(self) -> None:
123132
124133 This is the main entry point for force field file generation. It delegates
125134 to the appropriate method based on the force field type:
135+ - For OPENFF: verifies the per-system openff.lt generated by UnitTyper
136+ is in place (nothing to subset — SMIRNOFF parameters are per-molecule)
126137 - For GAFF/GAFF2: creates a filtered subset using GAFFAnalyzer
127138 - For DREIDING/COMPASS: creates a filtered subset based on monomer topology
128139 - For OPLS-AA/LOPLS: copies .lt file directly (new moltemplate 2.22.5 format)
@@ -135,7 +146,9 @@ def make_force_field_lt(self) -> None:
135146 SystemExit: If force field file generation fails
136147 """
137148 try :
138- if self .force_field in ("gaff" , "gaff2" ):
149+ if self .force_field == "openff" :
150+ self .make_openff_lt ()
151+ elif self .force_field in ("gaff" , "gaff2" ):
139152 self .make_gaff_lt ()
140153 elif self .force_field == "dreiding" :
141154 # DREIDING: create subset based on topology
@@ -150,6 +163,34 @@ def make_force_field_lt(self) -> None:
150163 except Exception as e :
151164 raise WorkflowError (f"Error in make_force_field_lt: { str (e )} " ) from e
152165
166+ def make_openff_lt (self ) -> None :
167+ """
168+ Verify the generated openff.lt is in place (OpenFF path).
169+
170+ Unlike the static force fields, openff.lt is not a bundled parameter
171+ file: SMIRNOFF assigns parameters per molecule, so the file is
172+ generated by UnitTyper (stage 2) into the build directory and copied
173+ here (the moltemplate working dir) by BoxPacker via the monomer_files
174+ manifest. There is nothing to subset — this method only checks the
175+ hand-off happened.
176+
177+ Raises:
178+ GenerationError: If openff.lt is missing (e.g. the build dir was
179+ not produced by UnitTyper(force_field='openff')).
180+ """
181+ dst = Path (self .path_cwd ) / "openff.lt"
182+ if not dst .exists ():
183+ raise GenerationError (
184+ f"openff.lt not found in { self .path_cwd } . With "
185+ "force_field='openff' the parameter file is generated during "
186+ "typing (UnitTyper) and copied by BoxPacker — do not run the "
187+ "force-field stage from a non-OpenFF build directory."
188+ )
189+ logger .info (
190+ f" Using generated OpenFF parameter file: { dst } "
191+ f"({ dst .stat ().st_size } bytes)"
192+ )
193+
153194 def make_gaff_lt (self ) -> None :
154195 """
155196 Create GAFF force field file using GAFFAnalyzer.
0 commit comments