Skip to content

Commit

Permalink
New SMILES flavour API documentation.
Browse files Browse the repository at this point in the history
  • Loading branch information
johnmay committed Aug 16, 2016
1 parent 49939f0 commit 2dffeff
Show file tree
Hide file tree
Showing 9 changed files with 431 additions and 264 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -26,7 +26,6 @@

import com.google.common.collect.Maps;

import org.openscience.cdk.CDK;
import org.openscience.cdk.CDKConstants;
import org.openscience.cdk.config.Isotopes;
import org.openscience.cdk.config.IsotopeFactory;
Expand Down Expand Up @@ -91,15 +90,33 @@ final class CDKToBeam {
* Whether to convert the molecule with isotope and stereo information -
* Isomeric SMILES.
*/
private final int options;
private final int flavour;

/** Create a isomeric and aromatic converter. */
CDKToBeam() {
this(SmiOpt.Isotope | SmiOpt.AtomAtomMap | SmiOpt.UseAromaticSymbols);
this(SmiFlavour.AtomicMass | SmiFlavour.AtomAtomMap | SmiFlavour.UseAromaticSymbols);
}

CDKToBeam(int options) {
this.options = options;
CDKToBeam(int flavour) {
this.flavour = flavour;
}

Graph toBeamGraph(IAtomContainer ac) throws CDKException {
return toBeamGraph(ac, flavour);
}

Atom toBeamAtom(IAtom atom) throws CDKException {
return toBeamAtom(atom, flavour);
}

Edge toBeamEdge(IBond b, Map<IAtom, Integer> indices) throws CDKException {

checkArgument(b.getAtomCount() == 2, "Invalid number of atoms on bond");

int u = indices.get(b.getAtom(0));
int v = indices.get(b.getAtom(1));

return toBeamEdgeLabel(b, this.flavour).edge(u, v);
}

/**
Expand All @@ -110,7 +127,7 @@ final class CDKToBeam {
* @param ac an atom container instance
* @return the Beam ChemicalGraph for additional manipulation
*/
Graph toBeamGraph(IAtomContainer ac) throws CDKException {
static Graph toBeamGraph(IAtomContainer ac, int flavour) throws CDKException {

int order = ac.getAtomCount();

Expand All @@ -119,23 +136,23 @@ Graph toBeamGraph(IAtomContainer ac) throws CDKException {

for (IAtom a : ac.atoms()) {
indices.put(a, indices.size());
gb.add(toBeamAtom(a));
gb.add(toBeamAtom(a, flavour));
}

for (IBond b : ac.bonds()) {
gb.add(toBeamEdge(b, indices));
gb.add(toBeamEdge(b, flavour, indices));
}

// configure stereo-chemistry by encoding the stereo-elements
if (SmiOpt.isSet(options, SmiOpt.Stereo)) {
if (SmiFlavour.isSet(flavour, SmiFlavour.Stereo)) {
for (IStereoElement se : ac.stereoElements()) {
if (SmiOpt.isSet(options, SmiOpt.StereoTetrahedral) &&
if (SmiFlavour.isSet(flavour, SmiFlavour.StereoTetrahedral) &&
se instanceof ITetrahedralChirality) {
addTetrahedralConfiguration((ITetrahedralChirality) se, gb, indices);
} else if (SmiOpt.isSet(options, SmiOpt.StereoCisTrans) &&
} else if (SmiFlavour.isSet(flavour, SmiFlavour.StereoCisTrans) &&
se instanceof IDoubleBondStereochemistry) {
addGeometricConfiguration((IDoubleBondStereochemistry) se, gb, indices);
} else if (SmiOpt.isSet(options, SmiOpt.StereoExTetrahedral) &&
addGeometricConfiguration((IDoubleBondStereochemistry) se, flavour, gb, indices);
} else if (SmiFlavour.isSet(flavour, SmiFlavour.StereoExTetrahedral) &&
se instanceof ExtendedTetrahedral) {
addExtendedTetrahedralConfiguration((ExtendedTetrahedral) se, gb, indices);
}
Expand All @@ -156,9 +173,9 @@ Graph toBeamGraph(IAtomContainer ac) throws CDKException {
* @throws NullPointerException the atom had an undefined symbol or implicit
* hydrogen count
*/
Atom toBeamAtom(final IAtom a) {
static Atom toBeamAtom(final IAtom a, final int flavour) {

final boolean aromatic = SmiOpt.isSet(options, SmiOpt.UseAromaticSymbols) && a.getFlag(CDKConstants.ISAROMATIC);
final boolean aromatic = SmiFlavour.isSet(flavour, SmiFlavour.UseAromaticSymbols) && a.getFlag(CDKConstants.ISAROMATIC);
final Integer charge = a.getFormalCharge();
final String symbol = checkNotNull(a.getSymbol(), "An atom had an undefined symbol");

Expand All @@ -178,7 +195,7 @@ Atom toBeamAtom(final IAtom a) {
if (charge != null) ab.charge(charge);

// use the mass number to specify isotope?
if (SmiOpt.isSet(options, SmiOpt.Isotope)) {
if (SmiFlavour.isSet(flavour, SmiFlavour.AtomicMass)) {
Integer massNumber = a.getMassNumber();
if (massNumber != null) {
// XXX: likely causing some overhead but okay for now
Expand All @@ -193,7 +210,7 @@ Atom toBeamAtom(final IAtom a) {
}

Integer atomClass = a.getProperty(ATOM_ATOM_MAPPING);
if (SmiOpt.isSet(options, SmiOpt.AtomAtomMap) && atomClass != null) {
if (SmiFlavour.isSet(flavour, SmiFlavour.AtomAtomMap) && atomClass != null) {
ab.atomClass(atomClass);
}

Expand All @@ -210,14 +227,14 @@ Atom toBeamAtom(final IAtom a) {
* unsupported order
* @throws NullPointerException the bond order was undefined
*/
Edge toBeamEdge(IBond b, Map<IAtom, Integer> indices) throws CDKException {
static Edge toBeamEdge(IBond b, int flavour, Map<IAtom, Integer> indices) throws CDKException {

checkArgument(b.getAtomCount() == 2, "Invalid number of atoms on bond");

int u = indices.get(b.getAtom(0));
int v = indices.get(b.getAtom(1));

return toBeamEdgeLabel(b).edge(u, v);
return toBeamEdgeLabel(b, flavour).edge(u, v);
}

/**
Expand All @@ -229,9 +246,9 @@ Edge toBeamEdge(IBond b, Map<IAtom, Integer> indices) throws CDKException {
* not-aromatic
* @throws IllegalArgumentException the bond order could not be converted
*/
private Bond toBeamEdgeLabel(IBond b) throws CDKException {
private static Bond toBeamEdgeLabel(IBond b, int flavour) throws CDKException {

if (SmiOpt.isSet(options, SmiOpt.UseAromaticSymbols) && b.getFlag(CDKConstants.ISAROMATIC)) return Bond.AROMATIC;
if (SmiFlavour.isSet(flavour, SmiFlavour.UseAromaticSymbols) && b.getFlag(CDKConstants.ISAROMATIC)) return Bond.AROMATIC;

if (b.getOrder() == null) throw new CDKException("A bond had undefined order, possible query bond?");

Expand All @@ -247,7 +264,7 @@ private Bond toBeamEdgeLabel(IBond b) throws CDKException {
case QUADRUPLE:
return Bond.QUADRUPLE;
default:
if (!SmiOpt.isSet(options, SmiOpt.UseAromaticSymbols) && b.getFlag(CDKConstants.ISAROMATIC))
if (!SmiFlavour.isSet(flavour, SmiFlavour.UseAromaticSymbols) && b.getFlag(CDKConstants.ISAROMATIC))
throw new CDKException("Cannot write Kekulé SMILES output due to aromatic bond with unset bond order - molecule should be Kekulized");
throw new CDKException("Unsupported bond order: " + order);
}
Expand All @@ -260,13 +277,13 @@ private Bond toBeamEdgeLabel(IBond b) throws CDKException {
* @param gb the current graph builder
* @param indices atom indices
*/
private void addGeometricConfiguration(IDoubleBondStereochemistry dbs, GraphBuilder gb, Map<IAtom, Integer> indices) {
private static void addGeometricConfiguration(IDoubleBondStereochemistry dbs, int flavour, GraphBuilder gb, Map<IAtom, Integer> indices) {

IBond db = dbs.getStereoBond();
IBond[] bs = dbs.getBonds();

// don't try to set a configuration on aromatic bonds
if (SmiOpt.isSet(options, SmiOpt.UseAromaticSymbols) && db.getFlag(CDKConstants.ISAROMATIC)) return;
if (SmiFlavour.isSet(flavour, SmiFlavour.UseAromaticSymbols) && db.getFlag(CDKConstants.ISAROMATIC)) return;

int u = indices.get(db.getAtom(0));
int v = indices.get(db.getAtom(1));
Expand All @@ -289,7 +306,7 @@ private void addGeometricConfiguration(IDoubleBondStereochemistry dbs, GraphBuil
* @param gb the current graph builder
* @param indices atom indices
*/
private void addTetrahedralConfiguration(ITetrahedralChirality tc, GraphBuilder gb, Map<IAtom, Integer> indices) {
private static void addTetrahedralConfiguration(ITetrahedralChirality tc, GraphBuilder gb, Map<IAtom, Integer> indices) {

IAtom[] ligands = tc.getLigands();

Expand All @@ -308,7 +325,7 @@ private void addTetrahedralConfiguration(ITetrahedralChirality tc, GraphBuilder
* @param gb the current graph builder
* @param indices atom indices
*/
private void addExtendedTetrahedralConfiguration(ExtendedTetrahedral et, GraphBuilder gb,
private static void addExtendedTetrahedralConfiguration(ExtendedTetrahedral et, GraphBuilder gb,
Map<IAtom, Integer> indices) {

IAtom[] ligands = et.peripherals();
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -23,21 +23,16 @@

package org.openscience.cdk.smiles;

import com.google.common.collect.Lists;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.smiles.CxSmilesState.PolymerSgroup;

import java.text.DecimalFormat;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.Collections;
import java.util.Comparator;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import java.util.Set;
import java.util.TreeMap;
import java.util.TreeSet;

public class CxSmilesGenerator {

Expand Down Expand Up @@ -75,7 +70,7 @@ private static int compare(Comparator<Integer> comp, List<Integer> a, List<Integ

static String generate(CxSmilesState state, int opts, int[] components, final int[] ordering) {

if (!SmiOpt.isSet(opts, SmiOpt.CxSmilesWithCoords))
if (!SmiFlavour.isSet(opts, SmiFlavour.CxSmilesWithCoords))
return "";

final int[] invorder = inverse(ordering);
Expand All @@ -98,7 +93,7 @@ public int compare(Integer a, Integer b) {
};

// Fragment Grouping
if (SmiOpt.isSet(opts, SmiOpt.CxFragmentGroup) &&
if (SmiFlavour.isSet(opts, SmiFlavour.CxFragmentGroup) &&
state.fragGroups != null && !state.fragGroups.isEmpty()) {

int maxCompId = 0;
Expand Down Expand Up @@ -146,7 +141,7 @@ public int compare(List<Integer> a, List<Integer> b) {
}

// Atom Labels
if (SmiOpt.isSet(opts, SmiOpt.CxAtomLabel) &&
if (SmiFlavour.isSet(opts, SmiFlavour.CxAtomLabel) &&
state.atomLabels != null && !state.atomLabels.isEmpty()) {

if (sb.length() > 2)
Expand All @@ -167,7 +162,7 @@ public int compare(List<Integer> a, List<Integer> b) {
}

// 2D/3D Coordinates
if (SmiOpt.isSet(opts, SmiOpt.CxCoordinates) &&
if (SmiFlavour.isSet(opts, SmiFlavour.CxCoordinates) &&
state.atomCoords != null && !state.atomCoords.isEmpty()) {
DecimalFormat fmt = new DecimalFormat("#.##");
if (sb.length() > 2) sb.append(',');
Expand All @@ -188,7 +183,7 @@ public int compare(List<Integer> a, List<Integer> b) {
}

// Multicenter/Positional variation bonds
if (SmiOpt.isSet(opts, SmiOpt.CxMulticenter) &&
if (SmiFlavour.isSet(opts, SmiFlavour.CxMulticenter) &&
state.positionVar != null && !state.positionVar.isEmpty()) {

if (sb.length() > 2) sb.append(',');
Expand Down Expand Up @@ -221,7 +216,7 @@ public int compare(Map.Entry<Integer, List<Integer>> a,


// *CCO* |$_AP1;;;;_AP2$,Sg:n:1,2,3::ht|
if (SmiOpt.isSet(opts, SmiOpt.CxPolymer) &&
if (SmiFlavour.isSet(opts, SmiFlavour.CxPolymer) &&
state.sgroups != null && !state.sgroups.isEmpty()) {
List<PolymerSgroup> sgroups = new ArrayList<>(state.sgroups);

Expand Down Expand Up @@ -254,7 +249,7 @@ public int compare(PolymerSgroup a, PolymerSgroup b) {
}

// [C]1[CH][CH]CCC1 |^1:1,2,^3:0|
if (SmiOpt.isSet(opts, SmiOpt.CxRadical) &&
if (SmiFlavour.isSet(opts, SmiFlavour.CxRadical) &&
state.atomRads != null && !state.atomRads.isEmpty()) {
Map<CxSmilesState.Radical, List<Integer>> radinv = new TreeMap<>();
for (Map.Entry<Integer, CxSmilesState.Radical> e : state.atomRads.entrySet()) {
Expand Down

0 comments on commit 2dffeff

Please sign in to comment.