diff --git a/automol/graph/_2conv.py b/automol/graph/_2conv.py index 1d60f7ee..dce5f911 100644 --- a/automol/graph/_2conv.py +++ b/automol/graph/_2conv.py @@ -188,7 +188,7 @@ def _clean_and_validate_connected_geometry( return geo if matches or not check else None -def inchi(gra, stereo: bool=True, local_stereo: bool=False): +def inchi(gra, stereo: bool = True, local_stereo: bool = False): """Generate an InChI string from a molecular graph. :param gra: molecular graph @@ -504,6 +504,63 @@ def ts_geometry_from_reactants( return ts_geo +def clean_ts_geometry( + tsg, + ts_geo, + geo_idx_dct: Dict[int, int] | None = None, + check: bool = True, + log: bool = False, +) -> Any: + """Clean a TS geometry based on its graph. + + :param tsg: TS graph + :type tsg: automol graph data structure + :param rct_geos: Reactant geometries + :type rct_geos: List[automol geom data structure] + :param geo_idx_dct: If they don't already match, specify which graph + keys correspond to which geometry indices, defaults to None + :param check: Check stereo and connectivity? defaults to True + :param log: Print optimization log?, defaults to False + :return: TS geometry + :rtype: automol geom data structure + """ + assert not has_dummy_atoms( + tsg + ), f"Cannot convert graph->geom with dummy atoms:\n{tsg}" + + # 1. Align the graph and the geometry keys/indices + tsg, ts_geo, *_ = align_with_geometry(tsg, ts_geo, (), geo_idx_dct) + + # 2. Convert to local stereo + tsg0 = tsg + tsg = to_local_stereo(tsg) + + # 3. Correct the stereochemistry against the TS graph, so it is consistent with + # both reactants and products + ts_geo = stereo_corrected_geometry(tsg, ts_geo, local_stereo=True) + + if log: + print(f"Raw TS stereo-corrected geometry before cleaning:\n{ts_geo}") + + # 4. Clean the geometry + ts_geo = clean_geometry( + tsg, + ts_geo, + local_stereo=True, + none_if_failed=False, + relax_angles=ts.has_reacting_ring(tsg), + log=log, + ) + + if log: + print(f"TS geometry after cleaning:\n{ts_geo}") + + if check and not geometry_matches(tsg, ts_geo, local_stereo=True, log=log): + raise error.FailedGeometryGenerationError(f"Failed TS graph:\n{string(tsg0)}") + + return ts_geo + + def ts_join_reactant_geometries(tsg, rct_geos, geo_idx_dct=None): """Join two reactant geometries at a single forming bond diff --git a/automol/graph/__init__.py b/automol/graph/__init__.py index 30ef3e45..7f5355de 100644 --- a/automol/graph/__init__.py +++ b/automol/graph/__init__.py @@ -34,6 +34,7 @@ # # conversions from ._2conv import ( chi, + clean_ts_geometry, display, display_reaction, geometry, @@ -769,6 +770,7 @@ # # conversions "geometry", "ts_geometry_from_reactants", + "clean_ts_geometry", "inchi", "chi", "rdkit_molecule", diff --git a/automol/reac/_4struc.py b/automol/reac/_4struc.py index c348f0a8..2c3a4e38 100644 --- a/automol/reac/_4struc.py +++ b/automol/reac/_4struc.py @@ -1,5 +1,6 @@ """ TS geometries for specific reaction classes """ + from typing import List from .. import geom, graph, zmat @@ -28,6 +29,25 @@ ) +def clean_ts_structure(rxn, ts_struc, struc_typ: str) -> object: + """Clean a TS structure based on a Reaction object. + + :param rxn: The reaction object + :param ts_struc: The TS structure to clean + :param struc_typ: The structure type, "geom" or "zmat" + :return: The cleaned TS structure + """ + xrxn = with_structures(rxn, struc_typ=struc_typ) + xrxn = update_structures(xrxn, ts_struc=ts_struc) + grxn = with_structures(xrxn, "geom") + ts_gra = ts_graph(grxn) + ts_geo = ts_structure(grxn) + ts_geo = graph.clean_ts_geometry(ts_gra, ts_geo=ts_geo) + grxn = update_structures(grxn, ts_struc=ts_geo) + xrxn = with_structures(grxn, struc_typ=struc_typ) + return ts_structure(xrxn) + + def with_structures( rxn: Reaction, struc_typ: str, diff --git a/automol/reac/__init__.py b/automol/reac/__init__.py index 9da43ce9..ea7263df 100644 --- a/automol/reac/__init__.py +++ b/automol/reac/__init__.py @@ -58,6 +58,7 @@ from ._3find import substitutions from ._3find import find # TS geometries +from ._4struc import clean_ts_structure from ._4struc import with_structures from ._4struc import reverse # TS zmatrices @@ -169,6 +170,7 @@ 'substitutions', 'find', # TS geometries + 'clean_ts_structure', 'with_structures', 'reverse', # TS zmatrices