From eb97d7f5b8e48008693c7a033823028cc3febb33 Mon Sep 17 00:00:00 2001 From: Piotr Gawron <piotr.gawron@uni.lu> Date: Wed, 14 Nov 2018 11:06:26 +0100 Subject: [PATCH] export of reaction contains information about arrow types and line types --- .../converter/model/sbml/SbmlParser.java | 7 +- .../sbml/reaction/SBOTermReactionType.java | 20 +- .../sbml/reaction/SbmlReactionExporter.java | 22 ++- .../sbml/reaction/SbmlReactionParser.java | 119 ++++++++++-- .../sbml/GenericSbmlToXmlParserTest.java | 3 +- .../reaction/AllSbmlReactionParserTests.java | 3 +- .../reaction/SbmlReactionExportArrowType.java | 183 ++++++++++++++++++ 7 files changed, 336 insertions(+), 21 deletions(-) create mode 100644 converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExportArrowType.java 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 84188fea07..2b97fc6adf 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 @@ -40,7 +40,9 @@ import lcsb.mapviewer.model.map.model.ModelFullIndexed; import lcsb.mapviewer.model.map.modifier.Modulation; import lcsb.mapviewer.model.map.reaction.AbstractNode; import lcsb.mapviewer.model.map.reaction.Modifier; +import lcsb.mapviewer.model.map.reaction.NodeOperator; import lcsb.mapviewer.model.map.reaction.Reaction; +import lcsb.mapviewer.model.map.reaction.type.BooleanLogicGateReaction; import lcsb.mapviewer.model.map.species.Complex; import lcsb.mapviewer.model.map.species.Element; import lcsb.mapviewer.model.map.species.Species; @@ -98,6 +100,7 @@ public class SbmlParser implements IConverter { speciesParser.mergeLayout(model.getSpeciesList(), layout, sbmlModel); reactionParser.mergeLayout(model.getReactions(), layout, sbmlModel); } + reactionParser.validateReactions(model.getReactions()); if (sbmlModel.getConstraintCount() > 0) { @@ -228,7 +231,9 @@ public class SbmlParser implements IConverter { if (node.getLine() == null) { return false; } else if (node.getLine().length() == 0) { - return false; + if (!(node instanceof NodeOperator) || !(reaction instanceof BooleanLogicGateReaction)) { + return false; + } } } return true; diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SBOTermReactionType.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SBOTermReactionType.java index 1461e078d0..dcc34214e6 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SBOTermReactionType.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SBOTermReactionType.java @@ -6,10 +6,15 @@ import java.util.List; import org.apache.log4j.Logger; import lcsb.mapviewer.model.map.reaction.Reaction; +import lcsb.mapviewer.model.map.reaction.type.BooleanLogicGateReaction; +import lcsb.mapviewer.model.map.reaction.type.CatalysisReaction; import lcsb.mapviewer.model.map.reaction.type.DissociationReaction; import lcsb.mapviewer.model.map.reaction.type.HeterodimerAssociationReaction; +import lcsb.mapviewer.model.map.reaction.type.InhibitionReaction; import lcsb.mapviewer.model.map.reaction.type.KnownTransitionOmittedReaction; +import lcsb.mapviewer.model.map.reaction.type.ModulationReaction; import lcsb.mapviewer.model.map.reaction.type.NegativeInfluenceReaction; +import lcsb.mapviewer.model.map.reaction.type.PhysicalStimulationReaction; import lcsb.mapviewer.model.map.reaction.type.PositiveInfluenceReaction; import lcsb.mapviewer.model.map.reaction.type.ReducedModulationReaction; import lcsb.mapviewer.model.map.reaction.type.ReducedPhysicalStimulationReaction; @@ -18,7 +23,10 @@ import lcsb.mapviewer.model.map.reaction.type.StateTransitionReaction; import lcsb.mapviewer.model.map.reaction.type.TranscriptionReaction; import lcsb.mapviewer.model.map.reaction.type.TranslationReaction; import lcsb.mapviewer.model.map.reaction.type.TransportReaction; +import lcsb.mapviewer.model.map.reaction.type.TriggerReaction; import lcsb.mapviewer.model.map.reaction.type.TruncationReaction; +import lcsb.mapviewer.model.map.reaction.type.UnknownCatalysisReaction; +import lcsb.mapviewer.model.map.reaction.type.UnknownInhibitionReaction; import lcsb.mapviewer.model.map.reaction.type.UnknownNegativeInfluenceReaction; import lcsb.mapviewer.model.map.reaction.type.UnknownPositiveInfluenceReaction; import lcsb.mapviewer.model.map.reaction.type.UnknownReducedModulationReaction; @@ -27,24 +35,32 @@ import lcsb.mapviewer.model.map.reaction.type.UnknownReducedTriggerReaction; import lcsb.mapviewer.model.map.reaction.type.UnknownTransitionReaction; public enum SBOTermReactionType { + BOOLEAN_LOGIC_GATE(BooleanLogicGateReaction.class, new String[] { "SBO:0000547" }), + CATALYSIS(CatalysisReaction.class, new String[] { "SBO:0000013" }), DISSOCIATION(DissociationReaction.class, new String[] { "SBO:0000180" }), HETERODIMER_ASSOCIATION(HeterodimerAssociationReaction.class, new String[] { "SBO:0000177" }), + INHIBITION(InhibitionReaction.class, new String[] { "SBO:0000537" }), KNOWN_TRANSITION_OMITTED(KnownTransitionOmittedReaction.class, new String[] { "SBO:0000205" }), + MODULATION(ModulationReaction.class, new String[] { "SBO:0000594" }), NEGATIVE_INFLUENCE(NegativeInfluenceReaction.class, new String[] { "SBO:0000407" }), + PHYSICAL_STIMULATION(PhysicalStimulationReaction.class, new String[] { "SBO:0000459" }), POSITIVE_INFLUENCE(PositiveInfluenceReaction.class, new String[] { "SBO:0000171" }), REDUCED_MODULATION(ReducedModulationReaction.class, new String[] { "SBO:0000632" }), REDUCED_PHYSICAL_STIMULATION(ReducedPhysicalStimulationReaction.class, new String[] { "SBO:0000411" }), - REDUCED_TRIGGER(ReducedTriggerReaction.class, new String[] { "SBO:0000461" }), + REDUCED_TRIGGER(ReducedTriggerReaction.class, new String[] { "SBO:0000533" }), STATE_TRANSITION(StateTransitionReaction.class, new String[] { "SBO:0000176" }), TRANSCRIPTION(TranscriptionReaction.class, new String[] { "SBO:0000183" }), TRANSLATION(TranslationReaction.class, new String[] { "SBO:0000184" }), TRANSPORT(TransportReaction.class, new String[] { "SBO:0000185" }), + TRIGGER(TriggerReaction.class, new String[] { "SBO:0000461" }), TRUNCATION(TruncationReaction.class, new String[] { "SBO:0000178" }), + UNKNOWN_CATALYSIS(UnknownCatalysisReaction.class, new String[] { "SBO:0000462" }), + UNKNOWN_INHIBITION(UnknownInhibitionReaction.class, new String[] { "SBO:0000536" }), UNKNOWN_NEGATIVE_INFLUENCE(UnknownNegativeInfluenceReaction.class, new String[] { "SBO:0000169" }), UNKNOWN_POSITIVE_INFLUENCE(UnknownPositiveInfluenceReaction.class, new String[] { "SBO:0000172" }), UNKNOWN_REDUCED_MODULATION(UnknownReducedModulationReaction.class, new String[] { "SBO:0000631" }), UNKNOWN_REDUCED_PHYSICAL_STIMULATION(UnknownReducedPhysicalStimulationReaction.class, new String[] { "SBO:0000170" }), - UNKNOWN_REDUCED_TRIGGER(UnknownReducedTriggerReaction.class, new String[] { "SBO:0000533" }), + UNKNOWN_REDUCED_TRIGGER(UnknownReducedTriggerReaction.class, new String[] { "SBO:0000534" }), UNKNOWN_TRANSITION(UnknownTransitionReaction.class, new String[] { "SBO:0000396" }), ; diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExporter.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExporter.java index 8143019170..5594f48fab 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExporter.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExporter.java @@ -24,7 +24,9 @@ import org.sbml.jsbml.ext.layout.ReactionGlyph; import org.sbml.jsbml.ext.layout.SpeciesReferenceGlyph; import org.sbml.jsbml.ext.layout.SpeciesReferenceRole; import org.sbml.jsbml.ext.render.ColorDefinition; +import org.sbml.jsbml.ext.render.LocalRenderInformation; import org.sbml.jsbml.ext.render.LocalStyle; +import org.sbml.jsbml.ext.render.RenderGroup; import org.w3c.dom.Node; import lcsb.mapviewer.common.Configuration; @@ -243,15 +245,31 @@ public class SbmlReactionExporter extends SbmlBioEntityExporter<Reaction, org.sb } else { modifierGlyph.setRole(SpeciesReferenceRole.MODIFIER); } + LocalStyle style = createStyleForModifier(modifier); + assignStyleToGlyph(modifierGlyph, style); } - + LocalStyle style = createStyle(reaction); ColorDefinition color = getColorDefinition(reaction.getReactants().get(0).getLine().getColor()); style.getGroup().setStrokeWidth(reaction.getReactants().get(0).getLine().getWidth()); style.getGroup().setFill(color.getId()); + style.getGroup().setStroke(reaction.getReactants().get(0).getLine().getType().name()); + style.getGroup().setEndHead(reaction.getProducts().get(0).getLine().getEndAtd().getArrowType().name()); assignStyleToGlyph(reactionGlyph, style); - + + } + + private LocalStyle createStyleForModifier(Modifier modifier) { + LocalRenderInformation renderInformation = new LocalRenderInformation(); + LocalStyle style = new LocalStyle(); + style.getRoleList() + .add("style_" + modifier.getReaction().getElementId() + "_modifier_" + modifier.getElement().getElementId()); + style.setGroup(new RenderGroup()); + renderInformation.addLocalStyle(style); + getRenderPlugin().addLocalRenderInformation(renderInformation); + style.getGroup().setStroke(modifier.getLine().getType().name()); + return style; } private void addOperatorLineToGlyph(ReactionGlyph reactantGlyph, NodeOperator operator, boolean reverse) { diff --git a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParser.java b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParser.java index 78f4e55e4d..0b001e485d 100644 --- a/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParser.java +++ b/converter-sbml/src/main/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionParser.java @@ -26,6 +26,7 @@ import org.sbml.jsbml.ext.layout.SpeciesReferenceGlyph; import org.sbml.jsbml.ext.render.LocalStyle; import org.sbml.jsbml.ext.render.RenderConstants; import org.sbml.jsbml.ext.render.RenderGraphicalObjectPlugin; +import org.sbml.jsbml.ext.render.RenderGroup; import org.w3c.dom.Node; import lcsb.mapviewer.common.exception.InvalidArgumentException; @@ -39,6 +40,7 @@ import lcsb.mapviewer.converter.model.sbml.SbmlParameterParser; import lcsb.mapviewer.converter.model.sbml.species.SbmlSpeciesParser; import lcsb.mapviewer.model.graphics.ArrowType; import lcsb.mapviewer.model.graphics.ArrowTypeData; +import lcsb.mapviewer.model.graphics.LineType; import lcsb.mapviewer.model.graphics.PolylineData; import lcsb.mapviewer.model.map.kinetics.SbmlArgument; import lcsb.mapviewer.model.map.kinetics.SbmlKinetics; @@ -48,6 +50,7 @@ import lcsb.mapviewer.model.map.modifier.Trigger; import lcsb.mapviewer.model.map.reaction.AbstractNode; import lcsb.mapviewer.model.map.reaction.AndOperator; import lcsb.mapviewer.model.map.reaction.AssociationOperator; +import lcsb.mapviewer.model.map.reaction.DissociationOperator; import lcsb.mapviewer.model.map.reaction.Modifier; import lcsb.mapviewer.model.map.reaction.NodeOperator; import lcsb.mapviewer.model.map.reaction.Product; @@ -55,7 +58,10 @@ import lcsb.mapviewer.model.map.reaction.Reactant; import lcsb.mapviewer.model.map.reaction.Reaction; import lcsb.mapviewer.model.map.reaction.ReactionNode; import lcsb.mapviewer.model.map.reaction.SplitOperator; +import lcsb.mapviewer.model.map.reaction.TruncationOperator; +import lcsb.mapviewer.model.map.reaction.type.DissociationReaction; import lcsb.mapviewer.model.map.reaction.type.HeterodimerAssociationReaction; +import lcsb.mapviewer.model.map.reaction.type.TruncationReaction; import lcsb.mapviewer.model.map.species.Element; import lcsb.mapviewer.model.map.species.Species; import lcsb.mapviewer.modelutils.map.ElementUtils; @@ -107,6 +113,7 @@ public class SbmlReactionParser extends SbmlBioEntityParser { } used.add(source); try { + Map<ReactionNode, SpeciesReferenceGlyph> glyphByNode = new HashMap<>(); Reaction reactionWithLayout = source.copy(); // getId doesn't have to be unique, therefore we concatenate with reaction reactionWithLayout.setIdReaction(glyph.getReaction() + "__" + glyph.getId()); @@ -135,6 +142,7 @@ public class SbmlReactionParser extends SbmlBioEntityParser { throw new InvalidInputDataExecption( "Cannot find reaction node for layouted reaction: " + speciesGlyph.getSpecies() + ", " + glyph.getId()); } + glyphByNode.put(minervaNode, speciesRefernceGlyph); Element minervaElement = minervaModel.getElementByElementId(speciesGlyph.getId()); if (minervaElement == null) { throw new InvalidInputDataExecption("Cannot find layouted reaction node for layouted reaction: " @@ -190,19 +198,18 @@ public class SbmlReactionParser extends SbmlBioEntityParser { reactionWithLayout.addNode(operator); } if (reactionWithLayout.getReactants().size() > 0 && reactionWithLayout.getProducts().size() > 1) { - PolylineData line = new PolylineData(); - Point2D p1 = reactionWithLayout.getReactants().get(0).getLine().getEndPoint(); - Point2D p2 = reactionWithLayout.getProducts().get(0).getLine().getBeginPoint(); - Point2D center = new Point2D.Double((p1.getX() + p2.getX()) / 2, (p1.getY() + p2.getY()) / 2); - line.addPoint(p2); - line.addPoint(center); - NodeOperator operator = new SplitOperator(); - operator.addOutputs(reactionWithLayout.getProducts()); - operator.setLine(line); + NodeOperator operator = createOutputOperator(reactionWithLayout); reactionWithLayout.addNode(operator); } assignRenderDataToReaction(glyph, reactionWithLayout); + for (Modifier modifier : reactionWithLayout.getModifiers()) { + SpeciesReferenceGlyph speciesGlyph = glyphByNode.get(modifier); + if (speciesGlyph != null) { + assignRenderDataToModifier(speciesGlyph, modifier); + } + } + minervaModel.addReaction(reactionWithLayout); } catch (InvalidArgumentException e) { throw new InvalidInputDataExecption(e); @@ -225,6 +232,67 @@ public class SbmlReactionParser extends SbmlBioEntityParser { } } + private void assignRenderDataToModifier(SpeciesReferenceGlyph glyph, ReactionNode modifier) + throws InvalidInputDataExecption { + RenderGraphicalObjectPlugin rgop = (RenderGraphicalObjectPlugin) glyph.getExtension(RenderConstants.shortLabel); + if (rgop != null) { + LocalStyle style = getStyleForRole(rgop.getObjectRole()); + if (style == null) { + throw new InvalidInputDataExecption("Style " + rgop.getObjectRole() + " is not defined"); + } + applyStyleToReactionNode(modifier, style); + } + } + + private void applyStyleToReactionNode(ReactionNode modifier, LocalStyle style) { + RenderGroup group = style.getGroup(); + if (group.isSetFill()) { + Color color = getColorByColorDefinition(group.getFill()); + modifier.getLine().setColor(color); + } + if (group.isSetStrokeWidth()) { + modifier.getLine().setWidth(group.getStrokeWidth()); + } + if (group.isSetStroke()) { + try { + LineType type = LineType.valueOf(group.getStroke()); + modifier.getLine().setType(type); + } catch (Exception e) { + logger.warn(new ElementUtils().getElementTag(modifier.getReaction()) + "Problematic line type: " + + group.getStroke(), e); + } + } + if (group.isSetEndHead()) { + try { + ArrowType type = ArrowType.valueOf(group.getEndHead()); + modifier.getLine().getEndAtd().setArrowType(type); + } catch (Exception e) { + logger.warn(new ElementUtils().getElementTag(modifier.getReaction()) + "Problematic arrow type: " + + group.getStroke(), e); + } + } + } + + private NodeOperator createOutputOperator(Reaction reactionWithLayout) { + PolylineData line = new PolylineData(); + Point2D p1 = reactionWithLayout.getReactants().get(0).getLine().getEndPoint(); + Point2D p2 = reactionWithLayout.getProducts().get(0).getLine().getBeginPoint(); + Point2D center = new Point2D.Double((p1.getX() + p2.getX()) / 2, (p1.getY() + p2.getY()) / 2); + line.addPoint(p2); + line.addPoint(center); + NodeOperator operator; + if (reactionWithLayout instanceof TruncationReaction) { + operator = new TruncationOperator(); + } else if (reactionWithLayout instanceof DissociationReaction) { + operator = new DissociationOperator(); + } else { + operator = new SplitOperator(); + } + operator.addOutputs(reactionWithLayout.getProducts()); + operator.setLine(line); + return operator; + } + private NodeOperator createInputOperator(Reaction reactionWithLayout) { PolylineData line = new PolylineData(); Point2D p1 = reactionWithLayout.getReactants().get(0).getLine().getEndPoint(); @@ -232,7 +300,7 @@ public class SbmlReactionParser extends SbmlBioEntityParser { Point2D center = new Point2D.Double((p1.getX() + p2.getX()) / 2, (p1.getY() + p2.getY()) / 2); line.addPoint(p1); line.addPoint(center); - NodeOperator operator ; + NodeOperator operator; if (reactionWithLayout instanceof HeterodimerAssociationReaction) { operator = new AssociationOperator(); } else { @@ -287,15 +355,38 @@ public class SbmlReactionParser extends SbmlBioEntityParser { } public void applyStyleToReaction(Reaction reactionWithLayout, LocalStyle style) { - if (style.getGroup().getFill() != null) { - Color color = getColorByColorDefinition(style.getGroup().getFill()); + RenderGroup group = style.getGroup(); + if (group.getFill() != null) { + Color color = getColorByColorDefinition(group.getFill()); for (AbstractNode node : reactionWithLayout.getNodes()) { node.getLine().setColor(color); } } - if (style.getGroup().getStrokeWidth() != null) { + if (group.isSetStrokeWidth()) { for (AbstractNode node : reactionWithLayout.getNodes()) { - node.getLine().setWidth(style.getGroup().getStrokeWidth()); + node.getLine().setWidth(group.getStrokeWidth()); + } + } + if (group.isSetStroke()) { + try { + LineType type = LineType.valueOf(group.getStroke()); + for (AbstractNode node : reactionWithLayout.getNodes()) { + node.getLine().setType(type); + } + } catch (Exception e) { + logger.warn(new ElementUtils().getElementTag(reactionWithLayout) + "Problematic line type: " + + group.getStroke(), e); + } + } + if (group.isSetEndHead()) { + try { + ArrowType type = ArrowType.valueOf(group.getEndHead()); + for (Product node : reactionWithLayout.getProducts()) { + node.getLine().getEndAtd().setArrowType(type); + } + } catch (Exception e) { + logger.warn(new ElementUtils().getElementTag(reactionWithLayout) + "Problematic arrow type: " + + group.getStroke(), e); } } } diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlToXmlParserTest.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlToXmlParserTest.java index 10843990e9..f9e8649a5a 100644 --- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlToXmlParserTest.java +++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/GenericSbmlToXmlParserTest.java @@ -22,6 +22,7 @@ import lcsb.mapviewer.converter.ConverterParams; import lcsb.mapviewer.converter.IConverter; import lcsb.mapviewer.model.map.model.Model; import lcsb.mapviewer.model.map.model.ModelComparator; +import lcsb.mapviewer.model.map.reaction.Reaction; @RunWith(Parameterized.class) public class GenericSbmlToXmlParserTest { @@ -65,7 +66,7 @@ public class GenericSbmlToXmlParserTest { + filePath.getFileName().toString().substring(0, filePath.getFileName().toString().indexOf(".xml")); String xmlFilePath = pathWithouExtension.concat(".xml"); converter.exportModelToFile(model, xmlFilePath); - + Model model2 = converter.createModel(new ConverterParams().filename(xmlFilePath).sizeAutoAdjust(false)); model2.setName(null); diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/reaction/AllSbmlReactionParserTests.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/reaction/AllSbmlReactionParserTests.java index d6e54657fa..b6b6039b1f 100644 --- a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/reaction/AllSbmlReactionParserTests.java +++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/reaction/AllSbmlReactionParserTests.java @@ -5,7 +5,8 @@ import org.junit.runners.Suite; import org.junit.runners.Suite.SuiteClasses; @RunWith(Suite.class) -@SuiteClasses({ SbmlReactionExporterTest.class, +@SuiteClasses({ SbmlReactionExportArrowType.class, + SbmlReactionExporterTest.class, SbmlReactionParserTest.class }) public class AllSbmlReactionParserTests { diff --git a/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExportArrowType.java b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExportArrowType.java new file mode 100644 index 0000000000..99be077087 --- /dev/null +++ b/converter-sbml/src/test/java/lcsb/mapviewer/converter/model/sbml/reaction/SbmlReactionExportArrowType.java @@ -0,0 +1,183 @@ +package lcsb.mapviewer.converter.model.sbml.reaction; + +import static org.junit.Assert.assertEquals; + +import java.awt.geom.Point2D; +import java.io.ByteArrayInputStream; +import java.lang.reflect.InvocationTargetException; +import java.util.ArrayList; +import java.util.Collection; + +import org.apache.log4j.Logger; +import org.junit.Test; +import org.junit.runner.RunWith; +import org.junit.runners.Parameterized; +import org.junit.runners.Parameterized.Parameters; + +import lcsb.mapviewer.common.exception.NotImplementedException; +import lcsb.mapviewer.converter.ConverterParams; +import lcsb.mapviewer.converter.InvalidInputDataExecption; +import lcsb.mapviewer.converter.model.celldesigner.CellDesignerXmlParser; +import lcsb.mapviewer.converter.model.celldesigner.reaction.ReactionLineData; +import lcsb.mapviewer.converter.model.sbml.SbmlExporter; +import lcsb.mapviewer.converter.model.sbml.SbmlParser; +import lcsb.mapviewer.model.graphics.PolylineData; +import lcsb.mapviewer.model.map.InconsistentModelException; +import lcsb.mapviewer.model.map.model.Model; +import lcsb.mapviewer.model.map.model.ModelFullIndexed; +import lcsb.mapviewer.model.map.reaction.AndOperator; +import lcsb.mapviewer.model.map.reaction.AssociationOperator; +import lcsb.mapviewer.model.map.reaction.NodeOperator; +import lcsb.mapviewer.model.map.reaction.Product; +import lcsb.mapviewer.model.map.reaction.Reactant; +import lcsb.mapviewer.model.map.reaction.Reaction; +import lcsb.mapviewer.model.map.reaction.ReactionComparator; +import lcsb.mapviewer.model.map.reaction.SplitOperator; +import lcsb.mapviewer.model.map.reaction.TruncationOperator; +import lcsb.mapviewer.model.map.reaction.type.HeterodimerAssociationReaction; +import lcsb.mapviewer.model.map.reaction.type.SimpleReactionInterface; +import lcsb.mapviewer.model.map.reaction.type.TruncationReaction; +import lcsb.mapviewer.model.map.reaction.type.TwoProductReactionInterface; +import lcsb.mapviewer.model.map.reaction.type.TwoReactantReactionInterface; +import lcsb.mapviewer.model.map.species.Ion; +import lcsb.mapviewer.modelutils.map.ElementUtils; + +@RunWith(Parameterized.class) +public class SbmlReactionExportArrowType { + + @SuppressWarnings("unused") + private static Logger logger = Logger.getLogger(SbmlReactionExportArrowType.class); + + SbmlParser parser = new SbmlParser(); + SbmlExporter exporter = new SbmlExporter(); + + @Parameters(name = "{index} : {0}") + public static Collection<Object[]> data() throws Exception { + Collection<Object[]> data = new ArrayList<>(); + ElementUtils eu = new ElementUtils(); + for (Class<?> clazz : eu.getAvailableReactionSubclasses()) { + Model modelAfterSerialization = createModelForReactionType(clazz); + + data.add(new Object[] { clazz.getSimpleName(), modelAfterSerialization }); + } + return data; + } + + private static Model createModelForReactionType(Class<?> clazz) throws InstantiationException, IllegalAccessException, + InvocationTargetException, NoSuchMethodException, InconsistentModelException, InvalidInputDataExecption { + Model model = new ModelFullIndexed(null); + model.setWidth(1000); + model.setHeight(1000); + Ion ion = new Ion("x1"); + ion.setName("ion 1"); + ion.setWidth(100); + ion.setHeight(100); + ion.setX(200); + ion.setY(50); + model.addElement(ion); + + Ion ion2 = new Ion("x2"); + ion2.setName("ion 1"); + ion2.setWidth(100); + ion2.setHeight(100); + ion2.setX(200); + ion2.setY(250); + model.addElement(ion2); + + Ion ion3 = new Ion("x3"); + ion3.setName("ion 1"); + ion3.setWidth(100); + ion3.setHeight(100); + ion3.setX(400); + ion3.setY(450); + model.addElement(ion3); + + Reaction reaction = (Reaction) clazz.getConstructor().newInstance(); + reaction.addReactant(createReactant(ion)); + Product product = createProduct(ion2); + reaction.addProduct(product); + if (SimpleReactionInterface.class.isAssignableFrom(clazz)) { + } else if (TwoReactantReactionInterface.class.isAssignableFrom(clazz)) { + reaction.addReactant(createReactant(ion3)); + NodeOperator operator; + if (HeterodimerAssociationReaction.class.isAssignableFrom(clazz)) { + operator = new AssociationOperator(); + } else { + operator = new AndOperator(); + ReactionLineData lineData = ReactionLineData.TRIGGER; + product.getLine().getEndAtd().setArrowLineType(lineData.getLineType()); + product.getLine().getEndAtd().setArrowType(lineData.getProductArrowType()); + product.getLine().setType(lineData.getLineType()); + } + operator.addInputs(reaction.getReactants()); + operator.setLine(new PolylineData(new Point2D.Double(100, 100), new Point2D.Double(100, 200))); + reaction.addNode(operator); + } else if (TwoProductReactionInterface.class.isAssignableFrom(clazz)) { + reaction.addProduct(createProduct(ion3)); + NodeOperator operator = new SplitOperator(); + if (TruncationReaction.class.isAssignableFrom(clazz)) { + operator = new TruncationOperator(); + } + operator.addOutputs(reaction.getProducts()); + operator.setLine(new PolylineData(new Point2D.Double(10, 10), new Point2D.Double(10, 20))); + reaction.addNode(operator); + } else { + throw new NotImplementedException(); + } + model.addReaction(reaction); + + CellDesignerXmlParser cellDesignerXmlParser = new CellDesignerXmlParser(); + String xmlString = cellDesignerXmlParser.toXml(model); + Model modelAfterSerialization = cellDesignerXmlParser + .createModel(new ConverterParams().inputStream(new ByteArrayInputStream(xmlString.getBytes()))); + return modelAfterSerialization; + } + + private static Reactant createReactant(Ion ion) { + Reactant result = new Reactant(ion); + Point2D point = ion.getCenter(); + point.setLocation(point.getX() + 300, point.getY()); + result.setLine(new PolylineData(ion.getCenter(), point)); + return result; + } + + private static Product createProduct(Ion ion) { + Product result = new Product(ion); + Point2D point = ion.getCenter(); + point.setLocation(point.getX() + 300, point.getY()); + result.setLine(new PolylineData(ion.getCenter(), point)); + return result; + } + + Model modelToBeTested; + + public SbmlReactionExportArrowType(String name, Model model) { + modelToBeTested = model; + } + + @Test + public void test() throws Exception { + try { + Model modelAfterSerialization = getModelAfterSerializing(modelToBeTested); + + ReactionComparator reactionComparator = new ReactionComparator(); + + Reaction originalReaction = modelToBeTested.getReactions().iterator().next(); + Reaction afterSerializationReaction = modelAfterSerialization.getReactions().iterator().next(); + + afterSerializationReaction.setIdReaction(originalReaction.getIdReaction()); + assertEquals(0, reactionComparator.compare(originalReaction, afterSerializationReaction)); + } catch (Exception e) { + e.printStackTrace(); + throw e; + } + } + + private Model getModelAfterSerializing(Model originalModel) throws Exception { + String xml = exporter.toXml(originalModel); + ByteArrayInputStream stream = new ByteArrayInputStream(xml.getBytes("UTF-8")); + Model result = parser.createModel(new ConverterParams().inputStream(stream)); + return result; + } + +} -- GitLab