com.actelion.research.chem.IsomericSmilesCreator Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openchemlib Show documentation
Show all versions of openchemlib Show documentation
Open Source Chemistry Library
/*
* 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.
*
*/
package com.actelion.research.chem;
import com.actelion.research.chem.reaction.Reaction;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
public class IsomericSmilesCreator {
private StereoMolecule mMol;
private Canonizer mCanonizer;
private String mSmiles;
private boolean mIncludeMapping;
private int[] mAtomRank;
private int[] mClosureNumber;
private int[] mSmilesIndex;
private int[] mClosureBuffer;
private int[][] mKnownTHCountInESRGroup;
private List mGraphAtomList;
private boolean[] mAtomUsed;
private boolean[] mBondUsed;
private boolean[] mClosureOpened;
private boolean[] mPseudoStereoGroupInversion;
private boolean[] mPseudoStereoGroupInitialized;
public static String createReactionSmiles(Reaction rxn) {
StringBuilder sb = new StringBuilder();
for (int i=0; i');
for (int i=0; i');
for (int i=0; i();
int atom = findUnusedStartAtom();
while (atom != -1) {
int graphIndex = mGraphAtomList.size();
addToGraph(new SmilesAtom(atom, -1, false, false), graphIndex);
if (mMol.getConnAtoms(atom) != 0) {
addHighestRankingChain(graphIndex, false);
while (graphIndex < mGraphAtomList.size() - 1) {
while (hasUnusedNeighborAtom(mGraphAtomList.get(graphIndex).atom))
addHighestRankingChain(graphIndex, true);
graphIndex++;
}
}
// we may have multiple unconnected fragments
atom = findUnusedStartAtom();
}
// assign a smiles position index to every atom (needed for stereo assignment)
mSmilesIndex = new int[mMol.getAtoms()];
int index = 0;
for (SmilesAtom smilesAtom:mGraphAtomList)
mSmilesIndex[smilesAtom.atom] = index++;
}
private void findRingClosures() {
boolean[] closureNumberUsed = new boolean[mMol.getBonds()];
mClosureNumber = new int[mMol.getBonds()];
for (SmilesAtom smilesAtom:mGraphAtomList) {
for (int i=0; i rank) {
startRank = rank;
startAtom = atom;
}
}
}
return startAtom;
}
private boolean hasUnusedNeighborAtom(int atom) {
for (int i=0; i 1)
builder.append(hCount);
}
}
if (charge != 0) {
builder.append(charge > 0 ? '+' : '-');
if (Math.abs(charge) > 1)
builder.append(Math.abs(charge));
}
if (mapNo != 0) {
builder.append(':');
builder.append(mapNo);
}
if (useBrackets)
builder.append(']');
appendClosureBonds(smilesAtom, builder);
if (smilesAtom.isSideChainEnd)
builder.append(')');
}
/**
* Don't store nitrogen parities in SMILES unless we have a quarternary nitrogen.
* Some software packages seem to have promblems when decoding parities on nitrogen atoms.
* @param atom
* @return
*/
private boolean qualifiesForAtomParity(int atom) {
return (mMol.getAtomParity(atom) == Molecule.cAtomParity1
|| mMol.getAtomParity(atom) == Molecule.cAtomParity2)
&& !isSingleKnownStereoCenterInESRGroup(atom)
&& (mMol.getAtomicNo(atom) != 7 || mMol.getAtomCharge(atom) > 0);
}
private boolean isSingleKnownStereoCenterInESRGroup(int atom) {
int type = mMol.getAtomESRType(atom) - 1;
return type == -1 ? false : mKnownTHCountInESRGroup[type][mMol.getAtomESRGroup(atom)] <= 1;
}
private void appendClosureBonds(SmilesAtom smilesAtom, StringBuilder builder) {
int closureCount = 0;
for (int i=0; i> 20);
if (!mClosureOpened[bond]) {
mClosureOpened[bond] = true;
appendBondOrderSymbol(bond, builder);
}
if (closureNumber > 9)
builder.append('%');
builder.append(closureNumber);
}
}
}
private void appendBondOrderSymbol(SmilesAtom smilesAtom, StringBuilder builder) {
if (smilesAtom.ezHalfParity != 0) {
builder.append(smilesAtom.ezHalfParity == 1 ? '/' : '\\');
return;
}
appendBondOrderSymbol(mMol.getBond(smilesAtom.atom, smilesAtom.parent), builder);
}
private void appendBondOrderSymbol(int bond, StringBuilder builder) {
if (!mMol.isAromaticBond(bond)) {
int order = mMol.getBondType(bond) & Molecule.cBondTypeMaskSimple;
if (order == Molecule.cBondTypeSingle) {
if (mMol.isAromaticAtom(mMol.getBondAtom(0, bond))
&& mMol.isAromaticAtom(mMol.getBondAtom(1, bond)))
builder.append('-');
} else if (order == Molecule.cBondTypeDouble)
builder.append('=');
else if (order == Molecule.cBondTypeTriple)
builder.append('#');
// else if (order == Molecule.cBondTypeQuadruple) // not supported by Molecule
// builder.append('$');
}
}
private String getAtomParitySymbol(int atom, int parent) {
boolean inversion = false;
if (mMol.getAtomPi(atom) != 0
&& mMol.getConnAtoms(atom) == 2
&& mMol.getConnBondOrder(atom,0) == 2
&& mMol.getConnBondOrder(atom,1) == 2) { // allene parities
for (int i=0; i neighborRank[1])
inversion = !inversion;
if (neighborRank[0] > neighborRank[2])
inversion = !inversion;
if (neighborRank[1] > neighborRank[2])
inversion = !inversion;
if (neighborAtom[0] > neighborAtom[1])
inversion = !inversion;
if (neighborAtom[0] > neighborAtom[2])
inversion = !inversion;
if (neighborAtom[1] > neighborAtom[2])
inversion = !inversion;
for (int i=0; i<3; i++)
if (parent > neighborAtom[i])
inversion = !inversion;
}
boolean isClockwise = ((mMol.getAtomParity(atom) == Molecule.cAtomParity1) ^ inversion);
if (mMol.isAtomParityPseudo(atom)) {
int group = mCanonizer.getPseudoTHGroup(atom);
if (!mPseudoStereoGroupInitialized[group]) {
mPseudoStereoGroupInitialized[group] = true;
mPseudoStereoGroupInversion[group] = isClockwise;
}
if (mPseudoStereoGroupInversion[group])
isClockwise = !isClockwise;
}
return isClockwise ? "@@" : "@";
}
/**
* @param atom for which to return a neighbor's smiles rank
* @param neighborIndex index for getConnAtoms() to get neighbor atom and bond
* @return neighbor's position rank in smiles from a perspective of atom using closure digit positions for closure neighbors
*/
private int getSmilesRank(int atom, int neighborIndex) {
int bond = mMol.getConnBond(atom, neighborIndex);
if (mClosureNumber[bond] != 0) {
// if neighbor is attached via a closure digit, then the rank is based primarily on atom's position
// in the smiles and secondary on the count of other closures at atom that precede this closure
int rank = 8 * mSmilesIndex[atom] + 1;
for (int i=0; i= 5 && atomicNo <= 9) // B,C,N,O,F
|| (atomicNo >= 15 && atomicNo <= 17) // P,S,Cl
|| atomicNo == 35 // Br
|| atomicNo == 53; // I
}
}
class SmilesAtom {
public int atom,parent,ezHalfParity;
public boolean isSideChainStart,isSideChainEnd;
public SmilesAtom(int atom, int parent, boolean isSideChainStart, boolean isSideChainEnd) {
this.atom = atom;
this.parent = parent;
this.isSideChainStart = isSideChainStart;
this.isSideChainEnd = isSideChainEnd;
}
}
© 2015 - 2025 Weber Informatics LLC | Privacy Policy