From 06d0fe3c2500f7a7a551346fa81bf53f5c76ab6c Mon Sep 17 00:00:00 2001 From: Dave Parker Date: Sat, 30 Jun 2012 22:14:00 +0000 Subject: [PATCH] First version of reactions-to-PRISM converter. git-svn-id: https://www.prismmodelchecker.org/svn/prism/prism/trunk@5410 bbc10eb1-c90d-0410-af57-cb519fbb1720 --- prism/src/prism/Reactions2Prism.java | 53 ++++- prism/src/prism/ReactionsText2Prism.java | 240 +++++++++++++++++++++++ 2 files changed, 283 insertions(+), 10 deletions(-) create mode 100644 prism/src/prism/ReactionsText2Prism.java diff --git a/prism/src/prism/Reactions2Prism.java b/prism/src/prism/Reactions2Prism.java index 6ad83c54..b5d70950 100644 --- a/prism/src/prism/Reactions2Prism.java +++ b/prism/src/prism/Reactions2Prism.java @@ -57,14 +57,14 @@ public class Reactions2Prism protected ArrayList reactionList; // Config - + /** Maximum amount of each species (unless some initial amount is higher). */ protected int maxAmount = 100; // Optional PRISM code header/footer protected String prismCodeHeader; protected String prismCodeFooter; - + // Constructors public Reactions2Prism() @@ -81,7 +81,7 @@ public class Reactions2Prism { this.maxAmount = maxAmount; } - + /** * Print the currently loaded reaction set model (for testing purposes). */ @@ -360,8 +360,12 @@ public class Reactions2Prism sb.append("\t// " + reaction.id); if (reaction.name.length() > 0) sb.append(" (" + reaction.name + ")"); + sb.append(": " + reaction.reactionString()); sb.append("\n"); - s2 = MathML2Prism.convert(reaction.kineticLaw, renameFrom, renameTo); + if (reaction.kineticLawString != null) + s2 = reaction.kineticLawString; + else + s2 = MathML2Prism.convert(reaction.kineticLaw, renameFrom, renameTo); sb.append("\t[" + reaction.id + "] " + s2 + " > 0 -> " + s2 + " : true;\n"); } sb.append("\nendmodule\n"); @@ -429,7 +433,7 @@ public class Reactions2Prism public String toString() { - return id + (name.length() > 0 ? (" (" + name + ")") : ""); + return id + (name != null && name.length() > 0 ? (" (" + name + ")") : ""); } } @@ -461,6 +465,7 @@ public class Reactions2Prism public ArrayList products; public ArrayList productStoichs; public Element kineticLaw; + public String kineticLawString; public ArrayList parameters; public Reaction(String id, String name) @@ -472,6 +477,7 @@ public class Reactions2Prism products = new ArrayList(); productStoichs = new ArrayList(); kineticLaw = null; + kineticLawString = null; parameters = new ArrayList(); } @@ -482,8 +488,13 @@ public class Reactions2Prism public void addReactant(String reactant, int stoich) { - reactants.add(reactant); - reactantStoichs.add(stoich); + int i = reactants.indexOf(reactant); + if (i == -1) { + reactants.add(reactant); + reactantStoichs.add(stoich); + } else { + reactantStoichs.set(i, reactantStoichs.get(i) + stoich); + } } public void addProduct(String product) @@ -493,13 +504,25 @@ public class Reactions2Prism public void addProduct(String product, int stoich) { - products.add(product); - productStoichs.add(stoich); + int i = products.indexOf(product); + if (i == -1) { + products.add(product); + productStoichs.add(stoich); + } else { + productStoichs.set(i, productStoichs.get(i) + stoich); + } } public void setKineticLaw(Element kineticLaw) { this.kineticLaw = kineticLaw; + this.kineticLawString = null; + } + + public void setKineticLawString(String kineticLawString) + { + this.kineticLawString = kineticLawString; + this.kineticLaw = null; } public void addParameter(String name, String value) @@ -528,6 +551,13 @@ public class Reactions2Prism return productStoichs.get(i); } + public String reactionString() + { + String s = PrismUtils.joinString(reactants, "+"); + s += " -> " + PrismUtils.joinString(products, "+"); + return s; + } + public String toString() { String s = ""; @@ -539,7 +569,10 @@ public class Reactions2Prism s += " Reactants stoichiometry: " + productStoichs + "\n"; s += " Products: " + products + "\n"; s += " Products stoichiometry: " + productStoichs + "\n"; - s += " Kinetic law: " + kineticLaw + "\n"; + if (kineticLawString != null) + s += " Kinetic law: " + kineticLawString + "\n"; + else + s += " Kinetic law: " + kineticLaw + "\n"; s += " Parameters: " + parameters + "\n"; return s; } diff --git a/prism/src/prism/ReactionsText2Prism.java b/prism/src/prism/ReactionsText2Prism.java new file mode 100644 index 00000000..dcf8d463 --- /dev/null +++ b/prism/src/prism/ReactionsText2Prism.java @@ -0,0 +1,240 @@ +//============================================================================== +// +// Copyright (c) 2002- +// Authors: +// * Dave Parker (University of Birmingham/Oxford) +// +//------------------------------------------------------------------------------ +// +// This file is part of PRISM. +// +// PRISM is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// PRISM is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with PRISM; if not, write to the Free Software Foundation, +// Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA +// +//============================================================================== + +package prism; + +import java.io.BufferedReader; +import java.io.File; +import java.io.FileReader; +import java.io.IOException; +import java.util.ArrayList; + +/** + * Class to convert a textual description of a set of reactions into PRISM code. + */ +public class ReactionsText2Prism extends Reactions2Prism +{ + /** + * Calling point for command-line script: + * e.g. java -cp classes prism.ReactionsText2Prism myfile.txt 100 + * (100 denotes (integer) maximum for species population sizes, default is 100) + */ + public static void main(String args[]) + { + PrismLog errLog = new PrismPrintStreamLog(System.err); + try { + if (args.length < 1) { + System.err.println("Usage: java -cp classes prism.ReactionsText2Prism [max_amount]"); + System.exit(1); + } + ReactionsText2Prism rt2prism = new ReactionsText2Prism(errLog); + try { + if (args.length > 1) + rt2prism.setMaxAmount(Integer.parseInt(args[1])); + } catch (NumberFormatException e) { + throw new PrismException("Invalid max amount \"" + args[1] + "\""); + } + rt2prism.translate(new File(args[0])); + } catch (PrismException e) { + errLog.println("Error: " + e.getMessage() + "."); + } + } + + // Enums + + private enum SectionType { + SPECIES, PARAMETERS, REACTIONS, RR, R + }; + + // Constructors + + public ReactionsText2Prism() + { + super(); + } + + public ReactionsText2Prism(PrismLog mainLog) + { + super(mainLog); + } + + /** + * Main method: load reactions file, process and send resulting PRISM file to stdout + */ + public void translate(File file) throws PrismException + { + // Read in file + extractModelFromFile(file); + // Generate PRISM code + prismCodeHeader = "// File generated by reactions-to-PRISM conversion\n"; + prismCodeHeader += "// Original file: " + file.getPath() + "\n\n"; + convertToPRISMCode(System.out); + } + + /** + * Build the reaction set model from a parsed SBML file. + */ + private void extractModelFromFile(File file) throws PrismException + { + BufferedReader in; + SectionType secType = null; + String s, s2, ss[], ss2[]; + int i, lineNum = 0; + Species species; + Parameter parameter; + Reaction reaction; + String reactionId = null, reactionName = null; + + // Initialise storage + speciesList = new ArrayList(); + parameterList = new ArrayList(); + reactionList = new ArrayList(); + + try { + // Open file for reading + in = new BufferedReader(new FileReader(file)); + // Read remaining lines + s = in.readLine(); + lineNum++; + while (s != null) { + // Skip blank lines + s = s.trim(); + if (s.length() > 0) { + + // Switch mode on section header + if (s.charAt(0) == '@') { + s2 = s.substring(1); + if (s2.equals("species")) { + secType = SectionType.SPECIES; + } else if (s2.equals("parameters")) { + secType = SectionType.PARAMETERS; + } else if (s2.equals("reactions")) { + secType = SectionType.REACTIONS; + } else if (s2.startsWith("rr=")) { + secType = SectionType.RR; + // Extract reaction id/name + s2 = s2.substring(3); + i = s2.indexOf(' '); + reactionId = s2.substring(0, i > 0 ? i : s2.length()); + reactionName = i > 0 ? s2.substring(i + 1).replaceAll("\"", "") : ""; + } else if (s2.startsWith("r=")) { + secType = SectionType.R; + // Extract reaction id/name + s2 = s2.substring(2); + i = s2.indexOf(' '); + reactionId = s2.substring(0, i > 0 ? i : s2.length()); + reactionName = i > 0 ? s2.substring(i + 1).replaceAll("\"", "") : ""; + } else { + throw new PrismException("@" + s2 + " section not supported"); + } + } else { + switch (secType) { + + // Species list + case SPECIES: + ss = s.split("="); + if (ss.length != 2) + throw new PrismException("invalid species definition \"" + s + "\""); + // Get id + String speciesId = ss[0]; + // Get init amount/name + s2 = ss[1].trim(); + i = s2.indexOf(' '); + String sInit = s2.substring(0, i > 0 ? i : s2.length()); + String speciesName = i > 0 ? s2.substring(i + 1).replaceAll("\"", "") : null; + int initialAmount = Integer.parseInt(sInit); + species = new Species(speciesId, speciesName, initialAmount); + speciesList.add(species); + break; + + // Parameter list + case PARAMETERS: + ss = s.split("="); + if (ss.length == 1) { + // Get id (value undefined) + String paramId = ss[0]; + parameter = new Parameter(paramId, null); + } else if (ss.length == 2) { + // Get id and value + String paramId = ss[0]; + parameter = new Parameter(paramId, ss[1]); + } else { + throw new PrismException("invalid parameter definition \"" + s + "\""); + } + parameterList.add(parameter); + break; + + // Reaction + case RR: + case R: + ss = s.split("->"); + if (ss.length != 2) + throw new PrismException("invalid reaction definition \"" + s + "\""); + // Create reaction object with earlier info + reaction = new Reaction(reactionId, reactionName); + // Get reactants + ss2 = ss[0].trim().split("\\+"); + for (String reactant : ss2) { + reaction.addReactant(reactant, 1); + } + // Get products + ss2 = ss[1].trim().split("\\+"); + for (String product : ss2) { + reaction.addProduct(product, 1); + } + // Next line + s = in.readLine(); + if (s == null) + throw new PrismException("missing line in reaction definition"); + s = s.trim(); + // Get kinetic law + // TODO: reversible case + reaction.setKineticLawString(s); + lineNum++; + reactionList.add(reaction); + break; + + // Anything else: skip + default: + } + } + } + // read next line + s = in.readLine(); + lineNum++; + } + + // close file + in.close(); + } catch (IOException e) { + throw new PrismException("File I/O error reading from \"" + file + "\""); + } catch (NumberFormatException e) { + throw new PrismException("Error detected at line " + lineNum + " of file \"" + file + "\""); + } catch (PrismException e) { + throw new PrismException("Error detected (" + e.getMessage() + ") at line " + lineNum + " of file \"" + file + "\""); + } + } +}