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

com.actelion.research.chem.reaction.mapping.ChemicalRule Maven / Gradle / Ivy

There is a newer version: 2024.11.2
Show newest version
/*
 * 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.reaction.mapping;

import com.actelion.research.chem.Molecule;
import com.actelion.research.chem.StereoMolecule;
import com.actelion.research.chem.reaction.Reaction;
import com.actelion.research.chem.reaction.ReactionEncoder;
import com.actelion.research.util.SortedList;

import java.util.Arrays;

/**
 * A ChemicalRule is basically a chemical reaction (transformation) defined by a reaction substructure
 * and a product substructure with full stoichiometry and completely mapped atoms.
 * ChemicalRules are used the following way:
* - a substructure search locates all matches of the rule's reactant structure in the to-be-mapped reactant
* - for every match the transformation of the ChemicalRule is applied to the to-be-mapped reactant
* - the modified reactant is similarity-graph-mapped with the original product and scored
* - the score of the unmodified reaction is compared to all modified reaction scores considering the ChemicalRule's score delta
* - the best scoring mapping is taken as final mapping
* In order to facilitate an efficient application of the rule to any query reactant, the ChemicalRule object * maintains an array of ChemicalRuleBond objects, which describe those bonds that need to be changed, * created, or broken in the query reactant. A */ public class ChemicalRule { private String mName,mIDCode; private float mPanalty; private StereoMolecule mReactant,mProduct; private ChemicalRuleBond[] mRuleBonds; private int[] mInvertedTHParity; private int[] mReactantAtomSymmetryConstraint; public ChemicalRule(String name, String idcode, float panalty) { mName = name; mIDCode = idcode; mPanalty = panalty; } public void initialize() { Reaction rxn = ReactionEncoder.decode(mIDCode, false); mReactant = rxn.getReactant(0); mProduct = rxn.getProduct(0); mReactant.ensureHelperArrays(Molecule.cHelperNeighbours); mProduct.ensureHelperArrays(Molecule.cHelperSymmetrySimple); // key: lower bondAtom mapNo, higher bondAtom mapNo // value: reactantAtom1, reactantAtom2, productBondOrder SortedList bondList = new SortedList<>(); int[] mapNoToReactantAtom = new int[mReactant.getAtoms()+1]; mapNoToReactantAtom[0] = -1; // to cause exceptions in case of faulty logic for (int atom=0; atom mapNoToProduct[connMapNo2]) ^ (connAtom1 > connAtom2)) inversion = !inversion; } } } return inversion; } private void addInvertedParityAtom(int atom) { mInvertedTHParity = Arrays.copyOf(mInvertedTHParity, mInvertedTHParity.length+1); mInvertedTHParity[mInvertedTHParity.length-1] = atom; } public void apply(StereoMolecule reactant, int[] match) { reactant.ensureHelperArrays(Molecule.cHelperNeighbours); for (ChemicalRuleBond ruleBond:mRuleBonds) { int reactantAtom1 = match[ruleBond.atom1]; int reactantAtom2 = match[ruleBond.atom2]; int reactantBond = reactant.getBond(reactantAtom1, reactantAtom2); if (reactantBond == -1) reactant.addBond(reactantAtom1, reactantAtom2, ruleBond.newBondType); else if (ruleBond.newBondType == ChemicalRuleBond.BOND_TYPE_DELETE) reactant.markBondForDeletion(reactantBond); else if (ruleBond.newBondType != ChemicalRuleBond.BOND_TYPE_KEEP_UNCHANGED) reactant.setBondType(reactantBond, ruleBond.newBondType); } reactant.deleteMarkedAtomsAndBonds(); if (mInvertedTHParity.length != 0) { reactant.ensureHelperArrays(Molecule.cHelperRings); for (int atom:mInvertedTHParity) { int reactantAtom = match[atom]; int reactantParity = reactant.getAtomParity(reactantAtom); reactant.setAtomParity(reactantAtom, reactantParity == Molecule.cAtomParity1 ? Molecule.cAtomParity2 : Molecule.cAtomParity1, false); reactant.setStereoBondFromAtomParity(reactantAtom); } } } public StereoMolecule getReactant() { return mReactant; } public StereoMolecule getProduct() { return mProduct; } public String getName() { return mName; } public float getPanalty() { return mPanalty; } /** * If the rule's reactant matches the real reactant multiple times, * then some of these matches may be symmetrically equivalent. To avoid building and * scoring redundant mapping graphs, these should be sorted out early. Reasons for * redundant matches may be:
* - if the rule reactant is one fragment, this may be symmetrical Cn or Dn
* - the rule reactant may contain multiple equivalent fragments, e.g. metathese
* - matching atoms in the real reactant my be symmetrical
* Otherwise, there certain causes may exist, that break these symmetries:
* - a symmetrical rule fragment must not considered symmetrical, if it doesn't react * symmetrically, i.e. if its matching rule product atoms are not equivalent anymore. * - in case of multiple symmetrical fragments in the rule's reactant (e.g. metathese), * inverted/rotated individual fragment matches cause different products, that means * that the relative match orientation of multiple symmetrical fragments breaks symmetry, * if the real matching atoms are not equivalent.
* This method calculates symmetry breaking values using these two reasons to be passed to * the reactant rule substructure searcher. */ private void calculateReactantAtomSymmetryConstraints(int[] mapNoToReactantAtom) { // break symmetries because of un-symmetrical rule products mReactantAtomSymmetryConstraint = new int[mReactant.getAtoms()]; for (int atom=0; atom 1) { int[] atomIndex = new int[fragmentCount]; for (int atom=0; atom { static final int BOND_TYPE_KEEP_UNCHANGED = -2; static final int BOND_TYPE_DELETE = -1; int atom1,atom2,mapNo1,mapNo2,newBondType; public ChemicalRuleBond(int atom1, int atom2, int mapNo1, int mapNo2, int newBondType) { if (mapNo1 < mapNo2) { this.atom1 = atom1; this.atom2 = atom2; this.mapNo1 = mapNo1; this.mapNo2 = mapNo2; } else { this.atom1 = atom2; this.atom2 = atom1; this.mapNo1 = mapNo2; this.mapNo2 = mapNo1; } this.newBondType = newBondType; } @Override public int compareTo(ChemicalRuleBond crb) { if (mapNo1< crb.mapNo1) return -1; if (mapNo1> crb.mapNo1) return 1; if (mapNo2< crb.mapNo2) return -1; if (mapNo2> crb.mapNo2) return 1; return 0; } public void setNewBondType(int newBondType) { this.newBondType = newBondType; } }




© 2015 - 2024 Weber Informatics LLC | Privacy Policy