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

com.actelion.research.chem.reaction.ReactionSearch Maven / Gradle / Ivy

There is a newer version: 2024.12.1
Show newest version
package com.actelion.research.chem.reaction;

import com.actelion.research.calc.ProgressController;
import com.actelion.research.chem.*;
import com.actelion.research.chem.descriptor.DescriptorHandlerLongFFP512;
import com.actelion.research.chem.descriptor.DescriptorHandlerReactionFP;
import com.actelion.research.util.IntArrayComparator;

import java.util.ArrayList;
import java.util.Arrays;
import java.util.TreeSet;
import java.util.concurrent.ConcurrentLinkedQueue;
import java.util.concurrent.atomic.AtomicInteger;

public class ReactionSearch {
	private static final boolean MULTITHREADED_SEARCH = true;

	private volatile ReactionSearchSpecification mSpecification;
	private volatile ReactionSearchDataSource mDataSource;
	private volatile StructureSearchController mSearchController;
	private volatile ProgressController mProgressController;
	private volatile Reaction[] mQueryReaction;
	private volatile StereoMolecule[] mQueryReactant,mQueryProduct,mQueryRetron;
	private volatile long[] mQueryHash;
	private volatile DescriptorHandlerLongFFP512 mDescriptorHandlerFFP512;
	private volatile DescriptorHandlerReactionFP mDescriptorHandlerRxnFP;
	private volatile long[][] mQueryReactionDescriptor,mQueryReactantDescriptor,mQueryProductDescriptor,mQueryRetronDescriptor;
	private volatile int mMaxSSSMatches,mMaxNonSSSMatches;
	private ConcurrentLinkedQueue mResultQueue;
	private AtomicInteger mSMPIndex,mMatchCount;

	/**
	 * This contructs a new structure search, which upon calling start()
	 * runs a multithreaded structure search on the structure rows provided by dataSource.
	 * If a searchController is given, this is asked for every row, whether the row
	 * meets all preconditions and qualifies for the search. 
	 * @param specification
	 * @param dataSource
	 * @param searchController may be null, if all rows need to be searched
	 * @param progressController may be null
	 */
	public ReactionSearch(ReactionSearchSpecification specification,
	                      ReactionSearchDataSource dataSource,
						  StructureSearchController searchController,
						  ProgressController progressController) {
		mSpecification = specification;
		mDataSource = dataSource;
		mSearchController = searchController;
		mProgressController = progressController;

		if (mSpecification != null) {
			// define needed descriptor handlers
			if (mSpecification.isSimilaritySearch()) {
				mDescriptorHandlerRxnFP = DescriptorHandlerReactionFP.getDefaultInstance();
				}
			else if (mSpecification.isSubreactionSearch()
				  || mSpecification.isRetronSearch()) {
				mDescriptorHandlerFFP512 = DescriptorHandlerLongFFP512.getDefaultInstance();
				}
			}
		}

	/**
	 * If the search shall be aborted once it exceed a given number of matches,
	 * then define the maximum number of matches with this method before starting the search.
	 * Calling start with then return the first maximum count valid matches.
	 * @param maxSSSMatches maximum number of allowed sub-reaction/retron search matches (0: no limit)
	 * @param maxNonSSSMatches maximum number of allowed matches for other search types (0: no limit)
	 */
	public void setMatchLimit(int maxSSSMatches, int maxNonSSSMatches) {
		mMaxSSSMatches = maxSSSMatches;
		mMaxNonSSSMatches = maxNonSSSMatches;
		}

