pymixef.pharmacometrics.ode module

Deterministic, event-aware ODE simulation built on SciPy.

The simulator splits integration intervals at every discontinuity. Boluses, finite and overlapping infusions, resets, time-varying covariates, ADDL doses, and same-time observations are handled above scipy.integrate.solve_ivp so that event semantics do not depend on a solver’s root-finding convention.

class pymixef.pharmacometrics.ode.EventSnapshot(row_id, source_row_id, subject_id, time, state, dv, mdv, lloq, occasion=None)[source]

Bases: object

State observed at a canonical observation event.

Parameters:
  • row_id (str)

  • source_row_id (str)

  • subject_id (Any)

  • time (float)

  • state (NDArray[float64])

  • dv (float | None)

  • mdv (int)

  • lloq (float | None)

  • occasion (Any)

row_id: str
source_row_id: str
subject_id: Any
time: float
state: NDArray[float64]
dv: float | None
mdv: int
lloq: float | None
occasion: Any
class pymixef.pharmacometrics.ode.ODEContext(parameters, covariates, infusion_rates, subject_id=None)[source]

Bases: Mapping[str, float]

Explicit dynamic inputs passed to three-argument RHS callables.

The context also implements the read-only mapping protocol by delegating to parameters. Thus both context.parameters["CL"] and the familiar shorthand context["CL"] are supported without making covariates or infusion rates implicit.

Parameters:
  • parameters (Mapping[str, float])

  • covariates (Mapping[str, Any])

  • infusion_rates (NDArray[float64])

  • subject_id (Any)

parameters: Mapping[str, float]
covariates: Mapping[str, Any]
infusion_rates: NDArray[float64]
subject_id: Any
exception pymixef.pharmacometrics.ode.ODESimulationError(message, *, time=None, subject_id=None, details=None)[source]

Bases: RuntimeError

A structured ODE or event-processing failure.

Parameters:
  • message (str)

  • time (float | None)

  • subject_id (Any)

  • details (Mapping[str, Any] | None)

Return type:

None

code = 'ODE-SIMULATION-FAILED-001'
to_dict()[source]
Return type:

dict[str, Any]

class pymixef.pharmacometrics.ode.ODESimulationResult(times, states, state_names, observations, metadata, subject_id=None, sensitivities=None, sensitivity_parameters=())[source]

Bases: object

State trajectories, event snapshots, sensitivities, and solver metadata.

Parameters:
  • times (NDArray[float64])

  • states (NDArray[float64])

  • state_names (tuple[str, ...])

  • observations (tuple[EventSnapshot, ...])

  • metadata (ODESolverMetadata)

  • subject_id (Any)

  • sensitivities (NDArray[float64] | None)

  • sensitivity_parameters (tuple[str, ...])

times: NDArray[float64]
states: NDArray[float64]
state_names: tuple[str, ...]
observations: tuple[EventSnapshot, ...]
metadata: ODESolverMetadata
subject_id: Any
sensitivities: NDArray[float64] | None
sensitivity_parameters: tuple[str, ...]
state(name_or_index)[source]

Return one read-only state trajectory.

Parameters:

name_or_index (str | int)

Return type:

NDArray[float64]

sensitivity(state, parameter)[source]

Return d state / d parameter from finite differences.

Parameters:
  • state (str | int)

  • parameter (str)

Return type:

NDArray[float64]

class pymixef.pharmacometrics.ode.ODESolverMetadata(solver, scipy_version, rtol, atol, max_step, success, message, nfev, njev, nlu, segments, event_actions, source_events, generated_additional_doses, generated_infusion_stops, same_time_order, sensitivity_method=None, sensitivity_step=None)[source]

Bases: object

Numerical and semantic metadata retained for every successful run.

Parameters:
  • solver (str)

  • scipy_version (str)

  • rtol (float)

  • atol (tuple[float, ...])

  • max_step (float)

  • success (bool)

  • message (str)

  • nfev (int)

  • njev (int)

  • nlu (int)

  • segments (int)

  • event_actions (int)

  • source_events (int)

  • generated_additional_doses (int)

  • generated_infusion_stops (int)

  • same_time_order (tuple[str, ...])

  • sensitivity_method (str | None)

  • sensitivity_step (float | None)

