int MoleculeSubstructureMatcher::_compare_frequency_asc (BaseMolecule &mol, int i1, int i2) { static int labels_by_freq[] = {ELEM_C, ELEM_H, ELEM_O, ELEM_N, ELEM_P, ELEM_F, ELEM_S, ELEM_Si, ELEM_Cl, ELEM_Br, ELEM_I, ELEM_At}; int label1 = mol.getAtomNumber(i1); int label2 = mol.getAtomNumber(i2); int idx1, idx2; for (idx1 = 0; idx1 < (int)NELEM(labels_by_freq); idx1++) if (label1 == labels_by_freq[idx1]) break; for (idx2 = 0; idx2 < (int)NELEM(labels_by_freq); idx2++) if (label2 == labels_by_freq[idx2]) break; return idx2 - idx1; }
void MoleculeCisTrans::_fillAtomExplicitHydrogens (BaseMolecule &mol, int atom_idx, int subst[2]) { const Vertex &vertex = mol.getVertex(atom_idx); for (int i = vertex.neiBegin(); i != vertex.neiEnd(); i = vertex.neiNext(i)) { int nei = vertex.neiVertex(i); // check [H]\N=C\C if (_pureH(mol, nei)) { if (subst[0] != nei) subst[1] = nei; else if (subst[1] != nei) subst[0] = nei; else throw Error("internal error in _fillAtomExplicitHydrogens"); } } }
void Metalayout::getBoundRect (Vec2f& min, Vec2f& max, BaseMolecule& mol) { if (mol.vertexCount() == 0) { min.zero(); max.zero(); return; } const Vec3f& v0 = mol.getAtomXyz(mol.vertexBegin()); Vec2f::projectZ(min, v0); Vec2f::projectZ(max, v0); Vec2f v2; for (int i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i)) { Vec2f::projectZ(v2, mol.getAtomXyz(i)); min.min(v2); max.max(v2); } }
MoleculeSubstructureMatcher::MoleculeSubstructureMatcher (BaseMolecule &target) : _target(target), TL_CP_GET(_3d_constrained_atoms), TL_CP_GET(_unfolded_target_h), TL_CP_GET(_used_target_h) { vertex_equivalence_handler = NULL; use_aromaticity_matcher = true; use_pi_systems_matcher = false; _query = 0; match_3d = 0; rms_threshold = 0; highlight = false; find_all_embeddings = false; find_unique_embeddings = false; find_unique_by_edges = false; save_for_iteration = false; disable_folding_query_h = false; not_ignore_first_atom = false; cb_embedding = 0; cb_embedding_context = 0; fmcache = 0; disable_unfolding_implicit_h = false; restore_unfolded_h = true; _h_unfold = false; _query_nei_counters = 0; _target_nei_counters = 0; _used_target_h.clear_resize(target.vertexEnd()); // won't ignore target hydrogens because query can contain // 3d features, hydrogen isotopes, etc. }
LayeredMolecules::LayeredMolecules(BaseMolecule& molecule) :_layersAromatized(0) { _proto.clone(molecule.asMolecule(), 0, 0); _proto.dearomatize(AromaticityOptions()); cloneGraph(_proto, 0); for (auto e_idx : _proto.edges()) { for(auto i = 0; i < BOND_TYPES_NUMBER; ++i) { _bond_masks[i].push(); _bond_masks[i].top().resize(1); } _bond_masks[BOND_ZERO].top().reset(0); _bond_masks[BOND_SINGLE].top().reset(0); _bond_masks[BOND_DOUBLE].top().reset(0); _bond_masks[BOND_TRIPLE].top().reset(0); _bond_masks[BOND_AROMATIC].top().reset(0); _bond_masks[_proto.getBondOrder(e_idx)].top().set(0); } _mobilePositions.expandFill(_proto.vertexCount(), false); _mobilePositionsOccupied.expand(_proto.vertexCount()); layers = 1; unsigned node = _trie.getRoot(); for (auto i : _proto.edges()) { bool stub; node = _trie.add(node, _proto.getBondOrder(i), stub); } _hashs.push(node); }
void Metalayout::adjustMol (BaseMolecule& mol, const Vec2f& min, const Vec2f& pos) { float scaleFactor = getScaleFactor(); // Compute center points for the data sgroups QS_DEF(Array<Vec2f>, data_centers); data_centers.resize(mol.data_sgroups.end()); for (int i = mol.data_sgroups.begin(); i < mol.data_sgroups.end(); i = mol.data_sgroups.next(i)) { BaseMolecule::DataSGroup &group = mol.data_sgroups[i]; if (!group.relative) mol.getSGroupAtomsCenterPoint(group, data_centers[i]); } for (int i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i)) { Vec2f v; Vec2f::projectZ(v, mol.getAtomXyz(i)); v.sub(min); v.scale(scaleFactor); v.add(pos); v.y = -v.y; mol.setAtomXyz(i, v.x, v.y, 0); } // Adjust data-sgroup label positions with absolute coordinates for (int i = mol.data_sgroups.begin(); i < mol.data_sgroups.end(); i = mol.data_sgroups.next(i)) { BaseMolecule::DataSGroup &group = mol.data_sgroups[i]; if (!group.relative) { Vec2f new_center; mol.getSGroupAtomsCenterPoint(group, new_center); group.display_pos.add(new_center); group.display_pos.sub(data_centers[i]); } } }
bool MoleculeCisTrans::_sameline (BaseMolecule &molecule, int i_beg, int i_end, int i_nei_beg) { return sameline(molecule.getAtomXyz(i_beg), molecule.getAtomXyz(i_end), molecule.getAtomXyz(i_nei_beg)); }
float Metalayout::getTotalMoleculeClosestDist (BaseMolecule& mol) { QS_DEF(Array<float>, dst); float sum = 0; dst.clear_resize(mol.vertexEnd()); for (int i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i)) dst[i] = -1; for (int i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i)) for (int j = mol.vertexNext(i); j < mol.vertexEnd(); j = mol.vertexNext(j)) { Vec2f u, v; Vec2f::projectZ(u, mol.getAtomXyz(i)); Vec2f::projectZ(v, mol.getAtomXyz(j)); float d = Vec2f::dist(u, v); if (dst[i] < 0 || dst[i] > d) dst[i] = d; if (dst[j] < 0 || dst[j] > d) dst[j] = d; } for (int i = mol.vertexBegin(); i < mol.vertexEnd(); i = mol.vertexNext(i)) sum += dst[i]; return sum; }
void MoleculeCisTrans::_fillExplicitHydrogens (BaseMolecule &mol, int bond_idx, int subst[4]) { _fillAtomExplicitHydrogens(mol, mol.getEdge(bond_idx).beg, subst); _fillAtomExplicitHydrogens(mol, mol.getEdge(bond_idx).end, subst + 2); }
bool MoleculeCisTrans::sortSubstituents (BaseMolecule &mol, int *substituents, bool *parity_changed) { bool e0 = substituents[0] < 0; bool e1 = substituents[1] < 0; bool e2 = substituents[2] < 0; bool e3 = substituents[3] < 0; if (e0 && e1) return false; if (e2 && e3) return false; bool h0 = !e0 && _pureH(mol, substituents[0]); bool h1 = !e1 && _pureH(mol, substituents[1]); bool h2 = !e2 && _pureH(mol, substituents[2]); bool h3 = !e3 && _pureH(mol, substituents[3]); // Query molecules [H]/C=C/C and [H]\C=C/C are different // But normal molecules are the same. if (!mol.isQueryMolecule()) { // Handle [H]/N=C\C and [H]/N=C/C if (!_commonHasLonePair(mol, substituents[0], substituents[1])) { h0 |= e0; h1 |= e1; } if (!_commonHasLonePair(mol, substituents[2], substituents[3])) { h2 |= e2; h3 |= e3; } } if (h0 && h1) return false; if (h2 && h3) return false; int tmp; // If hydrogens are explicit then keep them // And do not place explicit hydrogens to the end, because all static methods // should be converted into non-static with checking whether atom is hydrogen // or not. // For example, molecule [H]\C(O)=C/C can get invalid parity because static // functions getMappingParitySign, applyMapping doesn't know about bool swapped = false; if (!e1) if (e0 || substituents[0] > substituents[1]) { __swap(substituents[0], substituents[1], tmp); swapped = !swapped; } if (!e3) if (e2 || substituents[2] > substituents[3]) { __swap(substituents[2], substituents[3], tmp); swapped = !swapped; } if (parity_changed != 0) *parity_changed = swapped; return true; }
bool MoleculeCisTrans::isGeomStereoBond (BaseMolecule &mol, int bond_idx, int *substituents, bool have_xyz) { int substituents_local[4]; if (substituents == 0) substituents = substituents_local; // it must be [C,N,Si,Ge]=[C,N,Si,Ge] bond if (!mol.possibleBondOrder(bond_idx, BOND_DOUBLE)) return false; const Edge &edge = mol.getEdge(bond_idx); int beg_idx = edge.beg; int end_idx = edge.end; if (!mol.possibleAtomNumber(beg_idx, ELEM_C) && !mol.possibleAtomNumber(beg_idx, ELEM_N) && !mol.possibleAtomNumber(beg_idx, ELEM_Si) && !mol.possibleAtomNumber(beg_idx, ELEM_Ge)) return false; if (!mol.possibleAtomNumber(end_idx, ELEM_C) && !mol.possibleAtomNumber(end_idx, ELEM_N) && !mol.possibleAtomNumber(end_idx, ELEM_Si) && !mol.possibleAtomNumber(end_idx, ELEM_Ge)) return false; // Double bonds with R-sites are excluded because cis-trans configuration // cannot be determined when R-site is substituted with R-group if (mol.isRSite(beg_idx) || mol.isRSite(end_idx)) return false; // the atoms should have 1 or 2 single bonds // (apart from the double bond under consideration) const Vertex &beg = mol.getVertex(beg_idx); const Vertex &end = mol.getVertex(end_idx); if (beg.degree() < 2 || beg.degree() > 3 || end.degree() < 2 || end.degree() > 3) return false; substituents[0] = -1; substituents[1] = -1; substituents[2] = -1; substituents[3] = -1; int i; for (i = beg.neiBegin(); i != beg.neiEnd(); i = beg.neiNext(i)) { int nei_edge_idx = beg.neiEdge(i); if (nei_edge_idx == bond_idx) continue; if (!mol.possibleBondOrder(nei_edge_idx, BOND_SINGLE)) return false; if (substituents[0] == -1) substituents[0] = beg.neiVertex(i); else // (substituents[1] == -1) substituents[1] = beg.neiVertex(i); } for (i = end.neiBegin(); i != end.neiEnd(); i = end.neiNext(i)) { int nei_edge_idx = end.neiEdge(i); if (nei_edge_idx == bond_idx) continue; if (!mol.possibleBondOrder(nei_edge_idx, BOND_SINGLE)) return false; if (substituents[2] == -1) substituents[2] = end.neiVertex(i); else // (substituents[3] == -1) substituents[3] = end.neiVertex(i); } // Check trianges when substituents are the same: CC1=C(N)C1 if (substituents[0] >= 0) if (substituents[0] == substituents[2] || substituents[0] == substituents[3]) return false; if (substituents[1] >= 0) if (substituents[1] == substituents[2] || substituents[1] == substituents[3]) return false; if (have_xyz) { if (substituents[1] != -1 && _sameside(mol, beg_idx, end_idx, substituents[0], substituents[1]) != -1) return false; else if (_sameline(mol, beg_idx, end_idx, substituents[0])) return false; if (substituents[3] != -1 && _sameside(mol, beg_idx, end_idx, substituents[2], substituents[3]) != -1) return false; else if (_sameline(mol, beg_idx, end_idx, substituents[2])) return false; } return true; }
bool MoleculeExactMatcher::matchAtoms (BaseMolecule& query, BaseMolecule& target, int sub_idx, int super_idx, int flags) { if (query.isRSite(sub_idx) && target.isRSite(super_idx)) return query.getRSiteBits(sub_idx) == target.getRSiteBits(super_idx); if (query.isRSite(sub_idx) || target.isRSite(super_idx)) return false; if (query.isPseudoAtom(sub_idx) && target.isPseudoAtom(super_idx)) { if (strcmp(query.getPseudoAtom(sub_idx), target.getPseudoAtom(super_idx)) != 0) return false; } else if (query.isTemplateAtom(sub_idx) && target.isTemplateAtom(super_idx)) { if (strcmp(query.getTemplateAtom(sub_idx), target.getTemplateAtom(super_idx)) != 0) return false; } else if (!query.isPseudoAtom(sub_idx) && !target.isPseudoAtom(super_idx) && !query.isTemplateAtom(sub_idx) && !target.isTemplateAtom(super_idx)) { if (query.getAtomNumber(sub_idx) != target.getAtomNumber(super_idx)) return false; } else return false; if (flags & CONDITION_ISOTOPE) if (query.getAtomIsotope(sub_idx) != target.getAtomIsotope(super_idx)) return false; if (flags & CONDITION_ELECTRONS) { int qcharge = query.getAtomCharge(sub_idx); int tcharge = target.getAtomCharge(super_idx); if (qcharge == CHARGE_UNKNOWN) qcharge = 0; if (tcharge == CHARGE_UNKNOWN) tcharge = 0; if (qcharge != tcharge) return false; if (!query.isPseudoAtom(sub_idx) && !query.isTemplateAtom(sub_idx)) { if (!query.isQueryMolecule() && !target.isQueryMolecule()) { if (query.getAtomValence(sub_idx) != target.getAtomValence(super_idx)) return false; } int qrad = query.getAtomRadical(sub_idx); int trad = target.getAtomRadical(super_idx); if (qrad == -1) qrad = 0; if (trad == -1) trad = 0; if (qrad != trad) return false; if (query.isQueryMolecule()) { int qarom = query.getAtomAromaticity(sub_idx); int tarom = target.getAtomAromaticity(super_idx); if (qarom != -1 && tarom != -1) if (qarom != tarom) return false; } } } if (flags & CONDITION_STEREO) { int qtype = query.stereocenters.getType(sub_idx); if (qtype != target.stereocenters.getType(super_idx)) return false; } return true; }
bool MoleculeCisTrans::_pureH (BaseMolecule &mol, int idx) { return mol.getAtomNumber(idx) == ELEM_H && mol.getAtomIsotope(idx) == 0; }
void _getBounds (RenderParams& params, BaseMolecule &mol, Vec2f &min, Vec2f &max, float &scale) { // Compute average bond length float avg_bond_length = 1; if (mol.edgeCount() > 0) { float bond_length_sum = 0; for (int i = mol.edgeBegin(); i != mol.edgeEnd(); i = mol.edgeNext(i)) { const Edge& edge = mol.getEdge(i); const Vec3f &p1 = mol.getAtomXyz(edge.beg); const Vec3f &p2 = mol.getAtomXyz(edge.end); bond_length_sum += Vec3f::dist(p1, p2); } avg_bond_length = bond_length_sum / mol.edgeCount(); } float bond_length = 1; if (params.cnvOpt.bondLength > 0) bond_length = params.cnvOpt.bondLength / 100.0f; scale = bond_length / avg_bond_length; for (int i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i)) { Vec3f &p = mol.getAtomXyz(i); Vec2f p2(p.x, p.y); if (i == mol.vertexBegin()) min = max = p2; else { min.min(p2); max.max(p2); } } min.scale(scale); max.scale(scale); }
void _placeSGroupBracketsCrossBonds (Array<Vec2f[2]>& brackets, BaseMolecule& mol, const Array<int>& atoms, const Array<int>& crossBonds, const Array<bool>& crossBondOut, float bondLength) { brackets.clear(); if (crossBonds.size() == 2) { int bid1 = crossBonds[0], bid2 = crossBonds[1]; const Edge& edge1 = mol.getEdge(bid1); const Edge& edge2 = mol.getEdge(bid2); Vec2f pb1, pe1, pb2, pe2; Vec2f::projectZ(pb1, mol.getAtomXyz(edge1.beg)); Vec2f::projectZ(pe1, mol.getAtomXyz(edge1.end)); Vec2f::projectZ(pb2, mol.getAtomXyz(edge2.beg)); Vec2f::projectZ(pe2, mol.getAtomXyz(edge2.end)); Vec2f d1, d2; d1.diff(pe1, pb1); if (!crossBondOut[0]) d1.scale(-1); d1.normalize(); d2.diff(pe2, pb2); if (!crossBondOut[1]) d2.scale(-1); d2.normalize(); if (Vec2f::dot(d1, d2) < -0.3) { Vec2f d, n; d.add(pb1); d.add(pe1); d.sub(pb2); d.sub(pe2); d.normalize(); n.copy(d); n.rotate(1, 0); Vec2f min, max, a, b, c; c.add(pb1); c.add(pe1); c.add(pb2); c.add(pe2); c.scale(0.25f); for (int i = 0; i < atoms.size(); ++i) { int aid = atoms[i]; const Vec3f& pos = mol.getAtomXyz(aid); Vec2f p2d; Vec2f::projectZ(p2d, pos); p2d.sub(c); p2d.set(Vec2f::dot(p2d, d), Vec2f::dot(p2d, n)); if (i == 0) { min.copy(p2d); max.copy(p2d); } else { min.min(p2d); max.max(p2d); } } Vec2f b1(c), b2; b1.addScaled(d, max.x + 0.3f * bondLength); b2.copy(b1); float factor = 0.5; b1.addScaled(n, factor * bondLength); b2.addScaled(n, -factor * bondLength); Vec2f* const & bracket1 = brackets.push(); bracket1[0].copy(b1); bracket1[1].copy(b2); b1.copy(c); b1.addScaled(d, min.x - 0.3f * bondLength); b2.copy(b1); b1.addScaled(n, -factor * bondLength); b2.addScaled(n, factor * bondLength); Vec2f* const & bracket2 = brackets.push(); bracket2[0].copy(b1); bracket2[1].copy(b2); return; } } for (int i = 0; i < crossBonds.size(); ++i) { int bid = crossBonds[i]; const Edge& edge = mol.getEdge(bid); int aidIn = edge.beg, aidOut = edge.end; if (!crossBondOut[i]) { int t; __swap(aidIn, aidOut, t); } Vec2f p2dIn, p2dOut, d, n, b1, b2; Vec2f::projectZ(p2dIn, mol.getAtomXyz(aidIn)); Vec2f::projectZ(p2dOut, mol.getAtomXyz(aidOut)); d.diff(p2dOut, p2dIn); d.normalize(); n.copy(d); n.rotate(1, 0); float offset = 1.0f / 3; b1.lineCombin2(p2dIn, 1 - offset, p2dOut, offset); b2.copy(b1); float factor = 0.5; b1.addScaled(n, factor * bondLength); b2.addScaled(n, -factor * bondLength); Vec2f* const & bracket = brackets.push(); bracket[0].copy(b1); bracket[1].copy(b2); } }
void QueryMolecule::_mergeWithSubmolecule (BaseMolecule &bmol, const Array<int> &vertices, const Array<int> *edges, const Array<int> &mapping, int skip_flags) { QueryMolecule &mol = bmol.asQueryMolecule(); int i; // atoms for (i = 0; i < vertices.size(); i++) { int newidx = mapping[vertices[i]]; _atoms.expand(newidx + 1); _atoms.set(newidx, mol.getAtom(vertices[i]).clone()); } // bonds if (edges != 0) for (i = 0; i < edges->size(); i++) { const Edge &edge = mol.getEdge(edges->at(i)); int beg = mapping[edge.beg]; int end = mapping[edge.end]; if (beg == -1 || end == -1) // must have been thrown before in mergeWithSubgraph() throw Error("_mergeWithSubmolecule: internal"); int idx = findEdgeIndex(beg, end); _bonds.expand(idx + 1); _bonds.set(idx, mol.getBond(edges->at(i)).clone()); // Aromaticity if (!(skip_flags & SKIP_AROMATICITY)) aromaticity.setCanBeAromatic(idx, mol.aromaticity.canBeAromatic(edges->at(i))); if (!(skip_flags & SKIP_CIS_TRANS) && mol.cis_trans.getParity(edges->at(i)) != 0) setBondStereoCare(idx, mol.bondStereoCare(edges->at(i))); } else for (i = mol.edgeBegin(); i < mol.edgeEnd(); i = mol.edgeNext(i)) { const Edge &edge = mol.getEdge(i); int beg = mapping[edge.beg]; int end = mapping[edge.end]; if (beg == -1 || end == -1) continue; int idx = findEdgeIndex(beg, end); _bonds.expand(idx + 1); _bonds.set(idx, mol.getBond(i).clone()); // Aromaticity if (!(skip_flags & SKIP_AROMATICITY)) aromaticity.setCanBeAromatic(idx, mol.aromaticity.canBeAromatic(i)); if (!(skip_flags & SKIP_CIS_TRANS) && mol.cis_trans.getParity(i) != 0) setBondStereoCare(idx, mol.bondStereoCare(i)); } // 3D constraints if (!(skip_flags & SKIP_3D_CONSTRAINTS)) spatial_constraints.buildOnSubmolecule(mol.spatial_constraints, mapping.ptr()); // fixed atoms if (!(skip_flags & SKIP_FIXED_ATOMS)) { for (i = 0; i < mol.fixed_atoms.size(); i++) { int idx = mapping[mol.fixed_atoms[i]]; if (idx >= 0) fixed_atoms.push(idx); } } // components if (!(skip_flags & SKIP_COMPONENTS)) { for (i = 0; i < vertices.size(); i++) { int v_idx = vertices[i]; if (mol.components.size() > v_idx) { int newidx = mapping[v_idx]; components.expandFill(newidx + 1, 0); components[newidx] = mol.components[v_idx]; } } } updateEditRevision(); }
bool MoleculeSubstructureMatcher::matchQueryAtom (QueryMolecule::Atom *query, BaseMolecule &target, int super_idx, FragmentMatchCache *fmcache, dword flags) { int i; switch (query->type) { case QueryMolecule::OP_NONE: return true; case QueryMolecule::OP_AND: for (i = 0; i < query->children.size(); i++) if (!matchQueryAtom(query->child(i), target, super_idx, fmcache, flags)) return false; return true; case QueryMolecule::OP_OR: for (i = 0; i < query->children.size(); i++) if (matchQueryAtom(query->child(i), target, super_idx, fmcache, flags)) return true; return false; case QueryMolecule::OP_NOT: return !matchQueryAtom(query->child(0), target, super_idx, fmcache, flags ^ MATCH_DISABLED_AS_TRUE); case QueryMolecule::ATOM_NUMBER: return query->valueWithinRange(target.getAtomNumber(super_idx)); case QueryMolecule::ATOM_PSEUDO: return target.isPseudoAtom(super_idx) && strcmp(query->alias.ptr(), target.getPseudoAtom(super_idx)) == 0; case QueryMolecule::ATOM_RSITE: return true; case QueryMolecule::ATOM_ISOTOPE: return query->valueWithinRange(target.getAtomIsotope(super_idx)); case QueryMolecule::ATOM_CHARGE: { if (flags & MATCH_ATOM_CHARGE) return query->valueWithinRange(target.getAtomCharge(super_idx)); return (flags & MATCH_DISABLED_AS_TRUE) != 0; } case QueryMolecule::ATOM_RADICAL: { if (target.isPseudoAtom(super_idx) || target.isRSite(super_idx)) return false; return query->valueWithinRange(target.getAtomRadical(super_idx)); } case QueryMolecule::ATOM_VALENCE: { if (flags & MATCH_ATOM_VALENCE) { if (target.isPseudoAtom(super_idx) || target.isRSite(super_idx)) return false; return query->valueWithinRange(target.getAtomValence(super_idx)); } return (flags & MATCH_DISABLED_AS_TRUE) != 0; } case QueryMolecule::ATOM_CONNECTIVITY: { int conn = target.getVertex(super_idx).degree(); if (!target.isPseudoAtom(super_idx) && !target.isRSite(super_idx)) conn += target.asMolecule().getImplicitH(super_idx); return query->valueWithinRange(conn); } case QueryMolecule::ATOM_TOTAL_BOND_ORDER: { // TODO: target.isPseudoAtom(super_idx) || target.isRSite(super_idx) return query->valueWithinRange(target.asMolecule().getAtomConnectivity(super_idx)); } case QueryMolecule::ATOM_TOTAL_H: { if (target.isPseudoAtom(super_idx) || target.isRSite(super_idx)) return false; return query->valueWithinRange(target.getAtomTotalH(super_idx)); } case QueryMolecule::ATOM_SUBSTITUENTS: return query->valueWithinRange(target.getAtomSubstCount(super_idx)); case QueryMolecule::ATOM_SSSR_RINGS: return query->valueWithinRange(target.vertexCountSSSR(super_idx)); case QueryMolecule::ATOM_SMALLEST_RING_SIZE: return query->valueWithinRange(target.vertexSmallestRingSize(super_idx)); case QueryMolecule::ATOM_RING_BONDS: case QueryMolecule::ATOM_RING_BONDS_AS_DRAWN: return query->valueWithinRange(target.getAtomRingBondsCount(super_idx)); case QueryMolecule::ATOM_UNSATURATION: return !target.isSaturatedAtom(super_idx); case QueryMolecule::ATOM_FRAGMENT: { if (fmcache == 0) throw Error("unexpected 'fragment' constraint"); QueryMolecule *fragment = query->fragment.get(); const char *smarts = fragment->fragment_smarts.ptr(); if (fragment->vertexCount() == 0) throw Error("empty fragment"); if (smarts != 0 && strlen(smarts) > 0) { fmcache->expand(super_idx + 1); int *value = fmcache->at(super_idx).at2(smarts); if (value != 0) return *value != 0; } MoleculeSubstructureMatcher matcher(target.asMolecule()); matcher.not_ignore_first_atom = true; matcher.setQuery(*fragment); matcher.fmcache = fmcache; bool result = matcher.fix(fragment->vertexBegin(), super_idx); if (result) result = matcher.find(); if (smarts != 0 && strlen(smarts) > 0) { fmcache->expand(super_idx + 1); fmcache->at(super_idx).insert(smarts, result ? 1 : 0); } return result; } case QueryMolecule::ATOM_AROMATICITY: return query->valueWithinRange(target.getAtomAromaticity(super_idx)); case QueryMolecule::HIGHLIGHTING: return query->valueWithinRange((int)target.isAtomHighlighted(super_idx)); default: throw Error("bad query atom type: %d", query->type); } }
void MoleculeAutoLoader::_loadMolecule (BaseMolecule &mol, bool query) { properties.clear(); // check for GZip format if (!query && _scanner->length() >= 2) { byte id[2]; int pos = _scanner->tell(); _scanner->readCharsFix(2, (char *)id); _scanner->seek(pos, SEEK_SET); if (id[0] == 0x1f && id[1] == 0x8b) { GZipScanner gzscanner(*_scanner); QS_DEF(Array<char>, buf); gzscanner.readAll(buf); MoleculeAutoLoader loader2(buf); loader2.ignore_stereocenter_errors = ignore_stereocenter_errors; loader2.ignore_noncritical_query_features = ignore_noncritical_query_features; loader2.treat_x_as_pseudoatom = treat_x_as_pseudoatom; loader2.skip_3d_chirality = skip_3d_chirality; loader2.loadMolecule((Molecule &)mol); return; } } // check for MDLCT format { QS_DEF(Array<char>, buf); if (tryMDLCT(*_scanner, buf)) { BufferScanner scanner2(buf); MolfileLoader loader(scanner2); loader.ignore_stereocenter_errors = ignore_stereocenter_errors; loader.ignore_noncritical_query_features = ignore_noncritical_query_features; loader.skip_3d_chirality = skip_3d_chirality; loader.treat_x_as_pseudoatom = treat_x_as_pseudoatom; if (query) loader.loadQueryMolecule((QueryMolecule &)mol); else loader.loadMolecule((Molecule &)mol); return; } } // check for ICM format if (!query && _scanner->length() >= 4) { char id[3]; int pos = _scanner->tell(); _scanner->readCharsFix(3, id); _scanner->seek(pos, SEEK_SET); if (IcmSaver::checkVersion(id)) { if (query) throw Error("cannot load query molecule from ICM format"); IcmLoader loader(*_scanner); loader.loadMolecule((Molecule &)mol); return; } } // check for CML format { int pos = _scanner->tell(); _scanner->skipSpace(); if (_scanner->lookNext() == '<') { if (_scanner->findWord("<molecule")) { MoleculeCmlLoader loader(*_scanner); loader.ignore_stereochemistry_errors = ignore_stereocenter_errors; if (query) throw Error("CML queries not supported"); loader.loadMolecule(mol.asMolecule()); return; } } _scanner->seek(pos, SEEK_SET); } // check for SMILES format if (Scanner::isSingleLine(*_scanner)) { SmilesLoader loader(*_scanner); loader.ignore_closing_bond_direction_mismatch = ignore_closing_bond_direction_mismatch; loader.ignore_stereochemistry_errors = ignore_stereocenter_errors; if (query) loader.loadQueryMolecule((QueryMolecule &)mol); else loader.loadMolecule((Molecule &)mol); return; } // default is Molfile format { SdfLoader sdf_loader(*_scanner); sdf_loader.readNext(); // Copy properties properties.copy(sdf_loader.properties); BufferScanner scanner2(sdf_loader.data); MolfileLoader loader(scanner2); loader.ignore_stereocenter_errors = ignore_stereocenter_errors; loader.ignore_noncritical_query_features = ignore_noncritical_query_features; loader.skip_3d_chirality = skip_3d_chirality; loader.treat_x_as_pseudoatom = treat_x_as_pseudoatom; if (query) loader.loadQueryMolecule((QueryMolecule &)mol); else loader.loadMolecule((Molecule &)mol); } }
int MoleculeSubstructureMatcher::_compare_degree_asc (BaseMolecule &mol, int i1, int i2) { return mol.getVertex(i2).degree() - mol.getVertex(i1).degree(); }
void MoleculeSubstructureMatcher::markIgnoredHydrogens (BaseMolecule &mol, int *arr, int value_keep, int value_ignore) { int i; for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i)) arr[i] = value_keep; for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i)) { if (mol.getAtomNumber(i) != ELEM_H) continue; if (!mol.possibleAtomIsotope(i, 0)) continue; if (mol.isQueryMolecule()) { // Check if atom has fragment constraint. // For example [$([#1][N])] should be ignored if (mol.asQueryMolecule().getAtom(i).hasConstraint(QueryMolecule::ATOM_FRAGMENT)) continue; } const Vertex &vertex = mol.getVertex(i); if (vertex.degree() == 1) { int nei_idx = vertex.neiVertex(vertex.neiBegin()); if (mol.getAtomNumber(nei_idx) == ELEM_H && mol.possibleAtomIsotope(nei_idx, 0)) continue; // do not ignore rare H-H fragment // Check if hydrogen forms a cis-trans bond or stereocenter int nei_vertex_idx = vertex.neiVertex(vertex.neiBegin()); if (mol.stereocenters.exists(nei_vertex_idx)) continue; // For example for this query hydrogens should be unfolded: [H]\\C=C/C const Vertex &nei_vertex = mol.getVertex(nei_vertex_idx); bool not_ignore = false; for (int nei = nei_vertex.neiBegin(); nei != nei_vertex.neiEnd(); nei = nei_vertex.neiNext(nei)) { int edge = nei_vertex.neiEdge(nei); if (mol.cis_trans.getParity(edge) != 0) { not_ignore = true; break; } } if (not_ignore) continue; arr[i] = value_ignore; } } }
bool TautomerRule::check (BaseMolecule &molecule, int first_idx, int last_idx, char other_arom_first, char other_arom_last) const { if (first_idx != -1 && last_idx != -1) { int first_atom = molecule.getAtomNumber(first_idx); int last_atom = molecule.getAtomNumber(last_idx); if (list1.find(first_atom) >= 0) { if (aromaticity1 == -1 || (aromaticity1 == 1 && (atomInAromaticRing(molecule, first_idx) || other_arom_first == 1)) || (aromaticity1 == 0 && !atomInAromaticRing(molecule, first_idx))) { if (list2.find(last_atom) >= 0) { if (aromaticity2 == -1 || (aromaticity2 == 1 && (atomInAromaticRing(molecule, last_idx) || other_arom_last == 1)) || (aromaticity2 == 0 && !atomInAromaticRing(molecule, last_idx))) { return true; } } } } if (list2.find(first_atom) >= 0) { if (aromaticity2 == -1 || (aromaticity2 == 1 && (atomInAromaticRing(molecule, first_idx) || other_arom_first == 1)) || (aromaticity2 == 0 && !atomInAromaticRing(molecule, first_idx))) { if (list1.find(last_atom) >= 0) { if (aromaticity1 == -1 || (aromaticity1 == 1 && (atomInAromaticRing(molecule, last_idx) || other_arom_last == 1)) || (aromaticity1 == 0 && !atomInAromaticRing(molecule, last_idx))) { return true; } } } } return false; } else if (first_idx != -1 || last_idx != -1) { if (first_idx == -1) first_idx = last_idx; int first_atom = molecule.getAtomNumber(first_idx); if (list1.find(first_atom) >= 0) if (aromaticity1 == -1 || (aromaticity1 == 1 && (atomInAromaticRing(molecule, first_idx) || other_arom_first == 1)) || (aromaticity1 == 0 && !atomInAromaticRing(molecule, first_idx))) return true; if (list2.find(first_atom) >= 0) if (aromaticity2 == -1 || (aromaticity2 == 1 && (atomInAromaticRing(molecule, first_idx) || other_arom_first == 1)) || (aromaticity2 == 0 && !atomInAromaticRing(molecule, first_idx))) return true; return false; } return true; }
void MoleculeFingerprintBuilder::_calcExtraBits (BaseMolecule &mol, Filter &vfilter) { int counters[9] = {0, 0, 0, 0, 0, 0, 0, 0, 0}; int i; for (i = mol.vertexBegin(); i != mol.vertexEnd(); i = mol.vertexNext(i)) { if (!vfilter.valid(i)) continue; int an = mol.getAtomNumber(i); if (an == ELEM_C) counters[0]++; else if (an == ELEM_N) counters[1]++; else if (an == ELEM_O) counters[2]++; else if (an == ELEM_P) counters[3]++; else if (an == ELEM_S) counters[4]++; else if (Element::isHalogen(an)) counters[5]++; else if (an > ELEM_H) counters[6]++; if (!skip_ext_charge && mol.getAtomCharge(i) != 0 && mol.getAtomCharge(i) != CHARGE_UNKNOWN) counters[7]++; if (mol.getAtomIsotope(i) > 0) counters[8]++; } byte *fp = _total_fingerprint.ptr(); if (counters[0] > 13) // > 13 C fp[0] |= 1; if (counters[0] > 16) // > 16 C fp[0] |= 2; if (counters[0] > 19) // > 19 C fp[0] |= 4; if (counters[1] > 1) // > 1 N fp[0] |= 8; if (counters[1] > 2) // > 2 N fp[0] |= 16; if (counters[2] > 3) // > 3 O fp[0] |= 32; if (counters[2] > 4) // > 4 O fp[0] |= 64; if (counters[3] > 0) // have P fp[0] |= 128; if (counters[4] > 0) // have S fp[1] |= 1; if (counters[4] > 1) // > 1 S fp[1] |= 2; if (counters[5] > 1) // > 1 halogen fp[1] |= 4; if (counters[5] > 2) // > 2 halogen fp[1] |= 8; if (counters[6] > 0) // have rare atoms fp[1] |= 16; if (counters[6] > 1) // > 1 rare atom fp[1] |= 32; if (counters[7] > 0) // have charged atoms fp[1] |= 64; if (counters[8] > 1) // have isotopes fp[1] |= 128; }