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

com.actelion.research.chem.reaction.SRSearcher 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;

import com.actelion.research.chem.Molecule;
import com.actelion.research.chem.SSSearcher;
import com.actelion.research.chem.StereoMolecule;

import java.util.ArrayList;
import java.util.Arrays;

import static com.actelion.research.chem.SSSearcher.cCountModeRigorous;
import static com.actelion.research.chem.SSSearcher.cDefaultMatchMode;

/**
 * The SRSearcher class handles reaction-sub-structure searches. Correctly, the class
 * should be named SuperReactionSearcher, because it is rather a search for super reactions
 * for a given query reaction. The query reaction may also be called transformation and
 * may contain atom or bond based query features.
 */
public class SRSearcher {
	private StereoMolecule mQueryReactantBuffer,mQueryProductBuffer,mReactantBuffer,mProductBuffer;
	private StereoMolecule mQueryReactant,mQueryProduct,mReactant,mProduct;
	private SSSearcher mReactantSearcher,mProductSearcher;
	private boolean mQueryIsPreprocessed,mReactionIsPreprocessed;
	private int mQueryMaxMapNo,mMaxMapNo;
	private byte[] mQueryCode,mQueryCoords,mQueryMapping,mReactionCode,mReactionCoords,mReactionMapping;
	private long[] mQueryReactantFFP,mQueryProductFFP,mReactantFFP,mProductFFP;
	private int[] mQueryReactantToProductAtom,mQueryReactantToProductBond,mReactantToProductAtom,mReactantToProductBond;
	private int[] mProductMatch,mQueryNeighborDelta,mNeighborDelta;

	public SRSearcher() {
		mReactantSearcher = new SSSearcher() {
			@Override public boolean areAtomsSimilar(int moleculeAtom, int fragmentAtom) {
				return super.areAtomsSimilar(moleculeAtom, fragmentAtom) && productAtomMatches(moleculeAtom, fragmentAtom);
				}
			@Override public boolean areBondsSimilar(int moleculeBond, int fragmentBond) {
				return super.areBondsSimilar(moleculeBond, fragmentBond) && productBondMatches(moleculeBond, fragmentBond);
				}
			};
		mProductSearcher = new SSSearcher() {
			@Override public boolean areAtomsSimilar(int moleculeAtom, int fragmentAtom) {
				return (mProductMatch == null || mProductMatch[fragmentAtom] == -1 || mProductMatch[fragmentAtom] == moleculeAtom)
					&& super.areAtomsSimilar(moleculeAtom, fragmentAtom);
				}
			};
		}

	public void setQuery(byte[] rxncode, byte[] rxnmapping, byte[] rxncoords, long[] reactantFFP, long[] productFFP) {
		mQueryCode = rxncode;
		mQueryMapping = rxnmapping;
		mQueryCoords = rxncoords;
		mQueryIsPreprocessed = false;
		mQueryReactant = null;
		mQueryReactantFFP = reactantFFP;
		mQueryProduct = null;
		mQueryProductFFP = productFFP;
		}

	public void setReaction(byte[] rxncode, byte[] rxnmapping, byte[] rxncoords, long[] reactantFFP, long[] productFFP) {
		mReactionCode = rxncode;
		mReactionMapping = rxnmapping;
		mReactionCoords = rxncoords;
		mReactionIsPreprocessed = false;
		mReactant = null;
		mReactantFFP = reactantFFP;
		mProduct = null;
		mProductFFP = productFFP;
		}

	/**
	 * This defines the query reaction (or transformation).
	 * Typically, this method is called once, while setReaction() is called many times,
	 * if a reaction collection is searched for hits. For acceleration through ffp based
	 * pre-screening, you should use this method to supply query ffps.
	 * If the query reaction contains multiple reactants or multiple products,
	 * then setQuery() merges these into one reactant and one product molecule.
	 * If you call setQuery() with the same query reactions multiple times, then
	 * for a maximum of performance you should cache merged query reactions and pass these.
	 * Merging can be done by getMergedCopy() of the reaction class.
	 * @param query
	 * @param reactantFFP
	 * @param productFFP
	 */
	public void setQuery(Reaction query, long[] reactantFFP, long[] productFFP) {
		mQueryCode = null;
		mQueryReactantFFP = reactantFFP;
		mQueryProductFFP = productFFP;
		mQueryIsPreprocessed = false;
		if (query == null || query.getReactants() == 0 || query.getProducts() == 0) {
			mQueryReactant = null;
			mQueryProduct = null;
			return;
			}

		splitQuery(query);
		}

