diff --git a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionXmlParser.java b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionXmlParser.java index 18190f46ee7396e650e572f980f405d8d913667a..917ca54b971a73596161c3d9ccde1298dd572528 100644 --- a/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionXmlParser.java +++ b/converter-CellDesigner/src/main/java/lcsb/mapviewer/converter/model/celldesigner/function/FunctionXmlParser.java @@ -22,7 +22,7 @@ public class FunctionXmlParser extends XmlParser { if (mathDefinition == null) { throw new InvalidXmlSchemaException("Function " + functionId + " doesn't contain MathML definition (math node)"); } - result.setDefinition(nodeToString(mathDefinition)); + result.setDefinition(nodeToString(mathDefinition).replace(" xmlns=\"http://www.w3.org/1998/Math/MathML\"", "")); result.setArguments(parseArgumentsFromMath(mathDefinition, functionId)); return result; diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java index 2124b0065ba3b252e690dde923141ebfdc56537a..d05941bef41cf587f4e9ac39e7a0952dda198a7a 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlExporter.java @@ -25,16 +25,18 @@ public class SbmlExporter { SbmlCompartmentExporter compartmentExporter = new SbmlCompartmentExporter(layout, model); SbmlBioEntityExporter<Species, org.sbml.jsbml.Species> speciesExporter = new SbmlSpeciesExporter(layout, model, compartmentExporter); - SbmlReactionExporter reactionExporter = new SbmlReactionExporter(layout, model, speciesExporter, compartmentExporter); + SbmlReactionExporter reactionExporter = new SbmlReactionExporter(layout, model, speciesExporter, + compartmentExporter); SbmlUnitExporter unitExporter = new SbmlUnitExporter(model); SbmlParameterExporter parameterExporter = new SbmlParameterExporter(model); - + SbmlFunctionExporter functionExporter = new SbmlFunctionExporter(model); + compartmentExporter.exportElements(result); speciesExporter.exportElements(result); reactionExporter.exportElements(result); unitExporter.exportUnits(result); parameterExporter.exportParameter(result); - + functionExporter.exportFunction(result); ByteArrayOutputStream stream = new ByteArrayOutputStream(); SBMLWriter.write(doc, stream, "minerva", "1.0"); diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlFunctionExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlFunctionExporter.java new file mode 100644 index 0000000000000000000000000000000000000000..1ef4edfa9b7d1806171388d4aa2b8d662582610d --- /dev/null +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlFunctionExporter.java @@ -0,0 +1,35 @@ +package lcsb.mapviewer.converter.model.sbml; + +import org.apache.log4j.Logger; +import org.sbml.jsbml.ASTNode; +import org.sbml.jsbml.FunctionDefinition; + +import lcsb.mapviewer.model.map.kinetics.SbmlFunction; +import lcsb.mapviewer.model.map.model.Model; + +public class SbmlFunctionExporter { + Logger logger = Logger.getLogger(SbmlFunctionExporter.class); + private Model minervaModel; + + public SbmlFunctionExporter(lcsb.mapviewer.model.map.model.Model minervaModel) { + this.minervaModel = minervaModel; + } + + public void exportFunction(org.sbml.jsbml.Model result) { + for (SbmlFunction unit : minervaModel.getFunctions()) { + result.addFunctionDefinition(createFunction(unit)); + } + } + + private FunctionDefinition createFunction(SbmlFunction unit) { + FunctionDefinition result = new FunctionDefinition(); + result.setName(unit.getName()); + String definition = unit.getDefinition(); + definition = definition.replace(" xmlns=\"http://www.sbml.org/sbml/level2/version4\"", ""); + definition = "<math xmlns=\"http://www.w3.org/1998/Math/MathML\">" + definition + "</math>"; + result.setMath(ASTNode.parseMathML(definition)); + result.setId(unit.getFunctionId()); + return result; + } + +} diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlFunctionParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlFunctionParser.java new file mode 100644 index 0000000000000000000000000000000000000000..c2facb4d7c10f6cf97fd17ddbddcacd3f546b88c --- /dev/null +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlFunctionParser.java @@ -0,0 +1,62 @@ +package lcsb.mapviewer.converter.model.sbml; + +import java.util.ArrayList; +import java.util.Collection; +import java.util.List; + +import org.apache.log4j.Logger; +import org.sbml.jsbml.ListOf; +import org.sbml.jsbml.Model; +import org.w3c.dom.Node; + +import lcsb.mapviewer.common.exception.InvalidXmlSchemaException; +import lcsb.mapviewer.converter.InvalidInputDataExecption; +import lcsb.mapviewer.model.map.kinetics.SbmlFunction; + +public class SbmlFunctionParser extends SbmlBioEntityParser { + Logger logger = Logger.getLogger(SbmlFunctionParser.class); + + public SbmlFunctionParser(lcsb.mapviewer.model.map.model.Model minervaModel) { + this.minervaModel = minervaModel; + } + + protected SbmlFunction parse(org.sbml.jsbml.FunctionDefinition unitDefinition, Model sbmlModel) throws InvalidInputDataExecption { + try { + SbmlFunction result = new SbmlFunction(unitDefinition.getId()); + result.setName(unitDefinition.getName()); + Node node = super.getXmlDocumentFromString(unitDefinition.getMath().toMathML()); + Node mathDefinition = getNode("math", node); + result.setDefinition(super.nodeToString(mathDefinition)); + result.setArguments(parseArgumentsFromMath(mathDefinition, result.getFunctionId())); + return result; + } catch (InvalidXmlSchemaException e) { + throw new InvalidInputDataExecption(e); + } + + } + + private List<String> parseArgumentsFromMath(Node mathDefinition, String functionId) throws InvalidXmlSchemaException { + List<String> result = new ArrayList<>(); + Node lambdaDefinition = getNode("lambda", mathDefinition); + if (lambdaDefinition == null) { + throw new InvalidXmlSchemaException("Function " + functionId + " doesn't contain valid MathML lambda node"); + } + List<Node> variables = super.getNodes("bvar", lambdaDefinition.getChildNodes()); + for (Node node : variables) { + result.add(getNodeValue(getNode("ci", node)).trim()); + } + return result; + } + + protected ListOf<org.sbml.jsbml.FunctionDefinition> getSbmlElementList(Model sbmlModel) { + return sbmlModel.getListOfFunctionDefinitions(); + } + + public Collection<SbmlFunction> parseList(Model sbmlModel) throws InvalidInputDataExecption { + List<SbmlFunction> result = new ArrayList<>(); + for (org.sbml.jsbml.FunctionDefinition unitDefinition : getSbmlElementList(sbmlModel)) { + result.add(parse(unitDefinition, sbmlModel)); + } + return result; + } +} diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParameterExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParameterExporter.java index a89e7aebdf0d14bef465ff4bc73d3cb0bc1bcee8..ab52589200989af11b4c3865caad90415f14aa4f 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParameterExporter.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParameterExporter.java @@ -25,7 +25,9 @@ public class SbmlParameterExporter { result.setName(unit.getName()); result.setValue(unit.getValue()); result.setId(unit.getParameterId()); - result.setUnits(unit.getUnits().getUnitId()); + if (unit.getUnits() != null) { + result.setUnits(unit.getUnits().getUnitId()); + } return result; } diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParameterParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParameterParser.java index 111f6fe8b874cac340256fb29ff8b79a4baac21c..f2a9f645e0ee9050a393d8a870be3726523c5ffe 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParameterParser.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParameterParser.java @@ -7,6 +7,7 @@ import java.util.List; import org.apache.log4j.Logger; import org.sbml.jsbml.ListOf; import org.sbml.jsbml.Model; +import org.sbml.jsbml.QuantityWithUnit; import lcsb.mapviewer.model.map.kinetics.SbmlParameter; @@ -17,7 +18,7 @@ public class SbmlParameterParser extends SbmlBioEntityParser { this.minervaModel = minervaModel; } - protected SbmlParameter parse(org.sbml.jsbml.Parameter unitDefinition, Model sbmlModel) { + protected SbmlParameter parse(org.sbml.jsbml.QuantityWithUnit unitDefinition) { SbmlParameter result = new SbmlParameter(unitDefinition.getId()); result.setName(unitDefinition.getName()); result.setValue(unitDefinition.getValue()); @@ -30,10 +31,16 @@ public class SbmlParameterParser extends SbmlBioEntityParser { } public Collection<SbmlParameter> parseList(Model sbmlModel) { + Collection<SbmlParameter> result = parseList(getSbmlElementList(sbmlModel)); + return result; + } + + public Collection<SbmlParameter> parseList(Collection<? extends QuantityWithUnit> parameters) { List<SbmlParameter> result = new ArrayList<>(); - for (org.sbml.jsbml.Parameter unitDefinition : getSbmlElementList(sbmlModel)) { - result.add(parse(unitDefinition, sbmlModel)); + for (org.sbml.jsbml.QuantityWithUnit unitDefinition : parameters) { + result.add(parse(unitDefinition)); } return result; } + } diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParser.java index b7eb54f4ac0eee14c0cecfa754ee269ada365d6c..ee244ef5616df3ff148e939cb7fad5e871bc549c 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParser.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlParser.java @@ -31,6 +31,7 @@ import lcsb.mapviewer.converter.InvalidInputDataExecption; import lcsb.mapviewer.model.map.BioEntity; import lcsb.mapviewer.model.map.InconsistentModelException; import lcsb.mapviewer.model.map.MiriamData; +import lcsb.mapviewer.model.map.kinetics.SbmlFunction; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.model.map.model.ModelFullIndexed; import lcsb.mapviewer.model.map.modifier.Modulation; @@ -67,6 +68,7 @@ public class SbmlParser implements IConverter { SbmlReactionParser reactionParser = new SbmlReactionParser(layout, model, speciesParser, compartmentParser); SbmlUnitsParser unitParser = new SbmlUnitsParser(model); SbmlParameterParser parameterParser = new SbmlParameterParser(model); + SbmlFunctionParser functionParser = new SbmlFunctionParser(model); Set<MiriamData> annotations = compartmentParser.parseAnnotation(sbmlModel.getAnnotation()); if (annotations.size() > 0) { @@ -75,6 +77,7 @@ public class SbmlParser implements IConverter { model.addUnits(unitParser.parseList(sbmlModel)); model.addParameters(parameterParser.parseList(sbmlModel)); + model.addFunctions(functionParser.parseList(sbmlModel)); model.addElements(compartmentParser.parseList(sbmlModel)); model.addElements(speciesParser.parseList(sbmlModel)); @@ -109,9 +112,6 @@ public class SbmlParser implements IConverter { if (sbmlModel.getInitialAssignmentCount() > 0) { throw new NotImplementedException("InitialAssignment not implemented for model"); } - if (sbmlModel.getFunctionDefinitionCount() > 0) { - throw new NotImplementedException("Function not implemented for model"); - } if (sbmlModel.getRuleCount() > 0) { throw new NotImplementedException("Rule not implemented for model"); } diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionParser.java index acb2305454f134420d39435fbe2a023b14383f89..a623cd369572180ca7b2618e67f2c92976e96596 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionParser.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionParser.java @@ -34,7 +34,6 @@ import lcsb.mapviewer.model.graphics.ArrowTypeData; import lcsb.mapviewer.model.graphics.PolylineData; import lcsb.mapviewer.model.map.kinetics.SbmlArgument; import lcsb.mapviewer.model.map.kinetics.SbmlKinetics; -import lcsb.mapviewer.model.map.kinetics.SbmlParameter; import lcsb.mapviewer.model.map.modifier.Inhibition; import lcsb.mapviewer.model.map.modifier.Modulation; import lcsb.mapviewer.model.map.modifier.Trigger; @@ -301,13 +300,9 @@ public class SbmlReactionParser extends SbmlBioEntityParser { private SbmlKinetics createMinervaKinetics(KineticLaw kineticLaw) throws InvalidInputDataExecption { SbmlKinetics result = new SbmlKinetics(); result.setDefinition(kineticLaw.getMath().toMathML()); - for (LocalParameter parameter : kineticLaw.getListOfLocalParameters()) { - SbmlParameter minervaParameter = new SbmlParameter(parameter.getId()); - minervaParameter.setName(parameter.getName()); - minervaParameter.setValue(parameter.getValue()); - minervaParameter.setUnits(minervaModel.getUnitsByUnitId(parameter.getUnits())); - result.addParameter(minervaParameter); - } + + SbmlParameterParser parameterParser = new SbmlParameterParser(minervaModel); + result.addParameters(parameterParser.parseList((Collection<LocalParameter>)kineticLaw.getListOfLocalParameters())); try { Node node = super.getXmlDocumentFromString(result.getDefinition()); diff --git a/converter-sbml/testFiles/layoutExample/kinetic_function.xml b/converter-sbml/testFiles/layoutExample/kinetic_function.xml new file mode 100644 index 0000000000000000000000000000000000000000..5285496d41d09a3646c5f904c846291e561c2175 --- /dev/null +++ b/converter-sbml/testFiles/layoutExample/kinetic_function.xml @@ -0,0 +1,106 @@ +<?xml version="1.0" encoding="UTF-8"?> +<sbml level="2" version="3" xmlns="http://www.sbml.org/sbml/level2/version3"> + <model name="EnzymaticReaction"> +<listOfFunctionDefinitions> +<functionDefinition metaid="function_id" id="function_id" name="Function name"> +<math xmlns="http://www.w3.org/1998/Math/MathML"> +<lambda> +<bvar> +<ci> x </ci> +</bvar> +<bvar> +<ci> y </ci> +</bvar> +<apply> +<plus/> +<ci> x </ci> +<ci> y </ci> +</apply> +</lambda> +</math> +</functionDefinition> +</listOfFunctionDefinitions> + <listOfUnitDefinitions> + <unitDefinition id="per_second"> + <listOfUnits> + <unit kind="second" exponent="-1"/> + </listOfUnits> + </unitDefinition> + <unitDefinition id="litre_per_mole_per_second"> + <listOfUnits> + <unit kind="mole" exponent="-1"/> + <unit kind="litre" exponent="1"/> + <unit kind="second" exponent="-1"/> + </listOfUnits> + </unitDefinition> + </listOfUnitDefinitions> + <listOfCompartments> + <compartment id="cytosol" size="1e-14"/> + </listOfCompartments> + <listOfSpecies> + <species compartment="cytosol" id="ES" initialAmount="0" name="ES"/> + <species compartment="cytosol" id="P" initialAmount="0" name="P"/> + <species compartment="cytosol" id="S" initialAmount="1e-20" name="S"/> + <species compartment="cytosol" id="E" initialAmount="5e-21" name="E"/> + </listOfSpecies> + <listOfReactions> + <reaction id="veq"> + <listOfReactants> + <speciesReference species="E"/> + <speciesReference species="S"/> + </listOfReactants> + <listOfProducts> + <speciesReference species="ES"/> + </listOfProducts> + <kineticLaw> + <math xmlns="http://www.w3.org/1998/Math/MathML"> + <apply> + <times/> + <ci>cytosol</ci> + <apply> + <minus/> + <apply> + <times/> + <ci>kon</ci> + <ci>E</ci> + <ci>S</ci> + </apply> + <apply> + <times/> + <ci>koff</ci> + <ci>ES</ci> + </apply> + </apply> + </apply> + </math> + <listOfParameters> + <parameter id="kon" value="1000000" units="litre_per_mole_per_second"/> + <parameter id="koff" value="0.2" units="per_second"/> + </listOfParameters> + </kineticLaw> + </reaction> + <reaction id="vcat" reversible="false"> + <listOfReactants> + <speciesReference species="ES"/> + </listOfReactants> + <listOfProducts> + <speciesReference species="E"/> + <speciesReference species="P"/> + </listOfProducts> + <kineticLaw> + <math xmlns="http://www.w3.org/1998/Math/MathML"> + <apply> + <times/> + <ci>cytosol</ci> + <ci>kcat</ci> + <ci>ES</ci> + </apply> + </math> + <listOfParameters> + <parameter id="kcat" value="0.1" units="per_second"/> + </listOfParameters> + </kineticLaw> + </reaction> + </listOfReactions> + </model> +</sbml> diff --git a/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlFunctionComparator.java b/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlFunctionComparator.java index 74d4ea82313ecaebd2695e1cc27ab37bfa96f53a..15f90d66f8b719dc2e4931e7b7ede0c43c830254 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlFunctionComparator.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlFunctionComparator.java @@ -28,6 +28,8 @@ public class SbmlFunctionComparator extends Comparator<SbmlFunction> { if (stringComparator.compare(arg0.getDefinition(), arg1.getDefinition()) != 0) { logger.debug("definition different"); + logger.debug(arg0.getDefinition()); + logger.debug(arg1.getDefinition()); return stringComparator.compare(arg0.getDefinition(), arg1.getDefinition()); } diff --git a/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlKinetics.java b/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlKinetics.java index 9420e5e4d53debfdb48837b241003f2e92df0459..a4f1ec484c05dfbc35162710d95d8fd1c7a9de2b 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlKinetics.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/kinetics/SbmlKinetics.java @@ -2,6 +2,7 @@ package lcsb.mapviewer.model.map.kinetics; import java.io.Serializable; import java.util.ArrayList; +import java.util.Collection; import java.util.HashSet; import java.util.List; import java.util.Set; @@ -109,7 +110,7 @@ public class SbmlKinetics implements Serializable { } } - public void addParameters(Set<SbmlParameter> parameters) { + public void addParameters(Collection<SbmlParameter> parameters) { for (SbmlParameter parameter : parameters) { addParameter(parameter); }