solver: str
scipy_version: str
rtol: float
atol: tuple[float, ...]
max_step: float
success: bool
message: str
nfev: int
njev: int
nlu: int
segments: int
event_actions: int
source_events: int
generated_additional_doses: int
generated_infusion_stops: int
same_time_order: tuple[str, ...]
sensitivity_method: str | None
sensitivity_step: float | None
to_dict()[source]
Return type:

dict[str, Any]

class pymixef.pharmacometrics.ode.SensitivityCheck(parameter_names, forward, central, maximum_scaled_difference, step)[source]

Bases: object

Finite-difference sensitivity diagnostic.

Parameters:
  • parameter_names (tuple[str, ...])

  • forward (NDArray[float64])

  • central (NDArray[float64] | None)

  • maximum_scaled_difference (float | None)

  • step (float)

parameter_names: tuple[str, ...]
forward: NDArray[float64]
central: NDArray[float64] | None
maximum_scaled_difference: float | None
step: float
exception pymixef.pharmacometrics.ode.UnsupportedEventSemantics(message, *, time=None, subject_id=None, details=None)[source]

Bases: ODESimulationError

Raised rather than silently approximating unsupported event semantics.

Parameters:
  • message (str)

  • time (float | None)

  • subject_id (Any)

  • details (Mapping[str, Any] | None)

Return type:

None

code = 'ODE-EVENT-UNSUPPORTED-001'
pymixef.pharmacometrics.ode.finite_difference_sensitivities(rhs, initial_state, events, *, parameters, parameter_names=None, step=np.cbrt(np.finfo(float).eps), compare_central=False, **simulation_options)[source]

Compute forward sensitivities and optionally compare central differences.

This is a validation/debug path, not an automatic-differentiation claim. Event times are held fixed while parameter values are perturbed.

Parameters:
  • rhs (Callable[[...], ArrayLike])

  • initial_state (ArrayLike)

  • events (EventTable | Iterable[Mapping[str, Any]] | None)

  • parameters (Mapping[str, float])

  • parameter_names (Sequence[str] | None)

  • step (float)

  • compare_central (bool)

  • simulation_options (Any)

Return type:

SensitivityCheck

pymixef.pharmacometrics.ode.simulate_ode(rhs, initial_state, events=None, *, t_eval=None, parameters=None, initial_covariates=None, covariate_columns=(), state_names=None, compartment_map=None, subject_id=None, initial_time=0.0, final_time=None, method='RK45', rtol=1e-8, atol=1e-10, max_step=np.inf, sensitivity_parameters=None, sensitivity_step=np.sqrt(np.finfo(float).eps), debug_finite_difference=False)[source]

Simulate one subject with exact event-time discontinuities.

Supported RHS signatures are rhs(t, y), rhs(t, y, context) and rhs(t, y, parameters, covariates). For the three-argument form, context is an ODEContext. Infusion rates are always added to the returned state derivatives by the event manager.

Forward finite-difference sensitivities can be requested by parameter name. Set debug_finite_difference=True to compute all numeric parameter sensitivities when no explicit list is supplied.

Parameters:
  • rhs (Callable[[...], ArrayLike])

  • initial_state (ArrayLike)

  • events (EventTable | Iterable[Mapping[str, Any]] | None)

  • t_eval (ArrayLike | None)

  • parameters (Mapping[str, float] | None)

  • initial_covariates (Mapping[str, Any] | None)

  • covariate_columns (Sequence[str])

  • state_names (Sequence[str] | None)

  • compartment_map (Mapping[int | str, int | str] | None)

  • subject_id (Any)

  • initial_time (float)

  • final_time (float | None)

  • method (str)

  • rtol (float)

  • atol (float | ArrayLike)

  • max_step (float)

  • sensitivity_parameters (Sequence[str] | None)

  • sensitivity_step (float)

  • debug_finite_difference (bool)

Return type:

ODESimulationResult

pymixef.pharmacometrics.ode.simulate_subjects(rhs, initial_state, events, **options)[source]

Deterministically simulate every subject in an event table.

Parameters:
  • rhs (Callable[[...], ArrayLike])

  • initial_state (ArrayLike)

  • events (EventTable | Iterable[Mapping[str, Any]])

  • options (Any)

Return type:

Mapping[Any, ODESimulationResult]