pymixef.pharmacometrics.events module

Canonical pharmacometric event records.

The event layer is deliberately independent of pandas. Input records are normalized to immutable CanonicalEvent objects, sorted with a documented tie-breaking rule, and accompanied by an immutable audit trail.

Same-time events are applied in this order:

  1. reset (including the reset part of reset-and-dose);

  2. covariate change;

  3. infusion stop;

  4. dose or infusion start (including the dose part of reset-and-dose);

  5. observation;

  6. other event.

Input order is the final stable tie breaker. Consequently, an observation at the same time as a dose sees the post-dose state. This convention is explicit instead of being inherited from a dataframe sort implementation.

class pymixef.pharmacometrics.events.AuditEntry(code, action, row_id=None, source_row_id=None, details=<factory>)[source]

Bases: object

One machine-readable canonicalization or expansion action.

Parameters:
  • code (str)

  • action (str)

  • row_id (str | None)

  • source_row_id (str | None)

  • details (Mapping[str, Any])

code: str
action: str
row_id: str | None
source_row_id: str | None
details: Mapping[str, Any]
to_dict()[source]

Serialize the audit entry without exposing mutable internals.

Return type:

dict[str, Any]

class pymixef.pharmacometrics.events.CanonicalEvent(subject_id, time, evid, amount=None, amount_status=None, rate=None, duration=None, compartment=None, additional=0, interval=None, steady_state=0, mdv=1, dv=None, lloq=None, occasion=None, bioavailability=1.0, lag=0.0, covariates=<factory>, extras=<factory>, row_id='', source_row_id='', source_position=0, generated=False, generation=None)[source]

Bases: object

An immutable event in the PyMixEF canonical schema.

amount_status distinguishes a recorded amount (including zero), an explicitly unknown dose amount, and a field that is structurally not applicable to a non-dose event.

Parameters:
  • subject_id (Hashable)

  • time (float)

  • evid (EventType)

  • amount (float | None)

  • amount_status (DoseAmountStatus | str | None)

  • rate (float | None)

  • duration (float | None)

  • compartment (int | str | None)

  • additional (int)

  • interval (float | None)

  • steady_state (int)

  • mdv (int)

  • dv (float | None)

  • lloq (float | None)

  • occasion (Hashable | None)

  • bioavailability (float)

  • lag (float)

  • covariates (Mapping[str, Any])

  • extras (Mapping[str, Any])

  • row_id (str)

  • source_row_id (str)

  • source_position (int)

  • generated (bool)

  • generation (str | None)

subject_id: Hashable
time: float
evid: EventType
amount: float | None
amount_status: DoseAmountStatus | str | None
rate: float | None
duration: float | None
compartment: int | str | None
additional: int
interval: float | None
steady_state: int
mdv: int
dv: float | None
lloq: float | None
occasion: Hashable | None
bioavailability: float
lag: float
covariates: Mapping[str, Any]
extras: Mapping[str, Any]
row_id: str
source_row_id: str
source_position: int
generated: bool
generation: str | None
property is_observation: bool
property is_dose: bool
property is_reset: bool
property is_infusion: bool
property effective_rate: float

Infusion rate after bioavailability, or zero for a bolus.

property effective_amount: float | None
property infusion_duration: float | None
property kind: str
property id
property event_type
property amt
property cmt
property addl
property ii
property ss
property ID
property TIME
property EVID
property AMT
property RATE
property DUR
property CMT
property ADDL
property II
property SS
property MDV
property DV
property LLOQ
to_record()[source]

Return a mutable, uppercase-keyed record for serialization.

Return type:

dict[str, Any]

class pymixef.pharmacometrics.events.DoseAmountStatus(*values)[source]

Bases: StrEnum

Semantic state of the dose-amount field.

RECORDED = 'recorded'
UNKNOWN = 'unknown'
NOT_APPLICABLE = 'not-applicable'
class pymixef.pharmacometrics.events.EventTable(events, audit=(), source_count=0, source_records=())[source]

Bases: Sequence[CanonicalEvent]

Immutable, deterministically ordered collection of canonical events.

Parameters:
  • events (tuple[CanonicalEvent, ...])

  • audit (tuple[AuditEntry, ...])

  • source_count (int)

  • source_records (tuple[Mapping[str, Any], ...])

events: tuple[CanonicalEvent, ...]
audit: tuple[AuditEntry, ...]
source_count: int
source_records: tuple[Mapping[str, Any], ...]
classmethod from_records(records, *, covariate_columns=(), expand_additional=False, expand_infusions=False)[source]

Canonicalize mapping records or a NumPy structured array.

Calendar times are converted to UTC Unix seconds and must be timezone-aware. No input object is modified.

Parameters:
  • records (Iterable[Mapping[str, Any]] | ndarray)

  • covariate_columns (Sequence[str])

  • expand_additional (bool)

  • expand_infusions (bool)

Return type:

EventTable

property subjects: tuple[Hashable, ...]

Subject IDs in deterministic first-occurrence order.

for_subject(subject_id)[source]

Return an immutable view containing one subject.

Parameters:

subject_id (Hashable)

Return type:

EventTable

to_records()[source]

Return plain records suitable for pandas, Polars, Arrow, or JSON.

Return type:

list[dict[str, Any]]

to_source_records()[source]

Return fresh copies of the retained, pre-canonicalization records.

Return type:

list[dict[str, Any]]

expand_additional()[source]

Materialize ADDL/II doses without mutating the source table.

The returned records have ADDL=0 so expansion is idempotent. Every generated row retains the original source_row_id and receives a deterministic <row_id>:addl:<n> row identifier.

Return type:

EventTable

expand_infusions()[source]

Add explicit infusion-stop records for finite infusions.

Explicit stops already present in the source are retained. A finite start generated from AMT/RATE/DUR gets one deterministic stop.

Return type:

EventTable

provenance()[source]

Return the complete immutable audit as fresh dictionaries.

Return type:

tuple[dict[str, Any], …]

class pymixef.pharmacometrics.events.EventType(*values)[source]

Bases: IntEnum

Canonical EVID values, extending the common NONMEM values.

Values 0–4 retain their familiar meaning. Values 5 and 6 are explicit PyMixEF records used for time-varying covariates and infusion stops.

OBSERVATION = 0
DOSE = 1
OTHER = 2
RESET = 3
RESET_AND_DOSE = 4
COVARIATE = 5
INFUSION_STOP = 6
exception pymixef.pharmacometrics.events.EventValidationError(message, *, row=None)[source]

Bases: ValueError

Raised when an event record is ambiguous or internally inconsistent.

Parameters:
  • message (str)

  • row (int | str | None)

Return type:

None

code = 'EVENT-INVALID-001'
pymixef.pharmacometrics.events.canonicalize_events(records, *, covariate_columns=(), expand_additional=False, expand_infusions=False)[source]

Convenience wrapper around EventTable.from_records().

Parameters:
  • records (Iterable[Mapping[str, Any]] | ndarray)

  • covariate_columns (Sequence[str])

  • expand_additional (bool)

  • expand_infusions (bool)

Return type:

EventTable