Skip to content

PEtab v2 exporter: conditions/experiments chunk (mutants→conditions, suffix→experiments, dose-response) #422

@wshlavacek

Description

@wshlavacek

Part of #407 (PEtab v2 two-adapter umbrella; exporter-first pivot, ADR-0025).
Builds on #420 (the BnglModel adapter — now dogfooded: pybnf[tests] pins the Step B
libpetab-python fork branch, so Problem.from_yaml validates language: bngl problems at
MODEL level natively, all 18 default_validation_tasks, in-process and in CI).

Goal

The next exporter chunk after chunk 1 (single BNGL model, one time-course .exp): export a
PyBNF job with multiple experimental conditions to PEtab v2 conditions.tsv +
experiments.tsv, and lift the dose-response boundary. Chunk 1 emits everything with an
empty experimentId ("model as is"); this chunk gives experiments and conditions real
structure.

This is also where the BnglModel methods #420/ADR-0026 left only trivially exercised finally
get real requirements: get_valid_ids_for_condition_table (= params ∪ compartments) and
is_state_variable (= seed species), via CheckValidConditionTargets,
CheckValidParameterInConditionOrParameterTable, and CheckInitialChangeSymbols.

The mapping (recon; verify against the cited file:line)

  • PyBNF mutant → PEtab condition. Grammar parse.py:142: mutant = <base> <name> <var op val>... : f1.exp, ..., op ∈ {= * / + -}. config.py:613 _load_mutantsMutation(var, op, val) (pset.py:1351) + MutationSet (pset.py:1401), attached via model.add_mutant (pset.py:415). Each mutation → one conditions.tsv row (conditionId, targetId=var, targetValue). = is an absolute set; * / + - are relative to the base value.
  • PyBNF suffix → PEtab experiment. model.suffixes = (sim_type, prefix) tuples (pset.py:446, get_suffixes pset.py:408/846); each suffix is one simulation output = one timecourse. The base time_course suffix → the base experiment; a mutant's .exp is named <base_suffix><mutant_name>.exp (config.py:628-635), so experimentId derives from suffix+mutant and the experiment references that mutant's condition.
  • Dose-response → conditions + measurements. PyBNF param_scan (ParamScan, pset.py:1280: param/min/max/step/time/logspace/suffix); the .exp independent axis is the swept param (not time). Each scan point → a condition setting param=value; measurements at the scan's fixed time. Currently rejected at measurements.py:69.
  • Boundaries to lift: export.py ~99-136 / 207; measurements.py:69.

Key design decisions to settle (design-first / ADR before code)

  1. Mutating a parameter that is also a free/fit parameter (the crux). PyBNF mutants routinely modify fit params (e.g. examples/yeast_cell_cycle/yeast.conf), but PEtab's CheckValidParameterInConditionOrParameterTable errors if an id is in both the parameter table and a condition target. Decide the PEtab-idiomatic mapping (condition-specific override via the mapping table? per-condition placeholder parameters? restrict the chunk to non-fit-param mutations and defer the rest?). Gates the whole chunk.
  2. Relative operators * / + -: PEtab targetValue is an expression; decide how to express a scaling/offset of the base value (expression referencing the base nominal vs precomputed absolute vs defer non-=).
  3. Scope: mutants and dose-response both this chunk, or mutants first + dose-response as an immediate follow-on (they share the conditions/experiments machinery; dose-response adds the swept-axis pivot).
  4. Fixture/oracle: a synthetic minimal multi-condition conf (extend examples/demo) is the recommended gradeable fixture — the real mutant example (yeast) uses .prop/.con constraint files, not quantitative .exp data.

Acceptance

  • export_job on a multi-condition fixture writes conditions.tsv + experiments.tsv and lifts the relevant NotImplementedErrors.
  • The exported problem loads via Problem.from_yaml (native BnglModel) and passes all 18 default_validation_tasks with zero errors — genuinely exercising the condition/experiment cross-checks above.
  • Strong table oracle: condition/experiment cells map exactly to the PyBNF mutations/suffixes; the measurement pivot stays exact.
  • Remaining deferred boundaries still raise NotImplementedError (no silent mis-export).
  • ruff clean; petab test tier green; mirrors tests/test_petab_export.py.

Refs: ADR-0025 (exporter-first), ADR-0026 (BnglModel; the methods this chunk exercises for real), #407 (umbrella), #420 (adapter/dogfooding).

Metadata

Metadata

Assignees

No one assigned

    Labels

    No labels
    No labels

    Type

    No type
    No fields configured for issues without a type.

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions