') + ')', 'gi'); if (regex.test(text)) { found = true; var frag = document.createDocumentFragment(); var parts = text.split(regex); parts.forEach(function(part, i) { if (i % 2 === 0) { frag.appendChild(document.createTextNode(part)); } else { var span = document.createElement('span'); span.className = 'userscript-highlight'; span.textContent = part; frag.appendChild(span); } }); node.parentNode.replaceChild(frag, node); } }); } else if (node.nodeType === 1 && node.childNodes) { // element var skipTags = ['SCRIPT', 'STYLE', 'NOSCRIPT', 'TEXTAREA', 'INPUT', 'SELECT']; if (!skipTags.includes(node.tagName)) { Array.from(node.childNodes).forEach(highlight); } } } highlight(document.body); // Re-highlight on dynamic content var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1 || node.nodeType === 3) highlight(node); }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Highlight Search Terms]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Strip utm_, fbclid, gclid, etc. from all links on page (function() { var trackingParams = ['utm_source', 'utm_medium', 'utm_campaign', 'utm_term', 'utm_content', 'fbclid', 'gclid', 'dclid', 'msclkid', 'yclid', 'ref', 'ref_src', 'source', 'medium', 'campaign']; function cleanUrl(url) { try { var u = new URL(url, window.location.origin); var changed = false; trackingParams.forEach(function(p) { if (u.searchParams.has(p)) { u.searchParams.delete(p); changed = true; } }); return changed ? u.toString() : url; } catch (e) { return url; } } function cleanLinks() { document.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } cleanLinks(); var observer = new MutationObserver(function(mutations) { mutations.forEach(function(m) { m.addedNodes.forEach(function(node) { if (node.nodeType === 1) { if (node.tagName === 'A') cleanLinks(); node.querySelectorAll('a[href]').forEach(function(a) { var clean = cleanUrl(a.href); if (clean !== a.href) a.href = clean; }); } }); }); }); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:Remove Tracking Parameters from Links]', __e); } })(); (function(){ try { var __m = "youtube.com"; var __re = new RegExp('^' + "youtube\\.com" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Auto-enable theater mode on YouTube (function() { function tryTheater() { var btn = document.querySelector('button[aria-label="Theater mode"], ytd-player #player button[title="Theater mode"]'); if (btn && !btn.classList.contains('activated')) { btn.click(); } } // Try immediately tryTheater(); // Try after navigation (SPA) var lastUrl = location.href; setInterval(function() { if (location.href !== lastUrl) { lastUrl = location.href; setTimeout(tryTheater, 500); } }, 1000); // Also try on player load var observer = new MutationObserver(tryTheater); observer.observe(document.body, { childList: true, subtree: true }); })(); } } catch(__e) { console.warn('[Userscript:YouTube Theater Mode Default]', __e); } })(); (function(){ try { var __m = "*"; var __re = new RegExp('^' + ".*" + ', 'i'); if (__m === '*' || __re.test(location.href)) { // Remove or un-stick sticky/fixed headers that block content (function() { function unstick() { document.querySelectorAll('header, nav, [role="banner"], .header, .navbar, .sticky, .fixed-top, [style*="position: fixed"], [style*="position:sticky"]').forEach(function(el) { if (el.style.position === 'fixed' || el.style.position === 'sticky' || getComputedStyle(el).position === 'fixed' || getComputedStyle(el).position === 'sticky') { el.style.position = 'static'; el.style.top = 'auto'; el.style.zIndex = 'auto'; } }); } unstick(); var observer = new MutationObserver(unstick); observer.observe(document.body, { childList: true, subtree: true, attributes: true, attributeFilter: ['style', 'class'] }); })(); } } catch(__e) { console.warn('[Userscript:Kill Sticky Headers]', __e); } })(); })(); BioNetGen.run() returns data arrays that share references and get overwritten · Issue #113 · RuleWorld/PyBioNetGen · GitHub
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

importbionetgenimportnumpyasnp# Simple BNGL model templatebngl_template="""begin modelbegin parameters A {AREA} RasTotal 1000 * Aend parametersbegin molecule types Ras(a~p~0)end molecule typesbegin species Ras(a~0) RasTotalend speciesbegin observables Molecules Ras_act Ras(a~p)end observablesbegin reaction rules RasActivation: Ras(a~0) -> Ras(a~p) 0.01 RasDeactivation: Ras(a~p) -> Ras(a~0) 0.02end reaction rulesend modelsimulate({method=>"ssa", t_end=>1000, n_steps=>1000})"""# Run simulations for different areasAreas= [1, 4, 9]
results= []
forAinAreas:
bngl_content=bngl_template.replace("{AREA}", str(A))
withopen(f"test_A_{A}.bngl", "w") asf:
f.write(bngl_content)
result=bionetgen.run(f"test_A_{A}.bngl")
results.append(result[0]) # Store the data arrayprint(f"Area={A}, Final Ras_act: {result[0]['Ras_act'][-1]}")
# Check stored results - they should be different but they're all the sameprint("\n--- Checking stored results ---")
fori, datainenumerate(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 dataresult=bionetgen.run(f"test_A_{A}.bngl")
data_copy=result[0].copy() # numpy recarray .copy() methodresults.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 firstforAinAreas:
bngl_content=bngl_template.replace("{AREA}", str(A))
withopen(f"test_A_{A}.bngl", "w") asf:
f.write(bngl_content)
bionetgen.run(f"test_A_{A}.bngl")
# Then load results from .gdat filesresults= []
forAinAreas:
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