From 5874160a33b923f4dbe4578c97a13afa7d319a32 Mon Sep 17 00:00:00 2001 From: Amy He Date: Fri, 29 Nov 2024 21:51:46 -0800 Subject: [PATCH 1/3] use utility functions in jsonutils: string_to_tuple and tuple_to_string to fix dihedral (tuple of ints) as key problem in json --- meeko/molsetup.py | 12 ++++++------ test/json_serialization_test.py | 1 + 2 files changed, 7 insertions(+), 6 deletions(-) diff --git a/meeko/molsetup.py b/meeko/molsetup.py index 9d9216b4..0c087d42 100644 --- a/meeko/molsetup.py +++ b/meeko/molsetup.py @@ -1377,7 +1377,7 @@ def from_json(obj): obj["ring_closure_info"]["bonds_removed"], obj["ring_closure_info"]["pseudos_by_atom"], ) - molsetup.rotamers = obj["rotamers"] + molsetup.rotamers = [{string_to_tuple(k, element_type=int): v for k,v in rotamer.items()} for rotamer in obj["rotamers"]] molsetup.atom_params = obj["atom_params"] molsetup.restraints = [Restraint.from_json(x) for x in obj["restraints"]] molsetup.flexibility_model = obj["flexibility_model"] @@ -2147,8 +2147,8 @@ def from_json(obj): ] # TODO: Dihedral decoding may need another look rdkit_molsetup.dihedral_interactions = obj["dihedral_interactions"] - rdkit_molsetup.dihedral_partaking_atoms = obj["dihedral_partaking_atoms"] - rdkit_molsetup.dihedral_labels = obj["dihedral_labels"] + rdkit_molsetup.dihedral_partaking_atoms = {string_to_tuple(k, element_type=int): string_to_tuple(v, element_type=int) for k,v in obj["dihedral_partaking_atoms"].items()} + rdkit_molsetup.dihedral_labels = {string_to_tuple(k, element_type=int): v for k,v in obj["dihedral_labels"].items()} rdkit_molsetup.atom_to_ring_id = { int(k): [string_to_tuple(t) for t in v] for k, v in obj["atom_to_ring_id"].items() @@ -2332,7 +2332,7 @@ def default(self, obj): for k, v in obj.rings.items() }, "ring_closure_info": obj.ring_closure_info.__dict__, - "rotamers": obj.rotamers, + "rotamers": [{tuple_to_string(k): v for k, v in rotamer.items()} for rotamer in obj.rotamers], "atom_params": obj.atom_params, "restraints": [ self.restraint_encoder.default(x) for x in obj.restraints @@ -2358,8 +2358,8 @@ def default(self, obj): output_dict["mol"] = rdMolInterchange.MolToJSON(obj.mol) output_dict["modified_atom_positions"] = obj.modified_atom_positions output_dict["dihedral_interactions"] = obj.dihedral_interactions - output_dict["dihedral_partaking_atoms"] = obj.dihedral_partaking_atoms - output_dict["dihedral_labels"] = obj.dihedral_labels + output_dict["dihedral_partaking_atoms"] = {tuple_to_string(k): tuple_to_string(v) for k,v in obj.dihedral_partaking_atoms.items()} + output_dict["dihedral_labels"] = {tuple_to_string(k): v for k,v in obj.dihedral_labels.items()} output_dict["atom_to_ring_id"] = obj.atom_to_ring_id output_dict["ring_corners"] = obj.ring_corners output_dict["rmsd_symmetry_indices"] = obj.rmsd_symmetry_indices diff --git a/test/json_serialization_test.py b/test/json_serialization_test.py index 217b37ce..efab09cc 100644 --- a/test/json_serialization_test.py +++ b/test/json_serialization_test.py @@ -401,6 +401,7 @@ def check_molsetup_equality(decoded_obj: MoleculeSetup, starting_obj: MoleculeSe for idx, component_dict in enumerate(starting_obj.rotamers): decoded_dict = decoded_obj.rotamers[idx] for key in component_dict: + print(key, decoded_dict) assert key in decoded_dict assert decoded_dict[key] == component_dict[key] for key in starting_obj.atom_params: From 638c4f4d2ecc15012b169f696b62b503d3186fcc Mon Sep 17 00:00:00 2001 From: Amy He Date: Fri, 29 Nov 2024 22:01:13 -0800 Subject: [PATCH 2/3] remove unnecessary print --- test/json_serialization_test.py | 1 - 1 file changed, 1 deletion(-) diff --git a/test/json_serialization_test.py b/test/json_serialization_test.py index efab09cc..217b37ce 100644 --- a/test/json_serialization_test.py +++ b/test/json_serialization_test.py @@ -401,7 +401,6 @@ def check_molsetup_equality(decoded_obj: MoleculeSetup, starting_obj: MoleculeSe for idx, component_dict in enumerate(starting_obj.rotamers): decoded_dict = decoded_obj.rotamers[idx] for key in component_dict: - print(key, decoded_dict) assert key in decoded_dict assert decoded_dict[key] == component_dict[key] for key in starting_obj.atom_params: From 4b08a31ab83474dcb9050c717dd9d8f03d9c6220 Mon Sep 17 00:00:00 2001 From: diogom Date: Wed, 4 Dec 2024 11:05:04 -0800 Subject: [PATCH 3/3] add test for dihedral JSON (de)serialization --- meeko/molsetup.py | 4 ++-- test/json_serialization_test.py | 24 ++++++++++++++++++++++++ 2 files changed, 26 insertions(+), 2 deletions(-) diff --git a/meeko/molsetup.py b/meeko/molsetup.py index 0c087d42..2954da54 100644 --- a/meeko/molsetup.py +++ b/meeko/molsetup.py @@ -2147,7 +2147,7 @@ def from_json(obj): ] # TODO: Dihedral decoding may need another look rdkit_molsetup.dihedral_interactions = obj["dihedral_interactions"] - rdkit_molsetup.dihedral_partaking_atoms = {string_to_tuple(k, element_type=int): string_to_tuple(v, element_type=int) for k,v in obj["dihedral_partaking_atoms"].items()} + rdkit_molsetup.dihedral_partaking_atoms = {string_to_tuple(k, element_type=int): v for k,v in obj["dihedral_partaking_atoms"].items()} rdkit_molsetup.dihedral_labels = {string_to_tuple(k, element_type=int): v for k,v in obj["dihedral_labels"].items()} rdkit_molsetup.atom_to_ring_id = { int(k): [string_to_tuple(t) for t in v] @@ -2358,7 +2358,7 @@ def default(self, obj): output_dict["mol"] = rdMolInterchange.MolToJSON(obj.mol) output_dict["modified_atom_positions"] = obj.modified_atom_positions output_dict["dihedral_interactions"] = obj.dihedral_interactions - output_dict["dihedral_partaking_atoms"] = {tuple_to_string(k): tuple_to_string(v) for k,v in obj.dihedral_partaking_atoms.items()} + output_dict["dihedral_partaking_atoms"] = {tuple_to_string(k): v for k,v in obj.dihedral_partaking_atoms.items()} output_dict["dihedral_labels"] = {tuple_to_string(k): v for k,v in obj.dihedral_labels.items()} output_dict["atom_to_ring_id"] = obj.atom_to_ring_id output_dict["ring_corners"] = obj.ring_corners diff --git a/test/json_serialization_test.py b/test/json_serialization_test.py index 217b37ce..7101f313 100644 --- a/test/json_serialization_test.py +++ b/test/json_serialization_test.py @@ -31,6 +31,12 @@ from meeko.utils.pdbutils import PDBAtomInfo +try: + import openforcefields + _got_openff = True +except ImportError as err: + _got_openff = False + # from ..meeko.utils.pdbutils import PDBAtomInfo pkgdir = pathlib.Path(meeko.__file__).parents[1] @@ -413,6 +419,11 @@ def check_molsetup_equality(decoded_obj: MoleculeSetup, starting_obj: MoleculeSe decoded_obj.restraints[idx], starting_obj.restraints[idx] ) + # dihedrals + assert decoded_obj.dihedral_partaking_atoms == starting_obj.dihedral_partaking_atoms + assert decoded_obj.dihedral_interactions == starting_obj.dihedral_interactions + assert decoded_obj.dihedral_labels == starting_obj.dihedral_labels + # Checking flexibility model for key in starting_obj.flexibility_model: assert key in decoded_obj.flexibility_model @@ -763,5 +774,18 @@ def check_polymer_equality( assert decoded_obj.log == starting_obj.log return +@pytest.mark.skipif(not _got_openff, reason="requires openff-forcefields") +def test_dihedral_equality(): + mk_prep = MoleculePreparation( + merge_these_atom_types=(), + dihedral_model="openff", + ) + fn = str(pkgdir/"test"/"flexibility_data"/"non_sequential_atom_ordering_01.mol") + mol = Chem.MolFromMolFile(fn, removeHs=False) + starting_molsetup = mk_prep(mol)[0] + json_str = json.dumps(starting_molsetup, cls=MoleculeSetupEncoder) + decoded_molsetup = json.loads(json_str, object_hook=RDKitMoleculeSetup.from_json) + check_molsetup_equality(starting_molsetup, decoded_molsetup) + return # endregion