Skip to content

Load SBML in VCell's units: unit_system= and convert_vcml_units - #63

Merged
jcschaff merged 4 commits into
mainfrom
feat/convert-units
Oct 8, 2026
Merged

jcschaff merged 4 commits into
mainfrom
feat/convert-units

Conversation

@jcschaff

@jcschaff jcschaff commented Oct 8, 2026 •

Copy link
Copy Markdown
Member

VCell imports SBML in the SBML's own units; VCell itself writes SBML in dm, µmol, l and s. This PR adds a way to get such models in VCell's units: µm, µM and s, which VCell's spatial and stochastic math assumes. VCell does the conversion, geometry included, through libvcell's new vcml_convert_units (virtualcell/libvcell#26).

New API

  • load_sbml_str(sbml_str, unit_system=None) and load_sbml_file(...): with unit_system="vcell", the imported VCML, which still carries its <ModelUnitSystem>, is converted before pyvcell reads it. The default leaves the numbers as imported, which is today's behaviour.
  • convert_vcml_units(vcml_str, unit_system): the text-level utility, for "vcell" or "sbml".

Why not on the Biomodel. A first version kept <ModelUnitSystem> on pyvcell's Model through VCML read and write, and broke examples/notebooks/sysbio-1-antimony.ipynb.

  • A model from Antimony with no units gets a unit system with a dimensionless length.
  • The notebook then adds a µm geometry to it. That only works because pyvcell drops the unit system and VCell falls back to its defaults.
  • So the Model, reader and writer are unchanged here, and conversion happens on the VCML text instead.

Tests: test_load_sbml_in_vcell_units uses SmallSpatialProject_3D.xml (in dm) and checks:

  • the extent scales by 10⁵ when loaded in VCell units;
  • convert_vcml_units goes back to dm;
  • an unknown unit system is rejected.

It skips with a libvcell that lacks vcml_convert_units, and mypy passes against the released libvcell. Locally, with a libvcell built from #26, tests/vcml/test_utils.py and test_simulations.py pass, and sysbio-1-antimony.ipynb executes.

Context: Phase 6 of viva-pde-particle, reading PDE/particle hybrids from SBML Spatial (virtualcell/vcell#2175). Suggested by @jcschaff: VCell converts units internally anyway, so pyvcell and libvcell should expose it.

🤖 Generated with Claude Code

- pyvcell.vcml.convert_units(bio_model, unit_system="vcell"|"sbml"): the
  Biomodel in VCell's units (um, uM, s) or VCell's SBML units (dm, umol, l,
  s), every quantity converted by VCell (libvcell vcml_convert_units).
  VCell imports SBML in the SBML's own units, so
  convert_units(load_sbml_str(sbml)) gives the model in VCell's units.
- Model.unit_system holds VCML's <ModelUnitSystem> attributes. The reader
  and writer used to drop it, so a model imported from SBML (in dm, umol, l)
  was written back with its numbers read in VCell's default units. Results
  are unchanged for that case (the numbers are self-consistent either way;
  checked bit for bit on the 1D fixture), but generated names now carry the
  model's units (s0_init_umol_l_1 rather than s0_init_uM).

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
jcschaff and others added 2 commits October 7, 2026 21:21
…type-checks

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Keeping <ModelUnitSystem> on the pyvcell Model broke a common pattern:
a model from Antimony/SBML without units gets a unit system with a
dimensionless length, and users then add a um geometry to it
(examples/notebooks/sysbio-1-antimony.ipynb). The Model, reader and
writer are back to main. Instead:

- load_sbml_str/load_sbml_file(..., unit_system=None): "vcell" converts
  the imported VCML (which still carries its units) to VCell's units
  before reading; the default is unchanged.
- convert_vcml_units(vcml_str, unit_system): the text-level utility.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jcschaff jcschaff changed the title convert_units, and keep a model's unit system through VCML read/write Load SBML in VCell's units: unit_system= and convert_vcml_units Oct 8, 2026
Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
@jcschaff
jcschaff merged commit 8413fe5 into main Oct 8, 2026
5 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant