schedule_adherence
schedule_adherence ¤
Production schedule adherence: planned quantity vs. what the line made.
OEE answers "how well did the line run?" but not "did it make what the plan asked for?". Those come apart routinely: a line at 92 % OEE running the wrong order is still behind schedule, and a line that lost two hours to a changeover can be on plan if the plan accounted for it.
This detector joins a planned schedule -- period start/end, planned quantity, order id -- against actual production derived from a monotonic counter, and reports per period how far ahead or behind the line is, plus the rate it would have to hold for the rest of the period to recover.
Actual quantities are reset-aware by default (see
:mod:ts_shape.utils.counters): a counter that drops to zero at a part change
inside a scheduled period would otherwise report the period as catastrophically
behind. Pass handle_resets=False for the naive last - first reading.
ProductionScheduleAdherenceEvents ¤
ProductionScheduleAdherenceEvents(
dataframe: DataFrame,
schedule: DataFrame,
*,
event_uuid: str = "prod:schedule_adherence",
time_column: str = "systime",
uuid_column: str = "uuid",
value_column: str = "value_double",
schedule_start_column: str = "start",
schedule_end_column: str = "end",
planned_qty_column: str = "planned_qty",
order_id_column: str = "order_id"
)
Bases: Base
Production: schedule vs. actual adherence.
The schedule is a plain DataFrame — one row per planned period::
schedule = pd.DataFrame({
"start": pd.to_datetime(["2024-05-02 06:00", "2024-05-02 14:00"]),
"end": pd.to_datetime(["2024-05-02 14:00", "2024-05-02 22:00"]),
"planned_qty": [400, 400],
"order_id": ["WO-1001", "WO-1002"],
})
adherence = ProductionScheduleAdherenceEvents(df, schedule)
adherence.adherence_by_period("counter:line-1")
Column names are configurable via the constructor, so an MES export can be passed through without renaming.
Methods: - adherence_by_period: Planned vs. actual and recovery rate per period. - deviation_events: Point events for periods breaching the deviation bands. - adherence_summary: Roll-up across the scheduled horizon.
Initialize the adherence tracker.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
dataframe
|
DataFrame
|
Timeseries frame holding the production counter. |
required |
schedule
|
DataFrame
|
Planned schedule, one row per period. |
required |
event_uuid
|
str
|
UUID stamped on emitted events. |
'prod:schedule_adherence'
|
time_column
|
str
|
Timestamp column of |
'systime'
|
uuid_column
|
str
|
Signal-identifier column of |
'uuid'
|
value_column
|
str
|
Counter-value column of |
'value_double'
|
schedule_start_column
|
str
|
Period-start column of |
'start'
|
schedule_end_column
|
str
|
Period-end column of |
'end'
|
planned_qty_column
|
str
|
Planned-quantity column of |
'planned_qty'
|
order_id_column
|
str
|
Optional order-identifier column of |
'order_id'
|
Raises:
| Type | Description |
|---|---|
TypeError
|
If |
ValueError
|
If |
adherence_by_period ¤
adherence_by_period(
counter_uuid: str,
*,
handle_resets: bool = True,
as_of: Timestamp | str | None = None,
ahead_pct: float = 105.0,
behind_pct: float = 95.0,
critical_pct: float = 80.0
) -> pd.DataFrame
Compare planned against actual production for every scheduled period.
recovery_required_rate is the units per hour the line must hold
over the time still left in the period to finish on plan, evaluated at
as_of. It is 0 for a period already at or above plan and
NaN once the period is over — a finished period cannot be
recovered, and reporting a rate for it would invite planning against a
number that means nothing.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
counter_uuid
|
str
|
Identifier of the monotonic production counter. |
required |
handle_resets
|
bool
|
Treat a decreasing counter as a reset and count the
post-reset value as new production. Default |
True
|
as_of
|
Timestamp | str | None
|
Evaluation time for the recovery rate. Defaults to the last timestamp present in the data. |
None
|
ahead_pct
|
float
|
Adherence above this is |
105.0
|
behind_pct
|
float
|
Adherence below this is |
95.0
|
critical_pct
|
float
|
Adherence below this is |
80.0
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Summary-shape DataFrame: |
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
Raises:
| Type | Description |
|---|---|
ValueError
|
If the band thresholds are not ordered
|
deviation_events ¤
deviation_events(
counter_uuid: str,
*,
handle_resets: bool = True,
as_of: Timestamp | str | None = None,
ahead_pct: float = 105.0,
behind_pct: float = 95.0,
critical_pct: float = 80.0,
include_ahead: bool = False
) -> pd.DataFrame
Emit one event per period that deviates from plan.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
counter_uuid
|
str
|
Identifier of the monotonic production counter. |
required |
handle_resets
|
bool
|
See :meth: |
True
|
as_of
|
Timestamp | str | None
|
See :meth: |
None
|
ahead_pct
|
float
|
Adherence above this is |
105.0
|
behind_pct
|
float
|
Adherence below this is |
95.0
|
critical_pct
|
float
|
Adherence below this is |
80.0
|
include_ahead
|
bool
|
Also emit rows for periods running ahead of plan. Off by default — running ahead is rarely an alert, but it is worth reporting when the plan feeds a downstream commitment. |
False
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Point-shape DataFrame: |
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
adherence_summary ¤
adherence_summary(
counter_uuid: str,
*,
handle_resets: bool = True,
as_of: Timestamp | str | None = None,
ahead_pct: float = 105.0,
behind_pct: float = 95.0,
critical_pct: float = 80.0
) -> pd.DataFrame
Roll the per-period adherence up across the scheduled horizon.
overall_adherence_pct is computed from the summed quantities, not
as the mean of the per-period percentages: a period with a planned
quantity of 10 should not weigh as much as one planning 1000.
Parameters:
| Name | Type | Description | Default |
|---|---|---|---|
counter_uuid
|
str
|
Identifier of the monotonic production counter. |
required |
handle_resets
|
bool
|
See :meth: |
True
|
as_of
|
Timestamp | str | None
|
See :meth: |
None
|
ahead_pct
|
float
|
Adherence above this is |
105.0
|
behind_pct
|
float
|
Adherence below this is |
95.0
|
critical_pct
|
float
|
Adherence below this is |
80.0
|
Returns:
| Type | Description |
|---|---|
DataFrame
|
Summary-shape DataFrame with a single row: |
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|
DataFrame
|
|