diff --git a/lib/jsbml-2472-incl-libs.jar b/lib/jsbml-2482-incl-libs.jar similarity index 93% rename from lib/jsbml-2472-incl-libs.jar rename to lib/jsbml-2482-incl-libs.jar index 663c09f3..608adcdb 100644 Binary files a/lib/jsbml-2472-incl-libs.jar and b/lib/jsbml-2482-incl-libs.jar differ diff --git a/lib/sysbio-1388.jar b/lib/sysbio-1390.jar similarity index 93% rename from lib/sysbio-1388.jar rename to lib/sysbio-1390.jar index 2b5cab01..41eddc08 100644 Binary files a/lib/sysbio-1388.jar and b/lib/sysbio-1390.jar differ diff --git a/pom.xml b/pom.xml index fac1c4ea..5b5e5f7f 100644 --- a/pom.xml +++ b/pom.xml @@ -51,7 +51,7 @@ andraeger@eng.ucsd.edu Andreas Dräger - https://github.com/draeger + https://github.com/draeger/ draeger @@ -73,14 +73,14 @@ org.sbml JSBML - 2472 + 2482 compile de.zbit SysBio - 1388 + 1390 compile diff --git a/src/edu/ucsd/sbrg/bigg/MIRIAM.java b/src/edu/ucsd/sbrg/bigg/MIRIAM.java index e92a1227..32b6f7bf 100644 --- a/src/edu/ucsd/sbrg/bigg/MIRIAM.java +++ b/src/edu/ucsd/sbrg/bigg/MIRIAM.java @@ -232,7 +232,7 @@ public enum MIRIAM { * http://www.grenoble.prabi.fr/obiwarehouse/unipathway/ucr?upid= * TODO What is the actual pattern? Using any character! */ - unipathway_reaction(pairOf("http://www.grenoble.prabi.fr/obiwarehouse/unipathway/ucr?upid=", ".*")), + unipathway_reaction(pairOf(" http://identifiers.org/unipathway.reaction/", "^UCR\\d{5}$")), /** * UniPathway is a manually curated resource of enzyme-catalyzed and * spontaneous chemical reactions. It provides a hierarchical representation diff --git a/src/edu/ucsd/sbrg/bigg/ModelPolisher.java b/src/edu/ucsd/sbrg/bigg/ModelPolisher.java index 691da8e1..48ebddd9 100644 --- a/src/edu/ucsd/sbrg/bigg/ModelPolisher.java +++ b/src/edu/ucsd/sbrg/bigg/ModelPolisher.java @@ -57,9 +57,51 @@ public class ModelPolisher extends Launcher { /** - * Generated serial version identifier. + * Helper class to store all parameters for running ModelPolisher in batch mode. + * + * @author Andreas Dräger */ - private static final long serialVersionUID = 7745344693995142413L; + private static final class Parameters { + /** + * @see ModelPolisherOptions#CHECK_MASS_BALANCE + */ + Boolean checkMassBalance = null; + /** + * @see ModelPolisherOptions#COMPRESSION_TYPE + */ + Compression compression = Compression.NONE; + /** + * Can be {@code null} + * @see ModelPolisherOptions#DOCUMENT_NOTES_FILE + */ + File documentNotesFile = null; + /** + * Can be {@code null} (then a default is used). + * @see ModelPolisherOptions#DOCUMENT_TITLE_PATTERN + */ + String documentTitlePattern = null; + /** + * @see ModelPolisherOptions#FLUX_COEFFICIENTS + */ + double[] fluxCoefficients = null; + /** + * @see ModelPolisherOptions#FLUX_OBJECTIVES + */ + String[] fluxObjectives = null; + /** + * Can be {@code null} + * @see ModelPolisherOptions#MODEL_NOTES_FILE + */ + File modelNotesFile = null; + /** + * @see ModelPolisherOptions#OMIT_GENERIC_TERMS + */ + Boolean omitGenericTerms = null; + /** + * @see ModelPolisherOptions#SBML_VALIDATION + */ + Boolean sbmlValidation = null; + } /** * Localization support. @@ -71,6 +113,18 @@ public class ModelPolisher extends Launcher { */ private static final transient Logger logger = Logger.getLogger(ModelPolisher.class.getName()); + /** + * Generated serial version identifier. + */ + private static final long serialVersionUID = 7745344693995142413L; + + /** + * @param args + */ + public static void main(String[] args) { + new ModelPolisher(args); + } + /** * @param args */ @@ -78,6 +132,64 @@ public ModelPolisher(String... args) { super(args); } + /* (non-Javadoc) + * @see de.zbit.Launcher#addCopyrightToSplashScreen() + */ + @Override + protected boolean addCopyrightToSplashScreen() { + return false; + } + + /* (non-Javadoc) + * @see de.zbit.Launcher#addVersionNumberToSplashScreen() + */ + @Override + protected boolean addVersionNumberToSplashScreen() { + return false; + } + + /** + * + * @param bigg + * @param input + * @param output + * @param parameters + * @throws IOException + * @throws XMLStreamException + */ + public void batchProcess(BiGGDB bigg, File input, File output, Parameters parameters) throws IOException, + XMLStreamException { + + if (!output.exists() && !output.isFile() + && !(input.isFile() && input.getName().equals(output.getName()))) { + logger.info(MessageFormat.format("Creating directory {0}.", + output.getAbsolutePath())); + output.mkdir(); + } + if (input.isFile()) { + boolean matFile = SBFileFilter.hasFileType(input, SBFileFilter.FileType.MAT_FILES); + if (SBFileFilter.isSBMLFile(input) || matFile) { + if (output.isDirectory()) { + String fName = input.getName(); + if (matFile) { + fName = FileTools.removeFileExtension(fName) + ".xml"; + } + output = new File(Utils.ensureSlash(output.getAbsolutePath()) + fName); + } + polish(bigg, input, output, parameters); + } + } else { + if (!output.isDirectory()) { + throw new IOException(MessageFormat.format("Cannot write to file {0}.", + output.getAbsolutePath())); + } + for (File file : input.listFiles()) { + File target = new File(Utils.ensureSlash(output.getAbsolutePath()) + file.getName()); + batchProcess(bigg, file, target, parameters); + } + } + } + /* (non-Javadoc) * @see de.zbit.Launcher#commandLineMode(de.zbit.AppConf) */ @@ -90,6 +202,13 @@ public void commandLineMode(AppConf appConf) { * Formatter */ OneLineFormatter formatter = new OneLineFormatter(false, false, false); + /* (non-Javadoc) + * @see java.util.logging.StreamHandler#flush() + */ + @Override + public synchronized void flush() { + System.out.flush(); + } /* (non-Javadoc) * @see java.util.logging.ConsoleHandler#publish(java.util.logging.LogRecord) */ @@ -105,13 +224,6 @@ public void publish(LogRecord record) { } } } - /* (non-Javadoc) - * @see java.util.logging.StreamHandler#flush() - */ - @Override - public synchronized void flush() { - System.out.flush(); - } }, getLogPackages()); } try { @@ -132,208 +244,44 @@ public synchronized void flush() { documentTitlePattern = args.getProperty(ModelPolisherOptions.DOCUMENT_TITLE_PATTERN); } + double[] coefficients = null; + if (args.containsKey(ModelPolisherOptions.FLUX_COEFFICIENTS)) { + String c = args.getProperty(ModelPolisherOptions.FLUX_COEFFICIENTS); + String coeff[] = c.substring(1, c.length() - 1).split(","); + coefficients = new double[coeff.length]; + for (int i = 0; i < coeff.length; i++) { + coefficients[i] = Double.parseDouble(coeff[i].trim()); + } + } + String fObj[] = null; + if (args.containsKey(ModelPolisherOptions.FLUX_OBJECTIVES)) { + String fObjectives = args.getProperty(ModelPolisherOptions.FLUX_OBJECTIVES); + fObj = fObjectives.substring(1, fObjectives.length() - 1).split(":"); + } + + Parameters parameters = new Parameters(); + parameters.checkMassBalance = args.getBooleanProperty(ModelPolisherOptions.CHECK_MASS_BALANCE); + parameters.compression = ModelPolisherOptions.Compression.valueOf(args.getProperty(ModelPolisherOptions.COMPRESSION_TYPE)); + parameters.documentNotesFile = documentNotesFile; + parameters.documentTitlePattern = documentTitlePattern; + parameters.fluxCoefficients = coefficients; + parameters.fluxObjectives = fObj; + parameters.modelNotesFile = modelNotesFile; + parameters.omitGenericTerms = args.getBooleanProperty(ModelPolisherOptions.OMIT_GENERIC_TERMS); + parameters.sbmlValidation = args.getBooleanProperty(ModelPolisherOptions.SBML_VALIDATION); + // run polishing operations in background and parallel. batchProcess(bigg, new File(args.getProperty(IOOptions.INPUT)), new File(args.getProperty(IOOptions.OUTPUT)), - ModelPolisherOptions.Compression.valueOf(args.getProperty(ModelPolisherOptions.COMPRESSION_TYPE)), - args.getBooleanProperty(ModelPolisherOptions.OMIT_GENERIC_TERMS), - documentNotesFile, modelNotesFile, documentTitlePattern, - args.getBooleanProperty(ModelPolisherOptions.CHECK_MASS_BALANCE), - args.getBooleanProperty(ModelPolisherOptions.SBML_VALIDATION)); + parameters); + } catch (SBMLException | XMLStreamException | IOException | SQLException | ClassNotFoundException exc) { exc.printStackTrace(); } } - /** - * Scans the given command-line options for a specific file option and returns - * the corresponding file if it exists, {@code null} otherwise. - * - * @param args - * command-line options. - * @param option - * a specific file option to look for. - * @return a {@link File} object that corresponds to a desired command-line - * option, or {@code null} if it does not exist. - */ - private File parseFileOption(SBProperties args, Option option) { - if (args.containsKey(option)) { - File notesFile = new File(args.getProperty(option)); - if ((notesFile != null) && notesFile.exists() && notesFile.canRead()) { - return notesFile; - } - } - return null; - } - - /** - * - * @param bigg - * @param input - * @param output - * @param compressOutput ! - * @param omitGenericTerms - * @param documentNotesFile can be {@code null}. - * @param modelNotesFile can be {@code null}. - * @param documentTitlePattern can be {@code null} (then a default is used). - * @param checkMassBalance - * @param validateOutput - * @throws XMLStreamException - * @throws IOException - */ - public void polish(BiGGDB bigg, File input, File output, - Compression compressOutput, boolean omitGenericTerms, - File documentNotesFile, File modelNotesFile, String documentTitlePattern, - boolean checkMassBalance, boolean validateOutput) - throws XMLStreamException, IOException { - long time = System.currentTimeMillis(); - logger.info(MessageFormat.format("Reading input file {0}.", - input.getAbsolutePath())); - SBMLDocument doc = null; - if (SBFileFilter.hasFileType(input, SBFileFilter.FileType.MAT_FILES)) { - doc = COBRAparser.read(input, omitGenericTerms); - } else { - doc = SBMLReader.read(input, new UpdateListener()); - } - if (!doc.isSetLevelAndVersion() - || (doc.getLevelAndVersion().compareTo(ValuePair.of(3, 1)) < 0)) { - logger.info("Trying to convert the model to Level 3 Version 2."); - org.sbml.jsbml.util.SBMLtools.setLevelAndVersion(doc, 3, 1); - } - SBMLPolisher polisher = new SBMLPolisher(bigg); - polisher.setCheckMassBalance(checkMassBalance); - polisher.setOmitGenericTerms(omitGenericTerms); - if (documentNotesFile != null) { - polisher.setDocumentNotesFile(documentNotesFile); - } - if (modelNotesFile != null) { - polisher.setModelNotesFile(modelNotesFile); - } - if (documentTitlePattern != null) { - polisher.setDocumentTitlePattern(documentTitlePattern); - } - doc = polisher.polish(doc); - // - logger.info(MessageFormat.format("Writing output file {0}", - output.getAbsolutePath())); - TidySBMLWriter.write(doc, output, getClass().getSimpleName(), - getVersionNumber(), ' ', (short) 2); - // SBMLWriter.write(doc, sbmlFile, ' ', (short) 2); - if (compressOutput != Compression.NONE) { - String fileExtension = compressOutput.getFileExtension(); - String archive = output.getAbsolutePath() + "." + fileExtension; - logger.info(MessageFormat.format("Packing archive file {0}", archive)); - switch (compressOutput) { - case ZIP: - ZIPUtils.ZIPcompress(new String[] {output.getAbsolutePath()}, archive, - "SBML Archive", true); - break; - case GZIP: - ZIPUtils.GZip(output.getAbsolutePath(), archive); - break; - default: - break; - } - if (validateOutput) { - validate(archive); - } - } - time = System.currentTimeMillis() - time; - Calendar calendar = Calendar.getInstance(); - calendar.setTimeInMillis(time); - logger.info(MessageFormat.format("Done ({0,time,ss.sss} s).", - calendar.getTime())); - } - - /** - * - * @param filename - */ - private void validate(String filename) { - //org.sbml.jsbml.validator.SBMLValidator.main(new String[] {"-d", "p,u", compressedOutput}); - String output = "xml"; - String offcheck = "p,u"; - HashMap parameters = new HashMap(); - parameters.put("output", output); - parameters.put("offcheck", offcheck); - - logger.info("Validating " + filename + "\n"); - - SBMLErrorLog sbmlErrorLog = SBMLValidator.checkConsistency(filename, parameters); - - if (sbmlErrorLog != null) { - logger.info(MessageFormat.format( - "There {0,choice,0#are no errors|1#is one error|1> getCmdLineOptions() { return options; } + /* (non-Javadoc) + * @see de.zbit.Launcher#getInstitute() + */ + @Override + public String getInstitute() { + return baseBundle.getString("INSTITUTE"); + } + /* (non-Javadoc) * @see de.zbit.Launcher#getInteractiveOptions() */ @@ -380,14 +336,6 @@ public List> getInteractiveOptions() { return options; } - /* (non-Javadoc) - * @see de.zbit.Launcher#getInstitute() - */ - @Override - public String getInstitute() { - return baseBundle.getString("INSTITUTE"); - } - /* (non-Javadoc) * @see de.zbit.Launcher#getLogPackages() */ @@ -441,22 +389,6 @@ public String getVersionNumber() { return version == null ? "?" : version; } - /* (non-Javadoc) - * @see de.zbit.Launcher#addCopyrightToSplashScreen() - */ - @Override - protected boolean addCopyrightToSplashScreen() { - return false; - } - - /* (non-Javadoc) - * @see de.zbit.Launcher#addVersionNumberToSplashScreen() - */ - @Override - protected boolean addVersionNumberToSplashScreen() { - return false; - } - /* (non-Javadoc) * @see de.zbit.Launcher#getYearOfProgramRelease() */ @@ -490,10 +422,126 @@ public Window initGUI(AppConf appConf) { } /** + * Scans the given command-line options for a specific file option and returns + * the corresponding file if it exists, {@code null} otherwise. + * * @param args + * command-line options. + * @param option + * a specific file option to look for. + * @return a {@link File} object that corresponds to a desired command-line + * option, or {@code null} if it does not exist. */ - public static void main(String[] args) { - new ModelPolisher(args); + private File parseFileOption(SBProperties args, Option option) { + if (args.containsKey(option)) { + File notesFile = new File(args.getProperty(option)); + if ((notesFile != null) && notesFile.exists() && notesFile.canRead()) { + return notesFile; + } + } + return null; + } + + /** + * + * @param bigg + * @param input + * @param output + * @param parameters + * @throws XMLStreamException + * @throws IOException + */ + public void polish(BiGGDB bigg, File input, File output, Parameters parameters) + throws XMLStreamException, IOException { + long time = System.currentTimeMillis(); + logger.info(MessageFormat.format("Reading input file {0}.", + input.getAbsolutePath())); + SBMLDocument doc = null; + if (SBFileFilter.hasFileType(input, SBFileFilter.FileType.MAT_FILES)) { + doc = COBRAparser.read(input, parameters.omitGenericTerms); + } else { + doc = SBMLReader.read(input, new UpdateListener()); + } + if (!doc.isSetLevelAndVersion() + || (doc.getLevelAndVersion().compareTo(ValuePair.of(3, 1)) < 0)) { + logger.info("Trying to convert the model to Level 3 Version 2."); + org.sbml.jsbml.util.SBMLtools.setLevelAndVersion(doc, 3, 1); + } + SBMLPolisher polisher = new SBMLPolisher(bigg); + polisher.setCheckMassBalance(parameters.checkMassBalance); + polisher.setOmitGenericTerms(parameters.omitGenericTerms); + if (parameters.documentNotesFile != null) { + polisher.setDocumentNotesFile(parameters.documentNotesFile); + } + if (parameters.modelNotesFile != null) { + polisher.setModelNotesFile(parameters.modelNotesFile); + } + if (parameters.documentTitlePattern != null) { + polisher.setDocumentTitlePattern(parameters.documentTitlePattern); + } + polisher.setFluxCoefficients(parameters.fluxCoefficients); + polisher.setFluxObjectives(parameters.fluxObjectives); + doc = polisher.polish(doc); + // + logger.info(MessageFormat.format("Writing output file {0}", + output.getAbsolutePath())); + TidySBMLWriter.write(doc, output, getClass().getSimpleName(), getVersionNumber(), ' ', (short) 2); + // SBMLWriter.write(doc, sbmlFile, ' ', (short) 2); + if (parameters.compression != Compression.NONE) { + String fileExtension = parameters.compression.getFileExtension(); + String archive = output.getAbsolutePath() + "." + fileExtension; + logger.info(MessageFormat.format("Packing archive file {0}", archive)); + switch (parameters.compression) { + case ZIP: + ZIPUtils.ZIPcompress(new String[] {output.getAbsolutePath()}, archive, + "SBML Archive", true); + break; + case GZIP: + ZIPUtils.GZip(output.getAbsolutePath(), archive); + break; + default: + break; + } + if ((parameters.sbmlValidation != null) && parameters.sbmlValidation) { + validate(archive); + } + } + time = System.currentTimeMillis() - time; + Calendar calendar = Calendar.getInstance(); + calendar.setTimeInMillis(time); + logger.info(MessageFormat.format("Done ({0,time,ss.sss} s).", calendar.getTime())); + } + + /** + * + * @param filename + */ + private void validate(String filename) { + //org.sbml.jsbml.validator.SBMLValidator.main(new String[] {"-d", "p,u", compressedOutput}); + String output = "xml"; + String offcheck = "p,u"; + HashMap parameters = new HashMap(); + parameters.put("output", output); + parameters.put("offcheck", offcheck); + + logger.info("Validating " + filename + "\n"); + + SBMLErrorLog sbmlErrorLog = SBMLValidator.checkConsistency(filename, parameters); + + if (sbmlErrorLog != null) { + logger.info(MessageFormat.format( + "There {0,choice,0#are no errors|1#is one error|1 FLUX_COEFFICIENTS = new Option( + "FLUX_COEFFICIENTS", + (Class) (new Double[0]).getClass(), + "The flux coefficients, a comma-separated list", + new Double[0]); + + /** + * + */ + @SuppressWarnings("unchecked") + public static final Option FLUX_OBJECTIVES = new Option( + "FLUX_OBJECTIVES", + (Class) (new String[0]).getClass(), + "The flux objectives, a colon-separated list", + new String[0]); + /** * Decides whether or not the output file should directly be compressed and if * so, which archive type should be used. diff --git a/src/edu/ucsd/sbrg/bigg/SBMLPolisher.java b/src/edu/ucsd/sbrg/bigg/SBMLPolisher.java index 1c57eb3b..8468e995 100644 --- a/src/edu/ucsd/sbrg/bigg/SBMLPolisher.java +++ b/src/edu/ucsd/sbrg/bigg/SBMLPolisher.java @@ -156,6 +156,14 @@ public class SBMLPolisher { * */ private String documentNotesFile = "SBMLDocumentNotes.html"; + /** + * + */ + private double[] fluxCoefficients; + /** + * + */ + private String[] fluxObjectives; /** * @param bigg @@ -349,6 +357,10 @@ public void polish(Compartment c) { } if (!c.isSetUnits()) { // TODO: set compartment units. + /* + * This is a temporary solution until we agree on something better. + */ + c.setUnits(Unit.Kind.DIMENSIONLESS); } } /** @@ -1017,7 +1029,7 @@ public boolean polishListOfObjectives(boolean strict, FBCModelPlugin modelPlug) progress.DisplayBar(); //"Processing objective " + objective.getId()); if (!objective.isSetListOfFluxObjectives()) { Model model = modelPlug.getParent(); - strict &= SBMLFix.fixObjective(model.getId(), model.getListOfReactions(), modelPlug); + strict &= SBMLFix.fixObjective(model.getId(), model.getListOfReactions(), modelPlug, fluxCoefficients, fluxObjectives); } if (objective.isSetListOfFluxObjectives()) { strict &= polishListOfFluxObjectives(strict, objective); @@ -1221,4 +1233,20 @@ public void setDocumentNotesFile(File documentNotesFile) { this.documentNotesFile = documentNotesFile.getAbsolutePath(); } + /** + * + * @param fluxCoefficients + */ + public void setFluxCoefficients(double[] fluxCoefficients) { + this.fluxCoefficients = fluxCoefficients; + } + + /** + * + * @param fluxObjectives + */ + public void setFluxObjectives(String[] fluxObjectives) { + this.fluxObjectives = fluxObjectives; + } + } diff --git a/src/edu/ucsd/sbrg/cobra/ModelFields.java b/src/edu/ucsd/sbrg/cobra/ModelFields.java index 48efba9c..97c2d36c 100644 --- a/src/edu/ucsd/sbrg/cobra/ModelFields.java +++ b/src/edu/ucsd/sbrg/cobra/ModelFields.java @@ -31,6 +31,8 @@ public enum ModelFields { * If this cannot be expressed in SBML, then an error message would be * appropriate. The SBML file would probably not result in a functional joined * model though. + *

