Skip to content
Snippets Groups Projects
Commit 2f8a82f5 authored by Andrius Merkys's avatar Andrius Merkys
Browse files

New upstream version 1.3.6

parent 46d177bc
No related branches found
No related tags found
No related merge requests found
......@@ -5,7 +5,7 @@
<parent>
<artifactId>beam</artifactId>
<groupId>uk.ac.ebi.beam</groupId>
<version>1.3.5</version>
<version>1.3.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>
......
......@@ -106,6 +106,34 @@ public enum Bond {
return UP;
}
@Override boolean directional() {
return true;
}
},
/**
* This is an internal quirk to allow the aromaticity of input to be preserved when
* we kekulize. The up/down bonds may be between aromatic atoms:
* {@code O=c1cccc\c1=C/C} Since the double bond is exo, the / \ must be aromatic.
*/
UP_AROMATIC("/", 1) {
@Override public Bond inverse() {
return DOWN_AROMATIC;
}
@Override boolean directional() {
return true;
}
},
/**
* This is an internal quirk to allow the aromaticity of input to be preserved when
* we kekulize. The up/down bonds may be between aromatic atoms:
* {@code O=c1cccc\c1=C/C} Since the double bond is exo, the / \ must be aromatic.
*/
DOWN_AROMATIC("\\", 1) {
@Override public Bond inverse() {
return UP_AROMATIC;
}
@Override boolean directional() {
return true;
}
......
......@@ -95,6 +95,20 @@ final class Localise {
int v = e.other(u);
if (v < u) {
switch (e.bond()) {
case UP:
case UP_AROMATIC:
if (aromatic.get(u) && aromatic.get(v))
e.bond(Bond.UP_AROMATIC);
else
e.bond(Bond.UP);
break;
case DOWN:
case DOWN_AROMATIC:
if (aromatic.get(u) && aromatic.get(v))
e.bond(Bond.DOWN_AROMATIC);
else
e.bond(Bond.DOWN);
break;
case SINGLE:
if (aromatic.get(u) && aromatic.get(v)) {
e.bond(Bond.SINGLE);
......
......@@ -46,26 +46,38 @@ import static java.util.Map.Entry;
*/
final class Parser {
/** Keep track of branching. */
/**
* Keep track of branching.
*/
private final IntStack stack = new IntStack(10);
/** Molecule being loaded. */
/**
* Molecule being loaded.
*/
private final Graph g;
/** Keep track of ring information. */
/**
* Keep track of ring information.
*/
private RingBond[] rings = new RingBond[10];
/** Local arrangement for ring openings. */
/**
* Local arrangement for ring openings.
*/
private Map<Integer, LocalArrangement> arrangement
= new HashMap<Integer, LocalArrangement>(5);
private Map<Integer, Configuration> configurations
= new HashMap<Integer, Configuration>(5);
/** Current bond. */
/**
* Current bond.
*/
private Bond bond = Bond.IMPLICIT;
/** Current configuration. */
/**
* Current configuration.
*/
private Configuration configuration = Configuration.UNKNOWN;
......@@ -76,16 +88,20 @@ final class Parser {
*/
private Set<Integer> start = new TreeSet<Integer>();
/** Number of open rings - all rings should be closed. */
/**
* Number of open rings - all rings should be closed.
*/
private int openRings = 0;
/** Strict parsing. */
/**
* Strict parsing.
*/
private final boolean strict;
private BitSet checkDirectionalBonds = new BitSet();
private int lastBondPos = -1;
private Map<Edge,Integer> bondStrPos = new HashMap<>();
private Map<Edge, Integer> bondStrPos = new HashMap<>();
private List<String> warnings = new ArrayList<>();
......@@ -116,7 +132,7 @@ final class Parser {
int nArom = 0;
for (Edge e : g.edges(i)) {
if (e.bond() == Bond.AROMATIC ||
e.bond() == Bond.IMPLICIT && g.atom(e.other(i)).aromatic())
e.bond() == Bond.IMPLICIT && g.atom(e.other(i)).aromatic())
nArom++;
}
if (nArom >= 2) {
......@@ -124,13 +140,13 @@ final class Parser {
g.setAtom(i, AtomImpl.AromaticSubset.Any);
else
g.setAtom(i,
new AtomImpl.BracketAtom(-1,
Element.Unknown,
atom.label(),
atom.hydrogens(),
atom.charge(),
atom.atomClass(),
true));
new AtomImpl.BracketAtom(-1,
Element.Unknown,
atom.label(),
atom.hydrogens(),
atom.charge(),
atom.atomClass(),
true));
}
}
}
......@@ -190,6 +206,7 @@ final class Parser {
// create topologies (stereo configurations)
for (Entry<Integer, Configuration> e : configurations.entrySet()) {
addTopology(e.getKey(),
e.getValue(),
Topology.toExplicit(g, e.getKey(), e.getValue()));
}
......@@ -244,8 +261,8 @@ final class Parser {
offset2 = bondStrPos.get(e);
}
String errorPos = InvalidSmilesException.display(buffer,
offset1-buffer.length(),
offset2-buffer.length());
offset1 - buffer.length(),
offset2 - buffer.length());
if (strict)
throw new InvalidSmilesException("Ignored invalid Cis/Trans specification: " + errorPos);
else
......@@ -261,8 +278,8 @@ final class Parser {
offset2 = bondStrPos.get(e);
}
String errorPos = InvalidSmilesException.display(buffer,
offset1-buffer.length(),
offset2-buffer.length());
offset1 - buffer.length(),
offset2 - buffer.length());
if (strict)
throw new InvalidSmilesException("Ignored invalid Cis/Trans specification: " + errorPos);
else
......@@ -311,22 +328,25 @@ final class Parser {
return new int[]{prevEnd1, prevEnd2};
}
/** Access the local edges in order. */
/**
* Access the local edges in order.
*/
private List<Edge> getLocalEdges(int end) {
return getEdges(arrangement.get(end), end);
}
/**
* Complicated process to get correct Allene neighbors.
*
* @param focus the focus (central cumualted atom)
* @return the carrier list
*/
public int[] getAlleneCarriers(int focus) {
int[] carriers = new int[4];
int i = 0;
int[] ends = findExtendedTetrahedralEnds(focus);
int beg = ends[0];
int end = ends[1];
int i = 0;
int[] ends = findExtendedTetrahedralEnds(focus);
int beg = ends[0];
int end = ends[1];
boolean begh = g.implHCount(beg) == 1;
boolean endh = g.implHCount(end) == 1;
List<Edge> begEdges = new ArrayList<>(getLocalEdges(beg));
......@@ -372,52 +392,56 @@ final class Parser {
* @param c explicit configuration of that vertex
* @see Topology#toExplicit(Graph, int, Configuration)
*/
private void addTopology(int u, Configuration c) throws
InvalidSmilesException {
private void addTopology(int u, Configuration input, Configuration c) throws
InvalidSmilesException {
// stereo on ring closure - use local arrangement
if (arrangement.containsKey(u)) {
int[] us = arrangement.get(u).toArray();
List<Edge> es = getLocalEdges(u);
if (c.type() == Configuration.Type.Tetrahedral)
if (c.type() == Configuration.Type.Tetrahedral) {
us = insertThImplicitRef(u, us); // XXX: temp fix
else if (c.type() == Configuration.Type.DoubleBond)
} else if (c.type() == Configuration.Type.DoubleBond) {
us = insertDbImplicitRef(u, us); // XXX: temp fix
else if (c.type() == Configuration.Type.ExtendedTetrahedral) {
} else if (c.type() == Configuration.Type.ExtendedTetrahedral) {
g.addFlags(Graph.HAS_EXT_STRO);
if ((us = getAlleneCarriers(u)) == null) {
if (strict)
throw new InvalidSmilesException("Invalid Allene stereo");
else
warnings.add("Ignored invalid Allene stereochemistry");
return;
if (strict)
throw new InvalidSmilesException("Invalid Allene stereo");
else
warnings.add("Ignored invalid Allene stereochemistry");
return;
}
} else if (input.type() == Configuration.Type.SquarePlanar) {
us = insertMultipleImplicitRefs(u, us, 4);
} else if (input.type() == Configuration.Type.TrigonalBipyramidal) {
us = insertMultipleImplicitRefs(u, us, 5);
} else if (input.type() == Configuration.Type.Octahedral) {
us = insertMultipleImplicitRefs(u, us, 6);
} else if (c.type() == Configuration.Type.SquarePlanar &&
us.length != 4) {
if (strict)
throw new InvalidSmilesException("SquarePlanar without 4 explicit neighbours");
else
warnings.add("SquarePlanar without 4 explicit neighbours");
return;
if (strict)
throw new InvalidSmilesException("SquarePlanar without 4 explicit neighbours");
else
warnings.add("SquarePlanar without 4 explicit neighbours");
return;
} else if (c.type() == Configuration.Type.TrigonalBipyramidal &&
us.length != 5) {
if (strict)
throw new InvalidSmilesException("SquarePlanar without 5 explicit neighbours");
else
warnings.add("SquarePlanar without 5 explicit neighbours");
return;
if (strict)
throw new InvalidSmilesException("TrigonalBipyramidal without 5 explicit neighbours");
else
warnings.add("SquarePlanar without 5 explicit neighbours");
return;
} else if (c.type() == Configuration.Type.Octahedral &&
us.length != 6) {
if (strict)
throw new InvalidSmilesException("SquarePlanar without 6 explicit neighbours");
else
warnings.add("SquarePlanar without 6 explicit neighbours");
return;
if (strict)
throw new InvalidSmilesException("Octahedral without 6 explicit neighbours");
else
warnings.add("SquarePlanar without 6 explicit neighbours");
return;
}
g.addTopology(Topology.create(u, us, es, c));
}
else {
} else {
int[] us = new int[g.degree(u)];
List<Edge> es = g.edges(u);
for (int i = 0; i < us.length; i++)
......@@ -425,35 +449,78 @@ final class Parser {
if (c.type() == Configuration.Type.Tetrahedral) {
us = insertThImplicitRef(u, us); // XXX: temp fix
}
else if (c.type() == Configuration.Type.DoubleBond) {
} else if (c.type() == Configuration.Type.DoubleBond) {
us = insertDbImplicitRef(u, us); // XXX: temp fix
}
else if (c.type() == Configuration.Type.ExtendedTetrahedral) {
} else if (c.type() == Configuration.Type.ExtendedTetrahedral) {
g.addFlags(Graph.HAS_EXT_STRO);
if ((us = getAlleneCarriers(u)) == null)
return;
} else if (input.type() == Configuration.Type.SquarePlanar) {
us = insertMultipleImplicitRefs(u, us, 4);
} else if (input.type() == Configuration.Type.TrigonalBipyramidal) {
us = insertMultipleImplicitRefs(u, us, 5);
} else if (input.type() == Configuration.Type.Octahedral) {
us = insertMultipleImplicitRefs(u, us, 6);
} else if (c.type() == Configuration.Type.SquarePlanar &&
us.length != 4) {
if (strict)
throw new InvalidSmilesException("SquarePlanar without 4 explicit neighbours");
else
warnings.add("SquarePlanar without 4 explicit neighbours");
return;
} else if (c.type() == Configuration.Type.TrigonalBipyramidal &&
us.length != 5) {
if (strict)
throw new InvalidSmilesException("TrigonalBipyramidal without 5 explicit neighbours");
else
warnings.add("SquarePlanar without 5 explicit neighbours");
return;
} else if (c.type() == Configuration.Type.Octahedral &&
us.length != 6) {
if (strict)
throw new InvalidSmilesException("Octahedral without 6 explicit neighbours");
else
warnings.add("SquarePlanar without 6 explicit neighbours");
return;
}
g.addTopology(Topology.create(u, us, es, c));
}
}
// XXX: temporary fix for correcting configurations
private int[] insertThImplicitRef(int u, int[] vs) throws
InvalidSmilesException {
InvalidSmilesException {
if (vs.length == 4)
return vs;
if (vs.length != 3)
throw new InvalidSmilesException("Invaid number of verticies for TH1/TH2 stereo chemistry");
throw new InvalidSmilesException("Invalid number of vertices for TH1/TH2 stereo chemistry");
if (start.contains(u))
return new int[]{u, vs[0], vs[1], vs[2]};
else
return new int[]{vs[0], u, vs[1], vs[2]};
}
private int[] insertMultipleImplicitRefs(int u, int[] vs, int n) throws
InvalidSmilesException {
if (vs.length == n)
return vs;
if (vs.length <= 1)
throw new InvalidSmilesException("Cannot have <= 1 vertices for high-order stereo chemistry");
int cnt = n - vs.length;
int srcIdx = 0;
int dstIdx = 0;
int[] padded = new int[n];
if (!start.contains(u))
padded[dstIdx++] = vs[srcIdx++];
while (cnt-- > 0)
padded[dstIdx++] = u;
while (srcIdx < vs.length)
padded[dstIdx++] = vs[srcIdx++];
return padded;
}
// XXX: temporary fix for correcting configurations
private int[] insertDbImplicitRef(int u, int[] vs) throws
InvalidSmilesException {
InvalidSmilesException {
if (vs.length == 3)
return vs;
if (vs.length != 2)
......@@ -484,8 +551,7 @@ final class Parser {
g.addEdge(e);
if (arrangement.containsKey(u))
arrangement.get(u).add(v);
}
else {
} else {
start.add(v); // start of a new run
}
}
......@@ -507,7 +573,7 @@ final class Parser {
* @throws InvalidSmilesException invalid grammar
*/
private void readSmiles(final CharBuffer buffer) throws
InvalidSmilesException {
InvalidSmilesException {
// primary dispatch
while (buffer.hasRemaining()) {
char c = buffer.get();
......@@ -733,7 +799,7 @@ final class Parser {
* specification.
*/
Atom readBracketAtom(final CharBuffer buffer) throws
InvalidSmilesException {
InvalidSmilesException {
int start = buffer.position;
boolean arbitraryLabel = false;
......@@ -770,8 +836,7 @@ final class Parser {
if (!arbitraryLabel && !buffer.getIf(']')) {
if (strict) {
throw InvalidSmilesException.invalidBracketAtom(buffer);
}
else {
} else {
arbitraryLabel = true;
}
}
......@@ -852,10 +917,10 @@ final class Parser {
private static int readCharge(int acc, final CharBuffer buffer) {
if (buffer.getIf('+'))
return buffer.nextIsDigit() ? acc + buffer.getNumber()
: readCharge(acc + 1, buffer);
: readCharge(acc + 1, buffer);
if (buffer.getIf('-'))
return buffer.nextIsDigit() ? acc - buffer.getNumber()
: readCharge(acc - 1, buffer);
: readCharge(acc - 1, buffer);
return acc;
}
......@@ -988,7 +1053,7 @@ final class Parser {
* Decide the bond to use for a ring bond. The bond symbol can be present on
* either or both bonded atoms. This method takes those bonds, chooses the
* correct one or reports an error if there is a conflict.
*
* <p>
* Equivalent SMILES:
* <blockquote><pre>
* C=1CCCCC=1
......@@ -996,9 +1061,9 @@ final class Parser {
* C1CCCCC=1
* </pre></blockquote>
*
* @param a a bond
* @param b other bond
* @param pos the position in the string of bond a
* @param a a bond
* @param b other bond
* @param pos the position in the string of bond a
* @param buffer the buffer and it's current position
* @return the bond to use for this edge
* @throws InvalidSmilesException ring bonds did not match
......@@ -1013,11 +1078,11 @@ final class Parser {
if (strict || a.inverse() != b)
throw new InvalidSmilesException("Ring closure bonds did not match, '" + a + "'!='" + b + "':" +
InvalidSmilesException.display(buffer,
pos-buffer.position,
lastBondPos-buffer.position));
pos - buffer.position,
lastBondPos - buffer.position));
warnings.add("Ignored invalid Cis/Trans on ring closure, should flip:" +
InvalidSmilesException.display(buffer, pos-buffer.position,
lastBondPos-buffer.position));
InvalidSmilesException.display(buffer, pos - buffer.position,
lastBondPos - buffer.position));
return Bond.IMPLICIT;
}
......@@ -1035,6 +1100,7 @@ final class Parser {
/**
* Access any warning messages from parsing the SMILES.
*
* @return the warnings.
*/
public Collection<? extends String> getWarnings() {
......@@ -1046,9 +1112,9 @@ final class Parser {
* specify the bond type.
*/
private static final class RingBond {
int u;
int u;
Bond bond;
int pos;
int pos;
private RingBond(int u, Bond bond, int pos) {
this.u = u;
......@@ -1070,9 +1136,11 @@ final class Parser {
private static final class LocalArrangement {
int[] vs;
int n;
int n;
/** New local arrangement. */
/**
* New local arrangement.
*/
private LocalArrangement() {
this.vs = new int[4];
}
......
......@@ -5,7 +5,7 @@
<parent>
<artifactId>beam</artifactId>
<groupId>uk.ac.ebi.beam</groupId>
<version>1.3.5</version>
<version>1.3.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>
......
......@@ -5,7 +5,7 @@
<parent>
<artifactId>beam</artifactId>
<groupId>uk.ac.ebi.beam</groupId>
<version>1.3.5</version>
<version>1.3.6</version>
</parent>
<modelVersion>4.0.0</modelVersion>
......
......@@ -246,14 +246,16 @@ final class AddDirectionalLabels
return Status.COMPLETED;
break;
case UP:
case UP_AROMATIC:
case DOWN:
case DOWN_AROMATIC:
if (explicit != null) {
if (acc.containsKey(explicit))
explicit = acc.get(explicit);
// original bonds are invalid
if ((f.bond() == Bond.UP || f.bond() == Bond.DOWN) && explicit.bond(u).inverse() != f.bond(u)) {
if ((f.bond().directional()) && explicit.bond(u).inverse() != f.bond(u)) {
return Status.INVALID;
}
......
......@@ -182,7 +182,7 @@ final class NormaliseDirectionalLabels
if (first == null)
return;
if (ordering[first.other(u)] < ordering[u]) {
if (first.bond(u) == Bond.UP)
if (first.bond(u) == Bond.UP || first.bond(u) == Bond.UP_AROMATIC)
invertExistingDirectionalLabels(g,
u,
new BitSet(),
......@@ -198,7 +198,7 @@ final class NormaliseDirectionalLabels
u);
}
else {
if (first.bond(u) == Bond.DOWN)
if (first.bond(u) == Bond.DOWN || first.bond(u) == Bond.DOWN_AROMATIC)
invertExistingDirectionalLabels(g,
u,
new BitSet(),
......@@ -220,7 +220,7 @@ final class NormaliseDirectionalLabels
final int d = g.degree(u);
for (int j = 0; j < d; ++j) {
final Edge f = g.edgeAt(u, j);
if (f.bond() == Bond.UP || f.bond() == Bond.DOWN) {
if (f.bond().directional()) {
if (first == null || ordering[f.other(u)] < ordering[first.other(u)])
first = f;
}
......
......@@ -162,6 +162,8 @@ final class RemoveUpDownBonds extends AbstractFunction<Graph,Graph> {
break;
case UP:
case DOWN:
case UP_AROMATIC:
case DOWN_AROMATIC:
edges.add(f);
break;
}
......
......@@ -63,8 +63,7 @@ final class ToTrigonalTopology extends AbstractFunction<Graph,Graph> {
// change edges (only changed added to replacement)
for (int u = 0; u < g.order(); u++) {
for (final Edge e : g.edges(u)) {
if (e.other(u) > u && e.bond() == Bond.UP || e
.bond() == Bond.DOWN) {
if (e.other(u) > u && e.bond().directional()) {
replacements.put(e,
new Edge(u, e.other(u), Bond.IMPLICIT));
}
......@@ -181,11 +180,11 @@ final class ToTrigonalTopology extends AbstractFunction<Graph,Graph> {
}
static boolean isUp(Bond b) {
return b == Bond.UP;
return b == Bond.UP || b == Bond.UP_AROMATIC;
}
static boolean isDown(Bond b) {
return b == Bond.DOWN;
return b == Bond.DOWN || b == Bond.DOWN_AROMATIC;
}
private List<Edge> doubleBondLabelledEdges(Graph g) {
......
......@@ -7,7 +7,7 @@
<description>SMILES parsing and generation library for cheminformatics</description>
<url>http://www.github.com/johnmay/beam/</url>
<packaging>pom</packaging>
<version>1.3.5</version>
<version>1.3.6</version>
<modules>
<module>core</module>
<module>func</module>
......@@ -93,8 +93,8 @@
<plugin>
<groupId>org.sonatype.plugins</groupId>
<artifactId>nexus-staging-maven-plugin</artifactId>
<version>1.6.3</version>
<extensions>false</extensions>
<version>1.6.13</version>
<extensions>true</extensions>
<configuration>
<serverId>ossrh</serverId>
<nexusUrl>https://oss.sonatype.org/</nexusUrl>
......@@ -104,7 +104,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-gpg-plugin</artifactId>
<version>1.5</version>
<version>1.6</version>
<executions>
<execution>
<id>sign-artifacts</id>
......@@ -112,13 +112,21 @@
<goals>
<goal>sign</goal>
</goals>
<configuration>
<executable>gpg</executable>
<gpgArguments>
<arg>--pinentry-mode</arg>
<arg>loopback</arg>
</gpgArguments>
<passphrase>${gpg.passphrase}</passphrase>
</configuration>
</execution>
</executions>
</plugin>
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-source-plugin</artifactId>
<version>2.2.1</version>
<version>3.2.1</version>
<executions>
<execution>
<id>attach-sources</id>
......@@ -131,7 +139,7 @@
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-javadoc-plugin</artifactId>
<version>2.9.1</version>
<version>3.3.1</version>
<executions>
<execution>
<id>attach-javadocs</id>
......
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment