Factory methods:
Model.load(path)— Load any supported file, dispatching on its suffix (.ant,.xml/.sbml,.net,.bngl); raisesModelErrorfor anything elseModel.from_net(path)— Load from BNG.netfileModel.from_bngl(path, *, protocol=False, bng2_pl=None, net_out=None, timeout=600, cache=True)— Load from BNGL.bnglby runningBNG2.pl generate_network(requiresbngsim[bngl], or$BNGPATH/$BNG2_PL, plusperl). The file's actions block is not executed — onlygenerate_network, carrying the source's ownmax_iter/max_agg/max_stoich;protocol=Truereturns(model, ProtocolSpec)so the actions are recovered rather than discarded. Generated networks are cached under~/.cache/bngsim/networks($BNGSIM_BNGL_CACHE_DIR), keyed on the flattened model text and the BNG2.pl that produced itModel.from_antimony(path)— Load from Antimony.antfile (requiresantimony,python-libsbml)Model.from_antimony_string(text)— Load from Antimony stringModel.from_sbml(path)— Load from SBML.xmlfile (requirespython-libsbml)Model.from_sbml_string(text)— Load from SBML XML string
Properties:
n_species,n_reactions,n_observables,n_parameters,n_functions,n_eventsspecies_names,param_names,observable_names,function_namesanalytical_jacobian_status—"complete","pending"(functional rate laws not derived yet), or"declined: <reason>"when the model runs on the finite-difference Jacobian: the rate law and what stopped its derivation, the derivation budget, the C++ attach gate's verdict, or the environment switch. The gate's verdict names the entry it refused, with the probe state and both values —∂f[B()]/∂[A()] is non-finite (inf) at probe 0 (the seed state) while the RHS is finite, orthe finite-difference self-check found a trustworthy mismatch at probe 0 (the seed state) in ∂f[LX()]/∂[LX()]: analytical 0, finite-difference -10(issue #534). The same reason is logged at INFO on thebngsimlogger when it happens (issue #506)analytical_jacobian_decline— the same decline as a dict a census can group by:Nonewhile the status is"complete"or"pending", otherwisekind(a stable category frombngsim._jacobian.DECLINE_KINDS, such asbudget,unresolved_symbolor the C++ gate'sfd_mismatch) andreason(the status text afterdeclined:). The gate's kinds also carry the fields their verdict sets (ofrxn_idx,per_observable,target_idx,row,col,probe,analytical,finite_difference,n_nonfiniteanddetail; a field a kind does not set is absent) and the speciesrowandcolname asrow_species/col_species. Group bykind, not by the text, whose wording changes (issue #538)primary_param_names— the model's independent knobs, and the list to hand an optimizer or sampler, lessfrozen_paramswhere a model has any.param_namesminus two classes, one per flag:param_is_expression(a derivedConstantExpression, recomputed from the primaries underneath it) andparam_is_internal(a slot bngsim synthesized — an SBML_V0_<comp>, or a function's backing slot — whichset_paramrefuses to write). A constant written as arithmetic (gamma 1/7) is not in either class and is an ordinary knob (issue #227)frozen_params— the parameters that a number the model was built with was read from. For SBML (compartment sizes,speciesReferenceids and a kinetic law's own parameters among them): a compartment size set by aninitialAssignmentor a constant assignment rule, the initial value of a species converted by the size of a compartment that is a state, a stoichiometry, aconversionFactor, an initial value that could not be kept symbolic, each followed down through what it reads. For a compartmental BNGL model: the volumes BNG2.pl wrote into the rate constants (each parameter aunit_conversion=comment names, and what a derived parameter or a function among them reads).set_paramrefuses to change one and a sensitivity column for one is refused (issues #695, #696, #711). Empty for most models
Methods:
set_param(name, value)— Set a parameter valueget_param(name)— Get a parameter valueset_params(dict)— Set multiple parameters (atomic)reset()— Reset species to initial concentrations (=restore_concentrations()with no label)clone()— Deep copy for parallel workers, and the only way to get an independentModel. All of a model's state lives behind one handle into the compiled extension, socopy.copy(model)would share it — a write through the "copy" would change the original, which would then simulate differently with nothing raised. Bothcopy.copyandcopy.deepcopytherefore refuse and name this method (issue #643). Same for aSimulator: build a second one overmodel.clone(). AResultdoes still shallow-copy, having no setter to write throughsave_concentrations(label=None)— Snapshot current concentrations. No label rebases the default slot (reset()returns here); alabelstores a named snapshot (BNGsaveConcentrations("name")), and multiple named states coexist.restore_concentrations(label=None)— Restore a snapshot; no label restores the default slot, alabelrestores that named state (BNGresetConcentrations("name"))has_saved_concentrations(label=None)— Whether a named snapshot (or, with no label, any) existssaved_concentration_labels— Sorted names of saved named snapshotsset_concentration(name, value)— Set a single species concentrationget_concentration(name)— Get a single species concentrationpure_sink_species()→list[str]— write-only accumulator species: a product of ≥1 reaction, a reactant of none, read by no other species' derivative, and not$-fixed. These put a structural floor under||f(y)||_2/n(issue #74)is_pure_sink()→ndarray (n_species,) of bool— the array form, somask=~model.is_pure_sink()declare_ic_sensitivity({species: {param: d_ic_d_param}})— Declare∂x_k(0)/∂θfor an initial condition your own code assigns (issue #111). A declared species' row is taken as fully specified: parameters not named get0.0, so it replaces the model's parameter-graph row rather than adding to iteffective_ic_sensitivity(params=None)→dict[str, dict[str, float]]— the reader paired with the writer above:{species: {param: ∂x(0)/∂θ}}, the initial-condition seeding a run from this state would use, after the #113 retirement and the #111 overlay. Answers from model structure alone — no integration, no simulation — so a fitting frontend can build its gradient routing once at setup. Keys are the idssensitivity_params=accepts (a #147-lowered compound<initialAssignment>reports the original symbols, never the synthetic_ic_<species>carrier). A present entry valued0.0means seeded, coefficient zero at this state; an absent entry means no seeding path — the two are different answers. Needed becauseoutput_sensitivities(axis="parameter")is a total derivative that already contains this matrix times theicaxis (GH #155)add_table_function(name, *, file, times, values, index, method)— Give a table function the model declares new data, in place, over the same index and keeping its method unlessmethodis given; every engine reads it from then on. A plain function's name raisesModelError; a new name adds a table nothing reads, with a warning (issue #772)n_table_functions,table_function_names— TFUN introspection
Evaluators (issue #523; see Model evaluators). Each takes a state y of length n_species in species_names order, reads the live parameters, and leaves the stored concentrations alone:
rhs(y, t=0.0)→ndarray (n_species,)—dy/dtat(t, y): the interpreted RHS the CVODE callback evaluates, with its observable/function refresh run atyjacobian(y, t=0.0, *, sparse=False)→JacobianMatrixorscipy.sparse.csc_array—∂f/∂y,J[i, j] = ∂f_i/∂x_j; closed form when it covers every reaction, else the steady-state solver's difference quotient, and.sourcesays which ("analytical"/"finite-difference"). A difference quotient whose step decides an entry (it moves by more than 1e-4 of itself, 1e-10 of its column's largest at least, when the column is taken again at the species' own step or at half the first) raisesSimulationError(issue #1002).sparse=Trueuses the model's structural patternpropensities(y, t=0.0)→ndarray (n_reactions,)— every reaction's SSA propensity in the SSA volume convention (falling factorial for a repeated reactant, times the compartment volume), after the SSA loop's own observable refresh atystoichiometry_matrix(*, sparse=False)→ndarray (n_species, n_reactions)orcsc_array— net coefficients, 0-based; a$-fixed species has a zero row. The matrixconservation_lawswas row-reduced from, soL @ S == 0(except in an SBML model with a reaction between compartments of different size, whose laws carry the sizes:L @ rhs(y) == 0)
The dense return of Model.jacobian: a float64 ndarray subclass with one extra attribute, source — "analytical" or "finite-difference". Behaves as an ordinary array otherwise.
Constructor:
-
Simulator(model, method="ode", *, jacobian, codegen, net_path, sensitivity_params, poplevel, xml_path, gml)method:"ode","ssa","psa","nf","nf_reject","nfsim","nf_exact","rulemonkey","rm"(and aliases)ODE-specific kwargs:
jacobian("auto","analytical","fd","jax"),codegen(bool orNone),sensitivity_params(list[str])codegen=Truecompiles the model as built, whatever it was loaded from;None(the default) compiles at or aboveBNGSIM_CODEGEN_THRESHOLDspecies (256).jacobian="jax"differentiates a JAX RHS built from the model; a model it does not implement (a compartment size that is a parameter, as in every SBML model, amount-valued species, rate rules,rateOf, table functions) is refused with the construct named.net_pathis deprecated and ignored.PSA:
poplevel(float, required). Accepts.net, SBML, and Antimony models (same dispatch as SSA, sharing thevalidate_for_ssagate). NFsim/RuleMonkey:xml_path(str, required),gml(int).
Simulation:
run(t_span, n_points, *, seed, rtol, atol, max_steps, timeout, steady_state, steady_state_tol)→Resultrun_batch(t_span, n_points, *, params, seed, num_processors, squeeze, timeout, steady_state, steady_state_tol)→list[Result]orResult— clones + resets each point to the.netseedparameter_scan(parameter, par_scan_vals=None, *, par_min, par_max, n_scan_pts, log_scale, t_span, n_points, reset_conc=True, reset_to=None, on_point=None, seed, squeeze, …)→list[Result]orResult— BNGparameter_scan. Withreset_conc=True, each point resets to the state at scan invocation (or to the named snapshotreset_to), not the seed — so a pre-equilibrate → intervene → scan protocol carries its post-intervention state.on_point(model, value)applies coupledsetConcentrationoverrides that track the scanned value.bifurcate(parameter, par_scan_vals=None, *, …)→list[Result]orResult— continuation scan (reset_conc=0): each point continues from the previous point's end-statecompute_all_sensitivities(t_span, n_points, *, params, chunk_size, n_workers, rtol, atol, max_steps)→Resultwith full sensitivity tensor
timeout is a wall-clock budget in seconds (or None to disable, the default).
When the budget is exceeded, run / run_batch raise
bngsim.SimulationTimeout (a typed BngsimError) carrying timeout
(the configured limit) and elapsed (actual wall-clock time at the trip).
Supported on every backend (ODE, SSA, PSA, NFsim, RuleMonkey). NFsim and
RuleMonkey poll the budget at a coarser granularity than ODE/SSA/PSA
(between stepTo() output points for NFsim; every ~1024 SSA events for
RuleMonkey, via its upstream cancellation hook), so the surfaced elapsed
time may overshoot the budget by one such interval.
Interactive:
run_until(t, *, n_points, seed)→Resultintervene(params)— Change parameters mid-simulationsave_concentrations(label=None)/restore_concentrations(label=None)— Snapshot / restore the model's concentrations by name (delegates toModel); pair withparameter_scan(reset_to=label)for a preincubate → save → scan protocolsnapshot()→dict— Save staterestore(snapshot)— Restore stateget_state()→ndarray/set_state(state, *, time=None)— Bulk species vector;time=also setscurrent_time, so a step can be redone from a saved state and time withoutrestore's backend rebuild (rolling a step back)set_time(t)— Setcurrent_time(finite, elseValueError); the nextrun_untilintegrates from there
Stop conditions:
add_stop_condition(condition, *, label)—strexpression orcallableclear_stop_conditions()
Steady-state (method ∈ "integration" (default), "newton", "kinsol" alias):
-
steady_state(*, tol, max_time, method, rtol, atol, max_steps, sensitivity_params, mask)→SteadyStateResult -
steady_state_batch(params=None, *, states, tol, max_time, method, rtol, atol, max_steps, n_workers, mask, newton_burst)→list[SteadyStateResult].statesstarts each entry from a state of its own, paired row by row withparams;newton_burst=Falsewithmethod="newton"solves from that state with no integration burst and reports an unstable root instead of rejecting it (issue #524) -
steady_states(*, n_starts, seed, upper, decades, dedupe_rtol, tol, n_workers, mask)→SteadyStates: every steady state multistart Newton finds from starts sampled on the conservation manifold, each with its stability (issue #524). See the user guide's steady-state page -
Both raise
SimulationErrorfor a model with an event, or one that reads the time (issue #710): the solvers read the right-hand side att = 0and fire no event.run(steady_state=True)integrates such a model to the end of its span and does not stop early.mask(issue #74): which species enter the convergence norm — a boolean array of lengthn_species, or the species names to keep. DefaultNonetests every species (BNG2.pl parity). It also restricts the KINSOL unknown set and thedY_ss/dpsystem to the same subspace; excluded species get a NaNdY_ss/dprow. SeeModel.is_pure_sink().
Configuration:
set_tolerances(rtol, atol)— ODE solver tolerancesset_max_steps(max_steps)— Max internal solver stepsauto_atol(*, rtol=None, floor=None)→ndarray— derive a per-species absolute tolerance from the model's current state,rtol * max(|y_i|, floor)(issue #196). For a tolerance that is a constant of the model rather than of the point being integrated, usebngsim.derive_atolbelow.
Every atol above takes a float (scalar, CVodeSStolerances), a sequence of
n_species values ordered like model.species_names (per-species,
CVodeSVtolerances), or "auto" (derive one — see auto_atol). A wrong-length
vector raises ValueError rather than broadcasting. Multi-point calls resolve it
once, so every point of a batch or scan shares one tolerance. See the
solver guide.
Properties:
method,model,current_timehas_analytic_sens_rhs(bool) andsens_rhs_decline_reason(str | None, issue #438) — whether a forward-sensitivity run on this Simulator uses bngsim's analytic∂f/∂por CVODES' internal difference quotient, and why not when it does not. A property of the (build, model) pair rather than of the build, so nocapabilities()key can answer it. Ask a Simulator built for a sensitivity run: a plain one carries no analytic∂f/∂pbecause nobody asked for one, which is not a decline. See the PyBNF guide.
Stateful NFsim session API for multi-action workflows where parameters or live particle counts are changed between simulation segments.
Constructor:
NfsimSession(xml_path, *, molecule_limit)— Create an NFsim session from a BNGL-generated NFsim XML file
Session control:
initialize(seed)— Initialize the live NFsim systemsimulate(t_start, t_end, *, n_points, timeout)→Result—timeoutis a wall-clock budget in seconds (Nonedisables, the default). Checked betweenstepTo()output points; on overrun raisesbngsim.SimulationTimeoutand the session must be destroyed before reuse.destroy()— Release the live NFsim session
Parameters:
set_param(name, value)— Set a parameter before initializationget_parameter(name)— Evaluate a parameter in the live session
Live counts:
get_molecule_count(molecule_type)— Count all live molecules of a typeadd_molecules(molecule_type, count)— Add default unbound moleculesget_species_count(pattern)— Count an exact single-molecule BNGL speciesadd_species(pattern, count)— Add exact single-molecule species instancesremove_species(pattern, count)— Remove exact single-molecule species instancesset_species_count(pattern, count)— Set the exact species count by adding or removing instances
Species count mutation currently supports exact, unbound, single-molecule BNGL
patterns such as "X(p~0,y)", "L(r)", and "TNF()". Patterns must list every
component and specify every stateful component state. Multi-molecule complex
patterns fail with a clear SimulationError.
Saved states (in-process):
-
save_concentrations(label=None)— Snapshot the live molecular state (counts, component states, bonds). An optionallabelnames it (BNGsaveConcentrations("name")). -
restore_concentrations(label=None)— Rewind to the snapshot; alabelmust match the currently-held one. -
has_saved_concentrations(label=None)— Whether a (named) snapshot is held.The NFsim backend keeps a single in-session snapshot, so each save overwrites the previous one; the label lets a mismatched restore fail loudly. The network-based
Modelsupports true multi-slot named states.
Stateful RuleMonkey session API for exact network-free workflows where parameters are configured before initialization and live particle counts can be changed between simulation segments.
Constructor:
RuleMonkeySession(xml_path, *, molecule_limit, block_same_complex_binding)— Create a RuleMonkey session from a BNGL-generated NFsim XML file
Session control:
initialize(seed, t_start=None)— Initialize the live RuleMonkey system with the seed state att_starton the model's clock (current_timereads it). LeftNone, the clock starts at 0, and for a model that reads the clock the firstsimulatemoves the seed state to its own start if nothing has moved the session first (issue #1022)simulate(t_start, t_end, *, n_points, timeout)→Result—timeoutis a wall-clock budget in seconds (Nonedisables, the default). Polled by upstream every ~1024 SSA events; on overrun raisesbngsim.SimulationTimeoutand the session must be destroyed before reuse. A segment that starts atcurrent_timeruns on the session clock, which is model time. One that starts elsewhere continues fromcurrent_timeand is labelled with the times asked for; for a model that reads the clock (time()or a table function indexed by time) that raisesSimulationError.solver_stats["n_steps"]counts the events sinceinitialize, as anNfsimSession's does.step_to(time, *, timeout)— Advance totimeon the model's clock without recording output; honors the sametimeoutsemantics assimulate(...).destroy()— Release the live RuleMonkey session
Every time a session takes or reports (current_time, the clock read through
evaluate, a save_state snapshot) is model time. A model that reads the
clock in its functions has its events placed on time elapsed since the
session's start, which keeps a late start's waiting times (issue #1063).
Parameters and counts:
set_param(name, value)— Set a parameter before initializationclear_param_overrides()— Clear parameter overrides before initializationget_parameter(name)— Evaluate a parameter from XML plus overridesget_molecule_count(molecule_type)— Count all live molecules of a typeadd_molecules(molecule_type, count)— Add default unbound moleculesget_observable_names()— Return observable names from the XMLget_observable_values()— Return current observable values
Properties:
time—ndarray (n_times,)species—ndarray (n_times, n_species)with named accessstate—ndarray (n_times, n_state): the full integrator state, unprojected and unremapped, inModel.species_namesorder — the rowsModel.rhs/Model.jacobiantake. Wider thanspecieson an SBML model whose event assigns a parameter or compartment; the stored rather than the reported value where a species column is remapped after the solve. Solve results only (issue #508)state_names—list[str]column names ofstate(= the producing model'sspecies_names)observables—ndarray (n_times, n_obs)with named access (e.g.result.observables["A_tot"])expressions—ndarray (n_times, n_expr)with named accesssensitivities—ndarray (n_times, n_species, n_params)forward sensitivity tensorhas_sensitivities—boolsensitivity_params—list[str]parameter names for sensitivityic_sensitivity_seed—dict[str, dict[str, float]] | None— the per-run record of the same matrixModel.effective_ic_sensitivity()reports: what CVODES was actually seeded with for this run. Use theModelaccessor to build routing at setup; use this to see what a particular run used, which is the only correct answer for a batch/scan over a nonlinear derived IC (Rtot = R0*scale), where the coefficients move per point.{}= nothing seeds;None= not recorded (no parameter sensitivities, non-ODE, an older HDF5 file, a squeezed batch whose rows disagreed, or acarry_sensitivities=Truephase, where the engine seeds from the prior phase'sdx/dθand discards these rows — GH #210/#81)dataframe—pandas.DataFrame(requires pandas)xr— AMICI-style xarray accessor;result.xr.species,.observables,.expressions,.sensitivities,.sensitivities_icreturn labeledxarray.DataArrays withtime/state/observable/expression/parameter/ic_statecoords (requires xarray)solver_stats—dictwith solver diagnosticscustom_attrs—dictfor user metadatan_times,n_species,n_observables,n_expressionsspecies_names,observable_names,expression_names
Methods:
resolve_outputs(selectors)→list[dict]— resolve typed output selectors (species:/observable:/expression:, aliasesstate:→species:,function:→expression:, withexpression:foo()→expression:foo) to per-output metadata{"selector","kind","name","index","column_label"}. Bare names resolve only if unique across all three kinds; ambiguous/unresolved selectors raise with the candidates listed.outputs(selectors)→ndarray (n_times, n_outputs)— value columns for the named selectors (one column per selector, in order)fisher_information(sigma)→ndarray (n_params, n_params)— Fisher Information Matrix from sensitivity datagradient(loss_fn)→ndarray (n_params,)— parameter gradient ∇_p L from sensitivity tensor and loss functionto_gdat(path)— Export observables as BNG.gdatto_cdat(path)— Export species as BNG.cdatto_csv(path, *, kind="observables"|"species", sep=",", include_time=True, header=True)— Plain delimited-text export (CSV / TSV); no#prefix; SBML/RoadRunner-friendlyto_xarray()→xarray.Datasetbundling species/observables/expressions/sensitivities/sensitivities_ic with sharedtimecoord (requires xarray);custom_attrs+seedpropagate tods.attrssave(path)— Save to HDF5 (requires h5py)Result.load(path)— Load from HDF5 (class method)Result.squeeze(results)— Stack list into 3D batch result
Returned by Simulator.steady_state().
Properties:
concentrations—ndarray (n_species,)species values at steady statespecies_names—list[str]residual,method_used,converged,n_steps,n_rhs_evals— solve diagnosticsn_residual_species,excluded_species— how many species entered||f||_2/n, and the 0-based indicesmask=excluded (issue #74)unconverged_pure_sinks—list[str]; on a failed solve, the write-only accumulators that were in the test and are carrying flux — i.e. the residual has a structural floor, not a slow tail. Empty otherwisesensitivity—ndarray (n_species, n_params)speciesdY_ss/dp(orNoneif nosensitivity_params)sensitivity_params—list[str]observable_names,expression_names—list[str]labelling the output-sensitivity rows (populated on a sensitivity run;expression_namesfilters the auto-generated_rateLawNfunctions, matchingResult)sensitivities_observables—ndarray (n_observables, n_params)exactd(observable)/dpsensitivities_expressions—ndarray (n_expressions, n_params)d(function)/dptotal derivative (state chain + explicit∂func/∂p)rhs_backend,sens_jacobian_source,sens_dfdp_source,sens_output_source— which numerical path each piece took.sens_output_source(issues #75, #1002) is"codegen"/"partial"/"none"for thed(function)/dpblock: the compiledbngsim_codegen_output_senschain rule answered every function, some of them, or none. A function it does not answer is a NaN row, refused by name byoutput_sensitivities; it is not differencedsens_jacobian_rcond—min|U_jj|/max|U_jj|from the LU of the (reduced) Jacobian that was inverted. It depends on the units of the species and decides nothing; the measures below dosens_root_determinant_ratio,sens_root_pivot_share,sens_root_condition,sens_root_column_shift,sens_root_state_shift,sens_root_hold_shift,sens_root_growth_rate,sens_root_relaxation— whether the steady state is an isolated root of the systemdY_ss/dpwas solved on, one the system rests at, and the returned state on it (issue #995): what the determinant keeps of itself when the state is corrected by one Newton step, the least a pivot is of the terms it was computed from, the componentwise condition number (the Perron root of|A⁻¹|·|A|), the largest move of a column solved again a Newton step on, against the larger of itself and1e-3/|p|, and of a species under that step (where a column moves by more than 0.01 of itself, or the state does, the state is stepped on, up to ten times, andsens_root_newton_stepscounts the steps:concentrations,residualand the sensitivities are then those of the stepped state), the same where a run ends that is taken on formax_timefrom a millionth beside the returned state, the largest real part among the eigenvalues (up to 512 unknowns; above that, among those of the species the state has at a zero), and the most of a column that a run ofmax_timewould leave unestablished.steady_stateraisesSimulationErroroutside 0.6 to 1.67, below 1e-13, above 1e13 (1e-6 and 1e6 wheresens_jacobian_sourceis"finite-difference"), above 0.01 (either, after the steps), above 0.01, where the real part timesmax_timeis above 0.01 (sens_root_spectral_radiusis the largest eigenvalue in size), and above 0.01; and where the run that is taken on fails or uses itsmax_stepssteps short ofmax_time.sens_root_hold_drift,sens_root_hold_stepsandsens_root_hold_timedescribe that run, andsens_species_scaleis what an entry for each species is small against: its own concentration, or for a species at a zero where it has been and what it is coupled to. Thesens_root_*_speciesandsens_root_*_paramattributes name the species and the parameter each is read at (Nonewhere none)sens_mask_held_species,sens_mask_reader_species— a speciesmask=left out that the solve held, and a kept species whose rate reads it;steady_stateraises where there is oneroot_stability,n_unstable_roots_rejected— the issue #78 linear-stability verdict on a Newton root ("stable"/"undetermined"/"unstable",""for integration), and how many candidate roots the certificate discardedeigenvalues—ndarray (n_unknowns,) complex128; the spectrum the verdict was read off (issue #523): the Jacobian restricted to the species the polish solved for, sorted by descending real part, a conjugate pair adjacent with+imagfirst. Empty when no spectrum was computed — an integration result, or a root the certificate declined on (more than 512 unknowns)
Methods:
resolve_outputs(selectors)→list[dict]— same selector grammar asResult.resolve_outputsoutput_sensitivities(selectors, *, axis="parameter")→ndarray (n_selectors, n_params)— steady-state∂(named output)/∂pforspecies:/observable:/expression:selectors, mirroringResult.output_sensitivities(no time axis).axis="ic"raises: the initial-condition axis is not computed (a parameter that sets an initial amount carries its share of a conserved total in its own column, issue #704)__getitem__(name)→float— steady-state concentration by species nameto_dict()→dict[str, float]
All inherit from bngsim.BngsimError (which inherits RuntimeError):
ModelError—.netparse failures, invalid model stateSimulationError— Solver failures (convergence, NaN)SimulationTimeout— Wall-clock budget exceeded;.timeoutand.elapsedattributesParameterError— Unknown parameter name, invalid valueSensitivityUnsupportedError— Forward sensitivity declined for this model: an event whose crossing time moves in a waydt*/dpcannot be computed for, or a rate law that does not differentiate to closed form. A declared capability gap, not a failure — catch it to fall back on a derivative-free optimizer. Also inheritsValueError(what both sites raised before the class existed), soexcept ValueErrorstill catches it. A missing compiler/JIT is not this exception; that stays a plainRuntimeError.StopConditionMet— Stop condition triggered;.resulthas partial data
Warnings (UserWarning subclasses; filter or escalate them with warnings):
RuleMonkeyWarning—method="rm"or aRuleMonkeySessionloaded a model for which RuleMonkey reports a warning-level diagnostic: how it reads a rule or rate law, such as a rule whose products can never be what it writes, which it never fires as BioNetGen generates no reaction for it (issue #1022)
bngsim.parse_net_file(path)→dict— The components of a.netfile as a plain Python dict with keysparameters,species,species_ic_params,observables,functions,reactionsandnet_file_dir. It is the C++ loader's own reading of the file, the oneModel.from_netbuilds, with the values the built model holds, so it needs the compiled extension, raisesValueErrorwhereModel.from_netrefuses the file (FileNotFoundErrororIsADirectoryErrorfor a path that is not a file), and reports the numbersModel.from_netputs in the same slots. DeprecatedSat/Hillrate laws come back rewritten as explicit functions, with the loader's warning.bngsim.build_model_from_parsed(parsed)→Model— Build a BNGsimModelfrom the dict returned byparse_net_file(), or one of the same shape. It makes theModelBuildercalls the loader makes, so an unmodified dict builds the modelModel.from_netloads.
-
bngsim.AUTO→"auto"— the token everyatol=accepts. Also the capability probe for the whole per-species feature:hasattr(bngsim, "AUTO"). The version string is not one — the checkout that first carried #196 still declared0.12.2. -
bngsim.derive_atol(state, rtol, *, floor=None)→ndarray—rtol * max(|y_i|, floor)over a state you supply, ordered likemodel.species_names.floordefaults to the smallest strictly positive entry ofstate(1.0if every entry is zero). -
bngsim.normalize_atol_vector(atol, n_species, species_names=None, *, where="atol")→list[float]— the length/position/finiteness checkrun()applies, callable at the point a vector is built rather than at the first run. -
bngsim.TRACKING→"tracking"— the token for the over-time mode of issue #213; sugar forTrackingAtol(). -
bngsim.TrackingAtol(decades=12.0, ceiling="auto")— anatol=value that re-evaluates the vector against the state being integrated (CVodeWFtolerances):atol_i(y) = clamp(rtol*|y_i|, ceiling_i * 10**-decades, ceiling_i). A vector fixes the tolerance per species; this fixes it per instant, which is what a species that starts at order one and decays to something tiny needs. Atdecades=0it is the ceiling vector exactly, and it is never looser than that vector.hasattr(bngsim, "TrackingAtol")is the probe. Costs steps and can make a stiff model unintegrable — see the solver guide for the corpus numbers.
derive_atol and Simulator.auto_atol run the same rule; they differ only in
which state they read. auto_atol (and atol="auto") reads the model's live
state, which is right for a one-off run and wrong for a fit that moves initial
conditions — there the tolerance would become a function of the fit point and
put a step in the objective. derive_atol reads whatever state you hand it, so
the vector can be derived once from the nominal state and held constant. See the
solver guide.
The compiled-artifact cache is content-addressed and nothing prunes it
automatically, so these are the supported way to see how large it has grown and
to bound it. Each mirrors one bngsim-cache verb and takes dry_run=True; all four
accept a cache_dir positional to operate on a directory other than the configured
one. See the codegen guide.
bngsim.codegen_cache_info(cache_dir=None)→CacheInfo— path, entry count,total_bytes,by_kind,by_key,live/orphaned(artifacts under this install's codegen key and under any other, issue #363),built_span/used_span, andatime_is_live(whether this filesystem records access times, i.e. whether prune's LRU order is real recency or build order). Reads directory metadata only — the key comes off the artifact's name..to_dict()is the JSON form.bngsim.clean_codegen_cache(cache_dir=None, *, min_age=3600.0, dry_run=False)→CacheSweep— remove leaked compile partials only (bngsim_shard_*directories, stray.c, temp libraries). No compiled artifact is touched, so no cache hit is lost.bngsim.prune_codegen_cache(cache_dir=None, *, orphaned=False, keep_keys=(), older_than=None, max_size=None, min_age=3600.0, dry_run=False)→CacheSweep— bound the cache by orphan status (orphaned=Truedrops every artifact built under another codegen key, the targeted sweep after an emitter edit), age (older_than="30d") and/or total size (max_size="2G"), evicting least-recently-used artifacts. At least one bound is required; the partial sweep runs first, so the size cap covers the whole directory.keep_keysspares other installs sharing the directory (Nonein it spares the pre-#363 names) and is only accepted withorphaned=True.bngsim.clear_codegen_cache(cache_dir=None, *, min_age=0.0, dry_run=False)→CacheSweep— remove every artifact and partial bngsim owns.
Beside an artifact whose analytic ∂f/∂p was declined, bngsim writes a small
decline note (rhs_<key>_<hash>.sens.json, issue #438) so the reason survives a
warm cache. Beside an artifact built with the output-sensitivity code it writes a
second note (rhs_<key>_<hash>.outputs.json, issue #1004): which functions the
artifact holds a derivative for, and why not for the others. A process that is
handed the artifact from the cache reads it, so output_sensitivities([...])
raises the reason the build recorded, and the map is not worked out again. (The
note answers for a model whose tables are the builder's: one given a table
function after it ran keeps its artifact and is analysed for itself, beside
what the note says the build has no derivative for.) Both
are bngsim's own files: counted under one kind, removed by clear, and removed by
prune exactly when the artifact they describe is removed.
Entries bngsim did not write are classified foreign, reported, and never
removed — by clear as much as by clean — because BNGSIM_CODEGEN_CACHE_DIR is a
user-supplied path. Nothing modified within min_age is removed either, so a sweep
cannot delete the scratch files of a compile that is still running.
bngsim.cache carries the rest: the CacheEntry / CacheInfo / CacheSweep types,
the KIND_* taxonomy, classify() and artifact_key() (the kind and the codegen key
an entry's name identifies it by), and the parse_duration / parse_size value
parsers the CLI uses.
bngsim.reserved_names()→dictwith"constants"and"functions"listsbngsim.configure_logging(level)— Enable log output
The curated summaries above cover the common surface. The full, always-in-sync reference below is generated directly from the package docstrings.
.. automodule:: bngsim
:members:
:undoc-members:
:show-inheritance: