Add support for BNGL models#501
Open
wshlavacek wants to merge 7 commits into
Open
Conversation
Add a BnglModel loader (a peer of PySBModel/SbmlModel) so that a `language: bngl` PEtab problem loads and validates via petablint / Problem.from_yaml at the model level. See PEtab-dev/PEtab#436. - petab/v1/models/bngl_model.py: BnglModel backed by a small, dependency-free BNGL block reader (parse_bngl). Introspection only; is_valid shells out to `BNG2.pl --check` when a BNG backend is locatable and falls back to True otherwise (mirroring how the SBML loader always validates because libsbml is always present). - Register `bngl` in known_model_types and add a branch to model_factory; v2 picks it up via the existing re-exports (+ a v2 shim module). - tests/v1/test_model_bngl.py and a minimal BNGL fixture: ABC unit tests plus a full Problem.from_yaml validation oracle covering the model-cross checks.
Re-sync with PyBNF's sibling reader (pybnf/petab/_bngl.py, ADR-0026 / lanl/PyBNF#437): - Block aliases: `begin molecules` / `begin species` / `begin rules` now open the same blocks as `molecule types` / `seed species` / `reaction rules` (_block_lines consults a per-canonical-name alias table), per the BNGL grammar reference (BioNetGen Perl2/; BNG_vscode_extension docs/bngl-grammar.md). - Seed-species `$` clamp: `SeedSpeciesDefn = ["$"], Species, ...` -- the `$` fixed-concentration marker is stripped so `$counter() 10` enumerates the state variable `counter()`, keeping is_state_variable correct under the clamp. Adds grammar-hardening tests (alias parsing, `$`-clamp stripping, no cross-block shadowing, the is_state_variable seam) that double as the drift anchor against PyBNF's reader. ruff check + format clean; 19 passed. Refs: PEtab-dev/PEtab#436.
A trailing `\` (BNGL line continuation) splits one logical declaration across physical lines. The block scanner processed physical lines, so a continued parameter/function/observable was truncated at the `\` (e.g. `k = \` read as the value `\`). Add _logical_lines() mirroring BNG2.pl's readFile (Perl2/BNGModel.pm): strip the comment first, then while a line ends with `\` drop it and concatenate the next comment-stripped physical line directly (no space, so `1e\`+`3` -> `1e3`). Surfaced by the bng_parity corpus (895 community BNGL models): 252 use line continuation, incl. inside enumerated blocks (functions, observables, parameters, seed species). Adds continuation + backslash-in-comment tests; kept in sync with PyBNF's sibling reader (pybnf/petab/_bngl.py). ruff clean, 21 passed. Refs: PEtab-dev/PEtab#436.
BNGL declarations may carry a leading line label (LineLabel = {Digit}, WS |
Name, ":", [WS]): a legacy .net-style numeric index (`1 L0 1`) or a named label
(`CD14: CD14(...)`). The reader took the label as the entity -- the index as a
parameter name, the label as the seed species. Add _strip_line_label() and apply
it in the parameter and seed-species extractors (a valid BNGL identifier starts
with a letter, so a leading digit-run is unambiguously an index; a compartment
prefix carries `@`, so a bare `Name:` is unambiguously a label).
Surfaced by a writeModel-based differential over the bng_parity corpus (895
community models): 4 models disagreed with BNG2.pl's canonical parse (indexed
params/seed, labeled seed); after this fix, 0 -- parameters/observables/
functions/molecule-types/compartments all match BNG2.pl across the corpus.
Kept in sync with PyBNF's sibling reader. ruff clean, 24 passed.
Refs: PEtab-dev/PEtab#436.
Asserts parse_bngl enumerates the same model entities BNG2.pl does, over 21 curated public community BNGL models (RuleHub, BNGL-Models) under tests/v1/bngl_corpus/. BNG2.pl's answers are cached in golden.json -- the entity name sets it emits from `writeModel` (its canonical parse, no network generation) -- so the test needs NO BNG2.pl and runs anywhere; it compares the reader against the frozen oracle. Seed species are compared by molecule composition to absorb BNG2.pl's pattern canonicalization (t vs t(), component reordering, @compartment prefix vs suffix). The models exercise every hardened reader path: line continuations, indexed and labeled declarations, block aliases, the $ clamp, compartmental BNGL, energy patterns, states/bonds, component reordering, bare-molecule seed species. The golden is regenerated deliberately (needs BNG2.pl) via `python tests/v1/test_bngl_corpus.py` and reviewed as a diff. Mirrors PyBNF's live-BNG2.pl gate (lanl/PyBNF); validated there over the full 895-model bng_parity corpus (894/894 BNG2.pl-accepted models agree). ruff clean; 21 passed without BNG2.pl. Refs: PEtab-dev/PEtab#436.
…ies`)
The grammar doc lists `molecules` (for `molecule types`) and `rules` (for
`reaction rules`) as block aliases, but BNG2.pl 2.9.3 -- the reference this
reader targets -- REJECTS both ("Could not process block type 'molecules' /
'rules'"). Honoring them let the reader enumerate entities from a block BNG2.pl
refuses, i.e. accept models the reference rejects. Restrict _BLOCK_ALIASES to
`species` (for `seed species`), which BNG2.pl accepts and in fact emits as its
own canonical seed-species spelling. Verified empirically against BNG2.pl 2.9.3.
The corpus gate is unchanged (no fixture uses the dropped aliases; golden
regenerates identically). ruff clean; 24 passed. Refs: PEtab-dev/PEtab#436.
353c172 to
6276d1d
Compare
Codecov Report❌ Patch coverage is Additional details and impacted files@@ Coverage Diff @@
## main #501 +/- ##
==========================================
+ Coverage 75.12% 75.40% +0.28%
==========================================
Files 64 66 +2
Lines 7157 7324 +167
Branches 1265 1283 +18
==========================================
+ Hits 5377 5523 +146
- Misses 1290 1307 +17
- Partials 490 494 +4 ☔ View full report in Codecov by Harness. 🚀 New features to boost your workflow:
|
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.
Adds BNGL as a PEtab model language next to SBML and PySB, so a problem
declaring
language: bnglloads and validates instead of stopping atmodel-load in
petablint.BnglModelreads BNGL with a pure-Python parser that pulls the entitiesvalidation cares about (parameters, species, observables, functions) straight
from the model text. So loading and validating a BNGL problem needs no external
tools and adds no runtime dependency.
is_valid()will additionally runBNG2.pl --checkif that executable is on thePATH, for a stricter check, andreturns
Trueif it isn't — so BNG2.pl is used when available but neverrequired. Both v1 and v2 are covered.
PyBNF has been dogfooding this reader for a while — it uses it to fit rule-based
models against PEtab problems, and its PEtab tutorials exercise the loader end
to end: https://github.com/lanl/PyBNF/tree/main/examples/tutorial
Addresses PEtab-dev/PEtab#436.