From 09c23a938d68bd3993f88cc0a5ff31bb917e4948 Mon Sep 17 00:00:00 2001
From: cfrainay <clement.frainay@inrae.fr>
Date: Thu, 28 Jul 2022 16:44:43 +0200
Subject: [PATCH 1/3] Add app to turn SBML into lists of entities

---
 .../attributes/DecomposeSBML.java             | 134 ++++++++++++++++++
 1 file changed, 134 insertions(+)
 create mode 100644 met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/DecomposeSBML.java

diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/DecomposeSBML.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/DecomposeSBML.java
new file mode 100644
index 000000000..c483a3f9d
--- /dev/null
+++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/DecomposeSBML.java
@@ -0,0 +1,134 @@
+package fr.inrae.toulouse.metexplore.met4j_toolbox.attributes;
+
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.*;
+import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.JsbmlReader;
+import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.Met4jSbmlReaderException;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.AbstractMet4jApplication;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumFormats;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumParameterTypes;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.Format;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.ParameterType;
+import org.kohsuke.args4j.Option;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+public class DecomposeSBML extends AbstractMet4jApplication {
+
+
+    @ParameterType(name= EnumParameterTypes.InputFile)
+    @Format(name= EnumFormats.Sbml)
+    @Option(name = "-i", usage = "Input SBML file", required = true)
+    public String sbml;
+
+    @ParameterType(name= EnumParameterTypes.Boolean)
+    @Option(name = "-m", aliases = {"--metabolites"}, usage = "Extract Metabolites", required = false)
+    public Boolean printMetabolites = false;
+    @ParameterType(name= EnumParameterTypes.Boolean)
+    @Option(name = "-r", aliases = {"--reactions"}, usage = "Extract Reactions", required = false)
+    public Boolean printReactions = false;
+    @ParameterType(name= EnumParameterTypes.Boolean)
+    @Option(name = "-c", aliases = {"--compartments"}, usage = "Extract Compartments", required = false)
+    public Boolean printCompartments = false;
+    @ParameterType(name= EnumParameterTypes.Boolean)
+    @Option(name = "-p", aliases = {"--pathways"}, usage = "Extract Pathways", required = false)
+    public Boolean printPathways = false;
+    @ParameterType(name= EnumParameterTypes.Boolean)
+    @Option(name = "-g", aliases = {"--genes"}, usage = "Extract Genes", required = false)
+    public Boolean printGenes = false;
+
+    @ParameterType(name= EnumParameterTypes.Boolean)
+    @Option(name = "-nt", aliases = {"--noTypeCol"}, usage = "Do not output type column", required = false)
+    public Boolean noTypeCol = false;
+
+    @ParameterType(name= EnumParameterTypes.OutputFile)
+    @Format(name= EnumFormats.Tsv)
+    @Option(name = "-o", usage = "Output file", required=true)
+    public String outputFile;
+
+    /**
+     * <p>main.</p>
+     *
+     * @param args an array of {@link java.lang.String} objects.
+     */
+    public static void main(String[] args) {
+        DecomposeSBML app = new DecomposeSBML();
+        app.parseArguments(args);
+        app.run();
+    }
+
+    /**
+     * <p>run.</p>
+     */
+    public void run() {
+
+        String fileIn = this.sbml;
+        JsbmlReader reader = new JsbmlReader(fileIn);
+        BioNetwork network = null;
+        try {
+            network = reader.read();
+        } catch (Met4jSbmlReaderException e) {
+            System.err.println("Error while reading the SBML file");
+            System.err.println(e.getMessage());
+            System.exit(1);
+        }
+
+        //default case: everything printed
+        if(!(printMetabolites|printReactions|printPathways|printGenes|printCompartments)){
+            printMetabolites=printReactions=printPathways=printGenes=printCompartments=true;
+        }
+
+        try (PrintWriter writer = new PrintWriter(new FileWriter(this.outputFile, false))) {
+
+            if(!noTypeCol) writer.println("ID\tEntity.Type");
+            if(printMetabolites){
+                for (BioMetabolite metabolite : network.getMetabolitesView()) {
+                    writer.println(noTypeCol ? metabolite.getId() : metabolite.getId() + "\tMETABOLITE");
+                }
+            }
+            if(printReactions){
+                for (BioReaction reaction : network.getReactionsView()) {
+                    writer.println(noTypeCol ? reaction.getId() : reaction.getId() + "\tREACTION");
+                }
+            }
+            if(printGenes){
+                for (BioGene gene : network.getGenesView()) {
+                    writer.println(noTypeCol ? gene.getId() : gene.getId() + "\tGENE");
+                }
+            }
+            if(printPathways){
+                for (BioPathway pathway : network.getPathwaysView()) {
+                    writer.println(noTypeCol ? pathway.getId() : pathway.getId() + "\tPATHWAY");
+                }
+            }
+            if(printCompartments){
+                for (BioCompartment compartment : network.getCompartmentsView()) {
+                    writer.println(noTypeCol ? compartment.getId() : compartment.getId() + "\tCOMPARTMENT");
+                }
+            }
+
+        } catch (IOException e) {
+            System.err.println("Error while writing SBML entities");
+            System.exit(1);
+        }
+    }
+
+    @Override
+    public String getLabel() {
+        return this.getClass().getSimpleName();
+    }
+
+    @Override
+    public String getLongDescription() {
+        return "Parse SBML to render list of composing entities: metabolites, reactions, genes, pathways and compartments. " +
+                "The output file is a tsv with two columns, one with entities identifiers, and one with the entity type. " +
+                "If no entity type is selected, by default all of them are taken into account. " +
+                "Only identifiers are written, attributes can be extracted from dedicated apps or from the SBML2Tab.";
+    }
+
+    @Override
+    public String getShortDescription() {
+        return "Parse SBML to render list of composing entities: metabolites, reactions, genes and others.";
+    }
+}
-- 
GitLab