	public int[] start() {
		if (!mDataSource.isSupportedSearchType(mSpecification))
			return null;

		mMatchCount = new AtomicInteger(0);

		if (!mSpecification.isNoReactionSearch()) {
			final int queryReactionCount = mSpecification.getReactionCount();
			if (queryReactionCount == 0)
				return null;

			if (mSpecification.isSubreactionSearch()
			 || mSpecification.isSimilaritySearch()) {
				mQueryReaction = new Reaction[queryReactionCount];
				mQueryReactant = new StereoMolecule[queryReactionCount];
				mQueryProduct = new StereoMolecule[queryReactionCount];
				for (int i=0; i 0) {
						String[] idcodes = mSpecification.getEncodedQuery(i).substring(0, index).split(ReactionEncoder.MOLECULE_DELIMITER_STRING);
						for (String idcode:idcodes)
							mQueryHash[i] += CanonizerUtil.StrongHasher.hash(idcode);
						}
					}
				}
			else if (mSpecification.isNoStereoSearch()) {
				mQueryHash = new long[queryReactionCount];
				for (int i=0; i 0) {
						String[] idcodes = mSpecification.getEncodedQuery(i).substring(0, index).split(ReactionEncoder.MOLECULE_DELIMITER_STRING);
						for (String idcode:idcodes)
							mQueryHash[i] += CanonizerUtil.getNoStereoHash(
								new IDCodeParser(false).getCompactMolecule(idcode), false);
						}
					}
				}
			}

    	mSMPIndex = new AtomicInteger(mDataSource.getRowCount());

    	mResultQueue = new ConcurrentLinkedQueue<>();

		if (mProgressController != null && mSpecification.getReactionCount() > 1023)
			mProgressController.startProgress("Searching structures", 0, mSpecification.getReactionCount());

		if (MULTITHREADED_SEARCH) {
			int threadCount = Runtime.getRuntime().availableProcessors();
			SearchThread[] t = new SearchThread[threadCount];
			for (int i = 0; i 1) {
	        mSMPIndex = new AtomicInteger(mQueryReactionDescriptor.length);
			int threadCount = Math.min(queryReactionCount, Runtime.getRuntime().availableProcessors());
	        Thread[] t = new Thread[threadCount];
	        for (int i=0; i 1) {	// gather all products within product[0]
			mol[0] = new StereoMolecule(mol[0]);
			for (int i=1; i= 0 && (mProgressController == null || !mProgressController.threadMustDie())) {
				if (mProgressController != null && row%1024==1023)
					mProgressController.updateProgress(mSpecification.getReactionCount()-row);

				if (mSearchController == null || mSearchController.rowQualifies(row)) {
					boolean isMatch = false;

					if (mSpecification.isSubreactionSearch()
					 || mSpecification.isRetronSearch()) {
						if (mMaxSSSMatches != 0 && mMatchCount.get() > mMaxSSSMatches)
							break;

						if (mSpecification.isSubreactionSearch()) {
							long[] reactantFFP = (long[])mDataSource.getReactantDescriptor(row);
							long[] productFFP = (long[])mDataSource.getProductDescriptor(row);
							mSRSearcher.setReaction(mDataSource.getReactionCode(row), mDataSource.getMapping(row), mDataSource.getCoordinates(row), reactantFFP, productFFP);

							for (int i = 0; i inReactantCount) {
												isMatch = true;
												break;
												}
											}
										}
									}
								}
							}
						}
					else {
						if (mMaxNonSSSMatches != 0 && mMatchCount.get() > mMaxNonSSSMatches)
							break;

						if (mSpecification.isNoReactionSearch()) {
							isMatch = true;
							}
						else if (mSpecification.isSimilaritySearch()) {
							for (int i=0; i= mSpecification.getReactionCenterSimilarity()
								 && mDescriptorHandlerRxnFP.getPeripherySimilarity(mQueryReactionDescriptor[i], mDataSource.getReactionDescriptor(row))
									>= mSpecification.getPeripherySimilarity()) {
									isMatch = true;
									break;
									}
								}
							}
						else if (mSpecification.isExactSearch()) {
							for (int i=0; i matchList) {
		int equivalentCount = 0;
		TreeSet uniqueSet = new TreeSet<>(new IntArrayComparator());
		for (int[] match:matchList) {
			int[] mappingNo = new int[match.length];
			boolean foundZero = false;
			for (int i=0; i




© 2015 - 2025 Weber Informatics LLC | Privacy Policy