protected synchronized BitSet getStructureKeyBits(IAtomContainer ac) { // quick workaround for aromatic compounds, to avoid matching non-aromatic keys // TODO remove this when isoTester/keys processing is fixed // isoTester is fixed, but CDK isomorphism tester still needs the workaround, should be fixed in // CDK nightly Mar 2010 for (IBond bond : ac.bonds()) if (bond.getFlag(CDKConstants.ISAROMATIC)) { for (IAtom a : bond.atoms()) a.setFlag(CDKConstants.ISAROMATIC, true); // in e.g. triazole the atoms are not set as aromatics, but bonds are! if (cleanKekuleBonds) bond.setOrder(Order.SINGLE); } // end of the workaround BitSet keys = new BitSet(nKeys); boolean res; for (int i = 0; i < nKeys; i++) { isoTester.setSequence(smartsQueries.get(i), sequences.get(i)); res = isoTester.hasIsomorphism(ac); keys.set(i, res); } return (keys); }
/** Recursive function to produce valid configurations for {@link #getAllConfigurations()}. */ private void findConfigurationsRecursively( List<Integer> rGroupNumbers, List<List<Integer>> occurrences, List<Integer> occurIndexes, List<Integer[]> distributions, List<List<RGroup>> substitutes, int level, List<IAtomContainer> result) throws CDKException { if (level == rGroupNumbers.size()) { if (!checkIfThenConditionsMet(rGroupNumbers, distributions)) return; // Clone the root to get a scaffold to plug the substitutes into. IAtomContainer root = this.getRootStructure(); IAtomContainer rootClone = null; try { rootClone = (IAtomContainer) root.clone(); } catch (CloneNotSupportedException e) { // Abort with CDK exception throw new CDKException("clone() failed; could not perform R-group substitution."); } for (int rgpIdx = 0; rgpIdx < rGroupNumbers.size(); rgpIdx++) { int rNum = rGroupNumbers.get(rgpIdx); int pos = 0; List<RGroup> mapped = substitutes.get(rgpIdx); for (RGroup substitute : mapped) { IAtom rAtom = this.getRgroupQueryAtoms(rNum).get(pos); if (substitute != null) { IAtomContainer rgrpClone = null; try { rgrpClone = (IAtomContainer) (substitute.getGroup().clone()); } catch (CloneNotSupportedException e) { throw new CDKException("clone() failed; could not perform R-group substitution."); } // root cloned, substitute cloned. These now need to be attached to each other.. rootClone.add(rgrpClone); Map<Integer, IBond> rAttachmentPoints = this.getRootAttachmentPoints().get(rAtom); if (rAttachmentPoints != null) { // Loop over attachment points of the R# atom for (int apo = 0; apo < rAttachmentPoints.size(); apo++) { IBond bond = rAttachmentPoints.get(apo + 1); // Check how R# is attached to bond int whichAtomInBond = 0; if (bond.getAtom(1).equals(rAtom)) whichAtomInBond = 1; IAtom subsAt = null; if (apo == 0) subsAt = substitute.getFirstAttachmentPoint(); else subsAt = substitute.getSecondAttachmentPoint(); // Do substitution with the clones IBond cloneBond = rootClone.getBond(getBondPosition(bond, root)); if (subsAt != null) { IAtom subsCloneAtom = rgrpClone.getAtom(getAtomPosition(subsAt, substitute.getGroup())); cloneBond.setAtom(subsCloneAtom, whichAtomInBond); } } } // Optional: shift substitutes 2D for easier visual checking if (rAtom.getPoint2d() != null && substitute != null && substitute.getFirstAttachmentPoint() != null && substitute.getFirstAttachmentPoint().getPoint2d() != null) { Point2d pointR = rAtom.getPoint2d(); Point2d pointC = substitute.getFirstAttachmentPoint().getPoint2d(); double xDiff = pointC.x - pointR.x; double yDiff = pointC.y - pointR.y; for (IAtom subAt : rgrpClone.atoms()) { if (subAt.getPoint2d() != null) { subAt.getPoint2d().x -= xDiff; subAt.getPoint2d().y -= yDiff; } } } } else { // Distribution flag is 0, this means the R# group will not be substituted. // Any atom connected to this group should be given the defined RestH value. IAtom discarded = rootClone.getAtom(getAtomPosition(rAtom, root)); for (IBond r0Bond : rootClone.bonds()) { if (r0Bond.contains(discarded)) { for (IAtom atInBond : r0Bond.atoms()) { atInBond.setProperty( CDKConstants.REST_H, this.getRGroupDefinitions().get(rNum).isRestH()); } } } } pos++; } } // Remove R# remnants from the clone, bonds and atoms that may linger. boolean confHasRGroupBonds = true; while (confHasRGroupBonds) { for (IBond cloneBond : rootClone.bonds()) { boolean removeBond = false; if (cloneBond.getAtom(0) instanceof IPseudoAtom && isValidRgroupQueryLabel(((IPseudoAtom) cloneBond.getAtom(0)).getLabel())) removeBond = true; else if (cloneBond.getAtom(1) instanceof IPseudoAtom && isValidRgroupQueryLabel(((IPseudoAtom) cloneBond.getAtom(1)).getLabel())) removeBond = true; if (removeBond) { rootClone.removeBond(cloneBond); confHasRGroupBonds = true; break; } confHasRGroupBonds = false; } } boolean confHasRGroupAtoms = true; while (confHasRGroupAtoms) { for (IAtom cloneAt : rootClone.atoms()) { if (cloneAt instanceof IPseudoAtom) if (isValidRgroupQueryLabel(((IPseudoAtom) cloneAt).getLabel())) { rootClone.removeAtom(cloneAt); confHasRGroupAtoms = true; break; } confHasRGroupAtoms = false; } } // Add to result list result.add(rootClone); } else { for (int idx = 0; idx < occurrences.get(level).size(); idx++) { occurIndexes.set(level, idx); // With an occurrence picked 0..n for this level's R-group, now find // all possible distributions (positional alternatives). int occurrence = occurrences.get(level).get(idx); int positions = this.getRgroupQueryAtoms(rGroupNumbers.get(level)).size(); Integer[] candidate = new Integer[positions]; for (int j = 0; j < candidate.length; j++) { candidate[j] = 0; } List<Integer[]> rgrpDistributions = new ArrayList<Integer[]>(); findDistributions(occurrence, candidate, rgrpDistributions, 0); for (Integer[] distribution : rgrpDistributions) { distributions.set(level, distribution); RGroup[] mapping = new RGroup[distribution.length]; List<List<RGroup>> mappedSubstitutes = new ArrayList<List<RGroup>>(); mapSubstitutes( this.getRGroupDefinitions().get(rGroupNumbers.get(level)), 0, distribution, mapping, mappedSubstitutes); for (List<RGroup> mappings : mappedSubstitutes) { substitutes.set(level, mappings); findConfigurationsRecursively( rGroupNumbers, occurrences, occurIndexes, distributions, substitutes, level + 1, result); } } } } }