Rate kernel returns a propensity of 0.0 for an unresolvable rate parameter, silently killing the reaction (extends #580 to src/model.cpp)
Nobody has claimed this yet.
Assessment
- Difficulty
- 2/5
- Estimated time
- 1-3 hours
- Newbie friendliness
- 84/100
Research direction
Start in src/model.cpp at the Elementary/Functional and Michaelis-Menten/sQSSA guards in compute_reaction_rate(), then review the existing exception-translation boundary and ModelBuilder usage. Construct malformed rate-parameter state through ModelBuilder and verify that each invalid index raises an exception carrying the reaction and parameter indexes instead of returning zero.
Written by the indexing model from the issue text.
Description
Summary
compute_reaction_rate() in src/model.cpp — the innermost propensity kernel, called for every reaction at every step of every ODE and SSA run — responds to an unresolvable rate parameter by returning a rate of 0.0.
src/model.cpp:2876-2877, the Elementary/Functional path:
int k_idx = rxn.rate_param_idx0; // pre-computed 0-based index
if (k_idx < 0 || k_idx >= static_cast<int>(params.size()))
return 0.0;
src/model.cpp:2936-2941, the Michaelis-Menten / sQSSA path:
if (rxn.rate_law_param_indices.size() < 2)
return 0.0;
int kcat_idx = rxn.rate_law_param_indices[0] - 1;
int km_idx = rxn.rate_law_param_indices[1] - 1;
if (kcat_idx < 0 || km_idx < 0)
return 0.0;
A propensity of zero is not an error signal — it is a perfectly ordinary value meaning "this reaction does not fire right now". So if either guard ever fires, the model integrates with that reaction permanently dead, the run completes, the trajectory is well-formed, and nothing anywhere reports it.
Severity and honest scoping
These are guard clauses on paths that well-formed input should not reach — a reaction whose rate-parameter index is out of range indicates the model was built wrong upstream, not a user error. I have not demonstrated a reachable input that triggers either one, and they may well be unreachable today.
That is exactly why this is filed as an improvement rather than as a bug, and why it is low priority relative to the reachable defects in #553–#578. The argument for fixing it anyway is cheapness and blast radius: if one of these ever does become reachable — through a loader change, a new rate-law type, or a refactor of index assignment — the symptom is a silently wrong trajectory in the hottest path in the simulator, and there is no diagnostic trail back to the cause.
Proposed work
Turn each guard into a throw carrying the reaction index and the offending parameter index. An exception here is safe: the call sites are already inside the C++ exception-translation boundary, and a model that reaches one of these states cannot produce a meaningful trajectory anyway.
Roughly an hour, including tests that construct the malformed state through ModelBuilder and assert the throw.
Related
#580 — same policy, different sites (_net_reader.py:227, net_file_loader.cpp:237, ssa_simulator.cpp:1523). This issue extends that rule to the rate kernel. _exceptions.py:68's documented refuse-don't-default contract is the stated policy these sites contradict.
- Dominant language
- Python
- Stars
- 2
- Forks
- 3
- Avg merge
- 6h 57m
- Merged PRs (30d)
- 75
Contributor guide
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- Open a pull request that references the issue number.
More from lanl/bngsim
-
documentation
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
-
bug
Difficulty 2/5 1-3 hours Newbie friendliness 90/100
-
enhancement
Difficulty 1/5 Under an hour Newbie friendliness 92/100
-
documentation enhancement
Difficulty 1/5 Under an hour Newbie friendliness 88/100
Similar issues
-
Difficulty 2/5 1-3 hours Newbie friendliness 88/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 82/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 78/100
-
enhancement
Difficulty 2/5 1-3 hours Newbie friendliness 72/100
-
Difficulty 2/5 1-3 hours Newbie friendliness 74/100