{ "cells": [ { "cell_type": "markdown", "id": "ddd4c056", "metadata": {}, "source": [ "# Landing Congestion Analysis\n", "\n", "Explore the impact of landing shock events on stochastic playback outputs for the synthetic medium scenario." ] }, { "cell_type": "code", "execution_count": 1, "id": "16d5fc8e", "metadata": { "execution": { "iopub.execute_input": "2026-10-05T12:57:04.800215Z", "iopub.status.busy": "2026-10-05T12:57:04.800096Z", "iopub.status.idle": "2026-10-05T12:57:07.907173Z", "shell.execute_reply": "2026-10-05T12:57:07.906310Z" } }, "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", "from docs.examples.analytics import utils\n", "from fhops.scenario.synthetic import SyntheticDatasetConfig, sampling_config_for\n", "\n", "SCENARIO = PROJECT_ROOT / \"examples/synthetic/medium/scenario.yaml\"\n", "ASSIGNMENTS = PROJECT_ROOT / \"docs/examples/analytics/data/synthetic_medium_sa_assignments.csv\"\n", "\n", "config = SyntheticDatasetConfig(\n", " name=\"synthetic-medium\",\n", " tier=\"medium\",\n", " num_blocks=8,\n", " num_days=12,\n", " num_machines=4,\n", ")\n", "\n", "baseline_sampling = sampling_config_for(config).model_copy()\n", "baseline_sampling.landing.enabled = False\n", "baseline_tables, baseline_sampling = utils.run_stochastic_summary(\n", " SCENARIO, ASSIGNMENTS, sampling_config=baseline_sampling\n", ")\n", "\n", "shock_sampling = baseline_sampling.model_copy()\n", "shock_sampling.landing.enabled = True\n", "shock_sampling.landing.probability = 0.3\n", "shock_sampling.landing.capacity_multiplier_range = (0.35, 0.7)\n", "shock_sampling.landing.duration_days = 3\n", "shock_tables, shock_sampling = utils.run_stochastic_summary(\n", " SCENARIO, ASSIGNMENTS, sampling_config=shock_sampling\n", ")" ] }, { "cell_type": "markdown", "id": "45420d70", "metadata": {}, "source": [ "## Baseline Ensemble Snapshot" ] }, { "cell_type": "code", "execution_count": 2, "id": "9dcd3bd4", "metadata": { "execution": { "iopub.execute_input": "2026-10-05T12:57:07.909164Z", "iopub.status.busy": "2026-10-05T12:57:07.908997Z", "iopub.status.idle": "2026-10-05T12:57:07.918025Z", "shell.execute_reply": "2026-10-05T12:57:07.917449Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
dayshift_idmachine_idmachine_rolesample_idproduction_unitstotal_hoursidle_hoursmobilisation_costsequencing_violationsblackout_conflictsavailable_hoursutilisation_ratiodowntime_hoursdowntime_eventsweather_severity_total
02S1M4forwarder05.15588.00.00.0008.01.00.000.4
18S1M1harvester015.03408.00.00.0008.01.00.000.0
22S1M1harvester112.66008.00.00.0008.01.00.000.0
38S1M1harvester19.02048.00.00.0008.01.00.000.4
42S1M4forwarder28.59308.00.00.0008.01.00.000.0
\n", "
" ], "text/plain": [ " day shift_id machine_id machine_role sample_id production_units \\\n", "0 2 S1 M4 forwarder 0 5.1558 \n", "1 8 S1 M1 harvester 0 15.0340 \n", "2 2 S1 M1 harvester 1 12.6600 \n", "3 8 S1 M1 harvester 1 9.0204 \n", "4 2 S1 M4 forwarder 2 8.5930 \n", "\n", " total_hours idle_hours mobilisation_cost sequencing_violations \\\n", "0 8.0 0.0 0.0 0 \n", "1 8.0 0.0 0.0 0 \n", "2 8.0 0.0 0.0 0 \n", "3 8.0 0.0 0.0 0 \n", "4 8.0 0.0 0.0 0 \n", "\n", " blackout_conflicts available_hours utilisation_ratio downtime_hours \\\n", "0 0 8.0 1.0 0.0 \n", "1 0 8.0 1.0 0.0 \n", "2 0 8.0 1.0 0.0 \n", "3 0 8.0 1.0 0.0 \n", "4 0 8.0 1.0 0.0 \n", "\n", " downtime_events weather_severity_total \n", "0 0 0.4 \n", "1 0 0.0 \n", "2 0 0.0 \n", "3 0 0.4 \n", "4 0 0.0 " ] }, "execution_count": 2, "metadata": {}, "output_type": "execute_result" } ], "source": [ "baseline_tables.shift.head()" ] }, { "cell_type": "markdown", "id": "12a88345", "metadata": {}, "source": [ "## Landing Shock Ensemble Snapshot" ] }, { "cell_type": "code", "execution_count": 3, "id": "97c7830c", "metadata": { "execution": { "iopub.execute_input": "2026-10-05T12:57:07.919473Z", "iopub.status.busy": "2026-10-05T12:57:07.919359Z", "iopub.status.idle": "2026-10-05T12:57:07.925913Z", "shell.execute_reply": "2026-10-05T12:57:07.925369Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
dayshift_idmachine_idmachine_rolesample_idproduction_unitstotal_hoursidle_hoursmobilisation_costsequencing_violationsblackout_conflictsavailable_hoursutilisation_ratiodowntime_hoursdowntime_eventsweather_severity_total
02S1M4forwarder05.155808.00.00.0008.01.00.000.4
18S1M1harvester015.034008.00.00.0008.01.00.000.0
22S1M1harvester112.660008.00.00.0008.01.00.000.0
38S1M1harvester19.020408.00.00.0008.01.00.000.4
42S1M4forwarder24.843388.00.00.0008.01.00.000.0
\n", "
" ], "text/plain": [ " day shift_id machine_id machine_role sample_id production_units \\\n", "0 2 S1 M4 forwarder 0 5.15580 \n", "1 8 S1 M1 harvester 0 15.03400 \n", "2 2 S1 M1 harvester 1 12.66000 \n", "3 8 S1 M1 harvester 1 9.02040 \n", "4 2 S1 M4 forwarder 2 4.84338 \n", "\n", " total_hours idle_hours mobilisation_cost sequencing_violations \\\n", "0 8.0 0.0 0.0 0 \n", "1 8.0 0.0 0.0 0 \n", "2 8.0 0.0 0.0 0 \n", "3 8.0 0.0 0.0 0 \n", "4 8.0 0.0 0.0 0 \n", "\n", " blackout_conflicts available_hours utilisation_ratio downtime_hours \\\n", "0 0 8.0 1.0 0.0 \n", "1 0 8.0 1.0 0.0 \n", "2 0 8.0 1.0 0.0 \n", "3 0 8.0 1.0 0.0 \n", "4 0 8.0 1.0 0.0 \n", "\n", " downtime_events weather_severity_total \n", "0 0 0.4 \n", "1 0 0.0 \n", "2 0 0.0 \n", "3 0 0.4 \n", "4 0 0.0 " ] }, "execution_count": 3, "metadata": {}, "output_type": "execute_result" } ], "source": [ "shock_tables.shift.head()" ] }, { "cell_type": "markdown", "id": "6854bc62", "metadata": {}, "source": [ "## KPI Comparison" ] }, { "cell_type": "code", "execution_count": 4, "id": "fb6f580b", "metadata": { "execution": { "iopub.execute_input": "2026-10-05T12:57:07.927189Z", "iopub.status.busy": "2026-10-05T12:57:07.927067Z", "iopub.status.idle": "2026-10-05T12:57:07.933625Z", "shell.execute_reply": "2026-10-05T12:57:07.933024Z" } }, "outputs": [ { "data": { "text/html": [ "
\n", "\n", "\n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", " \n", "
scenariomean_productionmean_downtime_hoursmean_utilisation
0baseline20.2660830.01.0
1landing_shock19.9298460.01.0
\n", "
" ], "text/plain": [ " scenario mean_production mean_downtime_hours mean_utilisation\n", "0 baseline 20.266083 0.0 1.0\n", "1 landing_shock 19.929846 0.0 1.0" ] }, "execution_count": 4, "metadata": {}, "output_type": "execute_result" } ], "source": [ "import pandas as pd\n", "\n", "comparison = pd.DataFrame(\n", " {\n", " \"scenario\": [\"baseline\", \"landing_shock\"],\n", " \"mean_production\": [\n", " baseline_tables.shift.groupby(\"sample_id\")[\"production_units\"].sum().mean(),\n", " shock_tables.shift.groupby(\"sample_id\")[\"production_units\"].sum().mean(),\n", " ],\n", " \"mean_downtime_hours\": [\n", " baseline_tables.shift[\"downtime_hours\"].mean(),\n", " shock_tables.shift[\"downtime_hours\"].mean(),\n", " ],\n", " \"mean_utilisation\": [\n", " baseline_tables.shift[\"utilisation_ratio\"].mean(),\n", " shock_tables.shift[\"utilisation_ratio\"].mean(),\n", " ],\n", " }\n", ")\n", "comparison" ] }, { "cell_type": "markdown", "id": "4ab289eb", "metadata": {}, "source": [ "## Production Distributions" ] }, { "cell_type": "code", "execution_count": 5, "id": "e87408e5", "metadata": { "execution": { "iopub.execute_input": "2026-10-05T12:57:07.934944Z", "iopub.status.busy": "2026-10-05T12:57:07.934832Z", "iopub.status.idle": "2026-10-05T12:57:07.949748Z", "shell.execute_reply": "2026-10-05T12:57:07.949282Z" } }, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "" ], "text/plain": [ "alt.Chart(...)" ] }, "execution_count": 5, "metadata": {}, "output_type": "execute_result" } ], "source": [ "baseline_prod = baseline_tables.shift.groupby(\"sample_id\")[\"production_units\"].sum()\n", "baseline_chart = utils.plot_distribution(\n", " baseline_prod, title=\"Baseline Production Distribution\", xlabel=\"Production Units\"\n", ")\n", "baseline_chart" ] }, { "cell_type": "code", "execution_count": 6, "id": "bafa8bd1", "metadata": { "execution": { "iopub.execute_input": "2026-10-05T12:57:07.951323Z", "iopub.status.busy": "2026-10-05T12:57:07.951181Z", "iopub.status.idle": "2026-10-05T12:57:07.957959Z", "shell.execute_reply": "2026-10-05T12:57:07.957278Z" } }, "outputs": [ { "data": { "text/html": [ "\n", "\n", "
\n", "" ], "text/plain": [ "alt.Chart(...)" ] }, "execution_count": 6, "metadata": {}, "output_type": "execute_result" } ], "source": [ "shock_prod = shock_tables.shift.groupby(\"sample_id\")[\"production_units\"].sum()\n", "shock_chart = utils.plot_distribution(\n", " shock_prod, title=\"Landing Shock Production Distribution\", xlabel=\"Production Units\"\n", ")\n", "shock_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 }