/*************************************************************************
* *
* 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];
}
}