From 8829f615d70950265efb4e112bab643cdf9ae10d Mon Sep 17 00:00:00 2001 From: Dario Date: Wed, 14 Aug 2024 17:55:34 +0200 Subject: [PATCH] rampage --- build.gradle | 42 +- ...Oparser.java => ECOParserCLILauncher.java} | 21 +- .../ucsd/sbrg/ModelPolisherCLILauncher.java | 127 ++--- .../edu/ucsd/sbrg/SBMLFixerCLILauncher.java | 106 ++++ ...tor.java => SBMLValidatorCLILauncher.java} | 2 +- src/main/java/edu/ucsd/sbrg/XHTMLBuilder.java | 84 --- .../sbrg/annotation/AbstractAnnotator.java | 19 +- .../sbrg/annotation/AnnotationsSorter.java | 6 +- .../ucsd/sbrg/annotation/IAnnotateSBases.java | 18 + .../ucsd/sbrg/annotation/IProcessNotes.java | 4 + .../annotation/adb/ADBReactionsAnnotator.java | 10 +- .../sbrg/annotation/adb/ADBSBMLAnnotator.java | 4 +- .../annotation/adb/ADBSpeciesAnnotator.java | 10 +- .../annotation/adb/AbstractADBAnnotator.java | 6 +- .../bigg/AbstractBiGGAnnotator.java | 5 +- .../annotation/bigg/BiGGCVTermAnnotator.java | 5 +- .../bigg/BiGGCompartmentsAnnotator.java | 3 +- .../bigg/BiGGDocumentNotesProcessor.java | 2 - .../annotation/bigg/BiGGModelAnnotator.java | 3 +- .../bigg/BiGGPublicationsAnnotator.java | 3 +- .../bigg/BiGGReactionsAnnotator.java | 47 +- .../annotation/bigg/BiGGSBMLAnnotator.java | 3 +- .../annotation/bigg/BiGGSpeciesAnnotator.java | 82 +-- .../annotation/bigg/fbc/BiGGFBCAnnotator.java | 3 +- .../bigg/fbc/BiGGGeneProductAnnotator.java | 26 +- .../ucsd/sbrg/db/PostgresConnectionPool.java | 7 +- .../java/edu/ucsd/sbrg/db/adb/AnnotateDB.java | 3 - .../java/edu/ucsd/sbrg/db/bigg/BiGGDB.java | 8 +- .../java/edu/ucsd/sbrg/db/bigg/BiGGId.java | 119 ++-- src/main/java/edu/ucsd/sbrg/eco/DAG.java | 2 +- src/main/java/edu/ucsd/sbrg/eco/Node.java | 4 +- .../ucsd/sbrg/fixing/CompartmentFixer.java | 20 + .../java/edu/ucsd/sbrg/fixing/IFixSBases.java | 17 + .../sbrg/fixing/IFixSpeciesReferences.java | 16 + .../java/edu/ucsd/sbrg/fixing/ModelFixer.java | 16 + .../edu/ucsd/sbrg/fixing/ReactionFixer.java | 38 ++ .../java/edu/ucsd/sbrg/fixing/SBMLFixer.java | 19 + .../edu/ucsd/sbrg/fixing/SpeciesFixer.java | 29 + .../sbrg/fixing/SpeciesReferenceFixer.java | 16 + .../fixing/ext/fbc/ListOfObjectivesFixer.java | 40 ++ .../sbrg/fixing/ext/fbc/ObjectiveFixer.java | 90 +++ .../sbrg/fixing/ext/groups/GroupsFixer.java | 35 ++ .../java/edu/ucsd/sbrg/io/CombineArchive.java | 10 +- .../edu/ucsd/sbrg/io/IReadModelsFromFile.java | 11 + .../java/edu/ucsd/sbrg/io/IWriteModels.java | 11 + .../edu/ucsd/sbrg/io/IWriteModelsToFile.java | 10 + .../java/edu/ucsd/sbrg/io/ModelReader.java | 12 +- .../ucsd/sbrg/io/ModelReaderException.java | 7 +- .../java/edu/ucsd/sbrg/io/ModelWriter.java | 15 +- .../java/edu/ucsd/sbrg/io/SBMLFileUtils.java | 24 +- .../java/edu/ucsd/sbrg/io/UpdateListener.java | 19 +- .../sbrg/io/parsers/cobra/COBRAUtils.java | 26 +- .../sbrg/io/parsers/cobra/GeneParser.java | 16 +- .../sbrg/io/parsers/cobra/MatlabFields.java | 16 +- .../sbrg/io/parsers/cobra/MatlabParser.java | 13 +- .../sbrg/io/parsers/cobra/ReactionParser.java | 86 ++- .../sbrg/io/parsers/cobra/SpeciesParser.java | 44 +- .../sbrg/io/parsers/json/JSONConverter.java | 129 +---- .../ucsd/sbrg/io/parsers/json/JSONParser.java | 118 ++-- .../io/parsers/json/mapping/Compartments.java | 7 +- .../io/parsers/json/mapping/Metabolite.java | 7 +- .../parameters/ADBAnnotationParameters.java | 1 - .../parameters/BiGGAnnotationParameters.java | 1 - .../sbrg/parameters/BiGGNotesParameters.java | 1 - .../parameters/CommandLineParameters.java | 1 - .../FluxObjectivesPolishingParameters.java | 3 - .../ModelPolisherOptions.java | 6 +- .../edu/ucsd/sbrg/parameters/Parameters.java | 11 +- .../sbrg/parameters/PolishingParameters.java | 2 - .../ReactionPolishingParameters.java | 1 - .../ucsd/sbrg/parameters/SBOParameters.java | 7 +- .../ucsd/sbrg/polishing/AbstractPolisher.java | 30 +- .../sbrg/polishing/AnnotationPolisher.java | 20 +- .../sbrg/polishing/CompartmentPolisher.java | 65 +-- .../sbrg/polishing/IPolishAnnotations.java | 9 + .../polishing/IPolishSBaseAttributes.java | 19 + .../ucsd/sbrg/polishing/IPolishSBases.java | 17 + .../polishing/IPolishSpeciesReferences.java | 17 + .../ucsd/sbrg/polishing/ModelPolisher.java | 18 +- ...{PolishingUtils.java => NamePolisher.java} | 25 +- .../sbrg/polishing/ParametersPolisher.java | 22 +- .../sbrg/polishing/ReactionsPolisher.java | 513 ++++-------------- .../edu/ucsd/sbrg/polishing/SBMLPolisher.java | 4 +- .../ucsd/sbrg/polishing/SpeciesPolisher.java | 151 ++---- .../polishing/SpeciesReferencesPolisher.java | 19 + .../edu/ucsd/sbrg/polishing/UnitPolisher.java | 5 +- .../ucsd/sbrg/polishing/fbc/FBCPolisher.java | 16 +- .../polishing/fbc/FBCReactionPolisher.java | 238 ++++++++ .../polishing/fbc/FluxObjectivesPolisher.java | 98 ---- .../GeneProductAssociationsProcessor.java | 34 +- .../polishing/fbc/GeneProductsPolisher.java | 57 +- .../polishing/fbc/ObjectivesPolisher.java | 75 +++ .../edu/ucsd/sbrg/reporting/IReportDiffs.java | 7 + .../ucsd/sbrg/reporting/IReportStatus.java | 7 + .../java/edu/ucsd/sbrg/resolver/Registry.java | 2 +- .../identifiersorg/IdentifiersOrg.java | 10 +- .../IdentifiersOrgRegistryParser.java | 7 +- .../identifiersorg/IdentifiersOrgURI.java | 3 +- .../IdentifiersOrgURIUtils.java | 6 +- .../ReactionNamePatterns.java | 2 +- src/main/java/edu/ucsd/sbrg/util/SBMLFix.java | 220 -------- .../sbrg/util/{ => ext/fbc}/GPRParser.java | 96 ++-- .../groups/GroupsUtils.java} | 4 +- .../sbrg/{ => validation}/ModelValidator.java | 29 +- .../ModelValidatorException.java | 2 +- .../edu/ucsd/sbrg/{bigg => }/about.html | 0 .../edu/ucsd/sbrg/bigg/ZBIT_ModelNotes.html | 107 ---- .../sbrg/bigg/ZBIT_SBMLDocumentNotes.html | 35 -- .../edu/ucsd/sbrg/polisher/Messages.xml | 2 +- .../edu/ucsd/sbrg/polisher/Messages_de.xml | 2 +- .../bigg/BiGGCompartmentsAnnotatorTest.java | 1 - .../annotation/bigg/BiGGDBContainerTest.java | 7 +- .../bigg/BiGGReactionsAnnotatorTest.java | 5 +- .../bigg/BiGGSBMLAnnotatorTest.java | 2 +- .../bigg/BiGGSpeciesAnnotatorTest.java | 1 - .../edu/ucsd/sbrg/db/bigg/BiGGIdTest.java | 67 +-- .../fbc/ListOfObjectivesFixerTest.java} | 48 +- .../io/parsers/cobra/MatlabParserTest.java | 4 +- .../sbrg/io/parsers/json/JSONParserTest.java | 36 +- .../sbrg/parameters/ParametersParserTest.java | 3 +- .../sbrg/polishing/ReactionsPolisherTest.java | 455 +++------------- .../sbrg/polishing/SpeciesPolisherTest.java | 59 +- .../ucsd/sbrg/polishing/UnitPolisherTest.java | 1 - .../fbc/FBCReactionPolisherTest.java | 238 ++++++++ .../polishing/fbc/ObjectivesPolisherTest.java | 53 ++ .../sbrg/validation/ModelValidatorTest.java | 26 + .../resources/edu/ucsd/sbrg}/e_coli_core.xml | 0 .../edu/ucsd/sbrg/io}/e_coli_core.json | 0 .../edu/ucsd/sbrg/io}/e_coli_core.mat | Bin 129 files changed, 2164 insertions(+), 2570 deletions(-) rename src/main/java/edu/ucsd/sbrg/{eco/ECOparser.java => ECOParserCLILauncher.java} (81%) create mode 100644 src/main/java/edu/ucsd/sbrg/SBMLFixerCLILauncher.java rename src/main/java/edu/ucsd/sbrg/{SBMLValidator.java => SBMLValidatorCLILauncher.java} (94%) delete mode 100644 src/main/java/edu/ucsd/sbrg/XHTMLBuilder.java create mode 100644 src/main/java/edu/ucsd/sbrg/annotation/IAnnotateSBases.java create mode 100644 src/main/java/edu/ucsd/sbrg/annotation/IProcessNotes.java create mode 100644 src/main/java/edu/ucsd/sbrg/fixing/CompartmentFixer.java create mode 100644 src/main/java/edu/ucsd/sbrg/fixing/IFixSBases.java create mode 100644 src/main/java/edu/ucsd/sbrg/fixing/IFixSpeciesReferences.java create mode 100644 src/main/java/edu/ucsd/sbrg/fixing/ModelFixer.java create mode 100644 src/main/java/edu/ucsd/sbrg/fixing/ReactionFixer.java create mode 100644 src/main/java/edu/ucsd/sbrg/fixing/SBMLFixer.java create mode 100644 src/main/java/edu/ucsd/sbrg/fixing/SpeciesFixer.java create mode 100644 src/main/java/edu/ucsd/sbrg/fixing/SpeciesReferenceFixer.java create mode 100644 src/main/java/edu/ucsd/sbrg/fixing/ext/fbc/ListOfObjectivesFixer.java create mode 100644 src/main/java/edu/ucsd/sbrg/fixing/ext/fbc/ObjectiveFixer.java create mode 100644 src/main/java/edu/ucsd/sbrg/fixing/ext/groups/GroupsFixer.java create mode 100644 src/main/java/edu/ucsd/sbrg/io/IReadModelsFromFile.java create mode 100644 src/main/java/edu/ucsd/sbrg/io/IWriteModels.java create mode 100644 src/main/java/edu/ucsd/sbrg/io/IWriteModelsToFile.java rename src/main/java/edu/ucsd/sbrg/{ => parameters}/ModelPolisherOptions.java (96%) create mode 100644 src/main/java/edu/ucsd/sbrg/polishing/IPolishAnnotations.java create mode 100644 src/main/java/edu/ucsd/sbrg/polishing/IPolishSBaseAttributes.java create mode 100644 src/main/java/edu/ucsd/sbrg/polishing/IPolishSBases.java create mode 100644 src/main/java/edu/ucsd/sbrg/polishing/IPolishSpeciesReferences.java rename src/main/java/edu/ucsd/sbrg/polishing/{PolishingUtils.java => NamePolisher.java} (67%) create mode 100644 src/main/java/edu/ucsd/sbrg/polishing/SpeciesReferencesPolisher.java create mode 100644 src/main/java/edu/ucsd/sbrg/polishing/fbc/FBCReactionPolisher.java delete mode 100644 src/main/java/edu/ucsd/sbrg/polishing/fbc/FluxObjectivesPolisher.java rename src/main/java/edu/ucsd/sbrg/polishing/{ => fbc}/GeneProductAssociationsProcessor.java (81%) create mode 100644 src/main/java/edu/ucsd/sbrg/polishing/fbc/ObjectivesPolisher.java create mode 100644 src/main/java/edu/ucsd/sbrg/reporting/IReportDiffs.java create mode 100644 src/main/java/edu/ucsd/sbrg/reporting/IReportStatus.java rename src/main/java/edu/ucsd/sbrg/{polishing => util}/ReactionNamePatterns.java (98%) delete mode 100644 src/main/java/edu/ucsd/sbrg/util/SBMLFix.java rename src/main/java/edu/ucsd/sbrg/util/{ => ext/fbc}/GPRParser.java (84%) rename src/main/java/edu/ucsd/sbrg/util/{SBMLUtils.java => ext/groups/GroupsUtils.java} (95%) rename src/main/java/edu/ucsd/sbrg/{ => validation}/ModelValidator.java (67%) rename src/main/java/edu/ucsd/sbrg/{ => validation}/ModelValidatorException.java (90%) rename src/main/resources/edu/ucsd/sbrg/{bigg => }/about.html (100%) delete mode 100644 src/main/resources/edu/ucsd/sbrg/bigg/ZBIT_ModelNotes.html delete mode 100644 src/main/resources/edu/ucsd/sbrg/bigg/ZBIT_SBMLDocumentNotes.html rename src/test/java/edu/ucsd/sbrg/{polishing/fbc/FluxObjectivesPolisherTest.java => fixing/fbc/ListOfObjectivesFixerTest.java} (69%) create mode 100644 src/test/java/edu/ucsd/sbrg/polishing/fbc/FBCReactionPolisherTest.java create mode 100644 src/test/java/edu/ucsd/sbrg/polishing/fbc/ObjectivesPolisherTest.java create mode 100644 src/test/java/edu/ucsd/sbrg/validation/ModelValidatorTest.java rename src/{main/resources/edu/ucsd/sbrg/bigg/models => test/resources/edu/ucsd/sbrg}/e_coli_core.xml (100%) rename src/{main/resources/edu/ucsd/sbrg/bigg/models => test/resources/edu/ucsd/sbrg/io}/e_coli_core.json (100%) rename src/{main/resources/edu/ucsd/sbrg/bigg/models => test/resources/edu/ucsd/sbrg/io}/e_coli_core.mat (100%) diff --git a/build.gradle b/build.gradle index c1044a15..88a1badc 100755 --- a/build.gradle +++ b/build.gradle @@ -79,17 +79,18 @@ repositories { // snapshot versions of artifacts (i.e. dependency JARs) // Sonatype is the company behind the Maven Central repository maven { url "https://oss.sonatype.org/content/repositories/snapshots" } - // resolve dependencies from a local directory - flatDir { - dirs "lib/de/zbit/SysBio/1390" + maven { + name "biodata-reposilite" + url "https://biodata.informatik.uni-halle.de/maven/releases" } + } /** ==== Dependencies ==== **/ // variables used in dependency definitions def jacksonVersion = "2.17.1" def jupiterVersion = "5.10.2" -def testContainersVersion = "1.19.8" +def testContainersVersion = "1.20.1" /* - `implementation`: Dependencies required for the main source set. @@ -99,28 +100,35 @@ def testContainersVersion = "1.19.8" - `testRuntimeOnly`: Dependencies required only at test runtime, not at compile time. */ dependencies { + // systems biology tools + implementation "de.zbit.SysBio:SysBio:1390" // reading, writing, and manipulating SBML files - implementation "org.sbml.jsbml:jsbml:1.6.1" - // local dependency for systems biology tools - implementation "de.zbit:SysBio:1390" - // official JDBC driver for PostgreSQL - implementation "org.postgresql:postgresql:42.7.3" + implementation("org.sbml.jsbml:jsbml:1.6.1") { + exclude group: "org.apache.logging.log4j", module: "log4j-core" + exclude group: "org.apache.logging.log4j", module: "log4j-slf4j-impl" + } // ontology support within BioJava implementation "org.biojava:biojava-ontology:7.1.1" + // handle Combine Archives (packages of biological models) + implementation "de.uni-rostock.sbi:CombineArchive:1.4.1" // interacting with MATLAB files implementation 'us.hebi.matlab.mat:mfl-core:0.5.15' + + // JDBC connection pool + implementation "com.zaxxer:HikariCP:5.1.0" + // https://mvnrepository.com/artifact/commons-io/commons-io + implementation group: 'commons-io', name: 'commons-io', version: '2.16.1' + // https://mvnrepository.com/artifact/org.apache.commons/commons-lang3 + implementation group: 'org.apache.commons', name: 'commons-lang3', version: '3.15.0' // JSON processor implementation "com.fasterxml.jackson.core:jackson-core:${jacksonVersion}" - // data binding for Jackson +// data binding for Jackson implementation "com.fasterxml.jackson.core:jackson-databind:${jacksonVersion}" // Java port of HTML Tidy, for cleaning up malformed HTML implementation "net.sf.jtidy:jtidy:r938" - // handle Combine Archives (packages of biological models) - implementation "de.uni-rostock.sbi:CombineArchive:1.4.1" - // JDBC connection pool - implementation "com.zaxxer:HikariCP:5.1.0" - - implementation 'com.opentable.components:otj-pg-embedded:1.0.1' + // official JDBC driver for PostgreSQL + implementation "org.postgresql:postgresql:42.7.3" + // Test implementation dependencies // API for writing tests with JUnit 5 testImplementation "org.junit.jupiter:junit-jupiter-api:${jupiterVersion}" @@ -133,6 +141,7 @@ dependencies { // runtime engine for executing tests with JUnit 5 testRuntimeOnly 'org.junit.platform:junit-platform-launcher:1.10.2' testRuntimeOnly "org.junit.jupiter:junit-jupiter-engine:${jupiterVersion}" + } /** === Configuration for pre-existing Tasks === **/ @@ -162,6 +171,7 @@ tasks.withType(JavaCompile).configureEach { // config for all test tasks tasks.withType(Test).configureEach { + environment "TESTCONTAINERS_RYUK_DISABLED", "true" useJUnitPlatform() testLogging { showStandardStreams = true diff --git a/src/main/java/edu/ucsd/sbrg/eco/ECOparser.java b/src/main/java/edu/ucsd/sbrg/ECOParserCLILauncher.java similarity index 81% rename from src/main/java/edu/ucsd/sbrg/eco/ECOparser.java rename to src/main/java/edu/ucsd/sbrg/ECOParserCLILauncher.java index 49c99df8..95df9dc3 100644 --- a/src/main/java/edu/ucsd/sbrg/eco/ECOparser.java +++ b/src/main/java/edu/ucsd/sbrg/ECOParserCLILauncher.java @@ -1,4 +1,4 @@ -package edu.ucsd.sbrg.eco; +package edu.ucsd.sbrg; import java.io.BufferedReader; import java.io.IOException; @@ -7,14 +7,19 @@ import java.text.ParseException; import java.util.Set; +import edu.ucsd.sbrg.eco.DAG; +import edu.ucsd.sbrg.eco.Node; import org.biojava.nbio.ontology.Ontology; import org.biojava.nbio.ontology.Term; import org.biojava.nbio.ontology.Triple; import org.biojava.nbio.ontology.io.OboParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; -public class ECOparser { +public class ECOParserCLILauncher { private static Ontology ontology; + private static final Logger logger = LoggerFactory.getLogger(ECOParserCLILauncher.class); /** * @see Issue 5 @@ -57,8 +62,8 @@ public static String getECOTermFromScore(int confidenceScore) { } - public static void main(String[] args) { - ECOparser.parseECO(); + public static void main(String[] args) throws IOException, ParseException { + ECOParserCLILauncher.parseECO(); } @@ -82,18 +87,16 @@ public static int getConfidenceScoreForTerm(String query) { } - public static void parseECO() { + public static void parseECO() throws IOException, ParseException { String ecoName = "Evidence and Conclusion Ontology"; String ecoDesc = "TODO"; OboParser parser = new OboParser(); - try (InputStream inputStream = ECOparser.class.getResourceAsStream("eco.obo"); - BufferedReader oboReader = new BufferedReader(new InputStreamReader(inputStream))) { + try (InputStream inputStream = ECOParserCLILauncher.class.getResourceAsStream("eco.obo"); + BufferedReader oboReader = new BufferedReader(new InputStreamReader(inputStream))) { ontology = parser.parseOBO(oboReader, ecoName, ecoDesc); Term rootTerm = ontology.getTerm("ECO:0000000"); DAG ontologyDAG = new DAG(rootTerm); traverse(ontologyDAG.getRoot()); - } catch (IOException | ParseException e) { - e.printStackTrace(); } } diff --git a/src/main/java/edu/ucsd/sbrg/ModelPolisherCLILauncher.java b/src/main/java/edu/ucsd/sbrg/ModelPolisherCLILauncher.java index f6cbd69b..19011db8 100644 --- a/src/main/java/edu/ucsd/sbrg/ModelPolisherCLILauncher.java +++ b/src/main/java/edu/ucsd/sbrg/ModelPolisherCLILauncher.java @@ -9,13 +9,11 @@ import java.net.URISyntaxException; import java.net.URL; import java.sql.SQLException; -import java.util.Calendar; -import java.util.LinkedList; +import java.util.*; import java.util.List; -import java.util.ResourceBundle; import java.util.concurrent.TimeUnit; -import java.util.logging.Logger; +import de.zbit.util.prefs.SBProperties; import edu.ucsd.sbrg.annotation.AnnotationException; import edu.ucsd.sbrg.annotation.adb.ADBSBMLAnnotator; import edu.ucsd.sbrg.annotation.bigg.BiGGSBMLAnnotator; @@ -23,12 +21,17 @@ import edu.ucsd.sbrg.parameters.CommandLineParameters; import edu.ucsd.sbrg.db.adb.AnnotateDB; import edu.ucsd.sbrg.db.bigg.BiGGDB; +import edu.ucsd.sbrg.parameters.ModelPolisherOptions; import edu.ucsd.sbrg.polishing.SBMLPolisher; import edu.ucsd.sbrg.reporting.PolisherProgressBar; import edu.ucsd.sbrg.reporting.ProgressInitialization; import edu.ucsd.sbrg.reporting.ProgressObserver; import edu.ucsd.sbrg.resolver.Registry; import edu.ucsd.sbrg.resolver.identifiersorg.IdentifiersOrg; +import edu.ucsd.sbrg.validation.ModelValidator; +import edu.ucsd.sbrg.validation.ModelValidatorException; +import org.apache.commons.io.FileUtils; +import org.apache.commons.lang3.tuple.Pair; import org.sbml.jsbml.Model; import org.sbml.jsbml.SBMLDocument; @@ -37,11 +40,12 @@ import de.zbit.util.ResourceManager; import de.zbit.util.logging.LogOptions; import de.zbit.util.prefs.KeyProvider; -import de.zbit.util.prefs.SBProperties; import edu.ucsd.sbrg.db.adb.AnnotateDBOptions; import edu.ucsd.sbrg.db.bigg.BiGGDBOptions; import org.sbml.jsbml.ext.fbc.FBCConstants; import org.sbml.jsbml.ext.fbc.FBCModelPlugin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The ModelPolisher class is the entry point of this application. @@ -68,7 +72,7 @@ public class ModelPolisherCLILauncher extends Launcher { private static final ResourceBundle baseBundle = ResourceManager.getBundle("edu.ucsd.sbrg.Messages"); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); - private static final Logger logger = Logger.getLogger(ModelPolisherCLILauncher.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(ModelPolisherCLILauncher.class); private CommandLineParameters parameters; private Registry registry; @@ -117,37 +121,39 @@ public void commandLineMode(AppConf appConf) { parameters = new CommandLineParameters(args); registry = new IdentifiersOrg(); - if (parameters.annotationParameters().biggAnnotationParameters().annotateWithBiGG()) { - this.bigg = new BiGGDB(parameters.annotationParameters().biggAnnotationParameters().dbParameters()); - } - - if (parameters.annotationParameters().adbAnnotationParameters().addADBAnnotations()) { - this.adb = new AnnotateDB(parameters.annotationParameters().adbAnnotationParameters().dbParameters()); - } - try { - var input = parameters.input(); - var output = parameters.output(); + validateIOParameters(); - // Check if the input exists, throw an exception if it does not - if (!input.exists()) { - throw new IOException(format(MESSAGES.getString("READ_FILE_ERROR"), - input.toString())); + if (parameters.annotationParameters().biggAnnotationParameters().annotateWithBiGG()) { + this.bigg = new BiGGDB(parameters.annotationParameters().biggAnnotationParameters().dbParameters()); } - // If the output is not a directory but the input is, log an error and return - if (!output.isDirectory() && input.isDirectory()) { - throw new IOException(format(MESSAGES.getString("WRITE_DIR_TO_FILE_ERROR"), - input.getAbsolutePath(), - output.getAbsolutePath())); + if (parameters.annotationParameters().adbAnnotationParameters().addADBAnnotations()) { + this.adb = new AnnotateDB(parameters.annotationParameters().adbAnnotationParameters().dbParameters()); } - // Ensure the output directory or file's parent directory exists - SBMLFileUtils.checkCreateOutDir(output); - - batchProcess(input, parameters.output()); + var inputFiles = FileUtils.listFiles(parameters.input(), new String[]{"xml", "sbml", "json", "mat"}, true); + List> inputOutputPairs = new ArrayList<>(); + + if (parameters.input().isDirectory()) { + for (var input: inputFiles) { + inputOutputPairs.add(Pair.of(input, SBMLFileUtils.getOutputFileName(input, parameters.output()))); + } + + // TODO: this is a placeholder for a parallel implementation + for (var pair: inputOutputPairs) { + try { + processFile(pair.getLeft(), pair.getRight()); + } catch (ModelReaderException e) { + logger.debug(format("Skipping unreadable file \"{0}\".", pair.getLeft())); + } + } + } + else { + processFile(parameters.input(), parameters.output()); + } - } catch (ModelReaderException | ModelValidatorException | ModelWriterException | IOException | + } catch (ModelValidatorException | ModelWriterException | IOException | AnnotationException e) { // TODO: produce some user-friendly output and log to a file that can be provided for trouble-shooting throw new RuntimeException(e); @@ -157,37 +163,37 @@ public void commandLineMode(AppConf appConf) { } catch (SQLException e) { // TODO: produce some user-friendly output and log to a file that can be provided for trouble-shooting throw new RuntimeException(e); + } catch (ModelReaderException e) { + throw new RuntimeException(e); } } + private void validateIOParameters() throws IOException { + var input = parameters.input(); + var output = parameters.output(); - /** - * Processes the specified input and output paths. If the input is a directory, it recursively processes each file within. - * - * @param input Path to the input file or directory to be processed. This should correspond to {@link CommandLineParameters#input()}. - * @param output Path to the output file or directory where processed files should be saved. This should correspond to {@link CommandLineParameters#output()}. - */ - private void batchProcess(File input, File output) throws ModelReaderException, ModelWriterException, ModelValidatorException, AnnotationException, SQLException { - // If the input is a directory, process each file within it - if (input.isDirectory()) { - File[] files = input.listFiles(); - - if (files == null || files.length < 1) { - logger.info(MESSAGES.getString("NO_FILES_ERROR")); - return; - } - // Recursively process each file in the directory - for (File file : files) { - File target = SBMLFileUtils.getOutputFileName(file, output); - batchProcess(file, target); - } - } else { - // NOTE: input is a single file, but output can be a file or a directory - // Adjust output file name if the output is a directory - var newOutput = output.isDirectory() ? SBMLFileUtils.getOutputFileName(input, output) : output; + // Check if the input exists, throw an exception if it does not + if (!input.exists()) { + throw new IOException(format(MESSAGES.getString("READ_FILE_ERROR"), + input.toString())); + } - processFile(input, newOutput); + // If the input is a directory but the output is not, exit with error + if (input.isDirectory() && !output.isDirectory()) { + throw new IOException(format(MESSAGES.getString("WRITE_DIR_TO_FILE_ERROR"), + input.getAbsolutePath(), + output.getAbsolutePath())); } + + // If the output is a directory but the input is not, exit with error + if (output.isDirectory() && !input.isDirectory()) { + throw new IOException(format("Output \"{0}\" is a directory, but Input \"{1}\" is not", + output.getAbsolutePath(), + input.getAbsolutePath())); + } + + // Ensure the output directory or file's parent directory exists + SBMLFileUtils.checkCreateOutDir(output); } @@ -195,14 +201,10 @@ private void processFile(File input, File output) throws ModelReaderException, M long startTime = System.currentTimeMillis(); SBMLDocument doc = new ModelReader(parameters.sboParameters(), registry).read(input); - // TODO: we should be doing better sanity checking here; e.g.: just validate the SBML - if (doc == null) return; + + // TODO: hier wäre es jetzt angebracht das Ding zu validieren, geht aber nicht, weil es keinen Validator in JSBML gibt + Model model = doc.getModel(); - if (model == null) { - logger.severe(MESSAGES.getString("MODEL_MISSING")); - // TODO: handle this better - throw new RuntimeException(MESSAGES.getString("MODEL_MISSING")); - } List polishingObservers = List.of(new PolisherProgressBar()); int count = getPolishingTaskCount(model); @@ -240,6 +242,7 @@ private void processFile(File input, File output) throws ModelReaderException, M output = new ModelWriter(parameters.outputType()).write(doc, output); + // TODO: das ist keine anständige Validierung! if (parameters.SBMLValidation()) { var mv = new ModelValidator(); // use offline validation diff --git a/src/main/java/edu/ucsd/sbrg/SBMLFixerCLILauncher.java b/src/main/java/edu/ucsd/sbrg/SBMLFixerCLILauncher.java new file mode 100644 index 00000000..6204def7 --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/SBMLFixerCLILauncher.java @@ -0,0 +1,106 @@ +/** + * + */ +package edu.ucsd.sbrg; + +import de.zbit.io.ZIPUtils; +import de.zbit.io.filefilter.SBFileFilter; +import de.zbit.util.ResourceManager; +import de.zbit.util.Utils; +import de.zbit.util.logging.LogUtil; +import edu.ucsd.sbrg.fixing.ext.fbc.ObjectiveFixer; +import edu.ucsd.sbrg.fixing.ext.groups.GroupsFixer; +import org.sbml.jsbml.ListOf; +import org.sbml.jsbml.Model; +import org.sbml.jsbml.Reaction; +import org.sbml.jsbml.SBMLDocument; +import org.sbml.jsbml.SBMLReader; +import org.sbml.jsbml.TidySBMLWriter; +import org.sbml.jsbml.ext.fbc.FBCConstants; +import org.sbml.jsbml.ext.fbc.FBCModelPlugin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import javax.xml.stream.XMLStreamException; +import java.io.File; +import java.io.IOException; +import java.text.MessageFormat; +import java.util.ResourceBundle; + +/** + * This is a stand-alone bug-fix program. It recursively traverses a directory + * of SBML files and applies fixes to each model found. The result is saved to + * a target directory, which can be in-place, i.e., identical to the input + * directory. Otherwise, an identical directory structure will be created within + * the target directory. + *

+ * This program became necessary as a temporary solution for invalid SBML models + * in BiGG database before a new version of {@link ModelPolisherCLILauncher} could be + * released. + *

+ * The methods in this class can also be used in other parts of ModelPolisher, + * and are used in fact. This class can become a collection of repair functions + * for invalid SBML models. + *

+ * Date: 2016-02-19 + * @author Andreas Dräger + */ +public class SBMLFixerCLILauncher { + + private static final Logger logger = LoggerFactory.getLogger(SBMLFixerCLILauncher.class); + private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); + + private static void batchProcess(File input, File output) { + if (!output.exists() && !output.isFile() && !(input.isFile() && input.getName().equals(output.getName()))) { + logger.info(MessageFormat.format(MESSAGES.getString("DIRECTORY_CREATED"), output.getAbsolutePath())); + output.mkdir(); + } + if (input.isFile()) { + if (SBFileFilter.isSBMLFile(input)) { + if (output.isDirectory()) { + String fName = input.getName(); + output = new File(Utils.ensureSlash(output.getAbsolutePath()) + fName); + } + try { + fixSBML(input, output); + } catch (XMLStreamException | IOException exc) { + logger.error(exc.getMessage()); + } + } + } else { + if (!output.isDirectory()) { + logger.error(MessageFormat.format(MESSAGES.getString("WRITE_TO_FILE_ERROR"), output.getAbsolutePath())); + } + for (File file : input.listFiles()) { + File target = new File(Utils.ensureSlash(output.getAbsolutePath()) + file.getName()); + batchProcess(file, target); + } + } + } + + + private static void fixSBML(File in, File out) throws XMLStreamException, IOException { + long time = System.currentTimeMillis(); + logger.info(MessageFormat.format(MESSAGES.getString("READ_FILE_INFO"), in.getAbsolutePath())); + SBMLDocument doc = SBMLReader.read(in); + Model model = doc.getModel(); + GroupsFixer.fixGroups(model); + FBCModelPlugin fbcPlug = (FBCModelPlugin) model.getExtension(FBCConstants.shortLabel); + if ((fbcPlug != null) && fbcPlug.isSetListOfObjectives()) { + ListOf listOfReactions = model.isSetListOfReactions() ? model.getListOfReactions() : null; + ObjectiveFixer.fixObjective(in.getAbsolutePath(), listOfReactions, fbcPlug, null, null); + } + logger.info(MessageFormat.format(MESSAGES.getString("WRITE_FILE_INFO"), out.getAbsolutePath())); + TidySBMLWriter.write(doc, out, ModelPolisherCLILauncher.class.getName(), "1.1", ' ', (short) 2); + String archive = out.getAbsolutePath() + ".gz"; + logger.info(MessageFormat.format("ARCHIVE {0}", archive)); + ZIPUtils.GZip(out.getAbsolutePath(), archive); + logger.info(MessageFormat.format("Done. Time elapsed: {0,number,integer} ms", System.currentTimeMillis() - time)); + } + + + public static void main(String[] args) { + LogUtil.initializeLogging("de.zbit", "edu.ucsd.sbrg"); + batchProcess(new File(args[0]), new File(args[1])); + } +} diff --git a/src/main/java/edu/ucsd/sbrg/SBMLValidator.java b/src/main/java/edu/ucsd/sbrg/SBMLValidatorCLILauncher.java similarity index 94% rename from src/main/java/edu/ucsd/sbrg/SBMLValidator.java rename to src/main/java/edu/ucsd/sbrg/SBMLValidatorCLILauncher.java index 9c64870b..b61adc69 100644 --- a/src/main/java/edu/ucsd/sbrg/SBMLValidator.java +++ b/src/main/java/edu/ucsd/sbrg/SBMLValidatorCLILauncher.java @@ -5,7 +5,7 @@ /** * @author Andreas Dräger */ -public class SBMLValidator { +public class SBMLValidatorCLILauncher { /** * @param args diff --git a/src/main/java/edu/ucsd/sbrg/XHTMLBuilder.java b/src/main/java/edu/ucsd/sbrg/XHTMLBuilder.java deleted file mode 100644 index f8caef3b..00000000 --- a/src/main/java/edu/ucsd/sbrg/XHTMLBuilder.java +++ /dev/null @@ -1,84 +0,0 @@ -package edu.ucsd.sbrg; - -import java.util.Map; - -/** - * @author Andreas Dräger - */ -public class XHTMLBuilder { - - /** - * - */ - private XHTMLBuilder() { - } - - - /** - */ - public static String table(Object[] header, Object[][] data, String caption, Map attributes) { - StringBuilder sb = new StringBuilder(); - sb.append(" entry : attributes.entrySet()) { - appendAttribute(sb, entry); - } - } - sb.append(">\n"); - if (caption != null) { - sb.append(""); - sb.append(caption); - sb.append("\n"); - } - if ((header != null) && (header.length > 0)) { - sb.append(""); - for (Object head : header) { - sb.append(""); - sb.append(head.toString()); - sb.append(""); - } - sb.append("\n"); - } - if (data != null) { - for (Object[] row : data) { - if ((row != null) && (row.length > 0)) { - sb.append(""); - for (Object entry : row) { - sb.append(""); - sb.append(entry.toString()); - sb.append(""); - } - sb.append("\n"); - } - } - } - sb.append("\n"); - return sb.toString(); - } - - - /** - */ - public static void appendAttribute(StringBuilder sb, Map.Entry entry) { - appendAttribute(sb, entry.getKey(), entry.getValue()); - } - - - /** - */ - public static void appendAttribute(StringBuilder sb, String key, String value) { - if ((!sb.isEmpty()) && (sb.charAt(sb.length() - 1) != ' ')) { - sb.append(' '); - } - sb.append(key); - sb.append("=\""); - sb.append(value); - sb.append('"'); - } - - public static String p(String content) { - return "

\n" + - content + - "\n

\n"; - } -} diff --git a/src/main/java/edu/ucsd/sbrg/annotation/AbstractAnnotator.java b/src/main/java/edu/ucsd/sbrg/annotation/AbstractAnnotator.java index 52b40734..ca7b06dc 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/AbstractAnnotator.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/AbstractAnnotator.java @@ -1,14 +1,11 @@ package edu.ucsd.sbrg.annotation; -import edu.ucsd.sbrg.reporting.ProgressObserver; -import edu.ucsd.sbrg.reporting.ProgressUpdate; -import edu.ucsd.sbrg.reporting.ReportType; +import edu.ucsd.sbrg.reporting.*; -import java.sql.SQLException; import java.util.ArrayList; import java.util.List; -public abstract class AbstractAnnotator { +public abstract class AbstractAnnotator implements IReportStatus, IReportDiffs { private final List observers; @@ -20,19 +17,15 @@ public AbstractAnnotator(List observers) { this.observers = observers; } - public void annotate(List elementsToAnnotate) throws SQLException { - throw new UnsupportedOperationException(); - } - - abstract public void annotate(SBMLElement elementToAnnotate) throws SQLException, AnnotationException; - - protected void statusReport(String text, Object element) { + @Override + public void statusReport(String text, Object element) { for (var o : observers) { o.update(new ProgressUpdate(text, element, ReportType.STATUS)); } } - protected void diffReport(String elementType, Object element1, Object element2) { + @Override + public void diffReport(String elementType, Object element1, Object element2) { for (var o : observers) { o.update(new ProgressUpdate(elementType, List.of(element1, element2), ReportType.DATA)); } diff --git a/src/main/java/edu/ucsd/sbrg/annotation/AnnotationsSorter.java b/src/main/java/edu/ucsd/sbrg/annotation/AnnotationsSorter.java index 37c8f8d6..9561191d 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/AnnotationsSorter.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/AnnotationsSorter.java @@ -5,16 +5,16 @@ import org.sbml.jsbml.Model; import org.sbml.jsbml.SBMLDocument; import org.sbml.jsbml.SBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.swing.tree.TreeNode; import java.util.*; -import java.util.logging.Logger; import static java.text.MessageFormat.format; public class AnnotationsSorter { - - static final Logger logger = Logger.getLogger(AnnotationsSorter.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(AnnotationsSorter.class); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); diff --git a/src/main/java/edu/ucsd/sbrg/annotation/IAnnotateSBases.java b/src/main/java/edu/ucsd/sbrg/annotation/IAnnotateSBases.java new file mode 100644 index 00000000..1f5b41fb --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/annotation/IAnnotateSBases.java @@ -0,0 +1,18 @@ +package edu.ucsd.sbrg.annotation; + +import org.sbml.jsbml.SBase; + +import java.sql.SQLException; +import java.util.List; + +public interface IAnnotateSBases { + + default void annotate(List elementsToAnnotate) throws SQLException, AnnotationException { + for (var element: elementsToAnnotate) { + annotate(element); + } + } + + void annotate(SBMLElement elementToAnnotate) throws SQLException, AnnotationException; + +} diff --git a/src/main/java/edu/ucsd/sbrg/annotation/IProcessNotes.java b/src/main/java/edu/ucsd/sbrg/annotation/IProcessNotes.java new file mode 100644 index 00000000..e15a3e4b --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/annotation/IProcessNotes.java @@ -0,0 +1,4 @@ +package edu.ucsd.sbrg.annotation; + +public interface IProcessNotes { +} diff --git a/src/main/java/edu/ucsd/sbrg/annotation/adb/ADBReactionsAnnotator.java b/src/main/java/edu/ucsd/sbrg/annotation/adb/ADBReactionsAnnotator.java index 4360aa4b..50f49af4 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/adb/ADBReactionsAnnotator.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/adb/ADBReactionsAnnotator.java @@ -1,7 +1,7 @@ package edu.ucsd.sbrg.annotation.adb; +import edu.ucsd.sbrg.annotation.IAnnotateSBases; import edu.ucsd.sbrg.parameters.ADBAnnotationParameters; -import edu.ucsd.sbrg.parameters.BiGGAnnotationParameters; import edu.ucsd.sbrg.db.adb.AnnotateDB; import edu.ucsd.sbrg.db.bigg.BiGGId; import org.sbml.jsbml.Reaction; @@ -11,7 +11,7 @@ import static edu.ucsd.sbrg.db.adb.AnnotateDBContract.Constants.BIGG_REACTION; -public class ADBReactionsAnnotator extends AbstractADBAnnotator { +public class ADBReactionsAnnotator extends AbstractADBAnnotator implements IAnnotateSBases { public ADBReactionsAnnotator(AnnotateDB adb, ADBAnnotationParameters parameters) { super(adb, parameters); @@ -27,10 +27,8 @@ public void annotate(List reactions) throws SQLException { @Override public void annotate(Reaction reaction) throws SQLException { String id = reaction.getId(); - Optional reactionId = BiGGId.createReactionId(id); - if (reactionId.isPresent()) { - addBQB_IS_AnnotationsFromADB(reaction.getAnnotation(), BIGG_REACTION, reactionId.get()); - } + var reactionId = BiGGId.createReactionId(id); + addBQB_IS_AnnotationsFromADB(reaction.getAnnotation(), BIGG_REACTION, reactionId); if ((reaction.getCVTermCount() > 0) && !reaction.isSetMetaId()) { reaction.setMetaId(reaction.getId()); } diff --git a/src/main/java/edu/ucsd/sbrg/annotation/adb/ADBSBMLAnnotator.java b/src/main/java/edu/ucsd/sbrg/annotation/adb/ADBSBMLAnnotator.java index 2d7f6fe3..936d75bf 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/adb/ADBSBMLAnnotator.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/adb/ADBSBMLAnnotator.java @@ -1,14 +1,14 @@ package edu.ucsd.sbrg.annotation.adb; +import edu.ucsd.sbrg.annotation.IAnnotateSBases; import edu.ucsd.sbrg.parameters.ADBAnnotationParameters; -import edu.ucsd.sbrg.parameters.BiGGAnnotationParameters; import edu.ucsd.sbrg.db.adb.AnnotateDB; import org.sbml.jsbml.Model; import org.sbml.jsbml.SBMLDocument; import java.sql.SQLException; -public class ADBSBMLAnnotator extends AbstractADBAnnotator { +public class ADBSBMLAnnotator extends AbstractADBAnnotator implements IAnnotateSBases { public ADBSBMLAnnotator(AnnotateDB adb, ADBAnnotationParameters parameters) { super(adb, parameters); diff --git a/src/main/java/edu/ucsd/sbrg/annotation/adb/ADBSpeciesAnnotator.java b/src/main/java/edu/ucsd/sbrg/annotation/adb/ADBSpeciesAnnotator.java index 55576af8..71121475 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/adb/ADBSpeciesAnnotator.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/adb/ADBSpeciesAnnotator.java @@ -1,7 +1,7 @@ package edu.ucsd.sbrg.annotation.adb; +import edu.ucsd.sbrg.annotation.IAnnotateSBases; import edu.ucsd.sbrg.parameters.ADBAnnotationParameters; -import edu.ucsd.sbrg.parameters.BiGGAnnotationParameters; import edu.ucsd.sbrg.db.adb.AnnotateDB; import edu.ucsd.sbrg.db.bigg.BiGGId; import org.sbml.jsbml.Species; @@ -11,7 +11,7 @@ import static edu.ucsd.sbrg.db.adb.AnnotateDBContract.Constants.BIGG_METABOLITE; -public class ADBSpeciesAnnotator extends AbstractADBAnnotator { +public class ADBSpeciesAnnotator extends AbstractADBAnnotator implements IAnnotateSBases { public ADBSpeciesAnnotator(AnnotateDB adb, ADBAnnotationParameters parameters) { super(adb, parameters); @@ -27,10 +27,8 @@ public void annotate(List species) throws SQLException { @Override public void annotate(Species species) throws SQLException { String id = species.getId(); - Optional metaboliteId = BiGGId.createMetaboliteId(id); - if (metaboliteId.isPresent()) { - addBQB_IS_AnnotationsFromADB(species.getAnnotation(), BIGG_METABOLITE, metaboliteId.get()); - } + var metaboliteId = BiGGId.createMetaboliteId(id); + addBQB_IS_AnnotationsFromADB(species.getAnnotation(), BIGG_METABOLITE, metaboliteId); if ((species.getCVTermCount() > 0) && !species.isSetMetaId()) { species.setMetaId(species.getId()); } diff --git a/src/main/java/edu/ucsd/sbrg/annotation/adb/AbstractADBAnnotator.java b/src/main/java/edu/ucsd/sbrg/annotation/adb/AbstractADBAnnotator.java index bdd78822..f9169eed 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/adb/AbstractADBAnnotator.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/adb/AbstractADBAnnotator.java @@ -1,8 +1,6 @@ package edu.ucsd.sbrg.annotation.adb; -import edu.ucsd.sbrg.annotation.AbstractAnnotator; import edu.ucsd.sbrg.parameters.ADBAnnotationParameters; -import edu.ucsd.sbrg.parameters.BiGGAnnotationParameters; import edu.ucsd.sbrg.db.adb.AnnotateDB; import edu.ucsd.sbrg.db.bigg.BiGGId; import org.sbml.jsbml.Annotation; @@ -11,7 +9,7 @@ import java.sql.SQLException; import java.util.*; -public abstract class AbstractADBAnnotator extends AbstractAnnotator { +public abstract class AbstractADBAnnotator { protected final AnnotateDB adb; protected final ADBAnnotationParameters parameters; @@ -22,8 +20,6 @@ public AbstractADBAnnotator(AnnotateDB adb, ADBAnnotationParameters parameters) this.parameters = parameters; } - public abstract void annotate(SBMLElement element) throws SQLException; - protected void addBQB_IS_AnnotationsFromADB(Annotation annotation, String type, BiGGId biggId) throws SQLException { CVTerm cvTerm = annotation.getListOfCVTerms().stream() .filter(term -> term.getQualifier() == CVTerm.Qualifier.BQB_IS) diff --git a/src/main/java/edu/ucsd/sbrg/annotation/bigg/AbstractBiGGAnnotator.java b/src/main/java/edu/ucsd/sbrg/annotation/bigg/AbstractBiGGAnnotator.java index 0cfacf35..92ff3204 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/bigg/AbstractBiGGAnnotator.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/bigg/AbstractBiGGAnnotator.java @@ -18,9 +18,8 @@ import java.util.Optional; import java.util.stream.Stream; -import static java.util.stream.Stream.concat; -public abstract class AbstractBiGGAnnotator extends AbstractAnnotator { +public abstract class AbstractBiGGAnnotator extends AbstractAnnotator { protected final BiGGDB bigg; protected final Registry registry; @@ -59,7 +58,7 @@ public Optional getBiGGIdFromResources(List resources, String ty var resolvedIdentifiersOrgUrisStream = resources.stream() .filter(r -> !registry.isValid(r)) - .map(registry::findRegistryUrlForOtherUrl) + .map(registry::resolveBackwards) .filter(Optional::isPresent) .map(Optional::get) .filter(registry::validRegistryUrlPrefix); diff --git a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGCVTermAnnotator.java b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGCVTermAnnotator.java index f6b9d796..a7d39b4e 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGCVTermAnnotator.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGCVTermAnnotator.java @@ -9,7 +9,6 @@ import java.sql.SQLException; import java.util.List; -import java.util.Optional; /** * Abstract class providing a framework for annotating SBML elements with Controlled Vocabulary (CV) Terms. @@ -17,7 +16,7 @@ * It includes methods to check the validity of BiGG IDs, add annotations to SBML elements, and specifically handle * annotations for Species and Reactions using data from BiGG and other databases. */ -public abstract class BiGGCVTermAnnotator extends AbstractBiGGAnnotator { +public abstract class BiGGCVTermAnnotator extends AbstractBiGGAnnotator { public BiGGCVTermAnnotator(BiGGDB bigg, BiGGAnnotationParameters parameters, Registry registry) { super(bigg, parameters, registry); @@ -34,7 +33,7 @@ public BiGGCVTermAnnotator(BiGGDB bigg, BiGGAnnotationParameters parameters, Reg * * @return Optional containing the valid BiGG ID or empty if the ID is invalid. */ - protected abstract Optional findBiGGId(T element) throws SQLException; + protected abstract BiGGId findBiGGId(T element) throws SQLException; // /** // * Adds annotations to an SBML node (either a Species or a Reaction) using a given BiGGId. diff --git a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGCompartmentsAnnotator.java b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGCompartmentsAnnotator.java index 97ac0450..47c2cb79 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGCompartmentsAnnotator.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGCompartmentsAnnotator.java @@ -1,5 +1,6 @@ package edu.ucsd.sbrg.annotation.bigg; +import edu.ucsd.sbrg.annotation.IAnnotateSBases; import edu.ucsd.sbrg.parameters.BiGGAnnotationParameters; import edu.ucsd.sbrg.resolver.Registry; import edu.ucsd.sbrg.resolver.identifiersorg.IdentifiersOrgURI; @@ -17,7 +18,7 @@ * It allows for the addition of both BiGG and SBO annotations to a compartment, and can also set the compartment's name * based on information retrieved from the BiGG database. */ -public class BiGGCompartmentsAnnotator extends AbstractBiGGAnnotator { +public class BiGGCompartmentsAnnotator extends AbstractBiGGAnnotator implements IAnnotateSBases { public BiGGCompartmentsAnnotator(BiGGDB bigg, BiGGAnnotationParameters parameters, Registry registry) { diff --git a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGDocumentNotesProcessor.java b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGDocumentNotesProcessor.java index 5cd56344..8a5a1533 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGDocumentNotesProcessor.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGDocumentNotesProcessor.java @@ -10,13 +10,11 @@ import java.io.*; import java.sql.SQLException; import java.util.*; -import java.util.logging.Logger; import static java.text.MessageFormat.format; public class BiGGDocumentNotesProcessor { - static final Logger logger = Logger.getLogger(BiGGDocumentNotesProcessor.class.getName()); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); private final BiGGAnnotationParameters parameters; diff --git a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGModelAnnotator.java b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGModelAnnotator.java index 3841e592..f8c7aaab 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGModelAnnotator.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGModelAnnotator.java @@ -1,5 +1,6 @@ package edu.ucsd.sbrg.annotation.bigg; +import edu.ucsd.sbrg.annotation.IAnnotateSBases; import edu.ucsd.sbrg.db.bigg.BiGGDB; import edu.ucsd.sbrg.parameters.BiGGAnnotationParameters; import edu.ucsd.sbrg.resolver.Registry; @@ -23,7 +24,7 @@ * {@link Compartment}, {@link Species}, {@link Reaction}, and {@link GeneProduct}. * The annotations can include taxonomy information, database references, and meta identifiers. */ -public class BiGGModelAnnotator extends AbstractBiGGAnnotator { +public class BiGGModelAnnotator extends AbstractBiGGAnnotator implements IAnnotateSBases { public static final String REF_SEQ_ACCESSION_NUMBER_PATTERN = "^(((AC|AP|NC|NG|NM|NP|NR|NT|NW|XM|XP|XR|YP|ZP)_\\d+)|(NZ_[A-Z]{2,4}\\d+))(\\.\\d+)?$"; public static final String GENOME_ASSEMBLY_ID_PATTERN = "^GC[AF]_[0-9]{9}\\.[0-9]+$"; diff --git a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGPublicationsAnnotator.java b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGPublicationsAnnotator.java index b0134cc6..bcc10a20 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGPublicationsAnnotator.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGPublicationsAnnotator.java @@ -1,5 +1,6 @@ package edu.ucsd.sbrg.annotation.bigg; +import edu.ucsd.sbrg.annotation.IAnnotateSBases; import edu.ucsd.sbrg.db.bigg.BiGGDB; import edu.ucsd.sbrg.db.bigg.Publication; import edu.ucsd.sbrg.parameters.BiGGAnnotationParameters; @@ -12,7 +13,7 @@ import java.sql.SQLException; import java.util.List; -public class BiGGPublicationsAnnotator extends AbstractBiGGAnnotator { +public class BiGGPublicationsAnnotator extends AbstractBiGGAnnotator implements IAnnotateSBases { public BiGGPublicationsAnnotator(BiGGDB bigg, BiGGAnnotationParameters parameters, Registry registry, List observers) { super(bigg, parameters, registry, observers); diff --git a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGReactionsAnnotator.java b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGReactionsAnnotator.java index df0cd756..48b92327 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGReactionsAnnotator.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGReactionsAnnotator.java @@ -1,16 +1,16 @@ package edu.ucsd.sbrg.annotation.bigg; import de.zbit.util.ResourceManager; +import edu.ucsd.sbrg.annotation.IAnnotateSBases; import edu.ucsd.sbrg.parameters.BiGGAnnotationParameters; import edu.ucsd.sbrg.parameters.SBOParameters; import edu.ucsd.sbrg.db.bigg.BiGGId; import edu.ucsd.sbrg.resolver.Registry; -import edu.ucsd.sbrg.polishing.PolishingUtils; import edu.ucsd.sbrg.db.bigg.BiGGDB; import edu.ucsd.sbrg.reporting.ProgressObserver; import edu.ucsd.sbrg.resolver.identifiersorg.IdentifiersOrgURI; -import edu.ucsd.sbrg.util.GPRParser; -import edu.ucsd.sbrg.util.SBMLUtils; +import edu.ucsd.sbrg.util.ext.fbc.GPRParser; +import edu.ucsd.sbrg.util.ext.groups.GroupsUtils; import org.sbml.jsbml.CVTerm; import org.sbml.jsbml.CVTerm.Qualifier; import org.sbml.jsbml.Model; @@ -18,10 +18,11 @@ import org.sbml.jsbml.ext.groups.Group; import org.sbml.jsbml.ext.groups.GroupsConstants; import org.sbml.jsbml.ext.groups.GroupsModelPlugin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.sql.SQLException; import java.util.*; -import java.util.logging.Logger; import java.util.stream.Collectors; /** @@ -31,9 +32,9 @@ * the reaction's name, SBO term, and additional annotations. It also processes gene reaction rules and * subsystem information associated with the reaction. */ -public class BiGGReactionsAnnotator extends BiGGCVTermAnnotator { +public class BiGGReactionsAnnotator extends BiGGCVTermAnnotator implements IAnnotateSBases { - static final Logger logger = Logger.getLogger(BiGGReactionsAnnotator.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(BiGGReactionsAnnotator.class); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); private static boolean triggeredSubsystemWarning = false; @@ -74,13 +75,11 @@ public void annotate(Reaction reaction) throws SQLException { statusReport("Annotating Reactions (4/5) ", reaction); // Attempt to retrieve a BiGG ID for the reaction, either directly from the reaction ID or through associated annotations var biggId = findBiGGId(reaction); - if (biggId.isPresent()) { - setName(reaction, biggId.get()); // Set the reaction's name based on the BiGG ID - setSBOTerm(reaction, biggId.get()); // Assign the appropriate SBO term based on the BiGG ID - addAnnotations(reaction, biggId.get()); // Add additional annotations related to the BiGG ID - parseGeneReactionRules(reaction, biggId.get()); // Parse and process gene reaction rules associated with the BiGG ID - parseSubsystems(reaction, biggId.get()); // Convert subsystem information into corresponding groups based on the BiGG ID - } + setName(reaction, biggId); // Set the reaction's name based on the BiGG ID + setSBOTerm(reaction, biggId); // Assign the appropriate SBO term based on the BiGG ID + addAnnotations(reaction, biggId); // Add additional annotations related to the BiGG ID + parseGeneReactionRules(reaction, biggId); // Parse and process gene reaction rules associated with the BiGG ID + parseSubsystems(reaction, biggId); // Convert subsystem information into corresponding groups based on the BiGG ID } /** @@ -94,7 +93,7 @@ public void annotate(Reaction reaction) throws SQLException { * @return An {@link Optional} containing the BiGG ID if found or created successfully, otherwise {@link Optional#empty()} */ @Override - public Optional findBiGGId(Reaction reaction) throws SQLException { + public BiGGId findBiGGId(Reaction reaction) throws SQLException { String id = reaction.getId(); // Check if the reaction ID matches the expected BiGG ID format and exists in the database boolean isBiGGid = bigg.isReaction(id); @@ -104,7 +103,7 @@ public Optional findBiGGId(Reaction reaction) throws SQLException { .stream() .filter(cvTerm -> cvTerm.getQualifier() == Qualifier.BQB_IS) .flatMap(term -> term.getResources().stream()) - .map(registry::findRegistryUrlForOtherUrl) + .map(registry::resolveBackwards) .flatMap(Optional::stream) .map(bigg::getBiggIdsForReactionForeignId) .flatMap(Collection::stream) @@ -152,17 +151,15 @@ private boolean matchingCompartments(Reaction reaction, BiGGDB.ForeignReaction f } /** - * Sets the name of the reaction based on the provided BiGGId. It retrieves the reaction name using the abbreviation - * from the BiGGId, polishes the name, and updates the reaction's name if the new name is different from the current name. + * Sets the name of the reaction based on the provided BiGGId. It retrieves the reaction name + * using the abbreviation from the BiGGId, polishes the name, and updates the reaction's name + * if the new name is different from the current name. * * @param biggId The BiGGId object containing the abbreviation used to fetch and potentially update the reaction's name. */ public void setName(Reaction reaction, BiGGId biggId) throws SQLException { String abbreviation = biggId.getAbbreviation(); - bigg.getReactionName(abbreviation) - .filter(name -> !name.equals(reaction.getName())) - .map(PolishingUtils::polishName) - .ifPresent(reaction::setName); + bigg.getReactionName(abbreviation).ifPresent(reaction::setName); } /** @@ -179,7 +176,7 @@ public void setSBOTerm(Reaction reaction, BiGGId biggId) throws SQLException { if (!reaction.isSetSBOTerm()) { if (bigg.isPseudoreaction(abbreviation)) { reaction.setSBOTerm(631); - } else if (!sboParameters.omitGenericTerms()) { + } else if (sboParameters.addGenericTerms()) { reaction.setSBOTerm(375); // generic process } } @@ -245,7 +242,7 @@ public void parseGeneReactionRules(Reaction reaction, BiGGId biggId) throws SQLE String abbreviation = biggId.getAbbreviation(); List geneReactionRules = bigg.getGeneReactionRule(abbreviation, reaction.getModel().getId()); for (String geneReactionRule : geneReactionRules) { - GPRParser.parseGPR(reaction, geneReactionRule, sboParameters.omitGenericTerms()); + GPRParser.parseGPR(reaction, geneReactionRule, sboParameters.addGenericTerms()); } } @@ -270,7 +267,7 @@ private void parseSubsystems(Reaction reaction, BiGGId biggId) throws SQLExcepti } else { if (!triggeredSubsystemWarning) { triggeredSubsystemWarning = true; - logger.warning(MESSAGES.getString("SUBSYSTEM_MODEL_NOT_BIGG")); + logger.debug(MESSAGES.getString("SUBSYSTEM_MODEL_NOT_BIGG")); } subsystems = bigg.getSubsystemsForReaction(biggId.getAbbreviation()); } @@ -303,7 +300,7 @@ private void parseSubsystems(Reaction reaction, BiGGId biggId) throws SQLExcepti group.setSBOTerm(633); // subsystem groupForName.put(subsystem, group); } - SBMLUtils.createSubsystemLink(reaction, group.createMember()); + GroupsUtils.createSubsystemLink(reaction, group.createMember()); } } } diff --git a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGSBMLAnnotator.java b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGSBMLAnnotator.java index 12cb7753..4e5c3554 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGSBMLAnnotator.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGSBMLAnnotator.java @@ -4,6 +4,7 @@ import java.util.List; import edu.ucsd.sbrg.annotation.AnnotationException; +import edu.ucsd.sbrg.annotation.IAnnotateSBases; import edu.ucsd.sbrg.parameters.BiGGAnnotationParameters; import edu.ucsd.sbrg.parameters.SBOParameters; import edu.ucsd.sbrg.annotation.AnnotationsSorter; @@ -23,7 +24,7 @@ * @author Thomas Zajac * This code runs only, if ANNOTATE_WITH_BIGG is true */ -public class BiGGSBMLAnnotator extends AbstractBiGGAnnotator { +public class BiGGSBMLAnnotator extends AbstractBiGGAnnotator implements IAnnotateSBases { private final SBOParameters sboParameters; diff --git a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGSpeciesAnnotator.java b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGSpeciesAnnotator.java index 578087ad..9aacaa6a 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGSpeciesAnnotator.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/bigg/BiGGSpeciesAnnotator.java @@ -1,11 +1,10 @@ package edu.ucsd.sbrg.annotation.bigg; import de.zbit.util.ResourceManager; -import de.zbit.util.Utils; +import edu.ucsd.sbrg.annotation.IAnnotateSBases; import edu.ucsd.sbrg.parameters.BiGGAnnotationParameters; import edu.ucsd.sbrg.parameters.SBOParameters; import edu.ucsd.sbrg.db.bigg.BiGGId; -import edu.ucsd.sbrg.polishing.PolishingUtils; import edu.ucsd.sbrg.db.bigg.BiGGDB; import edu.ucsd.sbrg.reporting.ProgressObserver; import edu.ucsd.sbrg.resolver.Registry; @@ -14,10 +13,11 @@ import org.sbml.jsbml.CVTerm.Qualifier; import org.sbml.jsbml.ext.fbc.FBCConstants; import org.sbml.jsbml.ext.fbc.FBCSpeciesPlugin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.sql.SQLException; import java.util.*; -import java.util.logging.Logger; import java.util.stream.Collectors; import static edu.ucsd.sbrg.db.bigg.BiGGDBContract.Constants.TYPE_SPECIES; @@ -30,9 +30,9 @@ * the species' name, SBO term, and additional annotations. It also sets the chemical formula and charge * for the species using FBC (Flux Balance Constraints) extensions. */ -public class BiGGSpeciesAnnotator extends BiGGCVTermAnnotator { +public class BiGGSpeciesAnnotator extends BiGGCVTermAnnotator implements IAnnotateSBases { - static final Logger logger = Logger.getLogger(BiGGSpeciesAnnotator.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(BiGGSpeciesAnnotator.class); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); private final SBOParameters sboParameters; @@ -70,13 +70,11 @@ public void annotate(List species) throws SQLException { @Override public void annotate(Species species) throws SQLException { // Retrieve the BiGGId for the species, either from its URI list or its direct ID - Optional biGGId = findBiGGId(species); - if (biGGId.isPresent()) { - setName(species, biGGId.get()); // Set the species name based on the BiGGId - setSBOTerm(species, biGGId.get()); // Assign the appropriate SBO term - addAnnotations(species, biGGId.get()); // Add database cross-references and other annotations - FBCSetFormulaCharge(species, biGGId.get()); // Set the chemical formula and charge - }; + var biGGId = findBiGGId(species); + setName(species, biGGId); // Set the species name based on the BiGGId + setSBOTerm(species, biGGId); // Assign the appropriate SBO term + addAnnotations(species, biGGId); // Add database cross-references and other annotations + FBCSetFormulaCharge(species, biGGId); // Set the chemical formula and charge } @@ -88,30 +86,35 @@ public void annotate(Species species) throws SQLException { * @return An {@link Optional} containing the BiGGId if a valid one is found or created, otherwise {@link Optional#empty()} */ @Override - public Optional findBiGGId(Species species) throws SQLException { + public BiGGId findBiGGId(Species species) throws SQLException { // Attempt to create a BiGGId from the species ID - Optional metaboliteId = BiGGId.createMetaboliteId(species.getId()); + var metaboliteId = BiGGId.createMetaboliteId(species.getId()); + // Check if the created BiGGId is valid, if not, try to find a BiGGId from annotations - if (metaboliteId.isPresent()) { - boolean isBiGGid = bigg.isMetabolite(metaboliteId.get().getAbbreviation()); - if (!isBiGGid) { - // Collect all resources from CVTerms that qualify as BQB_IS - // Attempt to retrieve a BiGGId from the collected resources - return getBiGGIdFromResources(species.getAnnotation().getListOfCVTerms().stream() - .filter(cvTerm -> cvTerm.getQualifier() == Qualifier.BQB_IS) - .flatMap(term -> term.getResources().stream()) - .toList(), TYPE_SPECIES); + boolean isBiGGid = bigg.isMetabolite(metaboliteId.getAbbreviation()); + + if (!isBiGGid) { + // Collect all resources from CVTerms that qualify as BQB_IS + // Attempt to retrieve a BiGGId from the collected resources + var biggIdFromResources = getBiGGIdFromResources( + species.getAnnotation().getListOfCVTerms() + .stream() + .filter(cvTerm -> cvTerm.getQualifier() == Qualifier.BQB_IS) + .flatMap(term -> term.getResources().stream()) + .toList(), + TYPE_SPECIES); + if (biggIdFromResources.isPresent()) { + return biggIdFromResources.get(); } - // Return the found BiGGId or the originally created one if no new ID was found - return metaboliteId.map(BiGGId::toBiGGId).map(BiGGId::createMetaboliteId).orElse(metaboliteId); } - return Optional.empty(); + return metaboliteId; } /** - * Updates the name of the species based on data retrieved from the BiGG Knowledgebase. The species name is set only if it - * has not been previously set or if the current name follows a default format that combines the BiGGId abbreviation and + * Updates the name of the species based on data retrieved from the BiGG Knowledgebase. + * The species name is set only if it has not been previously set or if the current name + * follows a default format that combines the BiGGId abbreviation and * compartment code. This method relies on the availability of a valid {@link BiGGId} for the species. * * @param biggId The {@link BiGGId} associated with the species, used to fetch the component name from the BiGG database. @@ -119,7 +122,7 @@ public Optional findBiGGId(Species species) throws SQLException { public void setName(Species species, BiGGId biggId) throws SQLException { if (!species.isSetName() || species.getName().equals(format("{0}_{1}", biggId.getAbbreviation(), biggId.getCompartmentCode()))) { - bigg.getComponentName(biggId).map(PolishingUtils::polishName).ifPresent(species::setName); + bigg.getComponentName(biggId).ifPresent(species::setName); } } @@ -128,7 +131,7 @@ public void setName(Species species, BiGGId biggId) throws SQLException { * Assigns the SBO term to a species based on its component type as determined from the BiGG database. * The component type can be a metabolite, protein, or a generic material entity. If the component type is not explicitly * identified in the BiGG database, the species is annotated as a generic material entity unless the configuration - * explicitly omits such generic terms (controlled by {@link SBOParameters#omitGenericTerms()}). + * explicitly omits such generic terms (controlled by {@link SBOParameters#addGenericTerms()}). * * @param biggId The {@link BiGGId} associated with the species, used to determine the component type from the BiGG database. */ @@ -142,13 +145,13 @@ private void setSBOTerm(Species species, BiGGId biggId) throws SQLException { species.setSBOTerm(SBO.getProtein()); // Assign SBO term for proteins. break; default: - if (!sboParameters.omitGenericTerms()) { + if (sboParameters.addGenericTerms()) { species.setSBOTerm(SBO.getMaterialEntity()); // Assign SBO term for generic material entities. } break; } }, () -> { - if (!sboParameters.omitGenericTerms()) { + if (sboParameters.addGenericTerms()) { species.setSBOTerm(SBO.getMaterialEntity()); // Default SBO term assignment when no specific type is found. } }); @@ -226,13 +229,7 @@ private void FBCSetFormulaCharge(Species species, BiGGId biggId) throws SQLExcep if ((!isBiGGModel || chemicalFormula.isEmpty()) && compartmentNonEmpty) { chemicalFormula = bigg.getChemicalFormulaByCompartment(biggId.getAbbreviation(), compartmentCode); } - chemicalFormula.ifPresent(formula -> { - try { - fbcSpecPlug.setChemicalFormula(formula); - } catch (IllegalArgumentException exc) { - logger.severe(format(MESSAGES.getString("CHEM_FORMULA_INVALID"), Utils.getMessage(exc))); - } - }); + chemicalFormula.ifPresent(fbcSpecPlug::setChemicalFormula); } Optional chargeFromBiGG = Optional.empty(); if (isBiGGModel) { @@ -241,8 +238,11 @@ private void FBCSetFormulaCharge(Species species, BiGGId biggId) throws SQLExcep chargeFromBiGG = bigg.getChargeByCompartment(biggId.getAbbreviation(), biggId.getCompartmentCode()); } if (species.isSetCharge()) { - chargeFromBiGG.filter(charge -> charge != species.getCharge()).ifPresent(charge -> logger.warning( - format(MESSAGES.getString("CHARGE_CONTRADICTION"), charge, species.getCharge(), species.getId()))); + chargeFromBiGG + .filter(charge -> charge != species.getCharge()) + .ifPresent(charge -> + logger.debug(format(MESSAGES.getString("CHARGE_CONTRADICTION"), + charge, species.getCharge(), species.getId()))); species.unsetCharge(); } chargeFromBiGG.filter(charge -> charge != 0).ifPresent(fbcSpecPlug::setCharge); diff --git a/src/main/java/edu/ucsd/sbrg/annotation/bigg/fbc/BiGGFBCAnnotator.java b/src/main/java/edu/ucsd/sbrg/annotation/bigg/fbc/BiGGFBCAnnotator.java index ee688780..9db7d7c2 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/bigg/fbc/BiGGFBCAnnotator.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/bigg/fbc/BiGGFBCAnnotator.java @@ -1,5 +1,6 @@ package edu.ucsd.sbrg.annotation.bigg.fbc; +import edu.ucsd.sbrg.annotation.IAnnotateSBases; import edu.ucsd.sbrg.parameters.BiGGAnnotationParameters; import edu.ucsd.sbrg.annotation.bigg.AbstractBiGGAnnotator; import edu.ucsd.sbrg.db.bigg.BiGGDB; @@ -12,7 +13,7 @@ import java.sql.SQLException; import java.util.List; -public class BiGGFBCAnnotator extends AbstractBiGGAnnotator { +public class BiGGFBCAnnotator extends AbstractBiGGAnnotator implements IAnnotateSBases { public BiGGFBCAnnotator(BiGGDB bigg, BiGGAnnotationParameters parameters, Registry registry, List observers) { super(bigg, parameters, registry, observers); diff --git a/src/main/java/edu/ucsd/sbrg/annotation/bigg/fbc/BiGGGeneProductAnnotator.java b/src/main/java/edu/ucsd/sbrg/annotation/bigg/fbc/BiGGGeneProductAnnotator.java index 69931f3d..cd44429e 100644 --- a/src/main/java/edu/ucsd/sbrg/annotation/bigg/fbc/BiGGGeneProductAnnotator.java +++ b/src/main/java/edu/ucsd/sbrg/annotation/bigg/fbc/BiGGGeneProductAnnotator.java @@ -1,6 +1,7 @@ package edu.ucsd.sbrg.annotation.bigg.fbc; import de.zbit.util.ResourceManager; +import edu.ucsd.sbrg.annotation.IAnnotateSBases; import edu.ucsd.sbrg.parameters.BiGGAnnotationParameters; import edu.ucsd.sbrg.annotation.bigg.BiGGCVTermAnnotator; import edu.ucsd.sbrg.db.bigg.BiGGId; @@ -11,12 +12,13 @@ import org.sbml.jsbml.CVTerm; import org.sbml.jsbml.CVTerm.Qualifier; import org.sbml.jsbml.ext.fbc.GeneProduct; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.sql.SQLException; import java.util.List; import java.util.Optional; import java.util.ResourceBundle; -import java.util.logging.Logger; import java.util.stream.Collectors; import static edu.ucsd.sbrg.db.bigg.BiGGDBContract.Constants.TYPE_GENE_PRODUCT; @@ -27,9 +29,9 @@ * This class extends {@link BiGGCVTermAnnotator} and specifically handles the annotation of {@link GeneProduct} instances. * It includes methods to validate gene product IDs, retrieve and set labels, and add annotations based on BiGG IDs. */ -public class BiGGGeneProductAnnotator extends BiGGCVTermAnnotator { +public class BiGGGeneProductAnnotator extends BiGGCVTermAnnotator implements IAnnotateSBases { - static final Logger logger = Logger.getLogger(BiGGGeneProductAnnotator.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(BiGGGeneProductAnnotator.class); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); public static final String BIGG_GENE_ID_PATTERN = "^(G_)?([a-zA-Z][a-zA-Z0-9_]+)(?:_([a-z][a-z0-9]?))?(?:_([A-Z][A-Z0-9]?))?$"; @@ -69,19 +71,19 @@ public void annotate(List geneProducts) throws SQLException { */ @Override public void annotate(GeneProduct geneProduct) throws SQLException { - Optional biggId = findBiGGId(geneProduct); + var biggId = findBiGGId(geneProduct); - Optional label = biggId.map(id -> getLabel(geneProduct, id)); + String label = getLabel(geneProduct, biggId); if (label.isEmpty()) { return; } gprAnnotator.update(geneProduct); - addAnnotations(geneProduct, biggId.get()); + addAnnotations(geneProduct, biggId); if (geneProduct.getCVTermCount() > 0) { - geneProduct.setMetaId(biggId.get().toBiGGId()); + geneProduct.setMetaId(biggId.toBiGGId()); } - setGPLabelName(geneProduct, label.get()); + setGPLabelName(geneProduct, label); } @@ -96,7 +98,7 @@ public void annotate(GeneProduct geneProduct) throws SQLException { * @return An {@link Optional} containing the validated or retrieved BiGG ID, or an empty Optional if no valid ID is found. */ @Override - public Optional findBiGGId(GeneProduct geneProduct) throws SQLException { + public BiGGId findBiGGId(GeneProduct geneProduct) throws SQLException { String id = geneProduct.getId(); boolean isBiGGid = id.matches(BIGG_GENE_ID_PATTERN); if (!isBiGGid) { @@ -108,7 +110,7 @@ public Optional findBiGGId(GeneProduct geneProduct) throws SQLException // Attempt to update the ID with a valid BiGG ID from the resources, if available Optional biGGIdFromResources = getBiGGIdFromResources(resources, TYPE_GENE_PRODUCT); if (biGGIdFromResources.isPresent()) { - return biGGIdFromResources; + return biGGIdFromResources.get(); } } // Create and return a BiGGId object based on the validated or updated ID @@ -154,11 +156,11 @@ public void setGPLabelName(GeneProduct geneProduct, String label) throws SQLExce bigg.getGeneName(label).ifPresent(geneName -> { // Log if no gene name is associated with the label if (geneName.isEmpty()) { - logger.fine(format(MESSAGES.getString("NO_GENE_FOR_LABEL"), geneProduct.getName())); + logger.debug(format(MESSAGES.getString("NO_GENE_FOR_LABEL"), geneProduct.getName())); } else { // Log a warning if the gene product name is set and differs from the fetched gene name if (geneProduct.isSetName() && !geneProduct.getName().equals(geneName)) { - logger.warning(format(MESSAGES.getString("UPDATE_GP_NAME"), geneProduct.getName(), geneName)); + logger.debug(format(MESSAGES.getString("UPDATE_GP_NAME"), geneProduct.getName(), geneName)); } // Update the gene product name with the fetched gene name geneProduct.setName(geneName); diff --git a/src/main/java/edu/ucsd/sbrg/db/PostgresConnectionPool.java b/src/main/java/edu/ucsd/sbrg/db/PostgresConnectionPool.java index 5c5c7876..ff3cebcd 100644 --- a/src/main/java/edu/ucsd/sbrg/db/PostgresConnectionPool.java +++ b/src/main/java/edu/ucsd/sbrg/db/PostgresConnectionPool.java @@ -3,17 +3,18 @@ import com.zaxxer.hikari.HikariConfig; import com.zaxxer.hikari.HikariDataSource; import org.sbml.jsbml.util.StringTools; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.sql.Connection; import java.sql.SQLException; import java.util.Properties; -import java.util.logging.Logger; import static java.text.MessageFormat.format; public class PostgresConnectionPool { - private static final Logger logger = Logger.getLogger(PostgresConnectionPool.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(PostgresConnectionPool.class); private final HikariDataSource dataSource; public Connection getConnection() throws SQLException { @@ -37,6 +38,6 @@ public PostgresConnectionPool(String host, int port, String user, String passwor config.setMaximumPoolSize(16); config.setReadOnly(true); dataSource = new HikariDataSource(config); - logger.fine(format("{0}@{1}:{2}, password={3}", user, host, port, StringTools.fill(password.length(), '*'))); + logger.debug(format("{0}@{1}:{2}, password={3}", user, host, port, StringTools.fill(password.length(), '*'))); } } diff --git a/src/main/java/edu/ucsd/sbrg/db/adb/AnnotateDB.java b/src/main/java/edu/ucsd/sbrg/db/adb/AnnotateDB.java index 4824f8e3..bc21e03e 100644 --- a/src/main/java/edu/ucsd/sbrg/db/adb/AnnotateDB.java +++ b/src/main/java/edu/ucsd/sbrg/db/adb/AnnotateDB.java @@ -1,9 +1,6 @@ package edu.ucsd.sbrg.db.adb; -import de.zbit.util.Utils; -import de.zbit.util.prefs.SBProperties; import edu.ucsd.sbrg.db.PostgresConnectionPool; -import edu.ucsd.sbrg.db.bigg.BiGGDB; import edu.ucsd.sbrg.parameters.DBParameters; import org.slf4j.Logger; import org.slf4j.LoggerFactory; diff --git a/src/main/java/edu/ucsd/sbrg/db/bigg/BiGGDB.java b/src/main/java/edu/ucsd/sbrg/db/bigg/BiGGDB.java index 9ea9b03b..b5c66e2a 100644 --- a/src/main/java/edu/ucsd/sbrg/db/bigg/BiGGDB.java +++ b/src/main/java/edu/ucsd/sbrg/db/bigg/BiGGDB.java @@ -18,7 +18,7 @@ import de.zbit.util.Utils; import edu.ucsd.sbrg.parameters.DBParameters; import edu.ucsd.sbrg.db.PostgresConnectionPool; -import edu.ucsd.sbrg.polishing.SBMLPolisher; +import edu.ucsd.sbrg.polishing.NamePolisher; import edu.ucsd.sbrg.resolver.RegistryURI; import edu.ucsd.sbrg.resolver.identifiersorg.IdentifiersOrgURI; import org.slf4j.Logger; @@ -284,7 +284,7 @@ public Optional singleParamStatement(String query, String param) throws return Optional.of(results.iterator().next()); } else { if (results.size() > 1) { - logger.info(format(MESSAGES.getString("QUERY_MULTIPLE_RESULTS"), param, query)); + logger.debug(format(MESSAGES.getString("QUERY_MULTIPLE_RESULTS"), param, query)); } return Optional.empty(); } @@ -301,7 +301,7 @@ public Optional singleParamStatement(String query, String param) throws */ public Optional getComponentName(BiGGId biggId) throws SQLException { String query = "SELECT " + NAME + " FROM " + COMPONENT + " WHERE " + BIGG_ID + " = ? AND " + NAME + " <> ''"; - return singleParamStatement(query, biggId.getAbbreviation()); + return singleParamStatement(query, biggId.getAbbreviation()).map(name -> new NamePolisher().polish(name)); } /** @@ -472,7 +472,7 @@ public List getPublications(String abbreviation) throws SQLExceptio */ public Optional getReactionName(String abbreviation) throws SQLException { String query = "SELECT " + NAME + " FROM " + REACTION + " WHERE " + BIGG_ID + " = ? AND " + NAME + " <> ''"; - return singleParamStatement(query, abbreviation); + return singleParamStatement(query, abbreviation).map(name -> new NamePolisher().polish(name)); } diff --git a/src/main/java/edu/ucsd/sbrg/db/bigg/BiGGId.java b/src/main/java/edu/ucsd/sbrg/db/bigg/BiGGId.java index 0121cfa2..6445dbca 100644 --- a/src/main/java/edu/ucsd/sbrg/db/bigg/BiGGId.java +++ b/src/main/java/edu/ucsd/sbrg/db/bigg/BiGGId.java @@ -4,12 +4,11 @@ import java.util.Optional; import java.util.ResourceBundle; -import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; import de.zbit.util.ResourceManager; -import edu.ucsd.sbrg.io.parsers.cobra.MatlabParser; +import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -38,7 +37,7 @@ */ public class BiGGId { - private static final org.slf4j.Logger logger = LoggerFactory.getLogger(BiGGId.class); + private static final Logger logger = LoggerFactory.getLogger(BiGGId.class); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); /** * First part of BiGG ID, either R, M or G @@ -103,45 +102,27 @@ public BiGGId(String prefix, String abbreviation, String compartmentCode, String parseBiGGId(id); } - /** - * Creates a BiGG ID for a metabolite with default correction behavior. - * - * @param id The raw metabolite ID string. - * @return An Optional containing the BiGGId if the ID is non-empty and valid, or an empty Optional otherwise. - */ - public static Optional createMetaboliteId(String id) { - return createMetaboliteId(id, true); - } - - /** * Creates a BiGG ID for a metabolite based on the provided string identifier. * This method handles the correction and standardization of the metabolite ID according to BiGG database standards. * * @param id The raw metabolite ID string. - * @param correct A boolean flag indicating whether to correct the ID to conform to BiGG standards. * @return An Optional containing the BiGGId if the ID is non-empty and valid, or an empty Optional otherwise. */ - public static Optional createMetaboliteId(String id, boolean correct) { - // Return empty if the input ID is empty - if (id.isEmpty()) { - return Optional.empty(); - } + public static BiGGId createMetaboliteId(String id) { // Fix the compartment code in the ID id = fixCompartmentCode(id); // Correct the ID to conform to BiGG standards if required - if (correct) { - id = makeBiGGConform(id); - // Remove leading underscore if present - if (id.startsWith("_")) { - id = id.substring(1); - } - // Standardize the prefix for metabolites from 'm_' to 'M_' - if (id.startsWith("m_")) { - id = id.replaceAll("^m_", "M_"); - } else if (!id.startsWith("M_")) { - id = "M_" + id; - } + id = makeBiGGConform(id); + // Remove leading underscore if present + if (id.startsWith("_")) { + id = id.substring(1); + } + // Standardize the prefix for metabolites from 'm_' to 'M_' + if (id.startsWith("m_")) { + id = id.replaceAll("^m_", "M_"); + } else if (!id.startsWith("M_")) { + id = "M_" + id; } // Special handling for one-letter abbreviation metabolites not conforming to the specification, but still // present in BiGG @@ -151,23 +132,13 @@ public static Optional createMetaboliteId(String id, boolean correct) { biggId.setPrefix("M"); biggId.setAbbreviation(metaboliteSpecialCase.group("abbreviation")); biggId.setCompartmentCode(metaboliteSpecialCase.group("compartment")); - return Optional.of(biggId); + return biggId; } else { - return Optional.of(new BiGGId(id)); + return new BiGGId(id); } } - /** - * Creates a BiGG ID for a gene using the default correction behavior. - * - * @param id The raw gene ID string. - * @return An Optional containing the BiGGId if the ID is non-empty and valid, or an empty Optional otherwise. - */ - public static Optional createGeneId(String id) { - return createGeneId(id, true); - } - /** * Creates a BiGG ID for a gene, with an option to correct the ID to conform to BiGG standards. *

@@ -178,25 +149,19 @@ public static Optional createGeneId(String id) { * - If the ID does not start with "G_", the prefix "G_" is prepended. * * @param id The raw gene ID string. - * @param correct A boolean flag indicating whether to correct the ID to conform to BiGG standards. * @return An Optional containing the BiGGId if the ID is non-empty and valid, or an empty Optional otherwise. */ - public static Optional createGeneId(String id, boolean correct) { - if (id.isEmpty()) { - return Optional.empty(); + public static BiGGId createGeneId(String id) { + id = makeBiGGConform(id); + if (id.startsWith("_")) { + id = id.substring(1); } - if (correct) { - id = makeBiGGConform(id); - if (id.startsWith("_")) { - id = id.substring(1); - } - if (id.startsWith("g_")) { - id = id.replaceAll("^g_", "G_"); - } else if (!id.startsWith("G_")) { - id = "G_" + id; - } + if (id.startsWith("g_")) { + id = id.replaceAll("^g_", "G_"); + } else if (!id.startsWith("G_")) { + id = "G_" + id; } - return Optional.of(new BiGGId(id)); + return new BiGGId(id); } /** @@ -207,7 +172,7 @@ public static Optional createGeneId(String id, boolean correct) { * @param id The raw reaction ID string. * @return An Optional containing the BiGGId if the ID is non-empty and valid, or an empty Optional otherwise. */ - public static Optional createReactionId(String id) { + public static BiGGId createReactionId(String id) { String prefixStripped = ""; // Strip the prefix if it starts with 'R_' or 'r_' if (id.startsWith("R_") || id.startsWith("r_")) { @@ -215,15 +180,15 @@ public static Optional createReactionId(String id) { } // Check if the original ID is a pseudo-reaction if (isPseudo(id)) { - return createReactionId(id, true, true); + return createReactionId(id, true); } // Check if the ID without the prefix is a pseudo-reaction else if (!prefixStripped.isEmpty() && isPseudo(prefixStripped)) { - return createReactionId(prefixStripped, true, true); + return createReactionId(prefixStripped, true); } // Handle normal reaction ID else { - return createReactionId(id, true, false); + return createReactionId(id, false); } } @@ -239,8 +204,8 @@ else if (!prefixStripped.isEmpty() && isPseudo(prefixStripped)) { */ private static boolean isPseudo(String reactionId) { return IDPattern.ATPM.get().matcher(reactionId).matches() || - IDPattern.BIOMASS.get().matcher(reactionId).matches() || - IDPattern.PSEUDO.get().matcher(reactionId).matches(); + IDPattern.BIOMASS.get().matcher(reactionId).matches() || + IDPattern.PSEUDO.get().matcher(reactionId).matches(); } @@ -249,26 +214,20 @@ private static boolean isPseudo(String reactionId) { * The method can correct the ID to conform to BiGG standards and adjust the prefix based on whether it is a pseudo-reaction. * * @param id The raw reaction ID string. - * @param correct If true, the ID will be corrected to conform to BiGG standards. * @param isPseudo If true, the ID is treated as a pseudo-reaction, affecting the prefix handling. * @return An Optional containing the BiGGId if the ID is non-empty, or an empty Optional if the ID is empty. */ - public static Optional createReactionId(String id, boolean correct, boolean isPseudo) { - if (id.isEmpty()) { - return Optional.empty(); + public static BiGGId createReactionId(String id, boolean isPseudo) { + id = makeBiGGConform(id); + if (id.startsWith("_")) { + id = id.substring(1); } - if (correct) { - id = makeBiGGConform(id); - if (id.startsWith("_")) { - id = id.substring(1); - } - if (!isPseudo && id.startsWith("r_")) { - id = id.replaceAll("^r_", "R_"); - } else if (!isPseudo && !id.startsWith("R_")) { - id = "R_" + id; - } + if (!isPseudo && id.startsWith("r_")) { + id = id.replaceAll("^r_", "R_"); + } else if (!isPseudo && !id.startsWith("R_")) { + id = "R_" + id; } - return Optional.of(new BiGGId(id)); + return new BiGGId(id); } diff --git a/src/main/java/edu/ucsd/sbrg/eco/DAG.java b/src/main/java/edu/ucsd/sbrg/eco/DAG.java index 4c2a9525..e84396de 100644 --- a/src/main/java/edu/ucsd/sbrg/eco/DAG.java +++ b/src/main/java/edu/ucsd/sbrg/eco/DAG.java @@ -7,7 +7,7 @@ public class DAG { private final Node root; - DAG(Term term) { + public DAG(Term term) { root = new Node(term); } diff --git a/src/main/java/edu/ucsd/sbrg/eco/Node.java b/src/main/java/edu/ucsd/sbrg/eco/Node.java index 352f982d..fa28ae93 100644 --- a/src/main/java/edu/ucsd/sbrg/eco/Node.java +++ b/src/main/java/edu/ucsd/sbrg/eco/Node.java @@ -6,14 +6,14 @@ import org.biojava.nbio.ontology.Term; -class Node { +public class Node { private Term term; private List parents; private List children; - Node(Term term) { + public Node(Term term) { this.term = term; parents = new ArrayList<>(); children = new ArrayList<>(); diff --git a/src/main/java/edu/ucsd/sbrg/fixing/CompartmentFixer.java b/src/main/java/edu/ucsd/sbrg/fixing/CompartmentFixer.java new file mode 100644 index 00000000..1169f606 --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/fixing/CompartmentFixer.java @@ -0,0 +1,20 @@ +package edu.ucsd.sbrg.fixing; + +import org.sbml.jsbml.Compartment; + +public class CompartmentFixer implements IFixSBases { + + @Override + public void fix(Compartment compartment, int index) { + // TODO: das ist nicht gut genug, was wenn es mehrere gibt? + if (!compartment.isSetId()) { + compartment.setId("d"); // default ID if none is set + } + + // Ensure the compartment's 'constant' property is set to true if not already specified + if (!compartment.isSetConstant()) { + compartment.setConstant(true); + } + + } +} diff --git a/src/main/java/edu/ucsd/sbrg/fixing/IFixSBases.java b/src/main/java/edu/ucsd/sbrg/fixing/IFixSBases.java new file mode 100644 index 00000000..4e2816c6 --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/fixing/IFixSBases.java @@ -0,0 +1,17 @@ +package edu.ucsd.sbrg.fixing; + +import org.sbml.jsbml.SBase; + +import java.util.List; + +public interface IFixSBases { + + default void fix(List elements) { + var iterator = elements.listIterator(); + while (iterator.hasNext()) { + fix(iterator.next(), iterator.nextIndex()); + } + } + + void fix(SBMLElement element, int index); +} diff --git a/src/main/java/edu/ucsd/sbrg/fixing/IFixSpeciesReferences.java b/src/main/java/edu/ucsd/sbrg/fixing/IFixSpeciesReferences.java new file mode 100644 index 00000000..9c52e433 --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/fixing/IFixSpeciesReferences.java @@ -0,0 +1,16 @@ +package edu.ucsd.sbrg.fixing; + +import org.sbml.jsbml.SpeciesReference; + +import java.util.List; + +public interface IFixSpeciesReferences { + + default void fix(List elements) { + for (var sr : elements) { + fix(sr); + } + } + + void fix(SpeciesReference element); +} diff --git a/src/main/java/edu/ucsd/sbrg/fixing/ModelFixer.java b/src/main/java/edu/ucsd/sbrg/fixing/ModelFixer.java new file mode 100644 index 00000000..f0abae79 --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/fixing/ModelFixer.java @@ -0,0 +1,16 @@ +package edu.ucsd.sbrg.fixing; + +import org.sbml.jsbml.Model; + +public class ModelFixer implements IFixSBases { + + @Override + public void fix(Model model, int index) { + if(model.isSetListOfReactions()) { + new ReactionFixer().fix(model.getListOfReactions()); + } + if(model.isSetListOfSpecies()) { + new SpeciesFixer().fix(model.getListOfSpecies()); + } + } +} diff --git a/src/main/java/edu/ucsd/sbrg/fixing/ReactionFixer.java b/src/main/java/edu/ucsd/sbrg/fixing/ReactionFixer.java new file mode 100644 index 00000000..c81d37bc --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/fixing/ReactionFixer.java @@ -0,0 +1,38 @@ +package edu.ucsd.sbrg.fixing; + +import org.sbml.jsbml.Reaction; +import org.sbml.jsbml.util.ValuePair; + +import static java.lang.String.format; + +public class ReactionFixer implements IFixSBases { + + @Override + public void fix(Reaction reaction, int index) { + fixMissingReactionId(reaction, index); + setFastProperty(reaction); + setReversibleProperty(reaction); + } + + private void fixMissingReactionId(Reaction reaction, int index) { + if(null == reaction.getId() || reaction.getId().isEmpty()) { + reaction.setId(format("reaction_without_id_%d", index)); + } + } + + private void setReversibleProperty(Reaction reaction) { + if (!reaction.isSetReversible()) { + reaction.setReversible(false); + } + } + + @SuppressWarnings("deprecation") + private void setFastProperty(Reaction reaction) { + if ((!reaction.isSetLevelAndVersion() + || reaction.getLevelAndVersion().compareTo(ValuePair.of(3, 1)) <= 0) + && !reaction.isSetFast()) { + reaction.setFast(false); + } + } + +} diff --git a/src/main/java/edu/ucsd/sbrg/fixing/SBMLFixer.java b/src/main/java/edu/ucsd/sbrg/fixing/SBMLFixer.java new file mode 100644 index 00000000..8ab01f19 --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/fixing/SBMLFixer.java @@ -0,0 +1,19 @@ +package edu.ucsd.sbrg.fixing; + +import org.sbml.jsbml.Model; +import org.sbml.jsbml.SBMLDocument; + +public class SBMLFixer implements IFixSBases { + + @Override + public void fix(SBMLDocument sbmlDocument, int index) { + fixMissingModel(sbmlDocument); + new ModelFixer().fix(sbmlDocument.getModel(), 0); + } + + private void fixMissingModel(SBMLDocument sbmlDocument) { + if (!sbmlDocument.isSetModel()) { + sbmlDocument.setModel(new Model()); + } + } +} diff --git a/src/main/java/edu/ucsd/sbrg/fixing/SpeciesFixer.java b/src/main/java/edu/ucsd/sbrg/fixing/SpeciesFixer.java new file mode 100644 index 00000000..c17badaf --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/fixing/SpeciesFixer.java @@ -0,0 +1,29 @@ +package edu.ucsd.sbrg.fixing; + +import org.sbml.jsbml.Species; + +import static java.lang.String.format; + +public class SpeciesFixer implements IFixSBases { + + @Override + public void fix(Species species, int index) { + if(null == species.getId() || species.getId().isEmpty()) { + species.setId(format("species_without_id_%d", index)); + } + + // Set default values for mandatory attributes if they are not already set + if (!species.isSetHasOnlySubstanceUnits()) { + species.setHasOnlySubstanceUnits(true); + } + + if (!species.isSetConstant()) { + species.setConstant(false); + } + + if (!species.isSetBoundaryCondition()) { + species.setBoundaryCondition(false); + } + } + +} diff --git a/src/main/java/edu/ucsd/sbrg/fixing/SpeciesReferenceFixer.java b/src/main/java/edu/ucsd/sbrg/fixing/SpeciesReferenceFixer.java new file mode 100644 index 00000000..1856fc6c --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/fixing/SpeciesReferenceFixer.java @@ -0,0 +1,16 @@ +package edu.ucsd.sbrg.fixing; + +import org.sbml.jsbml.SpeciesReference; + +public class SpeciesReferenceFixer implements IFixSpeciesReferences{ + + @Override + public void fix(SpeciesReference sr) { + if (sr.getSpeciesInstance() == null) { + // TODO: das ist nicht recoverable + } + if (!sr.isSetConstant()) { + sr.setConstant(false); + } + } +} diff --git a/src/main/java/edu/ucsd/sbrg/fixing/ext/fbc/ListOfObjectivesFixer.java b/src/main/java/edu/ucsd/sbrg/fixing/ext/fbc/ListOfObjectivesFixer.java new file mode 100644 index 00000000..cc269a72 --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/fixing/ext/fbc/ListOfObjectivesFixer.java @@ -0,0 +1,40 @@ +package edu.ucsd.sbrg.fixing.ext.fbc; + +import edu.ucsd.sbrg.fixing.IFixSBases; +import edu.ucsd.sbrg.parameters.PolishingParameters; +import org.sbml.jsbml.ext.fbc.FBCModelPlugin; +import org.sbml.jsbml.ext.fbc.ListOfObjectives; +import org.sbml.jsbml.ext.fbc.Objective; + +import java.util.Collection; +import java.util.function.Predicate; + +public class ListOfObjectivesFixer implements IFixSBases { + + private final FBCModelPlugin modelPlug; + private final PolishingParameters polishingParameters; + + public ListOfObjectivesFixer(PolishingParameters polishingParameters, FBCModelPlugin modelPlug) { + this.modelPlug = modelPlug; + this.polishingParameters = polishingParameters; + } + + @Override + public void fix(ListOfObjectives objectives, int index) { + var model = objectives.getModel(); + ObjectiveFixer.fixObjective( + model.getId(), + model.getListOfReactions(), + modelPlug, + polishingParameters.fluxObjectivesPolishingParameters().fluxCoefficients(), + polishingParameters.fluxObjectivesPolishingParameters().fluxObjectives()); + + // Identify and remove unused objectives, i.e., those without flux objectives + Collection removals = modelPlug.getListOfObjectives() + .stream() + .filter(Predicate.not(Objective::isSetListOfFluxObjectives) + .or(o -> o.getListOfFluxObjectives().isEmpty())) + .toList(); + modelPlug.getListOfObjectives().removeAll(removals); + } +} diff --git a/src/main/java/edu/ucsd/sbrg/fixing/ext/fbc/ObjectiveFixer.java b/src/main/java/edu/ucsd/sbrg/fixing/ext/fbc/ObjectiveFixer.java new file mode 100644 index 00000000..3fc28144 --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/fixing/ext/fbc/ObjectiveFixer.java @@ -0,0 +1,90 @@ +package edu.ucsd.sbrg.fixing.ext.fbc; + +import de.zbit.util.ResourceManager; +import edu.ucsd.sbrg.util.ReactionNamePatterns; +import org.sbml.jsbml.ListOf; +import org.sbml.jsbml.Reaction; +import org.sbml.jsbml.ext.fbc.FBCModelPlugin; +import org.sbml.jsbml.ext.fbc.Objective; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.MessageFormat; +import java.util.List; +import java.util.ResourceBundle; +import java.util.regex.Pattern; + +public class ObjectiveFixer { + + private static final Logger logger = LoggerFactory.getLogger(ObjectiveFixer.class); + private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); + private static final double DEFAULT_COEFFICIENT = 1d; + + public static void fixObjective(String modelDescriptor, + ListOf listOfReactions, + FBCModelPlugin fbcPlug, + List fluxCoefficients, + List fluxObjectives) { + Objective activeObjective = null; + if (!fbcPlug.isSetActiveObjective()) { + logger.info(MessageFormat.format(MESSAGES.getString("OBJ_NOT_DEFINED"), modelDescriptor)); + if (fbcPlug.getObjectiveCount() == 1) { + activeObjective = fbcPlug.getObjective(0); + fbcPlug.setActiveObjective(activeObjective); + logger.info(MessageFormat.format(MESSAGES.getString("OBJ_SOLUTION"), activeObjective.getId())); + } + } else { + activeObjective = fbcPlug.getListOfObjectives().getActiveObjectiveInstance(); + } + if (activeObjective != null) { + if (!activeObjective.isSetListOfFluxObjectives()) { + logger.info(MessageFormat.format(MESSAGES.getString("TRY_GUESS_MISSING_FLUX_OBJ"), modelDescriptor)); + if (listOfReactions != null) { + if (fluxObjectives != null && !fluxObjectives.isEmpty()) { + /* + * An array of target reactions is provided. We want to use this as + * flux objectives. + */ + for (int i = 0; i < fluxObjectives.size(); i++) { + final String id = fluxObjectives.get(i); + Reaction r = listOfReactions.firstHit((obj) -> + (obj instanceof Reaction) && id.equals(((Reaction) obj).getId())); + if (r != null) { + createFluxObjective(modelDescriptor, r, fluxCoefficients, activeObjective, i); + } else { + logger.info(MessageFormat.format(MESSAGES.getString("REACTION_UNKNOWN_ERROR"), id, modelDescriptor)); + } + } + } else { + /* + * Search for biomass reaction in the model and use this as + * objective. + */ + final Pattern pattern = ReactionNamePatterns.BIOMASS_CASE_INSENSITIVE.getPattern(); + Reaction rBiomass = listOfReactions.firstHit((obj) -> + (obj instanceof Reaction) && pattern.matcher(((Reaction) obj).getId()).matches()); + if (rBiomass != null) { + createFluxObjective(modelDescriptor, rBiomass, fluxCoefficients, activeObjective, 0); + } else { + logger.info(MESSAGES.getString("REACTION_BIOMASS_UNKNOWN_ERROR")); + } + } + } else { + logger.info(MessageFormat.format(MESSAGES.getString("REACTION_LIST_MISSING"), modelDescriptor)); + } + } + } + } + + + private static void createFluxObjective(String modelDescriptor, Reaction r, List fluxCoefficients, Objective o, + int i) { + double coeff = DEFAULT_COEFFICIENT; + if ((fluxCoefficients != null) && (fluxCoefficients.size() > i)) { + coeff = fluxCoefficients.get(i); + } + logger.info(MessageFormat.format(MESSAGES.getString("ADDED_FLUX_OBJ"), r.getId(), coeff, modelDescriptor)); + o.createFluxObjective(null, null, coeff, r); + } + +} diff --git a/src/main/java/edu/ucsd/sbrg/fixing/ext/groups/GroupsFixer.java b/src/main/java/edu/ucsd/sbrg/fixing/ext/groups/GroupsFixer.java new file mode 100644 index 00000000..98e4ef54 --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/fixing/ext/groups/GroupsFixer.java @@ -0,0 +1,35 @@ +package edu.ucsd.sbrg.fixing.ext.groups; + +import de.zbit.util.ResourceManager; +import org.sbml.jsbml.Model; +import org.sbml.jsbml.ext.groups.Group; +import org.sbml.jsbml.ext.groups.GroupsConstants; +import org.sbml.jsbml.ext.groups.GroupsModelPlugin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; + +import java.text.MessageFormat; +import java.util.ResourceBundle; + +public class GroupsFixer { + + private static final Logger logger = LoggerFactory.getLogger(GroupsFixer.class); + private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); + + /** + * Set group kind where required + * + */ + public static void fixGroups(Model model) { + GroupsModelPlugin gPlug = (GroupsModelPlugin) model.getExtension(GroupsConstants.shortLabel); + if ((gPlug != null) && gPlug.isSetListOfGroups()) { + for (Group group : gPlug.getListOfGroups()) { + if (!group.isSetKind()) { + logger.info(MessageFormat.format(MESSAGES.getString("ADD_KIND_TO_GROUP"), + group.isSetName() ? group.getName() : group.getId())); + group.setKind(Group.Kind.partonomy); + } + } + } + } +} diff --git a/src/main/java/edu/ucsd/sbrg/io/CombineArchive.java b/src/main/java/edu/ucsd/sbrg/io/CombineArchive.java index 2b48d53a..4167af43 100644 --- a/src/main/java/edu/ucsd/sbrg/io/CombineArchive.java +++ b/src/main/java/edu/ucsd/sbrg/io/CombineArchive.java @@ -3,7 +3,6 @@ import de.unirostock.sems.cbarchive.CombineArchiveException; import de.zbit.util.ResourceManager; import org.jdom2.JDOMException; -import org.jetbrains.annotations.NotNull; import org.sbml.jsbml.Compartment; import org.sbml.jsbml.Reaction; import org.sbml.jsbml.SBMLDocument; @@ -13,6 +12,8 @@ import org.sbml.jsbml.ext.fbc.GeneProduct; import org.sbml.jsbml.xml.XMLNode; import org.sbml.jsbml.xml.parsers.SBMLRDFAnnotationParser; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import org.w3c.tidy.Tidy; import javax.xml.stream.XMLStreamException; @@ -29,7 +30,6 @@ import java.nio.charset.StandardCharsets; import java.text.ParseException; import java.util.ResourceBundle; -import java.util.logging.Logger; import static java.text.MessageFormat.format; @@ -52,7 +52,7 @@ */ public class CombineArchive { - private static final Logger logger = Logger.getLogger(CombineArchive.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(CombineArchive.class); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); public static final String COMBINE_SPECIFICATION = "https://identifiers.org/combine.specifications/sbml"; public static final String RDF_MEDIATYPE = "https://purl.org/NET/mediatypes/application/rdf+xml"; @@ -96,7 +96,7 @@ private void writeGlossary() throws XMLStreamException, IOException { } } - private @NotNull Tidy tidyParser() { + private Tidy tidyParser() { Tidy tidy = new Tidy(); // obtain a new Tidy instance tidy.setDropEmptyParas(false); tidy.setHideComments(false); @@ -184,7 +184,7 @@ private File writeCombineArchive() throws IOException, ParseException, JDOMExcep // Check if the COMBINE archive file already exists and attempt to delete it File caFile = new File(combineArcLocation); if (caFile.exists() && !caFile.delete()) { - logger.severe(format("Failed to delete existing archive file \"{0}\"", caFile.getPath())); + logger.info(format("Failed to delete existing archive file \"{0}\"", caFile.getPath())); } File outputXML = new File(output.getAbsolutePath()); diff --git a/src/main/java/edu/ucsd/sbrg/io/IReadModelsFromFile.java b/src/main/java/edu/ucsd/sbrg/io/IReadModelsFromFile.java new file mode 100644 index 00000000..d649c157 --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/io/IReadModelsFromFile.java @@ -0,0 +1,11 @@ +package edu.ucsd.sbrg.io; + +import org.sbml.jsbml.SBMLDocument; + +import java.io.File; + +public interface IReadModelsFromFile { + + SBMLDocument read(File input) throws ModelReaderException; + +} diff --git a/src/main/java/edu/ucsd/sbrg/io/IWriteModels.java b/src/main/java/edu/ucsd/sbrg/io/IWriteModels.java new file mode 100644 index 00000000..d67af7d3 --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/io/IWriteModels.java @@ -0,0 +1,11 @@ +package edu.ucsd.sbrg.io; + +import org.sbml.jsbml.SBMLDocument; + +import java.io.InputStream; + +public interface IWriteModels { + + InputStream write(SBMLDocument doc) throws ModelWriterException; + +} diff --git a/src/main/java/edu/ucsd/sbrg/io/IWriteModelsToFile.java b/src/main/java/edu/ucsd/sbrg/io/IWriteModelsToFile.java new file mode 100644 index 00000000..19fc917f --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/io/IWriteModelsToFile.java @@ -0,0 +1,10 @@ +package edu.ucsd.sbrg.io; + +import org.sbml.jsbml.SBMLDocument; + +import java.io.File; + +public interface IWriteModelsToFile { + + File write(SBMLDocument doc, File output) throws ModelWriterException; +} diff --git a/src/main/java/edu/ucsd/sbrg/io/ModelReader.java b/src/main/java/edu/ucsd/sbrg/io/ModelReader.java index eb5d9452..b8db9896 100644 --- a/src/main/java/edu/ucsd/sbrg/io/ModelReader.java +++ b/src/main/java/edu/ucsd/sbrg/io/ModelReader.java @@ -3,21 +3,19 @@ import edu.ucsd.sbrg.parameters.SBOParameters; import edu.ucsd.sbrg.io.parsers.cobra.MatlabParser; import edu.ucsd.sbrg.io.parsers.json.JSONParser; -import edu.ucsd.sbrg.polishing.SBMLPolisher; import edu.ucsd.sbrg.resolver.Registry; import org.sbml.jsbml.SBMLDocument; import org.sbml.jsbml.SBMLReader; import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import javax.xml.stream.XMLStreamException; import java.io.*; import java.util.Arrays; import java.util.stream.Collectors; import static java.text.MessageFormat.format; -public class ModelReader { +public class ModelReader implements IReadModelsFromFile { private static final Logger logger = LoggerFactory.getLogger(ModelReader.class); private final SBOParameters sboParameters; @@ -28,13 +26,13 @@ public ModelReader(SBOParameters sboParameters, Registry registry) { this.registry = registry; } - + @Override public SBMLDocument read(File input) throws ModelReaderException { logger.debug(format("Read model file: {0}", input.toString())); try { var fileType = SBMLFileUtils.getFileType(input); - return switch (fileType) { + SBMLDocument sbmlDocument = switch (fileType) { case MAT_FILE -> new MatlabParser(sboParameters, registry).parse(input); case JSON_FILE -> new JSONParser(registry).parse(input); case SBML_FILE -> SBMLReader.read(input, new UpdateListener()); @@ -44,6 +42,10 @@ public SBMLDocument read(File input) throws ModelReaderException { .map(SBMLFileUtils.FileType::name) .collect(Collectors.joining(", "))); }; + if (sbmlDocument == null) { + throw new ModelReaderException("Error while reading input document.", input); + } + return sbmlDocument; } catch (Exception e) { throw new ModelReaderException("Error while reading input document.", e, input); diff --git a/src/main/java/edu/ucsd/sbrg/io/ModelReaderException.java b/src/main/java/edu/ucsd/sbrg/io/ModelReaderException.java index dc7243fc..cad760f3 100644 --- a/src/main/java/edu/ucsd/sbrg/io/ModelReaderException.java +++ b/src/main/java/edu/ucsd/sbrg/io/ModelReaderException.java @@ -2,10 +2,15 @@ import java.io.File; -public class ModelReaderException extends Exception { +public class ModelReaderException extends Throwable { private final File input; + public ModelReaderException(String s, File input) { + super(s); + this.input = input; + } + public ModelReaderException(String s, Exception e, File input) { super(s, e); this.input = input; diff --git a/src/main/java/edu/ucsd/sbrg/io/ModelWriter.java b/src/main/java/edu/ucsd/sbrg/io/ModelWriter.java index fe357ae1..6d7126f3 100644 --- a/src/main/java/edu/ucsd/sbrg/io/ModelWriter.java +++ b/src/main/java/edu/ucsd/sbrg/io/ModelWriter.java @@ -1,11 +1,9 @@ package edu.ucsd.sbrg.io; import de.unirostock.sems.cbarchive.CombineArchiveException; -import de.zbit.util.ResourceManager; -import edu.ucsd.sbrg.ModelPolisherOptions; +import edu.ucsd.sbrg.parameters.ModelPolisherOptions; import edu.ucsd.sbrg.io.parsers.json.JSONConverter; import org.jdom2.JDOMException; -import org.jetbrains.annotations.NotNull; import org.sbml.jsbml.SBMLDocument; import org.sbml.jsbml.TidySBMLWriter; import org.slf4j.Logger; @@ -20,7 +18,7 @@ import static java.text.MessageFormat.format; -public class ModelWriter { +public class ModelWriter implements IWriteModelsToFile, IWriteModels{ private static final Logger logger = LoggerFactory.getLogger(ModelWriter.class); private final ModelPolisherOptions.OutputType outputType; @@ -43,7 +41,6 @@ public InputStream write(SBMLDocument doc) throws ModelWriterException { public File write(SBMLDocument doc, File output) throws ModelWriterException { logger.debug(format("Write document to File: {0}", output.toString())); - try { return switch (outputType) { case SBML -> writeSBML(doc, output); @@ -55,7 +52,7 @@ public File write(SBMLDocument doc, File output) throws ModelWriterException { } } - private InputStream writeSBML(SBMLDocument doc) throws IOException, XMLStreamException { + private InputStream writeSBML(SBMLDocument doc) throws IOException { PipedInputStream result = new PipedInputStream(); PipedOutputStream pout = new PipedOutputStream(result); @@ -91,12 +88,12 @@ private InputStream writeJSON(SBMLDocument doc) throws ModelWriterException { try (var writer = new BufferedWriter(new OutputStreamWriter(out))) { writer.write(JSONConverter.getJSONDocument(doc)); return new PipedInputStream(out); - } catch (IOException e) { + } catch (IOException | XMLStreamException e) { throw new ModelWriterException("Error while converting to JSON.", e, doc, null); } } - private InputStream writeCOMBINE(SBMLDocument doc) throws IOException, XMLStreamException, ParseException, URISyntaxException, JDOMException, CombineArchiveException, TransformerException, ModelWriterException { + private InputStream writeCOMBINE(SBMLDocument doc) throws IOException, XMLStreamException, ParseException, URISyntaxException, JDOMException, CombineArchiveException, TransformerException { File f = Files.createTempFile("", ".xml").toFile(); TidySBMLWriter.write( doc, @@ -129,7 +126,7 @@ private File writeCOMBINE(SBMLDocument doc, File output) throws IOException, XML return combineArchiveFile; } - private static @NotNull File writeJSON(SBMLDocument doc, File output) throws IOException { + private static File writeJSON(SBMLDocument doc, File output) throws IOException, XMLStreamException { String out = output.getAbsolutePath().replaceAll("\\.xml", ".json"); try (var writer = new BufferedWriter(new FileWriter(out))) { writer.write(JSONConverter.getJSONDocument(doc)); diff --git a/src/main/java/edu/ucsd/sbrg/io/SBMLFileUtils.java b/src/main/java/edu/ucsd/sbrg/io/SBMLFileUtils.java index 3ca45b61..13969c11 100644 --- a/src/main/java/edu/ucsd/sbrg/io/SBMLFileUtils.java +++ b/src/main/java/edu/ucsd/sbrg/io/SBMLFileUtils.java @@ -4,22 +4,19 @@ import de.zbit.io.filefilter.SBFileFilter; import de.zbit.util.ResourceManager; import de.zbit.util.Utils; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.io.File; import java.util.ResourceBundle; -import java.util.logging.Logger; import static java.text.MessageFormat.format; public class SBMLFileUtils { - /** - * Bundle for ModelPolisher logger messages - */ + private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); - /** - * A {@link Logger} for this class. - */ - private static final Logger logger = Logger.getLogger(SBMLFileUtils.class.getName()); + + private static final Logger logger = LoggerFactory.getLogger(SBMLFileUtils.class); /** * Possible FileTypes of input file @@ -97,10 +94,7 @@ public static void checkCreateOutDir(File output) { // output is directory if (isDirectory(output) && !output.exists()) { logger.info(format(MESSAGES.getString("CREATING_DIRECTORY"), output.getAbsolutePath())); - if (output.mkdirs()) { - logger.fine(format(MESSAGES.getString("DIRECTORY_CREATED"), output.getAbsolutePath())); - } else { - logger.severe(format(MESSAGES.getString("DIRECTORY_CREATION_FAILED"), output.getAbsolutePath())); + if (!output.mkdirs()) { // TODO: grace throw new RuntimeException(format(MESSAGES.getString("DIRECTORY_CREATION_FAILED"), output.getAbsolutePath())); } @@ -110,11 +104,7 @@ public static void checkCreateOutDir(File output) { // check if directory of outfile exist and create if required if (!output.getParentFile().exists()) { logger.info(format(MESSAGES.getString("CREATING_DIRECTORY"), output.getParentFile().getAbsolutePath())); - if (output.getParentFile().mkdirs()) { - logger.fine(format(MESSAGES.getString("DIRECTORY_CREATED"), output.getParentFile().getAbsolutePath())); - } else { - logger.severe( - format(MESSAGES.getString("DIRECTORY_CREATION_FAILED"), output.getParentFile().getAbsolutePath())); + if (!output.getParentFile().mkdirs()) { // TODO: grace throw new RuntimeException(format(MESSAGES.getString("DIRECTORY_CREATION_FAILED"), output.getParentFile().getAbsolutePath())); } diff --git a/src/main/java/edu/ucsd/sbrg/io/UpdateListener.java b/src/main/java/edu/ucsd/sbrg/io/UpdateListener.java index 25126786..c419f816 100644 --- a/src/main/java/edu/ucsd/sbrg/io/UpdateListener.java +++ b/src/main/java/edu/ucsd/sbrg/io/UpdateListener.java @@ -1,7 +1,7 @@ package edu.ucsd.sbrg.io; import de.zbit.util.ResourceManager; -import edu.ucsd.sbrg.util.SBMLUtils; +import edu.ucsd.sbrg.util.ext.groups.GroupsUtils; import org.sbml.jsbml.Model; import org.sbml.jsbml.NamedSBase; import org.sbml.jsbml.Reaction; @@ -10,6 +10,8 @@ import org.sbml.jsbml.util.TreeNodeChangeEvent; import org.sbml.jsbml.util.TreeNodeChangeListener; import org.sbml.jsbml.util.TreeNodeRemovedEvent; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.swing.tree.TreeNode; import java.beans.PropertyChangeEvent; @@ -19,7 +21,6 @@ import java.util.Map; import java.util.ResourceBundle; import java.util.Set; -import java.util.logging.Logger; /** @@ -37,10 +38,8 @@ */ public class UpdateListener implements TreeNodeChangeListener { - /** - * A {@link Logger} for this class. - */ - private static final Logger logger = Logger.getLogger(UpdateListener.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(UpdateListener.class); + /** * Bundle for ModelPolisher logger messages */ @@ -85,7 +84,7 @@ public void propertyChange(PropertyChangeEvent evt) { // Update reaction references in the FBC model plugin. updateReactionRef(oldId, newId, fbcModelPlug); // Update subsystem references if any. - Set subsystems = (Set) r.getUserObject(SBMLUtils.SUBSYSTEM_LINK); + Set subsystems = (Set) r.getUserObject(GroupsUtils.SUBSYSTEM_LINK); if (subsystems != null) { for (Member m : subsystems) { m.setIdRef(newId); @@ -104,7 +103,7 @@ else if (nsb instanceof GeneProduct) { } // Log a severe message if the ID change cannot be handled. else { - logger.severe( + logger.debug( MessageFormat.format(MESSAGES.getString("ID_CHANGE_WARNING"), nsb.getElementName(), oldId, newId)); } } @@ -159,7 +158,7 @@ public void nodeAdded(TreeNode node) { // } } // Log the addition of the node. - logger.fine(node.toString()); + logger.debug(node.toString()); } @@ -171,6 +170,6 @@ public void nodeAdded(TreeNode node) { */ @Override public void nodeRemoved(TreeNodeRemovedEvent event) { - logger.fine(event.toString()); + logger.debug(event.toString()); } } diff --git a/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/COBRAUtils.java b/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/COBRAUtils.java index 57d5e074..6bb09bc6 100644 --- a/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/COBRAUtils.java +++ b/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/COBRAUtils.java @@ -1,6 +1,8 @@ package edu.ucsd.sbrg.io.parsers.cobra; import de.zbit.util.ResourceManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import us.hebi.matlab.mat.types.Array; import us.hebi.matlab.mat.types.Cell; import us.hebi.matlab.mat.types.Char; @@ -8,16 +10,13 @@ import java.util.Arrays; import java.util.ResourceBundle; -import java.util.logging.Logger; import static java.text.MessageFormat.format; public class COBRAUtils { - /** - * A {@link Logger} for this class. - */ - private static final Logger logger = Logger.getLogger(SpeciesParser.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(COBRAUtils.class); + /** * Bundle for ModelPolisher logger messages */ @@ -50,7 +49,7 @@ public static String checkId(String id) { if (id.endsWith(";")) { id = id.substring(0, id.length() - 1); } else if (id.contains(";")) { - logger.warning(MESSAGES.getString("TRUNCATED_ID") + id); + logger.debug(MESSAGES.getString("TRUNCATED_ID") + id); id = id.substring(0, id.indexOf(";")); } return id; @@ -70,28 +69,17 @@ public static boolean exists(Array cell, int i) { } - /** - */ - public static void logException(Exception exc) { - logger.warning(format("{0}: {1}", exc.getClass().getSimpleName(), de.zbit.util.Utils.getMessage(exc))); - } - - - /** - */ public static String asString(Array array) { return asString(array, null, -1); } - /** - */ public static String asString(Array array, String parentName, int parentIndex) { StringBuilder sb = new StringBuilder(); if (array.getType() == MatlabType.Character) { Char string = (Char) array; if (string.getDimensions()[0] > 1) { - logger.fine(format(MESSAGES.getString("MANY_STRINGS_IN_CELL"), string.asCharSequence())); + logger.debug(format(MESSAGES.getString("MANY_STRINGS_IN_CELL"), string.asCharSequence())); } for (int i = 0; i < string.getDimensions()[0]; i++) { if (i > 0) { @@ -100,7 +88,7 @@ public static String asString(Array array, String parentName, int parentIndex) { sb.append(string.getRow(i)); } } else if (!Arrays.equals(array.getDimensions(), new int[] {0, 0})) { - logger.warning(format(MESSAGES.getString("TYPE_MISMATCH_STRING"), array.getType().toString(), "parentName = %s", + logger.debug(format(MESSAGES.getString("TYPE_MISMATCH_STRING"), array.getType().toString(), "parentName = %s", parentName, "parentIndex = %s", parentIndex)); } return sb.toString(); diff --git a/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/GeneParser.java b/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/GeneParser.java index d9f67bc5..62a06343 100644 --- a/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/GeneParser.java +++ b/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/GeneParser.java @@ -17,18 +17,14 @@ public GeneParser(FBCModelPlugin plugin, int index) { this.index = index; } - - /** - * - */ public void parse() { Optional geneCell = MatlabFields.getInstance().getCell(ModelField.genes.name()); geneCell.map(genes -> COBRAUtils.asString(genes.get(index), ModelField.genes.name(), index + 1)) - .ifPresent(id -> BiGGId.createGeneId(id) - .ifPresent(biggId -> { - GeneProduct gp = plugin.createGeneProduct(biggId.toBiGGId()); - gp.setLabel(id); - gp.setName(id); - })); + .ifPresent(id -> { + var biggId = BiGGId.createGeneId(id); + GeneProduct gp = plugin.createGeneProduct(biggId.toBiGGId()); + gp.setLabel(id); + gp.setName(id); + }); } } diff --git a/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/MatlabFields.java b/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/MatlabFields.java index c53bf562..bb331679 100644 --- a/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/MatlabFields.java +++ b/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/MatlabFields.java @@ -9,7 +9,6 @@ import java.util.Optional; import java.util.ResourceBundle; import java.util.function.Predicate; -import java.util.logging.Logger; import java.util.stream.Collectors; import javax.xml.stream.XMLStreamException; @@ -18,6 +17,8 @@ import de.zbit.sbml.util.SBMLtools; import de.zbit.util.ResourceManager; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import us.hebi.matlab.mat.types.Array; import us.hebi.matlab.mat.types.Cell; import us.hebi.matlab.mat.types.Char; @@ -26,15 +27,10 @@ import us.hebi.matlab.mat.types.Sparse; import us.hebi.matlab.mat.types.Struct; -/** - * - */ class MatlabFields { - /** - * A {@link Logger} for this class. - */ - private static final Logger logger = Logger.getLogger(MatlabFields.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(MatlabFields.class); + /** * Bundle for ModelPolisher logger messages */ @@ -86,7 +82,7 @@ public void setDescriptionFields(Model model) { if (desc.getDimensions()[0] == 1) { model.setName(desc.getRow(0)); } else { - logger.warning(format(MESSAGES.getString("MANY_IDS_IN_DESC"), desc.asCharSequence())); + logger.debug(format(MESSAGES.getString("MANY_IDS_IN_DESC"), desc.asCharSequence())); } } else if (description.getType() == MatlabType.Structure) { setDescriptionFromStruct(model, description); @@ -109,7 +105,7 @@ private void setDescriptionFromStruct(Model model, Array description) { try { model.appendNotes(SBMLtools.toNotesString("

" + COBRAUtils.asString(tmp) + "

")); } catch (XMLStreamException exc) { - COBRAUtils.logException(exc); + throw new RuntimeException(exc); } } } diff --git a/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/MatlabParser.java b/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/MatlabParser.java index 92607d70..b8c5998a 100644 --- a/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/MatlabParser.java +++ b/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/MatlabParser.java @@ -2,11 +2,10 @@ import de.zbit.sbml.util.SBMLtools; import de.zbit.util.ResourceManager; -import edu.ucsd.sbrg.io.parsers.json.JSONParser; import edu.ucsd.sbrg.parameters.SBOParameters; import edu.ucsd.sbrg.resolver.Registry; -import edu.ucsd.sbrg.util.GPRParser; -import edu.ucsd.sbrg.util.SBMLUtils; +import edu.ucsd.sbrg.util.ext.fbc.GPRParser; +import edu.ucsd.sbrg.util.ext.groups.GroupsUtils; import edu.ucsd.sbrg.io.UpdateListener; import org.sbml.jsbml.Model; import org.sbml.jsbml.Reaction; @@ -21,6 +20,7 @@ import org.sbml.jsbml.ext.groups.GroupsConstants; import org.sbml.jsbml.ext.groups.GroupsModelPlugin; import org.sbml.jsbml.util.ModelBuilder; +import org.slf4j.Logger; import org.slf4j.LoggerFactory; import us.hebi.matlab.mat.format.Mat5; import us.hebi.matlab.mat.format.Mat5File; @@ -37,7 +37,6 @@ import java.util.List; import java.util.Map; import java.util.ResourceBundle; -import java.util.logging.Logger; import static java.text.MessageFormat.format; @@ -46,7 +45,7 @@ */ public class MatlabParser { - private static final org.slf4j.Logger logger = LoggerFactory.getLogger(MatlabParser.class); + private static final Logger logger = LoggerFactory.getLogger(MatlabParser.class); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); private static MatlabFields matlabFields; private final SBOParameters sboParameters; @@ -220,7 +219,7 @@ private void parseGPRs(Model model) { if (model.getReaction(i) == null) { logger.info(format(MESSAGES.getString("CREATE_GPR_FAILED"), i)); } else { - GPRParser.parseGPR(model.getReaction(i), geneReactionRule, sboParameters.omitGenericTerms()); + GPRParser.parseGPR(model.getReaction(i), geneReactionRule, sboParameters.addGenericTerms()); } } }); @@ -245,7 +244,7 @@ private void parseSubsystems(Model model) { nameToGroup.put(name, group); } if (model.getReaction(i) != null) { - SBMLUtils.createSubsystemLink(model.getReaction(i), group.createMember()); + GroupsUtils.createSubsystemLink(model.getReaction(i), group.createMember()); } else { logger.info(format(MESSAGES.getString("SUBSYS_LINK_ERROR"), i)); } diff --git a/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/ReactionParser.java b/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/ReactionParser.java index 4f09a896..04938742 100644 --- a/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/ReactionParser.java +++ b/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/ReactionParser.java @@ -6,7 +6,6 @@ import java.util.Optional; import java.util.ResourceBundle; import java.util.StringTokenizer; -import java.util.logging.Logger; import java.util.regex.Pattern; import javax.xml.stream.XMLStreamException; @@ -27,16 +26,16 @@ import de.zbit.util.ResourceManager; import de.zbit.util.Utils; import edu.ucsd.sbrg.db.bigg.BiGGId; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import us.hebi.matlab.mat.types.Array; import us.hebi.matlab.mat.types.Cell; import us.hebi.matlab.mat.types.Matrix; public class ReactionParser { - /** - * A {@link Logger} for this class. - */ - private static final Logger logger = Logger.getLogger(ReactionParser.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(ReactionParser.class); + /** * Bundle for ModelPolisher logger messages */ @@ -56,26 +55,22 @@ public ReactionParser(ModelBuilder builder, int index, Registry registry) { } - /** - * - */ public void parse() { matlabFields.getCell(ModelField.rxns.name()) - .map(rxns -> COBRAUtils.asString(rxns.get(index), ModelField.rxns.name(), index + 1)).ifPresent(id -> { - if (!id.isEmpty()) { - Model model = builder.getModel(); - BiGGId.createReactionId(id).ifPresent(biggId -> { - Reaction reaction = model.createReaction(biggId.toBiGGId()); - setNameAndReversibility(reaction, index); - setReactionBounds(builder, reaction, index); - buildReactantsProducts(model, reaction, index); - parseAnnotations(builder, reaction, id, index); - if (reaction.getCVTermCount() > 0) { - reaction.setMetaId(reaction.getId()); - } - }); - } - }); + .map(rxns -> COBRAUtils.asString(rxns.get(index), ModelField.rxns.name(), index + 1)).ifPresent(id -> { + if (!id.isEmpty()) { + Model model = builder.getModel(); + var biggId = BiGGId.createReactionId(id); + Reaction reaction = model.createReaction(biggId.toBiGGId()); + setNameAndReversibility(reaction, index); + setReactionBounds(builder, reaction, index); + buildReactantsProducts(model, reaction, index); + parseAnnotations(builder, reaction, id, index); + if (reaction.getCVTermCount() > 0) { + reaction.setMetaId(reaction.getId()); + } + } + }); } @@ -104,22 +99,17 @@ private void buildReactantsProducts(Model model, Reaction reaction, int index) { for (int i = 0; i < S.getNumRows(); i++) { double coeff = S.getDouble(i, index); if (coeff != 0d) { - try { - Optional metCell = matlabFields.getCell(ModelField.mets.name()); - if (metCell.isPresent()) { - Cell mets = metCell.get(); - String id = COBRAUtils.asString(mets.get(i), ModelField.mets.name(), i + 1); - BiGGId.createMetaboliteId(id).ifPresent(metId -> { - Species species = model.getSpecies(metId.toBiGGId()); - if (coeff < 0d) { // Reactant - ModelBuilder.buildReactants(reaction, pairOf(-coeff, species)); - } else if (coeff > 0d) { // Product - ModelBuilder.buildProducts(reaction, pairOf(coeff, species)); - } - }); + Optional metCell = matlabFields.getCell(ModelField.mets.name()); + if (metCell.isPresent()) { + Cell mets = metCell.get(); + String id = COBRAUtils.asString(mets.get(i), ModelField.mets.name(), i + 1); + var metId = BiGGId.createMetaboliteId(id); + Species species = model.getSpecies(metId.toBiGGId()); + if (coeff < 0d) { // Reactant + ModelBuilder.buildReactants(reaction, pairOf(-coeff, species)); + } else if (coeff > 0d) { // Product + ModelBuilder.buildProducts(reaction, pairOf(coeff, species)); } - } catch (IllegalArgumentException exc) { - logger.warning(format(MESSAGES.getString("REACT_PARTIC_INVALID"), Utils.getMessage(exc))); } } } @@ -155,11 +145,11 @@ private void parseAnnotations(ModelBuilder builder, Reaction reaction, String rI Array cell = confidenceScores.get(index); if (cell instanceof Matrix) { if (cell.getNumElements() == 0) { - logger.warning(MESSAGES.getString("CONF_CELL_WRONG_DIMS")); + logger.debug(MESSAGES.getString("CONF_CELL_WRONG_DIMS")); return; } double score = ((Matrix) cell).getDouble(0); - logger.fine(format(MESSAGES.getString("DISPLAY_CONF_SCORE"), score, reaction.getId())); + logger.debug(format(MESSAGES.getString("DISPLAY_CONF_SCORE"), score, reaction.getId())); builder.buildParameter("P_confidenceScore_of_" + org.sbml.jsbml.util.SBMLtools.toSId(rId), // id format("Confidence score of reaction {0}", reaction.isSetName() ? reaction.getName() : reaction.getId()), // name score, // value @@ -169,7 +159,7 @@ private void parseAnnotations(ModelBuilder builder, Reaction reaction, String rI // TODO: there should be a specific term for confidence scores. // Use "613 - reaction parameter" for now. } else { - logger.warning(format(MESSAGES.getString("TYPE_MISMATCH_MLDOUBLE"), cell.getClass().getSimpleName())); + logger.debug(format(MESSAGES.getString("TYPE_MISMATCH_MLDOUBLE"), cell.getClass().getSimpleName())); } } }); @@ -187,7 +177,7 @@ private void appendComment(String comment, SBase sbase) { sbase.appendNotes(SBMLtools.toNotesString("

" + comment + "

")); } } catch (XMLStreamException exc) { - COBRAUtils.logException(exc); + throw new RuntimeException(exc); } } @@ -209,7 +199,7 @@ private void parseECcodes(String ec, Reaction reaction) { } } if (!match) { - logger.warning(format(MESSAGES.getString("EC_CODES_UNKNOWN"), ec)); + logger.debug(format(MESSAGES.getString("EC_CODES_UNKNOWN"), ec)); } if ((term.getResourceCount() > 0) && (term.getParent() == null)) { reaction.addCVTerm(term); @@ -307,7 +297,7 @@ private void parseCitation(String citation, Reaction reaction) { reaction.appendNotes(SBMLtools.toNotesString("

Reference: " + otherCitation + "

")); } } catch (XMLStreamException exc) { - COBRAUtils.logException(exc); + throw new RuntimeException(exc); } } if ((term.getResourceCount() > 0) && (term.getParent() == null)) { @@ -340,10 +330,10 @@ public boolean addResource(String resource, CVTerm term, String prefix) { if (validId(prefix, r)) { if (!resource.isEmpty()) { if (st.countTokens() > 1) { - logger.warning(format(MESSAGES.getString("SKIP_COMMENT"), resource, r, prefix)); + logger.debug(format(MESSAGES.getString("SKIP_COMMENT"), resource, r, prefix)); } resource = new IdentifiersOrgURI(prefix, r).getURI(); - logger.finest(format(MESSAGES.getString("ADDED_URI"), resource)); + logger.debug(format(MESSAGES.getString("ADDED_URI"), resource)); return term.addResource(resource); } } @@ -371,10 +361,10 @@ private boolean validId(String prefix, String id) { if (!pattern.isEmpty()) { validId = Pattern.compile(pattern).matcher(id).matches(); if (!validId) { - logger.warning(format(MESSAGES.getString("PATTERN_MISMATCH"), id, pattern)); + logger.debug(format(MESSAGES.getString("PATTERN_MISMATCH"), id, pattern)); } } else { - logger.severe(format(MESSAGES.getString("COLLECTION_UNKNOWN"), prefix)); + logger.debug(format(MESSAGES.getString("COLLECTION_UNKNOWN"), prefix)); } return validId; } diff --git a/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/SpeciesParser.java b/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/SpeciesParser.java index b69d5b39..68183856 100644 --- a/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/SpeciesParser.java +++ b/src/main/java/edu/ucsd/sbrg/io/parsers/cobra/SpeciesParser.java @@ -9,24 +9,19 @@ import org.sbml.jsbml.Species; import org.sbml.jsbml.ext.fbc.FBCConstants; import org.sbml.jsbml.ext.fbc.FBCSpeciesPlugin; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import us.hebi.matlab.mat.types.Array; import us.hebi.matlab.mat.types.Cell; import javax.xml.stream.XMLStreamException; import java.util.ResourceBundle; -import java.util.logging.Logger; import static java.text.MessageFormat.format; public class SpeciesParser { - /** - * A {@link Logger} for this class. - */ - private static final Logger logger = Logger.getLogger(SpeciesParser.class.getName()); - /** - * Bundle for ModelPolisher logger messages - */ + private static final Logger logger = LoggerFactory.getLogger(SpeciesParser.class); public static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); private final Model model; private final int index; @@ -42,21 +37,18 @@ public SpeciesParser(Model model, int index, Registry registry) { } - /** - */ public void parse() { matlabFields.getCell(ModelField.mets.name()) - .map(mets -> COBRAUtils.asString(mets.get(index), ModelField.mets.name(), index + 1)) - .flatMap(BiGGId::createMetaboliteId).ifPresent(biggId -> { - Species species = model.createSpecies(biggId.toBiGGId()); - parseSpeciesFields(species); - parseAnnotation(species); - }); + .map(mets -> COBRAUtils.asString(mets.get(index), ModelField.mets.name(), index + 1)) + .map(BiGGId::createMetaboliteId) + .ifPresent(biggId -> { + Species species = model.createSpecies(biggId.toBiGGId()); + parseSpeciesFields(species); + parseAnnotation(species); + }); } - /** - */ private void parseSpeciesFields(Species species) { matlabFields.getCell(ModelField.metNames.name()).ifPresent( metNames -> species.setName(COBRAUtils.asString(metNames.get(index), ModelField.metNames.name(), index + 1))); @@ -73,7 +65,7 @@ private void parseSpeciesFields(Species species) { double charge = metCharge.getDouble(index); specPlug.setCharge((int) charge); if (charge - ((int) charge) != 0d) { - logger.warning(format(MESSAGES.getString("CHARGE_TO_INT_COBRA"), charge, specPlug.getCharge())); + logger.debug(format(MESSAGES.getString("CHARGE_TO_INT_COBRA"), charge, specPlug.getCharge())); } } }); @@ -85,7 +77,7 @@ private void parseSpeciesFields(Species species) { try { species.appendNotes("SMILES: " + smile + ""); } catch (XMLStreamException exc) { - COBRAUtils.logException(exc); + throw new RuntimeException(exc); } } } @@ -96,8 +88,6 @@ private void parseSpeciesFields(Species species) { } - /** - */ private void parseAnnotation(Species species) { CVTerm term = new CVTerm(); term.setQualifierType(CVTerm.Type.BIOLOGICAL_QUALIFIER); @@ -138,13 +128,13 @@ private boolean addResource(Cell cell, int i, CVTerm term, String namespaceName) resource = new IdentifiersOrgURI(prefix, id).getURI(); } String finalId = id; - success = registry.findRegistryUrlForOtherUrl(resource) + success = registry.resolveBackwards(resource) .map(res -> { term.addResource(res.getURI()); - logger.finest(format(MESSAGES.getString("ADDED_URI_COBRA"), res)); + logger.debug(format(MESSAGES.getString("ADDED_URI_COBRA"), res)); return true; }).orElseGet(() -> { - logger.severe(format(MESSAGES.getString("ADD_URI_FAILED_COBRA"), namespaceName, finalId)); + logger.debug(format(MESSAGES.getString("ADD_URI_FAILED_COBRA"), namespaceName, finalId)); return false; }); } @@ -186,8 +176,6 @@ private String toMIRIAMid(String idCandidate) { } - /** - */ private void addKEGGResources(CVTerm term, int i) { // use short circuit evaluation to only run addResource until one of them returns true // return type is needed for this to work @@ -198,8 +186,6 @@ private void addKEGGResources(CVTerm term, int i) { } - /** - */ private void addPubChemResources(CVTerm term, int i) { matlabFields.getCell(ModelField.metPubChemID.name()) .map(metPubChemID -> addResource(metPubChemID, i, term, "PubChem-compound") diff --git a/src/main/java/edu/ucsd/sbrg/io/parsers/json/JSONConverter.java b/src/main/java/edu/ucsd/sbrg/io/parsers/json/JSONConverter.java index 355f4b66..76817b08 100644 --- a/src/main/java/edu/ucsd/sbrg/io/parsers/json/JSONConverter.java +++ b/src/main/java/edu/ucsd/sbrg/io/parsers/json/JSONConverter.java @@ -40,22 +40,13 @@ import edu.ucsd.sbrg.io.parsers.json.mapping.Metabolite; import edu.ucsd.sbrg.io.parsers.json.mapping.Metabolites; import edu.ucsd.sbrg.io.parsers.json.mapping.Root; -import edu.ucsd.sbrg.util.GPRParser; +import edu.ucsd.sbrg.util.ext.fbc.GPRParser; public class JSONConverter { - private static Map compartments = new HashMap<>(); - /** - */ - public static Root convertDocument(SBMLDocument doc) { - return convertModel(doc.getModel()); - } - - /** - */ - public static Root convertModel(Model model) { + public static Root convertModel(Model model) throws XMLStreamException { Root root = new Root(); root.setId(model.getId()); root.setName(model.getName()); @@ -78,9 +69,7 @@ public static Root convertModel(Model model) { } - /** - */ - public static List convertGenes(Model model) { + public static List convertGenes(Model model) throws XMLStreamException { List genes = new ArrayList<>(); FBCModelPlugin modelPlug = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); for (GeneProduct g : modelPlug.getListOfGeneProducts()) { @@ -90,9 +79,7 @@ public static List convertGenes(Model model) { } - /** - */ - public static Gene convertGene(GeneProduct g) { + public static Gene convertGene(GeneProduct g) throws XMLStreamException { Gene gene = new Gene(); gene.setId(g.getId()); gene.setName(g.getName()); @@ -106,9 +93,7 @@ public static Gene convertGene(GeneProduct g) { } - /** - */ - public static List convertMetabolites(Model model) { + public static List convertMetabolites(Model model) throws XMLStreamException { List metabolites = new ArrayList<>(); for (Species species : model.getListOfSpecies()) { metabolites.add(convertMetabolite(species)); @@ -117,20 +102,17 @@ public static List convertMetabolites(Model model) { } - /** - */ - public static Metabolite convertMetabolite(Species species) { + public static Metabolite convertMetabolite(Species species) throws XMLStreamException { Metabolite metabolite = new Metabolite(); metabolite.setId(species.getId()); metabolite.setName(species.getName()); if (species.isSetCompartment()) { String compartment = species.getCompartment(); - BiGGId.createMetaboliteId(species.getId()).ifPresent(biGGId -> { - String compartmentCode = biGGId.getCompartmentCode(); - if (!compartmentCode.isEmpty() && !compartments.containsKey(compartmentCode)) { - compartments.put(compartmentCode, compartment); - } - }); + var biGGId = BiGGId.createMetaboliteId(species.getId()); + String compartmentCode = biGGId.getCompartmentCode(); + if (!compartmentCode.isEmpty() && !compartments.containsKey(compartmentCode)) { + compartments.put(compartmentCode, compartment); + } metabolite.setCompartment(compartment); } else { metabolite.setCompartment(""); @@ -150,9 +132,7 @@ public static Metabolite convertMetabolite(Species species) { } - /** - */ - public static List convertReactions(Model model) { + public static List convertReactions(Model model) throws XMLStreamException { List reactions = new ArrayList<>(); for (Reaction reaction : model.getListOfReactions()) { reactions.add(convertReaction(reaction)); @@ -161,9 +141,7 @@ public static List convertReacti } - /** - */ - public static edu.ucsd.sbrg.io.parsers.json.mapping.Reaction convertReaction(Reaction r) { + public static edu.ucsd.sbrg.io.parsers.json.mapping.Reaction convertReaction(Reaction r) throws XMLStreamException { edu.ucsd.sbrg.io.parsers.json.mapping.Reaction reaction = new edu.ucsd.sbrg.io.parsers.json.mapping.Reaction(); reaction.setId(r.getId()); reaction.setName(r.getName()); @@ -235,79 +213,20 @@ public static edu.ucsd.sbrg.io.parsers.json.mapping.Reaction convertReaction(Rea } - /** - */ - public static String getJSONDocument(SBMLDocument doc) { + public static String getJSONDocument(SBMLDocument doc) throws JsonProcessingException, XMLStreamException { return getJSONModel(doc.getModel()); } - /** - */ - public static String getJSONGene(GeneProduct g) { - Gene gene = convertGene(g); - ObjectMapper mapper = new ObjectMapper(); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - mapper.enable(SerializationFeature.INDENT_OUTPUT); - try { - return mapper.writeValueAsString(gene); - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - return ""; - } - - - /** - */ - public static String getJSONMetabolite(Species species) { - Metabolite metabolite = convertMetabolite(species); - ObjectMapper mapper = new ObjectMapper(); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - mapper.enable(SerializationFeature.INDENT_OUTPUT); - try { - return mapper.writeValueAsString(metabolite); - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - return ""; - } - - - /** - */ - public static String getJSONReaction(Reaction r) { - edu.ucsd.sbrg.io.parsers.json.mapping.Reaction reaction = convertReaction(r); - ObjectMapper mapper = new ObjectMapper(); - mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); - mapper.enable(SerializationFeature.INDENT_OUTPUT); - try { - return mapper.writeValueAsString(reaction); - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - return ""; - } - - - /** - */ - public static String getJSONModel(Model model) { + public static String getJSONModel(Model model) throws JsonProcessingException, XMLStreamException { Root root = convertModel(model); ObjectMapper mapper = new ObjectMapper(); mapper.setSerializationInclusion(JsonInclude.Include.NON_NULL); mapper.enable(SerializationFeature.INDENT_OUTPUT); - try { - return mapper.writeValueAsString(root); - } catch (JsonProcessingException e) { - e.printStackTrace(); - } - return ""; + return mapper.writeValueAsString(root); } - /** - */ private static Map> serializeAnnotation(Annotation annotation) { Map> terms = new LinkedHashMap<>(); for (CVTerm term : annotation.getListOfCVTerms()) { @@ -317,23 +236,17 @@ private static Map> serializeAnnotation(Annotation annotati } - /** - */ - private static List serializeNotes(XMLNode notes) { + private static List serializeNotes(XMLNode notes) throws XMLStreamException { List convertedNotes = new ArrayList<>(); int numChildren = notes.getChildCount(); for (int i = 0; i < numChildren; i++) { XMLNode child = notes.getChild(i); for (int j = 0; j < child.getChildCount(); j++) { XMLNode leaf = child.getChild(j); - try { - // remove XML tags and whitespace - String text = leaf.toXMLString().replaceAll("<.*?>", "").strip(); - if (!text.isEmpty()) { - convertedNotes.add(text); - } - } catch (XMLStreamException e) { - e.printStackTrace(); + // remove XML tags and whitespace + String text = leaf.toXMLString().replaceAll("<.*?>", "").strip(); + if (!text.isEmpty()) { + convertedNotes.add(text); } } } diff --git a/src/main/java/edu/ucsd/sbrg/io/parsers/json/JSONParser.java b/src/main/java/edu/ucsd/sbrg/io/parsers/json/JSONParser.java index b1416497..64a3f828 100644 --- a/src/main/java/edu/ucsd/sbrg/io/parsers/json/JSONParser.java +++ b/src/main/java/edu/ucsd/sbrg/io/parsers/json/JSONParser.java @@ -14,7 +14,6 @@ import java.util.ResourceBundle; import java.util.Set; import java.util.StringJoiner; -import java.util.logging.Logger; import java.util.stream.Collectors; import javax.xml.stream.XMLStreamException; @@ -22,7 +21,7 @@ import edu.ucsd.sbrg.resolver.Registry; import edu.ucsd.sbrg.resolver.RegistryURI; import edu.ucsd.sbrg.resolver.identifiersorg.IdentifiersOrgURI; -import edu.ucsd.sbrg.util.SBMLFix; +import edu.ucsd.sbrg.util.ext.groups.GroupsUtils; import org.sbml.jsbml.CVTerm; import org.sbml.jsbml.Compartment; import org.sbml.jsbml.Model; @@ -53,8 +52,7 @@ import edu.ucsd.sbrg.io.parsers.json.mapping.Metabolite; import edu.ucsd.sbrg.io.parsers.json.mapping.Reaction; import edu.ucsd.sbrg.io.parsers.json.mapping.Root; -import edu.ucsd.sbrg.util.GPRParser; -import edu.ucsd.sbrg.util.SBMLUtils; +import edu.ucsd.sbrg.util.ext.fbc.GPRParser; import edu.ucsd.sbrg.io.UpdateListener; import org.slf4j.LoggerFactory; @@ -77,7 +75,6 @@ public JSONParser(Registry registry) { /** * Creates the {@link ModelBuilder}, {@link SBMLDocument} and reads the * jsonFile as a tree - * */ public SBMLDocument parse(File jsonFile) throws IOException { ObjectMapper mapper = new ObjectMapper(); @@ -103,7 +100,6 @@ public SBMLDocument parse(File jsonFile) throws IOException { * version), generates a basic unit definition (mmol_per_gDW_per_hr) and calls * the parse methods for the main fields (compartments, metabolites, genes, * reactions) - * */ private void parseModel(ModelBuilder builder, Root root) { logger.info(MESSAGES.getString("JSON_PARSER_STARTED")); @@ -128,8 +124,6 @@ private void parseModel(ModelBuilder builder, Root root) { } - /** - */ @SuppressWarnings("unchecked") public void parseAnnotation(SBase node, Object annotation) { if (annotation == null || annotation.equals("")) { @@ -153,8 +147,6 @@ public void parseAnnotation(SBase node, Object annotation) { } - /** - */ @SuppressWarnings("unchecked") private Set parseAnnotation(Map.Entry entry) { Set annotations = new HashSet<>(); @@ -173,8 +165,6 @@ private Set parseAnnotation(Map.Entry entry) { } - /** - */ private Optional checkResource(String providerCode, String id) { String resource; if (id.startsWith("http")) { @@ -182,12 +172,10 @@ private Optional checkResource(String providerCode, String id) { } else { resource = new IdentifiersOrgURI(providerCode, id).getURI(); } - return registry.findRegistryUrlForOtherUrl(resource).map(RegistryURI::getURI); + return registry.resolveBackwards(resource).map(RegistryURI::getURI); } - /** - */ @SuppressWarnings("unchecked") public void parseNotes(SBase node, Object notes) { Set content = new HashSet<>(); @@ -207,14 +195,14 @@ public void parseNotes(SBase node, Object notes) { try { node.appendNotes(SBMLtools.toNotesString(notesContent.toString())); } catch (XMLStreamException e) { - e.printStackTrace(); + logger.info("Could not append notes to node.", e); } } } else if (notes instanceof String) { try { node.appendNotes(SBMLtools.toNotesString("

" + notes + "

")); } catch (XMLStreamException e) { - e.printStackTrace(); + logger.info("Could not append notes to node.", e); } } else { logger.info(format(MESSAGES.getString("OPEN_ISSUE_NOTES_FORMAT"), notes.getClass().getName())); @@ -222,8 +210,6 @@ public void parseNotes(SBase node, Object notes) { } - /** - */ @SuppressWarnings("unchecked") private String parseNotes(Map.Entry entry) { String note = ""; @@ -242,8 +228,6 @@ private String parseNotes(Map.Entry entry) { } - /** - */ public void parseCompartments(ModelBuilder builder, Map compartments) { int compSize = compartments.size(); logger.info(format(MESSAGES.getString("NUM_COMPART"), compSize)); @@ -265,27 +249,22 @@ public void parseCompartments(ModelBuilder builder, Map compartm } - /** - */ private void parseMetabolites(ModelBuilder builder, List metabolites) { int metSize = metabolites.size(); logger.info(format(MESSAGES.getString("NUM_METABOLITES"), metSize)); Model model = builder.getModel(); for (Metabolite metabolite : metabolites) { String id = metabolite.getId(); - BiGGId.createMetaboliteId(id).ifPresent(metId -> { - if (model.getSpecies(metId.toBiGGId()) != null) { - logger.info(format(MESSAGES.getString("DUPLICATE_SPECIES_ID"), id)); - } else { - parseMetabolite(model, metabolite, metId); - } - }); + var metId = BiGGId.createMetaboliteId(id); + if (model.getSpecies(metId.toBiGGId()) != null) { + logger.info(format(MESSAGES.getString("DUPLICATE_SPECIES_ID"), id)); + } else { + parseMetabolite(model, metabolite, metId); + } } } - /** - */ public void parseMetabolite(Model model, Metabolite metabolite, BiGGId biggId) { Species species = model.createSpecies(biggId.toBiGGId()); String name = metabolite.getName(); @@ -318,7 +297,7 @@ public void parseMetabolite(Model model, Metabolite metabolite, BiGGId biggId) { try { species.appendNotes(SBMLtools.toNotesString("

FORMULA: " + formula + "

")); } catch (XMLStreamException e) { - e.printStackTrace(); + logger.info("Could not append notes to node.", e); } } if (species.isSetAnnotation()) { @@ -327,28 +306,23 @@ public void parseMetabolite(Model model, Metabolite metabolite, BiGGId biggId) { } - /** - */ private void parseGenes(ModelBuilder builder, List genes) { int genSize = genes.size(); logger.info(format(MESSAGES.getString("NUM_GENES"), genSize)); Model model = builder.getModel(); for (Gene gene : genes) { String id = gene.getId(); - BiGGId.createGeneId(id).ifPresent(geneId -> { - FBCModelPlugin modelPlug = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); - if (modelPlug.getGeneProduct(geneId.toBiGGId()) != null) { - logger.info(format(MESSAGES.getString("DUPLICATE_GENE_ID"), id)); - } else { - parseGene(model, gene, geneId.toBiGGId()); - } - }); + var geneId = BiGGId.createGeneId(id); + FBCModelPlugin modelPlug = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); + if (modelPlug.getGeneProduct(geneId.toBiGGId()) != null) { + logger.info(format(MESSAGES.getString("DUPLICATE_GENE_ID"), id)); + } else { + parseGene(model, gene, geneId.toBiGGId()); + } } } - /** - */ public void parseGene(Model model, Gene gene, String id) { FBCModelPlugin modelPlug = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); GeneProduct gp = modelPlug.createGeneProduct(id); @@ -363,27 +337,22 @@ public void parseGene(Model model, Gene gene, String id) { } - /** - */ private void parseReactions(ModelBuilder builder, List reactions) { int reactSize = reactions.size(); logger.info(format(MESSAGES.getString("NUM_REACTIONS"), reactSize)); for (Reaction reaction : reactions) { String id = reaction.getId(); // Add prefix for BiGGId - BiGGId.createReactionId(id).ifPresent(reactionId -> { - if (builder.getModel().getReaction(reactionId.toBiGGId()) != null) { - logger.info(format(MESSAGES.getString("DUPLICATE_REACTION_ID"), id)); - } else { - parseReaction(builder, reaction, reactionId.toBiGGId()); - } - }); + var reactionId = BiGGId.createReactionId(id); + if (builder.getModel().getReaction(reactionId.toBiGGId()) != null) { + logger.info(format(MESSAGES.getString("DUPLICATE_REACTION_ID"), id)); + } else { + parseReaction(builder, reaction, reactionId.toBiGGId()); + } } } - /** - */ public void parseReaction(ModelBuilder builder, Reaction reaction, String id) { Model model = builder.getModel(); org.sbml.jsbml.Reaction r = model.createReaction(id); @@ -405,8 +374,6 @@ public void parseReaction(ModelBuilder builder, Reaction reaction, String id) { } - /** - */ private void setReactionFluxBounds(ModelBuilder builder, Reaction reaction, org.sbml.jsbml.Reaction r) { FBCReactionPlugin rPlug = (FBCReactionPlugin) r.getPlugin(FBCConstants.shortLabel); double lowerBound = reaction.getLowerBound(); @@ -422,35 +389,30 @@ private void setReactionFluxBounds(ModelBuilder builder, Reaction reaction, org. } - /** - */ @SuppressWarnings("unchecked") private void setReactionStoichiometry(Reaction reaction, Model model, org.sbml.jsbml.Reaction r) { Map metabolites = reaction.getMetabolites().get(); for (Map.Entry metabolite : metabolites.entrySet()) { // removed mu code, as unused not matching schema String id = metabolite.getKey(); - BiGGId.createMetaboliteId(id).ifPresent(metId -> { - double value = metabolite.getValue(); - if (value != 0d) { - Species species = model.getSpecies(metId.toBiGGId()); - if (species == null) { - species = model.createSpecies(metId.toBiGGId()); - logger.info(format(MESSAGES.getString("SPECIES_UNDEFINED"), metId, r.getId())); - } - if (value < 0d) { - ModelBuilder.buildReactants(r, pairOf(-value, species)); - } else { - ModelBuilder.buildProducts(r, pairOf(value, species)); - } + var metId = BiGGId.createMetaboliteId(id); + double value = metabolite.getValue(); + if (value != 0d) { + Species species = model.getSpecies(metId.toBiGGId()); + if (species == null) { + species = model.createSpecies(metId.toBiGGId()); + logger.info(format(MESSAGES.getString("SPECIES_UNDEFINED"), metId, r.getId())); + } + if (value < 0d) { + ModelBuilder.buildReactants(r, pairOf(-value, species)); + } else { + ModelBuilder.buildProducts(r, pairOf(value, species)); } - }); + } } } - /** - */ private void createSubsystem(Model model, Reaction reaction, org.sbml.jsbml.Reaction r) { String subsystem = reaction.getSubsystem() != null ? reaction.getSubsystem() : ""; if (!subsystem.isEmpty()) { @@ -467,13 +429,11 @@ private void createSubsystem(Model model, Reaction reaction, org.sbml.jsbml.Reac group.setName(subsystem); group.setKind(Group.Kind.partonomy); } - SBMLUtils.createSubsystemLink(r, group.createMember()); + GroupsUtils.createSubsystemLink(r, group.createMember()); } } - /** - */ private void setObjectiveCoefficient(Reaction reaction, Model model, org.sbml.jsbml.Reaction r) { FBCModelPlugin fbc = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); Objective obj = fbc.getObjective(0); diff --git a/src/main/java/edu/ucsd/sbrg/io/parsers/json/mapping/Compartments.java b/src/main/java/edu/ucsd/sbrg/io/parsers/json/mapping/Compartments.java index fab1e608..c469c480 100644 --- a/src/main/java/edu/ucsd/sbrg/io/parsers/json/mapping/Compartments.java +++ b/src/main/java/edu/ucsd/sbrg/io/parsers/json/mapping/Compartments.java @@ -4,18 +4,19 @@ import java.util.HashMap; import java.util.Map; -import java.util.logging.Logger; import java.util.regex.Pattern; import com.fasterxml.jackson.annotation.JsonAnySetter; import com.fasterxml.jackson.annotation.JsonGetter; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonSetter; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @JsonIgnoreProperties(ignoreUnknown = true) public class Compartments { - private static final Logger logger = Logger.getLogger(Compartments.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(Compartments.class); private Map compartments = new HashMap<>(); @JsonAnySetter @@ -30,7 +31,7 @@ public void add(String key, String value) { } compartments.put(key, value); } else { - logger.warning(format("Compartment code {0} did not match required pattern (C_)?[a-z]'{'1,2'}'", key)); + logger.debug(format("Compartment code {0} did not match required pattern (C_)?[a-z]'{'1,2'}'", key)); } } diff --git a/src/main/java/edu/ucsd/sbrg/io/parsers/json/mapping/Metabolite.java b/src/main/java/edu/ucsd/sbrg/io/parsers/json/mapping/Metabolite.java index eb2a7cca..3852b969 100644 --- a/src/main/java/edu/ucsd/sbrg/io/parsers/json/mapping/Metabolite.java +++ b/src/main/java/edu/ucsd/sbrg/io/parsers/json/mapping/Metabolite.java @@ -2,18 +2,19 @@ import static java.text.MessageFormat.format; -import java.util.logging.Logger; import java.util.regex.Pattern; import com.fasterxml.jackson.annotation.JsonIgnoreProperties; import com.fasterxml.jackson.annotation.JsonProperty; import com.fasterxml.jackson.annotation.JsonPropertyOrder; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; @JsonIgnoreProperties(ignoreUnknown = true) @JsonPropertyOrder({"id", "name", "compartment", "charge", "formula", "bound", "notes", "annotation"}) public class Metabolite { - private static final Logger logger = Logger.getLogger(Metabolite.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(Metabolite.class); @JsonProperty(required = true) private String id; @JsonProperty(required = true) @@ -68,7 +69,7 @@ public void setCompartment(String compartment) { } this.compartment = compartment; } else { - logger.finest(format( + logger.debug(format( "Compartment code {0} in metabolite {1} did not match pattern (C_)?[a-z]'{'1,2'}', trying to extract from id after parsing", compartment, id)); } diff --git a/src/main/java/edu/ucsd/sbrg/parameters/ADBAnnotationParameters.java b/src/main/java/edu/ucsd/sbrg/parameters/ADBAnnotationParameters.java index 4151c858..9a99f8ac 100644 --- a/src/main/java/edu/ucsd/sbrg/parameters/ADBAnnotationParameters.java +++ b/src/main/java/edu/ucsd/sbrg/parameters/ADBAnnotationParameters.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import de.zbit.util.prefs.SBProperties; -import edu.ucsd.sbrg.ModelPolisherOptions; import edu.ucsd.sbrg.db.adb.AnnotateDBOptions; public class ADBAnnotationParameters { diff --git a/src/main/java/edu/ucsd/sbrg/parameters/BiGGAnnotationParameters.java b/src/main/java/edu/ucsd/sbrg/parameters/BiGGAnnotationParameters.java index 577a0867..924c7752 100644 --- a/src/main/java/edu/ucsd/sbrg/parameters/BiGGAnnotationParameters.java +++ b/src/main/java/edu/ucsd/sbrg/parameters/BiGGAnnotationParameters.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import de.zbit.util.prefs.SBProperties; -import edu.ucsd.sbrg.ModelPolisherOptions; import edu.ucsd.sbrg.db.bigg.BiGGDBOptions; public class BiGGAnnotationParameters { diff --git a/src/main/java/edu/ucsd/sbrg/parameters/BiGGNotesParameters.java b/src/main/java/edu/ucsd/sbrg/parameters/BiGGNotesParameters.java index 3469e6b3..48a2b322 100644 --- a/src/main/java/edu/ucsd/sbrg/parameters/BiGGNotesParameters.java +++ b/src/main/java/edu/ucsd/sbrg/parameters/BiGGNotesParameters.java @@ -3,7 +3,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import de.zbit.util.prefs.Option; import de.zbit.util.prefs.SBProperties; -import edu.ucsd.sbrg.ModelPolisherOptions; import java.io.File; diff --git a/src/main/java/edu/ucsd/sbrg/parameters/CommandLineParameters.java b/src/main/java/edu/ucsd/sbrg/parameters/CommandLineParameters.java index c7496e08..5b6f0419 100644 --- a/src/main/java/edu/ucsd/sbrg/parameters/CommandLineParameters.java +++ b/src/main/java/edu/ucsd/sbrg/parameters/CommandLineParameters.java @@ -2,7 +2,6 @@ import de.zbit.util.ResourceManager; import de.zbit.util.prefs.SBProperties; -import edu.ucsd.sbrg.ModelPolisherOptions; import edu.ucsd.sbrg.io.IOOptions; import java.io.File; diff --git a/src/main/java/edu/ucsd/sbrg/parameters/FluxObjectivesPolishingParameters.java b/src/main/java/edu/ucsd/sbrg/parameters/FluxObjectivesPolishingParameters.java index 243c4721..f9ba89ba 100644 --- a/src/main/java/edu/ucsd/sbrg/parameters/FluxObjectivesPolishingParameters.java +++ b/src/main/java/edu/ucsd/sbrg/parameters/FluxObjectivesPolishingParameters.java @@ -2,12 +2,9 @@ import com.fasterxml.jackson.annotation.JsonProperty; import de.zbit.util.prefs.SBProperties; -import edu.ucsd.sbrg.ModelPolisherOptions; -import org.sbml.jsbml.ext.fbc.FluxObjective; import java.util.ArrayList; import java.util.List; -import java.util.Map; public class FluxObjectivesPolishingParameters { diff --git a/src/main/java/edu/ucsd/sbrg/ModelPolisherOptions.java b/src/main/java/edu/ucsd/sbrg/parameters/ModelPolisherOptions.java similarity index 96% rename from src/main/java/edu/ucsd/sbrg/ModelPolisherOptions.java rename to src/main/java/edu/ucsd/sbrg/parameters/ModelPolisherOptions.java index a863c51d..47b5755e 100644 --- a/src/main/java/edu/ucsd/sbrg/ModelPolisherOptions.java +++ b/src/main/java/edu/ucsd/sbrg/parameters/ModelPolisherOptions.java @@ -1,7 +1,7 @@ /* * */ -package edu.ucsd.sbrg; +package edu.ucsd.sbrg.parameters; import java.io.File; import java.util.ResourceBundle; @@ -129,8 +129,8 @@ public String getFileExtension() { * resulting output file. */ @SuppressWarnings("unchecked") - Option OMIT_GENERIC_TERMS = - new Option<>("OMIT_GENERIC_TERMS", Boolean.class, MESSAGES.getString("OMIT_GENERIC_TERMS_DESC"), Boolean.FALSE); + Option ADD_GENERIC_TERMS = + new Option<>("ADD_GENERIC_TERMS", Boolean.class, MESSAGES.getString("ADD_GENERIC_TERMS_DESC"), Boolean.TRUE); /** * Produce output as a single COMBINE Archive. */ diff --git a/src/main/java/edu/ucsd/sbrg/parameters/Parameters.java b/src/main/java/edu/ucsd/sbrg/parameters/Parameters.java index d005228e..3efddaef 100644 --- a/src/main/java/edu/ucsd/sbrg/parameters/Parameters.java +++ b/src/main/java/edu/ucsd/sbrg/parameters/Parameters.java @@ -1,20 +1,19 @@ package edu.ucsd.sbrg.parameters; import com.fasterxml.jackson.annotation.JsonProperty; -import edu.ucsd.sbrg.ModelPolisherOptions; public class Parameters { @JsonProperty("polishing") - private PolishingParameters polishing = new PolishingParameters(); + private final PolishingParameters polishing = new PolishingParameters(); @JsonProperty("annotation") - private AnnotationParameters annotation = new AnnotationParameters(); + private final AnnotationParameters annotation = new AnnotationParameters(); @JsonProperty("sbo-terms") - private SBOParameters sboTerms = new SBOParameters(); + private final SBOParameters sboTerms = new SBOParameters(); @JsonProperty("sbml-validation") - protected boolean sbmlValidation = ModelPolisherOptions.SBML_VALIDATION.getDefaultValue(); + protected final boolean sbmlValidation = ModelPolisherOptions.SBML_VALIDATION.getDefaultValue(); @JsonProperty("outputType") - protected ModelPolisherOptions.OutputType outputType = ModelPolisherOptions.OUTPUT_TYPE.getDefaultValue(); + protected final ModelPolisherOptions.OutputType outputType = ModelPolisherOptions.OUTPUT_TYPE.getDefaultValue(); public Parameters() {} diff --git a/src/main/java/edu/ucsd/sbrg/parameters/PolishingParameters.java b/src/main/java/edu/ucsd/sbrg/parameters/PolishingParameters.java index 975ed614..859aec12 100644 --- a/src/main/java/edu/ucsd/sbrg/parameters/PolishingParameters.java +++ b/src/main/java/edu/ucsd/sbrg/parameters/PolishingParameters.java @@ -3,8 +3,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import de.zbit.util.prefs.SBProperties; -import java.util.Map; - public class PolishingParameters { @JsonProperty("reactions") diff --git a/src/main/java/edu/ucsd/sbrg/parameters/ReactionPolishingParameters.java b/src/main/java/edu/ucsd/sbrg/parameters/ReactionPolishingParameters.java index 8d51c2b1..37a72379 100644 --- a/src/main/java/edu/ucsd/sbrg/parameters/ReactionPolishingParameters.java +++ b/src/main/java/edu/ucsd/sbrg/parameters/ReactionPolishingParameters.java @@ -2,7 +2,6 @@ import com.fasterxml.jackson.annotation.JsonProperty; import de.zbit.util.prefs.SBProperties; -import edu.ucsd.sbrg.ModelPolisherOptions; import java.util.Map; diff --git a/src/main/java/edu/ucsd/sbrg/parameters/SBOParameters.java b/src/main/java/edu/ucsd/sbrg/parameters/SBOParameters.java index d8c2789d..418e23e7 100644 --- a/src/main/java/edu/ucsd/sbrg/parameters/SBOParameters.java +++ b/src/main/java/edu/ucsd/sbrg/parameters/SBOParameters.java @@ -2,21 +2,20 @@ import com.fasterxml.jackson.annotation.JsonProperty; import de.zbit.util.prefs.SBProperties; -import edu.ucsd.sbrg.ModelPolisherOptions; public class SBOParameters { @JsonProperty("omit-generic-terms") - protected boolean omitGenericTerms = ModelPolisherOptions.OMIT_GENERIC_TERMS.getDefaultValue(); + protected boolean omitGenericTerms = ModelPolisherOptions.ADD_GENERIC_TERMS.getDefaultValue(); public SBOParameters() { } public SBOParameters(SBProperties args) { - omitGenericTerms = args.getBooleanProperty(ModelPolisherOptions.OMIT_GENERIC_TERMS); + omitGenericTerms = args.getBooleanProperty(ModelPolisherOptions.ADD_GENERIC_TERMS); } - public boolean omitGenericTerms() { + public boolean addGenericTerms() { return omitGenericTerms; } diff --git a/src/main/java/edu/ucsd/sbrg/polishing/AbstractPolisher.java b/src/main/java/edu/ucsd/sbrg/polishing/AbstractPolisher.java index eb9bd3e4..4d1bf94e 100644 --- a/src/main/java/edu/ucsd/sbrg/polishing/AbstractPolisher.java +++ b/src/main/java/edu/ucsd/sbrg/polishing/AbstractPolisher.java @@ -1,14 +1,12 @@ package edu.ucsd.sbrg.polishing; import edu.ucsd.sbrg.parameters.PolishingParameters; -import edu.ucsd.sbrg.reporting.ProgressObserver; -import edu.ucsd.sbrg.reporting.ProgressUpdate; -import edu.ucsd.sbrg.reporting.ReportType; +import edu.ucsd.sbrg.reporting.*; import edu.ucsd.sbrg.resolver.Registry; import java.util.*; -public abstract class AbstractPolisher { +public abstract class AbstractPolisher implements IReportStatus { protected final PolishingParameters polishingParameters; protected final Registry registry; @@ -27,23 +25,19 @@ public AbstractPolisher(PolishingParameters polishingParameters, Registry regist this.observers = observers; } - public void polish(List elementsToPolish) { - throw new UnsupportedOperationException(); - } - - abstract public void polish(SBMLElement elementToPolish); - - protected void statusReport(String text, Object element) { + @Override + public void statusReport(String text, Object element) { for (var o : observers) { o.update(new ProgressUpdate(text, element, ReportType.STATUS)); } } - - protected void diffReport(String elementType, Object element1, Object element2) { - for (var o : observers) { - o.update(new ProgressUpdate(elementType, List.of(element1, element2), ReportType.DATA)); - } - } +// +// @Override +// public void diffReport(String elementType, Object element1, Object element2) { +// for (var o : observers) { +// o.update(new ProgressUpdate(elementType, List.of(element1, element2), ReportType.DATA)); +// } +// } public List getObservers() { return observers; @@ -53,7 +47,7 @@ public List getObservers() { public boolean equals(Object o) { if (this == o) return true; if (o == null || getClass() != o.getClass()) return false; - AbstractPolisher that = (AbstractPolisher) o; + AbstractPolisher that = (AbstractPolisher) o; return Objects.equals(polishingParameters, that.polishingParameters); } diff --git a/src/main/java/edu/ucsd/sbrg/polishing/AnnotationPolisher.java b/src/main/java/edu/ucsd/sbrg/polishing/AnnotationPolisher.java index 64cf8612..69327723 100644 --- a/src/main/java/edu/ucsd/sbrg/polishing/AnnotationPolisher.java +++ b/src/main/java/edu/ucsd/sbrg/polishing/AnnotationPolisher.java @@ -5,7 +5,6 @@ import edu.ucsd.sbrg.resolver.RegistryURI; import edu.ucsd.sbrg.reporting.ProgressObserver; import org.sbml.jsbml.Annotation; -import org.sbml.jsbml.CVTerm; import org.slf4j.Logger; import org.slf4j.LoggerFactory; @@ -16,7 +15,7 @@ import static java.text.MessageFormat.format; -public class AnnotationPolisher extends AbstractPolisher { +public class AnnotationPolisher extends AbstractPolisher implements IPolishAnnotations { private static final Logger logger = LoggerFactory.getLogger(AnnotationPolisher.class); public AnnotationPolisher(PolishingParameters polishingParameters, Registry registry) { @@ -37,18 +36,19 @@ public AnnotationPolisher(PolishingParameters polishingParameters, Registry regi * * @param annotation The {@link Annotation} object associated with an SBML entity that contains CV Terms to be processed. */ + @Override public void polish(Annotation annotation) { logger.trace(format("Polish Annotation: {0}", annotation.toString())); - for (CVTerm term : annotation.getListOfCVTerms()) { + + for (var term : annotation.getListOfCVTerms()) { Set resources = new HashSet<>(); for (String resource : term.getResources()) { - registry.findRegistryUrlForOtherUrl(resource) - .map(RegistryURI::getURI) - .map(resources::add); - - resource = resource.replaceAll("http://identifiers.org", "https://identifiers.org"); - - resources.add(resource); + var registryUri = registry.resolveBackwards(resource).map(RegistryURI::getURI); + if (registryUri.isPresent()) { + resources.add(registryUri.get()); + } else { + resources.add(resource); + } } // Remove all existing resources from the CV Term. for (int i = 0; i < term.getResourceCount(); i++) { diff --git a/src/main/java/edu/ucsd/sbrg/polishing/CompartmentPolisher.java b/src/main/java/edu/ucsd/sbrg/polishing/CompartmentPolisher.java index ada2ed88..8388b8d9 100644 --- a/src/main/java/edu/ucsd/sbrg/polishing/CompartmentPolisher.java +++ b/src/main/java/edu/ucsd/sbrg/polishing/CompartmentPolisher.java @@ -10,6 +10,7 @@ import edu.ucsd.sbrg.resolver.Registry; import org.sbml.jsbml.Compartment; import org.sbml.jsbml.Model; +import org.sbml.jsbml.SBO; import org.sbml.jsbml.Unit; import de.zbit.util.ResourceManager; @@ -22,7 +23,7 @@ * compliance with standards and completeness. It handles the annotation processing, ID and name setting, * and ensures that necessary attributes like units and spatial dimensions are appropriately set. */ -public class CompartmentPolisher extends AbstractPolisher { +public class CompartmentPolisher extends AbstractPolisher implements IPolishSBases { private static final Logger logger = LoggerFactory.getLogger(CompartmentPolisher.class); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); @@ -40,7 +41,6 @@ public CompartmentPolisher(PolishingParameters polishingParameters, Registry reg public void polish(List compartments) { logger.debug("Polish Compartments"); for (Compartment compartment : compartments) { - diffReport("compartment", compartment.clone(), compartment); statusReport("Polishing Compartments (3/9) ", compartment); polish(compartment); } @@ -53,50 +53,45 @@ public void polish(List compartments) { * and ensures that the compartment has appropriate units and other necessary attributes set. */ @Override - public void polish(Compartment compartment) { + public void polish(Compartment compartment) { // Process any external resources linked via annotations in the compartment new AnnotationPolisher(polishingParameters, registry).polish(compartment.getAnnotation()); - // Set a default ID if not already set, otherwise clean up the ID according to BiGG specifications - if (!compartment.isSetId()) { - compartment.setId("d"); // default ID if none is set - } else { - // Attempt to remove the 'C_' prefix from the compartment ID, log a warning if the format is incorrect - BiGGId.extractCompartmentCode(compartment.getId()).ifPresentOrElse(compartment::setId, - () -> logger.info(format(MESSAGES.getString("COMPARTMENT_CODE_WRONG_FORMAT"), compartment.getId()))); - } - - // Set the SBOTerm to indicate an implicit compartment - compartment.setSBOTerm(410); - - // Set a default name if not already set - if (!compartment.isSetName()) { - compartment.setName("default"); - } - // Set the metaId to the compartment's ID if it has CV terms but no metaId set if (!compartment.isSetMetaId() && (compartment.getCVTermCount() > 0)) { compartment.setMetaId(compartment.getId()); } - // Ensure the compartment's 'constant' property is set to true if not already specified - if (!compartment.isSetConstant()) { - compartment.setConstant(true); + if (!compartment.isSetSBOTerm()) { + compartment.setSBOTerm(SBO.getPhysicalCompartment()); } - // TODO: Implement logic to set spatial dimensions based on BiGG ID, considering special cases like surfaces - if (!compartment.isSetSpatialDimensions()) { - // Placeholder for future implementation - // compartment.setSpatialDimensions(3d); - } + // Attempt to remove the 'C_' prefix from the compartment ID, log a warning if the format is incorrect + BiGGId.extractCompartmentCode(compartment.getId()).ifPresentOrElse( + compartment::setId, + () -> logger.info(format(MESSAGES.getString("COMPARTMENT_CODE_WRONG_FORMAT"), compartment.getId()))); - // Set the units of the compartment to dimensionless if no specific units are set in the model - if (!compartment.isSetUnits()) { - Model model = compartment.getModel(); - if (!(model.isSetLengthUnits() || model.isSetAreaUnits() || model.isSetVolumeUnits())) { - compartment.setUnits(Unit.Kind.DIMENSIONLESS); - } - } + + // TODO: not good enough +// // Set a default name if not already set +// if (!compartment.isSetName()) { +// compartment.setName("default"); +// } + + // TODO: Implement logic to set spatial dimensions based on BiGG ID, considering special cases like surfaces +// if (!compartment.isSetSpatialDimensions()) { +// // Placeholder for future implementation +// // compartment.setSpatialDimensions(3d); +// } + + // TODO: I am doubtful this is correct usage of dimensionless +// // Set the units of the compartment to dimensionless if no specific units are set in the model +// if (!compartment.isSetUnits()) { +// Model model = compartment.getModel(); +// if (!(model.isSetLengthUnits() || model.isSetAreaUnits() || model.isSetVolumeUnits())) { +// compartment.setUnits(Unit.Kind.DIMENSIONLESS); +// } +// } } } diff --git a/src/main/java/edu/ucsd/sbrg/polishing/IPolishAnnotations.java b/src/main/java/edu/ucsd/sbrg/polishing/IPolishAnnotations.java new file mode 100644 index 00000000..ce646d26 --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/polishing/IPolishAnnotations.java @@ -0,0 +1,9 @@ +package edu.ucsd.sbrg.polishing; + +import org.sbml.jsbml.Annotation; + +public interface IPolishAnnotations { + + void polish(Annotation annotation); + +} diff --git a/src/main/java/edu/ucsd/sbrg/polishing/IPolishSBaseAttributes.java b/src/main/java/edu/ucsd/sbrg/polishing/IPolishSBaseAttributes.java new file mode 100644 index 00000000..25e016d2 --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/polishing/IPolishSBaseAttributes.java @@ -0,0 +1,19 @@ +package edu.ucsd.sbrg.polishing; + +import org.sbml.jsbml.SBase; + +import java.util.List; + +public interface IPolishSBaseAttributes { + + + default void polish(List elementsToPolish) { + for (var element : elementsToPolish) { + polish(element); + } + } + + void polish(SBase elementToPolish); + + +} diff --git a/src/main/java/edu/ucsd/sbrg/polishing/IPolishSBases.java b/src/main/java/edu/ucsd/sbrg/polishing/IPolishSBases.java new file mode 100644 index 00000000..74d0382e --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/polishing/IPolishSBases.java @@ -0,0 +1,17 @@ +package edu.ucsd.sbrg.polishing; + +import org.sbml.jsbml.SBase; + +import java.util.List; + +public interface IPolishSBases { + + default void polish(List elementsToPolish) { + for (var element : elementsToPolish) { + polish(element); + } + } + + void polish(SBMLElement elementToPolish); + +} diff --git a/src/main/java/edu/ucsd/sbrg/polishing/IPolishSpeciesReferences.java b/src/main/java/edu/ucsd/sbrg/polishing/IPolishSpeciesReferences.java new file mode 100644 index 00000000..c9b6de5c --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/polishing/IPolishSpeciesReferences.java @@ -0,0 +1,17 @@ +package edu.ucsd.sbrg.polishing; + +import org.sbml.jsbml.SpeciesReference; + +import java.util.List; + +public interface IPolishSpeciesReferences { + + default void polish(List elementsToPolish) { + for (var element : elementsToPolish) { + polish(element); + } + } + + void polish(SpeciesReference elementToPolish); + +} diff --git a/src/main/java/edu/ucsd/sbrg/polishing/ModelPolisher.java b/src/main/java/edu/ucsd/sbrg/polishing/ModelPolisher.java index 15cd7a78..b8acbfbe 100644 --- a/src/main/java/edu/ucsd/sbrg/polishing/ModelPolisher.java +++ b/src/main/java/edu/ucsd/sbrg/polishing/ModelPolisher.java @@ -39,7 +39,7 @@ * * @author Andreas Dräger */ -public class ModelPolisher extends AbstractPolisher { +public class ModelPolisher extends AbstractPolisher implements IPolishSBases { private static final Logger logger = LoggerFactory.getLogger(ModelPolisher.class); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); @@ -68,6 +68,13 @@ public void polish(Model model) { logger.debug(format(MESSAGES.getString("PROCESSING_MODEL"), model.toString())); statusReport("Polishing Model (1/9) ", model); + new AnnotationPolisher(polishingParameters, registry, getObservers()).polish(model.getAnnotation()); + + // Set the metaId of the model if it is not set and there are CV terms + if (!model.isSetMetaId() && (model.getCVTermCount() > 0)) { + model.setMetaId(model.getId()); + } + // Delegate polishing tasks new UnitPolisher(polishingParameters, registry, getObservers()).polish(model); @@ -77,19 +84,12 @@ public void polish(Model model) { new ParametersPolisher(polishingParameters, registry, getObservers()).polish(model.getListOfParameters()); - diffReport("modelAnnotation", model.getAnnotation().clone(), model.getAnnotation()); - new AnnotationPolisher(polishingParameters, registry, getObservers()).polish(model.getAnnotation()); - new ReactionsPolisher(polishingParameters, sboParameters, registry, getObservers()).polish(model.getListOfReactions()); if (model.isSetPlugin(FBCConstants.shortLabel)) { - new FBCPolisher(polishingParameters, registry, getObservers()).polish(model); + new FBCPolisher(polishingParameters, sboParameters, registry, getObservers()).polish(model); } - // Set the metaId of the model if it is not set and there are CV terms - if (!model.isSetMetaId() && (model.getCVTermCount() > 0)) { - model.setMetaId(model.getId()); - } } @Override diff --git a/src/main/java/edu/ucsd/sbrg/polishing/PolishingUtils.java b/src/main/java/edu/ucsd/sbrg/polishing/NamePolisher.java similarity index 67% rename from src/main/java/edu/ucsd/sbrg/polishing/PolishingUtils.java rename to src/main/java/edu/ucsd/sbrg/polishing/NamePolisher.java index 68c8b06c..9e5339c8 100644 --- a/src/main/java/edu/ucsd/sbrg/polishing/PolishingUtils.java +++ b/src/main/java/edu/ucsd/sbrg/polishing/NamePolisher.java @@ -1,26 +1,27 @@ package edu.ucsd.sbrg.polishing; import de.zbit.util.ResourceManager; +import org.sbml.jsbml.SBase; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.ResourceBundle; -import java.util.logging.Logger; import static java.text.MessageFormat.format; -public class PolishingUtils { +public class NamePolisher implements IPolishSBaseAttributes { - private static final Logger logger = Logger.getLogger(ModelPolisher.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(NamePolisher.class); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); - /** - * Processes and polishes a given identifier name by applying a series of string transformations - * to make it more readable or compliant with certain standards. - * - * @param name The original identifier name to be polished. - * @return The polished version of the identifier name. - */ - public static String polishName(String name) { + @Override + public void polish(SBase sbase) { + var name = sbase.getName(); + sbase.setName(polish(name)); + } + + public String polish(String name) { String newName = name; // Remove leading "?_" if present if (name.startsWith("?_")) { @@ -40,7 +41,7 @@ public static String polishName(String name) { newName = newName.replace("_", " "); // Log the change if the name was altered if (!newName.equals(name)) { - logger.fine(format(MESSAGES.getString("CHANGED_NAME"), name, newName)); + logger.debug(format(MESSAGES.getString("CHANGED_NAME"), name, newName)); } return newName; } diff --git a/src/main/java/edu/ucsd/sbrg/polishing/ParametersPolisher.java b/src/main/java/edu/ucsd/sbrg/polishing/ParametersPolisher.java index ead86ee4..939304d3 100644 --- a/src/main/java/edu/ucsd/sbrg/polishing/ParametersPolisher.java +++ b/src/main/java/edu/ucsd/sbrg/polishing/ParametersPolisher.java @@ -9,41 +9,27 @@ import java.util.List; -import static java.text.MessageFormat.format; - -public class ParametersPolisher extends AbstractPolisher { +public class ParametersPolisher extends AbstractPolisher implements IPolishSBases { private static final Logger logger = LoggerFactory.getLogger(ParametersPolisher.class); public ParametersPolisher(PolishingParameters parameters, Registry registry, List observers) { super(parameters, registry, observers); } - /** - * Iterates over all parameters in the model and polishes each one. - * Displays progress for each parameter polished. - */ @Override public void polish(List modelParameters) { logger.debug("Polish Parameters"); for (Parameter parameter : modelParameters) { - diffReport("parameter", parameter.clone(), parameter); statusReport("Polishing Parameters (9/9) ", parameter); polish(parameter); } } - /** - * Polishes the name of a parameter if it is not already set. - * This method checks if the parameter has an ID but no name. - * If the condition is true, it sets the parameter's name to a polished version of its ID. - * The polishing is done using the {@link PolishingUtils#polishName(String)} method. - * - * @param p The parameter to be polished. - */ @Override public void polish(Parameter p) { - if (p.isSetId() && !p.isSetName()) { - p.setName(PolishingUtils.polishName(p.getId())); + if (!p.isSetName()) { + p.setName(p.getId()); + new NamePolisher().polish(p); } } diff --git a/src/main/java/edu/ucsd/sbrg/polishing/ReactionsPolisher.java b/src/main/java/edu/ucsd/sbrg/polishing/ReactionsPolisher.java index 662d1c89..418a4d72 100644 --- a/src/main/java/edu/ucsd/sbrg/polishing/ReactionsPolisher.java +++ b/src/main/java/edu/ucsd/sbrg/polishing/ReactionsPolisher.java @@ -1,28 +1,19 @@ package edu.ucsd.sbrg.polishing; -import de.zbit.kegg.AtomBalanceCheck; -import de.zbit.kegg.AtomBalanceCheck.AtomCheckResult; -import de.zbit.util.ResourceManager; import edu.ucsd.sbrg.parameters.PolishingParameters; import edu.ucsd.sbrg.parameters.SBOParameters; import edu.ucsd.sbrg.db.bigg.BiGGId; import edu.ucsd.sbrg.resolver.Registry; -import edu.ucsd.sbrg.util.GPRParser; import edu.ucsd.sbrg.reporting.ProgressObserver; -import org.jetbrains.annotations.Nullable; +import edu.ucsd.sbrg.util.ReactionNamePatterns; import org.sbml.jsbml.*; -import org.sbml.jsbml.ext.fbc.*; -import org.sbml.jsbml.util.ValuePair; -import org.sbml.jsbml.xml.XMLNode; import org.slf4j.Logger; import org.slf4j.LoggerFactory; import java.util.List; import java.util.Optional; -import java.util.ResourceBundle; import java.util.stream.Collectors; -import static java.text.MessageFormat.format; /** * This class provides methods to polish and validate SBML reactions according to specific rules and patterns. @@ -36,436 +27,144 @@ * The class operates on an SBML {@link Reaction} object and modifies it to conform to standards and conventions * used in systems biology models, particularly those related to flux balance constraints. */ -public class ReactionsPolisher extends AbstractPolisher { +public class ReactionsPolisher extends AbstractPolisher implements IPolishSBases { - private static final Logger logger = LoggerFactory.getLogger(ReactionsPolisher.class); - private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); + private static final Logger logger = LoggerFactory.getLogger(ReactionsPolisher.class); - private final GeneProductAssociationsProcessor gpaPolisher; - private final SBOParameters sboParameters; + private final SBOParameters sboParameters; - public ReactionsPolisher(PolishingParameters polishingParameters, SBOParameters sboParameters, Registry registry) { - super(polishingParameters, registry); - this.sboParameters = sboParameters; - this.gpaPolisher = new GeneProductAssociationsProcessor(); - } - - public ReactionsPolisher(PolishingParameters polishingParameters, SBOParameters sboParameters, Registry registry, List observers) { - super(polishingParameters, registry, observers); - this.gpaPolisher = new GeneProductAssociationsProcessor(); - this.sboParameters = sboParameters; - } - - /** - * Polishes all reactions in the given SBML model. This method iterates through each reaction, - * updates the progress display, and applies polishing operations defined in the ReactionPolishing class. - * It also aggregates a strictness flag that indicates if all reactions conform to strict FBC (Flux Balance Constraints) standards. - */ - @Override - public void polish(List reactions) { - logger.debug("Polish Reactions"); - - var iterator = reactions.iterator(); - while (iterator.hasNext()) { - var reaction = iterator.next(); - statusReport("Polishing Reactions (5/9) ", reaction); - - // remove reaction if ID is missing - String id = reaction.getId(); - if (id.isEmpty()) { - if (reaction.isSetName()) { - logger.debug(format(MESSAGES.getString("REACTION_MISSING_ID"), reaction.getName())); - } else { - logger.debug(MESSAGES.getString("REACTION_MISSING_ID_NAME")); - } - iterator.remove(); - } else { - diffReport("reaction", reaction.clone(), reaction); - polish(reaction); - } + public ReactionsPolisher(PolishingParameters polishingParameters, + SBOParameters sboParameters, + Registry registry) { + super(polishingParameters, registry); + this.sboParameters = sboParameters; } - } - - /** - * Polishes the reaction by applying various checks and modifications to ensure it conforms to - * the expected standards and conventions. This includes setting SBO terms, checking compartments, - * and ensuring proper setup of reactants and products. - * - */ - @SuppressWarnings("deprecated") - @Override - public void polish(Reaction reaction) { - var originalReaction = reaction.clone(); - // Process any external resources linked via annotations in the reaction - new AnnotationPolisher(polishingParameters, registry).polish(reaction.getAnnotation()); - // Check and set the compartment of the reaction based on its reactants and products - polishCompartments(reaction); - // Set meta ID if not set and CV terms are present - setMetaId(reaction); - // Remove '_copy' suffix from reaction name if present - removeCopySuffix(reaction); - // Ensure reaction properties are set according to SBML Level and Version - setFastProperty(reaction); - setReversibleProperty(reaction); - // check mass balance of the reaction - no-op - checkBalance(reaction); - // Convert gene associations to FBCv2 format and set flux objectives from local parameters - gpaPolisher.convertAssociationsToFBCV2(reaction, sboParameters.omitGenericTerms()); - - fluxObjectiveFromLocalParameter(reaction); - associationFromNotes(reaction); - - setSBOTerm(reaction); - - polishBounds(reaction); - } - - private void polishCompartments(Reaction reaction) { - String compartmentId = reaction.isSetCompartment() ? reaction.getCompartment() : null; - boolean conflict = false; - if (reaction.isSetListOfReactants()) { - Optional cIdFromReactants = polishSpeciesReferences(reaction.getListOfReactants(), SBO.getReactant()); - conflict = cIdFromReactants.isEmpty(); - if (!conflict && (compartmentId == null || compartmentId.equals(cIdFromReactants.get()))) { - reaction.setCompartment(cIdFromReactants.get()); - } - } - if (reaction.isSetListOfProducts()) { - Optional cIdFromProducts = polishSpeciesReferences(reaction.getListOfProducts(), SBO.getProduct()); - conflict |= cIdFromProducts.isEmpty(); - if (!conflict && (compartmentId == null || compartmentId.equals(cIdFromProducts.get()))) { - reaction.setCompartment(cIdFromProducts.get()); - } else { - reaction.unsetCompartment(); - } - } - } - - - private void setReversibleProperty(Reaction reaction) { - if (!reaction.isSetReversible()) { - reaction.setReversible(false); + public ReactionsPolisher(PolishingParameters polishingParameters, + SBOParameters sboParameters, + Registry registry, + List observers) { + super(polishingParameters, registry, observers); + this.sboParameters = sboParameters; } - } + @Override + public void polish(List reactions) { + logger.debug("Polish Reactions"); - private void setFastProperty(Reaction reaction) { - if ((!reaction.isSetLevelAndVersion() - || reaction.getLevelAndVersion().compareTo(ValuePair.of(3, 1)) <= 0) - && !reaction.isSetFast()) { - reaction.setFast(false); + for (var reaction : reactions) { + statusReport("Polishing Reactions (5/9) ", reaction); + polish(reaction); + } } - } - private void removeCopySuffix(Reaction reaction) { - String rName = reaction.getName(); - if (rName.matches(".*_copy\\d*")) { - rName = rName.substring(0, rName.lastIndexOf('_')); - reaction.setName(rName); - } - } + /** + * Polishes the reaction by applying various checks and modifications to ensure it conforms to + * the expected standards and conventions. This includes setting SBO terms, checking compartments, + * and ensuring proper setup of reactants and products. + */ + @Override + public void polish(Reaction reaction) { + var originalReaction = reaction.clone(); + // Process any external resources linked via annotations in the reaction + new AnnotationPolisher(polishingParameters, registry).polish(reaction.getAnnotation()); - private void setMetaId(Reaction reaction) { - if (!reaction.isSetMetaId() && (reaction.getCVTermCount() > 0)) { - reaction.setMetaId(reaction.getId()); - } - } + setMetaId(reaction); - /** - * Sets the Systems Biology Ontology (SBO) term for a reaction based on the abbreviation of its BiGG ID. - * The method matches the abbreviation against predefined patterns to determine the appropriate SBO term. - * - * @param id The BiGGId object containing the abbreviation to be checked. - */ - private void setSBOTermFromPattern(Reaction reaction, BiGGId id) { - String abbrev = id.getAbbreviation(); - if (ReactionNamePatterns.BIOMASS_CASE_INSENSITIVE.getPattern().matcher(abbrev).matches()) { - reaction.setSBOTerm(629); // Set SBO term for biomass production - } else if (ReactionNamePatterns.DEMAND_REACTION.getPattern().matcher(abbrev).matches()) { - reaction.setSBOTerm(628); // Set SBO term for demand reaction - } else if (ReactionNamePatterns.EXCHANGE_REACTION.getPattern().matcher(abbrev).matches()) { - reaction.setSBOTerm(627); // Set SBO term for exchange reaction - } else if (ReactionNamePatterns.ATP_MAINTENANCE.getPattern().matcher(abbrev).matches()) { - reaction.setSBOTerm(630); // Set SBO term for ATP maintenance - } else if (ReactionNamePatterns.SINK_REACTION.getPattern().matcher(abbrev).matches()) { - reaction.setSBOTerm(632); // Set SBO term for sink reaction - } - } + if (sboParameters.addGenericTerms()) { + if (reaction.isSetListOfReactants()) { + new SpeciesReferencesPolisher(SBO.getReactant()).polish(reaction.getListOfReactants()); + } + if (reaction.isSetListOfProducts()) { + new SpeciesReferencesPolisher(SBO.getProduct()).polish(reaction.getListOfProducts()); + } + } - /** - * This method polishes a list of {@link SpeciesReference} objects, which represent either reactants or products in a reaction. - * It sets default SBO terms and constant values for each species reference, and attempts to determine a common compartment - * for the reaction based on these species references. If all species references are associated with the same compartment, - * this compartment code is returned. Otherwise, it returns an empty {@link Optional}. - * - * @param speciesReferences A {@link ListOf} containing reactants or products of a reaction. - * @param defaultSBOterm The default Systems Biology Ontology (SBO) term to assign to species references if not already set. - * @return An {@link Optional} containing the compartment code if it can be unambiguously determined; otherwise, {@link Optional#empty()}. - */ - private Optional polishSpeciesReferences(ListOf speciesReferences, int defaultSBOterm) { - // Assign default SBO terms and constant values to species references - for (SpeciesReference sr : speciesReferences) { - if (!sr.isSetSBOTerm() && !sboParameters.omitGenericTerms()) { - sr.setSBOTerm(defaultSBOterm); - } - if (!sr.isSetConstant()) { - sr.setConstant(false); - } - } - // Attempt to identify a common compartment for all species references - Model model = speciesReferences.getModel(); - if (null != model) { - var modelSpecies = speciesReferences.stream() - .map(SpeciesReference::getSpeciesInstance) - .map(Optional::ofNullable) - .map(o -> o.map(Species::getCompartmentInstance)) - .flatMap(Optional::stream) - .map(Compartment::getId) - .collect(Collectors.toSet()); + setCompartmentFromReactionParticipants(reaction); - return modelSpecies.size() == 1 ? modelSpecies.stream().findFirst() : Optional.empty(); - } - return Optional.empty(); - } + removeCopySuffix(reaction); - /** - * Checks the balance of the reaction based on its SBO term and reactant/product counts. - * It sets the SBO term for demand reactions if not already set and checks the atom balance - * for reactions not identified as biomass production, demand, exchange, or ATP maintenance. - */ - private void checkBalance(Reaction reaction) { - // TODO: logging this information is nonsense, this should be available as output - // Check mass balance if enabled in parameters and reaction is not a special type - if (polishingParameters.reactionPolishingParameters().checkMassBalance() - && ((reaction.getSBOTerm() < 627) || (630 < reaction.getSBOTerm()))) { - // Perform atom balance check - AtomCheckResult defects = AtomBalanceCheck.checkAtomBalance(reaction, 1); - if ((defects != null) && (defects.hasDefects())) { - // Log warning if atom defects are found - logger.trace(format(MESSAGES.getString("ATOMS_MISSING"), reaction.getId(), defects.getDefects().toString())); - } else if (defects == null) { - // Log failure to check atom balance - logger.trace(format(MESSAGES.getString("CHECK_ATOM_BALANCE_FAILED"), reaction.getId())); - } else { - // Log successful atom balance check - logger.trace(format(MESSAGES.getString("ATOMS_OK"), reaction.getId())); - } + setSBOTerm(reaction); } - } - - private void setSBOTerm(Reaction reaction) { - // Set the SBO term based on the reaction ID pattern - BiGGId.createReactionId(reaction.getId()).ifPresent(id -> setSBOTermFromPattern(reaction, id)); - if (!reaction.isSetSBOTerm()) { - if (reaction.getReactantCount() == 0) { - if (reaction.isReversible()) { - // Placeholder for handling sink reactions - // TODO: Implement sink reaction handling - } else { - // Log and set SBO term for demand reaction if not already set - // logger.info(format(mpMessageBundle.getString("REACTION_DM_NOT_IN_ID"), reaction.getId())); - reaction.setSBOTerm(628); // Set as demand reaction + private void setMetaId(Reaction reaction) { + if (!reaction.isSetMetaId() && (reaction.getCVTermCount() > 0)) { + reaction.setMetaId(reaction.getId()); } - } else if (reaction.getProductCount() == 0) { - if (reaction.isReversible()) { - // Placeholder for handling source reactions - // TODO: Implement source reaction handling - } else { - // Log and set SBO term for demand reaction if not already set - // logger.warning(format(mpMessageBundle.getString("REACTION_DM_NOT_IN_ID"), reaction.getId())); - reaction.setSBOTerm(628); // Set as demand reaction - } - } - } - } - - /** - * This method sets the flux objective and its coefficient for a reaction based on the kinetic law parameters. - * If the reaction does not already have a flux objective, this method will create one and set it to maximize. - * It then checks if a flux objective already exists for the reaction. If not, it attempts to retrieve the - * "OBJECTIVE_COEFFICIENT" from the reaction's kinetic law and uses it to create and set a new flux objective - * with the retrieved coefficient value. - */ - private void fluxObjectiveFromLocalParameter(Reaction reaction) { - // Retrieve the FBC model plugin from the reaction's model - FBCModelPlugin modelPlugin = (FBCModelPlugin) reaction.getModel().getPlugin(FBCConstants.shortLabel); - // Attempt to get the first objective, or create one if none exist - Objective obj = modelPlugin.getObjective(0); - if (obj == null) { - obj = modelPlugin.createObjective("obj"); - obj.setType(Objective.Type.MAXIMIZE); - modelPlugin.getListOfObjectives().setActiveObjective(obj.getId()); } - // Check if a flux objective associated with the reaction already exists - boolean foExists = obj.getListOfFluxObjectives().stream() - .anyMatch(fo -> fo.getReactionInstance().equals(reaction)); - if (foExists) { - return; - } - // Retrieve the kinetic law of the reaction, if it exists - KineticLaw kl = reaction.getKineticLaw(); - if (kl != null) { - // Attempt to get the objective coefficient from the kinetic law - LocalParameter coefficient = kl.getLocalParameter("OBJECTIVE_COEFFICIENT"); - if (coefficient != null && coefficient.getValue() != 0d) { - // Create a new flux objective with the coefficient and associate it with the reaction - FluxObjective fo = obj.createFluxObjective("fo_" + reaction.getId()); - fo.setCoefficient(coefficient.getValue()); - fo.setReaction(reaction); - } - } - } - - /** - * This method extracts gene associations from the notes of a reaction and converts them into - * the FBCv2 GeneProductAssociation format. It specifically looks for notes tagged with "GENE_ASSOCIATION:" - * and processes them to set the gene product association for the reaction if it has not been set already. - */ - private void associationFromNotes(Reaction reaction) { - // Obtain the FBC plugin for the reaction to handle FBC-specific features. - FBCReactionPlugin reactionPlugin = (FBCReactionPlugin) reaction.getPlugin(FBCConstants.shortLabel); - - // Check if the gene product association is not already set and if the reaction has notes. - if (!reactionPlugin.isSetGeneProductAssociation() && reaction.isSetNotes()) { - // Retrieve the 'body' element from the reaction notes. - XMLNode body = reaction.getNotes().getChildElement("body", null); - // Process each paragraph within the body that contains exactly one child node. - if (body != null) { - for (XMLNode p : body.getChildElements("p", null)) { - if (p.getChildCount() == 1) { - String associationCandidate = p.getChildAt(0).getCharacters(); - - // Check if the text starts with the expected gene association tag. - if (associationCandidate.startsWith("GENE_ASSOCIATION: ")) { - String[] splits = associationCandidate.split("GENE_ASSOCIATION: "); - - // Ensure the string was split into exactly two parts and the second part is not empty. - if (splits.length == 2) { - String association = splits[1]; - if (!association.isEmpty()) { - // Parse the gene product association and apply it to the reaction. - GPRParser.parseGPR(reaction, association, sboParameters.omitGenericTerms()); - } - } + private void setCompartmentFromReactionParticipants(Reaction reaction) { + if (reaction.getCompartment() == null || reaction.getCompartment().isEmpty()) { + var reactantsCompartment = getCommonCompartmentCode(reaction.getListOfReactants()); + var productsCompartment = getCommonCompartmentCode(reaction.getListOfProducts()); + if (reactantsCompartment.isEmpty() && productsCompartment.isPresent()) { + reaction.setCompartment(productsCompartment.get()); + } + else if (reactantsCompartment.isPresent() && productsCompartment.isEmpty()) { + reaction.setCompartment(reactantsCompartment.get()); + } + else if (reactantsCompartment.isPresent() + && reactantsCompartment.get().equals(productsCompartment.get())) { + reaction.setCompartment(reactantsCompartment.get()); } - } } - } - } - } - - /** - * Checks if the existing FBC flux bounds are strictly defined and attempts to infer missing bounds from the reaction's kinetic law. - * If bounds are not set, it creates and assigns new global parameters as flux bounds according to the FBC specification. - */ - private void polishBounds(Reaction reaction) { - // TODO: this code does multiple unrelated things at once; check for strictness should be its own function - FBCReactionPlugin rPlug = (FBCReactionPlugin) reaction.getPlugin(FBCConstants.shortLabel); - - Parameter lb = rPlug.getLowerFluxBoundInstance(); - Parameter ub = rPlug.getUpperFluxBoundInstance(); - - // try to set bounds if none exist yet - if (lb == null) { - lb = ensureBound(reaction, "LOWER_BOUND"); - } - if (ub == null) { - ub = ensureBound(reaction, "UPPER_BOUND"); } - // set appropriate SBO terms for bounds - if (lb != null) { - setFluxBoundSBOTerm(rPlug.getLowerFluxBoundInstance()); - } - if (ub != null) { - setFluxBoundSBOTerm(rPlug.getUpperFluxBoundInstance()); + private Optional getCommonCompartmentCode(ListOf speciesReferences) { + // Attempt to identify a common compartment for all species references + if (null != speciesReferences) { + var modelSpecies = speciesReferences.stream() + .map(SpeciesReference::getSpeciesInstance) + .map(Species::getCompartmentInstance) + .map(Compartment::getId) + .collect(Collectors.toSet()); + return modelSpecies.size() == 1 ? modelSpecies.stream().findFirst() : Optional.empty(); + } + return Optional.empty(); } - } - - private @Nullable Parameter ensureBound(Reaction reaction, String boundType) { - // set bounds from KineticLaw, if they are not set in FBC, create global Parameter, - // as required by specification - Parameter bound = getBoundFromKineticLawParameters(reaction, boundType); - if (bound != null) { - setBoundId(reaction, bound, bound.getValue()); - var preexistingParameter = reaction.getModel().getParameter(bound.getId()); - if (preexistingParameter == null) { - reaction.getModel().addParameter(bound); - updateReactionPlugin(reaction, boundType, bound); - } else { - updateReactionPlugin(reaction, boundType, preexistingParameter); - } + private void removeCopySuffix(Reaction reaction) { + String rName = reaction.getName(); + if (rName.matches(".*_copy\\d*")) { + rName = rName.substring(0, rName.lastIndexOf('_')); + reaction.setName(rName); + } } - return bound; - } - private void updateReactionPlugin(Reaction reaction, String boundType, Parameter parameter) { - FBCReactionPlugin rPlug = (FBCReactionPlugin) reaction.getPlugin(FBCConstants.shortLabel); - if (boundType.equals("LOWER_BOUND")) { - rPlug.setLowerFluxBound(parameter); - } else if (boundType.equals("UPPER_BOUND")) { - rPlug.setUpperFluxBound(parameter); - } - } + private void setSBOTerm(Reaction reaction) { + setSBOTermFromPattern(reaction, BiGGId.createReactionId(reaction.getId())); - /** - * Polishes the SBO term of a flux bound parameter based on its ID. - * If the parameter's ID matches the default flux bound pattern, it sets the SBO term to 626. - * Otherwise, it sets the SBO term to 625. - * - * @param bound The parameter representing a flux bound. - */ - public void setFluxBoundSBOTerm(Parameter bound) { - if (ReactionNamePatterns.DEFAULT_FLUX_BOUND.getPattern().matcher(bound.getId()).matches()) { - bound.setSBOTerm(626); // default flux bound - } else { - bound.setSBOTerm(625); // flux bound + if (!reaction.isSetSBOTerm()) { + if (reaction.getReactantCount() != 0 && reaction.getProductCount() == 0 && !reaction.isReversible()) { + reaction.setSBOTerm(632); + } + else if (reaction.getReactantCount() == 0 && reaction.getProductCount() != 0 && !reaction.isReversible()) { + reaction.setSBOTerm(628); + } + } } - } - - /** - * Retrieves a local parameter from a reaction's kinetic law based on the specified parameter name. - * This method specifically looks for parameters that define either the lower or upper flux bounds. - * - * @param r The reaction from which the kinetic law and the parameter are to be retrieved. - * @param parameterName The name of the parameter to retrieve, expected to be either "LOWER_BOUND" or "UPPER_BOUND". - * @return The local parameter if found, or {@code null} if the kinetic law is not defined or the parameter does not exist. - */ - private Parameter getBoundFromKineticLawParameters(Reaction r, String parameterName) { - return Optional.ofNullable(r.getKineticLaw()) - .map(kl -> kl.getLocalParameter(parameterName)) - .map(Parameter::new) - .orElse(null); - } - - /** - * Retrieves a modified {@link Parameter} instance based on the specified bound value. - * This method adjusts the ID of the {@link Parameter} based on predefined threshold values. - * If the bound value matches a specific threshold, the ID is set to a corresponding default value. - * Otherwise, the ID is customized using the reaction's ID combined with the original bound's ID. - * - * @param r The {@link Reaction} instance from which the model and parameter are derived. - * @param bound The {@link Parameter} instance representing either a lower or upper bound. - * @param boundValue The numeric value of the bound, which determines how the {@link Parameter}'s ID is set. - */ - private void setBoundId(Reaction r, Parameter bound, double boundValue) { - if (boundValue == -1000d) { - bound.setId("DEFAULT_LOWER_BOUND"); - } else if (boundValue == 0d) { - bound.setId("DEFAULT_BOUND"); - } else if (boundValue == 1000d) { - bound.setId("DEFAULT_UPPER_BOUND"); - } else { - bound.setId(r.getId() + "_" + bound.getId()); + /** + * Sets the Systems Biology Ontology (SBO) term for a reaction based on the abbreviation of its BiGG ID. + * The method matches the abbreviation against predefined patterns to determine the appropriate SBO term. + * + * @param id The BiGGId object containing the abbreviation to be checked. + */ + private void setSBOTermFromPattern(Reaction reaction, BiGGId id) { + String abbrev = id.getAbbreviation(); + if (ReactionNamePatterns.BIOMASS_CASE_INSENSITIVE.getPattern().matcher(abbrev).matches()) { + reaction.setSBOTerm(629); // Set SBO term for biomass production + } else if (ReactionNamePatterns.DEMAND_REACTION.getPattern().matcher(abbrev).matches()) { + reaction.setSBOTerm(628); // Set SBO term for demand reaction + } else if (ReactionNamePatterns.EXCHANGE_REACTION.getPattern().matcher(abbrev).matches()) { + reaction.setSBOTerm(627); // Set SBO term for exchange reaction + } else if (ReactionNamePatterns.ATP_MAINTENANCE.getPattern().matcher(abbrev).matches()) { + reaction.setSBOTerm(630); // Set SBO term for ATP maintenance + } else if (ReactionNamePatterns.SINK_REACTION.getPattern().matcher(abbrev).matches()) { + reaction.setSBOTerm(632); // Set SBO term for sink reaction + } } - } - } diff --git a/src/main/java/edu/ucsd/sbrg/polishing/SBMLPolisher.java b/src/main/java/edu/ucsd/sbrg/polishing/SBMLPolisher.java index 18739079..6daa6086 100644 --- a/src/main/java/edu/ucsd/sbrg/polishing/SBMLPolisher.java +++ b/src/main/java/edu/ucsd/sbrg/polishing/SBMLPolisher.java @@ -18,7 +18,7 @@ import static java.text.MessageFormat.format; -public class SBMLPolisher extends AbstractPolisher { +public class SBMLPolisher extends AbstractPolisher implements IPolishSBases { private static final Logger logger = LoggerFactory.getLogger(SBMLPolisher.class); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); @@ -58,8 +58,6 @@ public void polish(SBMLDocument doc) { Model model = doc.getModel(); new ModelPolisher(polishingParameters, sboParameters, registry, getObservers()).polish(model); - // Process any external resources linked in the document's annotations. - diffReport("documentAnnotation", doc.getAnnotation().clone(), doc.getAnnotation()); new AnnotationPolisher(polishingParameters, registry).polish(doc.getAnnotation()); } diff --git a/src/main/java/edu/ucsd/sbrg/polishing/SpeciesPolisher.java b/src/main/java/edu/ucsd/sbrg/polishing/SpeciesPolisher.java index 0bb19b9c..4a8e67b4 100644 --- a/src/main/java/edu/ucsd/sbrg/polishing/SpeciesPolisher.java +++ b/src/main/java/edu/ucsd/sbrg/polishing/SpeciesPolisher.java @@ -9,25 +9,16 @@ import org.slf4j.Logger; import org.slf4j.LoggerFactory; -import java.util.ArrayList; import java.util.List; -import java.util.Optional; import java.util.ResourceBundle; import static java.text.MessageFormat.format; -/** - * This class is responsible for polishing {@link Species} objects in an SBML model to ensure they conform to - * specific standards and completeness. It handles the annotation processing, ID validation, boundary condition settings, - * and default attribute assignments for species within the model. - */ -public class SpeciesPolisher extends AbstractPolisher { +public class SpeciesPolisher extends AbstractPolisher implements IPolishSBases { private static final Logger logger = LoggerFactory.getLogger(SpeciesPolisher.class); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); - private final List speciesToRemove = new ArrayList<>(); - public SpeciesPolisher(PolishingParameters parameters, Registry registry) { super(parameters, registry); } @@ -37,126 +28,70 @@ public SpeciesPolisher(PolishingParameters parameters, Registry registry, List

species) { logger.debug("Polish Species"); for (Species s : species) { statusReport("Polishing Species (4/9) ", s); // Update progress display for each species - diffReport("species", s.clone(), s); - // Polish each species and collect those that need to be removed polish(s); } - - species.removeAll(speciesToRemove); } - /** - * Polishes the properties of a {@link Species} to ensure compliance with standards and completeness. - * This method processes annotations, checks for missing IDs, sets boundary conditions, and ensures - * that mandatory attributes are set to default values. - */ + public void polish(Species species) { - // Process any external resources linked via annotations in the species new AnnotationPolisher(polishingParameters, registry).polish(species.getAnnotation()); - String id = species.getId(); - - // Check if the species ID is missing and log an error if so - if (id.isEmpty()) { - if (species.isSetName()) { - logger.info(format(MESSAGES.getString("SPECIES_MISSING_ID"), species.getName())); - } else { - logger.info(MESSAGES.getString("SPECIES_MISSING_ID_NAME")); - } - speciesToRemove.add(species); - return; - } - - // Warn if the species ID indicates a boundary species but the boundary condition is not set - if (species.getId().endsWith("_boundary")) { - logger.info(format(MESSAGES.getString("SPECIES_ID_INVALID"), id)); - if (!species.isSetBoundaryCondition() || !species.isBoundaryCondition()) { - logger.info(format(MESSAGES.getString("BOUNDARY_FLAG_MISSING"), id)); - species.setBoundaryCondition(true); - } - } else if (!species.isSetBoundaryCondition()) { - species.setBoundaryCondition(false); - } - // Set default values for mandatory attributes if they are not already set - if (!species.isSetHasOnlySubstanceUnits()) { - species.setHasOnlySubstanceUnits(true); - } - if (!species.isSetConstant()) { - species.setConstant(false); - } if ((species.getCVTermCount() > 0) && !species.isSetMetaId()) { species.setMetaId(species.getId()); } - // Check and potentially update the compartment reference based on BiGG ID - BiGGId.createMetaboliteId(id).ifPresent(biggId -> { - if (biggId.isSetCompartmentCode() && species.isSetCompartment() - && !biggId.getCompartmentCode().equals(species.getCompartment())) { - logger.info(format(MESSAGES.getString("CHANGE_COMPART_REFERENCE"), species.getId(), species.getCompartment(), - biggId.getCompartmentCode())); - species.setCompartment(biggId.getCompartmentCode()); - } - }); - - // Check the compartment of the species - checkCompartment(species); + setBoundaryConditions(species); + + var biggId = BiGGId.createMetaboliteId(species.getId()); + + setCompartmentFromBiggId(species, biggId); + + ensureCompartmentCodeFromBiggIdReferencesCompartment(species, biggId); } - /** - * Checks and sets the compartment for a given species. If the species does not have a compartment set, - * it attempts to set it using the BiGG ID compartment code. If the compartment is still not set or found, - * it logs a warning and creates a new compartment. - * - * @param species The species whose compartment needs to be checked or set. - */ - public void checkCompartment(Species species) { - // Check if the compartment is already set for the species - if (!species.isSetCompartment()) { - // Attempt to get the BiGG ID for the species - Optional biggId = BiGGId.createMetaboliteId(species.getId()); - boolean setCompartment = false; - // If BiGG ID is present, check for compartment code and set it - if (biggId.isPresent()) { - if (biggId.get().isSetCompartmentCode()) { - species.setCompartment(biggId.get().getCompartmentCode()); - setCompartment = true; - } - } - // If compartment is not set, exit the method - if (!setCompartment) { - return; - } + private void setBoundaryConditions(Species species) { + if (species.getId().endsWith("_boundary") && !species.isBoundaryCondition()) { + logger.debug(format(MESSAGES.getString("BOUNDARY_FLAG_MISSING"), species.getId())); + species.setBoundaryCondition(true); } - // Get the compartment ID from the species - String cId = species.getCompartment(); - // Get the model associated with the species - Model model = species.getModel(); + } + + private void setCompartmentFromBiggId(Species species, BiGGId biggId) { + if (biggId.isSetCompartmentCode() && !biggId.getCompartmentCode().equals(species.getCompartment())) { + + logger.debug(format(MESSAGES.getString("CHANGE_COMPART_REFERENCE"), + species.getId(), + species.getCompartment(), + biggId.getCompartmentCode())); - // If model is not available, exit the method - if (model == null) { - return; + species.setCompartment(biggId.getCompartmentCode()); } - // Find the compartment in the model using the compartment ID + } + + private void ensureCompartmentCodeFromBiggIdReferencesCompartment(Species species, BiGGId biggId) { + Model model = species.getModel(); + String cId = biggId.getCompartmentCode(); + SBase candidate = model.findUniqueNamedSBase(cId); - // If the found SBase is a Compartment, polish it - if (candidate instanceof Compartment) { - var compartmentPolisher = new CompartmentPolisher(polishingParameters, registry, getObservers()); - compartmentPolisher.polish((Compartment) candidate); - } else if (candidate == null) { - // If no compartment is found, log a warning and create a new compartment - logger.info(format(MESSAGES.getString("CREATE_MISSING_COMP"), cId, species.getId(), species.getElementName())); - var compartmentPolisher = new CompartmentPolisher(polishingParameters, registry, getObservers()); - compartmentPolisher.polish(model.createCompartment(cId)); + + if(candidate != null && !(candidate instanceof Compartment)) { + // TODO: this is not graceful + candidate.setId(candidate.getId() + "_non_compartment"); + } + + if (candidate == null && cId != null && !cId.isEmpty()) { + logger.debug(format(MESSAGES.getString("CREATE_MISSING_COMP"), + cId, species.getId(), species.getElementName())); + + var compartment = model.createCompartment(cId); + compartment.setConstant(true); // required attribute + + new CompartmentPolisher(polishingParameters, registry, getObservers()).polish(compartment); } } } diff --git a/src/main/java/edu/ucsd/sbrg/polishing/SpeciesReferencesPolisher.java b/src/main/java/edu/ucsd/sbrg/polishing/SpeciesReferencesPolisher.java new file mode 100644 index 00000000..dc0a1a4d --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/polishing/SpeciesReferencesPolisher.java @@ -0,0 +1,19 @@ +package edu.ucsd.sbrg.polishing; + +import org.sbml.jsbml.SpeciesReference; + +public class SpeciesReferencesPolisher implements IPolishSpeciesReferences{ + + private final Integer defaultSBOterm; + + public SpeciesReferencesPolisher(Integer defaultSBOterm) { + this.defaultSBOterm = defaultSBOterm; + } + + @Override + public void polish(SpeciesReference sr) { + if (!sr.isSetSBOTerm() && defaultSBOterm != null) { + sr.setSBOTerm(defaultSBOterm); + } + } +} diff --git a/src/main/java/edu/ucsd/sbrg/polishing/UnitPolisher.java b/src/main/java/edu/ucsd/sbrg/polishing/UnitPolisher.java index 7444a616..b3885a7f 100644 --- a/src/main/java/edu/ucsd/sbrg/polishing/UnitPolisher.java +++ b/src/main/java/edu/ucsd/sbrg/polishing/UnitPolisher.java @@ -12,8 +12,6 @@ import java.util.List; import java.util.Optional; -import static java.text.MessageFormat.format; - /** * This class is responsible for ensuring that all necessary {@link UnitDefinition}s and {@link Unit}s are correctly * defined and present in the SBML model. It handles the creation and verification of units used in the model, @@ -24,7 +22,7 @@ * This ensures that all these components adhere uniformly to the correct unit specifications, * maintaining consistency and accuracy throughout the model's unit definitions. */ -public class UnitPolisher extends AbstractPolisher{ +public class UnitPolisher extends AbstractPolisher implements IPolishSBases { public static final CVTerm CV_TERM_DESCRIBED_BY_PUBMED_GROWTH_UNIT = new CVTerm( CVTerm.Qualifier.BQB_IS_DESCRIBED_BY, @@ -60,7 +58,6 @@ public void polish(Model model) { statusReport("Polishing Unit Definitions (2/9) ", model); var unitDefinitions = model.getListOfUnitDefinitions(); - diffReport("unitDefinitions", unitDefinitions.clone(), unitDefinitions); // Create or retrieve a growth unit definition var growth = createGrowthUnitDefinition(model); diff --git a/src/main/java/edu/ucsd/sbrg/polishing/fbc/FBCPolisher.java b/src/main/java/edu/ucsd/sbrg/polishing/fbc/FBCPolisher.java index db93ad5c..89d47056 100644 --- a/src/main/java/edu/ucsd/sbrg/polishing/fbc/FBCPolisher.java +++ b/src/main/java/edu/ucsd/sbrg/polishing/fbc/FBCPolisher.java @@ -1,10 +1,10 @@ package edu.ucsd.sbrg.polishing.fbc; import de.zbit.util.ResourceManager; +import edu.ucsd.sbrg.parameters.SBOParameters; import edu.ucsd.sbrg.polishing.AbstractPolisher; import edu.ucsd.sbrg.parameters.PolishingParameters; -import edu.ucsd.sbrg.polishing.ReactionsPolisher; -import edu.ucsd.sbrg.polishing.SBMLPolisher; +import edu.ucsd.sbrg.polishing.IPolishSBases; import edu.ucsd.sbrg.reporting.ProgressObserver; import edu.ucsd.sbrg.resolver.Registry; import org.sbml.jsbml.Model; @@ -18,13 +18,15 @@ import static java.text.MessageFormat.format; -public class FBCPolisher extends AbstractPolisher { +public class FBCPolisher extends AbstractPolisher implements IPolishSBases { private static final Logger logger = LoggerFactory.getLogger(FBCPolisher.class); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); + private final SBOParameters sboParameters; - public FBCPolisher(PolishingParameters parameters, Registry registry, List observers) { + public FBCPolisher(PolishingParameters parameters, SBOParameters sboParameters, Registry registry, List observers) { super(parameters, registry, observers); + this.sboParameters = sboParameters; } @Override @@ -37,10 +39,12 @@ public void polish(Model model) { // Polish the list of objectives if set if (modelPlug.isSetListOfObjectives()) { if (modelPlug.getObjectiveCount() == 0) { - // Note: the strict attribute does not require the presence of any Objectives in the model. logger.info(format(MESSAGES.getString("OBJ_MISSING"), modelPlug.getParent().getId())); } else { - new FluxObjectivesPolisher(modelPlug, polishingParameters, registry, getObservers()).polish(modelPlug.getListOfObjectives()); + new ObjectivesPolisher(modelPlug, polishingParameters, registry, getObservers()) + .polish(modelPlug.getListOfObjectives()); + new FBCReactionPolisher(modelPlug, polishingParameters, sboParameters, registry, getObservers()) + .polish(model.getListOfReactions()); } } diff --git a/src/main/java/edu/ucsd/sbrg/polishing/fbc/FBCReactionPolisher.java b/src/main/java/edu/ucsd/sbrg/polishing/fbc/FBCReactionPolisher.java new file mode 100644 index 00000000..6c9ec004 --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/polishing/fbc/FBCReactionPolisher.java @@ -0,0 +1,238 @@ +package edu.ucsd.sbrg.polishing.fbc; + +import edu.ucsd.sbrg.parameters.PolishingParameters; +import edu.ucsd.sbrg.parameters.SBOParameters; +import edu.ucsd.sbrg.polishing.AbstractPolisher; +import edu.ucsd.sbrg.polishing.IPolishSBases; +import edu.ucsd.sbrg.util.ReactionNamePatterns; +import edu.ucsd.sbrg.reporting.ProgressObserver; +import edu.ucsd.sbrg.resolver.Registry; +import edu.ucsd.sbrg.util.ext.fbc.GPRParser; +import org.sbml.jsbml.KineticLaw; +import org.sbml.jsbml.LocalParameter; +import org.sbml.jsbml.Parameter; +import org.sbml.jsbml.Reaction; +import org.sbml.jsbml.ext.fbc.*; +import org.sbml.jsbml.xml.XMLNode; + +import java.util.List; +import java.util.Optional; + +public class FBCReactionPolisher extends AbstractPolisher implements IPolishSBases { + private final FBCModelPlugin fbcPlugin; + private final SBOParameters sboParameters; + private final GeneProductAssociationsProcessor gpaProcessor; + + public FBCReactionPolisher(FBCModelPlugin fbcPlugin, + PolishingParameters polishingParameters, + SBOParameters sboParameters, + Registry registry) { + super(polishingParameters, registry); + this.fbcPlugin = fbcPlugin; + this.sboParameters = sboParameters; + this.gpaProcessor = new GeneProductAssociationsProcessor(); + } + + public FBCReactionPolisher(FBCModelPlugin fbcPlugin, + PolishingParameters polishingParameters, + SBOParameters sboParameters, + Registry registry, + List observers) { + super(polishingParameters, registry, observers); + this.fbcPlugin = fbcPlugin; + this.sboParameters = sboParameters; + this.gpaProcessor = new GeneProductAssociationsProcessor(); + } + + + @Override + public void polish(List reactions) { + for (var reaction : reactions) { + polish(reaction); + } + } + + @Override + public void polish(Reaction reaction) { + if (fbcPlugin.isSetListOfObjectives()) { + fluxObjectiveFromLocalParameter(reaction); + } + associationFromNotes(reaction); + polishBounds(reaction); + gpaProcessor.convertAssociationsToFBCV2(reaction, sboParameters.addGenericTerms()); + } + + + private void fluxObjectiveFromLocalParameter(Reaction reaction) { + Objective obj = fbcPlugin.getActiveObjectiveInstance(); + + // Check if a flux objective associated with the reaction already exists + boolean foExists = obj.getListOfFluxObjectives().stream() + .anyMatch(fo -> fo.getReactionInstance().equals(reaction)); + if (foExists) { + return; + } + // Retrieve the kinetic law of the reaction, if it exists + KineticLaw kl = reaction.getKineticLaw(); + if (kl != null) { + // Attempt to get the objective coefficient from the kinetic law + LocalParameter coefficient = kl.getLocalParameter("OBJECTIVE_COEFFICIENT"); + if (coefficient != null && coefficient.getValue() != 0d) { + // Create a new flux objective with the coefficient and associate it with the reaction + FluxObjective fo = obj.createFluxObjective("fo_" + reaction.getId()); + fo.setCoefficient(coefficient.getValue()); + fo.setReaction(reaction); + } + } + } + + /** + * This method extracts gene associations from the notes of a reaction and converts them into + * the FBCv2 GeneProductAssociation format. It specifically looks for notes tagged with "GENE_ASSOCIATION:" + * and processes them to set the gene product association for the reaction if it has not been set already. + */ + private void associationFromNotes(Reaction reaction) { + // Obtain the FBC plugin for the reaction to handle FBC-specific features. + var reactionPlugin = (FBCReactionPlugin) reaction.getPlugin(FBCConstants.shortLabel); + + // Check if the gene product association is not already set and if the reaction has notes. + if (!reactionPlugin.isSetGeneProductAssociation() && reaction.isSetNotes()) { + // Retrieve the 'body' element from the reaction notes. + XMLNode body = reaction.getNotes().getChildElement("body", null); + + // Process each paragraph within the body that contains exactly one child node. + if (body != null) { + for (XMLNode p : body.getChildElements("p", null)) { + if (p.getChildCount() == 1) { + String associationCandidate = p.getChildAt(0).getCharacters(); + + // Check if the text starts with the expected gene association tag. + if (associationCandidate.startsWith("GENE_ASSOCIATION: ")) { + String[] splits = associationCandidate.split("GENE_ASSOCIATION: "); + + // Ensure the string was split into exactly two parts and the second part is not empty. + if (splits.length == 2) { + String association = splits[1]; + if (!association.isEmpty()) { + // Parse the gene product association and apply it to the reaction. + GPRParser.parseGPR(reaction, association, sboParameters.addGenericTerms()); + } + } + } + } + } + } + } + } + + /** + * Checks if the existing FBC flux bounds are strictly defined and attempts to infer missing bounds from the reaction's kinetic law. + * If bounds are not set, it creates and assigns new global parameters as flux bounds according to the FBC specification. + */ + private void polishBounds(Reaction reaction) { + // TODO: this code does multiple unrelated things at once; check for strictness should be its own function + FBCReactionPlugin rPlug = (FBCReactionPlugin) reaction.getPlugin(FBCConstants.shortLabel); + + Parameter lb = rPlug.getLowerFluxBoundInstance(); + Parameter ub = rPlug.getUpperFluxBoundInstance(); + + // try to set bounds if none exist yet + if (lb == null) { + lb = ensureBound(reaction, "LOWER_BOUND"); + } + if (ub == null) { + ub = ensureBound(reaction, "UPPER_BOUND"); + } + + // set appropriate SBO terms for bounds + if (lb != null) { + setFluxBoundSBOTerm(rPlug.getLowerFluxBoundInstance()); + } + if (ub != null) { + setFluxBoundSBOTerm(rPlug.getUpperFluxBoundInstance()); + } + } + + + private Parameter ensureBound(Reaction reaction, String boundType) { + // set bounds from KineticLaw, if they are not set in FBC, create global Parameter, + // as required by specification + Parameter bound = getBoundFromKineticLawParameters(reaction, boundType); + + if (bound != null) { + setBoundId(reaction, bound, bound.getValue()); + var preexistingParameter = reaction.getModel().getParameter(bound.getId()); + if (preexistingParameter == null) { + reaction.getModel().addParameter(bound); + updateReactionPlugin(reaction, boundType, bound); + } else { + updateReactionPlugin(reaction, boundType, preexistingParameter); + } + } + return bound; + } + + private void updateReactionPlugin(Reaction reaction, String boundType, Parameter parameter) { + FBCReactionPlugin rPlug = (FBCReactionPlugin) reaction.getPlugin(FBCConstants.shortLabel); + if (boundType.equals("LOWER_BOUND")) { + rPlug.setLowerFluxBound(parameter); + } else if (boundType.equals("UPPER_BOUND")) { + rPlug.setUpperFluxBound(parameter); + } + } + + + /** + * Polishes the SBO term of a flux bound parameter based on its ID. + * If the parameter's ID matches the default flux bound pattern, it sets the SBO term to 626. + * Otherwise, it sets the SBO term to 625. + * + * @param bound The parameter representing a flux bound. + */ + public void setFluxBoundSBOTerm(Parameter bound) { + if (ReactionNamePatterns.DEFAULT_FLUX_BOUND.getPattern().matcher(bound.getId()).matches()) { + bound.setSBOTerm(626); // default flux bound + } else { + bound.setSBOTerm(625); // flux bound + } + } + + /** + * Retrieves a local parameter from a reaction's kinetic law based on the specified parameter name. + * This method specifically looks for parameters that define either the lower or upper flux bounds. + * + * @param r The reaction from which the kinetic law and the parameter are to be retrieved. + * @param parameterName The name of the parameter to retrieve, expected to be either "LOWER_BOUND" or "UPPER_BOUND". + * @return The local parameter if found, or {@code null} if the kinetic law is not defined or the parameter does not exist. + */ + private Parameter getBoundFromKineticLawParameters(Reaction r, String parameterName) { + return Optional.ofNullable(r.getKineticLaw()) + .map(kl -> kl.getLocalParameter(parameterName)) + .map(Parameter::new) + .orElse(null); + } + + + /** + * Retrieves a modified {@link Parameter} instance based on the specified bound value. + * This method adjusts the ID of the {@link Parameter} based on predefined threshold values. + * If the bound value matches a specific threshold, the ID is set to a corresponding default value. + * Otherwise, the ID is customized using the reaction's ID combined with the original bound's ID. + * + * @param r The {@link Reaction} instance from which the model and parameter are derived. + * @param bound The {@link Parameter} instance representing either a lower or upper bound. + * @param boundValue The numeric value of the bound, which determines how the {@link Parameter}'s ID is set. + */ + private void setBoundId(Reaction r, Parameter bound, double boundValue) { + if (boundValue == -1000d) { + bound.setId("DEFAULT_LOWER_BOUND"); + } else if (boundValue == 0d) { + bound.setId("DEFAULT_BOUND"); + } else if (boundValue == 1000d) { + bound.setId("DEFAULT_UPPER_BOUND"); + } else { + bound.setId(r.getId() + "_" + bound.getId()); + } + } + +} diff --git a/src/main/java/edu/ucsd/sbrg/polishing/fbc/FluxObjectivesPolisher.java b/src/main/java/edu/ucsd/sbrg/polishing/fbc/FluxObjectivesPolisher.java deleted file mode 100644 index 1f7cbe6e..00000000 --- a/src/main/java/edu/ucsd/sbrg/polishing/fbc/FluxObjectivesPolisher.java +++ /dev/null @@ -1,98 +0,0 @@ -package edu.ucsd.sbrg.polishing.fbc; - -import edu.ucsd.sbrg.polishing.AbstractPolisher; -import edu.ucsd.sbrg.parameters.PolishingParameters; -import edu.ucsd.sbrg.reporting.ProgressObserver; -import edu.ucsd.sbrg.resolver.Registry; -import edu.ucsd.sbrg.util.SBMLFix; -import org.sbml.jsbml.ext.fbc.FBCModelPlugin; -import org.sbml.jsbml.ext.fbc.Objective; -import org.slf4j.Logger; -import org.slf4j.LoggerFactory; - -import java.util.Collection; -import java.util.List; -import java.util.function.Predicate; - -public class FluxObjectivesPolisher extends AbstractPolisher { - private static final Logger logger = LoggerFactory.getLogger(FluxObjectivesPolisher.class); - - private final FBCModelPlugin modelPlug; - - public FluxObjectivesPolisher(FBCModelPlugin modelPlug, PolishingParameters parameters, Registry registry) { - super(parameters, registry); - this.modelPlug = modelPlug; - } - public FluxObjectivesPolisher(FBCModelPlugin modelPlug, PolishingParameters parameters, Registry registry, List observers) { - super(parameters, registry, observers); - this.modelPlug = modelPlug; - } - - /** - * Polishes the list of objectives in the given FBC model plugin. - * This method checks for the presence of objectives and processes each one. - * If no objectives are present, a warning is logged. - * Each objective is checked for the presence of flux objectives, and if absent, attempts to fix them. - * Objectives without any flux objectives are removed from the model. - */ - @Override - public void polish(List objectives) { - logger.debug("Polish Objectives"); - - for (var objective : objectives) { - diffReport("objective", objective.clone(), objective); - statusReport("Polishing Objectives (7/9) ", objective); // "Processing objective " + objective.getId()); - if (!objective.isSetListOfFluxObjectives() || objective.getListOfFluxObjectives().isEmpty()) { - var model = objective.getModel(); - SBMLFix.fixObjective( - model.getId(), - model.getListOfReactions(), - modelPlug, - polishingParameters.fluxObjectivesPolishingParameters().fluxCoefficients(), - polishingParameters.fluxObjectivesPolishingParameters().fluxObjectives()); - } - } - // Identify and remove unused objectives, i.e., those without flux objectives - Collection removals = modelPlug.getListOfObjectives() - .stream() - .filter(Predicate.not(Objective::isSetListOfFluxObjectives) - .or(o -> o.getListOfFluxObjectives().isEmpty())) - .toList(); - modelPlug.getListOfObjectives().removeAll(removals); - } - - - @Override - public void polish(Objective elementToPolish) { - throw new UnsupportedOperationException(); - } - - - // TODO: this logging was pointless but we need to provide this information -// /** -// * Polishes the list of flux objectives within a given objective. -// * This method checks for the presence and validity of flux objectives and logs warnings if: -// * - No flux objectives are present. -// * - There are more than one flux objectives. -// * - Flux objectives have invalid coefficients. -// * -// * @param objective The objective whose flux objectives are to be polished. -// */ -// private void polishListOfFluxObjectives(Objective objective) { -// if (objective.getFluxObjectiveCount() == 0) { -// // Note: the strict attribute does not require the presence of any flux objectives. -// logger.warning(format(MESSAGES.getString("OBJ_FLUX_OBJ_MISSING"), objective.getId())); -// } else { -// if (objective.getFluxObjectiveCount() > 1) { -// logger.warning(format(MESSAGES.getString("TOO_MUCH_OBJ_TARGETS"), objective.getId())); -// } -// for (FluxObjective fluxObjective : objective.getListOfFluxObjectives()) { -// if (!fluxObjective.isSetCoefficient() || Double.isNaN(fluxObjective.getCoefficient()) -// || !Double.isFinite(fluxObjective.getCoefficient())) { -// logger.warning(format(MESSAGES.getString("FLUX_OBJ_COEFF_INVALID"), fluxObjective.getReaction())); -// } -// } -// } -// } - -} diff --git a/src/main/java/edu/ucsd/sbrg/polishing/GeneProductAssociationsProcessor.java b/src/main/java/edu/ucsd/sbrg/polishing/fbc/GeneProductAssociationsProcessor.java similarity index 81% rename from src/main/java/edu/ucsd/sbrg/polishing/GeneProductAssociationsProcessor.java rename to src/main/java/edu/ucsd/sbrg/polishing/fbc/GeneProductAssociationsProcessor.java index 9f202983..278f5f2a 100644 --- a/src/main/java/edu/ucsd/sbrg/polishing/GeneProductAssociationsProcessor.java +++ b/src/main/java/edu/ucsd/sbrg/polishing/fbc/GeneProductAssociationsProcessor.java @@ -1,4 +1,4 @@ -package edu.ucsd.sbrg.polishing; +package edu.ucsd.sbrg.polishing.fbc; import de.zbit.util.ResourceManager; import edu.ucsd.sbrg.db.bigg.BiGGId; @@ -7,15 +7,16 @@ import org.sbml.jsbml.Reaction; import org.sbml.jsbml.ext.fbc.*; import org.sbml.jsbml.xml.XMLNode; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import java.util.*; -import java.util.logging.Logger; import static java.text.MessageFormat.format; public class GeneProductAssociationsProcessor { - private static final Logger logger = Logger.getLogger(GeneProductAssociationsProcessor.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(GeneProductAssociationsProcessor.class); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); /** @@ -101,21 +102,20 @@ private List processAssociation(XMLNode association, Model model, b case "gene": String geneReference = current.getAttributes().getValue("reference"); GeneProductRef gpr = new GeneProductRef(level, version); - BiGGId.createGeneId(geneReference).map(BiGGId::toBiGGId).ifPresent(id -> { - if (!model.containsUniqueNamedSBase(id)) { - GeneProduct gp = (GeneProduct) model.findUniqueNamedSBase(id); - if (gp == null) { - logger.warning(format("Creating missing gene product {0}", id)); - FBCModelPlugin fbcPlug = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); - gp = fbcPlug.createGeneProduct(id); - gp.setLabel(id); - } else { - logger.info(format(MESSAGES.getString("UPDATE_GP_ID"), gp.getId(), id)); - gp.setId(id); - } + var id = BiGGId.createGeneId(geneReference).toBiGGId(); + if (!model.containsUniqueNamedSBase(id)) { + GeneProduct gp = (GeneProduct) model.findUniqueNamedSBase(id); + if (gp == null) { + logger.debug(format("Creating missing gene product {0}", id)); + FBCModelPlugin fbcPlug = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); + gp = fbcPlug.createGeneProduct(id); + gp.setLabel(id); + } else { + logger.info(format(MESSAGES.getString("UPDATE_GP_ID"), gp.getId(), id)); + gp.setId(id); } - gpr.setGeneProduct(id); - }); + } + gpr.setGeneProduct(id); if (gpr.isSetGeneProduct()) { associations.add(gpr); } diff --git a/src/main/java/edu/ucsd/sbrg/polishing/fbc/GeneProductsPolisher.java b/src/main/java/edu/ucsd/sbrg/polishing/fbc/GeneProductsPolisher.java index ab89a1e4..192c1657 100644 --- a/src/main/java/edu/ucsd/sbrg/polishing/fbc/GeneProductsPolisher.java +++ b/src/main/java/edu/ucsd/sbrg/polishing/fbc/GeneProductsPolisher.java @@ -3,6 +3,7 @@ import edu.ucsd.sbrg.polishing.AbstractPolisher; import edu.ucsd.sbrg.polishing.AnnotationPolisher; import edu.ucsd.sbrg.parameters.PolishingParameters; +import edu.ucsd.sbrg.polishing.IPolishSBases; import edu.ucsd.sbrg.reporting.ProgressObserver; import edu.ucsd.sbrg.resolver.Registry; import org.sbml.jsbml.ext.fbc.GeneProduct; @@ -13,10 +14,7 @@ import java.util.List; -/** - * This class is responsible for polishing GeneProduct instances by processing their annotations and adjusting their identifiers and names. - */ -public class GeneProductsPolisher extends AbstractPolisher { +public class GeneProductsPolisher extends AbstractPolisher implements IPolishSBases { private static final Logger logger = LoggerFactory.getLogger(GeneProductsPolisher.class); public GeneProductsPolisher(PolishingParameters parameters, Registry registry, List observers) { @@ -30,60 +28,39 @@ public void polish(List geneProducts) { for (GeneProduct geneProduct : geneProducts) { statusReport("Polishing Gene Products (8/9) ", geneProduct); - diffReport("geneProduct", geneProduct.clone(), geneProduct); polish(geneProduct); } } - /** - * Polishes the GeneProduct by processing its annotations, setting its ID and name based on certain conditions. - * The method first processes the annotations of the GeneProduct. It then determines a suitable label for the - * GeneProduct based on its existing label or ID. If no suitable label is found, the method returns early. - * If a new BiGG ID is generated and differs from the current ID, it updates the GeneProduct's ID and potentially - * its metaId if CV terms are present. Finally, if the GeneProduct does not have a name or its name is "None", - * it sets the GeneProduct's name to the determined label. - */ @Override public void polish(GeneProduct geneProduct) { // Process the annotations associated with the gene product new AnnotationPolisher(polishingParameters, registry).polish(geneProduct.getAnnotation()); - setName(geneProduct); - setIdToBiggId(geneProduct); - } - private void setName(GeneProduct geneProduct) { - - String label = null; - // Determine the label from the gene product's label or ID - if (geneProduct.isSetLabel() && !geneProduct.getLabel().equalsIgnoreCase("None")) { - label = geneProduct.getLabel(); - } else if (geneProduct.isSetId()) { - label = geneProduct.getId(); + if ((geneProduct.getCVTermCount() > 0) && !geneProduct.isSetMetaId()) { + geneProduct.setMetaId(geneProduct.getId()); } - if ((!geneProduct.isSetName() || geneProduct.getName().equalsIgnoreCase("None")) - && label != null) { - geneProduct.setName(label); + setName(geneProduct); + } + + private void setName(GeneProduct geneProduct) { + if (!geneProduct.isSetName() || geneProduct.getName().equalsIgnoreCase("None")) { + if (!geneProduct.getLabel().equalsIgnoreCase("None")) { + geneProduct.setName(geneProduct.getLabel()); + } else { + geneProduct.setName(geneProduct.getId()); + } } } private void setIdToBiggId(GeneProduct geneProduct) { // Create a new BiGG ID for the gene product, if possible - BiGGId.createGeneId(geneProduct.getId()).ifPresent(biggId -> { - String id = biggId.toBiGGId(); - - // Update the gene product's ID if the new ID is different - if (!id.equals(geneProduct.getId())) { - geneProduct.setId(id); - } - - // Set the metaId if there are CV terms associated with the gene product - if (geneProduct.getCVTermCount() > 0) { - geneProduct.setMetaId(id); - } - }); + var biggId = BiGGId.createGeneId(geneProduct.getId()); + String id = biggId.toBiGGId(); + geneProduct.setId(id); } } diff --git a/src/main/java/edu/ucsd/sbrg/polishing/fbc/ObjectivesPolisher.java b/src/main/java/edu/ucsd/sbrg/polishing/fbc/ObjectivesPolisher.java new file mode 100644 index 00000000..1a23701d --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/polishing/fbc/ObjectivesPolisher.java @@ -0,0 +1,75 @@ +package edu.ucsd.sbrg.polishing.fbc; + +import edu.ucsd.sbrg.polishing.AbstractPolisher; +import edu.ucsd.sbrg.parameters.PolishingParameters; +import edu.ucsd.sbrg.polishing.AnnotationPolisher; +import edu.ucsd.sbrg.polishing.IPolishSBases; +import edu.ucsd.sbrg.reporting.ProgressObserver; +import edu.ucsd.sbrg.resolver.Registry; +import org.sbml.jsbml.ext.fbc.FBCModelPlugin; +import org.sbml.jsbml.ext.fbc.Objective; + +import java.util.List; + +public class ObjectivesPolisher extends AbstractPolisher implements IPolishSBases { + + private FBCModelPlugin fbcPlugin; + + public ObjectivesPolisher(FBCModelPlugin fbcPlugin, PolishingParameters parameters, Registry registry) { + super(parameters, registry); + this.fbcPlugin = fbcPlugin; + } + public ObjectivesPolisher(FBCModelPlugin fbcPlugin, PolishingParameters parameters, Registry registry, List observers) { + super(parameters, registry, observers); + this.fbcPlugin = fbcPlugin; + } + + @Override + public void polish(Objective objective) { + statusReport("Polishing Objectives (7/9) ", objective); + + new AnnotationPolisher(polishingParameters, registry).polish(objective.getAnnotation()); + + if ((objective.getCVTermCount() > 0) && !objective.isSetMetaId()) { + objective.setMetaId(objective.getId()); + } + + createDefaultObjective(); + } + + private void createDefaultObjective() { + if (!fbcPlugin.isSetListOfObjectives()) { + var obj = fbcPlugin.createObjective("obj", "default objective", Objective.Type.MAXIMIZE); + fbcPlugin.getListOfObjectives().setActiveObjective(obj.getId()); + } + } + + + // TODO: this logging was pointless but we need to provide this information +// /** +// * Polishes the list of flux objectives within a given objective. +// * This method checks for the presence and validity of flux objectives and logs warnings if: +// * - No flux objectives are present. +// * - There are more than one flux objectives. +// * - Flux objectives have invalid coefficients. +// * +// * @param objective The objective whose flux objectives are to be polished. +// */ +// private void polishListOfFluxObjectives(Objective objective) { +// if (objective.getFluxObjectiveCount() == 0) { +// // Note: the strict attribute does not require the presence of any flux objectives. +// logger.warning(format(MESSAGES.getString("OBJ_FLUX_OBJ_MISSING"), objective.getId())); +// } else { +// if (objective.getFluxObjectiveCount() > 1) { +// logger.warning(format(MESSAGES.getString("TOO_MUCH_OBJ_TARGETS"), objective.getId())); +// } +// for (FluxObjective fluxObjective : objective.getListOfFluxObjectives()) { +// if (!fluxObjective.isSetCoefficient() || Double.isNaN(fluxObjective.getCoefficient()) +// || !Double.isFinite(fluxObjective.getCoefficient())) { +// logger.warning(format(MESSAGES.getString("FLUX_OBJ_COEFF_INVALID"), fluxObjective.getReaction())); +// } +// } +// } +// } + +} diff --git a/src/main/java/edu/ucsd/sbrg/reporting/IReportDiffs.java b/src/main/java/edu/ucsd/sbrg/reporting/IReportDiffs.java new file mode 100644 index 00000000..4e95c01c --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/reporting/IReportDiffs.java @@ -0,0 +1,7 @@ +package edu.ucsd.sbrg.reporting; + +public interface IReportDiffs { + + void diffReport(String elementType, Object element1, Object element2); + +} diff --git a/src/main/java/edu/ucsd/sbrg/reporting/IReportStatus.java b/src/main/java/edu/ucsd/sbrg/reporting/IReportStatus.java new file mode 100644 index 00000000..25faee7d --- /dev/null +++ b/src/main/java/edu/ucsd/sbrg/reporting/IReportStatus.java @@ -0,0 +1,7 @@ +package edu.ucsd.sbrg.reporting; + +public interface IReportStatus { + + void statusReport(String text, Object element); + +} diff --git a/src/main/java/edu/ucsd/sbrg/resolver/Registry.java b/src/main/java/edu/ucsd/sbrg/resolver/Registry.java index bd9a8ae2..a70d0c38 100644 --- a/src/main/java/edu/ucsd/sbrg/resolver/Registry.java +++ b/src/main/java/edu/ucsd/sbrg/resolver/Registry.java @@ -10,7 +10,7 @@ public interface Registry { String getPatternByNamespaceName(String namespaceName); - Optional findRegistryUrlForOtherUrl(String url); + Optional resolveBackwards(String url); boolean validRegistryUrlPrefix(RegistryURI uri); diff --git a/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrg.java b/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrg.java index 2dcee749..b3f1bda5 100644 --- a/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrg.java +++ b/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrg.java @@ -4,7 +4,6 @@ import java.io.IOException; import java.util.*; -import java.util.logging.Logger; import java.util.regex.Matcher; import java.util.regex.Pattern; @@ -14,6 +13,8 @@ import edu.ucsd.sbrg.resolver.identifiersorg.mapping.RawIdentifiersOrgRegistry; import edu.ucsd.sbrg.resolver.identifiersorg.mapping.Resource; import org.apache.commons.lang3.tuple.Pair; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The {@code IdentifiersOrg} class serves as a central hub for managing and processing identifiers related to the MIRIAM registry. @@ -25,7 +26,7 @@ */ public class IdentifiersOrg implements Registry { - private static final Logger logger = Logger.getLogger(IdentifiersOrg.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(IdentifiersOrg.class); private static final Map NAMESPACE_NAME_BY_PREFIX; private static final Map PATTERN_BY_NAMESPACE_NAME; @@ -86,9 +87,8 @@ public String getPatternByNamespaceName(String namespaceName) { * @return An {@link Optional} containing the processed URL if valid, or empty if the URL should be skipped. */ @Override - public Optional findRegistryUrlForOtherUrl(String url) { - // Remove trailing whitespaces from the URL - url = url.stripTrailing(); + public Optional resolveBackwards(String url) { + url = url.trim(); if (isValid(url)) { return Optional.of(new IdentifiersOrgURI(url)); diff --git a/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrgRegistryParser.java b/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrgRegistryParser.java index b7380bbc..ca465c00 100644 --- a/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrgRegistryParser.java +++ b/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrgRegistryParser.java @@ -2,12 +2,13 @@ import java.io.IOException; import java.io.InputStream; -import java.util.logging.Logger; import com.fasterxml.jackson.databind.DeserializationFeature; import com.fasterxml.jackson.databind.ObjectMapper; import edu.ucsd.sbrg.resolver.identifiersorg.mapping.RawIdentifiersOrgRegistry; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; /** * The {@code IdentifiersOrgRegistryParser} class is a singleton that provides functionality to parse the MIRIAM registry @@ -16,10 +17,10 @@ */ public class IdentifiersOrgRegistryParser { - private static final Logger logger = Logger.getLogger(IdentifiersOrgRegistryParser.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(IdentifiersOrgRegistryParser.class); public RawIdentifiersOrgRegistry parse(InputStream registry) throws IOException { - logger.fine("Parsing MIRIAM registry"); + logger.trace("Parsing MIRIAM registry"); ObjectMapper mapper = new ObjectMapper(); mapper.configure(DeserializationFeature.FAIL_ON_UNKNOWN_PROPERTIES, false); diff --git a/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrgURI.java b/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrgURI.java index cb3052a1..5feb0488 100644 --- a/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrgURI.java +++ b/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrgURI.java @@ -2,7 +2,6 @@ import edu.ucsd.sbrg.db.bigg.BiGGId; import edu.ucsd.sbrg.resolver.RegistryURI; -import org.jetbrains.annotations.NotNull; import java.util.Objects; import java.util.regex.Matcher; @@ -77,7 +76,7 @@ public int hashCode() { } @Override - public int compareTo(@NotNull IdentifiersOrgURI uri) { + public int compareTo(IdentifiersOrgURI uri) { return this.getURI().compareTo(uri.getURI()); } } diff --git a/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrgURIUtils.java b/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrgURIUtils.java index 1acbdf6e..73049674 100644 --- a/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrgURIUtils.java +++ b/src/main/java/edu/ucsd/sbrg/resolver/identifiersorg/IdentifiersOrgURIUtils.java @@ -1,19 +1,17 @@ package edu.ucsd.sbrg.resolver.identifiersorg; -import org.jetbrains.annotations.NotNull; - import java.util.regex.Matcher; import java.util.regex.Pattern; public class IdentifiersOrgURIUtils { - public static @NotNull String addJavaRegexCaptureGroup(String pattern) { + public static String addJavaRegexCaptureGroup(String pattern) { String idPattern = pattern.replaceAll("\\^|\\$", ""); idPattern = "(?" + idPattern + ")"; return idPattern; } - public static @NotNull String removeHttpProtocolFromUrl(String query) { + public static String removeHttpProtocolFromUrl(String query) { if (query.startsWith("http://") || query.startsWith("https://")) { Matcher protocolMatcher = Pattern.compile("^https?://").matcher(query); if (protocolMatcher.find()) { diff --git a/src/main/java/edu/ucsd/sbrg/polishing/ReactionNamePatterns.java b/src/main/java/edu/ucsd/sbrg/util/ReactionNamePatterns.java similarity index 98% rename from src/main/java/edu/ucsd/sbrg/polishing/ReactionNamePatterns.java rename to src/main/java/edu/ucsd/sbrg/util/ReactionNamePatterns.java index 8d57f8d7..8bb95f9b 100644 --- a/src/main/java/edu/ucsd/sbrg/polishing/ReactionNamePatterns.java +++ b/src/main/java/edu/ucsd/sbrg/util/ReactionNamePatterns.java @@ -1,4 +1,4 @@ -package edu.ucsd.sbrg.polishing; +package edu.ucsd.sbrg.util; import java.util.regex.Pattern; diff --git a/src/main/java/edu/ucsd/sbrg/util/SBMLFix.java b/src/main/java/edu/ucsd/sbrg/util/SBMLFix.java deleted file mode 100644 index ef57ae01..00000000 --- a/src/main/java/edu/ucsd/sbrg/util/SBMLFix.java +++ /dev/null @@ -1,220 +0,0 @@ -/** - * - */ -package edu.ucsd.sbrg.util; - -import de.zbit.io.ZIPUtils; -import de.zbit.io.filefilter.SBFileFilter; -import de.zbit.util.ResourceManager; -import de.zbit.util.Utils; -import de.zbit.util.logging.LogUtil; -import edu.ucsd.sbrg.ModelPolisherCLILauncher; -import edu.ucsd.sbrg.io.ModelWriter; -import edu.ucsd.sbrg.polishing.ReactionNamePatterns; -import org.sbml.jsbml.ListOf; -import org.sbml.jsbml.Model; -import org.sbml.jsbml.Reaction; -import org.sbml.jsbml.SBMLDocument; -import org.sbml.jsbml.SBMLReader; -import org.sbml.jsbml.TidySBMLWriter; -import org.sbml.jsbml.ext.fbc.FBCConstants; -import org.sbml.jsbml.ext.fbc.FBCModelPlugin; -import org.sbml.jsbml.ext.fbc.Objective; -import org.sbml.jsbml.ext.groups.Group; -import org.sbml.jsbml.ext.groups.GroupsConstants; -import org.sbml.jsbml.ext.groups.GroupsModelPlugin; -import org.slf4j.LoggerFactory; - -import javax.xml.stream.XMLStreamException; -import java.io.File; -import java.io.IOException; -import java.text.MessageFormat; -import java.util.List; -import java.util.ResourceBundle; -import java.util.logging.Logger; -import java.util.regex.Pattern; - -/** - * This is a stand-alone bug-fix program. It recursively traverses a directory - * of SBML files and applies fixes to each model found. The result is saved to - * a target directory, which can be in-place, i.e., identical to the input - * directory. Otherwise, an identical directory structure will be created within - * the target directory. - *

- * This program became necessary as a temporary solution for invalid SBML models - * in BiGG database before a new version of {@link ModelPolisherCLILauncher} could be - * released. - *

- * The methods in this class can also be used in other parts of ModelPolisher, - * and are used in fact. This class can become a collection of repair functions - * for invalid SBML models. - *

- * Date: 2016-02-19 - * @author Andreas Dräger - */ -public class SBMLFix { - - private static final org.slf4j.Logger logger = LoggerFactory.getLogger(SBMLFix.class); - private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); - private static final double DEFAULT_COEFFICIENT = 1d; - - public static void batchProcess(File input, File output) { - if (!output.exists() && !output.isFile() && !(input.isFile() && input.getName().equals(output.getName()))) { - logger.info(MessageFormat.format(MESSAGES.getString("DIRECTORY_CREATED"), output.getAbsolutePath())); - output.mkdir(); - } - if (input.isFile()) { - if (SBFileFilter.isSBMLFile(input)) { - if (output.isDirectory()) { - String fName = input.getName(); - output = new File(Utils.ensureSlash(output.getAbsolutePath()) + fName); - } - try { - fixSBML(input, output); - } catch (XMLStreamException | IOException exc) { - logger.error(exc.getMessage()); - } - } - } else { - if (!output.isDirectory()) { - logger.error(MessageFormat.format(MESSAGES.getString("WRITE_TO_FILE_ERROR"), output.getAbsolutePath())); - } - for (File file : input.listFiles()) { - File target = new File(Utils.ensureSlash(output.getAbsolutePath()) + file.getName()); - batchProcess(file, target); - } - } - } - - - /** - * Set group kind where required - * - */ - public static void fixGroups(Model model) { - GroupsModelPlugin gPlug = (GroupsModelPlugin) model.getExtension(GroupsConstants.shortLabel); - if ((gPlug != null) && gPlug.isSetListOfGroups()) { - for (Group group : gPlug.getListOfGroups()) { - if (!group.isSetKind()) { - logger.info(MessageFormat.format(MESSAGES.getString("ADD_KIND_TO_GROUP"), - group.isSetName() ? group.getName() : group.getId())); - group.setKind(Group.Kind.partonomy); - } - } - } - } - - - /** - * Check for missing objective function. - * - * @param modelDescriptor - * this can be the path to the model file or some name that describes - * this model. - */ - public static void fixObjective(String modelDescriptor, Model model) { - FBCModelPlugin fbcPlug = (FBCModelPlugin) model.getExtension(FBCConstants.shortLabel); - if ((fbcPlug != null) && fbcPlug.isSetListOfObjectives()) { - fixObjective(modelDescriptor, model.isSetListOfReactions() ? model.getListOfReactions() : null, fbcPlug); - } - } - - - /** - * @param modelDescriptor - * some descriptive String for the model, e.g., its id, the path to the - * file, or any other meaningful information for users. - */ - public static void fixObjective(String modelDescriptor, ListOf listOfReactions, FBCModelPlugin fbcPlug) { - fixObjective(modelDescriptor, listOfReactions, fbcPlug, null, null); - } - - - public static void fixObjective(String modelDescriptor, ListOf listOfReactions, FBCModelPlugin fbcPlug, - List fluxCoefficients, List fluxObjectives) { - Objective activeObjective = null; - if (!fbcPlug.isSetActiveObjective()) { - logger.info(MessageFormat.format(MESSAGES.getString("OBJ_NOT_DEFINED"), modelDescriptor)); - if (fbcPlug.getObjectiveCount() == 1) { - activeObjective = fbcPlug.getObjective(0); - fbcPlug.setActiveObjective(activeObjective); - logger.info(MessageFormat.format(MESSAGES.getString("OBJ_SOLUTION"), activeObjective.getId())); - } - } else { - activeObjective = fbcPlug.getListOfObjectives().getActiveObjectiveInstance(); - } - if (activeObjective != null) { - if (!activeObjective.isSetListOfFluxObjectives()) { - logger.info(MessageFormat.format(MESSAGES.getString("TRY_GUESS_MISSING_FLUX_OBJ"), modelDescriptor)); - if (listOfReactions != null) { - if (fluxObjectives != null && !fluxObjectives.isEmpty()) { - /* - * An array of target reactions is provided. We want to use this as - * flux objectives. - */ - for (int i = 0; i < fluxObjectives.size(); i++) { - final String id = fluxObjectives.get(i); - Reaction r = listOfReactions.firstHit((obj) -> - (obj instanceof Reaction) && id.equals(((Reaction) obj).getId())); - if (r != null) { - createFluxObjective(modelDescriptor, r, fluxCoefficients, activeObjective, i); - } else { - logger.info(MessageFormat.format(MESSAGES.getString("REACTION_UNKNOWN_ERROR"), id, modelDescriptor)); - } - } - } else { - /* - * Search for biomass reaction in the model and use this as - * objective. - */ - final Pattern pattern = ReactionNamePatterns.BIOMASS_CASE_INSENSITIVE.getPattern(); - Reaction rBiomass = listOfReactions.firstHit((obj) -> - (obj instanceof Reaction) && pattern.matcher(((Reaction) obj).getId()).matches()); - if (rBiomass != null) { - createFluxObjective(modelDescriptor, rBiomass, fluxCoefficients, activeObjective, 0); - } else { - logger.info(MESSAGES.getString("REACTION_BIOMASS_UNKNOWN_ERROR")); - } - } - } else { - logger.info(MessageFormat.format(MESSAGES.getString("REACTION_LIST_MISSING"), modelDescriptor)); - } - } - } - } - - - private static void createFluxObjective(String modelDescriptor, Reaction r, List fluxCoefficients, Objective o, - int i) { - double coeff = DEFAULT_COEFFICIENT; - if ((fluxCoefficients != null) && (fluxCoefficients.size() > i)) { - coeff = fluxCoefficients.get(i); - } - logger.info(MessageFormat.format(MESSAGES.getString("ADDED_FLUX_OBJ"), r.getId(), coeff, modelDescriptor)); - o.createFluxObjective(null, null, coeff, r); - } - - - public static void fixSBML(File in, File out) throws XMLStreamException, IOException { - long time = System.currentTimeMillis(); - logger.info(MessageFormat.format(MESSAGES.getString("READ_FILE_INFO"), in.getAbsolutePath())); - SBMLDocument doc = SBMLReader.read(in); - Model model = doc.getModel(); - fixGroups(model); - fixObjective(in.getAbsolutePath(), model); - logger.info(MessageFormat.format(MESSAGES.getString("WRITE_FILE_INFO"), out.getAbsolutePath())); - TidySBMLWriter.write(doc, out, ModelPolisherCLILauncher.class.getName(), "1.1", ' ', (short) 2); - String archive = out.getAbsolutePath() + ".gz"; - logger.info(MessageFormat.format("ARCHIVE {0}", archive)); - ZIPUtils.GZip(out.getAbsolutePath(), archive); - logger.info(MessageFormat.format("Done. Time elapsed: {0,number,integer} ms", System.currentTimeMillis() - time)); - } - - - /** - */ - public static void main(String[] args) { - LogUtil.initializeLogging("de.zbit", "edu.ucsd.sbrg"); - batchProcess(new File(args[0]), new File(args[1])); - } -} diff --git a/src/main/java/edu/ucsd/sbrg/util/GPRParser.java b/src/main/java/edu/ucsd/sbrg/util/ext/fbc/GPRParser.java similarity index 84% rename from src/main/java/edu/ucsd/sbrg/util/GPRParser.java rename to src/main/java/edu/ucsd/sbrg/util/ext/fbc/GPRParser.java index ac97a1f1..56a655b4 100644 --- a/src/main/java/edu/ucsd/sbrg/util/GPRParser.java +++ b/src/main/java/edu/ucsd/sbrg/util/ext/fbc/GPRParser.java @@ -1,13 +1,12 @@ -package edu.ucsd.sbrg.util; +package edu.ucsd.sbrg.util.ext.fbc; import java.io.StringReader; import java.util.HashSet; import java.util.List; import java.util.ResourceBundle; import java.util.Set; -import java.util.logging.Logger; -import edu.ucsd.sbrg.io.parsers.cobra.MatlabParser; +import de.zbit.util.Utils; import org.sbml.jsbml.*; import org.sbml.jsbml.ext.fbc.And; import org.sbml.jsbml.ext.fbc.Association; @@ -22,8 +21,9 @@ import org.sbml.jsbml.text.parser.CobraFormulaParser; import de.zbit.util.ResourceManager; -import de.zbit.util.Utils; import edu.ucsd.sbrg.db.bigg.BiGGId; +import org.sbml.jsbml.text.parser.ParseException; +import org.slf4j.Logger; import org.slf4j.LoggerFactory; import static java.text.MessageFormat.format; @@ -44,7 +44,7 @@ */ public class GPRParser { - private static final org.slf4j.Logger logger = LoggerFactory.getLogger(GPRParser.class); + private static final Logger logger = LoggerFactory.getLogger(GPRParser.class); private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); @@ -59,18 +59,19 @@ public class GPRParser { * @param omitGenericTerms Flag indicating whether to omit generic terms (e.g., SBO terms) in the association. */ public static void parseGPR(Reaction r, String geneReactionRule, boolean omitGenericTerms) { - if ((geneReactionRule != null) && (!geneReactionRule.isEmpty())) { - Association association = null; - try { - association = - convertToAssociation(ASTNode.parseFormula(geneReactionRule, new CobraFormulaParser(new StringReader(""))), - r.getId(), r.getModel(), omitGenericTerms); - } catch (Throwable exc) { - logger.info(format(MESSAGES.getString("PARSE_GPR_ERROR"), geneReactionRule, Utils.getMessage(exc))); - } - if (association != null) { - parseGPR(r, association, omitGenericTerms); - } + ASTNode ast = null; + try { + ast = ASTNode.parseFormula( + geneReactionRule, + new CobraFormulaParser(new StringReader(""))); + Association association = convertToAssociation( + ast, + r.getId(), + r.getModel(), + omitGenericTerms); + parseGPR(r, association, omitGenericTerms); + } catch (ParseException e) { + logger.info(format(MESSAGES.getString("PARSE_GPR_ERROR"), geneReactionRule, Utils.getMessage(e))); } } @@ -136,36 +137,35 @@ public static GeneProductRef createGPR(String identifier, String reactionId, Mod // Determine the SBML document level and version for creating new elements. int level = model.getLevel(), version = model.getVersion(); GeneProductRef gpr = new GeneProductRef(level, version); - + // Normalize the identifier to include "G_" prefix if missing. String oldId = identifier.startsWith("G_") ? identifier : "G_" + identifier; boolean containsOldId = !model.containsUniqueNamedSBase(oldId); - + // Attempt to create or find the GeneProduct using a standardized identifier. - BiGGId.createGeneId(identifier).map(BiGGId::toBiGGId).ifPresent(id -> { - if (!model.containsUniqueNamedSBase(id)) { - GeneProduct gp; - // Check if the old ID exists, if so, retrieve the GeneProduct, otherwise use the new ID. - if (containsOldId) { - gp = (GeneProduct) model.findUniqueNamedSBase(oldId); - } else { - gp = (GeneProduct) model.findUniqueNamedSBase(id); - } - // If the GeneProduct does not exist, create a new one and log a warning. - if (gp == null) { - logger.info(format(MESSAGES.getString("CREATE_MISSING_GPR"), id, reactionId)); - FBCModelPlugin fbcPlug = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); - gp = fbcPlug.createGeneProduct(id); - gp.setLabel(id); - } else { - // If the GeneProduct exists, update its ID and log the update. - logger.info(format(MESSAGES.getString("UPDATE_GP_ID"), gp.getId(), id)); - gp.setId(id); - } + var id = BiGGId.createGeneId(identifier).toBiGGId(); + if (!model.containsUniqueNamedSBase(id)) { + GeneProduct gp; + // Check if the old ID exists, if so, retrieve the GeneProduct, otherwise use the new ID. + if (containsOldId) { + gp = (GeneProduct) model.findUniqueNamedSBase(oldId); + } else { + gp = (GeneProduct) model.findUniqueNamedSBase(id); } - // Set the GeneProduct reference in the GeneProductRef. - gpr.setGeneProduct(id); - }); + // If the GeneProduct does not exist, create a new one and log a warning. + if (gp == null) { + logger.info(format(MESSAGES.getString("CREATE_MISSING_GPR"), id, reactionId)); + FBCModelPlugin fbcPlug = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); + gp = fbcPlug.createGeneProduct(id); + gp.setLabel(id); + } else { + // If the GeneProduct exists, update its ID and log the update. + logger.info(format(MESSAGES.getString("UPDATE_GP_ID"), gp.getId(), id)); + gp.setId(id); + } + } + // Set the GeneProduct reference in the GeneProductRef. + gpr.setGeneProduct(id); return gpr; } @@ -180,13 +180,13 @@ public static GeneProductRef createGPR(String identifier, String reactionId, Mod * @param omitGenericTerms A boolean flag indicating whether generic terms should be omitted during the merging process. */ private static void parseGPR(Reaction r, Association association, boolean omitGenericTerms) { - FBCReactionPlugin plugin = (FBCReactionPlugin) r.getPlugin(FBCConstants.shortLabel); - if (!plugin.isSetGeneProductAssociation()) { - GeneProductAssociation gpa = new GeneProductAssociation(r.getLevel(), r.getVersion()); + var reactionPlugin = (FBCReactionPlugin) r.getPlugin(FBCConstants.shortLabel); + if (!reactionPlugin.isSetGeneProductAssociation()) { + var gpa = new GeneProductAssociation(r.getLevel(), r.getVersion()); gpa.setAssociation(association); - plugin.setGeneProductAssociation(gpa); - } else if (!areEqual(association, plugin.getGeneProductAssociation().getAssociation())) { - mergeAssociation(r, association, plugin, omitGenericTerms); + reactionPlugin.setGeneProductAssociation(gpa); + } else if (!areEqual(association, reactionPlugin.getGeneProductAssociation().getAssociation())) { + mergeAssociation(r, association, reactionPlugin, omitGenericTerms); } } diff --git a/src/main/java/edu/ucsd/sbrg/util/SBMLUtils.java b/src/main/java/edu/ucsd/sbrg/util/ext/groups/GroupsUtils.java similarity index 95% rename from src/main/java/edu/ucsd/sbrg/util/SBMLUtils.java rename to src/main/java/edu/ucsd/sbrg/util/ext/groups/GroupsUtils.java index 37f6fcb8..95866769 100644 --- a/src/main/java/edu/ucsd/sbrg/util/SBMLUtils.java +++ b/src/main/java/edu/ucsd/sbrg/util/ext/groups/GroupsUtils.java @@ -1,7 +1,7 @@ /** * */ -package edu.ucsd.sbrg.util; +package edu.ucsd.sbrg.util.ext.groups; import org.sbml.jsbml.Reaction; import org.sbml.jsbml.ext.groups.Member; @@ -14,7 +14,7 @@ * * @author Andreas Dräger */ -public class SBMLUtils { +public class GroupsUtils { /** * Key to link from {@link Reaction} directly to {@link Member}s referencing diff --git a/src/main/java/edu/ucsd/sbrg/ModelValidator.java b/src/main/java/edu/ucsd/sbrg/validation/ModelValidator.java similarity index 67% rename from src/main/java/edu/ucsd/sbrg/ModelValidator.java rename to src/main/java/edu/ucsd/sbrg/validation/ModelValidator.java index 054f379b..eb5a167f 100644 --- a/src/main/java/edu/ucsd/sbrg/ModelValidator.java +++ b/src/main/java/edu/ucsd/sbrg/validation/ModelValidator.java @@ -1,4 +1,4 @@ -package edu.ucsd.sbrg; +package edu.ucsd.sbrg.validation; import de.zbit.io.ZIPUtils; import de.zbit.util.ResourceManager; @@ -7,17 +7,27 @@ import org.sbml.jsbml.SBMLErrorLog; import org.sbml.jsbml.SBMLReader; import org.sbml.jsbml.validator.offline.LoggingValidationContext; +import org.slf4j.Logger; +import org.slf4j.LoggerFactory; import javax.xml.stream.XMLStreamException; import java.io.*; import java.util.ResourceBundle; -import java.util.logging.Logger; import static java.text.MessageFormat.format; public class ModelValidator { private static final ResourceBundle MESSAGES = ResourceManager.getBundle("edu.ucsd.sbrg.polisher.Messages"); - private static final Logger logger = Logger.getLogger(ModelValidator.class.getName()); + private static final Logger logger = LoggerFactory.getLogger(ModelValidator.class); + + + public SBMLErrorLog validate(SBMLDocument doc) { + LoggingValidationContext context = new LoggingValidationContext(doc.getLevel(), doc.getVersion()); + context.setValidateRecursively(true); + context.loadConstraints(SBMLDocument.class, doc.getLevel(), doc.getVersion()); + context.validate(doc); + return context.getErrorLog(); + } public void validate(File outputFile) throws ModelValidatorException { @@ -36,13 +46,10 @@ public void validate(File outputFile) throws ModelValidatorException { } doc = SBMLReader.read(istream); if (doc != null) { - LoggingValidationContext context = new LoggingValidationContext(doc.getLevel(), doc.getVersion()); - context.loadConstraints(SBMLDocument.class); - context.validate(doc); - SBMLErrorLog sbmlErrorLog = context.getErrorLog(); - handleErrorLog(sbmlErrorLog, filename); + SBMLErrorLog sbmlErrorLog = validate(doc); + logErrorLog(sbmlErrorLog, filename); } else { - logger.severe(format(MESSAGES.getString("VAL_OFFLINE_FAIL"), filename)); + logger.info(format(MESSAGES.getString("VAL_OFFLINE_FAIL"), filename)); } } catch (XMLStreamException | IOException e) { throw new ModelValidatorException(e, outputFile); @@ -50,13 +57,13 @@ public void validate(File outputFile) throws ModelValidatorException { } - private void handleErrorLog(SBMLErrorLog sbmlErrorLog, String filename) { + private void logErrorLog(SBMLErrorLog sbmlErrorLog, String filename) { if (sbmlErrorLog != null) { logger.info(format(MESSAGES.getString("VAL_ERR_COUNT"), sbmlErrorLog.getErrorCount(), filename)); // printErrors for (int j = 0; j < sbmlErrorLog.getErrorCount(); j++) { SBMLError error = sbmlErrorLog.getError(j); - logger.warning(error.toString()); + logger.info(error.toString()); } } else { logger.info(MESSAGES.getString("VAL_ERROR")); diff --git a/src/main/java/edu/ucsd/sbrg/ModelValidatorException.java b/src/main/java/edu/ucsd/sbrg/validation/ModelValidatorException.java similarity index 90% rename from src/main/java/edu/ucsd/sbrg/ModelValidatorException.java rename to src/main/java/edu/ucsd/sbrg/validation/ModelValidatorException.java index 82128864..ee01e483 100644 --- a/src/main/java/edu/ucsd/sbrg/ModelValidatorException.java +++ b/src/main/java/edu/ucsd/sbrg/validation/ModelValidatorException.java @@ -1,4 +1,4 @@ -package edu.ucsd.sbrg; +package edu.ucsd.sbrg.validation; import java.io.File; diff --git a/src/main/resources/edu/ucsd/sbrg/bigg/about.html b/src/main/resources/edu/ucsd/sbrg/about.html similarity index 100% rename from src/main/resources/edu/ucsd/sbrg/bigg/about.html rename to src/main/resources/edu/ucsd/sbrg/about.html diff --git a/src/main/resources/edu/ucsd/sbrg/bigg/ZBIT_ModelNotes.html b/src/main/resources/edu/ucsd/sbrg/bigg/ZBIT_ModelNotes.html deleted file mode 100644 index f22e2b2b..00000000 --- a/src/main/resources/edu/ucsd/sbrg/bigg/ZBIT_ModelNotes.html +++ /dev/null @@ -1,107 +0,0 @@ - - - - - - ${title} - - - - - - - - - - -

Description

- -
-

- This is a model of ${organism} in - SBML format. -

-
- -
-

- The content of this model has been created by individual researchers and postprocessed using the - online version of the - JSBML-based - ModelPolisher application. -

-
- -
-

- This file has been produced by the - webservice facility of the - Center for Bioinformatics Tuebingen (ZBIT) using a local mirror of the - BiGG Models knowledgebase version of ${bigg.timestamp}. -

-
- -

Terms of use

-
-

Copyright © ${year} The Regents of the University of California and the University of Tuebingen.

-
-
-

- Redistribution and use of any part of models from BiGG Models knowledgebase, - with or without modification, are permitted provided that the - following conditions are met: -

    -
  1. Redistributions of this SBML file must retain the above copyright - notice, this list of conditions and the following disclaimer.
  2. -
  3. Redistributions in a different form must reproduce the above - copyright notice, this list of conditions and the following - disclaimer in the documentation and/or other materials - provided with the distribution.
  4. -
-

- This model 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. -

-
- -

References

- -

- When using webservices of the Center for Bioinformatics Tuebingen (ZBIT), the software - JSBML or - ModelPolisher, or content from the - BiGG Models knowledgebase in your research works, please cite -

-
-
Römer M., Eichner J., Dräger A., Wrzodek C., Wrzodek F., Zell A. (2016). -
- ZBIT Bioinformatics Toolbox: a Web-Platform for Systems Biology and Expression Data Analysis. - PLoS ONE. -
- -
King ZA, Lu JS, Dräger A, Miller PC, Federowicz S, Lerman JA, - Ebrahim A, Palsson BO, and Lewis NE. (2015). -
- BiGG Models: A platform for integrating, standardizing, and sharing genome-scale models. - Nucl Acids Res. -
- -
Rodriguez N., Thomas A., Watanabe L., Vazirabad I.Y., Kofia V., Gómez HF, - Mittag F., Matthes J., Rodolph J., Wrzodek F., Netz E., Diamantikos A., Eichner J., - Keller R., Wrzodek C., Fröhlich S., Lewis N.E., Myers C.J., Le Novère N., - Palsson B.Ø., Hucka M., and Dräger A. (2015). -
- JSBML 1.0: providing a smorgasbord of options to encode systems biology models. - Bioinformatics. 2015 May 29. -
- -
- - ${species_table} - - - diff --git a/src/main/resources/edu/ucsd/sbrg/bigg/ZBIT_SBMLDocumentNotes.html b/src/main/resources/edu/ucsd/sbrg/bigg/ZBIT_SBMLDocumentNotes.html deleted file mode 100644 index 0763e28c..00000000 --- a/src/main/resources/edu/ucsd/sbrg/bigg/ZBIT_SBMLDocumentNotes.html +++ /dev/null @@ -1,35 +0,0 @@ - - - - - - ${title} - - - - - - - - - - - -
-
-

-
${title}
-

-
-
- - - diff --git a/src/main/resources/edu/ucsd/sbrg/polisher/Messages.xml b/src/main/resources/edu/ucsd/sbrg/polisher/Messages.xml index 277aa209..85c1dca0 100644 --- a/src/main/resources/edu/ucsd/sbrg/polisher/Messages.xml +++ b/src/main/resources/edu/ucsd/sbrg/polisher/Messages.xml @@ -128,7 +128,7 @@ No objectives defined for model {0}. No active objective defined in model {0}. The problem could be successfully solved by declaring {0} the active objective. - Set this option to true if generic top-level annotations, such as 'process' should not be applied. Not using those terms will reduce the size of the resulting output file. + Set this option to true if generic top-level annotations, such as 'process' should not be applied. Not using those terms will reduce the size of the resulting output file. Please open an issue to see annotation format {0} implemented. Please open an issue to see parsing for id format {0} implemented. Please open an issue to see notes format {0} implemented. diff --git a/src/main/resources/edu/ucsd/sbrg/polisher/Messages_de.xml b/src/main/resources/edu/ucsd/sbrg/polisher/Messages_de.xml index 660b54a1..f5165168 100644 --- a/src/main/resources/edu/ucsd/sbrg/polisher/Messages_de.xml +++ b/src/main/resources/edu/ucsd/sbrg/polisher/Messages_de.xml @@ -128,7 +128,7 @@ Keine Zielfunktion für das Model {0} definiert. Keine aktive Zielfunktion definiert für Model {0}. Das Problem könnte erfolgreich gelöst werden, indem man {0} als die aktive Zielfunktion deklariert. - Wenn wahr, werden generische Top Level annotationen wie "Prozess" angewendet. Ist diese Option ausgeschaltet, wird die Ausgabedatei kleiner. + Wenn wahr, werden generische Top Level annotationen wie "Prozess" angewendet. Ist diese Option ausgeschaltet, wird die Ausgabedatei kleiner. Please open an issue to see annotation format {0} implemented. Please open an issue to see parsing for id format {0} implemented. Please open an issue to see notes format {0} implemented. diff --git a/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGCompartmentsAnnotatorTest.java b/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGCompartmentsAnnotatorTest.java index 30e90c46..d7802eb9 100644 --- a/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGCompartmentsAnnotatorTest.java +++ b/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGCompartmentsAnnotatorTest.java @@ -8,7 +8,6 @@ import org.sbml.jsbml.SBO; import java.sql.SQLException; -import java.util.Map; import static edu.ucsd.sbrg.TestUtils.*; import static org.junit.jupiter.api.Assertions.*; diff --git a/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGDBContainerTest.java b/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGDBContainerTest.java index 7433bddc..520856da 100644 --- a/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGDBContainerTest.java +++ b/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGDBContainerTest.java @@ -15,9 +15,10 @@ public abstract class BiGGDBContainerTest { @SuppressWarnings("resource") static final GenericContainer biggContainer = new GenericContainer<>(DockerImageName.parse("schmirgel/bigg_db:1.6")) - .withExposedPorts(5432) - .withEnv("POSTGRES_PASSWORD", "postgres") - .withStartupTimeout(Duration.ofMinutes(5)); + .withExposedPorts(5432) + .withReuse(true) + .withEnv("POSTGRES_PASSWORD", "postgres") + .withStartupTimeout(Duration.ofMinutes(5)); protected static final BiGGDB bigg; diff --git a/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGReactionsAnnotatorTest.java b/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGReactionsAnnotatorTest.java index b6b5c0f4..ab44072d 100644 --- a/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGReactionsAnnotatorTest.java +++ b/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGReactionsAnnotatorTest.java @@ -1,8 +1,6 @@ package edu.ucsd.sbrg.annotation.bigg; -import edu.ucsd.sbrg.ModelPolisherOptions; import edu.ucsd.sbrg.parameters.BiGGAnnotationParameters; -import edu.ucsd.sbrg.parameters.ParametersParser; import edu.ucsd.sbrg.parameters.SBOParameters; import edu.ucsd.sbrg.resolver.identifiersorg.IdentifiersOrg; import org.junit.jupiter.api.Test; @@ -15,7 +13,6 @@ import org.sbml.jsbml.ext.groups.GroupsModelPlugin; import org.sbml.jsbml.ext.groups.Member; -import java.io.ByteArrayInputStream; import java.io.IOException; import java.sql.SQLException; import java.util.Set; @@ -35,7 +32,7 @@ public class BiGGReactionsAnnotatorTest extends BiGGDBContainerTest { private final SBOParameters sboParameters = new SBOParameters(); - public BiGGReactionsAnnotatorTest() throws IOException { + public BiGGReactionsAnnotatorTest() { } @Test diff --git a/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGSBMLAnnotatorTest.java b/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGSBMLAnnotatorTest.java index 399aa03d..9c8ddd07 100644 --- a/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGSBMLAnnotatorTest.java +++ b/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGSBMLAnnotatorTest.java @@ -1,6 +1,6 @@ package edu.ucsd.sbrg.annotation.bigg; -import edu.ucsd.sbrg.ModelPolisherOptions; +import edu.ucsd.sbrg.parameters.ModelPolisherOptions; import edu.ucsd.sbrg.annotation.AnnotationException; import edu.ucsd.sbrg.parameters.BiGGAnnotationParameters; import edu.ucsd.sbrg.parameters.BiGGNotesParameters; diff --git a/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGSpeciesAnnotatorTest.java b/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGSpeciesAnnotatorTest.java index fe5616b8..a2c71b88 100644 --- a/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGSpeciesAnnotatorTest.java +++ b/src/test/java/edu/ucsd/sbrg/annotation/bigg/BiGGSpeciesAnnotatorTest.java @@ -10,7 +10,6 @@ import org.sbml.jsbml.ext.fbc.FBCSpeciesPlugin; import java.sql.SQLException; -import java.util.Map; import java.util.Set; import static edu.ucsd.sbrg.TestUtils.*; diff --git a/src/test/java/edu/ucsd/sbrg/db/bigg/BiGGIdTest.java b/src/test/java/edu/ucsd/sbrg/db/bigg/BiGGIdTest.java index 044fa5b7..057e3fb4 100644 --- a/src/test/java/edu/ucsd/sbrg/db/bigg/BiGGIdTest.java +++ b/src/test/java/edu/ucsd/sbrg/db/bigg/BiGGIdTest.java @@ -8,7 +8,6 @@ import java.util.List; import java.util.Map; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeAll; import org.junit.jupiter.api.Test; @@ -29,14 +28,10 @@ public class BiGGIdTest { */ @BeforeAll @SuppressWarnings("unchecked") - public static void setUp() { + public static void setUp() throws IOException { // load all BiGG SBML IDs ObjectMapper mapper = new ObjectMapper(); - try { - biggIds = mapper.readValue(BiGGId.class.getResourceAsStream("bigg_models_data_ids.json"), Map.class); - } catch (IOException e) { - e.printStackTrace(); - } + biggIds = mapper.readValue(BiGGId.class.getResourceAsStream("bigg_models_data_ids.json"), Map.class); // metabolites - unique cases from old implementation prepareMetaboliteId("h", "c", "h_c"); prepareMetaboliteId("12dgr_HP", "c", "12dgr_HP_c"); @@ -48,16 +43,16 @@ public static void setUp() { prepareMetaboliteId("nadh", "", "nadh"); prepareMetaboliteId("nadh____", "c", "nadh_____c"); // reactions - prepareReactionId("R", "2AGPE181tipp", "", "2AGPE181tipp"); - prepareReactionId("R", "24_25DHVITD2tm", "", "24_25DHVITD2tm"); - prepareReactionId("R", "3DSPHR", "", "3DSPHR"); - prepareReactionId("", "BIOMASS_Ecoli_core_w_GAM", "", "BIOMASS_Ecoli_core_w_GAM"); - prepareReactionId("", "BIOMASS_Ecoli_TM", "", "BIOMASS_Ecoli_TM"); - prepareReactionId("", "BIOMASS_HP_published", "", "BIOMASS_HP_published"); + prepareReactionId("R", "2AGPE181tipp", "2AGPE181tipp"); + prepareReactionId("R", "24_25DHVITD2tm", "24_25DHVITD2tm"); + prepareReactionId("R", "3DSPHR", "3DSPHR"); + prepareReactionId("", "BIOMASS_Ecoli_core_w_GAM", "BIOMASS_Ecoli_core_w_GAM"); + prepareReactionId("", "BIOMASS_Ecoli_TM", "BIOMASS_Ecoli_TM"); + prepareReactionId("", "BIOMASS_HP_published", "BIOMASS_HP_published"); // We don't handle reaction compartment code for now - prepareReactionId("", "EX_h2o_e", "", "EX_h2o_e"); + prepareReactionId("", "EX_h2o_e", "EX_h2o_e"); // r reactions - remaining cases - prepareReactionId("", "EX_h2o_e", "", "R_EX_h2o_e"); + prepareReactionId("", "EX_h2o_e", "R_EX_h2o_e"); // gene products prepareGeneProductId("10090_AT1", "10090_AT1"); prepareGeneProductId("1818", "1818"); @@ -97,21 +92,19 @@ private static void prepareMetaboliteId(String abbreviation, String compartmentC /** * Set up mapping for testIds to their corresponding correct BiGGId, test all four possibilites, i.e. w and w/o * prefix, lowercase prefix and prepended underscore - * - * @param prefix: - * Reaction prefix, if not pseudoreaction - * @param abbreviation: - * Abbreviation part of id with no further semantic meaning - * @param compartmentCode: - * CompartmentCode of id - * @param id: - * Full id to test + * + * @param prefix : + * Reaction prefix, if not pseudoreaction + * @param abbreviation : + * Abbreviation part of id with no further semantic meaning + * @param id : + * Full id to test */ - private static void prepareReactionId(String prefix, String abbreviation, String compartmentCode, String id) { + private static void prepareReactionId(String prefix, String abbreviation, String id) { BiGGId biGGId = new BiGGId(); biGGId.setPrefix(prefix); biGGId.setAbbreviation(abbreviation); - biGGId.setCompartmentCode(compartmentCode); + biGGId.setCompartmentCode(""); correctReactionId.put(id, biGGId); correctReactionId.put("_" + id, biGGId); // skip if pseudoreactions, produces duplicates of "_" + id for those @@ -146,30 +139,28 @@ private static void prepareGeneProductId(String abbreviation, String id) { @Test public final void geneIdsValid() { List ids = biggIds.get("genes"); - ids.forEach(id -> BiGGId.createGeneId(id).ifPresent(biggId -> { - assertTrue(BiGGId.isValid(biggId.toBiGGId())); - })); + ids.forEach(id -> assertTrue(BiGGId.isValid(BiGGId.createGeneId(id).toBiGGId()))); } @Test public final void metaboliteIdsValid() { List ids = biggIds.get("metabolites"); - ids.forEach(id -> BiGGId.createMetaboliteId(id).ifPresent(biggId -> assertTrue(BiGGId.isValid(biggId.toBiGGId())))); + ids.forEach(id -> assertTrue(BiGGId.isValid(BiGGId.createGeneId(id).toBiGGId()))); } @Test public final void reactionIdsValid() { List ids = biggIds.get("reactions"); - ids.forEach(id -> BiGGId.createReactionId(id).ifPresent(biggId -> assertTrue(BiGGId.isValid(biggId.toBiGGId())))); + ids.forEach(id -> assertTrue(BiGGId.isValid(BiGGId.createGeneId(id).toBiGGId()))); } @Test public final void testIsSetMetaboliteCompartment() { String metabolite = "M_5dglcn_c"; - BiGGId biggId = BiGGId.createMetaboliteId(metabolite).get(); + BiGGId biggId = BiGGId.createMetaboliteId(metabolite); assertTrue(biggId.isSetCompartmentCode()); assertEquals("c", biggId.getCompartmentCode()); } @@ -190,8 +181,8 @@ public final void testHashCode() { @Test public final void testToBiGGIdGeneProducts() { for (Map.Entry entry : correctGeneProductId.entrySet()) { - BiGGId.createGeneId(entry.getKey()) - .ifPresentOrElse(id -> assertEquals(id.toBiGGId(), entry.getValue().toBiGGId()), Assertions::fail); + var id = BiGGId.createGeneId(entry.getKey()); + assertEquals(id.toBiGGId(), entry.getValue().toBiGGId()); } } @@ -202,8 +193,8 @@ public final void testToBiGGIdGeneProducts() { @Test public final void testToBiGGIdMetabolites() { for (Map.Entry entry : correctMetaboliteId.entrySet()) { - BiGGId.createMetaboliteId(entry.getKey()) - .ifPresentOrElse(id -> assertEquals(id.toBiGGId(), entry.getValue().toBiGGId()), Assertions::fail); + var id = BiGGId.createMetaboliteId(entry.getKey()); + assertEquals(id.toBiGGId(), entry.getValue().toBiGGId()); } } @@ -214,8 +205,8 @@ public final void testToBiGGIdMetabolites() { @Test public final void testToBiGGIdReactions() { for (Map.Entry entry : correctReactionId.entrySet()) { - BiGGId.createReactionId(entry.getKey()) - .ifPresentOrElse(id -> assertEquals(id.toBiGGId(), entry.getValue().toBiGGId()), Assertions::fail); + var id = BiGGId.createReactionId(entry.getKey()); + assertEquals(id.toBiGGId(), entry.getValue().toBiGGId()); } } diff --git a/src/test/java/edu/ucsd/sbrg/polishing/fbc/FluxObjectivesPolisherTest.java b/src/test/java/edu/ucsd/sbrg/fixing/fbc/ListOfObjectivesFixerTest.java similarity index 69% rename from src/test/java/edu/ucsd/sbrg/polishing/fbc/FluxObjectivesPolisherTest.java rename to src/test/java/edu/ucsd/sbrg/fixing/fbc/ListOfObjectivesFixerTest.java index f995ceb4..0ed01384 100644 --- a/src/test/java/edu/ucsd/sbrg/polishing/fbc/FluxObjectivesPolisherTest.java +++ b/src/test/java/edu/ucsd/sbrg/fixing/fbc/ListOfObjectivesFixerTest.java @@ -1,8 +1,8 @@ -package edu.ucsd.sbrg.polishing.fbc; +package edu.ucsd.sbrg.fixing.fbc; +import edu.ucsd.sbrg.fixing.ext.fbc.ListOfObjectivesFixer; import edu.ucsd.sbrg.parameters.FluxObjectivesPolishingParameters; import edu.ucsd.sbrg.parameters.PolishingParameters; -import edu.ucsd.sbrg.resolver.identifiersorg.IdentifiersOrg; import org.junit.jupiter.api.Test; import org.sbml.jsbml.Model; import org.sbml.jsbml.ext.fbc.FBCConstants; @@ -10,43 +10,13 @@ import org.sbml.jsbml.ext.fbc.FluxObjective; import java.util.List; -import java.util.Map; import java.util.Set; import java.util.stream.Collectors; -import static org.junit.jupiter.api.Assertions.*; +import static org.junit.jupiter.api.Assertions.assertEquals; +public class ListOfObjectivesFixerTest { -public class FluxObjectivesPolisherTest { - - /** - * Test that if an objective is set, and it has flux objectives too, it won't be overwritten. - */ - @Test - public void activeObjectiveRemainsUnchangedIfItHasFluxObjective() { - var m = new Model(3,2); - var fbcPlugin = (FBCModelPlugin) m.getPlugin(FBCConstants.shortLabel); - - fbcPlugin.createObjective("obj1"); - var o2 = fbcPlugin.createObjective("obj2"); - o2.createFluxObjective(); - fbcPlugin.setActiveObjective(o2); - fbcPlugin.createObjective("obj3"); - - var parameters = new PolishingParameters( - null, - new FluxObjectivesPolishingParameters( - null, - List.of(" objective_reaction1 "))); - - m.createReaction("objective_reaction1"); - m.createReaction("yadda_Biomass_yadda"); - - var mPlug = (FBCModelPlugin) m.getPlugin(FBCConstants.shortLabel); - new FluxObjectivesPolisher(mPlug, parameters, new IdentifiersOrg()).polish(mPlug.getListOfObjectives()); - - assertEquals("obj2", fbcPlugin.getActiveObjective()); - } /** * Test that if objectives don't have flux objectives set and viable arguments are supplied, @@ -64,7 +34,6 @@ public void argumentsAreUsedToInferFluxObjectives() { fbcPlugin.createObjective("obj2"); var o3 = fbcPlugin.createObjective("obj3"); fbcPlugin.setActiveObjective(o3); - assertNotNull(fbcPlugin.getActiveObjectiveInstance()); m.createReaction("objective_reaction1"); m.createReaction("objective_reaction2"); @@ -76,7 +45,7 @@ public void argumentsAreUsedToInferFluxObjectives() { null, List.of("objective_reaction1", "objective_reaction2"))); - new FluxObjectivesPolisher(fbcPlugin, parameters, new IdentifiersOrg()).polish(fbcPlugin.getListOfObjectives()); + new ListOfObjectivesFixer(parameters, fbcPlugin).fix(fbcPlugin.getListOfObjectives(), 0); assertEquals("obj3", fbcPlugin.getActiveObjective()); assertEquals(2, fbcPlugin.getListOfObjectives() @@ -91,6 +60,7 @@ public void argumentsAreUsedToInferFluxObjectives() { assertEquals(List.of("objective_reaction1", "objective_reaction2"), fos); } + /** * Test that if objectives don't have flux objectives set and no (viable) arguments are supplied, * the biomass function is used to add flux objectives to the active objective. @@ -113,7 +83,7 @@ public void biomassIsUsedToInferFluxObjectives() { m.createReaction("yadda_Biomass_yadda"); var mPlug = (FBCModelPlugin) m.getPlugin(FBCConstants.shortLabel); - new FluxObjectivesPolisher(mPlug, new PolishingParameters(), new IdentifiersOrg()).polish(mPlug.getListOfObjectives()); + new ListOfObjectivesFixer(new PolishingParameters(), fbcPlugin).fix(mPlug.getListOfObjectives(), 0); assertEquals("obj2", fbcPlugin.getActiveObjective()); assertEquals(Set.of("yadda_Biomass_yadda"), @@ -140,8 +110,8 @@ public void emptyObjectivesAreRemoved() { // o1.setListOfFluxObjectives(new ListOf<>()); var mPlug = (FBCModelPlugin) m.getPlugin(FBCConstants.shortLabel); - new FluxObjectivesPolisher(mPlug, new PolishingParameters(), new IdentifiersOrg()).polish(mPlug.getListOfObjectives()); + new ListOfObjectivesFixer(new PolishingParameters(), fbcPlugin).fix(mPlug.getListOfObjectives(), 0); assertEquals(0, fbcPlugin.getObjectiveCount()); } -} \ No newline at end of file +} diff --git a/src/test/java/edu/ucsd/sbrg/io/parsers/cobra/MatlabParserTest.java b/src/test/java/edu/ucsd/sbrg/io/parsers/cobra/MatlabParserTest.java index 0bc164bd..c5e752db 100644 --- a/src/test/java/edu/ucsd/sbrg/io/parsers/cobra/MatlabParserTest.java +++ b/src/test/java/edu/ucsd/sbrg/io/parsers/cobra/MatlabParserTest.java @@ -7,7 +7,6 @@ import java.io.File; import java.io.IOException; -import java.util.Map; import static org.junit.jupiter.api.Assertions.assertTrue; import static org.junit.jupiter.api.Assertions.fail; @@ -32,8 +31,7 @@ public void parsingDoesNotThrowErrors() { new MatlabParser(parameters, new IdentifiersOrg()).parse(recon); assertTrue(true); } catch (IOException e) { - e.printStackTrace(); - fail("Parsing Recon3D.mat threw an exception."); + fail("Parsing Recon3D.mat threw an exception.", e); } } diff --git a/src/test/java/edu/ucsd/sbrg/io/parsers/json/JSONParserTest.java b/src/test/java/edu/ucsd/sbrg/io/parsers/json/JSONParserTest.java index 2477fc8f..dc375f1c 100644 --- a/src/test/java/edu/ucsd/sbrg/io/parsers/json/JSONParserTest.java +++ b/src/test/java/edu/ucsd/sbrg/io/parsers/json/JSONParserTest.java @@ -7,7 +7,6 @@ import edu.ucsd.sbrg.io.parsers.json.mapping.Metabolite; import edu.ucsd.sbrg.io.parsers.json.mapping.Reaction; import edu.ucsd.sbrg.resolver.identifiersorg.IdentifiersOrg; -import org.junit.jupiter.api.Assertions; import org.junit.jupiter.api.BeforeEach; import org.junit.jupiter.api.Test; import org.sbml.jsbml.*; @@ -40,7 +39,7 @@ public void setUp() { @Test - public void parseCompartmentsTest() { + public void parseCompartmentsTest() throws JsonProcessingException { String compartmentsJSON = """ { "":"", @@ -52,11 +51,7 @@ public void parseCompartmentsTest() { """; ObjectMapper mapper = new ObjectMapper(); Compartments compartments = null; - try { - compartments = mapper.readValue(compartmentsJSON, Compartments.class); - } catch (JsonProcessingException e) { - e.printStackTrace(); - } + compartments = mapper.readValue(compartmentsJSON, Compartments.class); assertNotNull(compartments); JSONParser parser = new JSONParser(new IdentifiersOrg()); parser.parseCompartments(builder, compartments.get()); @@ -74,7 +69,7 @@ public void parseCompartmentsTest() { } @Test - public void parseReactionTest() { + public void parseReactionTest() throws JsonProcessingException { String reactionJSON = """ { "id":"FAH1", @@ -95,15 +90,10 @@ public void parseReactionTest() { }"""; ObjectMapper mapper = new ObjectMapper(); Reaction reaction = null; - try { - reaction = mapper.readValue(reactionJSON, Reaction.class); - } catch (JsonProcessingException e) { - e.printStackTrace(); - } + reaction = mapper.readValue(reactionJSON, Reaction.class); assertNotNull(reaction); JSONParser parser = new JSONParser(new IdentifiersOrg()); - BiGGId.createReactionId(reaction.getId()).ifPresentOrElse(id -> assertEquals("R_FAH1", id.toBiGGId()), - Assertions::fail); + assertEquals("R_FAH1", BiGGId.createReactionId(reaction.getId()).toBiGGId()); parser.parseReaction(builder, reaction, "R_FAH1"); // Needs to be fetched no matter what, checking for id equality is thus already done here indirectly org.sbml.jsbml.Reaction r = builder.getModel().getReaction("R_FAH1"); @@ -169,7 +159,7 @@ public void parseReactionTest() { @Test - public void parseSpeciesTest() { + public void parseSpeciesTest() throws JsonProcessingException { String speciesJSON = """ { "id" : "amp_e", @@ -181,16 +171,11 @@ public void parseSpeciesTest() { """; ObjectMapper mapper = new ObjectMapper(); Metabolite metabolite = null; - try { - metabolite = mapper.readValue(speciesJSON, Metabolite.class); - } catch (JsonProcessingException e) { - e.printStackTrace(); - } + metabolite = mapper.readValue(speciesJSON, Metabolite.class); assertNotNull(metabolite); - BiGGId.createMetaboliteId(metabolite.getId()).ifPresentOrElse(id -> assertEquals("M_amp_e", id.toBiGGId()), - Assertions::fail); + assertEquals("M_amp_e", BiGGId.createMetaboliteId(metabolite.getId()).toBiGGId()); JSONParser parser = new JSONParser(new IdentifiersOrg()); - parser.parseMetabolite(builder.getModel(), metabolite, BiGGId.createMetaboliteId(metabolite.getId()).get()); + parser.parseMetabolite(builder.getModel(), metabolite, BiGGId.createMetaboliteId(metabolite.getId())); Species species = builder.getModel().getSpecies("M_amp_e"); assertNotNull(species); assertEquals("AMP", metabolite.getName()); @@ -217,8 +202,7 @@ public void iJB785isParsedWithoutError() throws XMLStreamException { assertTrue(s.get().getNotesString().contains("H70.5616C44.9625O13.1713S0.2669N12.1054R-1.0"), "Formula from the model not retained in notes!"); } catch (IOException e) { - e.printStackTrace(); - fail("Parsing iJB785.json threw an exception."); + fail("Parsing iJB785.json threw an exception.", e); } } } diff --git a/src/test/java/edu/ucsd/sbrg/parameters/ParametersParserTest.java b/src/test/java/edu/ucsd/sbrg/parameters/ParametersParserTest.java index ce4bffa0..648784a1 100644 --- a/src/test/java/edu/ucsd/sbrg/parameters/ParametersParserTest.java +++ b/src/test/java/edu/ucsd/sbrg/parameters/ParametersParserTest.java @@ -1,6 +1,5 @@ package edu.ucsd.sbrg.parameters; -import edu.ucsd.sbrg.ModelPolisherOptions; import edu.ucsd.sbrg.db.adb.AnnotateDBOptions; import edu.ucsd.sbrg.db.bigg.BiGGDBOptions; import org.junit.jupiter.api.Test; @@ -20,7 +19,7 @@ void defaults() throws IOException { assertEquals(ModelPolisherOptions.SBML_VALIDATION.getDefaultValue(), parameters.sbmlValidation()); - assertEquals(ModelPolisherOptions.OMIT_GENERIC_TERMS.getDefaultValue(), parameters.sboTerms().omitGenericTerms()); + assertEquals(ModelPolisherOptions.ADD_GENERIC_TERMS.getDefaultValue(), parameters.sboTerms().addGenericTerms()); assertEquals(ModelPolisherOptions.CHECK_MASS_BALANCE.getDefaultValue(), parameters.polishing().reactionPolishingParameters().checkMassBalance()); diff --git a/src/test/java/edu/ucsd/sbrg/polishing/ReactionsPolisherTest.java b/src/test/java/edu/ucsd/sbrg/polishing/ReactionsPolisherTest.java index f2d0dd01..b122b791 100644 --- a/src/test/java/edu/ucsd/sbrg/polishing/ReactionsPolisherTest.java +++ b/src/test/java/edu/ucsd/sbrg/polishing/ReactionsPolisherTest.java @@ -8,11 +8,7 @@ import org.sbml.jsbml.Model; import org.sbml.jsbml.Species; import org.sbml.jsbml.SpeciesReference; -import org.sbml.jsbml.ext.fbc.*; -import org.sbml.jsbml.xml.XMLNode; -import org.sbml.jsbml.xml.XMLTriple; -import java.util.Map; import java.util.Set; import java.util.stream.Collectors; @@ -23,24 +19,6 @@ public class ReactionsPolisherTest { public final SBOParameters sboParameters = new SBOParameters(); private final PolishingParameters polishingParameters = new PolishingParameters(); - @Test - public void noIdReactionIsDeletedFromModel() { - var model = new Model(3, 2); - var r = model.createReaction(); - - assertFalse(r.isSetId()); - assertFalse(r.isSetName()); - assertEquals(1, model.getReactionCount()); - - new ModelPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(model); - - boolean strict = new StrictnessPredicate().test(model); - - assertTrue(strict); - assertFalse(r.isSetId()); - assertFalse(r.isSetName()); - assertEquals(0, model.getReactionCount()); - } /** * Relevant defaults are set. @@ -53,8 +31,6 @@ public void defaultsAreSet() { var r = model.createReaction("some_reaction"); assertFalse(r.isSetName()); - assertFalse(r.isSetFast()); - assertFalse(r.isSetReversible()); assertEquals(1, model.getReactionCount()); new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); @@ -62,8 +38,6 @@ public void defaultsAreSet() { assertFalse(strict); assertFalse(r.isSetName()); - assertTrue(r.isSetFast()); - assertTrue(r.isSetReversible()); assertEquals(1, model.getReactionCount()); } @@ -98,29 +72,29 @@ public void reactionCompartmentIsSetFromParticipants() { assertEquals(cytosol, r.getCompartmentInstance()); } - @Test - public void compartmentIsSetFromPreferentiallyFromProducts() { - var model = new Model(3, 2); - var r = model.createReaction("some_reaction"); - var cytosol = model.createCompartment("c"); - var extracellular = model.createCompartment("e"); - - var s1 = model.createSpecies("s1", cytosol); - r.createReactant(s1); - - var s2 = model.createSpecies("s2", extracellular); - r.createProduct(s2); - - assertEquals("", r.getCompartment()); - - new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); - - assertEquals(1, r.getReactantCount()); - assertEquals(1, r.getProductCount()); - assertEquals(cytosol, r.getReactant(0).getSpeciesInstance().getCompartmentInstance()); - assertEquals(extracellular, r.getProduct(0).getSpeciesInstance().getCompartmentInstance()); - assertEquals(extracellular, r.getCompartmentInstance()); - } +// @Test +// public void compartmentIsSetFromPreferentiallyFromProducts() { +// var model = new Model(3, 2); +// var r = model.createReaction("some_reaction"); +// var cytosol = model.createCompartment("c"); +// var extracellular = model.createCompartment("e"); +// +// var s1 = model.createSpecies("s1", cytosol); +// r.createReactant(s1); +// +// var s2 = model.createSpecies("s2", extracellular); +// r.createProduct(s2); +// +// assertEquals("", r.getCompartment()); +// +// new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); +// +// assertEquals(1, r.getReactantCount()); +// assertEquals(1, r.getProductCount()); +// assertEquals(cytosol, r.getReactant(0).getSpeciesInstance().getCompartmentInstance()); +// assertEquals(extracellular, r.getProduct(0).getSpeciesInstance().getCompartmentInstance()); +// assertEquals(extracellular, r.getCompartmentInstance()); +// } @Test public void reactionCompartmentIsNotOverridden() { @@ -140,50 +114,48 @@ public void reactionCompartmentIsNotOverridden() { assertEquals(extracellular, r.getCompartmentInstance()); } - @Test - public void conflictingProductsLeadToUnset() { - var model = new Model(3, 2); - var r = model.createReaction("some_reaction"); - var cytosol = model.createCompartment("c"); - var extracellular = model.createCompartment("e"); - - var s1 = model.createSpecies("s1", cytosol); - r.createProduct(s1); - - r.setCompartment(extracellular); - - new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); - - assertEquals(1, r.getProductCount()); - assertNull(r.getCompartmentInstance()); - } - - @Test - public void inconsistentProductCompartmentsLeadToUnset() { - var model = new Model(3, 2); - var r = model.createReaction("some_reaction"); - var cytosol = model.createCompartment("c"); - var extracellular = model.createCompartment("e"); - - r.setCompartment(cytosol); - - var s2 = model.createSpecies("s2", extracellular); - r.createProduct(s2); - - var s1 = model.createSpecies("s1", cytosol); - r.createProduct(s1); - - assertEquals(cytosol, r.getCompartmentInstance()); - - new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); - - assertEquals(2, r.getListOfProducts().size()); - assertEquals(Set.of(cytosol, extracellular), r.getListOfProducts().stream() - .map(SpeciesReference::getSpeciesInstance) - .map(Species::getCompartmentInstance) - .collect(Collectors.toSet())); - assertNull(r.getCompartmentInstance()); - } +// @Test +// public void conflictingProductsLeadToUnset() { +// var model = new Model(3, 2); +// var r = model.createReaction("some_reaction"); +// var cytosol = model.createCompartment("c"); +// var extracellular = model.createCompartment("e"); +// +// var s1 = model.createSpecies("s1", cytosol); +// r.createProduct(s1); +// +// r.setCompartment(extracellular); +// +// new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); +// +// assertEquals(1, r.getProductCount()); +// assertNull(r.getCompartmentInstance()); +// } + +// @Test +// public void inconsistentProductCompartmentsLeadToUnset() { +// var model = new Model(3, 2); +// var r = model.createReaction("some_reaction"); +// var cytosol = model.createCompartment("c"); +// var extracellular = model.createCompartment("e"); +// +// r.setCompartment(cytosol); +// +// var s2 = model.createSpecies("s2", extracellular); +// r.createProduct(s2); +// +// var s1 = model.createSpecies("s1", cytosol); +// r.createProduct(s1); +// +// assertEquals(cytosol, r.getCompartmentInstance()); +// +// new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); +// +// assertEquals(2, r.getListOfProducts().size()); +// assertEquals(cytosol, r.getProduct("s1").getSpeciesInstance().getCompartmentInstance()); +// assertEquals(extracellular, r.getProduct("s2").getSpeciesInstance().getCompartmentInstance()); +// assertEquals(cytosol, r.getCompartmentInstance()); +// } @Test public void speciesReferencesWithoutSpeciesAreRetained() { @@ -202,301 +174,4 @@ public void speciesReferencesWithoutSpeciesAreRetained() { assertEquals(cytosol, r.getCompartmentInstance()); } - /** - * note this documents a bug - */ - @Test - public void missingProductSpeciesAreConflictAndLeadToUnset() { - var model = new Model(3, 2); - var r = model.createReaction("some_reaction"); - var cytosol = model.createCompartment("c"); - - r.setCompartment(cytosol); - - r.createProduct(); - r.createProduct(); - - new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); - - assertEquals(2, r.getListOfProducts().size()); - assertNull(r.getCompartmentInstance()); - } - - @Test - public void defaultsAreSetOnSpeciesReferences() { - var model = new Model(3, 2); - var r = model.createReaction("some_reaction"); - - var s1 = model.createSpecies("s1"); - var react1 = r.createReactant(s1); - - var s2 = model.createSpecies("s2"); - var product1 = r.createProduct(s2); - - assertEquals("", react1.getSBOTermID()); - assertEquals("", product1.getSBOTermID()); - assertFalse(react1.isSetConstant()); - assertFalse(product1.isSetConstant()); - - new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); - - assertEquals(1, r.getListOfReactants().size()); - assertEquals(1, r.getListOfProducts().size()); - - assertEquals("SBO:0000010", react1.getSBOTermID()); - assertEquals("SBO:0000011", product1.getSBOTermID()); - assertTrue(react1.isSetConstant()); - assertTrue(product1.isSetConstant()); - } - - /** - * Note: this test documents - * ... - */ - @Test - public void defaultsAreSetEvenIfCompartmentsAreInconsistent() { - var model = new Model(3, 2); - var r = model.createReaction("some_reaction"); - var cytosol = model.createCompartment("c"); - var extracellular = model.createCompartment("e"); - - var s1 = model.createSpecies("s1", cytosol); - var product1 = r.createProduct(s1); - - var s2 = model.createSpecies("s2", extracellular); - var product2 = r.createProduct(s2); - - var s3 = model.createSpecies("s3", cytosol); - var product3 = r.createProduct(s3); - - assertEquals("", product1.getSBOTermID()); - assertEquals("", product2.getSBOTermID()); - assertEquals("", product3.getSBOTermID()); - assertFalse(product1.isSetConstant()); - assertFalse(product2.isSetConstant()); - assertFalse(product3.isSetConstant()); - - new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); - - assertEquals(3, r.getListOfProducts().size()); - assertEquals("SBO:0000011", product1.getSBOTermID()); - assertEquals("SBO:0000011", product2.getSBOTermID()); - assertEquals("SBO:0000011", product3.getSBOTermID()); - assertTrue(product1.isSetConstant()); - assertTrue(product2.isSetConstant()); - assertTrue(product3.isSetConstant()); - } - - /** - * Note: I consider this behaviour to be a bug basically. - *

- * I am still testing the behaviour though for validation purposes should - * this get fixed. - */ - @Test - public void objectiveIsCreatedIfNoneIsPresent() { - var model = new Model(3, 2); - var fbcPlugin = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); - - var r = model.createReaction("some_reaction"); - var kl = r.createKineticLaw(); - var l1 = kl.createLocalParameter("OBJECTIVE_COEFFICIENT"); - l1.setValue(23); - - assertEquals(1, model.getReactionCount()); - assertEquals(0, fbcPlugin.getObjectiveCount()); - - new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); - - assertEquals(1, model.getReactionCount()); - assertEquals(1, fbcPlugin.getObjectiveCount()); - assertNotNull(fbcPlugin.getActiveObjectiveInstance()); - var fo = fbcPlugin.getObjective(0) - .getListOfFluxObjectives() - .get(0); - assertEquals("fo_some_reaction", fo.getId()); - assertEquals(r, fo.getReactionInstance()); - } - - @Test - public void fluxObjectivesAreSetFromKinematicLaws() { - var model = new Model(3, 2); - var fbcPlugin = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); - - var r = model.createReaction("some_reaction"); - var kl = r.createKineticLaw(); - var l1 = kl.createLocalParameter("OBJECTIVE_COEFFICIENT"); - l1.setValue(23); - - var obj1 = fbcPlugin.createObjective("obj1", Objective.Type.MINIMIZE); - var obj2 = fbcPlugin.createObjective("obj2", Objective.Type.MAXIMIZE); - - assertEquals(1, model.getReactionCount()); - assertEquals(2, fbcPlugin.getObjectiveCount()); - assertEquals(0, obj1.getFluxObjectiveCount()); - assertEquals(0, obj2.getFluxObjectiveCount()); - - new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); - - assertEquals(1, model.getReactionCount()); - assertEquals(2, fbcPlugin.getObjectiveCount()); - assertEquals(1, obj1.getFluxObjectiveCount()); - assertEquals(0, obj2.getFluxObjectiveCount()); - assertNull(fbcPlugin.getActiveObjectiveInstance()); - var fo = obj1 - .getListOfFluxObjectives() - .get(0); - assertEquals("fo_some_reaction", fo.getId()); - assertEquals(r, fo.getReactionInstance()); - assertEquals(23, fo.getCoefficient()); - } - - @Test - public void existingObjectivesAreRespected() { - var model = new Model(3, 2); - var fbcPlugin = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); - - var r = model.createReaction("some_reaction"); - var kl = r.createKineticLaw(); - var l1 = kl.createLocalParameter("OBJECTIVE_COEFFICIENT"); - l1.setValue(23); - - var obj1 = fbcPlugin.createObjective("obj1", Objective.Type.MINIMIZE); - var existing_fo = obj1.createFluxObjective("existing_fo"); - existing_fo.setReaction(r); - var obj2 = fbcPlugin.createObjective("obj2", Objective.Type.MAXIMIZE); - - assertEquals(1, model.getReactionCount()); - assertEquals(2, fbcPlugin.getObjectiveCount()); - assertEquals(1, obj1.getFluxObjectiveCount()); - assertEquals(0, obj2.getFluxObjectiveCount()); - - new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); - - assertEquals(1, model.getReactionCount()); - assertEquals(2, fbcPlugin.getObjectiveCount()); - assertEquals(1, obj1.getFluxObjectiveCount()); - assertEquals(0, obj2.getFluxObjectiveCount()); - assertNull(fbcPlugin.getActiveObjectiveInstance()); - var fo = obj1 - .getListOfFluxObjectives() - .get(0); - assertEquals("existing_fo", fo.getId()); - assertEquals(r, fo.getReactionInstance()); - assertFalse(fo.isSetCoefficient()); - } - - @Test - public void boundsAreCreatedFromLocalParameters() { - var model = new Model(3, 2); - - var r = model.createReaction("some_reaction"); - var rFbcPlugin = (FBCReactionPlugin) r.getPlugin(FBCConstants.shortLabel); - - var kl = r.createKineticLaw(); - kl.createLocalParameter("LOWER_BOUND"); - kl.createLocalParameter("UPPER_BOUND"); - - assertNull(rFbcPlugin.getLowerFluxBoundInstance()); - assertNull(rFbcPlugin.getUpperFluxBoundInstance()); - - new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); - - var lb = rFbcPlugin.getLowerFluxBoundInstance(); - assertEquals("some_reaction_LOWER_BOUND", lb.getId()); - assertTrue(lb.isSetConstant()); - assertTrue(lb.isConstant()); - assertEquals("SBO:0000625", lb.getSBOTermID()); - var ub = rFbcPlugin.getUpperFluxBoundInstance(); - assertEquals("some_reaction_UPPER_BOUND", ub.getId()); - assertTrue(ub.isSetConstant()); - assertTrue(ub.isConstant()); - assertEquals("SBO:0000625", lb.getSBOTermID()); - } - - @Test - public void existingBoundsGetDefaults() { - var model = new Model(3, 2); - - var r = model.createReaction("some_reaction"); - var rFbcPlugin = (FBCReactionPlugin) r.getPlugin(FBCConstants.shortLabel); - - var kl = r.createKineticLaw(); - kl.createLocalParameter("LOWER_BOUND"); - kl.createLocalParameter("UPPER_BOUND"); - - var p1 = model.createParameter("default_blubb"); - rFbcPlugin.setLowerFluxBound(p1); - var p2 = model.createParameter("other_blubb"); - rFbcPlugin.setUpperFluxBound(p2); - - new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); - - var lb = rFbcPlugin.getLowerFluxBoundInstance(); - assertEquals("default_blubb", lb.getId()); - assertFalse(lb.isSetConstant()); - assertEquals("SBO:0000626", lb.getSBOTermID()); - var ub = rFbcPlugin.getUpperFluxBoundInstance(); - assertEquals("other_blubb", ub.getId()); - assertFalse(ub.isSetConstant()); - assertEquals("SBO:0000625", ub.getSBOTermID()); - } - - @Test - public void newBoundsSettingsByValueAndExistingParameters() { - var model = new Model(3, 2); - - var r = model.createReaction("some_reaction"); - var rFbcPlugin = (FBCReactionPlugin) r.getPlugin(FBCConstants.shortLabel); - - var kl = r.createKineticLaw(); - var p1 = kl.createLocalParameter("LOWER_BOUND"); - p1.setValue(1000); - kl.createLocalParameter("UPPER_BOUND"); - - var pModel = model.createParameter("some_reaction_UPPER_BOUND"); - - assertNull(rFbcPlugin.getLowerFluxBoundInstance()); - assertNull(rFbcPlugin.getUpperFluxBoundInstance()); - - new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); - - var lb = rFbcPlugin.getLowerFluxBoundInstance(); - assertEquals("DEFAULT_UPPER_BOUND", lb.getId()); - var ub = rFbcPlugin.getUpperFluxBoundInstance(); - assertEquals("some_reaction_UPPER_BOUND", ub.getId()); - assertEquals(pModel, ub); - } - - /** - * Note: this apparently shows a bug in the GPRParser::areEqual method. - * That is, hopefully, once that bug is fixed, this should fail. - * - */ - @Test - public void notesToGPRs() { - var model = new Model(3, 2); - - var r = model.createReaction("some_reaction"); - var rFbcPlugin = (FBCReactionPlugin) r.getPlugin(FBCConstants.shortLabel); - var body = new XMLNode(new XMLTriple("body", "", "")); - var p1 = new XMLNode(new XMLTriple("p", "", "")); - p1.addChild(new XMLNode("GENE_ASSOCIATION: some_assoc")); - body.addChild(p1); - var p2 = new XMLNode(new XMLTriple("p", "", "")); - p2.addChild(new XMLNode("GENE_ASSOCIATION: some_other_assoc")); - body.addChild(p2); - r.setNotes(body); - - new ReactionsPolisher(polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); - - assertInstanceOf(GeneProductRef.class, rFbcPlugin.getGeneProductAssociation() - .getAssociation(), "The result is expected to be " + - "(wrongly, happy fixing should this fail for you!) " + - "a single gene association, not an AND or OR."); - assertEquals("G_some_assoc", - ((GeneProductRef) rFbcPlugin.getGeneProductAssociation() - .getAssociation()).getGeneProduct()); - } - } diff --git a/src/test/java/edu/ucsd/sbrg/polishing/SpeciesPolisherTest.java b/src/test/java/edu/ucsd/sbrg/polishing/SpeciesPolisherTest.java index b0c34ab2..3a5df200 100644 --- a/src/test/java/edu/ucsd/sbrg/polishing/SpeciesPolisherTest.java +++ b/src/test/java/edu/ucsd/sbrg/polishing/SpeciesPolisherTest.java @@ -5,36 +5,12 @@ import org.junit.jupiter.api.Test; import org.sbml.jsbml.Model; -import java.util.Map; - import static org.junit.jupiter.api.Assertions.*; public class SpeciesPolisherTest { private final PolishingParameters parameters = new PolishingParameters(); - @Test - public void speciesWithoutIdIsDeleted() { - var m = new Model(3, 2); - var s = m.createSpecies(); - - assertEquals(0, m.getCompartmentCount()); - assertFalse(s.isSetConstant()); - assertFalse(s.isSetBoundaryCondition()); - assertFalse(s.isSetHasOnlySubstanceUnits()); - assertEquals(1, m.getSpeciesCount()); - - new SpeciesPolisher(parameters, new IdentifiersOrg()).polish(m.getListOfSpecies()); - - assertEquals(0, m.getCompartmentCount()); - assertFalse(s.isSetMetaId()); - assertFalse(s.isSetId()); - assertFalse(s.isSetConstant()); - assertFalse(s.isSetBoundaryCondition()); - assertFalse(s.isSetHasOnlySubstanceUnits()); - assertEquals(0, m.getSpeciesCount()); - } - /** * Default values according to the SBML spec are set and the model is aware of it. */ @@ -44,23 +20,14 @@ public void defaultsAreSet() { var s = m.createSpecies("stuff_c"); assertEquals(0, m.getCompartmentCount()); - assertFalse(s.isSetConstant()); - assertFalse(s.isSetBoundaryCondition()); - assertFalse(s.isSetHasOnlySubstanceUnits()); assertEquals(1, m.getSpeciesCount()); new SpeciesPolisher(parameters, new IdentifiersOrg()).polish(s); assertEquals("c", s.getCompartment()); assertEquals("stuff_c", s.getId()); - assertEquals("default", m.getListOfCompartments().get(0).getName()); + assertEquals("", m.getListOfCompartments().get(0).getName()); assertEquals("c", m.getListOfCompartments().get(0).getId()); - assertTrue(s.isSetConstant()); - assertFalse(s.getConstant()); - assertTrue(s.isSetBoundaryCondition()); - assertFalse(s.isBoundaryCondition()); - assertTrue(s.isSetHasOnlySubstanceUnits()); - assertTrue(s.hasOnlySubstanceUnits()); assertEquals(1, m.getSpeciesCount()); } @@ -82,30 +49,8 @@ public void compartmentIsSetFromId() { assertEquals("c", s.getCompartment()); assertEquals("stuff_c", s.getId()); - assertEquals("default", m.getListOfCompartments().get(0).getName()); + assertEquals("", m.getListOfCompartments().get(0).getName()); assertEquals("c", m.getListOfCompartments().get(0).getId()); assertEquals(1, m.getSpeciesCount()); } - - /** - * If a species has its compartment attribute set, but no compartment postfix on the ID, - * the compartment is created in the model if it does not exist, but the - * species ID is not changed, - */ - @Test - public void nonCompartmentIdIsNotSetToCompartmentAttribute() { - var m = new Model(3, 2); - var s = m.createSpecies("stuff"); - s.setCompartment("e"); - - assertEquals(0, m.getCompartmentCount()); - - new SpeciesPolisher(parameters, new IdentifiersOrg()).polish(s); - - assertEquals("e", s.getCompartment()); - assertEquals("stuff", s.getId()); - assertEquals("default", m.getListOfCompartments().get(0).getName()); - assertEquals("e", m.getListOfCompartments().get(0).getId()); - } - } diff --git a/src/test/java/edu/ucsd/sbrg/polishing/UnitPolisherTest.java b/src/test/java/edu/ucsd/sbrg/polishing/UnitPolisherTest.java index c831dbfc..f4de3b45 100644 --- a/src/test/java/edu/ucsd/sbrg/polishing/UnitPolisherTest.java +++ b/src/test/java/edu/ucsd/sbrg/polishing/UnitPolisherTest.java @@ -9,7 +9,6 @@ import org.sbml.jsbml.UnitDefinition; import java.util.HashSet; -import java.util.Map; import java.util.Set; import java.util.stream.Collectors; diff --git a/src/test/java/edu/ucsd/sbrg/polishing/fbc/FBCReactionPolisherTest.java b/src/test/java/edu/ucsd/sbrg/polishing/fbc/FBCReactionPolisherTest.java new file mode 100644 index 00000000..301c73ed --- /dev/null +++ b/src/test/java/edu/ucsd/sbrg/polishing/fbc/FBCReactionPolisherTest.java @@ -0,0 +1,238 @@ +package edu.ucsd.sbrg.polishing.fbc; + +import edu.ucsd.sbrg.parameters.PolishingParameters; +import edu.ucsd.sbrg.parameters.SBOParameters; +import edu.ucsd.sbrg.resolver.identifiersorg.IdentifiersOrg; +import org.junit.jupiter.api.Test; +import org.sbml.jsbml.Model; +import org.sbml.jsbml.ext.fbc.*; +import org.sbml.jsbml.xml.XMLNode; +import org.sbml.jsbml.xml.XMLTriple; + +import static org.junit.jupiter.api.Assertions.*; + +class FBCReactionPolisherTest { + + public final SBOParameters sboParameters = new SBOParameters(); + private final PolishingParameters polishingParameters = new PolishingParameters(); + + @Test + public void existingBoundsGetDefaults() { + var model = new Model(3, 2); + var modelFbcPlugin = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); + var r = model.createReaction("some_reaction"); + var rFbcPlugin = (FBCReactionPlugin) r.getPlugin(FBCConstants.shortLabel); + + var kl = r.createKineticLaw(); + kl.createLocalParameter("LOWER_BOUND"); + kl.createLocalParameter("UPPER_BOUND"); + + var p1 = model.createParameter("default_blubb"); + rFbcPlugin.setLowerFluxBound(p1); + var p2 = model.createParameter("other_blubb"); + rFbcPlugin.setUpperFluxBound(p2); + + new FBCReactionPolisher(modelFbcPlugin, polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); + + var lb = rFbcPlugin.getLowerFluxBoundInstance(); + assertEquals("default_blubb", lb.getId()); + assertFalse(lb.isSetConstant()); + assertEquals("SBO:0000626", lb.getSBOTermID()); + var ub = rFbcPlugin.getUpperFluxBoundInstance(); + assertEquals("other_blubb", ub.getId()); + assertFalse(ub.isSetConstant()); + assertEquals("SBO:0000625", ub.getSBOTermID()); + } + + +// /** +// * Note: I consider this behaviour to be a bug basically. +// *

+// * I am still testing the behaviour though for validation purposes should +// * this get fixed. +// */ +// @Test +// public void objectiveIsCreatedIfNoneIsPresent() { +// var model = new Model(3, 2); +// var fbcPlugin = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); +// +// var r = model.createReaction("some_reaction"); +// var kl = r.createKineticLaw(); +// var l1 = kl.createLocalParameter("OBJECTIVE_COEFFICIENT"); +// l1.setValue(23); +// +// assertEquals(1, model.getReactionCount()); +// assertEquals(0, fbcPlugin.getObjectiveCount()); +// +// new FBCReactionPolisher(fbcPlugin, polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); +// +// assertEquals(1, model.getReactionCount()); +// assertEquals(1, fbcPlugin.getObjectiveCount()); +// assertNotNull(fbcPlugin.getActiveObjectiveInstance()); +// var fo = fbcPlugin.getObjective(0) +// .getListOfFluxObjectives() +// .get(0); +// assertEquals("fo_some_reaction", fo.getId()); +// assertEquals(r, fo.getReactionInstance()); +// } + + + @Test + public void fluxObjectivesAreSetFromKinematicLaws() { + var model = new Model(3, 2); + var fbcPlugin = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); + + var r = model.createReaction("some_reaction"); + var kl = r.createKineticLaw(); + var l1 = kl.createLocalParameter("OBJECTIVE_COEFFICIENT"); + l1.setValue(23); + + var obj1 = fbcPlugin.createObjective("obj1", Objective.Type.MINIMIZE); + var obj2 = fbcPlugin.createObjective("obj2", Objective.Type.MAXIMIZE); + fbcPlugin.setActiveObjective(obj1); + + assertEquals(1, model.getReactionCount()); + assertEquals(2, fbcPlugin.getObjectiveCount()); + assertEquals(0, obj1.getFluxObjectiveCount()); + assertEquals(0, obj2.getFluxObjectiveCount()); + + new FBCReactionPolisher(fbcPlugin, polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); + + assertEquals(1, model.getReactionCount()); + assertEquals(2, fbcPlugin.getObjectiveCount()); + assertEquals(1, obj1.getFluxObjectiveCount()); + assertEquals(0, obj2.getFluxObjectiveCount()); + var fo = obj1 + .getListOfFluxObjectives() + .get(0); + assertEquals("fo_some_reaction", fo.getId()); + assertEquals(r, fo.getReactionInstance()); + assertEquals(23, fo.getCoefficient()); + } + + + @Test + public void existingObjectivesAreRespected() { + var model = new Model(3, 2); + var fbcPlugin = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); + + var r = model.createReaction("some_reaction"); + var kl = r.createKineticLaw(); + var l1 = kl.createLocalParameter("OBJECTIVE_COEFFICIENT"); + l1.setValue(23); + + var obj1 = fbcPlugin.createObjective("obj1", Objective.Type.MINIMIZE); + var existing_fo = obj1.createFluxObjective("existing_fo"); + existing_fo.setReaction(r); + var obj2 = fbcPlugin.createObjective("obj2", Objective.Type.MAXIMIZE); + fbcPlugin.setActiveObjective(obj1); + + assertEquals(1, model.getReactionCount()); + assertEquals(2, fbcPlugin.getObjectiveCount()); + assertEquals(1, obj1.getFluxObjectiveCount()); + assertEquals(0, obj2.getFluxObjectiveCount()); + + new FBCReactionPolisher(fbcPlugin, polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); + + assertEquals(1, model.getReactionCount()); + assertEquals(2, fbcPlugin.getObjectiveCount()); + assertEquals(1, obj1.getFluxObjectiveCount()); + assertEquals(0, obj2.getFluxObjectiveCount()); + var fo = obj1 + .getListOfFluxObjectives() + .get(0); + assertEquals("existing_fo", fo.getId()); + assertEquals(r, fo.getReactionInstance()); + assertFalse(fo.isSetCoefficient()); + } + + @Test + public void boundsAreCreatedFromLocalParameters() { + var model = new Model(3, 2); + var fbcPlugin = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); + + var r = model.createReaction("some_reaction"); + var rFbcPlugin = (FBCReactionPlugin) r.getPlugin(FBCConstants.shortLabel); + + var kl = r.createKineticLaw(); + kl.createLocalParameter("LOWER_BOUND"); + kl.createLocalParameter("UPPER_BOUND"); + + assertNull(rFbcPlugin.getLowerFluxBoundInstance()); + assertNull(rFbcPlugin.getUpperFluxBoundInstance()); + + new FBCReactionPolisher(fbcPlugin, polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); + + var lb = rFbcPlugin.getLowerFluxBoundInstance(); + assertEquals("some_reaction_LOWER_BOUND", lb.getId()); + assertTrue(lb.isSetConstant()); + assertTrue(lb.isConstant()); + assertEquals("SBO:0000625", lb.getSBOTermID()); + var ub = rFbcPlugin.getUpperFluxBoundInstance(); + assertEquals("some_reaction_UPPER_BOUND", ub.getId()); + assertTrue(ub.isSetConstant()); + assertTrue(ub.isConstant()); + assertEquals("SBO:0000625", lb.getSBOTermID()); + } + + + @Test + public void newBoundsSettingsByValueAndExistingParameters() { + var model = new Model(3, 2); + var fbcPlugin = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); + + var r = model.createReaction("some_reaction"); + var rFbcPlugin = (FBCReactionPlugin) r.getPlugin(FBCConstants.shortLabel); + + var kl = r.createKineticLaw(); + var p1 = kl.createLocalParameter("LOWER_BOUND"); + p1.setValue(1000); + kl.createLocalParameter("UPPER_BOUND"); + + var pModel = model.createParameter("some_reaction_UPPER_BOUND"); + + assertNull(rFbcPlugin.getLowerFluxBoundInstance()); + assertNull(rFbcPlugin.getUpperFluxBoundInstance()); + + new FBCReactionPolisher(fbcPlugin, polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); + + var lb = rFbcPlugin.getLowerFluxBoundInstance(); + assertEquals("DEFAULT_UPPER_BOUND", lb.getId()); + var ub = rFbcPlugin.getUpperFluxBoundInstance(); + assertEquals("some_reaction_UPPER_BOUND", ub.getId()); + assertEquals(pModel, ub); + } + + /** + * Note: this apparently shows a bug in the GPRParser::areEqual method. + * That is, hopefully, once that bug is fixed, this should fail. + * + */ + @Test + public void notesToGPRs() { + var model = new Model(3, 2); + var fbcPlugin = (FBCModelPlugin) model.getPlugin(FBCConstants.shortLabel); + + var r = model.createReaction("some_reaction"); + var rFbcPlugin = (FBCReactionPlugin) r.getPlugin(FBCConstants.shortLabel); + var body = new XMLNode(new XMLTriple("body", "", "")); + var p1 = new XMLNode(new XMLTriple("p", "", "")); + p1.addChild(new XMLNode("GENE_ASSOCIATION: some_assoc")); + body.addChild(p1); + var p2 = new XMLNode(new XMLTriple("p", "", "")); + p2.addChild(new XMLNode("GENE_ASSOCIATION: some_other_assoc")); + body.addChild(p2); + r.setNotes(body); + + new FBCReactionPolisher(fbcPlugin, polishingParameters, sboParameters, new IdentifiersOrg()).polish(r); + + assertInstanceOf(GeneProductRef.class, rFbcPlugin.getGeneProductAssociation() + .getAssociation(), "The result is expected to be " + + "(wrongly, happy fixing should this fail for you!) " + + "a single gene association, not an AND or OR."); + assertEquals("G_some_assoc", + ((GeneProductRef) rFbcPlugin.getGeneProductAssociation() + .getAssociation()).getGeneProduct()); + } + +} \ No newline at end of file diff --git a/src/test/java/edu/ucsd/sbrg/polishing/fbc/ObjectivesPolisherTest.java b/src/test/java/edu/ucsd/sbrg/polishing/fbc/ObjectivesPolisherTest.java new file mode 100644 index 00000000..d0a30ae7 --- /dev/null +++ b/src/test/java/edu/ucsd/sbrg/polishing/fbc/ObjectivesPolisherTest.java @@ -0,0 +1,53 @@ +package edu.ucsd.sbrg.polishing.fbc; + +import edu.ucsd.sbrg.parameters.FluxObjectivesPolishingParameters; +import edu.ucsd.sbrg.parameters.PolishingParameters; +import edu.ucsd.sbrg.resolver.identifiersorg.IdentifiersOrg; +import org.junit.jupiter.api.Test; +import org.sbml.jsbml.Model; +import org.sbml.jsbml.ext.fbc.FBCConstants; +import org.sbml.jsbml.ext.fbc.FBCModelPlugin; +import org.sbml.jsbml.ext.fbc.FluxObjective; + +import java.util.List; +import java.util.Set; +import java.util.stream.Collectors; + +import static org.junit.jupiter.api.Assertions.*; + + +public class ObjectivesPolisherTest { + + /** + * Test that if an objective is set, and it has flux objectives too, it won't be overwritten. + */ + @Test + public void activeObjectiveRemainsUnchangedIfItHasFluxObjective() { + var m = new Model(3,2); + var fbcPlugin = (FBCModelPlugin) m.getPlugin(FBCConstants.shortLabel); + + fbcPlugin.createObjective("obj1"); + var o2 = fbcPlugin.createObjective("obj2"); + o2.createFluxObjective(); + fbcPlugin.setActiveObjective(o2); + fbcPlugin.createObjective("obj3"); + + var parameters = new PolishingParameters( + null, + new FluxObjectivesPolishingParameters( + null, + List.of(" objective_reaction1 "))); + + m.createReaction("objective_reaction1"); + m.createReaction("yadda_Biomass_yadda"); + + var mPlug = (FBCModelPlugin) m.getPlugin(FBCConstants.shortLabel); + new ObjectivesPolisher(fbcPlugin, parameters, new IdentifiersOrg()).polish(mPlug.getListOfObjectives()); + + assertEquals("obj2", fbcPlugin.getActiveObjective()); + } + + + + +} \ No newline at end of file diff --git a/src/test/java/edu/ucsd/sbrg/validation/ModelValidatorTest.java b/src/test/java/edu/ucsd/sbrg/validation/ModelValidatorTest.java new file mode 100644 index 00000000..f0bda704 --- /dev/null +++ b/src/test/java/edu/ucsd/sbrg/validation/ModelValidatorTest.java @@ -0,0 +1,26 @@ +package edu.ucsd.sbrg.validation; + +import org.junit.jupiter.api.Test; +import org.sbml.jsbml.Model; +import org.sbml.jsbml.SBMLDocument; +import org.sbml.jsbml.validator.offline.LoggingValidationContext; + +import static org.junit.jupiter.api.Assertions.*; + +public class ModelValidatorTest { + + @Test + public void invalidSBMLFails() { + var doc = new SBMLDocument(3, 1); + doc.setModel(new Model()); +// var validator = new ModelValidator(); +// var errorLog = validator.validate(sbml); + LoggingValidationContext context = new LoggingValidationContext(doc.getLevel(), doc.getVersion()); + context.setValidateRecursively(true); + context.loadConstraints(Model.class, doc.getLevel(), doc.getVersion()); + context.validate(doc.getModel()); + var errorLog = context.getErrorLog(); + assertEquals(0, errorLog.getErrorCount()); + assertFalse(doc.getModel().isSetId()); + } +} diff --git a/src/main/resources/edu/ucsd/sbrg/bigg/models/e_coli_core.xml b/src/test/resources/edu/ucsd/sbrg/e_coli_core.xml similarity index 100% rename from src/main/resources/edu/ucsd/sbrg/bigg/models/e_coli_core.xml rename to src/test/resources/edu/ucsd/sbrg/e_coli_core.xml diff --git a/src/main/resources/edu/ucsd/sbrg/bigg/models/e_coli_core.json b/src/test/resources/edu/ucsd/sbrg/io/e_coli_core.json similarity index 100% rename from src/main/resources/edu/ucsd/sbrg/bigg/models/e_coli_core.json rename to src/test/resources/edu/ucsd/sbrg/io/e_coli_core.json diff --git a/src/main/resources/edu/ucsd/sbrg/bigg/models/e_coli_core.mat b/src/test/resources/edu/ucsd/sbrg/io/e_coli_core.mat similarity index 100% rename from src/main/resources/edu/ucsd/sbrg/bigg/models/e_coli_core.mat rename to src/test/resources/edu/ucsd/sbrg/io/e_coli_core.mat