diff --git a/api/tests/integration/tests/formats/ket_with_query_properties.py b/api/tests/integration/tests/formats/ket_with_query_properties.py index 79a2bb22d0..369ae7c28e 100644 --- a/api/tests/integration/tests/formats/ket_with_query_properties.py +++ b/api/tests/integration/tests/formats/ket_with_query_properties.py @@ -20,8 +20,8 @@ def find_diff(a, b): print("*** KET with query properties ***") ref_path = joinPathPy("ref/", __file__) - -filename = os.path.join(ref_path, "ket_with_query_properties.ket") +name = "ket_with_query_properties.ket" +filename = os.path.join(ref_path, name) mol = indigo.loadQueryMoleculeFromFile(filename) with open(filename, "r") as file: @@ -29,7 +29,7 @@ def find_diff(a, b): ket = mol.json() diff = find_diff(ket_ref, ket) if not diff: - print(filename + ".ket:SUCCEED") + print(name + ":SUCCEED") else: - print(filename + ".ket:FAILED") + print(name + ":FAILED") print(diff) diff --git a/api/tests/integration/tests/formats/ref/ket_with_query_properties.ket b/api/tests/integration/tests/formats/ref/ket_with_query_properties.ket index 6af971306d..3752098544 100644 --- a/api/tests/integration/tests/formats/ref/ket_with_query_properties.ket +++ b/api/tests/integration/tests/formats/ref/ket_with_query_properties.ket @@ -58,12 +58,9 @@ ], "queryProperties": { "aromaticity": "aliphatic", - "degree": 2, - "ringMembership": 3, - "ringSize": 4, "connectivity": 5, - "ringConnectivity": 6, - "atomicMass": 12 + "ringMembership": 3, + "ringSize": 4 } } ], diff --git a/core/indigo-core/molecule/query_molecule.h b/core/indigo-core/molecule/query_molecule.h index cd98fa75fd..abaa057edd 100644 --- a/core/indigo-core/molecule/query_molecule.h +++ b/core/indigo-core/molecule/query_molecule.h @@ -329,6 +329,7 @@ namespace indigo static bool isNotAtom(QueryMolecule::Atom& qa, int elem); static QueryMolecule::Atom* stripKnownAttrs(QueryMolecule::Atom& qa); static bool collectAtomList(Atom& qa, Array& list, bool& notList); + static int parseQueryAtom(QueryMolecule::Atom& qa, Array& list); static int parseQueryAtom(QueryMolecule& qm, int aid, Array& list); static bool queryAtomIsRegular(QueryMolecule& qm, int aid); static bool queryAtomIsSpecial(QueryMolecule& qm, int aid); diff --git a/core/indigo-core/molecule/src/molecule_json_loader.cpp b/core/indigo-core/molecule/src/molecule_json_loader.cpp index 6b6cebe821..f1d5aa084b 100644 --- a/core/indigo-core/molecule/src/molecule_json_loader.cpp +++ b/core/indigo-core/molecule/src/molecule_json_loader.cpp @@ -540,12 +540,6 @@ void MoleculeJsonLoader::parseAtoms(const rapidjson::Value& atoms, BaseMolecule& _pqmol->resetAtom(atom_idx, QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx), new QueryMolecule::Atom(QueryMolecule::ATOM_AROMATICITY, aromatic))); } - if (qProps.HasMember("degree")) - { - int degree = qProps["degree"].GetInt(); - _pqmol->resetAtom(atom_idx, QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx), - new QueryMolecule::Atom(QueryMolecule::ATOM_SUBSTITUENTS, degree))); - } if (qProps.HasMember("ringMembership")) { int rmem = qProps["ringMembership"].GetInt(); @@ -564,26 +558,14 @@ void MoleculeJsonLoader::parseAtoms(const rapidjson::Value& atoms, BaseMolecule& _pqmol->resetAtom( atom_idx, QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx), new QueryMolecule::Atom(QueryMolecule::ATOM_CONNECTIVITY, conn))); } - if (qProps.HasMember("ringConnectivity")) - { - int rconn = qProps["ringConnectivity"].GetInt(); - _pqmol->resetAtom( - atom_idx, QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx), new QueryMolecule::Atom(QueryMolecule::ATOM_RING_BONDS, rconn))); - } - if (qProps.HasMember("atomicMass")) - { - int mass = qProps["atomicMass"].GetInt(); - _pqmol->resetAtom(atom_idx, - QueryMolecule::Atom::und(_pqmol->releaseAtom(atom_idx), new QueryMolecule::Atom(QueryMolecule::ATOM_ISOTOPE, mass))); - } if (qProps.HasMember("chirality")) { std::string arom = qProps["chirality"].GetString(); int chirality; if (arom == "clockwise") - chirality = ATOM_AROMATIC; + chirality = 1; else if (arom == "anticlockwise") - chirality = ATOM_ALIPHATIC; + chirality = 2; else throw Error("Wrong value for chirality."); // 2do - add hirality to atom diff --git a/core/indigo-core/molecule/src/molecule_json_saver.cpp b/core/indigo-core/molecule/src/molecule_json_saver.cpp index 36efc8b334..5187209be2 100644 --- a/core/indigo-core/molecule/src/molecule_json_saver.cpp +++ b/core/indigo-core/molecule/src/molecule_json_saver.cpp @@ -612,91 +612,6 @@ void MoleculeJsonSaver::saveSelection(BaseMolecule& mol, JsonWriter& writer) } } -bool MoleculeJsonSaver::_needCustomQuery(QueryMolecule::Atom* atom) const -{ - switch (atom->type) - { - case QueryMolecule::ATOM_NUMBER: - case QueryMolecule::ATOM_UNSATURATION: // Processed in other place - case QueryMolecule::ATOM_AROMATICITY: - case QueryMolecule::ATOM_SUBSTITUENTS: - case QueryMolecule::ATOM_SSSR_RINGS: - case QueryMolecule::ATOM_SMALLEST_RING_SIZE: - case QueryMolecule::ATOM_CONNECTIVITY: - case QueryMolecule::ATOM_RING_BONDS: - case QueryMolecule::ATOM_ISOTOPE: - // 2do add hirality - // case QueryMolecule::ATOM_CHIRALITY: - return false; - case QueryMolecule::OP_AND: - for (int i = 0; i < atom->children.size(); i++) - { - if (_needCustomQuery(static_cast(atom->children[i]))) - return true; - } - return false; - case QueryMolecule::OP_OR: - case QueryMolecule::OP_NOT: - default: - return true; - } -} - -void MoleculeJsonSaver::_writeQueryProperties(QueryMolecule::Atom* atom, JsonWriter& writer) -{ - switch (atom->type) - { - case QueryMolecule::ATOM_NUMBER: - case QueryMolecule::ATOM_UNSATURATION: - // Processed in other place - break; - case QueryMolecule::ATOM_AROMATICITY: - writer.Key("aromaticity"); - if (atom->value_min == ATOM_AROMATIC) - writer.String(ATOM_AROMATIC_STR); - else if (atom->value_min == ATOM_ALIPHATIC) - writer.String(ATOM_ALIPHATIC_STR); - else - throw "Wrong aromaticity value"; - break; - case QueryMolecule::ATOM_SUBSTITUENTS: - writer.Key("degree"); - writer.Int(atom->value_min); - break; - case QueryMolecule::ATOM_SSSR_RINGS: - writer.Key("ringMembership"); - writer.Int(atom->value_min); - break; - case QueryMolecule::ATOM_SMALLEST_RING_SIZE: - writer.Key("ringSize"); - writer.Int(atom->value_min); - break; - case QueryMolecule::ATOM_CONNECTIVITY: - writer.Key("connectivity"); - writer.Int(atom->value_min); - break; - case QueryMolecule::ATOM_RING_BONDS: - writer.Key("ringConnectivity"); - writer.Int(atom->value_min); - break; - case QueryMolecule::ATOM_ISOTOPE: - writer.Key("atomicMass"); - writer.Int(atom->value_min); - break; - // 2do add hirality - // case QueryMolecule::ATOM_CHIRALITY: - // break; - case QueryMolecule::OP_AND: - for (int i = 0; i < atom->children.size(); i++) - { - _writeQueryProperties(static_cast(atom->children[i]), writer); - } - break; - default: - throw "Invalid queryProperties option."; - } -} - void MoleculeJsonSaver::saveAtoms(BaseMolecule& mol, JsonWriter& writer) { QS_DEF(Array, buf); @@ -924,20 +839,51 @@ void MoleculeJsonSaver::saveAtoms(BaseMolecule& mol, JsonWriter& writer) if (_pqmol) { QueryMolecule::Atom& atom = _pqmol->getAtom(i); - if (atom.type != QueryMolecule::ATOM_NUMBER && atom.type != QueryMolecule::OP_NONE && atom.type != QueryMolecule::ATOM_UNSATURATION) + int query_atom_type = -1; + QS_DEF(Array, qatom_list); + query_atom_type = QueryMolecule::parseQueryAtom(atom, qatom_list); + QueryMolecule::Atom* s_atom = QueryMolecule::stripKnownAttrs(atom); + bool needCustomQuery = query_atom_type == -1 && s_atom->type != QueryMolecule::ATOM_NUMBER; + std::map qprops{{QueryMolecule::ATOM_SSSR_RINGS, "ringMembership"}, + {QueryMolecule::ATOM_SMALLEST_RING_SIZE, "ringSize"}, + {QueryMolecule::ATOM_CONNECTIVITY, "connectivity"}}; + bool hasQueryProperties = atom.hasConstraint(QueryMolecule::ATOM_AROMATICITY) || + std::any_of(qprops.cbegin(), qprops.cend(), [&atom](auto p) { return atom.hasConstraint(p.first); }); + if (needCustomQuery || hasQueryProperties) { writer.Key("queryProperties"); writer.StartObject(); - if (_needCustomQuery(&atom)) + if (needCustomQuery) { // 2do generate customquery - std::string customQuery; + std::string customQuery = ""; writer.Key("customQuery"); writer.String(customQuery.c_str()); } else { - _writeQueryProperties(&atom, writer); + int value = -1; + + if (atom.sureValue(QueryMolecule::ATOM_AROMATICITY, value)) + { + writer.Key("aromaticity"); + if (value == ATOM_AROMATIC) + writer.String(ATOM_AROMATIC_STR); + else if (value == ATOM_ALIPHATIC) + writer.String(ATOM_ALIPHATIC_STR); + else + throw "Wrong aromaticity value"; + } + for (auto p : qprops) + { + if (atom.sureValue(p.first, value)) + { + writer.Key(p.second); + writer.Uint(value); + } + } + // 2do add hirality + //*/ } writer.EndObject(); } diff --git a/core/indigo-core/molecule/src/query_molecule.cpp b/core/indigo-core/molecule/src/query_molecule.cpp index 6a46a3175c..7673371a40 100644 --- a/core/indigo-core/molecule/src/query_molecule.cpp +++ b/core/indigo-core/molecule/src/query_molecule.cpp @@ -1868,7 +1868,8 @@ bool QueryMolecule::isKnownAttr(QueryMolecule::Atom& qa) return (qa.type == QueryMolecule::ATOM_CHARGE || qa.type == QueryMolecule::ATOM_ISOTOPE || qa.type == QueryMolecule::ATOM_RADICAL || qa.type == QueryMolecule::ATOM_VALENCE || qa.type == QueryMolecule::ATOM_TOTAL_H || qa.type == QueryMolecule::ATOM_SUBSTITUENTS || qa.type == QueryMolecule::ATOM_SUBSTITUENTS_AS_DRAWN || qa.type == QueryMolecule::ATOM_RING_BONDS || - qa.type == QueryMolecule::ATOM_RING_BONDS_AS_DRAWN || qa.type == QueryMolecule::ATOM_UNSATURATION) && + qa.type == QueryMolecule::ATOM_RING_BONDS_AS_DRAWN || qa.type == QueryMolecule::ATOM_UNSATURATION || qa.type == QueryMolecule::ATOM_AROMATICITY || + qa.type == QueryMolecule::ATOM_SSSR_RINGS || qa.type == QueryMolecule::ATOM_SMALLEST_RING_SIZE || qa.type == QueryMolecule::ATOM_CONNECTIVITY) && qa.value_max == qa.value_min; } @@ -1951,7 +1952,11 @@ QueryMolecule::Atom* QueryMolecule::stripKnownAttrs(QueryMolecule::Atom& qa) int QueryMolecule::parseQueryAtom(QueryMolecule& qm, int aid, Array& list) { - QueryMolecule::Atom& qa = qm.getAtom(aid); + return parseQueryAtom(qm.getAtom(aid), list); +} + +int QueryMolecule::parseQueryAtom(QueryMolecule::Atom& qa, Array& list) +{ QueryMolecule::Atom* qc = stripKnownAttrs(qa); if (qa.type == QueryMolecule::OP_NONE) return QUERY_ATOM_AH;