com.act.biointerpretation.desalting.ChemicalDesalter.java Source code

Java tutorial

Introduction

Here is the source code for com.act.biointerpretation.desalting.ChemicalDesalter.java

Source

/*************************************************************************
*                                                                        *
*  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.desalting;

import chemaxon.license.LicenseProcessingException;
import chemaxon.reaction.ReactionException;
import com.act.biointerpretation.Utils.ReactionProjector;
import com.act.lcms.db.io.LoadPlateCompositionIntoDB;
import org.apache.commons.cli.CommandLine;
import org.apache.commons.cli.CommandLineParser;
import org.apache.commons.cli.DefaultParser;
import org.apache.commons.cli.HelpFormatter;
import org.apache.commons.cli.Option;
import org.apache.commons.cli.Options;
import org.apache.commons.cli.ParseException;
import org.apache.commons.lang3.StringUtils;
import org.apache.logging.log4j.LogManager;
import org.apache.logging.log4j.Logger;

import java.io.BufferedReader;
import java.io.BufferedWriter;
import java.io.File;
import java.io.FileReader;
import java.io.FileWriter;
import java.io.IOException;
import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;
import java.util.Map;

public class ChemicalDesalter {
    private static final Logger LOGGER = LogManager.getFormatterLogger(ChemicalDesalter.class);

    public static final String OPTION_OUTPUT_PREFIX = "o";
    public static final String OPTION_INCHI_INPUT_LIST = "i";
    public static final String HELP_MESSAGE = StringUtils.join(new String[] {
            "This class desalts a list of InChIs and outputs the results to a file.  To desalt an entire installer DB, ",
            "use BiointerpretationDriver." }, "");

    public static final List<Option.Builder> OPTION_BUILDERS = new ArrayList<Option.Builder>() {
        {
            add(Option.builder(OPTION_OUTPUT_PREFIX).argName("output prefix")
                    .desc("A prefix for the output data/pdf files").hasArg().required().longOpt("output-prefix"));
            add(Option.builder(OPTION_INCHI_INPUT_LIST).argName("inchi list file")
                    .desc("A file containing a list of InChIs to desalt").hasArg().required()
                    .longOpt("input-inchis"));
            add(Option.builder("h").argName("help").desc("Prints this help message").longOpt("help"));
        }
    };
    public static final HelpFormatter HELP_FORMATTER = new HelpFormatter();

    static {
        HELP_FORMATTER.setWidth(100);
    }

    private Desalter desalter = new Desalter(new ReactionProjector());

    public static void main(String[] args) throws Exception {
        Options opts = new Options();
        for (Option.Builder b : OPTION_BUILDERS) {
            opts.addOption(b.build());
        }

        CommandLine cl = null;
        try {
            CommandLineParser parser = new DefaultParser();
            cl = parser.parse(opts, args);
        } catch (ParseException e) {
            System.err.format("Argument parsing failed: %s\n", e.getMessage());
            HELP_FORMATTER.printHelp(LoadPlateCompositionIntoDB.class.getCanonicalName(), HELP_MESSAGE, opts, null,
                    true);
            System.exit(1);
        }

        if (cl.hasOption("help")) {
            HELP_FORMATTER.printHelp(ReactionDesalter.class.getCanonicalName(), HELP_MESSAGE, opts, null, true);
            return;
        }

        ChemicalDesalter runner = new ChemicalDesalter();
        String outAnalysis = cl.getOptionValue(OPTION_OUTPUT_PREFIX);
        if (cl.hasOption(OPTION_INCHI_INPUT_LIST)) {
            File inputFile = new File(cl.getOptionValue(OPTION_INCHI_INPUT_LIST));
            if (!inputFile.exists()) {
                System.err.format("Cannot find input file at %s\n", inputFile.getAbsolutePath());
                HELP_FORMATTER.printHelp(LoadPlateCompositionIntoDB.class.getCanonicalName(), HELP_MESSAGE, opts,
                        null, true);
                System.exit(1);
            }
            runner.exampleChemicalsList(outAnalysis, inputFile);
        }
    }

    public ChemicalDesalter() {

    }

    public void exampleChemicalsList(String outputPrefix, File inputFile)
            throws IOException, LicenseProcessingException, ReactionException {
        desalter.initReactors();
        List<String> inchis = new ArrayList<>();
        try (BufferedReader reader = new BufferedReader(new FileReader(inputFile))) {
            String line;
            // Slurp in the list of InChIs from the input file.
            while ((line = reader.readLine()) != null) {
                inchis.add(line.trim());
            }
        }
        generateAnalysisOfDesaltingSaltyChemicals(inchis, outputPrefix);
    }

    /**
     * This function bins each reaction into modified, unchanged, errors and complex files based on
     * processing them through the desalter module.
     *
     * @param salties      A list of reactions
     * @param outputPrefix The output prefix for the generated files
     */
    private void generateAnalysisOfDesaltingSaltyChemicals(List<String> salties, String outputPrefix) {
        try (BufferedWriter substrateModifiedFileWriter = new BufferedWriter(
                new FileWriter(new File(outputPrefix + "_modified.txt")));
                BufferedWriter substrateUnchangedFileWriter = new BufferedWriter(
                        new FileWriter(new File(outputPrefix + "_unchanged.txt")));
                BufferedWriter substrateErrorsFileWriter = new BufferedWriter(
                        new FileWriter(new File(outputPrefix + "_errors.txt")));
                BufferedWriter substrateComplexFileWriter = new BufferedWriter(
                        new FileWriter(new File(outputPrefix + "_complex.txt")))) {
            for (int i = 0; i < salties.size(); i++) {
                String salty = salties.get(i);
                String saltySmile = null;
                try {
                    saltySmile = desalter.InchiToSmiles(salty);
                } catch (Exception err) {
                    LOGGER.error(
                            String.format("Exception caught while desalting inchi: %s with error message: %s\n",
                                    salty, err.getMessage()));
                    substrateErrorsFileWriter.write("InchiToSmiles1\t" + salty);
                    substrateErrorsFileWriter.newLine();
                    continue;
                }

                Map<String, Integer> results = null;
                try {
                    results = desalter.desaltInchi(salty);
                } catch (Exception err) {
                    LOGGER.error(
                            String.format("Exception caught while desalting inchi: %s with error message: %s\n",
                                    salty, err.getMessage()));
                    substrateErrorsFileWriter.append("cleaned\t" + salty);
                    substrateErrorsFileWriter.newLine();
                    continue;
                }

                //Not sure results can be size zero or null, but check anyway
                if (results == null) {
                    LOGGER.error(String.format("Clean results are null for chemical: %s\n", salty));
                    substrateErrorsFileWriter.append("clean results are null:\t" + salty);
                    substrateErrorsFileWriter.newLine();
                    continue;
                }
                if (results.isEmpty()) {
                    LOGGER.error(String.format("Clean results are empty for chemical: %s\n", salty));
                    substrateErrorsFileWriter.append("clean results are empty:\t" + salty);
                    substrateErrorsFileWriter.newLine();
                    continue;
                }

                //If cleaning resulted in a single organic product
                if (results.size() == 1) {
                    String cleaned = results.keySet().iterator().next();
                    String cleanSmile = null;
                    try {
                        cleanSmile = desalter.InchiToSmiles(cleaned);
                    } catch (Exception err) {
                        LOGGER.error(
                                String.format("Exception caught while desalting inchi: %s with error message: %s\n",
                                        cleaned, err.getMessage()));
                        substrateErrorsFileWriter.append("InchiToSmiles2\t" + salty);
                        substrateErrorsFileWriter.newLine();
                    }

                    if (!salty.equals(cleaned)) {
                        String[] stringElements = { salty, cleaned, saltySmile, cleanSmile };
                        substrateModifiedFileWriter.append(StringUtils.join(Arrays.asList(stringElements), "\t"));
                        substrateModifiedFileWriter.newLine();
                    } else {
                        String[] stringElements = { salty, saltySmile };
                        substrateUnchangedFileWriter.append(StringUtils.join(Arrays.asList(stringElements), "\t"));
                        substrateUnchangedFileWriter.newLine();
                    }
                } else {
                    //Otherwise there were multiple organic products
                    substrateComplexFileWriter.append(">>\t" + salty + "\t" + saltySmile);
                    substrateComplexFileWriter.newLine();
                    for (String inchi : results.keySet()) {
                        substrateComplexFileWriter.append("\t" + inchi + "\t" + desalter.InchiToSmiles(inchi));
                        substrateComplexFileWriter.newLine();
                    }
                }
            }
        } catch (IOException exception) {
            LOGGER.error(String.format("IOException: %s", exception.getMessage()));
        }
    }
}