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

org.openmolecules.chem.conf.so.TorsionRule 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.StereoMolecule;
import com.actelion.research.chem.conf.Conformer;
import com.actelion.research.chem.conf.TorsionDB;
import com.actelion.research.chem.conf.TorsionDetail;
import com.actelion.research.chem.conf.TorsionPrediction;

import java.util.ArrayList;

public class TorsionRule extends ConformationRule {
	final static double COLLIDING_ATOM_STRAIN = 0.1;

	private int		    mSmallerSubstituentIndex;
	private int[]	    mAtomToRotate;
	private short[] 	mTorsion,mFrequency;
	private short[][]   mRange;

	public TorsionRule(short[] torsion, short[] frequency, short[][] range, int[] torsionAtom, int[] atomToRotate, int smallerSubstituentIndex) {
		super(torsionAtom);
		mTorsion = torsion;
		mFrequency = frequency;
		mRange = range;
		mAtomToRotate = atomToRotate;
		mSmallerSubstituentIndex = smallerSubstituentIndex;
		}

	@Override
	public int getRuleType() {
		return RULE_TYPE_TORSION;
		}

    public static void calculateRules(ArrayList ruleList, StereoMolecule mol) {
		TorsionDB.initialize(TorsionDB.MODE_ANGLES);

		boolean[] isRotatableBond = new boolean[mol.getAllBonds()];
		TorsionDB.findRotatableBonds(mol, true, isRotatableBond);
		for (int bond=0; bond 6 && mol.getAtomPi(rearAtom) == 1)
							addHeteroPiRule(mol, bondAtom, rearAtom, hCount, ruleList);
						else if (mol.getAtomPi(rearAtom) != 2 && mol.getAllConnAtoms(rearAtom) > 1)
							addDegree60Rule(mol, bondAtom, rearAtom, hCount, ruleList);
						break;
						}
					}
				}
			}
    	}

    private static void addHeteroPiRule(StereoMolecule mol, int bondAtom, int piAtom, int hCount, ArrayList ruleList) {
	    int piNeighbour = -1;
	    for (int j=0; j ruleList) {
		int[] atomToRotate = new int[hCount];
		int[] torsionAtom = new int[4];
		torsionAtom[0] = mol.getConnAtom(rearAtom, (mol.getConnAtom(rearAtom, 0) == bondAtom) ? 1 : 0);
		torsionAtom[1] = rearAtom;
		torsionAtom[2] = bondAtom;
		torsionAtom[3] = mol.getConnAtom(bondAtom, (mol.getConnAtom(bondAtom, 0) == rearAtom) ? 1 : 0);

		int hIndex = 0;
		for (int i = 0; i ruleList) {
		for (ConformationRule rule:ruleList) {
			if (rule.getRuleType() == ConformationRule.RULE_TYPE_PLANE) {
				int[] planeAtom = rule.getAtomList();
				for (int ta:torsionAtom) {
					if (ta == -1)
						return false;

					boolean found = false;
					for (int pa : planeAtom) {
						if (ta == pa) {
							found = true;
							break;
							}
						}
					if (!found)
						return false;
					}

				return true;
				}
			}
		return false;
		}

	@Override
	public boolean apply(Conformer conformer, double cycleFactor) {
	    double currentTorsion = TorsionDB.calculateTorsionExtended(conformer, mAtom);
	    if (Double.isNaN(currentTorsion))
	    	return false;

	    if (currentTorsion < 0.0)
	        currentTorsion += 2 * Math.PI;

		int index = findApplicableTorsionIndex(currentTorsion);

		double severity = getSeverity(currentTorsion, index);
		if (severity == 0.0)
			return false;

	    double angleCorrection = Math.PI * mTorsion[index] / 180.0 - currentTorsion;
	    if (Math.abs(angleCorrection) > Math.PI)
	        angleCorrection = (angleCorrection < 0) ? 2*Math.PI + angleCorrection : angleCorrection - 2*Math.PI;

	    if (Math.abs(angleCorrection) < 0.001 * Math.PI)
	    	return false;

		Coordinates unit = conformer.getCoordinates(mAtom[2]).subC(conformer.getCoordinates(mAtom[1]));
		unit.unit();

		angleCorrection *= cycleFactor * severity;

	    StereoMolecule mol = conformer.getMolecule();

	    if (mAtomToRotate != null) {	// rotate smaller side of the molecule
    	    double rotation = (mSmallerSubstituentIndex == 0) ? -angleCorrection : angleCorrection;
            for (int a:mAtomToRotate)
            	rotateAtom(conformer, a, conformer.getCoordinates(mAtom[1]), unit, rotation);
	        }
	    else {	// rotate first and second atom shell from bond atoms; reduce angle for second shell atoms and if one side is more rigid
	    	int bond = mol.getBond(mAtom[1], mAtom[2]);
	    	boolean isFiveMemberedRing = (bond != -1 && mol.getBondRingSize(bond) <= 5);
	    	for (int i=1; i<=2; i++) {
			    double factor = (i==1 ? -2.0 : 2.0) * mol.getAtomRingBondCount(mAtom[i]);
	    	    for (int j=0; j Math.PI)
				dif = 2*Math.PI - dif;
			dif /= (10+Math.sqrt(mFrequency[i]));	// normalize somewhat by frequency
			if (minDif > dif) {
				minDif = dif;
				index = i;
				}
			}
		return index;
		}

	/**
	 * Calculates a severity factor for the torsion depending on how
	 * far it is from the optimum and whether it is still in the range.
	 * @param angle from 0 to 2pi
	 * @param index of the torsion
	 * @return severity from 0 to 1
	 */
	private double getSeverity(double angle, int index) {
		double range0 = mRange[index][0] * Math.PI / 180;
		double range1 = mRange[index][1] * Math.PI / 180;
		double torsion = mTorsion[index] * Math.PI / 180;
		if (angle < torsion - Math.PI)
			angle += 2 * Math.PI;
		else if (angle > torsion + Math.PI)
			angle -= 2 * Math.PI;

		double dif = (torsion - angle) / (torsion - ((angle 180)
            dif = 360 - dif;
        if (dif > 60)
            dif = 60;

	    StereoMolecule mol = conformer.getMolecule();

		// Use 50% the rotation barrier of butane (6 kcal/mol), if 60 degrees off.
		// The major strain contribution should come from atom repulsion strains if a torsion is not optimal.
	    double strain = 3.0 * severity * dif*dif/3600;

		double totalStrain = 0;
	    for (int i=0; i maxAtomStrain)
		        	maxAtomStrain = conformer.getAtomStrain(connAtom);
		    	}
			}

System.out.println(((maxAtomStrain < COLLIDING_ATOM_STRAIN) ? "kept:" : "disabled:")+toString());

		if (maxAtomStrain < COLLIDING_ATOM_STRAIN)
			return false;

		mIsEnabled = false;
		return true;
		}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder("torsion rule:");
		super.addAtomList(sb);
        sb.append(" torsions:");
        for (int i=0; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy