diff --git a/core/src/org/sbml/jsbml/util/AntimonySerializer.java b/core/src/org/sbml/jsbml/util/AntimonySerializer.java index cde29c93c..7748965d6 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() != 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()) : @@ -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() != 1d) { 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 ""; @@ -250,11 +258,32 @@ 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.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..263d44178 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. @@ -250,6 +252,40 @@ 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 + 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 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