From 06239a8fc1f9a00956394da2e1291a094502d3e7 Mon Sep 17 00:00:00 2001
From: cfrainay <clement.frainay@inrae.fr>
Date: Thu, 28 Jul 2022 17:54:57 +0200
Subject: [PATCH 2/3] Add app to get substrates and/or products list from a
 list of reactions

---
 .../attributes/GetReactantsFromReactions.java | 141 ++++++++++++++++++
 1 file changed, 141 insertions(+)
 create mode 100644 met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/GetReactantsFromReactions.java

diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/GetReactantsFromReactions.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/GetReactantsFromReactions.java
new file mode 100644
index 000000000..336ac4dd7
--- /dev/null
+++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/GetReactantsFromReactions.java
@@ -0,0 +1,141 @@
+package fr.inrae.toulouse.metexplore.met4j_toolbox.attributes;
+
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.*;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection;
+import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.JsbmlReader;
+import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.Met4jSbmlReaderException;
+import fr.inrae.toulouse.metexplore.met4j_mapping.Mapper;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.AbstractMet4jApplication;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumFormats;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumParameterTypes;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.Format;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.ParameterType;
+import org.kohsuke.args4j.Option;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+public class GetReactantsFromReactions extends AbstractMet4jApplication {
+
+
+    @ParameterType(name= EnumParameterTypes.InputFile)
+    @Format(name= EnumFormats.Sbml)
+    @Option(name = "-i", usage = "Input SBML file", required = true)
+    public String sbml;
+
+    @ParameterType(name= EnumParameterTypes.InputFile)
+    @Format(name= EnumFormats.Tsv)
+    @Option(name = "-r", usage = "Input Reaction file", required = true)
+    public String reactionFile;
+
+    @ParameterType(name= EnumParameterTypes.Text)
+    @Option(name = "-sep", usage = "Separator in reaction file", required = false)
+    public String sep = "\t";
+    @ParameterType(name= EnumParameterTypes.Boolean)
+    @Option(name = "-header", usage = "Skip reaction file header", required = false)
+    public boolean hasHeader = false;
+    @ParameterType(name= EnumParameterTypes.Integer)
+    @Option(name = "-col", usage = "Column number in reaction file (first as 1)", required = false)
+    public int i=1;
+
+    @ParameterType(name= EnumParameterTypes.Boolean)
+    @Option(name = "-s", aliases = {"--substrates"}, usage = "Extract substrates only", required = false)
+    public Boolean printSubstrates = false;
+    @ParameterType(name= EnumParameterTypes.Boolean)
+    @Option(name = "-p", aliases = {"--products"}, usage = "Extract products only", required = false)
+    public Boolean printProducts = false;
+
+    @ParameterType(name= EnumParameterTypes.OutputFile)
+    @Format(name= EnumFormats.Tsv)
+    @Option(name = "-o", usage = "Output file", required=true)
+    public String outputFile;
+
+    /**
+     * <p>main.</p>
+     *
+     * @param args an array of {@link java.lang.String} objects.
+     */
+    public static void main(String[] args) {
+        GetReactantsFromReactions app = new GetReactantsFromReactions();
+        app.parseArguments(args);
+        app.run();
+    }
+
+
+    /**
+     * <p>run.</p>
+     */
+    public void run() {
+
+        //read SBML, create bionetwork
+        String fileIn = this.sbml;
+        JsbmlReader reader = new JsbmlReader(fileIn);
+        BioNetwork network = null;
+        try {
+            network = reader.read();
+        } catch (Met4jSbmlReaderException e) {
+            System.err.println("Error while reading the SBML file");
+            System.err.println(e.getMessage());
+            System.exit(1);
+        }
+
+        //Import Reaction File
+        BioCollection<BioReaction> input = new BioCollection<>();
+        try {
+            BioNetwork finalNetwork = network;
+            Mapper map = new Mapper(finalNetwork, bioNetwork -> {
+                return finalNetwork.getReactionsView();
+            })
+                    .columnSeparator(sep)
+                    .idColumn(i)
+                    .skipIfNotFound();
+            if(hasHeader) map = map.skipHeader();
+            input = map.map(reactionFile);
+            System.err.println(input.size()+" reactions mapped");
+            System.err.println(map.getNumberOfSkippedEntries()+" reactions not found in model");
+        } catch (IOException e) {
+            System.err.println("Error while reading the Reaction file");
+            System.err.println(e.getMessage());
+            System.exit(1);
+        }
+
+        //default case: everything printed
+        if(!(printSubstrates|printProducts)){
+            printSubstrates=printProducts=true;
+        }
+
+        //Print output
+        try (PrintWriter writer = new PrintWriter(new FileWriter(this.outputFile, false))) {
+            for (BioReaction r : input){
+                BioCollection<BioMetabolite> metabolites = new BioCollection<>();
+                if(printSubstrates || r.isReversible()) metabolites.addAll(network.getLefts(r));
+                if(printProducts || r.isReversible()) metabolites.addAll(network.getRights(r));
+                for (BioMetabolite m : metabolites) {
+                    writer.println(r.getId()+"\t"+m.getId());
+                }
+            }
+        } catch (IOException e) {
+            System.err.println("Error while writing SBML entities");
+            System.exit(1);
+        }
+    }
+
+    @Override
+    public String getLabel() {
+        return this.getClass().getSimpleName();
+    }
+
+    @Override
+    public String getLongDescription() {
+        return "Get reactants lists from a list of reactions and a GSMN. Output a tab-separated file " +
+                "with one row per reactant, reaction identifiers in first column, reactant identifiers in second column. " +
+                "It can provides substrates, products, or both (by default). In the case of reversible reactions, " +
+                "all reactants are considered both substrates and products";
+    }
+
+    @Override
+    public String getShortDescription() {
+        return "Get reactants lists from a list of reactions and a GSMN.";
+    }
+}
-- 
GitLab


