com.actelion.research.chem.StereoMolecule Maven / Gradle / Ivy
Go to download
Show more of this group Show more artifacts with this name
Show all versions of openchemlib Show documentation
Show all versions of openchemlib Show documentation
Open Source Chemistry Library
/*
* Copyright (c) 1997 - 2016
* Actelion Pharmaceuticals Ltd.
* Gewerbestrasse 16
* CH-4123 Allschwil, Switzerland
*
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions are met:
*
* 1. Redistributions of source code must retain the above copyright notice, this
* list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright notice,
* this list of conditions and the following disclaimer in the documentation
* and/or other materials provided with the distribution.
* 3. Neither the name of the the copyright holder nor the
* names of its contributors may be used to endorse or promote products
* derived from this software without specific prior written permission.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND
* ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
* WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
* DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES
* (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND
* ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
* (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
* SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
*
* @author Thomas Sander
*/
package com.actelion.research.chem;
import com.actelion.research.chem.coords.CoordinateInventor;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
public class StereoMolecule extends ExtendedMolecule {
static final long serialVersionUID = 0x2006CAFE;
public static final String VALIDATION_ERROR_ESR_CENTER_UNKNOWN = "Members of ESR groups must only be stereo centers with known configuration.";
public static final String VALIDATION_ERROR_OVER_UNDER_SPECIFIED = "Over- or under-specified stereo feature or more than one racemic type bond";
public static final String VALIDATION_ERROR_AMBIGUOUS_CONFIGURATION = "Ambiguous configuration at stereo center because of 2 parallel bonds";
public static final String[] VALIDATION_ERRORS_STEREO = {
VALIDATION_ERROR_ESR_CENTER_UNKNOWN,
VALIDATION_ERROR_OVER_UNDER_SPECIFIED,
VALIDATION_ERROR_AMBIGUOUS_CONFIGURATION
};
transient private Canonizer mCanonizer;
transient private boolean mAssignParitiesToNitrogen;
public StereoMolecule() {
}
public StereoMolecule(int maxAtoms, int maxBonds) {
super(maxAtoms, maxBonds);
}
public StereoMolecule(Molecule mol) {
super(mol);
}
public StereoMolecule createMolecule(int atoms, int bonds) {
return new StereoMolecule(atoms, bonds);
}
@Override
public void clear() {
super.clear();
mCanonizer = null;
}
public StereoMolecule getCompactCopy() {
StereoMolecule theCopy = new StereoMolecule(mAllAtoms, mAllBonds);
copyMolecule(theCopy);
return theCopy;
}
/**
* Copies name, isFragment, chirality. If this molecule has valid parities, but no
* atom coordinates, then the validity of parity & CIP flags is copied as well.
* When copying molecules parts only or when changing the atom order during copy,
* then atom parities or CIP parities may not be valid anymore and
* invalidateHelperArrays([affected bits]) should be called in these cases.
* @param destMol
*/
public void copyMoleculeProperties(Molecule destMol) {
super.copyMoleculeProperties(destMol);
// Super class behavior is to retain parity and CIP bits, which is correct in
// the rare case where we have valid parities and no atom coordinates.
// Then mCanonizer is null and the parities were read as part of a persistent
// molecule. In this case and parity and CIP validity needs to be copied.
// Otherwise, parity is a perceived property from up/down bonds or 3D atom coords
// and should be freshly calculated.
if (mCanonizer != null)
destMol.mValidHelperArrays = cHelperNone;
}
/**
* Separates all disconnected fragments of this Molecule into individual Molecule objects.
* If fragment separation is only needed, if there are multiple fragments, it may be more
* efficient to run this functionality in two steps, e.g.:
* int[] fragmentNo = new int[mol.getAllAtoms()];
* int fragmentCount = mol.getFragmentNumbers(fragmentNo, false, false);
* if (fragmentCount > 1) {
* StereoMolecule[] fragment = mol.getFragments(fragmentNo, fragmentCount);
* ...
* }
* @return
*/
public StereoMolecule[] getFragments() {
int[] fragmentNo = new int[mAllAtoms];
int fragments = getFragmentNumbers(fragmentNo, false, false);
return getFragments(fragmentNo, fragments);
}
/**
* Separates all disconnected fragments of this Molecule into individual molecule objects.
* The parameters fragmentNo and fragmentCount are typically obtained from a call of
* getFragmentNumbers().
* @param fragmentNo
* @param fragmentCount
* @return
*/
public StereoMolecule[] getFragments(int[] fragmentNo, int fragmentCount) {
StereoMolecule[] fragment = new StereoMolecule[fragmentCount];
int[] atoms = new int[fragmentCount];
int[] bonds = new int[fragmentCount];
int[] atomMap = new int[mAllAtoms];
for (int atom=0; atom
* Whenever the molecule connectivity changes (e.g. through methods
* like addAtom(), setAtomCharge() or deleteBond()), then the state
* of the computed 'helper' data as neighbour aroms, ring information
* or stereo information gets invalid. Therefore, after constructing or
* changing a molecule and before accessing any of the helper data
* (e.g. getConnAtoms(), isAromaticAtom(), or getAtomParity()) one must
* ensure that the required information is in a valid state by calling
* ensureHelperArrays() passing the required level of information:
* - cHelperNeighbours: neighbour atoms and bonds, pi-electrons for all atoms
* - cHelperRings: cHelperNeighbours plus rings,aromaticity/allylic/stabilized for non-H-atoms
* - cHelperParities: cHelperRings plus stereo parities for non-H-atoms/bonds
* - cHelperCIP: cHelperParities plus Cahn-Ingold-Prelog assignments for non-H-atoms/bonds
* Call ensureHelperArrays(cHelperParities) only if either parities are available anyway
* (e.g. from idcode parsing) or if coordinates with stereo bonds are available.
* Call ensureHelperArrays(cHelperCIP) only if coordinates with stereo bonds are available.
* @param required typically one of cHelperNeighbours,cHelperRings,cHelperParities,cHelperCIP
*/
public void ensureHelperArrays(int required) {
super.ensureHelperArrays(required);
if ((required & ~mValidHelperArrays) == 0)
return;
// If we have valid parities, but no atom coordinates, and if we need to run the Canonizer
// for extended stereo features, then we need to create 2D-coordinates first to not loose
// the given parities, because the Canonizer recalculates parities from coords and up/down bonds.
if ((mValidHelperArrays & cHelperParities) != 0
&& (mAllAtoms > 1) && mCoordinates[0].equals(mCoordinates[1]))
new CoordinateInventor(0).invent(this);
if (mAssignParitiesToNitrogen)
required |= cHelperBitIncludeNitrogenParities;
for (int atom=0; atom
* - up/down-bonds are converted to double bonds
* - stereo centers are flagged to be unknown
* - double bonds with implicit stereo configurations are converted into cross bonds
* - all atom and bond ESR assignments are removed
* - parity and CIP helper state is set to invalid, such that stereo calculation is redone, if needed.
*/
public void stripStereoInformation() {
ensureHelperArrays(cHelperParities);
mIsRacemate = false;
for (int atom=0; atomWARNING: If the molecule has no atom coordinates but valid parities,
* e.g. after new IDCodeParser(false).parse(idcode, null), this method returns null;
* @return
*/
public String getIDCode() {
ensureHelperArrays(cHelperParities);
if (mCanonizer == null && (getAtoms() < 2 || !mCoordinates[0].equals(mCoordinates[1])))
mCanonizer = new Canonizer(this);
return mCanonizer == null ? null : mCanonizer.getIDCode();
}
/**
* This is a convenience method that creates the molecule's id-coordinates
* matching the idcode available with getIDCode().
* It does not explicitly create a Canonizer object for this purpose.
*
WARNING: If the molecule has no atom coordinates but valid parities,
* e.g. after new IDCodeParser(false).parse(idcode, null), this method returns null;
* @return
*/
public String getIDCoordinates() {
ensureHelperArrays(cHelperParities);
if (mCanonizer == null && (getAtoms() < 2 || !mCoordinates[0].equals(mCoordinates[1])))
mCanonizer = new Canonizer(this);
return mCanonizer == null ? null : mCanonizer.getEncodedCoordinates();
}
/**
* This is a convenience method returning the StereoMolecule's Canonizer
* object after calling internally ensureHelperArrays(cHelperParities) and,
* thus, effectively running the canonicalization and validating the Canonizer itself.
*
WARNING: If the molecule has no atom coordinates but valid parities,
* e.g. after new IDCodeParser(false).parse(idcode, null), this method returns null;
* @return
*/
public Canonizer getCanonizer() {
ensureHelperArrays(cHelperParities);
return mCanonizer;
}
public int getStereoCenterCount() {
ensureHelperArrays(cHelperCIP);
int scCount = 0;
for (int atom=0; atom