From 836994f33cf56b82fdae8a0623ecb8adeb17693e Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Thu, 21 Dec 2017 16:16:38 +0100 Subject: [PATCH] export of sbml reaction without layout --- .../model/sbml/SbmlBioEntityExporter.java | 84 +++++++++++++++++++ .../model/sbml/SbmlElementExporter.java | 71 +--------------- .../model/sbml/SbmlElementParser.java | 20 +++-- .../converter/model/sbml/SbmlExporter.java | 2 + .../converter/model/sbml/SbmlParser.java | 2 +- .../model/sbml/SbmlReactionExporter.java | 63 ++++++++++++++ .../model/sbml/SbmlReactionParser.java | 12 ++- .../model/sbml/SbmlSpeciesParser.java | 2 +- .../model/sbml/SbmlExporterTest.java | 17 +--- .../layout/ApplySimpleLayoutModelCommand.java | 2 - .../lcsb/mapviewer/model/map/BioEntity.java | 2 + .../model/map/reaction/Reaction.java | 5 ++ 12 files changed, 187 insertions(+), 95 deletions(-) create mode 100644 converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityExporter.java create mode 100644 converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionExporter.java diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityExporter.java new file mode 100644 index 0000000000..1a18c6ef25 --- /dev/null +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlBioEntityExporter.java @@ -0,0 +1,84 @@ +package lcsb.mapviewer.converter.model.sbml; + +import java.util.Collection; +import java.util.HashMap; +import java.util.Map; + +import javax.xml.stream.XMLStreamException; + +import org.apache.log4j.Logger; +import org.sbml.jsbml.Model; +import org.sbml.jsbml.ext.layout.AbstractReferenceGlyph; +import org.sbml.jsbml.ext.layout.Layout; + +import lcsb.mapviewer.common.exception.InvalidStateException; +import lcsb.mapviewer.model.map.BioEntity; +import lcsb.mapviewer.model.map.InconsistentModelException; + +public abstract class SbmlBioEntityExporter<T extends BioEntity, S extends org.sbml.jsbml.AbstractNamedSBase> { + Logger logger = Logger.getLogger(SbmlBioEntityExporter.class); + + Layout layout; + + lcsb.mapviewer.model.map.model.Model minervaModel; + Model sbmlModel; + + Map<String, S> sbmlElementByElementId = new HashMap<>(); + Map<String, AbstractReferenceGlyph> sbmlGlyphByElementId = new HashMap<>(); + + private Map<String, S> sbmlElementByElementNameAndCompartmentName = new HashMap<>(); + + public SbmlBioEntityExporter(Layout sbmlLayout, lcsb.mapviewer.model.map.model.Model minervaModel) { + this.layout = sbmlLayout; + this.minervaModel = minervaModel; + } + + public void exportElements(Model model) throws InconsistentModelException { + sbmlModel = model; + Collection<T> speciesList = getElementList(); + for (T species : speciesList) { + S sbmlCompartment = getSbmlElement(species, null); + + if (sbmlElementByElementId.get(species.getElementId()) != null) { + throw new InconsistentModelException("More than one species with id: " + species.getElementId()); + } + sbmlElementByElementId.put(species.getElementId(), sbmlCompartment); + } + for (T species : speciesList) { + AbstractReferenceGlyph compartmentGlyph = createGlyph(species); + sbmlGlyphByElementId.put(species.getElementId(), compartmentGlyph); + } + } + + protected abstract Collection<T> getElementList(); + + public abstract S createSbmlElement(T element) throws InconsistentModelException; + + protected S getSbmlElement(T element, String compartmentName) throws InconsistentModelException { + String mapKey = element.getName() + "\n" + compartmentName; + if (sbmlElementByElementNameAndCompartmentName.get(mapKey) == null) { + S sbmlElement = createSbmlElement(element); + sbmlElement.setName(element.getName()); + try { + sbmlElement.setNotes(element.getNotes()); + } catch (XMLStreamException e) { + throw new InvalidStateException(e); + } + sbmlElementByElementNameAndCompartmentName.put(mapKey, sbmlElement); + } + return sbmlElementByElementNameAndCompartmentName.get(mapKey); + } + + protected abstract void assignLayoutToGlyph(T element, AbstractReferenceGlyph compartmentGlyph); + + protected AbstractReferenceGlyph createGlyph(T element) { + String sbmlCompartmentId = sbmlElementByElementId.get(element.getElementId()).getId(); + String glyphId = element.getElementId(); + AbstractReferenceGlyph compartmentGlyph = createElementGlyph(sbmlCompartmentId, glyphId); + assignLayoutToGlyph(element, compartmentGlyph); + return compartmentGlyph; + } + + protected abstract AbstractReferenceGlyph createElementGlyph(String sbmlCompartmentId, String glyphId); + +} diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementExporter.java index de56245f1f..d0aebc087f 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementExporter.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementExporter.java @@ -1,75 +1,20 @@ package lcsb.mapviewer.converter.model.sbml; -import java.util.HashMap; -import java.util.List; -import java.util.Map; - -import javax.xml.stream.XMLStreamException; - import org.apache.log4j.Logger; -import org.sbml.jsbml.Model; import org.sbml.jsbml.ext.layout.AbstractReferenceGlyph; import org.sbml.jsbml.ext.layout.BoundingBox; import org.sbml.jsbml.ext.layout.Dimensions; import org.sbml.jsbml.ext.layout.Layout; import org.sbml.jsbml.ext.layout.Point; -import lcsb.mapviewer.common.exception.InvalidStateException; -import lcsb.mapviewer.model.map.InconsistentModelException; import lcsb.mapviewer.model.map.species.Element; -public abstract class SbmlElementExporter<T extends Element, S extends org.sbml.jsbml.Symbol> { +public abstract class SbmlElementExporter<T extends Element, S extends org.sbml.jsbml.Symbol> + extends SbmlBioEntityExporter<T, S> { Logger logger = Logger.getLogger(SbmlElementExporter.class); - Layout layout; - - lcsb.mapviewer.model.map.model.Model minervaModel; - Model sbmlModel; - - Map<String, S> sbmlElementByElementId = new HashMap<>(); - Map<String, AbstractReferenceGlyph> sbmlGlyphByElementId = new HashMap<>(); - - private Map<String, S> sbmlElementByElementNameAndCompartmentName = new HashMap<>(); - public SbmlElementExporter(Layout sbmlLayout, lcsb.mapviewer.model.map.model.Model minervaModel) { - this.layout = sbmlLayout; - this.minervaModel = minervaModel; - } - - public void exportElements(Model model) throws InconsistentModelException { - sbmlModel = model; - List<T> speciesList = getElementList(); - for (T species : speciesList) { - S sbmlCompartment = getSbmlElement(species, null); - - if (sbmlElementByElementId.get(species.getElementId()) != null) { - throw new InconsistentModelException("More than one species with id: " + species.getElementId()); - } - sbmlElementByElementId.put(species.getElementId(), sbmlCompartment); - } - for (T species : speciesList) { - AbstractReferenceGlyph compartmentGlyph = createCompartmentGlyph(species); - sbmlGlyphByElementId.put(species.getElementId(), compartmentGlyph); - } - } - - protected abstract List<T> getElementList(); - - public abstract S createSbmlElement(T element) throws InconsistentModelException; - - protected S getSbmlElement(T element, String compartmentName) throws InconsistentModelException { - String mapKey = element.getName() + "\n" + compartmentName; - if (sbmlElementByElementNameAndCompartmentName.get(mapKey) == null) { - S sbmlElement = createSbmlElement(element); - sbmlElement.setName(element.getName()); - try { - sbmlElement.setNotes(element.getNotes()); - } catch (XMLStreamException e) { - throw new InvalidStateException(e); - } - sbmlElementByElementNameAndCompartmentName.put(mapKey, sbmlElement); - } - return sbmlElementByElementNameAndCompartmentName.get(mapKey); + super(sbmlLayout, minervaModel); } protected void assignLayoutToGlyph(T element, AbstractReferenceGlyph compartmentGlyph) { @@ -84,14 +29,4 @@ public abstract class SbmlElementExporter<T extends Element, S extends org.sbml. compartmentGlyph.setBoundingBox(boundingBox); } - protected AbstractReferenceGlyph createCompartmentGlyph(T compartment) { - String sbmlCompartmentId = sbmlElementByElementId.get(compartment.getElementId()).getId(); - String glyphId = compartment.getElementId(); - AbstractReferenceGlyph compartmentGlyph = createElementGlyph(sbmlCompartmentId, glyphId); - assignLayoutToGlyph(compartment, compartmentGlyph); - return compartmentGlyph; - } - - protected abstract AbstractReferenceGlyph createElementGlyph(String sbmlCompartmentId, String glyphId); - } diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementParser.java index f97d872d5f..5250fc675f 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementParser.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlElementParser.java @@ -35,28 +35,32 @@ public abstract class SbmlElementParser<T extends org.sbml.jsbml.Symbol> { public List<Element> parseList(Model sbmlModel) throws InvalidInputDataExecption { List<Element> result = new ArrayList<>(); for (T sbmlElement : getSbmlElementList(sbmlModel)) { - result.add(parse(sbmlElement, sbmlModel)); + Element element = parse(sbmlElement, sbmlModel); + result.add(element); + elementBySbmlId.put(element.getElementId(), element); } return result; } protected abstract ListOf<T> getSbmlElementList(Model sbmlModel); + Map<String, Element> elementBySbmlId = new HashMap<>(); + + public Element getAnyElementBySbmlElementId(String id) { + return elementBySbmlId.get(id); + } + protected List<Element> mergeLayout(List<? extends Element> elements, Layout sbmlLayout, Model sbmlModel) throws InvalidInputDataExecption { Set<String> used = new HashSet<>(); - Map<String, Element> elementById = new HashMap<>(); List<Element> result = new ArrayList<>(); for (Element species : elements) { - if (elementById.get(species.getElementId()) != null) { - throw new InvalidInputDataExecption("Duplicated element id: " + species.getElementId()); - } - elementById.put(species.getElementId(), species); + elementBySbmlId.put(species.getElementId(), species); } for (Pair<String, AbstractReferenceGlyph> idGlyphPair : getGlyphs(sbmlLayout)) { String id = idGlyphPair.getLeft(); - Element source = elementById.get(id); + Element source = elementBySbmlId.get(id); if (source == null) { throw new InvalidInputDataExecption("Layout contains invalid Species id: " + idGlyphPair.getLeft()); } @@ -70,6 +74,8 @@ public abstract class SbmlElementParser<T extends org.sbml.jsbml.Symbol> { elementWithLayout.setHeight(glyph.getBoundingBox().getDimensions().getHeight()); minervaModel.addElement(elementWithLayout); result.add(elementWithLayout); + elementBySbmlId.put(id, elementWithLayout); + elementBySbmlId.put(elementWithLayout.getElementId(), elementWithLayout); } for (Element element : elements) { if (!used.contains(element.getElementId())) { 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 2ce062a880..0a54f2fa59 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 @@ -22,8 +22,10 @@ public class SbmlExporter { SbmlCompartmentExporter compartmentExporter = new SbmlCompartmentExporter(layout, model); SbmlSpeciesExporter speciesExporter = new SbmlSpeciesExporter(layout, model, compartmentExporter); + SbmlReactionExporter reactionExporter = new SbmlReactionExporter(layout, model, speciesExporter); compartmentExporter.exportElements(result); speciesExporter.exportElements(result); + reactionExporter.exportElements(result); // // Create some sample content in the SBML model. // Species specOne = result.createSpecies("test_spec1", compartment); 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 2847e01973..733826af7b 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 @@ -62,7 +62,7 @@ public class SbmlParser implements IConverter { SbmlCompartmentParser compartmentParser = new SbmlCompartmentParser(layout, model); SbmlSpeciesParser speciesParser = new SbmlSpeciesParser(layout, model); - SbmlReactionParser reactionParser = new SbmlReactionParser(layout, model); + SbmlReactionParser reactionParser = new SbmlReactionParser(layout, model, speciesParser); Set<MiriamData> annotations = compartmentParser.parseAnnotation(sbmlModel.getAnnotation()); if (annotations.size() > 0) { diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionExporter.java new file mode 100644 index 0000000000..092a3b7679 --- /dev/null +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlReactionExporter.java @@ -0,0 +1,63 @@ +package lcsb.mapviewer.converter.model.sbml; + +import java.util.Collection; + +import org.apache.log4j.Logger; +import org.sbml.jsbml.Species; +import org.sbml.jsbml.ext.layout.AbstractReferenceGlyph; +import org.sbml.jsbml.ext.layout.Layout; + +import lcsb.mapviewer.model.map.InconsistentModelException; +import lcsb.mapviewer.model.map.reaction.Modifier; +import lcsb.mapviewer.model.map.reaction.Product; +import lcsb.mapviewer.model.map.reaction.Reactant; +import lcsb.mapviewer.model.map.reaction.Reaction; + +public class SbmlReactionExporter extends SbmlBioEntityExporter<Reaction, org.sbml.jsbml.Reaction> { + Logger logger = Logger.getLogger(SbmlReactionExporter.class); + private int idCounter = 0; + private SbmlSpeciesExporter speciesExporter; + + public SbmlReactionExporter(Layout layout, lcsb.mapviewer.model.map.model.Model minervaModel, + SbmlSpeciesExporter speciesExporter) { + super(layout, minervaModel); + this.speciesExporter = speciesExporter; + } + + @Override + public org.sbml.jsbml.Reaction createSbmlElement(Reaction reaction) throws InconsistentModelException { + org.sbml.jsbml.Reaction result = sbmlModel.createReaction("reaction_" + (idCounter++)); + for (Product product : reaction.getProducts()) { + Species sbmlSymbol = speciesExporter.sbmlElementByElementId.get(product.getElement().getElementId()); + result.createProduct(sbmlSymbol); + } + for (Reactant reactant : reaction.getReactants()) { + Species sbmlSymbol = speciesExporter.sbmlElementByElementId.get(reactant.getElement().getElementId()); + result.createReactant(sbmlSymbol); + } + for (Modifier modifier : reaction.getModifiers()) { + Species sbmlSymbol = speciesExporter.sbmlElementByElementId.get(modifier.getElement().getElementId()); + result.createModifier(sbmlSymbol); + } + return result; + } + + @Override + protected AbstractReferenceGlyph createElementGlyph(String sbmlElementId, String glyphId) { +// AbstractReferenceGlyph speciesGlyph = layout.createReactionGlyph(glyphId, sbmlElementId); +// return speciesGlyph; + return null; + } + + @Override + protected Collection<Reaction> getElementList() { + return minervaModel.getReactions(); + } + + @Override + protected void assignLayoutToGlyph(Reaction element, AbstractReferenceGlyph compartmentGlyph) { + // TODO Auto-generated method stub + + } + +} 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 f96d4e2f7b..33b08697c0 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 @@ -55,9 +55,13 @@ public class SbmlReactionParser { lcsb.mapviewer.model.map.model.Model minervaModel; ElementUtils eu = new ElementUtils(); - public SbmlReactionParser(Layout sbmlLayout, lcsb.mapviewer.model.map.model.Model minervaModel) { + SbmlSpeciesParser speciesParser; + + public SbmlReactionParser(Layout sbmlLayout, lcsb.mapviewer.model.map.model.Model minervaModel, + SbmlSpeciesParser speciesParser) { this.layout = sbmlLayout; this.minervaModel = minervaModel; + this.speciesParser = speciesParser; } public List<Reaction> parseList(Model sbmlModel) throws InvalidInputDataExecption { @@ -224,7 +228,11 @@ public class SbmlReactionParser { Set<Reaction> elementsToRemove = new HashSet<>(); for (Reaction reaction : reactions) { if (!used.contains(reaction)) { - logger.warn("Layout doesn't contain information about Reaction: " + reaction.getIdReaction()); + for (ReactionNode node : reaction.getReactionNodes()) { + // we might have different elements here, the reason is that single SBML species + // can be split into two or more (due to layout) + node.setElement(speciesParser.getAnyElementBySbmlElementId(node.getElement().getElementId())); + } } else { elementsToRemove.add(reaction); } diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlSpeciesParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlSpeciesParser.java index 648d7002ba..7b0900458d 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlSpeciesParser.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/SbmlSpeciesParser.java @@ -91,7 +91,7 @@ public class SbmlSpeciesParser extends SbmlElementParser<org.sbml.jsbml.Species> compartment = compartment2; } } - + } if (compartment != null) { compartment.addElement(element); diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java index a5a7554748..a6cda5f298 100644 --- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java +++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/SbmlExporterTest.java @@ -21,6 +21,7 @@ import lcsb.mapviewer.model.map.compartment.Compartment; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.model.map.reaction.Reaction; import lcsb.mapviewer.model.map.reaction.ReactionNode; +import lcsb.mapviewer.model.map.species.Element; import lcsb.mapviewer.model.map.species.Species; public class SbmlExporterTest { @@ -51,7 +52,8 @@ public class SbmlExporterTest { String xml = exporter.toXml(originalModel); ByteArrayInputStream stream = new ByteArrayInputStream(xml.getBytes("UTF-8")); Model result = parser.createModel(new ConverterParams().inputStream(stream)); - +// showImage(originalModel); +// showImage(result); return result; } @@ -118,17 +120,4 @@ public class SbmlExporterTest { assertEquals(2, reaction.getOperators().size()); } - @Test - public void testReactionWithoutLayout() throws Exception { - Model model = getModelAfterSerializing("testFiles/layoutExample/Complete_Example_level2.xml"); - assertNotNull(model); - assertEquals(1, model.getReactions().size()); - Reaction reaction = model.getReactions().iterator().next(); - for (ReactionNode node : reaction.getReactionNodes()) { - assertNotNull(node.getLine()); - assertTrue(node.getLine().length() > 0); - } - assertEquals(2, reaction.getOperators().size()); - } - } diff --git a/model-command/src/main/java/lcsb/mapviewer/commands/layout/ApplySimpleLayoutModelCommand.java b/model-command/src/main/java/lcsb/mapviewer/commands/layout/ApplySimpleLayoutModelCommand.java index 83cfd8e86b..041820ea04 100644 --- a/model-command/src/main/java/lcsb/mapviewer/commands/layout/ApplySimpleLayoutModelCommand.java +++ b/model-command/src/main/java/lcsb/mapviewer/commands/layout/ApplySimpleLayoutModelCommand.java @@ -114,8 +114,6 @@ public class ApplySimpleLayoutModelCommand extends ApplyLayoutModelCommand { protected void modifyElementLocation(Collection<Element> elements, Compartment parent, Point2D minPoint, Dimension2D dimension) { - logger.debug(minPoint); - logger.debug(dimension); Set<Compartment> compartments = new HashSet<>(); Set<Species> elementToAlign = new HashSet<>(); Map<Compartment, Set<Element>> elementsByStaticCompartment = new HashMap<>(); diff --git a/model/src/main/java/lcsb/mapviewer/model/map/BioEntity.java b/model/src/main/java/lcsb/mapviewer/model/map/BioEntity.java index 70319d5914..068af61908 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/BioEntity.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/BioEntity.java @@ -173,4 +173,6 @@ public interface BioEntity extends Serializable { */ Model getModel(); + String getElementId(); + } diff --git a/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java b/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java index 5d04e7781c..d1139cf5a6 100644 --- a/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java +++ b/model/src/main/java/lcsb/mapviewer/model/map/reaction/Reaction.java @@ -621,6 +621,11 @@ public class Reaction implements BioEntity { return idReaction; } + @Override + public String getElementId() { + return getIdReaction(); + } + /** * @param idReaction * the idReaction to set -- GitLab