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

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

There is a newer version: 2024.12.1
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.Molecule;
import com.actelion.research.chem.RingCollection;
import com.actelion.research.chem.StereoMolecule;
import com.actelion.research.chem.conf.BondAngleSet;
import com.actelion.research.chem.conf.BondLengthSet;
import com.actelion.research.chem.conf.Conformer;
import com.actelion.research.chem.conf.VDWRadii;
import com.actelion.research.util.DoubleFormat;

import java.util.ArrayList;

public class DistanceRule extends ConformationRule {
	private static final double VDW_TOLERANCE = 0.85;

	private static final int PRIORITY_ONE_BOND = 10;
	private static final int PRIORITY_TWO_BONDS = 5;
	private static final int PRIORITY_THREE_BONDS = 3;

	private double[] mDistance;
	private int[] mNotList;
	private int mPriority;

	/**
	 * Creates a dummy rule to be neglected
	 */
	public DistanceRule() {
		super(null);
		}

	/**
	 * Constructor for 2 bonds in between.
	 * @param atom
	 * @param notList atoms (direct neighbors of atom[0] and atom[1]) to be excluded from movement
	 * @param distance
	 */
	public DistanceRule(int[] atom, int[] notList, double distance, int priority) {
		super(atom);
		mDistance = new double[1];
		mDistance[0] = distance;
		mNotList = notList;
		mPriority = priority;
		}

	public DistanceRule(int[] atom, double minDistance, double maxDistance, int priority) {
		super(atom);
		mDistance = new double[2];
		mDistance[0] = minDistance;
		mDistance[1] = maxDistance;
		mPriority = priority;
		}

   public DistanceRule(int[] atom, int[] notList, double minDistance, double maxDistance, int priority) {
		super(atom);
		mDistance = new double[2];
		mDistance[0] = minDistance;
		mDistance[1] = maxDistance;
		mNotList = notList;
		mPriority = priority;
		}

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

	public boolean isFixedDistance() {
		return mDistance.length == 1;
		}

	public static void calculateRules(ArrayList ruleList, StereoMolecule mol) {
		BondLengthSet bondLengthSet = new BondLengthSet(mol);
		BondAngleSet bondAngleSet = new BondAngleSet(mol, bondLengthSet);

		DistanceRule[][] rule = new DistanceRule[mol.getAllAtoms()][];
		for (int i=1; i 1
			 && mol.getAllConnAtoms(atom[1]) > 1) {

					// triple bonds
				if (mol.getBondOrder(bond) == 3) {
					double distance = bondLengthSet.getLength(bond);
					int[] outerAtom = new int[2];
					for (int i = 0; i < 2; i++) {
						for (int j = 0; j < mol.getAllConnAtoms(atom[i]); j++) {
							int connBond = mol.getConnBond(atom[i], j);
							if (connBond != bond) {
								distance += bondLengthSet.getLength(connBond);
								outerAtom[i] = mol.getConnAtom(atom[i], j);
								break;
								}
							}
						}
					int[] notAtom = new int[2];
					notAtom[0] = atom[0];
					notAtom[1] = atom[1];
					setFixedDistance(rule, combineAtoms(outerAtom[0], outerAtom[1]), notAtom, distance, PRIORITY_THREE_BONDS);
					}
				else if (mol.getBondOrder(bond) == 2
					  && mol.getAtomPi(atom[0]) == 1
					  && mol.getAtomPi(atom[1]) == 1
					  && mol.getBondParity(bond) != Molecule.cBondParityUnknown) {
					// strainless double bond with stereo information
					// (including symmetrical ones with parityNone)
					int[][] connAtom = new int[2][];
					int[][] connBond = new int[2][];
					double[][] connAngle = new double[2][];
					for (int i=0; i<2; i++) {
						connAtom[i] = new int[mol.getAllConnAtoms(atom[i])-1];
						connBond[i] = new int[mol.getAllConnAtoms(atom[i])-1];
						connAngle[i] = new double[mol.getAllConnAtoms(atom[i])-1];

						int doubleBondOpponentIndex = -1;
						for (int j=0; j connAtom[0][1-i])
								isE = !isE;
							if (connAtom[1].length == 2 && connAtom[1][j] > connAtom[1][1-j])
								isE = !isE;
							setDoubleBondDistance(connAtom[0][i], connAtom[1][j],
												  connBond[0][i], connBond[1][j],
												  connAngle[0][i], connAngle[1][j],
												  bond, isE, bondLengthSet, rule, mol);
							}
						}
					}
				else if (mol.getBondOrder(bond) != 0) {
					int[] opponentIndex = new int[2];
					for (int i = 0; i < 2; i++) {
						for (int j = 0; j < mol.getAllConnAtoms(atom[i]); j++) {
							if (mol.getConnAtom(atom[i], j) == atom[1 - i]) {
								opponentIndex[i] = j;
								break;
								}
							}
						}
					for (int i = 0; i < mol.getAllConnAtoms(atom[0]); i++) {
						if (i != opponentIndex[0]) {
							for (int j = 0; j < mol.getAllConnAtoms(atom[1]); j++) {
								if (j != opponentIndex[1]) {
									if (mol.getAtomPi(atom[0]) == 0
											&& mol.getAtomPi(atom[1]) == 0)
										setSingleBondConnAtomDistance(
												mol.getConnAtom(atom[0], i), mol.getConnAtom(atom[1], j),
												mol.getConnBond(atom[0], i), mol.getConnBond(atom[1], j),
												bondAngleSet.getConnAngle(atom[0], opponentIndex[0], i),
												bondAngleSet.getConnAngle(atom[1], opponentIndex[1], j),
												bond, bondLengthSet, rule, mol);
									else
										setAnyBondConnAtomDistance(
												mol.getConnAtom(atom[0], i), mol.getConnAtom(atom[1], j),
												mol.getConnBond(atom[0], i), mol.getConnBond(atom[1], j),
												bondAngleSet.getConnAngle(atom[0], opponentIndex[0], i),
												bondAngleSet.getConnAngle(atom[1], opponentIndex[1], j),
												bond, bondLengthSet, rule, mol);
									}
								}
							}
						}
					}
				}
			}

			// distances over 4 bonds in allenes
		for (int atom=0; atom 2) {
						distanceToRoot[candidate] = distanceToRoot[parent]
												  + bondLengthSet.getLength(mol.getConnBond(parent, i));

						if (candidate < rootAtom && rule[rootAtom][candidate] == null) {
							if (bondCount[candidate] == 3) {
								rule[rootAtom][candidate] = new DistanceRule();	// add dummy rule to block this atom combination
								}
							else {
								int[] notList = new int[2];
								notList[0] = graphAtom[1];
								notList[1] = parent;
								rule[rootAtom][candidate] = new DistanceRule(combineAtoms(rootAtom, candidate), notList,
										getVDWRadius(rootAtom, mol) + getVDWRadius(candidate, mol), distanceToRoot[candidate], 0);

								rule[rootAtom][candidate].mDistance[0] *= VDW_TOLERANCE; // in reality non binding atoms sometimes come closer...
								}
							}
						}
					}
				}
			current++;
			}
		}

	private static void calculateDisconnectedDistanceRules(DistanceRule[][] rule, StereoMolecule mol) {
		for (int atom1=1; atom1 atom2) {
			atom[0] = atom1;
			atom[1] = atom2;
			}
		else {
			atom[0] = atom2;
			atom[1] = atom1;
			}
		return atom;
		}

	private static int[] calculateBondRingSizes(StereoMolecule mol) {
		int[] bondRingSize = new int[mol.getBonds()];
		RingCollection ringSet = mol.getRingSet();
		for (int ring=0; ring ringBond.length) {
					bondRingSize[ringBond[i]] = ringBond.length;
					}
				}
			}
		return bondRingSize;
		}

	@Override
	public boolean apply(Conformer conformer, double cycleFactor) {
/*
double strainBefore = addStrain(conformer, new double[conformer.getMolecule().getAllAtoms()]);
*/
		double dx = conformer.getX(mAtom[1]) - conformer.getX(mAtom[0]);
		double dy = conformer.getY(mAtom[1]) - conformer.getY(mAtom[0]);
		double dz = conformer.getZ(mAtom[1]) - conformer.getZ(mAtom[0]);
		double distance = Math.sqrt(dx*dx+dy*dy+dz*dz);

		double distanceFactor = 0.0f;
		if (mDistance.length == 2) {	// is min and max
			if (distance < mDistance[0]) {
				distanceFactor = (distance-mDistance[0]) / distance;
				}
			else if (distance > mDistance[1]) {
				distanceFactor = (distance-mDistance[1]) / distance;
				}
			}
		else {	// exact distance
			if (distance < mDistance[0]) {
				distanceFactor = (distance-mDistance[0]) / distance;
				}
			else if (distance > mDistance[0]) {
				distanceFactor = (distance-mDistance[0]) / distance;
				}
			}

		if (Math.abs(distanceFactor) < 0.001)
			return false;

		double factor = cycleFactor * distanceFactor;

// for exclusively moving each of both involved atoms atom 50%
//moveAtom(conformer, mAtom[0], dx*factor/2f, dy*factor/2f, dz*factor/2f);
//moveAtom(conformer, mAtom[1], -dx*factor/2f, -dy*factor/2f, -dz*factor/2f);

		StereoMolecule mol = conformer.getMolecule();

		if (mPriority == PRIORITY_ONE_BOND) {
			if (mol.getAllConnAtoms(mAtom[0]) == 1
			 && mol.getAllConnAtoms(mAtom[1]) != 1) {
				conformer.getCoordinates(mAtom[0]).add(dx*factor, dy*factor, dz*factor);
//printStuff(conformer, distance);
				return true;
				}
			if (mol.getAllConnAtoms(mAtom[0]) != 1
			 && mol.getAllConnAtoms(mAtom[1]) == 1) {
				conformer.getCoordinates(mAtom[1]).add(-dx*factor, -dy*factor, -dz*factor);
//printStuff(conformer, distance);
				return true;
				}
			}

		factor /= 2f;
		moveGroup(conformer, mAtom[0], mNotList, dx*factor, dy*factor, dz*factor);
		moveGroup(conformer, mAtom[1], mNotList, -dx*factor, -dy*factor, -dz*factor);
/*
double strainAfter = addStrain(conformer, new double[conformer.getMolecule().getAllAtoms()]);
if (strainAfter > 0.0001) System.out.println("Strain before:"+strainBefore+" after:"+strainAfter+" distanceBefore:"+distance+" "+toString());
*/
//printStuff(conformer, distance);
		return true;
		}
