/*************************************************************************
* *
* 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.formats.MolExporter;
import chemaxon.formats.MolImporter;
import chemaxon.reaction.ReactionException;
import chemaxon.reaction.Reactor;
import chemaxon.sss.SearchConstants;
import chemaxon.sss.search.MolSearchOptions;
import chemaxon.sss.search.SearchException;
import chemaxon.struc.Molecule;
import chemaxon.struc.MoleculeGraph;
import chemaxon.struc.RxnMolecule;
import com.act.biointerpretation.Utils.ReactionProjector;
import org.junit.Test;
import java.io.IOException;
import static org.junit.Assert.assertEquals;
import static org.junit.Assert.assertNotNull;
import static org.junit.Assert.assertNull;
public class ExpandedReactionSearcherTest {
private static final String ANTHRANILIC_ACID = "InChI=1S/C7H7NO2/c8-6-4-2-1-3-5(6)7(9)10/h1-4H,8H2,(H,9,10)";
private static final String AMINOBENZYL_ALCOHOL = "InChI=1S/C7H9NO/c8-7-4-2-1-3-6(7)5-9/h1-4,9H,5,8H2";
private static final String ANTHRANILIC_PRODUCT = "InChI=1S/C8H9NO2/c1-11-8(10)6-4-2-3-5-7(6)9/h2-5H,9H2,1H3";
private static final String AMINOBENZYL_PRODUCT = "InChI=1S/C7H7NO/c8-7-4-2-1-3-6(7)5-9/h1-5H,8H2";
private static final String ANTHRANILIC_SUBSTRUCTURE = "InChI=1S/C7H6O2/c8-7(9)6-4-2-1-3-5-6/h1-5H,(H,8,9)";
private static final String ANTHRANILIC_SUBSTRUCTURE_NO_OVERLAP = "InChI=1S/C6H6/c1-2-4-6-5-3-1/h1-6H";
private static final String AMINOBENZYL_SUBSTRUCTURE = "InChI=1S/C7H8O/c8-6-7-4-2-1-3-5-7/h1-5,8H,6H2";
private static final String BASIC_SEED_RULE = "[H][#8:12]-[#6:1]>>[H]C([H])([H])[#8:12]-[#6:1]";
private static final String SEED_RULE_WITH_BENZENE =
"[H][#8:7]-[#6:6]([H])-[c:5]1[c:8][c:1][c:2][c:3][c:4]1>>[O:7]=[#6:6]-[c:5]1[c:8][c:1][c:2][c:3][c:4]1";
private static final MolSearchOptions SEARCH_OPTIONS = new MolSearchOptions(SearchConstants.SUBSTRUCTURE);
static {
SEARCH_OPTIONS.setStereoModel(SearchConstants.STEREO_MODEL_LOCAL);
SEARCH_OPTIONS.setStereoSearchType(SearchConstants.STEREO_EXACT);
}
private static final String INCHI_SETTINGS = "inchi:AuxNone";
private static final ReactionProjector PROJECTOR = new ReactionProjector();
@Test
public void ExpandedReactionSearcherFiltersBadRoMatch() throws IOException, ReactionException, SearchException {
// Arrange
String ambiguousSubstrateInchi = "InChI=1S/C8H8O3/c9-5-6-1-3-7(4-2-6)8(10)11/h1-4,9H,5H2,(H,10,11)";
String expectedFulllRuleReactant = "InChI=1S/C7H6O2/c8-7(9)6-4-2-1-3-5-6/h1-5H,(H,8,9)";
String expectedFullRuleProduct = "InChI=1S/C8H8O2/c1-10-8(9)7-5-3-2-4-6-7/h2-6H,1H3";
Molecule substrate = MolImporter.importMol(ANTHRANILIC_ACID);
Molecule expectedProduct = MolImporter.importMol(ANTHRANILIC_PRODUCT);
Molecule substructure = MolImporter.importMol(ANTHRANILIC_SUBSTRUCTURE);
Molecule ambiguousSubstrate = MolImporter.importMol(ambiguousSubstrateInchi);
Reactor seedReactor = new Reactor();
seedReactor.setReactionString(BASIC_SEED_RULE);
ExpandedReactionSearcher searcher = new ExpandedReactionSearcher(PROJECTOR);
searcher.initSearch(seedReactor,
substrate,
expectedProduct,
substructure);
// Act
Reactor fullReactor = searcher.getNextReactor();
// Assert
seedReactor.setReactants(new Molecule[] {ambiguousSubstrate});
int counter = 0;
while (seedReactor.react() != null) {
counter++;
}
assertEquals("Seed reactor should produce 2 products.", 2, counter);
fullReactor.setReactants(new Molecule[] {ambiguousSubstrate});
counter = 0;
while (fullReactor.react() != null) {
counter++;
}
assertEquals("Full reactor should produce only 1 product.", 1, counter);
RxnMolecule rxnMolecule = fullReactor.getReaction();
String reactant = MolExporter.exportToFormat(rxnMolecule.getComponent(RxnMolecule.REACTANTS, 0), INCHI_SETTINGS);
String product = MolExporter.exportToFormat(rxnMolecule.getComponent(RxnMolecule.PRODUCTS, 0), INCHI_SETTINGS);
assertEquals("Reactant of reactor should be as expected.", reactant, expectedFulllRuleReactant);
assertEquals("Product of reactor should be as expected.", product, expectedFullRuleProduct);
}
@Test
public void ExpandedReactionSearcherDisjointRegionsReturnsNull() throws IOException, ReactionException, SearchException {
// Arrange
Molecule substrate = MolImporter.importMol(ANTHRANILIC_ACID);
Molecule expectedProduct = MolImporter.importMol(ANTHRANILIC_PRODUCT);
Molecule substructure = MolImporter.importMol(ANTHRANILIC_SUBSTRUCTURE_NO_OVERLAP);
Reactor seedReactor = new Reactor();
seedReactor.setReactionString(BASIC_SEED_RULE);
ExpandedReactionSearcher searcher = new ExpandedReactionSearcher(PROJECTOR);
searcher.initSearch(seedReactor,
substrate,
expectedProduct,
substructure);
// Act
Reactor fullReactor = searcher.getNextReactor();
// Assert
assertNull("Reactor should be null.", fullReactor);
}
@Test
public void ExpandedReactionSearcherPrimaryOnPrimaryWorks() throws IOException, ReactionException, SearchException {
// Arrange
Molecule primarySubstrate = MolImporter.importMol(AMINOBENZYL_ALCOHOL);
Molecule expectedProduct = MolImporter.importMol(AMINOBENZYL_PRODUCT);
Molecule substructure = MolImporter.importMol(AMINOBENZYL_SUBSTRUCTURE);
Reactor seedReactor = new Reactor();
seedReactor.setReactionString(SEED_RULE_WITH_BENZENE);
ExpandedReactionSearcher searcher = new ExpandedReactionSearcher(PROJECTOR);
searcher.initSearch(seedReactor,
primarySubstrate,
expectedProduct,
substructure);
// Act
Reactor fullReactor = searcher.getNextReactor();
// Assert
primarySubstrate = MolImporter.importMol(AMINOBENZYL_ALCOHOL);
fullReactor.setReactants(new Molecule[] {primarySubstrate});
int counter = 0;
Molecule[] products;
Molecule predictedProduct = null;
while ((products = fullReactor.react()) != null) {
predictedProduct = products[0];
assertEquals("Reactor should produce 1 product.", 1, products.length);
assertEquals("Product should be as expected.", AMINOBENZYL_PRODUCT, MolExporter.exportToFormat(predictedProduct, INCHI_SETTINGS));
counter++;
}
assertEquals("Full reactor should produce 1 product set.", 1, counter);
}
@Test
public void ExpandedReactionSearcherPrimaryOnSecondaryNoProduct() throws IOException, ReactionException, SearchException {
// Arrange
Molecule secondarySubstrate = MolImporter.importMol(ANTHRANILIC_ACID);
Molecule primarySubstrate = MolImporter.importMol(AMINOBENZYL_ALCOHOL);
Molecule expectedProduct = MolImporter.importMol(AMINOBENZYL_PRODUCT);
Molecule substructure = MolImporter.importMol(AMINOBENZYL_SUBSTRUCTURE);
Reactor seedReactor = new Reactor();
seedReactor.setReactionString(SEED_RULE_WITH_BENZENE);
ExpandedReactionSearcher searcher = new ExpandedReactionSearcher(PROJECTOR);
searcher.initSearch(seedReactor,
primarySubstrate,
expectedProduct,
substructure);
// Act
Reactor fullReactor = searcher.getNextReactor();
// Assert
fullReactor.setReactants(new Molecule[] {secondarySubstrate});
int counter = 0;
while (fullReactor.react() != null) {
counter++;
}
assertEquals("Full reactor should produce no product set.", 0, counter);
}
@Test
public void ExpandedReactionSearcherStereoMatching() throws IOException, ReactionException, SearchException {
// Arrange
String substrateInchi = "InChI=1S/C29H48O/c1-7-21(19(2)3)9-8-20(4)25-12-13-26-24-11-10-22-18-23(30)14-16-28(22,5)" +
"27(24)15-17-29(25,26)6/h8-10,19-21,23-27,30H,7,11-18H2,1-6H3/b9-8+/t20-,21-,23+,24+,25-,26+,27+,28+,29-/m1/s1";
String productInchi = "InChI=1S/C29H46O/c1-7-21(19(2)3)9-8-20(4)25-12-13-26-24-11-10-22-18-23(30)14-16-28(22,5)27" +
"(24)15-17-29(25,26)6/h8-10,19-21,24-27H,7,11-18H2,1-6H3/t20-,21-,24+,25-,26+,27+,28+,29-/m1/s1";
String substructureInchi = "InChI=1S/C29H50O/c1-7-21(19(2)3)9-8-20(4)25-12-13-26-24-11-10-22-18-23(30)14-16-28(22" +
",5)27(24)15-17-29(25,26)6/h10,19-21,23-27,30H,7-9,11-18H2,1-6H3/t20-,21-,23+,24+,25-,26+,27+,28+,29-/m1/s1";
String roString = "[H:1][#8:4]-[#6:3]([H:5])-[#6:2]>>[#6:2]-[#6:3]=[O:4]";
Molecule substrate = MolImporter.importMol(substrateInchi);
Molecule expectedProduct = MolImporter.importMol(productInchi);
Molecule substructure = MolImporter.importMol(substructureInchi);
substructure.aromatize(MoleculeGraph.AROM_LOOSE);
substrate.aromatize(MoleculeGraph.AROM_LOOSE);
Reactor seedReactor = new Reactor();
seedReactor.setReactionString(roString);
ExpandedReactionSearcher searcher = new ExpandedReactionSearcher(PROJECTOR);
searcher.initSearch(seedReactor,
substrate,
expectedProduct,
substructure);
// Act
Reactor fullReactor = searcher.getNextReactor();
assertNotNull("There should be at least one expanded reaction result.", fullReactor);
}
}