All Downloads are FREE. Search and download functionalities are using the official Maven repository.

org.openmolecules.chem.conf.so.TetrahedralStereoRule Maven / Gradle / Ivy

There is a newer version: 2024.11.2
Show newest version
/*
 * 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();
		}
	}




© 2015 - 2024 Weber Informatics LLC | Privacy Policy