/************************************************************************* * * * This file is part of the 20n/act project. * * 20n/act enables DNA prediction for synthetic biology/bioengineering. * * Copyright (C) 2017 20n Labs, Inc. * * * * Please direct all queries to act@20n.com. * * * * This program is free software: you can redistribute it and/or modify * * it under the terms of the GNU General Public License as published by * * the Free Software Foundation, either version 3 of the License, or * * (at your option) any later version. * * * * This program is distributed in the hope that it will be useful, * * but WITHOUT ANY WARRANTY; without even the implied warranty of * * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the * * GNU General Public License for more details. * * * * You should have received a copy of the GNU General Public License * * along with this program. If not, see <http://www.gnu.org/licenses/>. * * * *************************************************************************/ package com.act.biointerpretation.sars; import chemaxon.reaction.ReactionException; import chemaxon.reaction.Reactor; import chemaxon.sss.search.SearchException; import chemaxon.struc.Molecule; import chemaxon.struc.RxnMolecule; import com.act.biointerpretation.Utils.ReactionProjector; import org.apache.logging.log4j.LogManager; import org.apache.logging.log4j.Logger; import java.util.List; import java.util.stream.Collectors; public class FullReactionBuilder { private static final Logger LOGGER = LogManager.getFormatterLogger(FullReactionBuilder.class); private final McsCalculator mcsCalculator; private final ExpandedReactionSearcher searcher; private final ReactionProjector projector; public FullReactionBuilder( McsCalculator mcsCalculator, ExpandedReactionSearcher searcher, ReactionProjector projector) { this.mcsCalculator = mcsCalculator; this.searcher = searcher; this.projector = projector; } /** * Builds a Reactor that matches every reaction in the list and expands the seedReactor. To do this, we pull * out the first substrate,product pair, build possible generalizations of that reaction, and then test them against * the other reactions. If a generalization is found that matches every reaction in the list, that Reactor is * returned. * * @param rxnMolecules The reactions that the expansion must match. * @param seedReactor The seed reactor to expand. * @return The full Reactor. * @throws ReactionException If somethign goes seriously wrong, and returning just the original seed is not a severe * enough mode of failure. */ public Reactor buildReaction(List<RxnMolecule> rxnMolecules, Reactor seedReactor) throws ReactionException { if (!DbAPI.areAllOneSubstrate(rxnMolecules) || !DbAPI.areAllOneProduct(rxnMolecules)) { throw new IllegalArgumentException("FullReactionBuilder only handles one substrate, one product reactions."); } List<Molecule> allSubstrates = rxnMolecules.stream() .map(rxn -> getOnlySubstrate(rxn)).collect(Collectors.toList()); Molecule substructure = mcsCalculator.getMCS(allSubstrates); Molecule firstSubstrate = allSubstrates.get(0); Molecule expectedProduct = getOnlyProduct(rxnMolecules.get(0)); try { searcher.initSearch(seedReactor, firstSubstrate, expectedProduct, substructure); } catch (SearchException e) { LOGGER.warn("SearchException on ExpandedReactionSearcher.init(): %s", e.getMessage()); throw new ReactionException(e.getMessage()); } Reactor fullReactor; while ((fullReactor = searcher.getNextReactor()) != null) { if (checkReactorAgainstReactions(fullReactor, rxnMolecules)) { return fullReactor; } } LOGGER.warn("Didn't find an expansion that fit all reactions. Returning seed reactor only."); return seedReactor; } /** * Checks the Reactor against the Reactions represented by the RxnMolecule list. Returns true iff the * Reactor correctly predicts all reactions. * * @param fullReactor The Reactor to check. * @param reactions the ReactionMolecules. * @return True if the reactor produces the correct product on each substrate. */ public boolean checkReactorAgainstReactions(Reactor fullReactor, List<RxnMolecule> reactions) { try { for (RxnMolecule reaction : reactions) { fullReactor.setReactants(new Molecule[] {getOnlySubstrate(reaction)}); projector.reactUntilProducesProduct(fullReactor, getOnlyProduct(reaction)); } } catch (ReactionException e) { return false; } return true; } public Molecule getOnlySubstrate(RxnMolecule molecule) { return molecule.getReactants()[0]; } public Molecule getOnlyProduct(RxnMolecule molecule) { return molecule.getProducts()[0]; } }