From 0561c10ae86d091adb28d263abe31067ce5a5695 Mon Sep 17 00:00:00 2001 From: Aliaksandr Dziarkach <18146690+AliaksandrDziarkach@users.noreply.github.com> Date: Thu, 26 Oct 2023 22:13:30 +0300 Subject: [PATCH] Backmerge #1371 Chirality symbol is added to the SMARTS when 'single up/down' or 'double cis/trans' bond type is set up (#1382) --- .../ref/formats/custom_query.py.out | 2 + .../integration/tests/formats/custom_query.py | 9 ++ .../ref/ket_with_bond_stereo_ether.ket | 108 ++++++++++++++++++ core/indigo-core/molecule/query_molecule.h | 5 +- .../molecule/src/molecule_json_saver.cpp | 2 +- .../molecule/src/query_molecule.cpp | 29 +++-- .../indigo-core/molecule/src/smiles_saver.cpp | 2 +- 7 files changed, 143 insertions(+), 14 deletions(-) create mode 100644 api/tests/integration/tests/formats/ref/ket_with_bond_stereo_ether.ket diff --git a/api/tests/integration/ref/formats/custom_query.py.out b/api/tests/integration/ref/formats/custom_query.py.out index e18909f816..5135fb25db 100644 --- a/api/tests/integration/ref/formats/custom_query.py.out +++ b/api/tests/integration/ref/formats/custom_query.py.out @@ -4,3 +4,5 @@ ket_with_rb_as_drawn.ket OK. Smarts equals expected string '[#6](-[#6])(-[#6;x0])-[#6]' **** #1337 wrong smarts for ring bond count as drawn **** ket_with_custom_query_with_list.ket OK. Smarts equals expected string '[#6]1-[#6]=[Cl,Br,I,Na,O]-[#6]=[#6]-[#6]=1' +**** #1371 Chirality symbol is added to the SMARTS when 'single up/down' or 'double cis/trans' bond type is set up wrong smarts for ring bond count as drawn **** +ket_with_bond_stereo_ether.ket OK. Smarts equals expected string '[#6]1-[#6]=[#6]-[#6]=[#6]\[#6]=1' diff --git a/api/tests/integration/tests/formats/custom_query.py b/api/tests/integration/tests/formats/custom_query.py index 352ee17edb..91db21c2a0 100644 --- a/api/tests/integration/tests/formats/custom_query.py +++ b/api/tests/integration/tests/formats/custom_query.py @@ -50,3 +50,12 @@ def test_ket_to_smarts(filename, expected_str): fname = "ket_with_custom_query_with_list.ket" expected = "[#6]1-[#6]=[Cl,Br,I,Na,O]-[#6]=[#6]-[#6]=1" test_ket_to_smarts(fname, expected) + +print( + "**** #1371 Chirality symbol is added to the SMARTS when " + "'single up/down' or 'double cis/trans' bond type is set up" + " wrong smarts for ring bond count as drawn ****" +) +fname = "ket_with_bond_stereo_ether.ket" +expected = "[#6]1-[#6]=[#6]-[#6]=[#6]\[#6]=1" +test_ket_to_smarts(fname, expected) diff --git a/api/tests/integration/tests/formats/ref/ket_with_bond_stereo_ether.ket b/api/tests/integration/tests/formats/ref/ket_with_bond_stereo_ether.ket new file mode 100644 index 0000000000..100fbd51fb --- /dev/null +++ b/api/tests/integration/tests/formats/ref/ket_with_bond_stereo_ether.ket @@ -0,0 +1,108 @@ +{ + "root": { + "nodes": [ + { + "$ref": "mol0" + } + ] + }, + "mol0": { + "type": "molecule", + "atoms": [ + { + "label": "C", + "location": [ + 2.9673491521285666, + -16.35007441717461, + 0 + ] + }, + { + "label": "C", + "location": [ + 4.697650847871435, + -16.349589229177205, + 0 + ], + "stereoLabel": "abs" + }, + { + "label": "C", + "location": [ + 3.8341375094912395, + -15.849966888850188, + 0 + ] + }, + { + "label": "C", + "location": [ + 4.697650847871435, + -17.35053206782215, + 0 + ] + }, + { + "label": "C", + "location": [ + 2.9673491521285666, + -17.35502005679814, + 0 + ] + }, + { + "label": "C", + "location": [ + 3.836320855479559, + -17.850033111149813, + 0 + ] + } + ], + "bonds": [ + { + "type": 2, + "atoms": [ + 2, + 0 + ] + }, + { + "type": 1, + "atoms": [ + 0, + 4 + ] + }, + { + "type": 2, + "atoms": [ + 4, + 5 + ] + }, + { + "type": 1, + "atoms": [ + 5, + 3 + ] + }, + { + "type": 2, + "atoms": [ + 3, + 1 + ] + }, + { + "type": 1, + "atoms": [ + 1, + 2 + ], + "stereo": 6 + } + ] + } +} \ No newline at end of file diff --git a/core/indigo-core/molecule/query_molecule.h b/core/indigo-core/molecule/query_molecule.h index 1fb16595fc..1a61ca65d9 100644 --- a/core/indigo-core/molecule/query_molecule.h +++ b/core/indigo-core/molecule/query_molecule.h @@ -334,8 +334,9 @@ namespace indigo static std::string getSmartsBondStr(QueryMolecule::Bond* bond); static void writeSmartsBond(Output& output, QueryMolecule::Bond* bond, bool has_or_parent); - static std::string getSmartsAtomStr(QueryMolecule::Atom* atom); - static void writeSmartsAtom(Output& output, Atom* atom, int aam, int chirality, int depth, bool has_or_parent, bool has_not_parent); + static std::string getSmartsAtomStr(QueryMolecule::Atom* atom, int original_format); + static void writeSmartsAtom(Output& output, Atom* atom, int aam, int chirality, int depth, bool has_or_parent, bool has_not_parent, + int original_format); enum QUERY_ATOM { diff --git a/core/indigo-core/molecule/src/molecule_json_saver.cpp b/core/indigo-core/molecule/src/molecule_json_saver.cpp index 0d3c5cc8fc..d36b822d1a 100644 --- a/core/indigo-core/molecule/src/molecule_json_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_json_saver.cpp @@ -830,7 +830,7 @@ void MoleculeJsonSaver::saveAtoms(BaseMolecule& mol, JsonWriter& writer) if (needCustomQuery) { QueryMolecule::Atom& atom = _pqmol->getAtom(i); - std::string customQuery = QueryMolecule::getSmartsAtomStr(&atom); + std::string customQuery = QueryMolecule::getSmartsAtomStr(&atom, _pqmol->original_format); writer.Key("customQuery"); writer.String(customQuery.c_str()); } diff --git a/core/indigo-core/molecule/src/query_molecule.cpp b/core/indigo-core/molecule/src/query_molecule.cpp index 7b2c5b9a58..b33bc40efa 100644 --- a/core/indigo-core/molecule/src/query_molecule.cpp +++ b/core/indigo-core/molecule/src/query_molecule.cpp @@ -404,11 +404,11 @@ void QueryMolecule::writeSmartsBond(Output& output, Bond* bond, bool has_or_pare } } -std::string QueryMolecule::getSmartsAtomStr(QueryMolecule::Atom* atom) +std::string QueryMolecule::getSmartsAtomStr(QueryMolecule::Atom* atom, int original_format) { Array out; ArrayOutput output(out); - writeSmartsAtom(output, atom, -1, -1, 1, false, false); + writeSmartsAtom(output, atom, -1, -1, 1, false, false, original_format); std::string result{out.ptr(), static_cast(out.size())}; return result; } @@ -438,7 +438,7 @@ static void writeAnd(Output& _output, QueryMolecule::Node* node, bool has_or_par _output.writeChar(';'); } -void QueryMolecule::writeSmartsAtom(Output& output, Atom* atom, int aam, int chirality, int depth, bool has_or_parent, bool has_not_parent) +void QueryMolecule::writeSmartsAtom(Output& output, Atom* atom, int aam, int chirality, int depth, bool has_or_parent, bool has_not_parent, int original_format) { int i; @@ -454,7 +454,7 @@ void QueryMolecule::writeSmartsAtom(Output& output, Atom* atom, int aam, int chi break; } output.writeChar('!'); - writeSmartsAtom(output, atom->child(0), aam, chirality, depth + 1, has_or_parent, true); + writeSmartsAtom(output, atom->child(0), aam, chirality, depth + 1, has_or_parent, true, original_format); break; } case OP_AND: { @@ -498,7 +498,7 @@ void QueryMolecule::writeSmartsAtom(Output& output, Atom* atom, int aam, int chi output.writeChar(has_or_parent ? '&' : ';'); cur_pos = output.tell(); } - writeSmartsAtom(output, atom->child(i), aam, chirality, depth + 1, has_or_parent, has_not_parent); + writeSmartsAtom(output, atom->child(i), aam, chirality, depth + 1, has_or_parent, has_not_parent, original_format); } break; } @@ -512,7 +512,7 @@ void QueryMolecule::writeSmartsAtom(Output& output, Atom* atom, int aam, int chi if (i > 0) output.printf(has_not_parent ? "!" : ","); - writeSmartsAtom(output, atom->child(i), aam, chirality, depth + 1, true, has_not_parent); + writeSmartsAtom(output, atom->child(i), aam, chirality, depth + 1, true, has_not_parent, original_format); } break; } @@ -521,10 +521,19 @@ void QueryMolecule::writeSmartsAtom(Output& output, Atom* atom, int aam, int chi break; case ATOM_NUMBER: { output.printf("#%d", atom->value_max); - if (chirality == 1) - output.printf("@"); - else if (chirality == 2) - output.printf("@@"); + switch (original_format) + { + case SMARTS: + case KET: + // SMARTS and ket save chirality in ATOM_CHIRALITY for query molecule + break; + default: + if (chirality == CHIRALITY_ANTICLOCKWISE) + output.printf("@"); + else if (chirality == CHIRALITY_CLOCKWISE) + output.printf("@@"); + break; + } if (aam > 0) output.printf(":%d", aam); diff --git a/core/indigo-core/molecule/src/smiles_saver.cpp b/core/indigo-core/molecule/src/smiles_saver.cpp index 9313f8e245..0facfc913f 100644 --- a/core/indigo-core/molecule/src/smiles_saver.cpp +++ b/core/indigo-core/molecule/src/smiles_saver.cpp @@ -601,7 +601,7 @@ void SmilesSaver::_saveMolecule() else if (_qmol != 0) { int aam = _bmol->reaction_atom_mapping[v_idx]; - QueryMolecule::writeSmartsAtom(_output, &_qmol->getAtom(v_idx), aam, _atoms[v_idx].chirality, 0, false, false); + QueryMolecule::writeSmartsAtom(_output, &_qmol->getAtom(v_idx), aam, _atoms[v_idx].chirality, 0, false, false, _qmol->original_format); } else throw Error("SMARTS format available for query only!");