Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
41 changes: 35 additions & 6 deletions core/src/org/sbml/jsbml/util/AntimonySerializer.java
Original file line number Diff line number Diff line change
Expand Up @@ -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 "";
Expand All @@ -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()) :
Expand All @@ -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(" ");
Expand Down Expand Up @@ -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 "";
Expand All @@ -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 ");
Comment thread
dyrpsf marked this conversation as resolved.
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++) {
Expand Down
38 changes: 37 additions & 1 deletion core/test/org/sbml/jsbml/util/AntimonySerializerTest.java
Original file line number Diff line number Diff line change
Expand Up @@ -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.
Expand Down Expand Up @@ -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));
}
}