+ * Data type: double array. Length must be identical to the number of reactions. */ b, /** @@ -41,7 +43,13 @@ public enum ModelFields { */ B, /** - * The objective function vector for max(c' ⋅ v) + * The objective function vector for max(c' ⋅ v). The dimension + * of this element must be identical to the number of reactions. Dimensions + * that have a zero value in this field, do not contribute to the objective + * function. + *

+ * Data type: double array. + * Corresponds to {@link FluxObjective#getCoefficient()}. */ c, /** @@ -80,7 +88,8 @@ public enum ModelFields { */ disabled, /** - * The Enzyme Commission codes for the reactions. + * The Enzyme Commission codes for the reactions. Length must be identical to + * the number of reactions. */ ecNumbers, /** @@ -92,7 +101,8 @@ public enum ModelFields { */ geneindex, /** - * The gene products. + * The list of gene in the model, where each contained gene corresponds to a + * {@link GeneProduct#getId()}. Data type: cell array of string. */ genes, /** @@ -100,7 +110,9 @@ public enum ModelFields { */ genesource, /** - * + * Boolean GPR rules (AND/OR). Data type: cell array of strings. + * Example: {@code (8639.1) or (26.1) or (314.2) or (314.1)}. Dimensions must + * be identical to the number of reactions. Corresponds to {@link GeneProductAssociation} */ grRules, /** @@ -108,39 +120,50 @@ public enum ModelFields { */ lb, /** - * Must have same dimension as {@link #mets}. + * Must have same dimension as {@link #mets}. Data type: double array. + * For SBML Level < 3, it corresponds to {@link Species#getCharge()}. Since + * Level 3, it corresponds to {@link FBCSpeciesPlugin#getCharge()}. */ metCharge, /** * Optional: if present, it must have same dimension as {@link #mets}. + * Data type: cell array of strings. Corresponds to the annotation of + * {@link Species} */ metCHEBIID, /** * Chemical formulas for metabolites, must have same dimension as {@link #mets}. + * Datatype: cell array of strings. Corresponds to {@link FBCSpeciesPlugin#getChemicalFormula()}. */ metFormulas, /** * Optional: if present, it must have same dimension as {@link #mets}. + * Data type: cell array of strings. */ metHMDB, /** * Optional: if present, it must have same dimension as {@link #mets}. + * Data type: cell array of strings. */ metInchiString, /** * Optional: if present, it must have same dimension as {@link #mets}. + * Data type: cell array of strings. */ metKeggID, /** - * Descriptive metabolite names, must have same dimension as {@link #mets} + * Descriptive metabolite names, must have same dimension as {@link #mets}. + * Datatype: cell array of strings. Corresponds to {@link Species#getName()} */ metNames, /** * Optional: if present, it must have same dimension as {@link #mets}. + * Data type: cell array of strings. */ metPubChemID, /** - * Metabolite BiGG ids (incl. compartment code) + * Metabolite BiGG ids (incl. compartment code). Data type: cell array of + * strings. Corresponds to {@link Species#getId()}. */ mets, /** @@ -168,6 +191,8 @@ public enum ModelFields { /** * A vector consisting of zeros and ones that translate to binary and determine * if the corresponding reaction of that index is reversible (1) or not (0). + * Dimensions must be equal to the number of reactions. Corresponds to the + * value {@linkReaction#isReversible()} */ rev, /** @@ -175,21 +200,58 @@ public enum ModelFields { */ rules, /** - * + * Cell array of strings, can any value in a range of 0 to 4. Length must be + * equal to the number of reactions. + */ + rxnConfidenceEcoIDA, + /** + * @see #confidenceScores. + */ + rxnConfidenceScores, + /** + * The Systems Biology Ontology Term to describe the role of a reaction. + * Length must be identical to the number of reactions. Value corresponds to + * the attribute {@link Reaction#getSBOTerm()} + */ + rxnsboTerm, + /** + * A matrix with rows corresponding to reaction list and columns corresponding + * to gene list. Data type: sparse double. Size of this matrix must be number + * of reactions times number of genes. No counterpart in FBC v2. */ rxnGeneMat, /** * Reaction identifiers in KEGG, but sometimes also contains {@link #ecNumbers}. + * Length must be identical to the number of reactions. Entries belong to the + * annotation of {@link Reaction}. */ rxnKeggID, /** - * Descriptive reaction names + * Descriptive reaction names, length must be identical to the number of + * reactions. Data type: cell array of string. Corresponds to the name of a + * {@link Reaction}. */ rxnNames, /** - * Reaction BiGG ids + * @see #ecNumbers + */ + rxnECNumbers, + /** + * Example: + *

+   * 'Na coupled transport of pyruvate, lactate, and short chain fatty acids, i.e., acetate, propionate, and butyrate mediated by SMCT1
+   * 
+ */ + rxnReferences, + /** + * Reaction BiGG ids. Corresponds to the id of {@link Reaction}. */ rxns, + /** + * Cell array of strings. Text notes (description) about reactions. Length + * must be identical to the number of reactions. + */ + rxnNotes, /** * Stoichiometric matrix */ @@ -198,6 +260,9 @@ public enum ModelFields { * This defines groups of reactions that belong to a common reaction subsystem. * Their number must hence be identical to the reaction count. Subsystems are * listed repeatedly in the source file. + * If present, the size of this field must be identical to the number of + * reactions. + * Data type: cell array of strings. */ subSystems, /** diff --git a/src/edu/ucsd/sbrg/util/SBMLFix.java b/src/edu/ucsd/sbrg/util/SBMLFix.java index 40aad6e2..612009ee 100644 --- a/src/edu/ucsd/sbrg/util/SBMLFix.java +++ b/src/edu/ucsd/sbrg/util/SBMLFix.java @@ -56,7 +56,7 @@ public class SBMLFix { /** * A {@link Logger} for this class. */ - private static final transient Logger logger = Logger.getLogger(SBMLFix.class.getSimpleName()); + private static final transient Logger logger = Logger.getLogger(SBMLFix.class.getName()); /** * @@ -143,6 +143,21 @@ public static void fixObjective(String modelDescriptor, Model model) { */ public static boolean fixObjective(String modelDescriptor, ListOf listOfReactions, FBCModelPlugin fbcPlug) { + return fixObjective(modelDescriptor, listOfReactions, fbcPlug, null, null); + } + + /** + * + * @param modelDescriptor + * @param listOfReactions + * @param fbcPlug + * @param fluxCoefficients + * @param fluxObjectives + * @return + */ + public static boolean fixObjective(String modelDescriptor, + ListOf listOfReactions, FBCModelPlugin fbcPlug, double[] fluxCoefficients, + String[] fluxObjectives) { Objective activeObjective = null; if (!fbcPlug.isSetActiveObjective()) { logger.severe(MessageFormat.format( @@ -165,20 +180,42 @@ public static boolean fixObjective(String modelDescriptor, ListOf list "Trying to identify missing flux objective from model in model {0}.", modelDescriptor)); if (listOfReactions != null) { - final Pattern pattern = SBMLPolisher.PATTERN_BIOMASS_CASE_INSENSITIVE; - Reaction rBiomass = listOfReactions.firstHit((obj) -> { - return (obj instanceof Reaction) && pattern.matcher(((Reaction) obj).getId()).matches(); - }); - if (rBiomass != null) { - logger.info(MessageFormat.format( - "Added biomass function {0} with coefficient {1,number} to model {2}.", - rBiomass.getId(), DEFAULT_COEFFICIENT, modelDescriptor)); - o.createFluxObjective(null, null, DEFAULT_COEFFICIENT, rBiomass); - - return true; + if (fluxObjectives != null) { + /* + * An array of target reactions is provided. We want to use this as flux objectives. + */ + boolean strict = false; + for (int i = 0; i < fluxObjectives.length; i++) { + final String id = fluxObjectives[i]; + Reaction r = listOfReactions.firstHit((obj) -> { + return (obj instanceof Reaction) && id.equals(((Reaction) obj).getId()); + }); + if (r != null) { + createFluxObjective(modelDescriptor, r, fluxCoefficients, o, i); + // if at least one flux objective exists, the model qualifies as strict model. + strict = true; + } else { + logger.severe(MessageFormat.format( + "Operation failed! Could not identify reaction ''{0}'' in model {1}.", + id, modelDescriptor)); + } + } + return strict; } else { - logger.severe("Operation failed! Could not identify biomass reaction."); + /* + * Search for biomass reaction in the model and use this as objective. + */ + final Pattern pattern = SBMLPolisher.PATTERN_BIOMASS_CASE_INSENSITIVE; + Reaction rBiomass = listOfReactions.firstHit((obj) -> { + return (obj instanceof Reaction) && pattern.matcher(((Reaction) obj).getId()).matches(); + }); + if (rBiomass != null) { + createFluxObjective(modelDescriptor, rBiomass, fluxCoefficients, o, 0); + return true; + } else { + logger.severe("Operation failed! Could not identify biomass reaction."); + } } } else { logger.severe(MessageFormat.format( @@ -191,6 +228,26 @@ public static boolean fixObjective(String modelDescriptor, ListOf list return false; } + /** + * + * @param modelDescriptor + * @param r + * @param fluxCoefficients + * @param o + * @param i + */ + private static void createFluxObjective(String modelDescriptor, + Reaction r, double[] fluxCoefficients, Objective o, int i) { + double coeff = DEFAULT_COEFFICIENT; + if ((fluxCoefficients != null) && (fluxCoefficients.length > i)) { + coeff = fluxCoefficients[i]; + } + logger.info(MessageFormat.format( + "Added flux objective for reaction ''{0}'' with coefficient {1,number} to model {2}.", + r.getId(), coeff, modelDescriptor)); + o.createFluxObjective(null, null, coeff, r); + } + /** * * @param in