diff --git a/CHANGELOG.md b/CHANGELOG.md index 2f85fb2afeeeacd128a34564d7ac71f89eb51fd6..b710baa73443ee96cac86b7532869b63d5a5bb4a 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -4,13 +4,21 @@ All notable changes to this project will be documented in this file. The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.0.0/), and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). +## Next version + +[met4j-io] Fix SetIdsFromFile : do not throw an exception when a new id is found twice + + ## 1.2.0 ### Features [met4j-toolbox] Add Apps to compute compound graph's classical weights (degree/chemical similarity) + [met4j-toolbox] Add App to identify model seeds and targets + [met4j-toolbox] Add App to set new ids to metabolic entities in a SBML file + [met4j-graph] Add method to create RPAIRs-like tags on compound graph's edges ## 1.1.1 diff --git a/coverage/pom.xml b/coverage/pom.xml index 4dd7d5c3900843c83db76af57d68a870778e6e09..58bd7b29f9d5c764aeea078e5be263c140e34c26 100644 --- a/coverage/pom.xml +++ b/coverage/pom.xml @@ -80,6 +80,12 @@ <artifactId>met4j-mapping</artifactId> <version>${project.version}</version> </dependency> + + <dependency> + <groupId>${project.groupId}</groupId> + <artifactId>met4j-reconstruction</artifactId> + <version>${project.version}</version> + </dependency> </dependencies> <build> diff --git a/met4j-chemUtils/pom.xml b/met4j-chemUtils/pom.xml index 62212bfbfd1f42cb9401dc9eab2344a3a2a2aaf1..d025c5174b52b414427e389082563daea2cbfa9c 100644 --- a/met4j-chemUtils/pom.xml +++ b/met4j-chemUtils/pom.xml @@ -21,12 +21,6 @@ <url>http://maven.apache.org</url> <dependencies> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>4.12</version> - <scope>test</scope> - </dependency> <dependency> <groupId>org.openscience.cdk</groupId> <artifactId>cdk-bundle</artifactId> diff --git a/met4j-core/pom.xml b/met4j-core/pom.xml index ede3e822d54a464c1ba3c0cf082a1b6e8243c7cc..0be4d4d55384d06f5eecfab86450dfeaf78c6417 100644 --- a/met4j-core/pom.xml +++ b/met4j-core/pom.xml @@ -27,12 +27,7 @@ </properties> <dependencies> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>4.12</version> - <scope>test</scope> - </dependency> + <dependency> <groupId>org.apache.commons</groupId> <artifactId>commons-lang3</artifactId> diff --git a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/utils/StringUtils.java b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/utils/StringUtils.java index 9810059fb7ddc9f81c38dee9583055409565ca3d..9976c2cddadd398e98a116084a092b75b2de9b8d 100644 --- a/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/utils/StringUtils.java +++ b/met4j-core/src/main/java/fr/inrae/toulouse/metexplore/met4j_core/utils/StringUtils.java @@ -126,7 +126,11 @@ public class StringUtils { * @param formula a String to check * @return true if it looks like a chemical formula (e.g. CH3, C, (n)CH2O6) */ - public static boolean checkMetaboliteFormula(@NonNull String formula) { + public static boolean checkMetaboliteFormula(String formula) { + + if(formula == null) { + return false; + } Matcher m = patternFormula.matcher(formula); return m.matches(); } diff --git a/met4j-graph/pom.xml b/met4j-graph/pom.xml index 8d8662a7c000c53562748538f76929e2294acf64..8ff197c446aee69f0b0e340a278b84b1bd843d6b 100644 --- a/met4j-graph/pom.xml +++ b/met4j-graph/pom.xml @@ -21,12 +21,6 @@ </properties> <dependencies> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>4.12</version> - <scope>test</scope> - </dependency> <dependency> <groupId>org.jgrapht</groupId> <artifactId>jgrapht-core</artifactId> diff --git a/met4j-io/pom.xml b/met4j-io/pom.xml index 9869a361f3508b8fbb5e1d1fb3ee10a1c76b6d67..a5aea77312ff2da49010fdf48e0224c258cea025 100644 --- a/met4j-io/pom.xml +++ b/met4j-io/pom.xml @@ -32,11 +32,6 @@ <artifactId>jsbml</artifactId> <version>1.6.1</version> </dependency> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>4.12</version> - </dependency> <dependency> <groupId>xerces</groupId> <artifactId>xercesImpl</artifactId> diff --git a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetIdsFromFile.java b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetIdsFromFile.java index f32a689cb3acc3bf802ac1bbca99a3cab307752a..78a46d59836e3ddf1f560b8bed02ed1102f4befa 100644 --- a/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetIdsFromFile.java +++ b/met4j-io/src/main/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetIdsFromFile.java @@ -46,15 +46,15 @@ public class SetIdsFromFile extends AbstractSetAttributesFromFile { /** * <p>Constructor for AbstractSetAttributesFromFile.</p> * - * @param colId a int. + * @param colId an int. * @param colAttr : number of the attribute column * @param bn : {@link BioNetwork} * @param fileIn : tabulated file containing the ids and the attributes * @param c : comment character - * @param nSkip a int. Number of lines to skip + * @param nSkip an int. Number of lines to skip * @param entityType a {@link EntityType} * @param p a {@link Boolean} object : To match the objects in the sbml file, adds the prefix R_ to reactions and M_ to metabolites - * @param s a {@link Boolean} object : To match the objects in the sbml file, adds the suffix _comparmentID to metabolite + * @param s a {@link Boolean} object : To match the objects in the sbml file, adds the suffix _compartmentID to metabolite */ public SetIdsFromFile(int colId, int colAttr, BioNetwork bn, String fileIn, String c, int nSkip, EntityType entityType, Boolean p, Boolean s) { super(colId, colAttr, bn, fileIn, c, nSkip, entityType, p, s); @@ -111,7 +111,7 @@ public class SetIdsFromFile extends AbstractSetAttributesFromFile { break; } default: { - throw new EntityTypeException("Entity type "+this.entityType+" not recognized"); + throw new EntityTypeException("Entity type " + this.entityType + " not recognized"); } } } @@ -119,7 +119,7 @@ public class SetIdsFromFile extends AbstractSetAttributesFromFile { System.err.println(n + " entities processed"); - return flag; + return true; } /** @@ -132,35 +132,38 @@ public class SetIdsFromFile extends AbstractSetAttributesFromFile { BioCompartment compartment = this.bn.getCompartment(id); if (compartment != null) { - BioCompartment newCompartment = new BioCompartment(compartment, newId); - this.bn.add(newCompartment); + BioCompartment newCompartment; + + if (!this.bn.containsCompartment(newId)) { + newCompartment = new BioCompartment(compartment, newId); + this.bn.add(newCompartment); + } else { + System.err.println("[WARNING] The compartment "+newId+" already exists"); + newCompartment = this.bn.getCompartment(newId); + } // Add metabolites this.bn.affectToCompartment(newCompartment, compartment.getComponentsView()); // Change compartment in each left reactant - this.bn.getReactionsView().forEach(r -> { - r.getLeftReactantsView().forEach(reactant -> { - if (reactant.getLocation().equals(compartment)) { - BioMetabolite metabolite = reactant.getMetabolite(); - Double sto = reactant.getQuantity(); - this.bn.affectLeft(r, sto, newCompartment, metabolite); - this.bn.removeLeft(metabolite, compartment, r); - } - }); - }); + this.bn.getReactionsView().forEach(r -> r.getLeftReactantsView().forEach(reactant -> { + if (reactant.getLocation().equals(compartment)) { + BioMetabolite metabolite = reactant.getMetabolite(); + Double sto = reactant.getQuantity(); + this.bn.affectLeft(r, sto, newCompartment, metabolite); + this.bn.removeLeft(metabolite, compartment, r); + } + })); // Change compartment in each right reactant - this.bn.getReactionsView().forEach(r -> { - r.getRightReactantsView().forEach(reactant -> { - if (reactant.getLocation().equals(compartment)) { - BioMetabolite metabolite = reactant.getMetabolite(); - Double sto = reactant.getQuantity(); - this.bn.affectRight(r, sto, newCompartment, metabolite); - this.bn.removeRight(metabolite, compartment, r); - } - }); - }); + this.bn.getReactionsView().forEach(r -> r.getRightReactantsView().forEach(reactant -> { + if (reactant.getLocation().equals(compartment)) { + BioMetabolite metabolite = reactant.getMetabolite(); + Double sto = reactant.getQuantity(); + this.bn.affectRight(r, sto, newCompartment, metabolite); + this.bn.removeRight(metabolite, compartment, r); + } + })); this.bn.removeOnCascade(compartment); @@ -177,20 +180,24 @@ public class SetIdsFromFile extends AbstractSetAttributesFromFile { BioReaction reaction = this.bn.getReaction(id); if (reaction != null) { - BioReaction newReaction = new BioReaction(reaction, newId); - this.bn.add(newReaction); + BioReaction newReaction; + + if (!this.bn.containsReaction(newId)) { + newReaction = new BioReaction(reaction, newId); + this.bn.add(newReaction); + // Add lefts and rights + this.bn.affectLeft(newReaction, reaction.getLeftReactantsView()); + this.bn.affectRight(newReaction, reaction.getRightReactantsView()); + } else { + newReaction = this.bn.getReaction(newId); + System.err.println("[WARNING] The reaction "+newId+" already exists"); + } // Add enzymes this.bn.affectEnzyme(newReaction, reaction.getEnzymesView()); // Change reaction in the pathways - this.bn.getPathwaysFromReaction(reaction).forEach(p -> { - this.bn.affectToPathway(p, newReaction); - }); - - // Add lefts and rights - this.bn.affectLeft(newReaction, reaction.getLeftReactantsView()); - this.bn.affectRight(newReaction, reaction.getRightReactantsView()); + this.bn.getPathwaysFromReaction(reaction).forEach(p -> this.bn.affectToPathway(p, newReaction)); this.bn.removeOnCascade(reaction); } @@ -206,24 +213,28 @@ public class SetIdsFromFile extends AbstractSetAttributesFromFile { BioMetabolite metabolite = this.bn.getMetabolite(id); if (metabolite != null) { - BioMetabolite newMetabolite = new BioMetabolite(metabolite, newId); - this.bn.add(newMetabolite); - - // Change the metabolite in the compartments - this.bn.getCompartmentsView().stream().filter(c -> c.getComponentsView().contains(metabolite)).forEach(c -> { - this.bn.removeFromCompartment(c, metabolite); - this.bn.affectToCompartment(c, newMetabolite); - }); + BioMetabolite newMetabolite; + + if (!this.bn.containsMetabolite(newId)) { + newMetabolite = new BioMetabolite(metabolite, newId); + this.bn.add(newMetabolite); + // Change the metabolite in the compartments + this.bn.getCompartmentsView().stream().filter(c -> c.getComponentsView().contains(metabolite)).forEach(c -> { + this.bn.removeFromCompartment(c, metabolite); + this.bn.affectToCompartment(c, newMetabolite); + }); + } else { + newMetabolite = this.bn.getMetabolite(newId); + System.err.println("[WARNING] The metabolite "+newId+" already exists"); + } // Change the metabolite in the left reactants - this.bn.getReactionsView().forEach(r -> { - r.getLeftReactantsView().stream().filter(reactant -> reactant.getMetabolite().equals(metabolite)) - .forEach(reactant -> { - Double sto = reactant.getQuantity(); - BioCompartment cpt = reactant.getLocation(); - this.bn.affectLeft(r, sto, cpt, newMetabolite); - }); - }); + this.bn.getReactionsView().forEach(r -> r.getLeftReactantsView().stream().filter(reactant -> reactant.getMetabolite().equals(metabolite)) + .forEach(reactant -> { + Double sto = reactant.getQuantity(); + BioCompartment cpt = reactant.getLocation(); + this.bn.affectLeft(r, sto, cpt, newMetabolite); + })); // Change the metabolite in the right reactants this.bn.getReactionsView().forEach(r -> @@ -239,8 +250,8 @@ public class SetIdsFromFile extends AbstractSetAttributesFromFile { this.bn.getEnzymesView(). forEach(e -> e.getParticipantsView() .stream().filter(p -> p.getPhysicalEntity().equals(metabolite)) - .forEach(partcipant -> { - Double sto = partcipant.getQuantity(); + .forEach(participant -> { + Double sto = participant.getQuantity(); this.bn.affectSubUnit(e, sto, newMetabolite); })); @@ -258,8 +269,16 @@ public class SetIdsFromFile extends AbstractSetAttributesFromFile { BioPathway originalPathway = this.bn.getPathway(id); if (originalPathway != null) { - BioPathway newPathway = new BioPathway(originalPathway, newId); - this.bn.add(newPathway); + BioPathway newPathway; + + if (!this.bn.containsPathway(newId)) { + newPathway = new BioPathway(originalPathway, newId); + this.bn.add(newPathway); + } else { + newPathway = this.bn.getPathway(newId); + System.err.println("[WARNING] The pathway "+newId+" already exists"); + } + this.bn.affectToPathway(newPathway, this.bn.getReactionsFromPathways(originalPathway)); this.bn.removeOnCascade(originalPathway); } @@ -268,18 +287,24 @@ public class SetIdsFromFile extends AbstractSetAttributesFromFile { /** * Replace a gene with the same gene with another id * - * @param id : the origina id + * @param id : the original id * @param newId : the new id */ private void setGeneId(String id, String newId) { BioGene originalGene = this.bn.getGene(id); if (originalGene != null) { - BioGene newGene = new BioGene(originalGene, newId); - this.bn.add(newGene); - this.bn.getProteinsView().stream().filter(p -> p.getGene().equals(originalGene)).forEach(p -> { - this.bn.affectGeneProduct(p, newGene); - }); + BioGene newGene; + if (!this.bn.containsGene(newId)) { + newGene = new BioGene(originalGene, newId); + this.bn.add(newGene); + } else { + newGene = this.bn.getGene(id); + System.err.println("[WARNING] The gene "+newId+" already exists"); + } + + this.bn.getProteinsView().stream().filter(p -> p.getGene().equals(originalGene)).forEach(p -> this.bn.affectGeneProduct(p, newGene)); + this.bn.removeOnCascade(originalGene); } } diff --git a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetIdsFromFileTest.java b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetIdsFromFileTest.java index 579b835b8e6338d108dad6656a12dac44151ce6d..e5d1d32e28e21d41bc3f7dd17f17f1523880234a 100644 --- a/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetIdsFromFileTest.java +++ b/met4j-io/src/test/java/fr/inrae/toulouse/metexplore/met4j_io/tabulated/attributes/SetIdsFromFileTest.java @@ -83,6 +83,22 @@ public class SetIdsFromFileTest { assertEquals(1, network.getProteinsView().size()); + // Test when the gene is already present + network.add(new BioGene("g1")); + + setIdsFromFile = Mockito.spy(new SetIdsFromFile(0, 1, network, "", "", 0, EntityType.GENE,false, false)); + + Mockito.doReturn(true).when(setIdsFromFile).parseAttributeFile(); + + flag = setIdsFromFile.parseLine(line, 1); + + assertTrue(flag); + + setIdsFromFile.setAttributes(); + + assertEquals(1, network.getGenesView().size()); + + } @Test @@ -136,6 +152,21 @@ public class SetIdsFromFileTest { assertTrue(e.getParticipantsView().stream().anyMatch(p -> p.getPhysicalEntity().equals(newMetabolite))); assertFalse(e.getParticipantsView().stream().anyMatch(p -> p.getPhysicalEntity().equals(metabolite))); + // Test when the metabolite is already present + network.add(new BioMetabolite("m1")); + + setIdsFromFile = Mockito.spy(new SetIdsFromFile(0, 1, network, "", "", 0, EntityType.METABOLITE,false, false)); + + Mockito.doReturn(true).when(setIdsFromFile).parseAttributeFile(); + + flag = setIdsFromFile.parseLine(line, 1); + + assertTrue(flag); + + setIdsFromFile.setAttributes(); + + assertEquals(1, network.getMetabolitesView().size()); + } @Test @@ -165,6 +196,21 @@ public class SetIdsFromFileTest { assertNotNull(newPathway); assertEquals(2, network.getReactionsFromPathways(newPathway).size()); + // test when the pathway is already present + network.add(new BioPathway("p1")); + + setIdsFromFile = Mockito.spy(new SetIdsFromFile(0, 1, network, "", "", 0, EntityType.PATHWAY,false, false)); + + Mockito.doReturn(true).when(setIdsFromFile).parseAttributeFile(); + + flag = setIdsFromFile.parseLine(line, 1); + + assertTrue(flag); + + setIdsFromFile.setAttributes(); + + assertEquals(1, network.getPathwaysView().size()); + } @Test @@ -212,6 +258,22 @@ public class SetIdsFromFileTest { assertEquals(1, newReaction.getLeftsView().size()); assertEquals(1, newReaction.getRightsView().size()); + + // Check if the reaction is already in the network + this.network.add(new BioReaction("r1")); + + setIdsFromFile = Mockito.spy(new SetIdsFromFile(0, 1, network, "", "", 0, EntityType.REACTION,false, false)); + + Mockito.doReturn(true).when(setIdsFromFile).parseAttributeFile(); + + flag = setIdsFromFile.parseLine(line, 1); + + assertTrue(flag); + + setIdsFromFile.setAttributes(); + + assertEquals(1, network.getReactionsView().size()); + } @Test @@ -256,5 +318,20 @@ public class SetIdsFromFileTest { assertTrue(r1.getLeftReactantsView().stream().allMatch(reactant -> reactant.getLocation().equals(newCpt))); assertTrue(r1.getRightReactantsView().stream().allMatch(reactant -> reactant.getLocation().equals(newCpt))); + // Check if the compartment is already in the network + this.network.add(new BioCompartment("cpt")); + + setIdsFromFile = Mockito.spy(new SetIdsFromFile(0, 1, network, "", "", 0, EntityType.COMPARTMENT,false, false)); + + Mockito.doReturn(true).when(setIdsFromFile).parseAttributeFile(); + + flag = setIdsFromFile.parseLine(line, 1); + + assertTrue(flag); + + setIdsFromFile.setAttributes(); + + assertEquals(1, this.network.getCompartmentsView().size()); + } } \ No newline at end of file diff --git a/met4j-mapping/pom.xml b/met4j-mapping/pom.xml index c2262605df07896b6febbacab9fcfc9a74a60796..647b884c14b7b1c8ca239b3041f823e1bb595727 100644 --- a/met4j-mapping/pom.xml +++ b/met4j-mapping/pom.xml @@ -21,11 +21,6 @@ <artifactId>met4j-core</artifactId> <version>1.2.0-SNAPSHOT</version> </dependency> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>4.12</version> - </dependency> </dependencies> <build> diff --git a/met4j-mathUtils/pom.xml b/met4j-mathUtils/pom.xml index 4b36813caef46e0d29543cf0eabf4b2428d1cfd1..d1ce169ef310f8d843a915b653f4ef85f5139e64 100644 --- a/met4j-mathUtils/pom.xml +++ b/met4j-mathUtils/pom.xml @@ -22,12 +22,6 @@ </properties> <dependencies> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>4.12</version> - <scope>test</scope> - </dependency> <dependency> <groupId>org.ejml</groupId> <artifactId>all</artifactId> diff --git a/met4j-reconstruction/pom.xml b/met4j-reconstruction/pom.xml new file mode 100644 index 0000000000000000000000000000000000000000..3404a2d2df5476337e2fb69f680fcd959790802a --- /dev/null +++ b/met4j-reconstruction/pom.xml @@ -0,0 +1,101 @@ +<?xml version="1.0" encoding="UTF-8"?> +<!-- + ~ Copyright INRAE (2022) + ~ + ~ contact-metexplore@inrae.fr + ~ + ~ This software is a computer program whose purpose is to [describe + ~ functionalities and technical features of your software]. + ~ + ~ This software is governed by the CeCILL license under French law and + ~ abiding by the rules of distribution of free software. You can use, + ~ modify and/ or redistribute the software under the terms of the CeCILL + ~ license as circulated by CEA, CNRS and INRIA at the following URL + ~ "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html". + ~ + ~ As a counterpart to the access to the source code and rights to copy, + ~ modify and redistribute granted by the license, users are provided only + ~ with a limited warranty and the software's author, the holder of the + ~ economic rights, and the successive licensors have only limited + ~ liability. + ~ + ~ In this respect, the user's attention is drawn to the risks associated + ~ with loading, using, modifying and/or developing or reproducing the + ~ software by the user in light of its specific status of free software, + ~ that may mean that it is complicated to manipulate, and that also + ~ therefore means that it is reserved for developers and experienced + ~ professionals having in-depth computer knowledge. Users are therefore + ~ encouraged to load and test the software's suitability as regards their + ~ requirements in conditions enabling the security of their systems and/or + ~ data to be ensured and, more generally, to use and operate it in the + ~ same conditions as regards security. + ~ + ~ The fact that you are presently reading this means that you have had + ~ knowledge of the CeCILL license and that you accept its terms. + ~ + --> + +<project xmlns="http://maven.apache.org/POM/4.0.0" + xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> + <parent> + <artifactId>met4j</artifactId> + <groupId>fr.inrae.toulouse.metexplore</groupId> + <version>1.2.0-SNAPSHOT</version> + </parent> + <modelVersion>4.0.0</modelVersion> + + <artifactId>met4j-reconstruction</artifactId> + <packaging>jar</packaging> + + <name>met4j-reconstruction</name> + <url>http://maven.apache.org</url> + + <properties> + <maven.compiler.source>11</maven.compiler.source> + <maven.compiler.target>11</maven.compiler.target> + <project.build.sourceEncoding>UTF-8</project.build.sourceEncoding> + </properties> + + <dependencies> + <dependency> + <groupId>fr.inrae.toulouse.metexplore</groupId> + <artifactId>met4j-io</artifactId> + <version>1.2.0-SNAPSHOT</version> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.12</version> + </dependency> + </dependencies> + + <build> + <plugins> + <plugin> + <groupId>org.jacoco</groupId> + <artifactId>jacoco-maven-plugin</artifactId> + <version>0.8.7</version> + <executions> + <!-- to avoid bugs in some situations --> + <execution> + <id>default-prepare-agent</id> + <goals> + <goal>prepare-agent</goal> + </goals> + </execution> + + <!-- create report during maven verify phase --> + <execution> + <id>report</id> + <phase>verify</phase> + <goals> + <goal>report</goal> + </goals> + </execution> + </executions> + </plugin> + </plugins> + </build> + +</project> \ No newline at end of file diff --git a/met4j-reconstruction/src/main/java/fr/inrae/toulouse/metexplore/met4j_reconstruction/check/balance/NetworkBalanceAnalysis.java b/met4j-reconstruction/src/main/java/fr/inrae/toulouse/metexplore/met4j_reconstruction/check/balance/NetworkBalanceAnalysis.java new file mode 100644 index 0000000000000000000000000000000000000000..8c027af44a56c0fe1a588aaf985bf34ebf8366c7 --- /dev/null +++ b/met4j-reconstruction/src/main/java/fr/inrae/toulouse/metexplore/met4j_reconstruction/check/balance/NetworkBalanceAnalysis.java @@ -0,0 +1,78 @@ +/* + * Copyright INRAE (2022) + * + * contact-metexplore@inrae.fr + * + * This software is a computer program whose purpose is to [describe + * functionalities and technical features of your software]. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + * + */ +package fr.inrae.toulouse.metexplore.met4j_reconstruction.check.balance; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioEntity; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; +import lombok.Getter; + +import java.util.Comparator; +import java.util.List; +import java.util.stream.Collectors; + +/** + * Performs the balance checking on all the reactions of a BioNetwork + */ +public class NetworkBalanceAnalysis { + + @Getter + private final List<ReactionBalanceAnalysis> allBalances; + @Getter + private final List<ReactionBalanceAnalysis> balanced; + @Getter + private final List<ReactionBalanceAnalysis> unbalanced; + + /** + * Constructor + * + * @param network a BioNetwork + */ + public NetworkBalanceAnalysis(BioNetwork network) { + + this.allBalances = network.getReactionsView().stream() + .sorted(Comparator.comparing(BioEntity::getId)) + .map(ReactionBalanceAnalysis::new) + .collect(Collectors.toList()); + + this.balanced = this.allBalances.stream().filter(ReactionBalanceAnalysis::isBalanced).collect(Collectors.toList()); + this.unbalanced = this.allBalances.stream().filter(b -> !b.isBalanced() && !b.isExchange()).collect(Collectors.toList()); + + } + + +} + + diff --git a/met4j-reconstruction/src/main/java/fr/inrae/toulouse/metexplore/met4j_reconstruction/check/balance/ReactionBalanceAnalysis.java b/met4j-reconstruction/src/main/java/fr/inrae/toulouse/metexplore/met4j_reconstruction/check/balance/ReactionBalanceAnalysis.java new file mode 100644 index 0000000000000000000000000000000000000000..a418b9fe1f560a696ab4142af9e1b7b4961a6b55 --- /dev/null +++ b/met4j-reconstruction/src/main/java/fr/inrae/toulouse/metexplore/met4j_reconstruction/check/balance/ReactionBalanceAnalysis.java @@ -0,0 +1,150 @@ +/* + * Copyright INRAE (2022) + * + * contact-metexplore@inrae.fr + * + * This software is a computer program whose purpose is to [describe + * functionalities and technical features of your software]. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + * + */ +package fr.inrae.toulouse.metexplore.met4j_reconstruction.check.balance; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioMetabolite; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioReactant; +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_core.utils.StringUtils; +import fr.inrae.toulouse.metexplore.met4j_io.annotations.metabolite.MetaboliteAttributes; +import lombok.Getter; + +import java.util.HashMap; +import java.util.regex.Matcher; +import java.util.regex.Pattern; + +/** + * Class to store the result of a reaction balance checking + */ +public class ReactionBalanceAnalysis +{ + @Getter + private HashMap<String, Double> balances; + @Getter + private final BioReaction reaction; + @Getter + private final BioCollection<BioMetabolite> metabolitesWithBadFormula; + + public ReactionBalanceAnalysis(BioReaction reaction) { + this.reaction = reaction; + + this.metabolitesWithBadFormula = new BioCollection<>(); + + this.computeBalances(); + } + + private void computeBalances() { + + HashMap<String, Double> tmpBalances = new HashMap<>(); + + for(BioReactant left : reaction.getLeftReactantsView()) { + boolean flag = this.countAtoms(tmpBalances, left, false); + if(!flag) { + metabolitesWithBadFormula.add(left.getMetabolite()); + } + } + for(BioReactant right : reaction.getRightReactantsView()) { + boolean flag = this.countAtoms(tmpBalances, right, true); + if(!flag) { + metabolitesWithBadFormula.add(right.getMetabolite()); + } + } + + this.balances = tmpBalances; + } + + private boolean countAtoms(HashMap<String, Double> tmpBalances, BioReactant reactant, Boolean isRight) { + + Double sto = isRight ? reactant.getQuantity() : - reactant.getQuantity(); + + String formula = reactant.getMetabolite().getChemicalFormula(); + + if(! StringUtils.checkMetaboliteFormula(formula)) { + return false; + } + + String REGEX = "([A-Z][a-z]*)([0-9]*)"; + + Pattern pattern = Pattern.compile(REGEX); + Matcher matcher = pattern.matcher(formula); + + while (matcher.find()) { + + String atom = matcher.group(1); + + String numStr = matcher.group(2); + + if (numStr.equals("")) { + numStr = "1.0"; + } + + Double number = Double.parseDouble(numStr); + + if (!tmpBalances.containsKey(atom)) { + tmpBalances.put(atom, sto * number); + } else { + tmpBalances.put(atom, tmpBalances.get(atom) + sto * number); + } + + } + + return true; + } + + /** + * @return true if the reaction is balanced + */ + public boolean isBalanced() { + return metabolitesWithBadFormula.size() == 0 && balances.values().stream().reduce(0.0, Double::sum).equals(0.0); + } + + /** + * check if the reaction is an exchange reaction, ie : + * - has an empty side + * - or contains a metabolite that has boundary condition equals to true + * @return a boolean + */ + public boolean isExchange() { + if(reaction.getLeftReactantsView().size() == 0 || reaction.getRightReactantsView().size() == 0) + { + return true; + } + return reaction.getMetabolitesView().stream().anyMatch(MetaboliteAttributes::getBoundaryCondition); + + } + +} diff --git a/met4j-reconstruction/src/test/java/fr/inrae/toulouse/metexplore/met4j_reconstruction/check/balance/NetworkBalanceAnalysisTest.java b/met4j-reconstruction/src/test/java/fr/inrae/toulouse/metexplore/met4j_reconstruction/check/balance/NetworkBalanceAnalysisTest.java new file mode 100644 index 0000000000000000000000000000000000000000..d9057f059956acd6ed8d4e8ac9970e663f5b56bc --- /dev/null +++ b/met4j-reconstruction/src/test/java/fr/inrae/toulouse/metexplore/met4j_reconstruction/check/balance/NetworkBalanceAnalysisTest.java @@ -0,0 +1,125 @@ +/* + * Copyright INRAE (2022) + * + * contact-metexplore@inrae.fr + * + * This software is a computer program whose purpose is to [describe + * functionalities and technical features of your software]. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + * + */ + +package fr.inrae.toulouse.metexplore.met4j_reconstruction.check.balance; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment; +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 org.junit.BeforeClass; +import org.junit.Test; + +import java.util.List; + +import static org.junit.Assert.assertEquals; + +public class NetworkBalanceAnalysisTest { + + public static BioNetwork network; + public static BioReaction r1, r2, r3; + public static BioMetabolite s1; + public static BioMetabolite s2; + public static BioMetabolite p1; + public static BioMetabolite p2; + private static NetworkBalanceAnalysis analysis; + + @BeforeClass + public static void init() { + + network = new BioNetwork(); + s1 = new BioMetabolite("s1"); + s2 = new BioMetabolite("s2"); + p1 = new BioMetabolite("p1"); + p2 = new BioMetabolite("p2"); + r1 = new BioReaction("r1"); + r2 = new BioReaction("r2"); + r3 = new BioReaction("r03"); + + s1.setChemicalFormula("C6H6O3"); + s2.setChemicalFormula("C2H3"); + p1.setChemicalFormula("C2H2O"); + p2.setChemicalFormula("C4H6"); + + BioCompartment cpt = new BioCompartment("cpt"); + + network.add(s1, s2, p1, p2, r1, r2, r3, cpt); + network.affectToCompartment(cpt, s1, s2, p1, p2); + + network.affectLeft(r1, 1.0, cpt, s1); + network.affectLeft(r1, 2.0, cpt, s2); + network.affectRight(r1, 3.0, cpt, p1); + network.affectRight(r1, 1.0, cpt, p2); + + network.affectLeft(r2, 1.0, cpt, s1); + network.affectRight(r2, 3.0, cpt, p1); + network.affectRight(r2, 1.0, cpt, p2); + + network.affectLeft(r3, 1.0, cpt, s1); + network.affectRight(r3, 3.0, cpt, p1); + + // r1 : s1 + 2 s2 -> 3 p1 + 1 p2 // balanced + // r2 : s1 -> 3 p1 + 1 p2 // not balanced + // r3 : s1 -> 3 p1 // balanced + + analysis = new NetworkBalanceAnalysis(network); + + + } + + + @Test + public void getAllBalances() { + List<ReactionBalanceAnalysis> allBalances = analysis.getAllBalances(); + + assertEquals(3, allBalances.size()); + } + + @Test + public void getBalanced() { + List<ReactionBalanceAnalysis> balanced = analysis.getBalanced(); + + assertEquals(2, balanced.size()); + } + + @Test + public void getUnbalanced() { + List<ReactionBalanceAnalysis> unbalanced = analysis.getUnbalanced(); + + assertEquals(1, unbalanced.size()); + } +} \ No newline at end of file diff --git a/met4j-reconstruction/src/test/java/fr/inrae/toulouse/metexplore/met4j_reconstruction/check/balance/ReactionBalanceAnalysisTest.java b/met4j-reconstruction/src/test/java/fr/inrae/toulouse/metexplore/met4j_reconstruction/check/balance/ReactionBalanceAnalysisTest.java new file mode 100644 index 0000000000000000000000000000000000000000..4bc8f96f29e712034403a765fa0b0f81145f0d36 --- /dev/null +++ b/met4j-reconstruction/src/test/java/fr/inrae/toulouse/metexplore/met4j_reconstruction/check/balance/ReactionBalanceAnalysisTest.java @@ -0,0 +1,224 @@ +/* + * Copyright INRAE (2022) + * + * contact-metexplore@inrae.fr + * + * This software is a computer program whose purpose is to [describe + * functionalities and technical features of your software]. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + * + */ + +package fr.inrae.toulouse.metexplore.met4j_reconstruction.check.balance; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioCompartment; +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_io.annotations.metabolite.MetaboliteAttributes; +import org.junit.Before; +import org.junit.Test; + +import java.util.HashMap; + +import static org.junit.Assert.*; + +public class ReactionBalanceAnalysisTest { + + private static BioNetwork network; + private static BioReaction reaction; + private static BioMetabolite s1; + private static BioMetabolite s2; + private static BioMetabolite p1; + private static BioMetabolite p2; + private static BioCompartment cpt; + + @Before + public void init() { + + network = new BioNetwork(); + s1 = new BioMetabolite("s1"); + s2 = new BioMetabolite("s2"); + p1 = new BioMetabolite("p1"); + p2 = new BioMetabolite("p2"); + reaction = new BioReaction("r1"); + cpt = new BioCompartment("cpt"); + + network.add(s1, s2, p1, p2, reaction, cpt); + network.affectToCompartment(cpt, s1, s2, p1, p2); + network.affectLeft(reaction, 1.0, cpt, s1); + network.affectLeft(reaction, 2.0, cpt, s2); + network.affectRight(reaction, 3.0, cpt, p1); + network.affectRight(reaction, 1.0, cpt, p2); + + // reaction : s1 + 2 s2 -> 3 p1 + 1 p2 + } + + public void createBalanced() { + s1.setChemicalFormula("C6H6O3"); + s2.setChemicalFormula("C2H3"); + p1.setChemicalFormula("C2H2O"); + p2.setChemicalFormula("C4H6"); + + } + + public void createUnbalanced() { + s1.setChemicalFormula("C6H6O3"); + s2.setChemicalFormula("C2H3"); + p1.setChemicalFormula("CH2O"); + p2.setChemicalFormula("C4H6"); + + } + + public void createBalancedWithNull() { + s1.setChemicalFormula("C6H9O3"); + s2.setChemicalFormula(null); + p1.setChemicalFormula("C2H2O"); + p2.setChemicalFormula("H3"); + } + + public void createBalancedWithBadFormula() { + s1.setChemicalFormula("C6H9O3"); + s2.setChemicalFormula("2C"); + p1.setChemicalFormula("C2H2O"); + p2.setChemicalFormula("H3"); + } + + @Test + public void isBalanced() { + this.createBalanced(); + ReactionBalanceAnalysis balance = new ReactionBalanceAnalysis(reaction); + + assertTrue(balance.isBalanced()); + + this.createUnbalanced(); + + balance = new ReactionBalanceAnalysis(reaction); + + assertFalse(balance.isBalanced()); + } + + @Test + public void isBalancedWithNull() { + this.createBalancedWithNull(); + ReactionBalanceAnalysis balance = new ReactionBalanceAnalysis(reaction); + + assertFalse(balance.isBalanced()); + + assertTrue(balance.getMetabolitesWithBadFormula().contains(s2)); + } + + @Test + public void isBalancedWithBadFormula() { + this.createBalancedWithBadFormula(); + ReactionBalanceAnalysis balance = new ReactionBalanceAnalysis(reaction); + + assertFalse(balance.isBalanced()); + + assertTrue(balance.getMetabolitesWithBadFormula().contains(s2)); + } + + @Test + public void getBalances() { + this.createBalanced(); + ReactionBalanceAnalysis balance = new ReactionBalanceAnalysis(reaction); + HashMap<String, Double> test = balance.getBalances(); + + HashMap<String, Double> ref = new HashMap<>(); + ref.put("O", 0.0); + ref.put("C", 0.0); + ref.put("H", 0.0); + + assertEquals(ref, test); + + this.createUnbalanced(); + balance = new ReactionBalanceAnalysis(reaction); + test = balance.getBalances(); + + ref = new HashMap<>(); + ref.put("O", 0.0); + ref.put("C", -3.0); + ref.put("H", 0.0); + + assertEquals(ref, test); + } + + @Test + public void getBalancesWithNull() { + this.createBalancedWithNull(); + ReactionBalanceAnalysis balance = new ReactionBalanceAnalysis(reaction); + HashMap<String, Double> test = balance.getBalances(); + + HashMap<String, Double> ref = new HashMap<>(); + ref.put("O", 0.0); + ref.put("C", 0.0); + ref.put("H", 0.0); + + assertEquals(ref, test); + } + + @Test + public void getBalancesWithBadFormula() { + this.createBalancedWithBadFormula(); + ReactionBalanceAnalysis balance = new ReactionBalanceAnalysis(reaction); + HashMap<String, Double> test = balance.getBalances(); + + HashMap<String, Double> ref = new HashMap<>(); + ref.put("O", 0.0); + ref.put("C", 0.0); + ref.put("H", 0.0); + + assertEquals(ref, test); + } + + @Test + public void isExchange() { + + this.createBalanced(); + + ReactionBalanceAnalysis balance = new ReactionBalanceAnalysis(reaction); + + assertFalse(balance.isExchange()); + + MetaboliteAttributes.setBoundaryCondition(s1, true); + + assertTrue(balance.isExchange()); + + MetaboliteAttributes.setBoundaryCondition(s1, false); + MetaboliteAttributes.setBoundaryCondition(p1, true); + + assertTrue(balance.isExchange()); + + network.removeRight(p1, cpt, reaction); + network.removeRight(p2, cpt, reaction); + + assertTrue(balance.isExchange()); + + + } +} \ No newline at end of file diff --git a/met4j-toolbox/pom.xml b/met4j-toolbox/pom.xml index 40ff14d3b98e646a682ef05091e9ddca9998f934..c656eead9842255ded4c788493b7f2d649c2b6b6 100644 --- a/met4j-toolbox/pom.xml +++ b/met4j-toolbox/pom.xml @@ -19,12 +19,6 @@ </properties> <dependencies> - <dependency> - <groupId>junit</groupId> - <artifactId>junit</artifactId> - <version>4.12</version> - <scope>test</scope> - </dependency> <dependency> <groupId>args4j</groupId> <artifactId>args4j</artifactId> @@ -60,6 +54,11 @@ <artifactId>met4j-mapping</artifactId> <version>1.2.0-SNAPSHOT</version> </dependency> + <dependency> + <groupId>fr.inrae.toulouse.metexplore</groupId> + <artifactId>met4j-reconstruction</artifactId> + <version>1.2.0-SNAPSHOT</version> + </dependency> <!-- https://mvnrepository.com/artifact/com.googlecode.json-simple/json-simple --> <dependency> <groupId>com.googlecode.json-simple</groupId> @@ -80,6 +79,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-shade-plugin</artifactId> + <version>3.2.4</version> <executions> <execution> <phase>package</phase> diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/SbmlSetIdsFromFile.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/SbmlSetIdsFromFile.java index 12def855d3df0696cbcf54cc2d79058eba2d8ef5..dae320521c936fa7e6ef9ed9a25def39052a7ef9 100644 --- a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/SbmlSetIdsFromFile.java +++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/attributes/SbmlSetIdsFromFile.java @@ -94,6 +94,7 @@ public class SbmlSetIdsFromFile extends AbstractSbmlSetAny { try { flag = setter.setAttributes(); } catch (Exception e) { + e.printStackTrace(); flag=false; } diff --git a/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/SbmlCheckBalance.java b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/SbmlCheckBalance.java new file mode 100644 index 0000000000000000000000000000000000000000..f01b4155296cec0f2ba0f7aa18da44c94df90d9c --- /dev/null +++ b/met4j-toolbox/src/main/java/fr/inrae/toulouse/metexplore/met4j_toolbox/reconstruction/SbmlCheckBalance.java @@ -0,0 +1,158 @@ +/* + * Copyright INRAE (2022) + * + * contact-metexplore@inrae.fr + * + * This software is a computer program whose purpose is to [describe + * functionalities and technical features of your software]. + * + * This software is governed by the CeCILL license under French law and + * abiding by the rules of distribution of free software. You can use, + * modify and/ or redistribute the software under the terms of the CeCILL + * license as circulated by CEA, CNRS and INRIA at the following URL + * "https://cecill.info/licences/Licence_CeCILL_V2.1-en.html". + * + * As a counterpart to the access to the source code and rights to copy, + * modify and redistribute granted by the license, users are provided only + * with a limited warranty and the software's author, the holder of the + * economic rights, and the successive licensors have only limited + * liability. + * + * In this respect, the user's attention is drawn to the risks associated + * with loading, using, modifying and/or developing or reproducing the + * software by the user in light of its specific status of free software, + * that may mean that it is complicated to manipulate, and that also + * therefore means that it is reserved for developers and experienced + * professionals having in-depth computer knowledge. Users are therefore + * encouraged to load and test the software's suitability as regards their + * requirements in conditions enabling the security of their systems and/or + * data to be ensured and, more generally, to use and operate it in the + * same conditions as regards security. + * + * The fact that you are presently reading this means that you have had + * knowledge of the CeCILL license and that you accept its terms. + * + */ +package fr.inrae.toulouse.metexplore.met4j_toolbox.reconstruction; + +import fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork; +import fr.inrae.toulouse.metexplore.met4j_core.biodata.utils.BioReactionUtils; +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_reconstruction.check.balance.NetworkBalanceAnalysis; +import fr.inrae.toulouse.metexplore.met4j_reconstruction.check.balance.ReactionBalanceAnalysis; +import fr.inrae.toulouse.metexplore.met4j_toolbox.generic.AbstractMet4jApplication; +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.util.HashMap; +import java.util.List; +import java.util.Set; + +import static fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumFormats.Sbml; +import static fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumFormats.Tsv; +import static fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumParameterTypes.InputFile; +import static fr.inrae.toulouse.metexplore.met4j_toolbox.generic.annotations.EnumParameterTypes.OutputFile; + +public class SbmlCheckBalance extends AbstractMet4jApplication { + + @Format(name = Sbml) + @ParameterType(name = InputFile) + @Option(name = "-sbml", usage = "Original sbml file", required = true) + public String sbml; + + @Format(name = Tsv) + @ParameterType(name = OutputFile) + @Option(name = "-out", usage = "[checkBalances.tsv] Output tabulated file (1st col: reaction id, 2nd col: " + + "boolean indicating if the reaction is balanced, 3rd col: atom balances, 4th col: metabolites with bad formula") + public String out = "checkBalances.tsv"; + private NetworkBalanceAnalysis analysis; + + public static void main(String[] args) { + SbmlCheckBalance app = new SbmlCheckBalance(); + + app.parseArguments(args); + + app.run(); + } + + private void run() { + + BioNetwork network = this.readSbml(); + + analysis = new NetworkBalanceAnalysis(network); + + try { + this.writeResults(); + } catch (IOException e) { + e.printStackTrace(); + System.err.println("[MET4J ERROR] Error while writing the results"); + } + + } + + private void writeResults() throws IOException { + + List<ReactionBalanceAnalysis> balances = analysis.getAllBalances(); + + FileWriter writer = new FileWriter(this.out); + + writer.write("#Id\tisBalanced\tisExchange\tformula\tatom balances\tmetabolites with bad formula\n"); + + for (ReactionBalanceAnalysis balance : balances) { + String id = balance.getReaction().getId(); + HashMap<String, Double> atomBalances = balance.getBalances(); + Set<String> metabolitesWithBadFormula = balance.getMetabolitesWithBadFormula().getIds(); + String formula = BioReactionUtils.getEquation(balance.getReaction(), false, true); + + writer.write(id + "\t" + balance.isBalanced() + "\t" + balance.isExchange() + "\t" + formula +"\t" + atomBalances + "\t" + (metabolitesWithBadFormula.size() > 0 ? metabolitesWithBadFormula : "") + "\n"); + } + + writer.close(); + + } + + /** + * <p>readSbml.</p> + * + * @return a {@link fr.inrae.toulouse.metexplore.met4j_core.biodata.BioNetwork} object. + */ + private BioNetwork readSbml() { + JsbmlReader reader = new JsbmlReader(this.sbml); + + BioNetwork bn = null; + try { + bn = reader.read(); + } catch (Met4jSbmlReaderException e) { + e.printStackTrace(); + System.err.println("Problem while reading the sbml file " + this.sbml); + System.exit(1); + } + + return bn; + + } + + @Override + public String getLabel() { + return this.getClass().getSimpleName(); + } + + @Override + public String getLongDescription() { + return this.getShortDescription()+"\n"+ + "A reaction is balanced if all its reactants have a chemical formula with a good syntax and if the " + + "quantity of each atom is the same in both sides of the reaction.\n" + + "For each reaction, indicates if the reaction is balanced, the list of the atoms and the sum of their quantity, and the list of the metabolites " + + "that don't have a correct chemical formula."; + } + + @Override + public String getShortDescription() { + return "Check balance of all the reactions in a SBML."; + } +} diff --git a/pom.xml b/pom.xml index 93cc4e6d4302573bfea467408ff461cb5c233175..929bc15ad538fc9a9486adf507d046796db45888 100644 --- a/pom.xml +++ b/pom.xml @@ -1,5 +1,6 @@ <?xml version="1.0" encoding="UTF-8"?> -<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> +<project xmlns="http://maven.apache.org/POM/4.0.0" xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" + xsi:schemaLocation="http://maven.apache.org/POM/4.0.0 http://maven.apache.org/xsd/maven-4.0.0.xsd"> <modelVersion>4.0.0</modelVersion> <groupId>fr.inrae.toulouse.metexplore</groupId> @@ -84,6 +85,7 @@ <plugin> <groupId>org.apache.maven.plugins</groupId> <artifactId>maven-compiler-plugin</artifactId> + <version>3.8.1</version> <configuration> <source>11</source> <target>11</target> @@ -173,6 +175,7 @@ <module>met4j-mathUtils</module> <module>met4j-graph</module> <module>met4j-mapping</module> + <module>met4j-reconstruction</module> <module>coverage</module> <module>met4j-toolbox</module> </modules> @@ -184,11 +187,17 @@ <version>3.0.0</version> <type>maven-plugin</type> </dependency> - <dependency> - <groupId>org.projectlombok</groupId> - <artifactId>lombok</artifactId> - <version>1.18.22</version> - <scope>provided</scope> - </dependency> + <dependency> + <groupId>org.projectlombok</groupId> + <artifactId>lombok</artifactId> + <version>1.18.22</version> + <scope>provided</scope> + </dependency> + <dependency> + <groupId>junit</groupId> + <artifactId>junit</artifactId> + <version>4.13.2</version> + <scope>test</scope> + </dependency> </dependencies> </project> \ No newline at end of file