
com.actelion.research.chem.StereoMolecule Maven / Gradle / Ivy
/*
* 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
© 2015 - 2025 Weber Informatics LLC | Privacy Policy