/*
private void printStuff(Conformer conformer, double distanceBefore) {
 double dx = conformer.x[mAtom[1]] - conformer.x[mAtom[0]];
 double dy = conformer.y[mAtom[1]] - conformer.y[mAtom[0]];
 double dz = conformer.z[mAtom[1]] - conformer.z[mAtom[0]];
 double distanceAfter = Math.sqrt(dx*dx+dy*dy+dz*dz);
 System.out.println("Distance before:"+distanceBefore+" distanceAfter:"+distanceAfter+((mDistance.length==1 && Math.abs(distanceAfter-mDistance[0])>Math.abs(distanceBefore-mDistance[0]))?"!!!!!!!!!!!!!":""));	
}*/

	@Override
	public double addStrain(Conformer conformer, double[] atomStrain) {
		double distance = conformer.getCoordinates(mAtom[1]).distance(conformer.getCoordinates(mAtom[0]));
		double totalStrain = 0;
		if (mDistance.length == 2) {
			if (distance < mDistance[0]) {	// van der waals radii
				double strain = (mDistance[0] - distance) / 2.0f;
				double panalty = strain*strain;
				atomStrain[mAtom[0]] += panalty;
				atomStrain[mAtom[1]] += panalty;
				totalStrain += 2*panalty;
/*TLSSystem.out.println(toString()+" distance:"+distance+" strain:"+strain+" panalty:"+panalty);*/
				}
			else if (distance > mDistance[1]) {
				double strain = (distance - mDistance[1]) / 2.0f;
				double panalty = strain*strain;
				atomStrain[mAtom[0]] += panalty;
				atomStrain[mAtom[1]] += panalty;
				totalStrain += 2*panalty;
/*TLSSystem.out.println(toString()+" distance:"+distance+" strain:"+strain+" panalty:"+panalty);*/
				}
			}
		else {
			double strain = (distance - mDistance[0]) / 2.0f;
			if (Math.abs(strain) > 0.005f) {
				double panalty = strain*strain;
    			atomStrain[mAtom[0]] += panalty;
    			atomStrain[mAtom[1]] += panalty;
    			totalStrain += 2*panalty;
/*TLSSystem.out.println(toString()+" distance:"+distance+" strain:"+strain+" panalty:"+panalty);*/
			    }
			}
		return totalStrain;
		}

	@Override
	public String toString() {
		StringBuilder sb = new StringBuilder("distance rule:");
		super.addAtomList(sb);
		if (mDistance.length == 1)
			sb.append(" distance:"+DoubleFormat.toString(mDistance[0]));
		else
			sb.append(" min:"+DoubleFormat.toString(mDistance[0])+" max:"+DoubleFormat.toString(mDistance[1]));
		if (mNotList != null) {
			sb.append(" not:"+mNotList[0]);
			for (int i=1; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy