pypi sbmlsim 0.7.0

latest release: 0.7.1
5 hours ago

sbmlsim 0.7.0

Features

  • the SBML Test Suite runs as part of the tests and of every release (#201). sbmlsim.testsuite runs the semantic cases of the SBML Test Suite and says which parts of SBML the simulation supports: SemanticCase reads a case from its NNNNN-settings.txt and the tags of its NNNNN-model.m, SemanticSuite downloads and caches a release, run_case simulates it and compare_case decides whether the results are within the tolerances of the case, |c - u| <= abs_tol + rel_tol · |c|. Of the release 3.5.0, 1578 of 1789 cases pass (88.2%); the 211 which do not are almost all SBML libroadrunner cannot compile, i.e. 125 cases with an algebraic rule, 54 with a delay and 34 with a fast reaction, next to 2 cases with a variable which is not produced and a single case outside the tolerances

  • an interactive report of the run in the documentation, SBML Test Suite. It extends report_base.html like the reports of the experiments and of a fit, so it has the same search, filter chips and sortable tables and loads nothing from the network. The cases are aggregated over their componentTags and their testTags and sorted by pass rate, so the parts of SBML which fail are what the page leads with rather than the tags almost every case carries; the outcome of a case, i.e. pass, tolerance, not_read, simulation_error or missing_variable, is a chip which filters the table of the 1789 cases. The report is generated into the site by the documentation workflow and is not committed, the way llms.txt is

  • the cases are one test each, so a failure names the case and the cases distribute over the workers of pytest-xdist. They carry the testsuite marker and a normal pytest deselects them: they answer what libroadrunner supports, which a change to sbmlsim rarely moves. They run before a release, i.e. the testsuite job of the CI is what the release waits for. The suite is never fully green, so tests/data/testsuite_baseline.json records the outcome of every case which does not pass and a run is compared with it. The baseline fails in both directions: a case which passed and now fails is a regression, and a case which is listed and passes is a baseline which is out of date, so an improvement is not silently absorbed. tests/testsuite skips when the cases were not downloaded, a test run does not reach the network on its own

  • the release attaches the results a submission is made of. scripts/testsuite.py submission writes one CSV per case which could be simulated and a manifest.json with the versions of sbmlsim, libroadrunner and libsbml and the release of the suite, and the release workflow attaches the archive to the GitHub release. A release resolves the newest release of the suite, the tests and the documentation run against the pinned SUITE_VERSION so that a build is reproducible, and .github/workflows/testsuite-pin.yml opens the pull request which adopts a newer release with its baseline recorded again, so the diff of the baseline is what the new release changes

  • sbmlsim.comparison.diff.within_tolerance is the tolerance criterion of the SBML Test Suite as one function, which DataSetsComparison and the comparison of a case share

  • a report without the figures of every fit mapping. The two figures of a mapping, the data with the simulation and the residuals, are almost the whole cost of a report: for the 35 mappings of the HCTZ problem they are 70 of the 76 figures and 88% of the 21 s it takes. FitReport(mapping_figures=False) and --no-mapping-figures on fit_cli, report_cli and identifiability_cli leave them out and the cards of the mappings carry their metrics alone, which takes the same report to 2.5 s. The tests create their reports this way, and with the SBML Test Suite deselected the tests went from 140 s to 56 s

  • a parameter can be estimated separately for parts of the data, in one optimization. FitParameter(target=..., mappings=...) writes its value to a target entity of the model (pid by default) for the fit mappings a selector, or a filter combination of them, passes; several parameters share one target when each covers a different subset, e.g. Ka_dis_hctz_po, added to examples/hctz_fitting/fitting/parameters.py (PARAMETERS_BY_ROUTE), writes Ka_dis_hctz for the oral data only. The intravenous data is left unversioned on purpose: a dissolution rate has no effect on it, so a second version there would be a parameter no curve constrains, and problem.parameter_mapping.coverage() reports it as uncovered rather than as an estimated value. sbmlsim.fit.parameter_mapping.ParameterMapping resolves the selectors to the simulations of the initialized problem and validates the binding: it raises when a selector splits one simulation, i.e. selects some but not all of the fit mappings which share it, when two parameters write one target in one simulation, or when the versions of a target disagree on their unit, and it warns when a selector matches nothing. The console and the HTML report gain a target column once a parameter writes an entity of another name (sbmlsim.fit.parameter_mapping.has_renamed_targets, the one place that question is answered), and a coverage table naming, per parameter, the simulations it does not reach, which keep the value of the model rather than being an error. The PEtab v2 export writes a version as a condition which assigns the target the value of the estimated parameter, on period 0 of every experiment it covers, and refuses a parameter which has a selector but no target of its own, since PEtab has no id to write such a condition with and would otherwise estimate the entity everywhere instead of only where the selector matches; the reader turns a condition it can write back into a versioned FitParameter selected by the explicit mapping ids of sbmlsim.fit.helpers.filter_keys. The selector itself does not round trip, so the resolution is what PEtab stores and the fit, its cost and its parameters come back the same, i.e. exact in effect and not in source form. An experiment whose fit mappings span several MappingKinds is written as one PEtab experiment per kind, so a problem read back can report a higher coverage count than the fit which was written even though the binding and the simulations are unchanged, the experiment-split gap of sbmlsim.fit.petab_v2.gaps

  • interactive figures (sbmlsim.plot.serialization_plotly). plot/plotting.py describes a figure without saying how it is drawn and the matplotlib serializer is one way of drawing it; PlotlyFigureSerializer is a second one, and the reader can zoom, pan, hover and switch curves off. On the figures of the HCTZ experiments it is 5 times faster, 23 ms against 117 ms per figure, because a plotly figure carries its data and the browser draws it: writing the page is 3 ms of those 23, the rest is resolving the data and converting its units, which both backends do. The javascript is written once next to the pages, so a report still loads nothing from the network. The format chooses the backend: figure_formats=["svg", "png"] are the static images matplotlib draws, figure_formats=["html"] the interactive pages plotly draws, and a run asks for both at once. A run which asks only for html never builds a matplotlib figure, which is why the whole pipeline of two HCTZ experiments takes 0.38 s instead of 0.77 s. The static images stay with matplotlib: plotly writes PNG and SVG through a headless browser, 1150 ms per figure and 301 ms batched against 117 ms, and it needs a Chrome on the machine. plotly is in the dev extra and not a dependency, a run which asks for html without it says so and writes no page; a figure of figures_mpl() is a matplotlib figure already and has no interactive version. The experiment report links the page next to the image and embeds it when there is no image

Fixes

  • a fit mapping is simulated even when data() does not name it. The reduced selections, which is what a run of a SimulationExperiment simulates, were collected from data() alone; a FitData builds its Data when it is resolved and does not register it, so an observable which was not also declared as data was missing from the results and the experiment raised KeyError: No variable named '[Y]'. The selections cover the fit mappings now, and reduced_selections=True is the default, so this hit the normal path

  • the models of the experiments are loaded once. ExperimentRunner cached the loaded model under the AbstractModel an experiment returns, which has no equality of its own, so the cache never found anything and every experiment loaded and compiled the model again. The key is the description of the model now, i.e. its source, its language and its changes, and the three HCTZ experiments load their model once instead of three times

  • a Data function which evaluates to a plain number no longer raises. A formula of parameters alone evaluates to a number rather than a quantity and 'int' object has no attribute 'units' came out of it; the value is dimensionless. examples/repressilator runs again because of it, and its test is no longer skipped, as is the test of examples/glucose, which was skipped although it passed

  • a run which neither shows nor saves its figures does not draw them any more; it drew every figure and closed it again

  • a timecourse of a model with a species or a parameter named reset no longer breaks every simulation which follows it in the same process. libroadrunner exposes the symbols of a model as attributes of the instance, so such a model hides the reset method, resetToOrigin calls it and raises, and the symbol stays hidden for every instance created afterwards. Case 00952 of the test suite is such a model and it took the 837 cases after it down with it

Documentation

  • SBML Test Suite describes what is run and what is not, the tolerances, the baseline and the submission, and links the report of the current run

Don't miss a new sbmlsim release

NewReleases is sending notifications on new releases.