From 3df40b4bd07cec01727d2294379890ca5a45cd4c Mon Sep 17 00:00:00 2001
From: cfrainay <clement.frainay@inrae.fr>
Date: Thu, 28 Jul 2022 18:10:04 +0200
Subject: [PATCH 3/3] Add app to get gene list from a list of reactions and
 SBML GPR annotations

---
 .../attributes/GetGenesFromReactions.java     | 128 ++++++++++++++++++
 1 file changed, 128 insertions(+)
 create mode 100644 met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/GetGenesFromReactions.java

diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/GetGenesFromReactions.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/GetGenesFromReactions.java
new file mode 100644
index 000000000..777cba704
--- /dev/null
+++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/GetGenesFromReactions.java
@@ -0,0 +1,128 @@
+package fr.inrae.toulouse.metexplore.met4j_toolbox.attributes;
+
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioGene;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReaction;
+import fr.inrae.toulouse.metexplore.met4j_core.biodata.collection.BioCollection;
+import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.JsbmlReader;
+import fr.inrae.toulouse.metexplore.met4j_io.jsbml.reader.Met4jSbmlReaderException;
+import fr.inrae.toulouse.metexplore.met4j_mapping.Mapper;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.AbstractMet4jApplication;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumFormats;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumParameterTypes;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.Format;
+import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.ParameterType;
+import org.kohsuke.args4j.Option;
+
+import java.io.FileWriter;
+import java.io.IOException;
+import java.io.PrintWriter;
+
+public class GetGenesFromReactions extends AbstractMet4jApplication {
+
+
+    @ParameterType(name= EnumParameterTypes.InputFile)
+    @Format(name= EnumFormats.Sbml)
+    @Option(name = "-i", usage = "Input SBML file", required = true)
+    public String sbml;
+
+    @ParameterType(name= EnumParameterTypes.InputFile)
+    @Format(name= EnumFormats.Tsv)
+    @Option(name = "-r", usage = "Input Reaction file", required = true)
+    public String reactionFile;
+
+    @ParameterType(name= EnumParameterTypes.Text)
+    @Option(name = "-sep", usage = "Separator in reaction file", required = false)
+    public String sep = "\t";
+    @ParameterType(name= EnumParameterTypes.Boolean)
+    @Option(name = "-header", usage = "Skip reaction file header", required = false)
+    public boolean hasHeader = false;
+    @ParameterType(name= EnumParameterTypes.Integer)
+    @Option(name = "-col", usage = "Column number in reaction file (first as 1)", required = false)
+    public int i=1;
+
+    @ParameterType(name= EnumParameterTypes.OutputFile)
+    @Format(name= EnumFormats.Tsv)
+    @Option(name = "-o", usage = "Output file", required=true)
+    public String outputFile;
+
+    /**
+     * <p>main.</p>
+     *
+     * @param args an array of {@link String} objects.
+     */
+    public static void main(String[] args) {
+        GetGenesFromReactions app = new GetGenesFromReactions();
+        app.parseArguments(args);
+        app.run();
+    }
+
+
+    /**
+     * <p>run.</p>
+     */
+    public void run() {
+
+        //read SBML, create bionetwork
+        String fileIn = this.sbml;
+        JsbmlReader reader = new JsbmlReader(fileIn);
+        BioNetwork network = null;
+        try {
+            network = reader.read();
+        } catch (Met4jSbmlReaderException e) {
+            System.err.println("Error while reading the SBML file");
+            System.err.println(e.getMessage());
+            System.exit(1);
+        }
+
+        //Import Reaction File
+        BioCollection<BioReaction> input = new BioCollection<>();
+        try {
+            BioNetwork finalNetwork = network;
+            Mapper map = new Mapper(finalNetwork, bioNetwork -> {
+                return finalNetwork.getReactionsView();
+            })
+                    .columnSeparator(sep)
+                    .idColumn(i)
+                    .skipIfNotFound();
+            if(hasHeader) map = map.skipHeader();
+            input = map.map(reactionFile);
+            System.err.println(input.size()+" reactions mapped");
+            System.err.println(map.getNumberOfSkippedEntries()+" reactions not found in model");
+        } catch (IOException e) {
+            System.err.println("Error while reading the Reaction file");
+            System.err.println(e.getMessage());
+            System.exit(1);
+        }
+
+        //Print output
+        try (PrintWriter writer = new PrintWriter(new FileWriter(this.outputFile, false))) {
+            for (BioReaction r : input){
+                BioCollection<BioGene> genes = network.getGenesFromReactions(r);
+                for (BioGene g : genes) {
+                    writer.println(r.getId()+"\t"+g.getId());
+                }
+            }
+        } catch (IOException e) {
+            System.err.println("Error while writing SBML entities");
+            System.exit(1);
+        }
+    }
+
+    @Override
+    public String getLabel() {
+        return this.getClass().getSimpleName();
+    }
+
+    @Override
+    public String getLongDescription() {
+        return "Get associated gene list from a list of reactions and a GSMN. Parse GSMN GPR annotations and output a tab-separated file " +
+                "with one row per gene, associated reaction identifiers from input file in first column, gene identifiers in second column.";
+    }
+
+    @Override
+    public String getShortDescription() {
+        return "Get gene lists from a list of reactions and a GSMN.";
+    }
+}
-- 
GitLab