{
"cells": [
{
"cell_type": "markdown",
"id": "2ec166b9",
"metadata": {},
"source": [
"# KPI Decomposition Deep Dive\n",
"\n",
"Break down production, mobilisation, sequencing, and downtime metrics for the tiny7 scenario."
]
},
{
"cell_type": "code",
"execution_count": 1,
"id": "5f2971e1",
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-05T12:57:12.650851Z",
"iopub.status.busy": "2026-10-05T12:57:12.650745Z",
"iopub.status.idle": "2026-10-05T12:57:15.331066Z",
"shell.execute_reply": "2026-10-05T12:57:15.329925Z"
}
},
"outputs": [],
"source": [
"import sys\n",
"from pathlib import Path\n",
"\n",
"PROJECT_ROOT = Path.cwd().resolve()\n",
"while PROJECT_ROOT != PROJECT_ROOT.parent and not (PROJECT_ROOT / \"pyproject.toml\").exists():\n",
" PROJECT_ROOT = PROJECT_ROOT.parent\n",
"if not (PROJECT_ROOT / \"pyproject.toml\").exists():\n",
" raise RuntimeError(\n",
" \"Notebook must be executed within a FHOPS checkout (pyproject.toml not found).\"\n",
" )\n",
"if str(PROJECT_ROOT) not in sys.path:\n",
" sys.path.insert(0, str(PROJECT_ROOT))\n",
"\n",
"import pandas as pd\n",
"\n",
"from docs.examples.analytics import utils\n",
"from fhops.evaluation import playback_summary_metrics\n",
"from fhops.scenario.io import load_scenario\n",
"\n",
"SCENARIO = PROJECT_ROOT / \"examples/tiny7/scenario.yaml\"\n",
"ASSIGNMENTS = PROJECT_ROOT / \"tests/fixtures/playback/tiny7_assignments.csv\"\n",
"playback_tables = utils.load_deterministic_playback(SCENARIO, ASSIGNMENTS)"
]
},
{
"cell_type": "markdown",
"id": "b7f495ea",
"metadata": {},
"source": [
"## Scenario Overview"
]
},
{
"cell_type": "code",
"execution_count": 2,
"id": "d3062e03",
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-05T12:57:15.332743Z",
"iopub.status.busy": "2026-10-05T12:57:15.332586Z",
"iopub.status.idle": "2026-10-05T12:57:15.353754Z",
"shell.execute_reply": "2026-10-05T12:57:15.353281Z"
}
},
"outputs": [
{
"data": {
"text/plain": [
"samples 1.000000\n",
"total_production 17658.811008\n",
"total_hours 576.000000\n",
"mobilisation_cost 479.160000\n",
"average_utilisation 0.380952\n",
"dtype: float64"
]
},
"execution_count": 2,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"scenario = load_scenario(SCENARIO)\n",
"summary_metrics = playback_summary_metrics(playback_tables.shift, playback_tables.day)\n",
"pd.Series(summary_metrics)"
]
},
{
"cell_type": "markdown",
"id": "f1a4b6ec",
"metadata": {},
"source": [
"## Production vs Mobilisation"
]
},
{
"cell_type": "code",
"execution_count": 3,
"id": "fdf3a10c",
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-05T12:57:15.355379Z",
"iopub.status.busy": "2026-10-05T12:57:15.355241Z",
"iopub.status.idle": "2026-10-05T12:57:15.361536Z",
"shell.execute_reply": "2026-10-05T12:57:15.360852Z"
}
},
"outputs": [
{
"data": {
"text/html": [
"
\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" day | \n",
" production_units | \n",
" mobilisation_cost | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 1 | \n",
" 2007.912755 | \n",
" 0.00 | \n",
"
\n",
" \n",
" | 1 | \n",
" 2 | \n",
" 1438.086529 | \n",
" 0.00 | \n",
"
\n",
" \n",
" | 2 | \n",
" 3 | \n",
" 3193.795810 | \n",
" 53.24 | \n",
"
\n",
" \n",
" | 3 | \n",
" 4 | \n",
" 4047.344153 | \n",
" 106.48 | \n",
"
\n",
" \n",
" | 4 | \n",
" 5 | \n",
" 2969.193965 | \n",
" 106.48 | \n",
"
\n",
" \n",
" | 5 | \n",
" 6 | \n",
" 1595.687799 | \n",
" 53.24 | \n",
"
\n",
" \n",
" | 6 | \n",
" 7 | \n",
" 2406.789997 | \n",
" 159.72 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" day production_units mobilisation_cost\n",
"0 1 2007.912755 0.00\n",
"1 2 1438.086529 0.00\n",
"2 3 3193.795810 53.24\n",
"3 4 4047.344153 106.48\n",
"4 5 2969.193965 106.48\n",
"5 6 1595.687799 53.24\n",
"6 7 2406.789997 159.72"
]
},
"execution_count": 3,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"prod_metrics = playback_tables.day[[\"day\", \"production_units\", \"mobilisation_cost\"]]\n",
"prod_metrics"
]
},