	/**
	 * This defines the query reaction (or transformation).
	 * Typically, this method is called once, while setReaction() is called many times,
	 * if a reaction collection is searched for hits. For acceleration through ffp based
	 * pre-screening, you should use this method to supply query ffps.
	 * If the query reaction contains multiple reactants or multiple products,
	 * these are merged into one molecule each.
	 * Thus, for a maximum of performance you may avoid this step by parsing a reaction
	 * that contains one reactant and one product only.
	 * @param reaction
	 * @param reactantFFP
	 * @param productFFP
	 */
	public void setReaction(Reaction reaction, long[] reactantFFP, long[] productFFP) {
		mReactionCode = null;
		mReactantFFP = reactantFFP;
		mProductFFP = productFFP;
		mReactionIsPreprocessed = false;
		if (reaction == null || reaction.getReactants() == 0 || reaction.getProducts() == 0) {
			mReactant = null;
			mProduct = null;
			return;
		}

		splitReaction(reaction);
	}

	/**
	 * This defines the query reaction (or transformation).
	 * Typically, this method is called once, while setReaction() is called many times,
	 * if a reaction collection is searched for hits.
	 * If the query reaction contains multiple reactants or multiple products,
	 * these are merged into one molecule each.
	 * Thus, for a maximum of performance you may avoid this step by parsing a reaction
	 * that contains one reactant and one product only.
	 * @param query
	 */
	public void setQuery(Reaction query) {
		mQueryCode = null;
		mQueryReactantFFP = null;
		mQueryProductFFP = null;
		mQueryIsPreprocessed = false;
		if (query == null || query.getReactants() == 0 || query.getProducts() == 0) {
			mQueryReactant = null;
			mQueryProduct = null;
			return;
			}

//		if (!query.isPerfectlyMapped())
//			return;

		splitQuery(query);
		}

	public void setReaction(Reaction reaction) {
		mReactionCode = null;
		mReactantFFP = null;
		mProductFFP = null;
		mReactionIsPreprocessed = false;
		if (reaction == null || reaction.getReactants() == 0 || reaction.getProducts() == 0) {
			mReactant = null;
			mProduct = null;
			return;
			}

		splitReaction(reaction);
		}

	public void stop() {
		mReactantSearcher.stop();
		mProductSearcher.stop();
		}

	private void preprocessQuery() {
		if (!mQueryIsPreprocessed) {
			mQueryMaxMapNo = getHighestMapNo(mQueryReactant, mQueryProduct);
			mReactantSearcher.setFragment(mQueryReactant);
			mProductSearcher.setFragment(mQueryProduct);

			if (mQueryReactant != null && mQueryProduct != null) {
				mQueryReactantToProductAtom = createReactantToProductAtomMap(mQueryReactant, mQueryProduct, mQueryMaxMapNo);
				mQueryReactantToProductBond = createReactantToProductBondMap(mQueryReactant, mQueryProduct, mQueryReactantToProductAtom);
				mQueryNeighborDelta = createMappedAtomNeighborDeltas(mQueryReactant, mQueryProduct, mQueryReactantToProductAtom);
				}

			mQueryIsPreprocessed = true;
			}
		}

	private void preprocessReaction() {
		if (!mReactionIsPreprocessed) {
			mMaxMapNo = getHighestMapNo(mReactant, mProduct);
			mReactantSearcher.setMolecule(mReactant);
			mProductSearcher.setMolecule(mProduct);

			if (mReactant != null && mProduct != null) {
				mReactantToProductAtom = createReactantToProductAtomMap(mReactant, mProduct, mMaxMapNo);
				mReactantToProductBond = createReactantToProductBondMap(mReactant, mProduct, mReactantToProductAtom);
				mNeighborDelta = createMappedAtomNeighborDeltas(mReactant, mProduct, mReactantToProductAtom);
				}

			mReactionIsPreprocessed = true;
			}
		}

	private int getHighestMapNo(StereoMolecule reactant, StereoMolecule product) {
		int maxMapNo = 0;
		for (int atom=0; atom matchList = mReactantSearcher.getMatchList();
		for (int[] match:matchList) {
			Arrays.fill(mProductMatch, -1);
			for (int i=0; i 1) {
			if (mQueryReactantBuffer == null)
				mQueryReactantBuffer = new StereoMolecule();
			mQueryReactant = mQueryReactantBuffer;

			query.getReactant(0).copyMolecule(mQueryReactant);
			for (int i=1; i 1) {
			if (mReactantBuffer == null)
				mReactantBuffer = new StereoMolecule();
			mReactant = mReactantBuffer;

			reaction.getReactant(0).copyMolecule(mReactant);
			for (int i=1; i




© 2015 - 2024 Weber Informatics LLC | Privacy Policy