Skip to content

Commit

Permalink
Merge pull request #387 from cdk/patch/stereoapi2
Browse files Browse the repository at this point in the history
Wonderful!
  • Loading branch information
egonw committed Nov 29, 2017
2 parents 8186fd9 + 7e38efe commit 9dec975
Show file tree
Hide file tree
Showing 20 changed files with 1,250 additions and 28 deletions.
Expand Up @@ -43,12 +43,16 @@ abstract class AbstractStereo<F extends IChemObject, C extends IChemObject>
private List<C> carriers;
private IChemObjectBuilder builder;

protected static int numCarriers(int cfg) {
return ((cfg >>> 12) & 0xf);
}

AbstractStereo(F focus, C[] carriers, int value) {
if (focus == null)
throw new NullPointerException("Focus of stereochemistry can not be null!");
if (carriers == null)
throw new NullPointerException("Carriers of the configuration can not be null!");
if (carriers.length != ((value >>> 12) & 0xf))
if (carriers.length != numCarriers(value))
throw new IllegalArgumentException("Unexpected number of stereo carriers! expected " + ((value >>> 12) & 0xf) + " was " + carriers.length);
for (C carrier : carriers) {
if (carrier == null)
Expand Down Expand Up @@ -88,15 +92,23 @@ public int getConfigClass() {
* {@inheritDoc}
*/
@Override
public int getConfig() {
public int getConfigOrder() {
return value & CFG_MASK;
}

/**
* {@inheritDoc}
*/
@Override
public void setConfig(int cfg) {
public int getConfig() {
return value;
}

/**
* {@inheritDoc}
*/
@Override
public void setConfigOrder(int cfg) {
value = getConfigClass() | cfg;
}

Expand Down Expand Up @@ -170,4 +182,15 @@ public IChemObjectBuilder getBuilder() {
protected void setBuilder(IChemObjectBuilder builder) {
this.builder = builder;
}

// labels for describing permutation
protected static final int A = 0, B = 1, C = 2, D = 3, E = 4, F = 5;

// apply the inverse of a permutation
protected static <T> T[] invapply(T[] src, int[] perm) {
T[] res = src.clone();
for (int i = 0; i < src.length; i++)
res[i] = src[perm[i]];
return res;
}
}
Expand Up @@ -75,7 +75,7 @@ public IBond getStereoBond() {
/** {@inheritDoc} */
@Override
public Conformation getStereo() {
return Conformation.toConformation(getConfig());
return Conformation.toConformation(getConfigOrder());
}

@Override
Expand Down
Expand Up @@ -27,12 +27,9 @@
import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IAtomContainer;
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IChemObjectBuilder;
import org.openscience.cdk.interfaces.IStereoElement;

import java.util.Arrays;
import java.util.List;
import java.util.Map;

import static org.openscience.cdk.interfaces.ITetrahedralChirality.Stereo;

Expand Down Expand Up @@ -128,7 +125,7 @@ public IAtom[] peripherals() {
* @return winding configuration
*/
public Stereo winding() {
return Stereo.toStereo(getConfig());
return Stereo.toStereo(getConfigOrder());
}

/**
Expand Down
319 changes: 319 additions & 0 deletions base/core/src/main/java/org/openscience/cdk/stereo/Octahedral.java

Large diffs are not rendered by default.

126 changes: 126 additions & 0 deletions base/core/src/main/java/org/openscience/cdk/stereo/SquarePlanar.java
@@ -0,0 +1,126 @@
/*
* Copyright (c) 2017 John Mayfield <jwmay@users.sf.net>
*
* Contact: cdk-devel@lists.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at
* your option) any later version. All we ask is that proper credit is given
* for our work, which includes - but is not limited to - adding the above
* copyright notice to the beginning of your source code files, and to any
* copyright notice that you may distribute with programs based on this work.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

package org.openscience.cdk.stereo;

import org.openscience.cdk.interfaces.IAtom;
import org.openscience.cdk.interfaces.IStereoElement;

import java.util.List;

/**
* Describes square planar configuration. The configuration around a square
* planar is described by 3 possible values (1:U, 2:4, or 3:Z) based on the
* ordering of the planar carries around the focus:
* <pre>{@code
* Configurations:
*
* a a a
* | | |
* d--f--b = U c--f--d = 4 b--f--c = Z
* | | |
* c b d
*
* SP1 SP2 SP3
* }</pre>
* cis-platin can be represented as any of the following:
* <pre>
* [NH3][Pt@SP1]([NH3])(Cl)Cl
* [NH3][Pt@SP3]([NH3])(Cl)Cl
* [NH3][Pt@SP2](Cl)([NH3])Cl
* [NH3][Pt@SP1](Cl)(Cl)[NH3]
* </pre>
* trans-platin can be represented as any of the following:
* <pre>
* [NH3][Pt@SP2]([NH3])(Cl)Cl
* [NH3][Pt@SP1](Cl)([NH3])Cl
* [NH3][Pt@SP1](Cl)([NH3])Cl
* [NH3][Pt@SP3](Cl)(Cl)[NH3]
* </pre>
*
* The normalize function ({@link #normalize()}) create a new
* <pre>IStereoElement</pre> where the carriers have been reorder such that the
* configuration is in a <code>U</code> shape (order=1).
*
* @see <a href="http://opensmiles.org/opensmiles.html#_square_planar_centers">
* Square Planar Centers, OpenSMILES</a>
* @see TrigonalBipyramidal
* @see Octahedral
*/
public final class SquarePlanar extends AbstractStereo<IAtom,IAtom> {

private static final int[][] PERMUTATIONS = new int[][]{
{A, B, C, D, A, D, C, B,
B, C, D, A, B, A, D, C,
C, D, A, B, C, B, A, D,
D, C, B, A, D, A, B, C}, // SP1 (U)
{A, C, B, D, A, D, B, C,
B, D, A, C, B, C, A, D,
C, A, D, B, C, B, D, A,
D, B, C, A, D, A, C, B}, // SP2 (4)
{A, B, D, C, A, C, D, B,
B, A, C, D, B, D, C, A,
C, D, B, A, C, A, B, D,
D, C, A, B, D, B, A, C} // SP3 (Z)
};

/**
* Create a square-planar configuration around a provided focus atom. The
* carriers are flat in the plane and their arrangement is either, U-shape,
* 4-shape, or Z-shape.
*
* @param focus the focus
* @param carriers the carriers
* @param order the configuration order, 1-3
*/
public SquarePlanar(IAtom focus, IAtom[] carriers, int order) {
super(focus, carriers, IStereoElement.SP | order & 0xff);
if (getConfigOrder() < 0 || getConfigOrder() > 3)
throw new IllegalArgumentException("Invalid configuration order,"
+ "should be between 1-3");
}

/**
* Normalize the configuration to the lowest configuration order (1) -
* U-shaped.
* @return the normalized configuration
*/
public SquarePlanar normalize() {
int cfg = getConfigOrder();
if (cfg == 1)
return this;
IAtom[] carriers = invapply(getCarriers().toArray(new IAtom[4]),
PERMUTATIONS[cfg-1]);
return new SquarePlanar(getFocus(),
carriers,
SPU);
}

/**
* {@inheritDoc}
*/
@Override
protected SquarePlanar create(IAtom focus, List<IAtom> carriers, int cfg) {
return new SquarePlanar(focus, carriers.toArray(new IAtom[4]), cfg);
}
}
Expand Up @@ -68,12 +68,12 @@ public IAtom getChiralAtom() {

@Override
public Stereo getStereo() {
return Stereo.toStereo(getConfig());
return Stereo.toStereo(getConfigOrder());
}

@Override
public void setStereo(Stereo stereo) {
setConfig(Stereo.toConfig(stereo));
setConfigOrder(Stereo.toConfig(stereo));
}

@Override
Expand Down
@@ -0,0 +1,134 @@
/*
* Copyright (c) 2017 John Mayfield <jwmay@users.sf.net>
*
* Contact: cdk-devel@lists.sourceforge.net
*
* This program is free software; you can redistribute it and/or modify it
* under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation; either version 2.1 of the License, or (at
* your option) any later version. All we ask is that proper credit is given
* for our work, which includes - but is not limited to - adding the above
* copyright notice to the beginning of your source code files, and to any
* copyright notice that you may distribute with programs based on this work.
*
* This program is distributed in the hope that it will be useful, but WITHOUT
* ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
* FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public
* License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program; if not, write to the Free Software
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
*/

package org.openscience.cdk.stereo;

import org.openscience.cdk.interfaces.IAtom;

import java.util.List;

/**
* Describes a trigonal-bipyramidal configuration. The configuration carriers
* are arranged with two co-linear on an axis and three equatorial. The
* configuration order is between 1 and 20 and follows the same meaning as
* SMILES.
* <pre>
* d c TB1
* \ /
* a---x---e where a: first carrier, b: second carrier, ... *
* | x: focus
* b 'c' is in front of 'x', 'd' is behind
* </pre>
*
* The configuration can be normalized to the lowest order (1) using the
* {@link #normalize()} function.
*
* @see <a href="http://opensmiles.org/opensmiles.html#_trigonal_bipyramidal_centers">
* Trigonal Bipyramidal, OpenSMILES</a>
* @see Octahedral
* @see SquarePlanar
*/
public final class TrigonalBipyramidal extends AbstractStereo<IAtom,IAtom> {

private static final int[][] PERMUTATIONS = new int[][]{
{A, B, C, D, E, A, C, D, B, E, A, D, B, C, E,
E, D, C, B, A, E, B, D, C, A, E, C, B, D, A }, // TB1 a -> e @
{A, D, C, B, E, A, C, B, D, E, A, B, D, C, E,
E, B, C, D, A, E, D, B, C, A, E, C, D, B, A }, // TB2 a -> e @@
{A, B, C, E, D, A, C, E, B, D, A, E, B, C, D,
D, E, C, B, A, D, B, E, C, A, D, C, B, E, A }, // TB3 a -> d @
{A, E, C, B, D, A, C, B, E, D, A, B, E, C, D,
D, B, C, E, A, D, E, B, C, A, D, C, E, B, A }, // TB4 a -> d @@
{A, B, D, E, C, A, D, E, B, C, A, E, B, D, C,
C, E, D, B, A, C, B, E, D, A, C, D, B, E, A }, // TB5 a -> c @
{A, E, D, B, C, A, D, B, E, C, A, B, E, D, C,
C, B, D, E, A, C, E, B, D, A, C, D, E, B, A }, // TB6 a -> c @@
{A, C, D, E, B, A, D, E, C, B, A, E, C, D, B,
B, E, D, C, A, B, C, E, D, A, B, D, C, E, A }, // TB7 a -> b @
{A, E, D, C, B, A, D, C, E, B, A, C, E, D, B,
B, C, D, E, A, B, E, C, D, A, B, D, E, C, A }, // TB8 a -> b @@
{B, A, C, D, E, B, C, D, A, E, B, D, A, C, E,
E, D, C, A, B, E, A, D, C, B, E, C, A, D, B }, // TB9 b -> e @
{B, A, C, E, D, B, C, E, A, D, B, E, A, C, D,
D, E, C, A, B, D, A, E, C, B, D, C, A, E, B }, // TB10 b -> d @
{B, D, C, A, E, B, C, A, D, E, B, A, D, C, E,
E, A, C, D, B, E, D, A, C, B, E, C, D, A, B }, // TB11 b -> e @@
{B, E, C, A, D, B, C, A, E, D, B, A, E, C, D,
D, A, C, E, B, D, E, A, C, B, D, C, E, A, B }, // TB12 b -> d @@
{B, A, D, E, C, B, D, E, A, C, B, E, A, D, C,
C, E, D, A, B, C, A, E, D, B, C, D, A, E, B }, // TB13 b -> c @
{B, E, D, A, C, B, D, A, E, C, B, A, E, D, C,
C, A, D, E, B, C, E, A, D, B, C, D, E, A, B }, // TB14 b -> c @@
{C, A, B, D, E, C, B, D, A, E, C, D, A, B, E,
E, D, B, A, C, E, A, D, B, C, E, B, A, D, C }, // TB15 c -> e @
{C, A, B, E, D, C, B, E, A, D, C, E, A, B, D,
D, E, B, A, C, D, A, E, B, C, D, B, A, E, C }, // TB16 c -> d @
{D, A, B, C, E, D, B, C, A, E, D, C, A, B, E,
E, C, B, A, D, E, A, C, B, D, E, B, A, C, D }, // TB17 d -> e @
{D, C, B, A, E, D, B, A, C, E, D, A, C, B, E,
E, A, B, C, D, E, C, A, B, D, E, B, C, A, D }, // TB18 d -> e @@
{C, E, B, A, D, C, B, A, E, D, C, A, E, B, D,
D, A, B, E, C, D, E, A, B, C, D, B, E, A, C }, // TB19 c -> d @@
{C, D, B, A, E, C, B, A, D, E, C, A, D, B, E,
E, A, B, D, C, E, D, A, B, C, E, B, D, A, C }, // TB20 c -> e @@
};

/**
* Create a new trigonal bipyramidal configuration.
* @param focus the focus
* @param carriers the carriers
* @param order the order (1-20)
*/
public TrigonalBipyramidal(IAtom focus, IAtom[] carriers, int order) {
super(focus, carriers, TrigonalBipyramidal | order & 0xff);
if (getConfigOrder() < 0 || getConfigOrder() > 20)
throw new IllegalArgumentException("Invalid configuration order,"
+ "should be between 1-20");
}

/**
* Normalize the configuration to the lowest configuration order (1) -
* the axis goes from the first to last carrier, the three middle carriers
* are anti-clockwise looking from the first carrier.
* @return the normalized configuration
*/
public TrigonalBipyramidal normalize() {
int cfg = getConfigOrder();
if (cfg == 1)
return this;
IAtom[] carriers = invapply(getCarriers().toArray(new IAtom[5]),
PERMUTATIONS[cfg-1]);
return new TrigonalBipyramidal(getFocus(),
carriers,
1);

}

/**
* {@inheritDoc}
*/
@Override
protected TrigonalBipyramidal create(IAtom focus, List<IAtom> carriers, int cfg) {
return new TrigonalBipyramidal(focus, carriers.toArray(new IAtom[5]), cfg);
}
}

0 comments on commit 9dec975

Please sign in to comment.