
{
"cell_type": "markdown",
"id": "98676f1a",
"metadata": {},
"source": [
"## Sequencing & Downtime"
]
},
{
"cell_type": "code",
"execution_count": 4,
"id": "045fb3b6",
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-05T12:57:15.362884Z",
"iopub.status.busy": "2026-10-05T12:57:15.362762Z",
"iopub.status.idle": "2026-10-05T12:57:15.368138Z",
"shell.execute_reply": "2026-10-05T12:57:15.367427Z"
}
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"
\n",
" \n",
" \n",
" | \n",
" day | \n",
" sequencing_violations | \n",
" downtime_hours | \n",
" downtime_events | \n",
"
\n",
" \n",
" \n",
" \n",
" | 0 | \n",
" 1 | \n",
" 0 | \n",
" 0.0 | \n",
" 0 | \n",
"
\n",
" \n",
" | 1 | \n",
" 2 | \n",
" 0 | \n",
" 0.0 | \n",
" 0 | \n",
"
\n",
" \n",
" | 2 | \n",
" 3 | \n",
" 0 | \n",
" 0.0 | \n",
" 0 | \n",
"
\n",
" \n",
" | 3 | \n",
" 4 | \n",
" 0 | \n",
" 0.0 | \n",
" 0 | \n",
"
\n",
" \n",
" | 4 | \n",
" 5 | \n",
" 0 | \n",
" 0.0 | \n",
" 0 | \n",
"
\n",
" \n",
" | 5 | \n",
" 6 | \n",
" 0 | \n",
" 0.0 | \n",
" 0 | \n",
"
\n",
" \n",
" | 6 | \n",
" 7 | \n",
" 0 | \n",
" 0.0 | \n",
" 0 | \n",
"
\n",
" \n",
"
\n",
"
"
],
"text/plain": [
" day sequencing_violations downtime_hours downtime_events\n",
"0 1 0 0.0 0\n",
"1 2 0 0.0 0\n",
"2 3 0 0.0 0\n",
"3 4 0 0.0 0\n",
"4 5 0 0.0 0\n",
"5 6 0 0.0 0\n",
"6 7 0 0.0 0"
]
},
"execution_count": 4,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"seq_metrics = playback_tables.day[\n",
" [\"day\", \"sequencing_violations\", \"downtime_hours\", \"downtime_events\"]\n",
"]\n",
"seq_metrics"
]
},
{
"cell_type": "markdown",
"id": "9d222853",
"metadata": {},
"source": [
"## Visualise Utilisation"
]
},
{
"cell_type": "code",
"execution_count": 5,
"id": "1566b1e1",
"metadata": {
"execution": {
"iopub.execute_input": "2026-10-05T12:57:15.369590Z",
"iopub.status.busy": "2026-10-05T12:57:15.369442Z",
"iopub.status.idle": "2026-10-05T12:57:15.392115Z",
"shell.execute_reply": "2026-10-05T12:57:15.391443Z"
}
},
"outputs": [
{
"data": {
"text/html": [
"\n",
"\n",
"\n",
""
],
"text/plain": [
"alt.Chart(...)"
]
},
"execution_count": 5,
"metadata": {},
"output_type": "execute_result"
}
],
"source": [
"chart = utils.plot_utilisation_heatmap(playback_tables.shift)\n",
"chart"
]
}
],
"metadata": {
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.11.16"
}
},
"nbformat": 4,
"nbformat_minor": 5
}