Skip to content

Commit

Permalink
Merge pull request #328 from cdk/patch/stereoapi
Browse files Browse the repository at this point in the history
The minor issues I've spotted can be addressed later.
  • Loading branch information
egonw committed Jun 24, 2017
2 parents 3ef62c1 + 253820a commit 851842c
Show file tree
Hide file tree
Showing 20 changed files with 1,589 additions and 350 deletions.
173 changes: 173 additions & 0 deletions base/core/src/main/java/org/openscience/cdk/stereo/AbstractStereo.java
@@ -0,0 +1,173 @@
/*
* 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.IBond;
import org.openscience.cdk.interfaces.IChemObject;
import org.openscience.cdk.interfaces.IChemObjectBuilder;
import org.openscience.cdk.interfaces.IStereoElement;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

abstract class AbstractStereo<F extends IChemObject, C extends IChemObject>
implements IStereoElement<F, C> {

private int value;
private F focus;
private List<C> carriers;
private IChemObjectBuilder builder;

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))
throw new IllegalArgumentException("Unexpected number of stereo carriers! expected " + ((value >>> 12) & 0xf) + " was " + carriers.length);
for (C carrier : carriers) {
if (carrier == null)
throw new NullPointerException("A carrier was undefined!");
}
this.value = value;
this.focus = focus;
this.carriers = new ArrayList<>();
Collections.addAll(this.carriers, carriers);
}

/**
* {@inheritDoc}
*/
@Override
public F getFocus() {
return focus;
}

/**
* {@inheritDoc}
*/
@Override
public List<C> getCarriers() {
return carriers;
}

/**
* {@inheritDoc}
*/
@Override
public int getConfigClass() {
return value & CLS_MASK;
}

/**
* {@inheritDoc}
*/
@Override
public int getConfig() {
return value & CFG_MASK;
}

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

/**
* {@inheritDoc}
*/
@Override
public boolean contains(IAtom atom) {
if (focus.equals(atom) || (focus instanceof IBond && ((IBond) focus).contains(atom)))
return true;
for (C carrier : carriers) {
if (carrier.equals(atom) ||
(carrier instanceof IBond && ((IBond) carrier).contains(atom)))
return true;
}
return false;
}

/**
* {@inheritDoc}
*/
@Override
public IStereoElement<F,C> map(Map<IAtom, IAtom> atoms,
Map<IBond, IBond> bonds) {
if (atoms == null)
throw new IllegalArgumentException("Atom map should be non-null");
if (bonds == null)
throw new IllegalArgumentException("Bond map should be non-null");
Map<IChemObject,IChemObject> map = new HashMap<>(atoms.size() + bonds.size());
map.putAll(atoms);
map.putAll(bonds);
return map(map);
}

@Override
@SuppressWarnings("unchecked")
public IStereoElement<F, C> map(Map<IChemObject, IChemObject> chemobjs) {
if (chemobjs == null)
throw new NullPointerException("chemobj map was not provided!");
F newfocus = (F) chemobjs.get(focus);
if (newfocus == null)
newfocus = focus;
List<C> newcarriers = carriers;
for (int i = 0; i < newcarriers.size(); i++) {
C newcarrier = (C) chemobjs.get(newcarriers.get(i));
if (newcarrier != null) {
// make a copy if this is the first change
if (newcarriers == carriers)
newcarriers = new ArrayList<>(carriers);
newcarriers.set(i, newcarrier);
}
}
// no change, return self
if (newfocus == focus && newcarriers == carriers)
return this;
return create(newfocus, newcarriers, value);
}

protected abstract IStereoElement<F,C> create(F focus, List<C> carriers, int cfg);

/**
*{@inheritDoc}
*/
@Override
public IChemObjectBuilder getBuilder() {
if (builder == null)
throw new UnsupportedOperationException("Non-domain object!");
return this.builder;
}

protected void setBuilder(IChemObjectBuilder builder) {
this.builder = builder;
}
}
@@ -0,0 +1,70 @@
/*
* 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.IBond;
import org.openscience.cdk.interfaces.IStereoElement;

import java.util.List;

/**
* Restricted axial rotation around Aryl-Aryl bonds. The atropisomer is
* stored in a similar manner to {@link ExtendedTetrahedral} (and
* {@link TetrahedralChirality}) except instead of storing the central atom
* we store the sigma bond around which the rotation is restricted and the
* four carriers are connect to either end atom of the 'focus' bond.
* <br>
* <pre>
* a b'
* / \
* Ar --f-- Ar
* \ /
* a' b
* f: focus
* Ar: Aryl (carriers connected to either end of 'f')
* a,a',b,b': ortho substituted on the Aryl
* </pre>
* <br>
* Typical examples include <a href="https://en.wikipedia.org/wiki/BINOL">
* BiNOL</a>, and <a href="https://en.wikipedia.org/wiki/BINAP">BiNAP</a>.
*
* @see <a href="https://en.wikipedia.org/wiki/Atropisomer">Atropisomer (Wikipedia)</a>
*/
public class Atropisomeric extends AbstractStereo<IBond,IAtom> {

public Atropisomeric(IBond focus, IAtom[] carriers, int value) {
super(focus, carriers, IStereoElement.AT | value);
}

/**
* {@inheritDoc}
*/
@Override
protected IStereoElement<IBond, IAtom> create(IBond focus,
List<IAtom> carriers,
int cfg) {
return new Atropisomeric(focus, carriers.toArray(new IAtom[4]), cfg);
}
}
Expand Up @@ -26,7 +26,9 @@
import org.openscience.cdk.interfaces.IBond;
import org.openscience.cdk.interfaces.IChemObjectBuilder;
import org.openscience.cdk.interfaces.IDoubleBondStereochemistry;
import org.openscience.cdk.interfaces.IStereoElement;

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

/**
Expand All @@ -38,87 +40,53 @@
*
* @see org.openscience.cdk.interfaces.IDoubleBondStereochemistry
*/
public class DoubleBondStereochemistry implements IDoubleBondStereochemistry {

private Conformation stereo;
private IBond[] ligandBonds;
private IBond stereoBond;
private IChemObjectBuilder builder;
public class DoubleBondStereochemistry
extends AbstractStereo<IBond,IBond>
implements IDoubleBondStereochemistry {

/**
* Creates a new double bond stereo chemistry. The path of length three is defined by
* <code>ligandBonds[0]</code>, <code>stereoBonds</code>, and <code>ligandBonds[1]</code>.
*/
public DoubleBondStereochemistry(IBond stereoBond, IBond[] ligandBonds, Conformation stereo) {
if (ligandBonds.length > 2) throw new IllegalArgumentException("expected two ligand bonds");
this.stereoBond = stereoBond;
this.ligandBonds = ligandBonds;
this.stereo = stereo;
this(stereoBond, ligandBonds, Conformation.toConfig(stereo));
}

/**
* Sets a new {@link IChemObjectBuilder}.
*
* @param builder the new {@link IChemObjectBuilder} to be returned
* @see #getBuilder()
*/
public void setBuilder(IChemObjectBuilder builder) {
this.builder = builder;
public DoubleBondStereochemistry(IBond stereoBond, IBond[] ligandBonds, int config) {
super(stereoBond, ligandBonds, CT | (CFG_MASK & config));
}

/** {@inheritDoc} */
@Override
public IChemObjectBuilder getBuilder() {
return this.builder;
public void setBuilder(IChemObjectBuilder builder) {
super.setBuilder(builder);
}

/** {@inheritDoc} */
@Override
public IBond[] getBonds() {
IBond[] arrayCopy = new IBond[2];
System.arraycopy(ligandBonds, 0, arrayCopy, 0, 2);
return arrayCopy;
return getCarriers().toArray(new IBond[0]);
}

/** {@inheritDoc} */
@Override
public IBond getStereoBond() {
return this.stereoBond;
return getFocus();
}

/** {@inheritDoc} */
@Override
public Conformation getStereo() {
return this.stereo;
return Conformation.toConformation(getConfig());
}

/**
*{@inheritDoc}
*/
@Override
public boolean contains(IAtom atom) {
return stereoBond.contains(atom) || ligandBonds[0].contains(atom) || ligandBonds[1].contains(atom);
public IDoubleBondStereochemistry map(Map<IAtom, IAtom> atoms,
Map<IBond, IBond> bonds) {
return (IDoubleBondStereochemistry) super.map(atoms, bonds);
}

@Override
public IDoubleBondStereochemistry map(Map<IAtom, IAtom> atoms, Map<IBond, IBond> bonds) {

if (bonds == null) throw new IllegalArgumentException("null bond mapping provided");

// map the double bond and the connected ligand bonds
IBond doubleBond = bonds.containsKey(stereoBond) ? bonds.get(stereoBond) : stereoBond;
IBond[] connected = new IBond[ligandBonds.length];

for (int i = 0; i < connected.length; i++) {
if (ligandBonds[i] != null) {
IBond bond = bonds.get(ligandBonds[i]);
if (bond != null)
connected[i] = bond;
else
connected[i] = ligandBonds[i];
}
}

return new DoubleBondStereochemistry(doubleBond, connected, stereo);
protected IStereoElement<IBond, IBond> create(IBond focus, List<IBond> carriers,
int cfg) {
return new DoubleBondStereochemistry(focus, carriers.toArray(new IBond[2]), cfg);
}
}

0 comments on commit 851842c

Please sign in to comment.