
com.actelion.research.chem.RingCollection Maven / Gradle / Ivy
/*
* Copyright (c) 1997 - 2016
* Actelion Pharmaceuticals Ltd.
* Gewerbestrasse 16
* CH-4123 Allschwil, Switzerland
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @author Thomas Sander
*/
package com.actelion.research.chem;
import java.util.ArrayList;
public class RingCollection {
public static final int MAX_SMALL_RING_SIZE = 7;
public static final int MAX_SMALL_RING_COUNT = 1024; // to prevent explosions with highly connected metal grids, etc.
private static final int MODE_SMALL_RINGS = 1;
private static final int MODE_LARGE_RINGS = 2;
private static final int MODE_AROMATICITY = 4;
public static final int MODE_SMALL_RINGS_ONLY = MODE_SMALL_RINGS;
public static final int MODE_SMALL_AND_LARGE_RINGS = MODE_SMALL_RINGS
| MODE_LARGE_RINGS;
public static final int MODE_SMALL_RINGS_AND_AROMATICITY = MODE_SMALL_RINGS
| MODE_AROMATICITY;
public static final int MODE_SMALL_AND_LARGE_RINGS_AND_AROMATICITY = MODE_SMALL_RINGS
| MODE_LARGE_RINGS
| MODE_AROMATICITY;
public static final int MODE_INCLUDE_TAUTOMERIC_BONDS = 8;
private static final int FEATURES_RING_SIZE = 0x0000FFFF;
private static final int FEATURES_AROMATIC = 0x00010000;
private static final int FEATURES_DELOCALIZED = 0x00020000;
private static final int FEATURES_HETERO_AROMATIC = 0x00040000;
private ExtendedMolecule mMol;
private ArrayList mRingAtomSet;
private ArrayList mRingBondSet;
private int[] mAtomRingFeatures;
private int[] mBondRingFeatures;
private int[] mHeteroPosition;
private boolean[] mIsAromatic;
private boolean[] mIsDelocalized;
private int mMaxSmallRingSize;
/**
* Generates the complete set of small rings, which don't contain metal atoms
* and have up to 7 members.
If mode includes LARGE_RINGS, then it determines
* for every atom and bond the size of the smallest ring, which they are
* a member of.
If mode includes AROMATICITY then every small ring
* is checked, whether it is aromatic.
* @param mol
* @param mode one of the public MODE_ options
*/
public RingCollection(ExtendedMolecule mol, int mode) {
this(mol, mode, MAX_SMALL_RING_SIZE);
}
/**
* Generates the complete set of small rings, which don't contain metal atoms
* and have up to 7 members.
If mode includes LARGE_RINGS, then it determines
* for every atom and bond the size of the smallest ring, which they are
* a member of.
If mode includes AROMATICITY then every small ring
* is checked, whether it is aromatic.
* @param mol
* @param mode one of the public MODE_ options
* @param maxSmallRingSize largest ring size considered a small ring
*/
public RingCollection(ExtendedMolecule mol, int mode, int maxSmallRingSize) {
mMol = mol;
mMaxSmallRingSize = maxSmallRingSize;
mRingAtomSet = new ArrayList<>();
mRingBondSet = new ArrayList<>();
mAtomRingFeatures = new int[mMol.getAtoms()];
mBondRingFeatures = new int[mMol.getBonds()];
mMol.ensureHelperArrays(ExtendedMolecule.cHelperNeighbours);
boolean[] isConfirmedChainAtom = new boolean[mMol.getAtoms()];
boolean[] isConfirmedChainBond = new boolean[mMol.getBonds()];
boolean found;
do { // detect atoms of side chains as non-ring-atoms
found = false;
for (int atom=0; atom highest) {
// if run out of atoms look for new base atom of other fragment
for (int atom=0; atom 1) && candidate == atom1) {
int ringAtom[] = new int[graphLevel[graphAtom[current]]];
int atom = graphAtom[current];
for (int j = 0; j < ringAtom.length; j++) {
ringAtom[j] = atom;
atom = graphParent[atom];
}
return ringAtom;
}
if (graphLevel[candidate] == 0 && !isConfirmedChainAtom[candidate]) {
graphAtom[++highest] = candidate;
graphLevel[candidate] = graphLevel[graphAtom[current]] + 1;
graphParent[candidate] = graphAtom[current];
}
}
current++;
}
return null;
}
/**
* An atom's ring size is the size of the smallest ring the atom is a member of.
* If the atom doesn't belong to any ring the ring size is 0. If an atom is member
* of rings larger than 7 members and if the mode parameter of the constructor
* didn't include LARGE_RINGS, then the returned ring size is also 0.
* @param atom
* @return ring size or 0
*/
public int getAtomRingSize(int atom) {
return mAtomRingFeatures[atom] & FEATURES_RING_SIZE;
}
/**
* A bond's ring size is the size of the smallest ring the bond is a member of.
* If the bond doesn't belong to any ring the ring size is 0. If a bond is member
* of rings larger than 7 members and if the mode parameter of the constructor
* didn't include LARGE_RINGS, then the returned ring size is also 0.
* @param bond
* @return ring size or 0
*/
public int getBondRingSize(int bond) {
return mBondRingFeatures[bond] & FEATURES_RING_SIZE;
}
private void addSmallRingsToSet(int closureBond, boolean[] isConfirmedChainAtom) {
int[] graphAtom = new int[mMaxSmallRingSize];
int[] connIndex = new int[mMaxSmallRingSize];
boolean[] isUsed = new boolean[mMol.getAtoms()];
int atom1 = mMol.getBondAtom(0, closureBond);
int atom2 = mMol.getBondAtom(1, closureBond);
graphAtom[0] = atom1;
graphAtom[1] = atom2;
connIndex[1] = -1;
isUsed[atom2] = true;
int current = 1;
while(current >= 1) {
connIndex[current]++;
if (connIndex[current] == mMol.getConnAtoms(graphAtom[current])) {
isUsed[graphAtom[current]] = false;
current--;
continue;
}
int candidate = mMol.getConnAtom(graphAtom[current], connIndex[current]);
if (isUsed[candidate] || isConfirmedChainAtom[candidate])
continue;
if (candidate == atom1 && current > 1) {
addRingIfNew(graphAtom, current+1);
// if we have already such many rings, we only collect the smallest ring to avoid a combinatorial explosion
if (mRingAtomSet.size() >= MAX_SMALL_RING_COUNT)
return;
continue;
}
if (current+1 < mMaxSmallRingSize) {
current++;
graphAtom[current] = candidate;
isUsed[candidate] = true;
connIndex[current] = -1;
}
}
}
private void addRingIfNew(int ringAtom[], int ringSize) {
int lowAtom = mMol.getMaxAtoms();
int lowIndex = 0;
for (int i=0; i ringAtom[i]) {
lowAtom = ringAtom[i];
lowIndex = i;
}
}
int sortedRing[] = new int[ringSize];
int leftIndex = (lowIndex > 0) ? lowIndex - 1 : ringSize - 1;
int rightIndex = (lowIndex < ringSize - 1) ? lowIndex + 1 : 0;
boolean inverse = (ringAtom[leftIndex] < ringAtom[rightIndex]);
for (int i=0; i= ringSize)
index -= ringSize;
while (index < 0)
index += ringSize;
return index;
}
/**
* Returns the position of the electron pair providing hetero atom
* or carbenium atom in case of 5-membered, respective 7-membered
* aromatic ring.
* @param ringNo
* @return position index referring to ringAtom array
*/
public int getHeteroPosition(int ringNo) {
return mHeteroPosition[ringNo];
}
public boolean isAtomMember(int ringNo, int atom) {
int[] ringAtom = mRingAtomSet.get(ringNo);
for (int i=0; iringSize) {
mAtomRingFeatures[ringAtom[i]] &= ~FEATURES_RING_SIZE;
mAtomRingFeatures[ringAtom[i]] |= ringSize;
}
}
for (int i=0; iringSize) {
mBondRingFeatures[ringBond[i]] &= ~FEATURES_RING_SIZE;
mBondRingFeatures[ringBond[i]] |= ringSize;
}
}
}
private void updateAromaticity() {
for (int ring=0; ring= 5 && ringBond.length <= 7)) {
for (int i=0; i 0) {
annelatedRing[ringMembership[bond] >>> 16]
[ringMembership[bond] & 0x7FFF] = ring;
annelatedRing[ring][i] = (ringMembership[bond] >>> 16);
}
else {
ringMembership[bond] = (ring << 16) + 0x8000 + i;
}
}
}
}
}
boolean[] aromaticityHandled = new boolean[mRingAtomSet.size()];
int ringsHandled = 0;
int lastRingsHandled = -1;
while (ringsHandled > lastRingsHandled) {
lastRingsHandled = ringsHandled;
for (int ring=0; ring 1
|| mMol.getBondType(bond) == Molecule.cBondTypeDelocalized);
}
/**
* Checks, whether this bond may contribute pi-electrons from an amide-resonance
* to an aromatic ring. According to M J Cook, A R Katritzky, P Linda, R D Tack
* J. Chem. Soc., Perkin Trans. 2, 1972, 1295-1301
* 2-pyridone and 2-pyridinethione retain most of the aromatic resonance
* energy of pyridine unless the nitrogen atom is methylated.
* @param bond
* @return
*/
public boolean qualifiesAsAmideTypeBond(int bond) {
for (int i=0; i<2; i++) {
int atom1 = mMol.getBondAtom(i, bond);
if ((mMol.getAtomicNo(atom1) == 7)
&& mMol.getConnAtoms(atom1) == 2) {
int atom2 = mMol.getBondAtom(1-i, bond);
if (mMol.getAtomicNo(atom2) == 6) {
for (int j=0; j
© 2015 - 2025 Weber Informatics LLC | Privacy Policy