org.openmolecules.chem.conf.so.TetrahedralStereoRule 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 2013-2020 Thomas Sander, openmolecules.org
*
* 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 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 HOLDER 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 org.openmolecules.chem.conf.so;
import com.actelion.research.chem.Coordinates;
import com.actelion.research.chem.Molecule;
import com.actelion.research.chem.MolfileCreator;
import com.actelion.research.chem.StereoMolecule;
import com.actelion.research.chem.conf.Conformer;
import java.util.ArrayList;
public class TetrahedralStereoRule extends ConformationRule {
private int[] mRotatableAtom,mStaticNeighbour,mRotatableNeighbour;
/**
* Expects neighbourAtom[5] as list of 3 or 4 neighbour atoms of the stereo center.
* The list must be sorted by atom index. In case of 3 neighbours neighbourAtom[3] is -1.
* neighbourAtom[4] contains the stereo center. If desired parity==cAtomParity1, then
* neighbourAtom[0] && neighbourAtom[1] have swapped positions.
* @param mol
* @param neighbourAtom
* @param neighbourBond
*/
public TetrahedralStereoRule(StereoMolecule mol, int[] neighbourAtom, int[] neighbourBond) {
super(neighbourAtom);
calculateRotatableAtoms(mol, neighbourAtom, neighbourBond);
}
public static void calculateRules(ArrayList ruleList, StereoMolecule mol) {
for (int atom=0; atom= 3) {
int parity = mol.getAtomParity(atom);
if ((parity == Molecule.cAtomParity1 || parity == Molecule.cAtomParity2)
&& !mol.isCentralAlleneAtom(atom)) {
int[] atomList = new int[5];
int[] bondList = new int[4];
for (int i=0; i atomList[index])
index++;
for (int j=i-1; j>=index; j--) {
atomList[j + 1] = atomList[j];
bondList[j + 1] = bondList[j];
}
atomList[index] = connAtom;
bondList[index] = connBond;
}
if (mol.getAllConnAtoms(atom) == 3) {
atomList[3] = -1;
bondList[3] = -1;
}
atomList[4] = atom;
if (parity == Molecule.cAtomParity1) {
int temp = atomList[1];
atomList[1] = atomList[0];
atomList[0] = temp;
temp = bondList[1];
bondList[1] = bondList[0];
bondList[0] = temp;
}
ruleList.add(new TetrahedralStereoRule(mol, atomList, bondList));
}
}
}
}
@Override
public boolean apply(Conformer conformer, double cycleFactor) {
double[] n = getPlaneVector(conformer);
// We invert if 3rd substituent is on wrong side (3 substituents)
// or if 3rd and 4th substituent are on wrong side (4 substituents)
boolean invert = (mAtom[3] == -1 && !isOnSameSide(conformer, n, mAtom[4], mAtom[2]))
|| (mAtom[3] != -1 && !isOnSameSide(conformer, n, mAtom[4], mAtom[2])
&& isOnSameSide(conformer, n, mAtom[4], mAtom[3]));
if (!invert)
return false;
Coordinates rotationAxis = calculateRotationAxis(conformer);
for (int atom:mRotatableAtom)
rotateAtom(conformer, atom, conformer.getCoordinates(mAtom[4]), rotationAxis, Math.PI);
return true;
}
@Override
public double addStrain(Conformer conformer, double[] atomStrain) {
double totalStrain = 0;
double[] n = getPlaneVector(conformer);
// We add a penalty for 3rd and 4th (if existing) substituent that is on the wrong side
int wrongCount = 0;
if (mAtom[3] == -1) {
if (!isOnSameSide(conformer, n, mAtom[4], mAtom[2]))
wrongCount++;
}
else {
if (!isOnSameSide(conformer, n, mAtom[4], mAtom[2]))
wrongCount++;
if (isOnSameSide(conformer, n, mAtom[4], mAtom[3]))
wrongCount++;
}
if (wrongCount != 0) {
for (int i=0; ia1 to normal vector
return v[0]*n[0]+v[1]*n[1]+v[2]*n[2] > 0;
}
/**
* Calculates the vector of plane (a4->a1, a4->a2)
* @param conformer
* @return
*/
private double[] getPlaneVector(Conformer conformer) {
double[][] coords = new double[2][3];
for (int i=0; i<2; i++) {
coords[i][0] = conformer.getX(mAtom[i]) - conformer.getX(mAtom[4]);
coords[i][1] = conformer.getY(mAtom[i]) - conformer.getY(mAtom[4]);
coords[i][2] = conformer.getZ(mAtom[i]) - conformer.getZ(mAtom[4]);
}
// calculate the vector of the plane (vector product of coords[0] and coords[1])
double[] v = new double[3];
v[0] = coords[0][1]*coords[1][2]-coords[0][2]*coords[1][1];
v[1] = coords[0][2]*coords[1][0]-coords[0][0]*coords[1][2];
v[2] = coords[0][0]*coords[1][1]-coords[0][1]*coords[1][0];
return v;
}
private void calculateRotatableAtoms(StereoMolecule mol, int[] neighbourAtom, int[] neighbourBond) {
int stereoCenter = neighbourAtom[4];
int neighbours = (neighbourAtom[3] == -1) ? 3 : 4;
int[] fragmentNo = new int[mol.getAllAtoms()];
boolean[] neglectBond = new boolean[mol.getAllBonds()];
for (int i=0; i=3 neighbour-bond-fragment and to proportionally rotate the closer part of it and not just one atom
int remainingNeighboursToRotate = neighbours - 2 - (rotatableAtomCount == 0 ? 0 : 1);
for (int i=0; i=mRotatableNeighbour.length) {
System.out.println("##### Out of bounds exception:"+new MolfileCreator(mol).getMolfile());
System.out.print("neighbours:"+neighbours+" ");
System.out.print("neighbourAtom:"); for (int k:neighbourAtom) System.out.print(" " + k); System.out.println();
System.out.print("neighbourBond:"); for (int k : neighbourBond) System.out.print(" " + k); System.out.println();
System.out.print("fragmentNo:"); for (int k : fragmentNo) System.out.print(" " + k); System.out.println();
System.out.print("isNeighbourFragment:"); for (boolean k : isNeighbourFragment) System.out.print(" " + k); System.out.println();
System.out.print("isRotatableAtom:"); for (boolean b : isRotatableAtom) System.out.print(" " + b); System.out.println();
}
mRotatableNeighbour[rotatableIndex++] = neighbourAtom[i];
}
else
mStaticNeighbour[staticIndex++] = neighbourAtom[i];
}
private Coordinates calculateRotationAxis(Conformer conformer) {
Coordinates axis = new Coordinates();
int[] neighbour = (mStaticNeighbour.length == 2) ? mStaticNeighbour : mRotatableNeighbour;
for (int atom:neighbour)
axis.add(conformer.getCoordinates(atom));
axis.scale(0.5);
axis.sub(conformer.getCoordinates(mAtom[4])).unit();
return axis;
}
@Override
public int getRuleType() {
return RULE_TYPE_STEREO;
}
@Override
public String toString() {
StringBuilder sb = new StringBuilder("stereo rule:");
super.addAtomList(sb);
sb.append(" rotatable:");
for (int ra:mRotatableAtom)
sb.append(ra+" ");
return sb.toString();
}
}