diff --git a/storage/smiles/src/main/java/org/openscience/cdk/smiles/CDKToBeam.java b/storage/smiles/src/main/java/org/openscience/cdk/smiles/CDKToBeam.java index b419d94e5a..f60a683448 100644 --- a/storage/smiles/src/main/java/org/openscience/cdk/smiles/CDKToBeam.java +++ b/storage/smiles/src/main/java/org/openscience/cdk/smiles/CDKToBeam.java @@ -162,6 +162,33 @@ static Graph toBeamGraph(IAtomContainer ac, int flavour) throws CDKException { return gb.build(); } + private static Integer getMajorMassNumber(Element e) { + try { + switch (e) { + case Hydrogen: return 1; + case Boron: return 11; + case Carbon: return 12; + case Nitrogen: return 14; + case Oxygen: return 16; + case Fluorine: return 19; + case Silicon: return 28; + case Phosphorus: return 31; + case Sulfur: return 32; + case Chlorine: return 35; + case Iodine: return 127; + default: + IsotopeFactory isotopes = Isotopes.getInstance(); + IIsotope isotope = isotopes.getMajorIsotope(e.symbol()); + if (isotope != null) + return isotope.getMassNumber(); + return null; + } + + } catch (IOException ex) { + throw new InternalError("Isotope factory wouldn't load: " + ex.getMessage()); + } + } + /** * Convert an CDK {@link IAtom} to a Beam Atom. The symbol and implicit * hydrogen count are not optional. If the symbol is not supported by the @@ -195,17 +222,12 @@ static Atom toBeamAtom(final IAtom a, final int flavour) { if (charge != null) ab.charge(charge); // use the mass number to specify isotope? - if (SmiFlavor.isSet(flavour, SmiFlavor.AtomicMass)) { + if (SmiFlavor.isSet(flavour, SmiFlavor.AtomicMass | SmiFlavor.AtomicMassStrict)) { Integer massNumber = a.getMassNumber(); if (massNumber != null) { - // XXX: likely causing some overhead but okay for now - try { - IsotopeFactory isotopes = Isotopes.getInstance(); - IIsotope isotope = isotopes.getMajorIsotope(a.getSymbol()); - if (isotope == null || !isotope.getMassNumber().equals(massNumber)) ab.isotope(massNumber); - } catch (IOException e) { - throw new InternalError("Isotope factory wouldn't load: " + e.getMessage()); - } + if (SmiFlavor.isSet(flavour, SmiFlavor.AtomicMassStrict) || + !massNumber.equals(getMajorMassNumber(element))) + ab.isotope(massNumber); } } diff --git a/storage/smiles/src/main/java/org/openscience/cdk/smiles/SmiFlavor.java b/storage/smiles/src/main/java/org/openscience/cdk/smiles/SmiFlavor.java index 9ab29b29c7..76a55c0d10 100644 --- a/storage/smiles/src/main/java/org/openscience/cdk/smiles/SmiFlavor.java +++ b/storage/smiles/src/main/java/org/openscience/cdk/smiles/SmiFlavor.java @@ -55,7 +55,12 @@ private SmiFlavor() { public static final int AtomAtomMap = 0x004; /** - * Output atomic mass on atoms. + * Output atomic mass on atoms. For historical reasons the atomic mass is + * often set on all atoms in a CDK molecule. Therefore to avoid SMILES like + * {@code [12CH3][12CH2][16OH]} major isotopes are not generated. If you + * wish to generate SMILES with the major isotopes please use the flag + * {@link #AtomicMassStrict} this will output all mass numbers and only be + * omitted when the mass is unset (null). */ public static final int AtomicMass = 0x008; @@ -88,6 +93,13 @@ private SmiFlavor() { */ public static final int StereoExTetrahedral = 0x400; + /** + * Generate SMILES with the major isotopes, only omit mass numbers when it + * is unset. + */ + public static final int AtomicMassStrict = 0x800; + + /** * Output supported stereochemistry types. * @see #StereoTetrahedral diff --git a/storage/smiles/src/test/java/org/openscience/cdk/smiles/SmilesGeneratorTest.java b/storage/smiles/src/test/java/org/openscience/cdk/smiles/SmilesGeneratorTest.java index d0046c95a6..85d000f1cc 100644 --- a/storage/smiles/src/test/java/org/openscience/cdk/smiles/SmilesGeneratorTest.java +++ b/storage/smiles/src/test/java/org/openscience/cdk/smiles/SmilesGeneratorTest.java @@ -49,6 +49,7 @@ import org.openscience.cdk.config.Elements; import org.openscience.cdk.config.IsotopeFactory; import org.openscience.cdk.exception.CDKException; +import org.openscience.cdk.exception.InvalidSmilesException; import org.openscience.cdk.graph.AtomContainerAtomPermutor; import org.openscience.cdk.graph.AtomContainerBondPermutor; import org.openscience.cdk.graph.Cycles; @@ -1238,6 +1239,14 @@ public void inconsistentAromaticState() throws Exception { smigen.create(mol); } + @Test + public void strictIsotopes() throws CDKException { + SmilesParser smipar = new SmilesParser(SilentChemObjectBuilder.getInstance()); + IAtomContainer mol = smipar.parseSmiles("[12CH3]C"); + assertThat(new SmilesGenerator(SmiFlavor.AtomicMassStrict).create(mol), is("[12CH3]C")); + assertThat(new SmilesGenerator(SmiFlavor.AtomicMass).create(mol), is("CC")); + } + static ITetrahedralChirality anticlockwise(IAtomContainer container, int central, int a1, int a2, int a3, int a4) { return new TetrahedralChirality(container.getAtom(central), new IAtom[]{container.getAtom(a1), container.getAtom(a2), container.getAtom(a3), container.getAtom(a4)},