Release notes for sbmlsim 0.13.0
A release of the speed of the simulation experiments, found with the sampling profiler of python 3.15. The experiments of a run run in a pool of worker processes, a figure is saved without drawing it twice, a formula is parsed without importing petab, and the PK analysis of the steps of the integrator analyses the points of a chunk together. run_simulation pkdb_models.models.hctz --action simulate --experiments all (28 experiments, 128 figures) takes 16 s instead of 28 s of 0.12.1 on the same busy machine, 12 s instead of 21 s on an idle one. The simulations and the fits are unchanged. The figures are unchanged except their box, which is at most 1.4 pt wider. The PK parameters of a ragged scan differ from 0.12.1 by at most a few units in the last place.
Features
- The experiments of a run run in a pool of worker processes (#387).
- What the pool is.
ExperimentRunner.run_experiments(n_workers=None)andrun_experimentsrun the experiments in a pool, since the experiments of a run are independent. - How many workers.
- By default there is a worker per
EXPERIMENTS_PER_WORKER(4) experiments, at most one per CPU. - A few experiments run serially, and so does a run inside a worker.
n_workers=1runs every experiment in the calling process; a number gives a pool of that many workers.
- By default there is a worker per
- What a worker does.
- It creates an experiment again from its class with the settings of the runner and keeps the loaded models for its next experiment.
- It runs the experiment with the parameters of matplotlib which the run changed, e.g. the
rc_contextof pkpdsim, and writes its outputs. - The parent logs the messages of the workers in the order of the experiments and creates the report from its own experiments.
- The most expensive experiments start first, and the forkserver imports the modules of the experiments once.
- An experiment whose worker died runs in the calling process again.
- When the run stays serial. An experiment runs its scans serially in its worker. So by default a runner whose simulator runs its scans in a pool stays serial and its scans keep that pool; this is a simulator of more than one worker, or of
n_workers=Nonewith a scan ofPOOL_THRESHOLDpoints. A run is serial as well when:- its figures are shown, or its results are kept;
- its runner has a unit registry of its own;
- an experiment cannot be imported by a worker, e.g. a class defined in a function or in the main script.
- Measured. The 28 experiments of the HCTZ model take 11.9 s on 8 workers instead of 20.8 s serially, with 3.6 GB of all processes instead of 0.5 GB. Their 740 SVG, TSV, JSON and HTML files are the same.
- A script which runs the pool needs the guard
if __name__ == "__main__":, as for a pooled scan.
- What the pool is.
Changes
- A figure of the serializer is saved without a second drawing (#388).
- Before.
bbox_inches="tight"draws a figure once to find its box and once more to write it. - Now.
saved_boxgives the tight box of a figure built byMatplotlibFigureSerializer, measured with the renderer of a pixel of #385 and padded bysavefig.pad_inches.SimulationExperiment.save_mpl_figuressaves the figure with it, without drawing it first. - Effect. The measuring renderer is one per resolution, so the metrics of the texts of a figure are measured once. The 128 figures of the HCTZ model are saved in 7.2 s instead of 8.8 s. A box is never smaller than the tight box and at most 1.4 pt wider, since Agg measures a text a little wider than the paths of SVG.
- Unchanged. The custom figures of
figures_mpl()and a figure with a layout engine are saved"tight"as before.
- Before.
- Formulas are parsed without importing the package petab (#389).
- Before.
compile_formulaimportedpetab.v2.math, which imports petab withmatplotlib.pyplotandscipy.stats, and its SciML extension with torch. Every process and every worker of a pool paid 0.7 to 1.4 s for its firstFormulaobservable orDatafunction. - Now.
parse_mathimports the parser of petab, the self-contained packagepetab.v1.math, from its directory assbmlsim._petab_math. It is the same code, with the same semantics. - Effect. The first formula takes 0.04 s.
- Before.
- The points of a PK observable are analysed in padded groups (#390).
- Before.
evaluate_pkanalysed the points of a chunk in groups of the same number of time points. The steps of the integrator give every point its own number, so pkpdutils was called once per point. - Now. A point is padded with
NaNto the next power of two of its number of time points. This length depends on the point alone, so a parameter still does not depend on the chunking, and the points of a chunk share a call of pkpdutils. - Effect. A scan of midazolam over 200 doses with three oral doses takes 4.5 ms per point instead of 8.4 ms. Of its 63 parameters and flags, 41 are bitwise the same and the others differ by at most 6e-16 relative.
- Unchanged. A manual terminal phase, whose points pkpdutils indexes in the columns of a row, is analysed unpadded.
- Before.