com.actelion.research.chem.reaction.Reactor 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 (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;
import com.actelion.research.chem.*;
import com.actelion.research.chem.coords.CoordinateInventor;
import com.actelion.research.util.IntArrayComparator;
import java.util.ArrayList;
import java.util.Arrays;
public class Reactor {
public static final int MODE_RETAIN_COORDINATES = 1;
public static final int MODE_FULLY_MAP_REACTIONS = 2;
public static final int MODE_REMOVE_DUPLICATE_PRODUCTS = 4;
public static final int MODE_ALLOW_CHARGE_CORRECTIONS = 8;
private Reaction mGenericReaction;
private SSSearcher mSSSearcher;
private StereoMolecule[] mReactant;
private int[][] mMinFreeValence; // minimum required free valence on reactant atoms
private boolean[][] mIsReactionCenter; // reaction center flags on product atoms
private boolean mRetainCoordinates,mFullyMapReactions,mUniqueProductsOnly,mAllowChargeCorrections;
private int mMaxGenericMapNo,mMaxCount,mReactantMatchCombinationCount;
private final ArrayList[] mMatchList;
private int[][][] mReactantMapNo; // Reactant mapNos of the real reactant change with every reactant substructure match
private StereoMolecule[][] mProduct;
private String[][] mIDCode;
private boolean[] mIsDuplicate;
/**
* Constructs a Reactor that is able to construct products from a generic reaction (transformation)
* and a list of real world reactants. Reactors built with this constructor will not use product
* atom coordinates from the generic products, nor will they be able to generate fully mapped reactions.
* They will produce and return all unique products or reactions.
* @param reaction generic reactions consisting of reactant substructures with optional query features
*/
public Reactor(Reaction reaction) {
this(reaction, false, false, Integer.MAX_VALUE, true);
}
/**
* Constructs a Reactor that is able to construct products from a generic reaction (transformation)
* and a list of real world reactants. Reactors built with this constructor will be able to generate
* fully mapped reactions, They will produce and return all unique products or reactions.
* @param reaction generic reactions consisting of reactant substructures with optional query features
* @param retainCoordinates if true, then atom coordinates from the generic products are taken into the real world products
*/
public Reactor(Reaction reaction, boolean retainCoordinates) {
this(reaction, (retainCoordinates ? MODE_RETAIN_COORDINATES : 0) + MODE_REMOVE_DUPLICATE_PRODUCTS, Integer.MAX_VALUE);
}
/**
* Constructs a Reactor that is able to construct products from a generic reaction (transformation)
* and a list of real world reactants. The reactor may or may not use atoms coordinates from the generic
* products, when generating clean product atom coordinates.
* @param reaction generic reactions consisting of reactant substructures with optional query features
* @param retainCoordinates if true, then atom coordinates from the generic products are taken into the real world products
* @param fullyMapReactions if true, then real world reactants and products will have valid mapping numbers after product generation
* @param maxProducts maximum number of products/reactions to be enumerated
* @param uniqueOnly whether to skip duplicate products/reactions because of starting material symmetry
*/
@Deprecated // Use: Reactor(Reaction reaction, int mode, int maxProducts)
public Reactor(Reaction reaction, boolean retainCoordinates, boolean fullyMapReactions, int maxProducts, boolean uniqueOnly) {
this(reaction, (retainCoordinates ? MODE_RETAIN_COORDINATES : 0)
+ (fullyMapReactions ? MODE_FULLY_MAP_REACTIONS : 0)
+ (uniqueOnly ? MODE_REMOVE_DUPLICATE_PRODUCTS : 0), maxProducts);
}
/**
* Constructs a Reactor that is able to build products from a generic reaction (transformation)
* and a list of real world reactants. These MODE_xxx flags can be used to finetune the Reactor's
* behaviour:
* MODE_RETAIN_COORDINATES: If set, then atom coordinates from the generic products are taken into the
* real world products as fixed atom coordinates set when creating atom coordinates for all product atoms.
* MODE_FULLY_MAP_REACTIONS: If true, then real world reactants and products will have valid mapping numbers
* after product generation. getFullyMappedReactions() can be used after each setReactant() call to get
* complete and mapped Reaction objects, one for every potential product.
* MODE_REMOVE_DUPLICATE_PRODUCTS: Whether to skip duplicate products/reactions because of starting material
* symmetry.
* MODE_ALLOW_CHARGE_CORRECTIONS: If set, then the Reactor will try to neutralize real world reactant atoms,
* if the matching generic reactant atom has no charge. E.g. this would allow carboxylate anions to represent
* a carboxylic acid in an esterification despite formally the anion oxygen has no free valence to form a new bond.
* WARNING: This may produce products with unbalanced atom charges.
* @param reaction generic reaction with reactant & product substructures with optional query features (reactant)
* @param mode 0 or any combination of MODE_xxx flags
* @param maxProducts limitation of products/reactions to be enumerated in case of heavy symmetries
*/
public Reactor(Reaction reaction, int mode, int maxProducts) {
mRetainCoordinates = (mode & MODE_RETAIN_COORDINATES) != 0;
mFullyMapReactions = (mode & MODE_FULLY_MAP_REACTIONS) != 0;
mUniqueProductsOnly = (mode & MODE_REMOVE_DUPLICATE_PRODUCTS) != 0;
mAllowChargeCorrections = (mode & MODE_ALLOW_CHARGE_CORRECTIONS) != 0;
mMaxCount = maxProducts;
mGenericReaction = reaction;
mReactant = new StereoMolecule[reaction.getReactants()];
// for sub-structure-search all generic reactants must be fragments
for (int i=0; i();
mReactantMatchCombinationCount = 0;
return false;
}
// eliminate matches where reaction would exceed an atom valence
mMatchList[no] = mSSSearcher.getMatchList();
for (int j=mMatchList[no].size()-1; j>=0; j--) {
int[] matchingAtom = mMatchList[no].get(j);
for (int k=0; k 0
&& mMinFreeValence[no][k] > mReactant[no].getFreeValence(matchingAtom[k]) - correction) {
mMatchList[no].remove(j);
break;
}
}
}
}
mReactantMatchCombinationCount = 1;
for (int i=0; i 0 && count > mMaxCount)
count = mMaxCount;
return count;
}
/**
* After instantiating the Reactor with MODE_FULLY_MAP_REACTIONS and after supplying real reactants,
* this method may be used to construct the fully mapped reaction. If one or more reactants have multiple
* matches of their generic reactants, then multiple reactions leading to isomeric products are returned.
* After calling this method, one or more new real reactants may provided with setReactant()
* before calling this method again.
* @return array with one or more reactions
*/
public Reaction[] getFullyMappedReactions() {
ensureProducts();
Reaction[] reaction = new Reaction[getProductCount()];
int count = 0;
int index = 0;
int[] matchIndex = new int[mReactant.length];
do {
if (!mIsDuplicate[index] || !mUniqueProductsOnly) {
reaction[count] = new Reaction();
for (int i=0; i[] matchList, int[] matchListIndex, int genericProductNo) {
// currently only support for first product of generic reaction
StereoMolecule genericProduct = mGenericReaction.getProduct(genericProductNo);
StereoMolecule product = new StereoMolecule();
int esrGroupCountAND = 0;
int esrGroupCountOR = 0;
ArrayList racemicAtomList = null;
for (int i=0; i();
racemicAtomList.add(newAtomNo[j]);
}
else {
if (parity == Molecule.cAtomParity1 || parity == Molecule.cAtomParity2) {
// Excluded atoms are added later to the product. Therefore, the parity needs
// to be inverted for every atom index that is between the current and the atom's new index
// Without further potential correction of final order of here excluded atoms
// this only works for substitution reactions of one atom for a new one!!!
boolean inversion = (productParityHint == Molecule.cAtomQFRxnParityInvert);
for (int l=0; l connAtom)
inversion = !inversion;
}
}
}
if (inversion)
parity = (parity == Molecule.cAtomParity1) ? Molecule.cAtomParity2 : Molecule.cAtomParity1;
product.setAtomParity(newAtomNo[j], parity, false);
}
else {
product.setAtomParity(newAtomNo[j], 0, false);
}
}
}
break;
}
}
}
}
}
// Delocalized double bonds are copied as delocalized to avoid cumulated double bonds
// when delocalized double bonds from generic product and from real reactant touch.
for (int j=0; j pseudoParityList = new ArrayList<>();
for (int i=0; i