{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "9a81a49a",
   "metadata": {},
   "source": [
    "# Harvest System Mix Explorer\n",
    "\n",
    "Analyse machine-role allocation and system mixes for the synthetic medium scenario."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "858c7745",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-11-14T10:34:47.312670Z",
     "iopub.status.busy": "2025-11-14T10:34:47.311844Z",
     "iopub.status.idle": "2025-11-14T10:34:47.820933Z",
     "shell.execute_reply": "2025-11-14T10:34:47.820126Z"
    }
   },
   "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",
    "\n",
    "import pandas as pd\n",
    "import yaml\n",
    "\n",
    "from fhops.scenario.io import load_scenario\n",
    "from fhops.scenario.synthetic import SyntheticDatasetConfig, generate_random_dataset\n",
    "\n",
    "SCENARIO = PROJECT_ROOT / \"examples/synthetic/medium/scenario.yaml\"\n",
    "ASSIGNMENTS = PROJECT_ROOT / \"docs/examples/analytics/data/synthetic_medium_sa_assignments.csv\""
   ]
  },
  {
   "cell_type": "markdown",
   "id": "7e51062d",
   "metadata": {},
   "source": [
    "## System Mix Metadata"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "95f81bca",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-11-14T10:34:47.824588Z",
     "iopub.status.busy": "2025-11-14T10:34:47.824363Z",
     "iopub.status.idle": "2025-11-14T10:34:47.835662Z",
     "shell.execute_reply": "2025-11-14T10:34:47.835097Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "{}"
      ]
     },
     "execution_count": 2,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "metadata = yaml.safe_load((PROJECT_ROOT / \"examples/synthetic/metadata.yaml\").read_text())\n",
    "medium_meta = metadata[\"medium\"]\n",
    "medium_meta.get(\"system_mix\", {})"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a4cd5879",
   "metadata": {},
   "source": [
    "## Machine Roles in Scenario"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "5a009dc3",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-11-14T10:34:47.838635Z",
     "iopub.status.busy": "2025-11-14T10:34:47.838491Z",
     "iopub.status.idle": "2025-11-14T10:34:47.875139Z",
     "shell.execute_reply": "2025-11-14T10:34:47.874246Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "role\n",
       "harvester    2\n",
       "forwarder    2\n",
       "Name: count, dtype: int64"
      ]
     },
     "execution_count": 3,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "scenario = load_scenario(SCENARIO)\n",
    "roles = pd.Series([machine.role or \"unassigned\" for machine in scenario.machines], name=\"role\")\n",
    "roles.value_counts()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f3badfd0",
   "metadata": {},
   "source": [
    "## Generate Custom Mix"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "653747c1",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-11-14T10:34:47.878538Z",
     "iopub.status.busy": "2025-11-14T10:34:47.878399Z",
     "iopub.status.idle": "2025-11-14T10:34:47.885895Z",
     "shell.execute_reply": "2025-11-14T10:34:47.885329Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/plain": [
       "role\n",
       "harvester    3\n",
       "forwarder    3\n",
       "Name: count, dtype: int64"
      ]
     },
     "execution_count": 4,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "custom_config = SyntheticDatasetConfig(\n",
    "    name=\"synthetic-mix-demo\",\n",
    "    tier=\"large\",\n",
    "    num_blocks=12,\n",
    "    num_days=16,\n",
    "    num_machines=6,\n",
    "    system_mix={\"ground_fb_skid\": 0.5, \"ctl\": 0.3, \"steep_tethered\": 0.2},\n",
    ")\n",
    "bundle = generate_random_dataset(custom_config, seed=404)\n",
    "custom_roles = bundle.machines[\"role\"].fillna(\"unassigned\")\n",
    "custom_roles.value_counts()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "05c8313f",
   "metadata": {},
   "source": [
    "## Role Comparison"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "f25034bc",
   "metadata": {
    "execution": {
     "iopub.execute_input": "2025-11-14T10:34:47.888805Z",
     "iopub.status.busy": "2025-11-14T10:34:47.888650Z",
     "iopub.status.idle": "2025-11-14T10:34:47.895819Z",
     "shell.execute_reply": "2025-11-14T10:34:47.895222Z"
    }
   },
   "outputs": [
    {
     "data": {
      "text/html": [
       "<div>\n",
       "<style scoped>\n",
       "    .dataframe tbody tr th:only-of-type {\n",
       "        vertical-align: middle;\n",
       "    }\n",
       "\n",
       "    .dataframe tbody tr th {\n",
       "        vertical-align: top;\n",
       "    }\n",
       "\n",
       "    .dataframe thead th {\n",
       "        text-align: right;\n",
       "    }\n",
       "</style>\n",
       "<table border=\"1\" class=\"dataframe\">\n",
       "  <thead>\n",
       "    <tr style=\"text-align: right;\">\n",
       "      <th></th>\n",
       "      <th>scenario_roles</th>\n",
       "      <th>custom_mix_roles</th>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>role</th>\n",
       "      <th></th>\n",
       "      <th></th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>harvester</th>\n",
       "      <td>2</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>forwarder</th>\n",
       "      <td>2</td>\n",
       "      <td>3</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "           scenario_roles  custom_mix_roles\n",
       "role                                       \n",
       "harvester               2                 3\n",
       "forwarder               2                 3"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "comparison_df = pd.DataFrame(\n",
    "    {\"scenario_roles\": roles.value_counts(), \"custom_mix_roles\": custom_roles.value_counts()}\n",
    ").fillna(0)\n",
    "comparison_df"
   ]
  }
 ],
 "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.12.3"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
