Add support for fixed species (clamped populations)#60
Merged
jrfaeder merged 1 commit intoRuleWorld:masterfrom Apr 6, 2026
Merged
Add support for fixed species (clamped populations)#60jrfaeder merged 1 commit intoRuleWorld:masterfrom
jrfaeder merged 1 commit intoRuleWorld:masterfrom
Conversation
* feat: add support for fixed (clamped) species This change introduces tracking and replenishment for BioNetGen "Fixed" species (where `Fixed="1"`). - `MoleculeType` now tracks `isFixed_`, `fixedCount_`, and `fixedCompartment_`. - `NFinput`'s XML parser sets these attributes when reading a `<Species>` element with `Fixed="1"`. A warning is logged for unsupported multi-molecule fixed species. - `System::replenishFixedSpecies()` creates or deletes molecules of a fixed `MoleculeType` to maintain the clamped total. It handles compartment-specific assignment for the replenished molecules. - The replenishment fixup runs immediately post-fire in `System::sim()`, `System::stepTo()`, and `System::singleStep()`. Tests (`v42.bngl` and `v43.bngl`) verified fixed count clamping during synthesis, degradation, and binding. Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com> * Finalize fixed species implementation: robust single-molecule replenishment, multi-molecule error, and validation tests v42-v44. Fixes BNG root artifact clutter and validate.py BNG invocation. * Remove subset validation scratch file. * fix(refactor): simplify NFinput parsing for fixed species and clean up .gitignore scope. Fix test Suite trailing newlines. * feat: add support for fixed (clamped) species This change introduces tracking and replenishment for BioNetGen "Fixed" species (where `Fixed="1"`). - `MoleculeType` now tracks `isFixed_`, `fixedCount_`, and `fixedCompartment_`. - `NFinput`'s XML parser sets these attributes when reading a `<Species>` element with `Fixed="1"`. A warning is logged for unsupported multi-molecule fixed species. - `System::replenishFixedSpecies()` creates or deletes molecules of a fixed `MoleculeType` to maintain the clamped total. It handles compartment-specific assignment for the replenished molecules. - The replenishment fixup runs immediately post-fire in `System::sim()`, `System::stepTo()`, and `System::singleStep()`. Tests (`v42.bngl` and `v43.bngl`) verified fixed count clamping during synthesis, degradation, and binding. Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com> * fix: correct fixed species counting, replenishment, and testing - Corrected `System::replenishFixedSpecies` to only count free molecules (`m->getDegree() == 0`) and safely remove explicitly free molecules, avoiding corruption of existing complexes. - Restored delegation to `mt->addMoleculeToRunningSystem` for molecule initialization to prevent missed lifecycle steps. - Restored `recompute_A_tot()` at the end of `replenishFixedSpecies` to prevent stale propensities in the Gillespie algorithm. - Reverted multi-molecule fixed species check in `NFinput` to correctly error and halt (`return ""`) rather than silently skipping. - Restored and integrated `v42` and `v43` BNGL tests into the validation suite alongside proper tracking configuration. - Cleaned up incorrectly committed artifact files (`.gdat`, `.net`, `.xml`, `.species`) and `__pycache__` directories from the PR branch. Co-authored-by: akutuva21 <44119804+akutuva21@users.noreply.github.com> --------- Co-authored-by: google-labs-jules[bot] <161369871+google-labs-jules[bot]@users.noreply.github.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Pull Request Report: Fixed Species (Clamped Populations) Support
PR #25: feat: Add support for fixed species (clamped populations)
Author: @akutuva21 (Achyudhan Kutuva)
Status: Open
Base Branch: master
Changes: +244 additions, -5 deletions across 11 files
Executive Summary
This PR implements support for BioNetGen's "fixed" (clamped) species in NFsim, allowing species populations to remain constant despite reactions that would normally create or destroy them. This feature is critical for modeling biological systems with synthesis/degradation bottlenecks, enzyme clamping, and buffered species without requiring explicit compensatory reaction rules.
Motivation
Problem Statement
Standard BioNetGen supports fixed species using the
Fixed="1"attribute or$Speciesnotation, which maintains a constant population count regardless of reactions. NFsim previously lacked this capability, forcing users to either:Biological Use Cases
Technical Implementation
1. Core Data Structure Changes
MoleculeType Extension (src/NFcore/NFcore.hh:878-888)
Design rationale: Fixed status is tracked at the
MoleculeTypelevel since clamping applies to all molecules of a given type, not individual instances.2. Replenishment Algorithm
System::replenishFixedSpecies() (src/NFcore/system.cpp)
Algorithm:
Key implementation details:
getDegree() == 0): Prevents corruption of existing complexesaddMoleculeToRunningSystem()to ensure all initialization steps occurrecompute_A_tot()after replenishment to maintain Gillespie algorithm correctnessIntegration points:
System::sim()- Main simulation loopSystem::stepTo()- Step-to-time simulationSystem::singleStep()- Single-step simulationReplenishment occurs immediately after
ReactionClass::fire()in all simulation modes.3. XML Parsing Integration
NFinput::initStartSpecies() (src/NFinput/NFinput.cpp:793-802, 1140-1164)
Parsing logic:
Error handling: Multi-molecule (complex) fixed species trigger a hard error and halt simulation setup, preventing silent failures.
Verbose output: When verbose logging is enabled, fixed species are clearly marked:
Test Coverage
Test 1: Binding/Unbinding with Fixed Species (test/testSuite/v42.bngl)
Scenario:
$A(b) 10)A(b) + B(a) <-> A(b!1).B(a!1)B(a) -> 00 -> B(a)Expected behavior:
Atot) remains exactly 10 throughout simulationAfree) fluctuates as complexes form/dissociateTests:
Test 2: Degradation-Only with Fixed Species (test/testSuite/v43.bngl)
Scenario:
$A() 5)A() -> 0(should be compensated)0 -> B()(normal growth)Expected behavior:
Atot) remains exactly 5 despite degradation reactionsBtot) grows linearly according to synthesis rateTests:
Validation Framework Integration
Both tests integrated into
validate/basicModels/with reference outputs:Known Limitations
1. Multi-Molecule Fixed Species Not Supported (v1)
Issue: Cannot fix complexes like
A(b!1).B(a!1)Workaround: Only fix single-molecule species
Future work: Extend tracking to complex patterns
Example not supported:
2. State-Specific Clamping Not Addressed
Issue: Clamping occurs on total
MoleculeTypecount, not state-specific countsImpact: If A binds to form complexes, total A molecules stay constant, but free A drops
Example:
Future work: Add state-pattern-based clamping (e.g., fix only
A(b)notA(b!+))3. Compartment Clamping is All-or-Nothing
Issue: Cannot clamp different counts in different compartments for the same species
Current behavior: Compartment is optional, applies to entire
MoleculeTypeif setCode Quality & Architecture
Strengths
✅ Minimal invasiveness: Changes isolated to 5 core files
✅ Proper lifecycle integration: Uses existing
addMoleculeToRunningSystem()infrastructure✅ Performance-conscious: Only iterates fixed molecule types (typically very few)
✅ Compartment-aware: Designed for future multi-compartment support
✅ Clear error messages: Multi-molecule fixed species fail loudly with explanation
Design Decisions
Backwards Compatibility
✅ Fully backwards compatible: No breaking changes to existing models
Performance Impact
Expected Overhead
Negligible for typical simulations:
Profiling Recommendation
For models with:
Consider profiling to measure actual impact.
Integration & Deployment
Merge Readiness
✅ All identified issues resolved:
__pycache__directories.gitignoreto prevent future artifact commitsFiles Changed
Documentation Needs
Future Enhancements
Priority 1 (High Value)
Priority 2 (Medium Value)
Priority 3 (Nice to Have)
Testing Recommendations Before Merge
Functional Tests
Edge Cases
Integration Tests
Conclusion
This PR delivers a highly requested feature that brings NFsim's capabilities closer to standard BioNetGen. The implementation is:
Recommendation
✅ APPROVE FOR MERGE with post-merge documentation updates
The v1 implementation correctly handles the most common use case (single-molecule fixed species) while clearly documenting limitations. Multi-molecule support can be added in a future enhancement without breaking changes.
Report Generated: 2026-04-06
PR URL: akutuva21#25
Review Status: Ready for maintainer review