From 067da25ff4b411a74d8b5cefbdea1b1cf81b23b2 Mon Sep 17 00:00:00 2001 From: dyrpsf Date: Mon, 11 May 2026 08:36:13 +0530 Subject: [PATCH 1/3] feat: implement named stoichiometry and advanced event options --- .../sbml/jsbml/util/AntimonySerializer.java | 34 +++++++++++++++--- .../jsbml/util/AntimonySerializerTest.java | 36 +++++++++++++++++++ 2 files changed, 66 insertions(+), 4 deletions(-) diff --git a/core/src/org/sbml/jsbml/util/AntimonySerializer.java b/core/src/org/sbml/jsbml/util/AntimonySerializer.java index cde29c93c..53620f765 100644 --- a/core/src/org/sbml/jsbml/util/AntimonySerializer.java +++ b/core/src/org/sbml/jsbml/util/AntimonySerializer.java @@ -166,7 +166,7 @@ public static String toAntimony(Species s) { /** * Converts an individual SBML Reaction into an Antimony string. - * Handles reactants, products, stoichiometry, reversibility, and kinetic laws. + * Handles reactants, products, named stoichiometry, reversibility, and kinetic laws. */ public static String toAntimony(Reaction r) { if (r == null) return ""; @@ -178,7 +178,11 @@ public static String toAntimony(Reaction r) { // 2. Reactants for (int i = 0; i < r.getReactantCount(); i++) { SpeciesReference sr = r.getReactant(i); - if (sr.isSetStoichiometry() && sr.getStoichiometry() != 1.0) { + + // Check for Named Stoichiometry (e.g., 'n S2') + if (sr.isSetId()) { + ant.append(sr.getId()).append(" "); + } else if (sr.isSetStoichiometry() && sr.getStoichiometry() != 1.0) { // Formatting to remove trailing zeros for clean output (e.g. 2.0 -> 2) ant.append(sr.getStoichiometry() == (long) sr.getStoichiometry() ? String.format("%d", (long)sr.getStoichiometry()) : @@ -198,7 +202,10 @@ public static String toAntimony(Reaction r) { // 4. Products for (int i = 0; i < r.getProductCount(); i++) { SpeciesReference sr = r.getProduct(i); - if (sr.isSetStoichiometry() && sr.getStoichiometry() != 1.0) { + + if (sr.isSetId()) { + ant.append(sr.getId()).append(" "); + } else if (sr.isSetStoichiometry() && sr.getStoichiometry() != 1.0) { ant.append(sr.getStoichiometry() == (long) sr.getStoichiometry() ? String.format("%d", (long)sr.getStoichiometry()) : String.format("%s", sr.getStoichiometry())).append(" "); @@ -241,6 +248,7 @@ public static String toAntimony(Rule r) { /** * Converts an SBML Event into an Antimony string. + * Supports advanced options including delays, priorities, t0, and persistence. */ public static String toAntimony(Event e) { if (e == null) return ""; @@ -254,7 +262,25 @@ public static String toAntimony(Event e) { if (e.isSetTrigger() && e.getTrigger().isSetMath()) { ant.append(ASTNode.formulaToString(e.getTrigger().getMath())); } - ant.append("): "); + ant.append(")"); + + // Advanced Event Options + if (e.isSetDelay() && e.getDelay().isSetMath()) { + ant.append(", delay=").append(ASTNode.formulaToString(e.getDelay().getMath())); + } + if (e.isSetPriority() && e.getPriority().isSetMath()) { + ant.append(", priority=").append(ASTNode.formulaToString(e.getPriority().getMath())); + } + if (e.isSetTrigger()) { + org.sbml.jsbml.Trigger t = e.getTrigger(); + if (t.isSetInitialValue() && !t.getInitialValue()) { + ant.append(", t0=false"); + } + if (t.isSetPersistent() && !t.getPersistent()) { + ant.append(", persistent=false"); + } + } + ant.append(": "); int count = e.getEventAssignmentCount(); for (int i = 0; i < count; i++) { diff --git a/core/test/org/sbml/jsbml/util/AntimonySerializerTest.java b/core/test/org/sbml/jsbml/util/AntimonySerializerTest.java index b92cc842b..4732f22ce 100644 --- a/core/test/org/sbml/jsbml/util/AntimonySerializerTest.java +++ b/core/test/org/sbml/jsbml/util/AntimonySerializerTest.java @@ -21,6 +21,8 @@ import org.sbml.jsbml.Event; import org.sbml.jsbml.EventAssignment; import org.sbml.jsbml.Trigger; +import org.sbml.jsbml.Delay; +import org.sbml.jsbml.Priority; /** * Tests for the {@link AntimonySerializer} Phase 1 LLM utility. @@ -252,4 +254,38 @@ public void testEventSerialization() { String result = AntimonySerializer.toAntimony(e); assertEquals("Should serialize Event with multiple assignments", "E1: at (time+delay): S1 = 0, S2 = 5;", result); } + + @Test + public void testNamedStoichiometry() { + Reaction r = model.createReaction("J0"); + r.setReversible(false); + SpeciesReference sr1 = r.createReactant(model.createSpecies("S2")); + sr1.setId("n"); // This is the named stoichiometry + r.createProduct(model.createSpecies("S3")); + + assertEquals("Should serialize named stoichiometry", "J0: n S2 => S3;", AntimonySerializer.toAntimony(r)); + } + + @Test + public void testAdvancedEventOptions() { + Event e = model.createEvent("E2"); + + Trigger t = e.createTrigger(); + t.setMath(new ASTNode("x")); + t.setInitialValue(false); + t.setPersistent(false); + + Delay d = e.createDelay(); + d.setMath(new ASTNode(5)); + + Priority p = e.createPriority(); + p.setMath(new ASTNode(1)); + + EventAssignment ea = e.createEventAssignment(); + ea.setVariable("S1"); + ea.setMath(new ASTNode(0)); + + String expected = "E2: at (x), delay=5, priority=1, t0=false, persistent=false: S1 = 0;"; + assertEquals("Should serialize advanced event options", expected, AntimonySerializer.toAntimony(e)); + } } \ No newline at end of file From 1f55d5810dd16bd92e196bb8f1a956afa108e045 Mon Sep 17 00:00:00 2001 From: dyrpsf Date: Mon, 11 May 2026 09:39:22 +0530 Subject: [PATCH 2/3] fix: correct Antimony syntax for event delays per maintainer review --- .../org/sbml/jsbml/util/AntimonySerializer.java | 15 +++++++++------ .../sbml/jsbml/util/AntimonySerializerTest.java | 4 ++-- 2 files changed, 11 insertions(+), 8 deletions(-) diff --git a/core/src/org/sbml/jsbml/util/AntimonySerializer.java b/core/src/org/sbml/jsbml/util/AntimonySerializer.java index 53620f765..fa9d34560 100644 --- a/core/src/org/sbml/jsbml/util/AntimonySerializer.java +++ b/core/src/org/sbml/jsbml/util/AntimonySerializer.java @@ -258,16 +258,19 @@ public static String toAntimony(Event e) { ant.append(e.getId()).append(": "); } - ant.append("at ("); - if (e.isSetTrigger() && e.getTrigger().isSetMath()) { + ant.append("at "); + boolean hasTrigger = e.isSetTrigger() && e.getTrigger().isSetMath(); + boolean hasDelay = e.isSetDelay() && e.getDelay().isSetMath(); + + if (hasDelay && hasTrigger) { + ant.append(ASTNode.formulaToString(e.getDelay().getMath())); + ant.append(" after "); + ant.append(ASTNode.formulaToString(e.getTrigger().getMath())); + } else if (hasTrigger) { ant.append(ASTNode.formulaToString(e.getTrigger().getMath())); } - ant.append(")"); // Advanced Event Options - if (e.isSetDelay() && e.getDelay().isSetMath()) { - ant.append(", delay=").append(ASTNode.formulaToString(e.getDelay().getMath())); - } if (e.isSetPriority() && e.getPriority().isSetMath()) { ant.append(", priority=").append(ASTNode.formulaToString(e.getPriority().getMath())); } diff --git a/core/test/org/sbml/jsbml/util/AntimonySerializerTest.java b/core/test/org/sbml/jsbml/util/AntimonySerializerTest.java index 4732f22ce..602de3f6d 100644 --- a/core/test/org/sbml/jsbml/util/AntimonySerializerTest.java +++ b/core/test/org/sbml/jsbml/util/AntimonySerializerTest.java @@ -252,7 +252,7 @@ public void testEventSerialization() { ea2.setMath(new ASTNode(5)); String result = AntimonySerializer.toAntimony(e); - assertEquals("Should serialize Event with multiple assignments", "E1: at (time+delay): S1 = 0, S2 = 5;", result); + assertEquals("Should serialize Event with multiple assignments", "E1: at time+delay: S1 = 0, S2 = 5;", result); } @Test @@ -285,7 +285,7 @@ public void testAdvancedEventOptions() { ea.setVariable("S1"); ea.setMath(new ASTNode(0)); - String expected = "E2: at (x), delay=5, priority=1, t0=false, persistent=false: S1 = 0;"; + String expected = "E2: at 5 after x, priority=1, t0=false, persistent=false: S1 = 0;"; assertEquals("Should serialize advanced event options", expected, AntimonySerializer.toAntimony(e)); } } \ No newline at end of file From 5ee374a1d3b0139b22b644ef0df6bd3ec179a73a Mon Sep 17 00:00:00 2001 From: dyrpsf Date: Mon, 11 May 2026 12:29:10 +0530 Subject: [PATCH 3/3] style: update double literals to 1d and add spacing to event output per review --- core/src/org/sbml/jsbml/util/AntimonySerializer.java | 10 +++++----- .../org/sbml/jsbml/util/AntimonySerializerTest.java | 2 +- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/core/src/org/sbml/jsbml/util/AntimonySerializer.java b/core/src/org/sbml/jsbml/util/AntimonySerializer.java index fa9d34560..7748965d6 100644 --- a/core/src/org/sbml/jsbml/util/AntimonySerializer.java +++ b/core/src/org/sbml/jsbml/util/AntimonySerializer.java @@ -182,7 +182,7 @@ public static String toAntimony(Reaction r) { // Check for Named Stoichiometry (e.g., 'n S2') if (sr.isSetId()) { ant.append(sr.getId()).append(" "); - } else if (sr.isSetStoichiometry() && sr.getStoichiometry() != 1.0) { + } else if (sr.isSetStoichiometry() && sr.getStoichiometry() != 1d) { // Formatting to remove trailing zeros for clean output (e.g. 2.0 -> 2) ant.append(sr.getStoichiometry() == (long) sr.getStoichiometry() ? String.format("%d", (long)sr.getStoichiometry()) : @@ -205,7 +205,7 @@ public static String toAntimony(Reaction r) { if (sr.isSetId()) { ant.append(sr.getId()).append(" "); - } else if (sr.isSetStoichiometry() && sr.getStoichiometry() != 1.0) { + } else if (sr.isSetStoichiometry() && sr.getStoichiometry() != 1d) { ant.append(sr.getStoichiometry() == (long) sr.getStoichiometry() ? String.format("%d", (long)sr.getStoichiometry()) : String.format("%s", sr.getStoichiometry())).append(" "); @@ -272,15 +272,15 @@ public static String toAntimony(Event e) { // Advanced Event Options if (e.isSetPriority() && e.getPriority().isSetMath()) { - ant.append(", priority=").append(ASTNode.formulaToString(e.getPriority().getMath())); + ant.append(", priority = ").append(ASTNode.formulaToString(e.getPriority().getMath())); } if (e.isSetTrigger()) { org.sbml.jsbml.Trigger t = e.getTrigger(); if (t.isSetInitialValue() && !t.getInitialValue()) { - ant.append(", t0=false"); + ant.append(", t0 = false"); } if (t.isSetPersistent() && !t.getPersistent()) { - ant.append(", persistent=false"); + ant.append(", persistent = false"); } } ant.append(": "); diff --git a/core/test/org/sbml/jsbml/util/AntimonySerializerTest.java b/core/test/org/sbml/jsbml/util/AntimonySerializerTest.java index 602de3f6d..263d44178 100644 --- a/core/test/org/sbml/jsbml/util/AntimonySerializerTest.java +++ b/core/test/org/sbml/jsbml/util/AntimonySerializerTest.java @@ -285,7 +285,7 @@ public void testAdvancedEventOptions() { ea.setVariable("S1"); ea.setMath(new ASTNode(0)); - String expected = "E2: at 5 after x, priority=1, t0=false, persistent=false: S1 = 0;"; + String expected = "E2: at 5 after x, priority = 1, t0 = false, persistent = false: S1 = 0;"; assertEquals("Should serialize advanced event options", expected, AntimonySerializer.toAntimony(e)); } } \ No newline at end of file