Skip to content

BioNetGen.run() returns data arrays that share references and get overwritten #113

Description

@jrfaeder

Summary

When calling bionetgen.run() multiple times in a loop and storing the results in a list, all entries in the list end up pointing to the same data from the final simulation. The data appears to be overwritten on each iteration, and even using .copy() on the returned numpy recarray does not create independent copies.

Expected Behavior

Each call to bionetgen.run() should return independent data that is not affected by subsequent calls.

Actual Behavior

All stored results reference the same underlying data, which gets overwritten with each new call to bionetgen.run().

Minimal Reproducible Example

import bionetgen
import numpy as np

# Simple BNGL model template
bngl_template = """
begin model
begin parameters
    A {AREA}
    RasTotal 1000 * A
end parameters

begin molecule types
    Ras(a~p~0)
end molecule types

begin species
    Ras(a~0) RasTotal
end species

begin observables
    Molecules Ras_act Ras(a~p)
end observables

begin reaction rules
    RasActivation: Ras(a~0) -> Ras(a~p) 0.01
    RasDeactivation: Ras(a~p) -> Ras(a~0) 0.02
end reaction rules

end model

simulate({method=>"ssa", t_end=>1000, n_steps=>1000})
"""

# Run simulations for different areas
Areas = [1, 4, 9]
results = []

for A in Areas:
    bngl_content = bngl_template.replace("{AREA}", str(A))
    with open(f"test_A_{A}.bngl", "w") as f:
        f.write(bngl_content)

    result = bionetgen.run(f"test_A_{A}.bngl")
    results.append(result[0])  # Store the data array
    print(f"Area={A}, Final Ras_act: {result[0]['Ras_act'][-1]}")

# Check stored results - they should be different but they're all the same
print("\n--- Checking stored results ---")
for i, data in enumerate(results):
    print(f"Results[{i}] (Area={Areas[i]}): Final Ras_act = {data['Ras_act'][-1]}")

Output:

Area=1, Final Ras_act: 123.0
Area=4, Final Ras_act: 456.0
Area=9, Final Ras_act: 789.0

--- Checking stored results ---
Results[0] (Area=1): Final Ras_act = 789.0  # Should be 123.0!
Results[1] (Area=4): Final Ras_act = 789.0  # Should be 456.0!
Results[2] (Area=9): Final Ras_act = 789.0  # Correct

All results show the same value (from the last simulation), even though they were different when first returned.

Attempted Fix That Didn't Work

# Attempting to copy the data
result = bionetgen.run(f"test_A_{A}.bngl")
data_copy = result[0].copy()  # numpy recarray .copy() method
results.append(data_copy)

This also fails - all copies still reference the same underlying data.

Workaround

The only reliable workaround is to reload the data from the .gdat files after all simulations complete:

# Run all simulations first
for A in Areas:
    bngl_content = bngl_template.replace("{AREA}", str(A))
    with open(f"test_A_{A}.bngl", "w") as f:
        f.write(bngl_content)
    bionetgen.run(f"test_A_{A}.bngl")

# Then load results from .gdat files
results = []
for A in Areas:
    data = np.genfromtxt(f"test_A_{A}.gdat", names=True)
    results.append(data)

Environment

  • PyBioNetGen version: 0.8.6
  • Python version: 3.12.3
  • Operating system: macOS (Darwin 23.6.0)

Impact

This issue makes it impossible to store and compare results from multiple BioNetGen simulations in memory, forcing users to reload data from disk. This is both inefficient and non-intuitive.

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions