Skip to content

Commit

Permalink
Merge pull request #246 from cdk/patch/atom-creation
Browse files Browse the repository at this point in the history
Improved API for atom creation.
  • Loading branch information
egonw committed Oct 28, 2016
2 parents 3030f4d + f3c112b commit ddbc988
Show file tree
Hide file tree
Showing 42 changed files with 771 additions and 235 deletions.
169 changes: 164 additions & 5 deletions base/data/src/main/java/org/openscience/cdk/Atom.java
Expand Up @@ -22,6 +22,7 @@
*/
package org.openscience.cdk;

import org.openscience.cdk.config.Elements;
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IElement;
import org.openscience.cdk.tools.periodictable.PeriodicTable;
Expand Down Expand Up @@ -113,15 +114,67 @@ public Atom() {
}

/**
* Constructs an Atom from a String containing an element symbol.
* Create a new atom with of the specified element.
*
* @param elementSymbol The String describing the element for the Atom
* @param elem atomic number
*/
public Atom(String elementSymbol) {
this(new Element(elementSymbol, PeriodicTable.getAtomicNumber(elementSymbol)));
this.formalCharge = 0;
public Atom(int elem) {
this(elem, 0, 0);
}

/**
* Create a new atom with of the specified element and hydrogen count.
*
* @param elem atomic number
* @param hcnt hydrogen count
*/
public Atom(int elem, int hcnt) {
this(elem, hcnt, 0);
}

/**
* Create a new atom with of the specified element, hydrogen count, and formal charge.
*
* @param elem atomic number
* @param hcnt hydrogen count
* @param fchg formal charge
*/
public Atom(int elem, int hcnt, int fchg) {
super((String)null);
setAtomicNumber(elem);
setSymbol(Elements.ofNumber(elem).symbol());
setImplicitHydrogenCount(hcnt);
setFormalCharge(fchg);
}

/**
* Constructs an Atom from a string containing an element symbol and optionally
* the atomic mass, hydrogen count, and formal charge. The symbol grammar allows
* easy construction from common symbols, for example:
*
* <pre>
* new Atom("NH+"); // nitrogen cation with one hydrogen
* new Atom("OH"); // hydroxy
* new Atom("O-"); // oxygen anion
* new Atom("13CH3"); // methyl isotope 13
* </pre>
*
* <pre>
* atom := {mass}? {symbol} {hcnt}? {fchg}?
* mass := \d+
* hcnt := 'H' \d+
* fchg := '+' \d+? | '-' \d+?
* </pre>
*
* @param symbol string with the element symbol
*/
public Atom(String symbol) {
super((String)null);
if (!parseAtomSymbol(this, symbol))
throw new IllegalArgumentException("Cannot pass atom symbol: " + symbol);
}


/**
* Constructs an Atom from an Element and a Point3d.
*
Expand Down Expand Up @@ -452,4 +505,110 @@ public IAtom clone() throws CloneNotSupportedException {
return (IAtom) clone;
}


private static boolean isUpper(char c) {
return c >= 'A' && c <= 'Z';
}

private static boolean isLower(char c) {
return c >= 'a' && c <= 'z';
}

private static boolean isDigit(char c) {
return c >= '0' && c <= '9';
}

private static boolean parseAtomSymbol(IAtom atom, String str) {
final int len = str.length();
int pos = 0;

int mass = -1;
int anum = 0;
int hcnt = 0;
int chg = 0;

// optional mass
if (pos < len && isDigit(str.charAt(pos))) {
mass = (str.charAt(pos++) - '0');
while (pos < len && isDigit(str.charAt(pos)))
mass = 10 * mass + (str.charAt(pos++) - '0');
} else if ("R".equals(str)) {
atom.setAtomicNumber(0);
atom.setSymbol("R");
return true;
} else if ("D".equals(str)) {
atom.setAtomicNumber(1);
atom.setMassNumber(2);
atom.setSymbol("H");
return true;
} else if ("T".equals(str)) {
atom.setAtomicNumber(1);
atom.setMassNumber(3);
atom.setSymbol("H");
return true;
}

// atom symbol
if (pos < len && isUpper(str.charAt(pos))) {
int beg = pos;
pos++;
while (pos < len && isLower(str.charAt(pos)))
pos++;
Elements elem = Elements.ofString(str.substring(beg, pos));
if (elem == Elements.Unknown)
return false;
anum = elem.number();

// optional fields after atom symbol
while (pos < len) {
switch (str.charAt(pos)) {
case 'H':
pos++;
if (pos < len && isDigit(str.charAt(pos))) {
while (pos < len && isDigit(str.charAt(pos)))
hcnt = 10 * hcnt + (str.charAt(pos++) - '0');
} else {
hcnt = 1;
}
break;
case '+':
pos++;
if (pos < len && isDigit(str.charAt(pos))) {
chg = (str.charAt(pos++) - '0');
while (pos < len && isDigit(str.charAt(pos)))
chg = 10 * chg + (str.charAt(pos++) - '0');
} else {
chg = +1;
}
break;
case '-':
pos++;
if (pos < len && isDigit(str.charAt(pos))) {
chg = (str.charAt(pos++) - '0');
while (pos < len && isDigit(str.charAt(pos)))
chg = 10 * chg + (str.charAt(pos++) - '0');
chg *= -1;
} else {
chg = -1;
}
break;
default:
return false;
}
}
} else {
return false;
}

if (mass < 0)
atom.setMassNumber(null);
else
atom.setMassNumber(mass);
atom.setAtomicNumber(anum);
atom.setSymbol(Elements.ofNumber(anum).symbol());
atom.setImplicitHydrogenCount(hcnt);
atom.setFormalCharge(chg);

return pos == len && len > 0;
}
}
Expand Up @@ -110,6 +110,7 @@ record = null;
oxt = false;
hetAtom = false;

super.hydrogenCount = null;
super.charge = Double.valueOf(0.0);
super.formalCharge = Integer.valueOf(0);
}
Expand Down
86 changes: 86 additions & 0 deletions base/data/src/test/java/org/openscience/cdk/AtomTest.java
Expand Up @@ -77,6 +77,92 @@ public void testAtom_String() {
Assert.assertNull(a.getFractionalPoint3d());
}

@Test
public void testAtom_NH4plus_direct() {
IAtom a = new Atom(7, 4, +1);
Assert.assertEquals("N", a.getSymbol());
Assert.assertEquals((Integer) 7, a.getAtomicNumber());
Assert.assertEquals((Integer) 4, a.getImplicitHydrogenCount());
Assert.assertEquals((Integer) 1, a.getFormalCharge());
Assert.assertNull(a.getPoint2d());
Assert.assertNull(a.getPoint3d());
Assert.assertNull(a.getFractionalPoint3d());
}

@Test
public void testAtom_CH3_direct() {
IAtom a = new Atom(6, 3);
Assert.assertEquals("C", a.getSymbol());
Assert.assertEquals((Integer) 6, a.getAtomicNumber());
Assert.assertEquals((Integer) 3, a.getImplicitHydrogenCount());
Assert.assertEquals((Integer) 0, a.getFormalCharge());
Assert.assertNull(a.getPoint2d());
Assert.assertNull(a.getPoint3d());
Assert.assertNull(a.getFractionalPoint3d());
}

@Test
public void testAtom_Cl_direct() {
IAtom a = new Atom(17);
Assert.assertEquals("Cl", a.getSymbol());
Assert.assertEquals((Integer) 17, a.getAtomicNumber());
Assert.assertEquals((Integer) 0, a.getImplicitHydrogenCount());
Assert.assertEquals((Integer) 0, a.getFormalCharge());
Assert.assertNull(a.getPoint2d());
Assert.assertNull(a.getPoint3d());
Assert.assertNull(a.getFractionalPoint3d());
}

@Test
public void testAtom_NH4plus() {
IAtom a = new Atom("NH4+");
Assert.assertEquals("N", a.getSymbol());
Assert.assertEquals((Integer) 7, a.getAtomicNumber());
Assert.assertEquals((Integer) 4, a.getImplicitHydrogenCount());
Assert.assertEquals((Integer) 1, a.getFormalCharge());
Assert.assertNull(a.getPoint2d());
Assert.assertNull(a.getPoint3d());
Assert.assertNull(a.getFractionalPoint3d());
}

@Test
public void testAtom_Ominus() {
IAtom a = new Atom("O-");
Assert.assertEquals("O", a.getSymbol());
Assert.assertEquals((Integer) 8, a.getAtomicNumber());
Assert.assertEquals((Integer) 0, a.getImplicitHydrogenCount());
Assert.assertEquals(Integer.valueOf(-1), a.getFormalCharge());
Assert.assertNull(a.getPoint2d());
Assert.assertNull(a.getPoint3d());
Assert.assertNull(a.getFractionalPoint3d());
}

@Test
public void testAtom_Ca2plus() {
IAtom a = new Atom("Ca+2");
Assert.assertEquals("Ca", a.getSymbol());
Assert.assertEquals((Integer) 20, a.getAtomicNumber());
Assert.assertEquals((Integer) 0, a.getImplicitHydrogenCount());
Assert.assertEquals(Integer.valueOf(+2), a.getFormalCharge());
Assert.assertNull(a.getPoint2d());
Assert.assertNull(a.getPoint3d());
Assert.assertNull(a.getFractionalPoint3d());
}

@Test
public void testAtom_13CH3() {
IAtom a = new Atom("13CH3");
Assert.assertEquals("C", a.getSymbol());
Assert.assertEquals((Integer) 13, a.getMassNumber());
Assert.assertEquals((Integer) 6, a.getAtomicNumber());
Assert.assertEquals((Integer) 3, a.getImplicitHydrogenCount());
Assert.assertEquals((Integer) 0, a.getFormalCharge());
Assert.assertNull(a.getPoint2d());
Assert.assertNull(a.getPoint3d());
Assert.assertNull(a.getFractionalPoint3d());
}


/**
* Method to test the Atom(String symbol, javax.vecmath.Point3d point3D) method.
*/
Expand Down
10 changes: 5 additions & 5 deletions base/data/src/test/java/org/openscience/cdk/BioPolymerTest.java
Expand Up @@ -66,11 +66,11 @@ public void testBioPolymer() {
oMono2.setMonomerName(new String("HOH"));
IMonomer oMono3 = oBioPolymer.getBuilder().newInstance(IMonomer.class);
oMono3.setMonomerName(new String("GLYA16"));
IAtom oAtom1 = oBioPolymer.getBuilder().newInstance(IAtom.class, "C1");
IAtom oAtom2 = oBioPolymer.getBuilder().newInstance(IAtom.class, "C2");
IAtom oAtom3 = oBioPolymer.getBuilder().newInstance(IAtom.class, "C3");
IAtom oAtom4 = oBioPolymer.getBuilder().newInstance(IAtom.class, "C4");
IAtom oAtom5 = oBioPolymer.getBuilder().newInstance(IAtom.class, "C5");
IAtom oAtom1 = oBioPolymer.getBuilder().newInstance(IAtom.class, "C");
IAtom oAtom2 = oBioPolymer.getBuilder().newInstance(IAtom.class, "C");
IAtom oAtom3 = oBioPolymer.getBuilder().newInstance(IAtom.class, "C");
IAtom oAtom4 = oBioPolymer.getBuilder().newInstance(IAtom.class, "C");
IAtom oAtom5 = oBioPolymer.getBuilder().newInstance(IAtom.class, "C");

oBioPolymer.addAtom(oAtom1);
oBioPolymer.addAtom(oAtom2, oStrand1);
Expand Down
10 changes: 5 additions & 5 deletions base/data/src/test/java/org/openscience/cdk/StrandTest.java
Expand Up @@ -64,11 +64,11 @@ public void testStrand() {
oMono2.setMonomerName(new String("HOH"));
IMonomer oMono3 = oStrand.getBuilder().newInstance(IMonomer.class);
oMono3.setMonomerName(new String("GLYA16"));
IAtom oAtom1 = oStrand.getBuilder().newInstance(IAtom.class, "C1");
IAtom oAtom2 = oStrand.getBuilder().newInstance(IAtom.class, "C2");
IAtom oAtom3 = oStrand.getBuilder().newInstance(IAtom.class, "C3");
IAtom oAtom4 = oStrand.getBuilder().newInstance(IAtom.class, "C4");
IAtom oAtom5 = oStrand.getBuilder().newInstance(IAtom.class, "C5");
IAtom oAtom1 = oStrand.getBuilder().newInstance(IAtom.class, "C");
IAtom oAtom2 = oStrand.getBuilder().newInstance(IAtom.class, "C");
IAtom oAtom3 = oStrand.getBuilder().newInstance(IAtom.class, "C");
IAtom oAtom4 = oStrand.getBuilder().newInstance(IAtom.class, "C");
IAtom oAtom5 = oStrand.getBuilder().newInstance(IAtom.class, "C");

oStrand.addAtom(oAtom1);
oStrand.addAtom(oAtom2);
Expand Down
Expand Up @@ -68,11 +68,11 @@ public void testPDBPolymer() {
oMono2.setMonomerName(new String("HOH"));
IMonomer oMono3 = pdbPolymer.getBuilder().newInstance(IMonomer.class);
oMono3.setMonomerName(new String("GLYA16"));
IPDBAtom oPDBAtom1 = pdbPolymer.getBuilder().newInstance(IPDBAtom.class, "C1");
IPDBAtom oPDBAtom2 = pdbPolymer.getBuilder().newInstance(IPDBAtom.class, "C2");
IPDBAtom oPDBAtom3 = pdbPolymer.getBuilder().newInstance(IPDBAtom.class, "C3");
IPDBAtom oPDBAtom4 = pdbPolymer.getBuilder().newInstance(IPDBAtom.class, "C4");
IPDBAtom oPDBAtom5 = pdbPolymer.getBuilder().newInstance(IPDBAtom.class, "C5");
IPDBAtom oPDBAtom1 = pdbPolymer.getBuilder().newInstance(IPDBAtom.class, "C");
IPDBAtom oPDBAtom2 = pdbPolymer.getBuilder().newInstance(IPDBAtom.class, "C");
IPDBAtom oPDBAtom3 = pdbPolymer.getBuilder().newInstance(IPDBAtom.class, "C");
IPDBAtom oPDBAtom4 = pdbPolymer.getBuilder().newInstance(IPDBAtom.class, "C");
IPDBAtom oPDBAtom5 = pdbPolymer.getBuilder().newInstance(IPDBAtom.class, "C");

pdbPolymer.addAtom(oPDBAtom1);
pdbPolymer.addAtom(oPDBAtom2, oStrand1);
Expand Down Expand Up @@ -117,8 +117,8 @@ public void testGetMonomerNamesInSequentialOrder() {
oMono1.setMonomerName("TRP279");
IMonomer oMono2 = pdbPolymer.getBuilder().newInstance(IMonomer.class);
oMono2.setMonomerName("CYS280");
IPDBAtom oPDBAtom2 = pdbPolymer.getBuilder().newInstance(IPDBAtom.class, "C2");
IPDBAtom oPDBAtom3 = pdbPolymer.getBuilder().newInstance(IPDBAtom.class, "C3");
IPDBAtom oPDBAtom2 = pdbPolymer.getBuilder().newInstance(IPDBAtom.class, "C");
IPDBAtom oPDBAtom3 = pdbPolymer.getBuilder().newInstance(IPDBAtom.class, "C");
pdbPolymer.addAtom(oPDBAtom2, oMono1, oStrand1);
pdbPolymer.addAtom(oPDBAtom3, oMono2, oStrand1);
Assert.assertNotNull(pdbPolymer.getAtom(0));
Expand Down
Expand Up @@ -1870,6 +1870,8 @@ public static IAtomContainer makeGappedCyclophaneLike() {

private static void configureAtoms(IAtomContainer mol) {
try {
for (IAtom atom : mol.atoms())
atom.setImplicitHydrogenCount(null);
Isotopes.getInstance().configureAtoms(mol);
} catch (Exception exc) {
logger.error("Could not configure molecule!");
Expand Down
Expand Up @@ -45,7 +45,7 @@ public class DebugAtom extends Atom implements IAtom {

private static final long serialVersionUID = 188945429187084868L;

ILoggingTool logger = LoggingToolFactory.createLoggingTool(DebugAtom.class);
private static final ILoggingTool logger = LoggingToolFactory.createLoggingTool(DebugAtom.class);

public DebugAtom() {
super();
Expand Down
Expand Up @@ -51,7 +51,7 @@ public class DebugFragmentAtom extends FragmentAtom {

private static final long serialVersionUID = 0L;

ILoggingTool logger = LoggingToolFactory.createLoggingTool(DebugFragmentAtom.class);
private static final ILoggingTool logger = LoggingToolFactory.createLoggingTool(DebugFragmentAtom.class);

public DebugFragmentAtom() {
super();
Expand Down
Expand Up @@ -37,7 +37,7 @@ public class DebugPDBAtom extends PDBAtom implements IPDBAtom {

private static final long serialVersionUID = -2432127382224382452L;

ILoggingTool logger = LoggingToolFactory.createLoggingTool(DebugPDBAtom.class);
private static final ILoggingTool logger = LoggingToolFactory.createLoggingTool(DebugPDBAtom.class);

public DebugPDBAtom(IElement element) {
super(element);
Expand Down
Expand Up @@ -45,7 +45,7 @@ public class DebugPseudoAtom extends PseudoAtom implements IPseudoAtom {

private static final long serialVersionUID = -5935090219383862070L;

ILoggingTool logger = LoggingToolFactory.createLoggingTool(DebugPseudoAtom.class);
private static final ILoggingTool logger = LoggingToolFactory.createLoggingTool(DebugPseudoAtom.class);

public DebugPseudoAtom() {
super();
Expand Down

0 comments on commit ddbc988

Please sign in to comment.