{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 68,
   "metadata": {},
   "outputs": [],
   "source": [
    "#https://umrs.org.ua/activities/conferences/hmt-2025/abstract-guidelines/\n",
    "import pandas as pd\n",
    "import matplotlib.pyplot as plt\n",
    "import sklearn\n",
    "import numpy as np"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 69,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Material and mold constants\n",
    "MOLD_DIAMETER_MM = 20\n",
    "MAX_THEORETICAL_DENSITY = 5.43  # g/cm³ for TiN\n",
    "mold_area_mm2 = 3.14 * MOLD_DIAMETER_MM * MOLD_DIAMETER_MM / 4\n",
    "\n",
    "def calculate_relative_density(\n",
    "        travel,\n",
    "        weight,  # in grams\n",
    "        measuredDensity,  # in g/cm^3\n",
    "        totalTravel,\n",
    "        maxTemperature):\n",
    "    \n",
    "    # Calculate final sample dimensions from measured density\n",
    "    final_volume_cm3 = weight / measuredDensity\n",
    "    final_volume_mm3 = final_volume_cm3 * 1000\n",
    "    final_height_mm = final_volume_mm3 / mold_area_mm2\n",
    "    \n",
    "    # Calculate initial height (before sintering started)\n",
    "    initial_height_mm = (totalTravel / 1000) + final_height_mm\n",
    "    \n",
    "    # Calculate current height based on piston travel\n",
    "    current_height_mm = initial_height_mm - (travel / 1000)\n",
    "    \n",
    "    # Calculate current volume and density\n",
    "    current_volume_mm3 = mold_area_mm2 * current_height_mm\n",
    "    current_volume_cm3 = current_volume_mm3 / 1000\n",
    "    current_density_g_cm3 = weight / current_volume_cm3\n",
    "    \n",
    "    # Convert to relative density (percentage of theoretical maximum)\n",
    "    relative_density_percent = (current_density_g_cm3 / MAX_THEORETICAL_DENSITY) * 100\n",
    "    \n",
    "    return relative_density_percent\n",
    "\n",
    "\n",
    "def calculate_density_for_series(travel, series):\n",
    "    total_travel = series['TravelRelativeTempCorrected'].max() - series['TravelRelativeTempCorrected'].min()\n",
    "    max_temp = series['Pyrometer'].max()\n",
    "    \n",
    "    return calculate_relative_density(\n",
    "        travel,\n",
    "        series.attrs['weight'],\n",
    "        series.attrs['measuredDensity'],\n",
    "        total_travel,\n",
    "        max_temp\n",
    "    )\n",
    "\n",
    "\n",
    "def calculate_densityForVirtualExperiment(\n",
    "        travel,\n",
    "        weight,  # in grams\n",
    "        relative_start_density,  # in %\n",
    "    ):\n",
    "    # Convert relative density to absolute density\n",
    "    absolute_start_density_g_cm3 = (relative_start_density / 100) * MAX_THEORETICAL_DENSITY\n",
    "    \n",
    "    # Calculate initial sample dimensions from starting density\n",
    "    initial_volume_cm3 = weight / absolute_start_density_g_cm3\n",
    "    initial_volume_mm3 = initial_volume_cm3 * 1000\n",
    "    initial_height_mm = initial_volume_mm3 / mold_area_mm2\n",
    "    \n",
    "    # Calculate current height after piston travel\n",
    "    current_height_mm = initial_height_mm - (travel / 1000)\n",
    "    \n",
    "    # Calculate current volume and density\n",
    "    current_volume_mm3 = mold_area_mm2 * current_height_mm\n",
    "    current_volume_cm3 = current_volume_mm3 / 1000\n",
    "    current_density_g_cm3 = weight / current_volume_cm3\n",
    "    \n",
    "    # Convert to relative density (percentage of theoretical maximum)\n",
    "    relative_density_percent = (current_density_g_cm3 / MAX_THEORETICAL_DENSITY) * 100\n",
    "    \n",
    "    return relative_density_percent\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 70,
   "metadata": {},
   "outputs": [],
   "source": [
    "def filter_data(df):\n",
    "    # Convert time to timedelta format\n",
    "    df['P.Zeit'] = pd.to_timedelta(df['P.Zeit'])\n",
    "    \n",
    "    # Filter out low temperature and low current readings\n",
    "    df = df[df['Pyrometer'] > 500].copy()\n",
    "    df = df[df['I RMS'] > 0.2].copy()\n",
    "    \n",
    "    # Calculate relative piston travel in micrometers\n",
    "    min_piston_travel = df['Abs Piston Tra.'].min()\n",
    "    df['TravelRelative'] = ((df['Abs Piston Tra.'] - min_piston_travel) * 1000).astype(int)\n",
    "    \n",
    "    # Smooth the travel data using cumulative maximum\n",
    "    df['TravelRelativeCorrected'] = np.maximum.accumulate(df['TravelRelative'])\n",
    "    df['TravelRelativeCorrected'] = df['TravelRelativeCorrected'].rolling(window=6).mean()\n",
    "    df.loc[pd.isnull(df['TravelRelativeCorrected']), 'TravelRelativeCorrected'] = 0\n",
    "    \n",
    "    # Apply thermal expansion correction (1.241 μm/°C)\n",
    "    min_temperature = df['Pyrometer'].min()\n",
    "    thermal_expansion_coefficient = 1.241  # μm/°C\n",
    "    temperature_delta = df['Pyrometer'] - min_temperature\n",
    "    df['TravelRelativeTempCorrected'] = df['TravelRelativeCorrected'] + (temperature_delta * thermal_expansion_coefficient)\n",
    "    \n",
    "    # Convert time to seconds\n",
    "    df['seconds'] = df['P.Zeit'].dt.total_seconds().astype(int)\n",
    "    df = df.drop(columns=['P.Zeit'])\n",
    " \n",
    "    # Downsample: keep every 10th row to reduce data size\n",
    "    #df = df.iloc[::10]\n",
    "    \n",
    "    # Calculate original travel delta for comparison\n",
    "    df['TravelDeltaOriginal'] = df['Abs Piston Tra.'] - df['Abs Piston Tra.'].shift(1)\n",
    "    \n",
    "    # Calculate shifted values for next time step prediction\n",
    "    df['TravelRelativeCorrectedShifted'] = df['TravelRelativeCorrected'].shift(-1)\n",
    "    df['TravelRelativeCorrectedShifted'] = df['TravelRelativeCorrectedShifted'].fillna(0)\n",
    "    df['TravelRelativeTempCorrectedShifted'] = df['TravelRelativeTempCorrected'].shift(-1)\n",
    "    df['PyrometerShifted'] = df['Pyrometer'].shift(-1)\n",
    "    \n",
    "    # Calculate travel deltas (densification rates)\n",
    "    df['TravelDelta'] = df['TravelRelativeTempCorrectedShifted'] - df['TravelRelativeTempCorrected']\n",
    "    df['TravelDelta2'] = df['TravelRelativeCorrectedShifted'] - df['TravelRelativeCorrected']\n",
    "    df.loc[pd.isnull(df['TravelDelta']), 'TravelDelta'] = 0\n",
    "\n",
    "         \n",
    "    # --- Trim initial data until piston travel rate exceeds threshold ---\n",
    "    piston_rate_threshold_um_s = 27.0  # μm/s (start threshold)\n",
    "    piston_rate_end_threshold_um_s = 10.0  # μm/s (end/drop threshold)\n",
    "    # Determine indices where piston rate is above each threshold\n",
    "    mask_start = df['TravelDelta'] > piston_rate_threshold_um_s\n",
    "    mask_end = df['TravelDelta'] > piston_rate_end_threshold_um_s\n",
    "    first_idx = None\n",
    "    last_idx = None\n",
    "    if mask_start.any():\n",
    "        first_idx = mask_start.idxmax()\n",
    "    if mask_end.any():\n",
    "        # last index where rate stays above end-threshold\n",
    "        end_indices = mask_end[mask_end].index\n",
    "        if len(end_indices) > 0:\n",
    "            last_idx = end_indices[-1]\n",
    "    # Apply trimming logic based on discovered indices\n",
    "    if first_idx is not None and last_idx is not None:\n",
    "        if first_idx <= last_idx:\n",
    "            df = df.loc[first_idx:last_idx].copy()\n",
    "        else:\n",
    "            # If indices are inconsistent, keep from first_idx to end\n",
    "            df = df.loc[first_idx:].copy()\n",
    "    elif first_idx is not None:\n",
    "        df = df.loc[first_idx:].copy()\n",
    "    elif last_idx is not None:\n",
    "        df = df.loc[:last_idx].copy()\n",
    "    else:\n",
    "        print(f'Warning: piston rate did not cross either threshold ({piston_rate_threshold_um_s} or {piston_rate_end_threshold_um_s} μm/s); returning filtered data as-is')\n",
    "    # -----------------------------------------------------------------\n",
    "   \n",
    "   # Normalize piston travel to start from zero\n",
    "    min_piston_travel = df['TravelRelativeCorrected'].min()\n",
    "    df['TravelRelativeCorrected'] = df['TravelRelativeCorrected'] - min_piston_travel\n",
    "    min_piston_travel_temp = df['TravelRelativeTempCorrected'].min()\n",
    "    df['TravelRelativeTempCorrected'] = df['TravelRelativeTempCorrected'] - min_piston_travel_temp\n",
    "    \n",
    "    df['TravelRelativeCorrectedShifted'] = df['TravelRelativeCorrected'].shift(-1)\n",
    "    df['TravelRelativeCorrectedShifted'] = df['TravelRelativeCorrectedShifted'].fillna(0)\n",
    "    df['TravelRelativeTempCorrectedShifted'] = df['TravelRelativeTempCorrected'].shift(-1)\n",
    "\n",
    "    # Normalize time to start from 1 second\n",
    "    min_seconds = df['seconds'].min()\n",
    "    df['seconds'] = df['seconds'] - min_seconds + 1\n",
    "\n",
    "    \n",
    "    # Calculate relative density\n",
    "    df['Density'] = calculate_density_for_series(df['TravelRelativeTempCorrected'], df)\n",
    "    \n",
    "    # Remove last row (has no valid shifted values)\n",
    "    df = df.drop(df.index[-1])\n",
    "    \n",
    "    return df\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 71,
   "metadata": {},
   "outputs": [],
   "source": [
    "# Load experimental data into a dictionary\n",
    "experiments = {\n",
    "    '100_1500_32_ann': {\n",
    "        'file': 'TiN-Starck-0/1483.csv',\n",
    "        'measuredDensity': 4.92,\n",
    "        'weight': 6.5\n",
    "    },\n",
    "    '100_1500_32': {\n",
    "        'file': 'TiN-Starck-0/1500.csv',\n",
    "        'measuredDensity': 4.94,\n",
    "        'weight': 6.5\n",
    "    },\n",
    "    '100_1500_50': {\n",
    "        'file': 'TiN-Starck-0/1471.csv',\n",
    "        'measuredDensity': 5.12,\n",
    "        'weight': 6.47\n",
    "    },\n",
    "    '100_1500_70': {\n",
    "        'file': 'TiN-Starck-0/1499.csv',\n",
    "        'measuredDensity': 5.12,\n",
    "        'weight': 6.5\n",
    "    },\n",
    "    '200_1500_32': {\n",
    "        'file': 'TiN-Starck-0/1460.csv',\n",
    "        'measuredDensity': 4.94,\n",
    "        'weight': 6.5\n",
    "    },\n",
    "    '200_1600_50': {\n",
    "        'file': 'TiN-Starck-0/1459.csv',\n",
    "        'measuredDensity': 5.11,\n",
    "        'weight': 6.5\n",
    "    },\n",
    "    '200_1500_70': {\n",
    "        'file': 'TiN-Starck-0/1468.csv',\n",
    "        'measuredDensity': 5.12,\n",
    "        'weight': 6.2\n",
    "    },\n",
    "    '200_1500_70_noBn': {\n",
    "        'file': 'TiN-Starck-0/1469.csv',\n",
    "        'measuredDensity': 4.93,\n",
    "        'weight': 6.2\n",
    "    }\n",
    "}\n",
    "\n",
    "# Load and process all data\n",
    "data = {}\n",
    "original_data = {}\n",
    "for key, exp in experiments.items():\n",
    "    df = pd.read_csv(exp['file'], sep=';', decimal=',')\n",
    "    df.attrs['measuredDensity'] = exp['measuredDensity']\n",
    "    df.attrs['weight'] = exp['weight']\n",
    "    data[key] = filter_data(df)\n",
    "    original_data[key] = df.copy()\n",
    "    #print(data[key]['TravelRelativeCorrected'].max()- data[key]['TravelRelativeCorrected'].min())\n",
    "    #print(data[key]['TravelRelativeTempCorrected'].max()- data[key]['TravelRelativeTempCorrected'].min())\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 72,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 133144 characters]",
      "text/plain": [
       "<Figure size 1200x800 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# write a code to plot time vs piston travel for all experiments in original_data\n",
    "plt.figure(figsize=(12, 8))\n",
    "for key, df in original_data.items():\n",
    "    plt.plot(df['P.Zeit'], df['Abs Piston Tra.'], label=key)\n",
    "plt.xlabel('Time')\n",
    "plt.ylabel('Piston Travel (mm)')\n",
    "plt.title('Time vs Piston Travel for All Experiments')\n",
    "plt.ylim(33, 44)\n",
    "plt.grid(True)\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 73,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 4000x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 331116 characters]",
      "text/plain": [
       "<Figure size 2000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(40, 6))\n",
    "fig, ax1 = plt.subplots( figsize=(20, 6))\n",
    "for key in data.keys():\n",
    "    ax1.plot(data[key]['Density'], data[key]['TravelDelta'])\n",
    "# Add color bar to show the color scale\n",
    "ax1.set_ylabel('Швидкість ущільнення')\n",
    "#ax1.set_ylim(400, 1000)\n",
    "ax1.set_xlim(30, 100)\n",
    "#ax1.set_title('title')\n",
    "ax1.set_xlabel('Відносна щільність')\n",
    "ax1.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 74,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 4000x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 188808 characters]",
      "text/plain": [
       "<Figure size 2000x1000 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(40, 6))\n",
    "fig, ax1 = plt.subplots( figsize=(20, 10))\n",
    "for key in data.keys():\n",
    "    ax1.plot(data[key]['seconds'], data[key]['TravelRelativeTempCorrected'], label=key)\n",
    "ax1.set_ylabel('Хід поршня (μm)')\n",
    "ax1.set_xlabel('час, с')\n",
    "ax1.grid(True)\n",
    "plt.legend()\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 75,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 4000x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 184616 characters]",
      "text/plain": [
       "<Figure size 2000x1000 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(40, 6))\n",
    "fig, ax1 = plt.subplots( figsize=(20, 10))\n",
    "for key in data.keys():\n",
    "    ax1.plot(data[key]['seconds'], data[key]['Pyrometer'], label=key)\n",
    "ax1.set_ylabel('температура (°C)')\n",
    "ax1.set_xlabel('час, с')\n",
    "ax1.grid(True)\n",
    "plt.legend()\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 76,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_data_Seconds(data, title):\n",
    "    setToPlot = data.copy()\n",
    "    plt.figure(figsize=(40, 6))\n",
    "    fig, ax1 = plt.subplots( figsize=(40, 6))\n",
    "    fig, ax2 = plt.subplots( figsize=(40, 6))\n",
    "    fig, ax3 = plt.subplots( figsize=(40, 6))\n",
    "    fig, ax4 = plt.subplots( figsize=(40, 6))\n",
    "    fig, ax5 = plt.subplots( figsize=(40, 6))\n",
    "    fig, ax6 = plt.subplots( figsize=(40, 6))\n",
    "    sc2 = ax1.plot(setToPlot['seconds'], setToPlot['Force'], color='black')\n",
    "    sc2 = ax2.plot(setToPlot['seconds'], setToPlot['TravelRelativeTempCorrected'], color='green')\n",
    "    sc2 = ax2.plot(setToPlot['seconds'], setToPlot['TravelRelative'], color='blue')\n",
    "    sc2 = ax3.plot(setToPlot['seconds'], setToPlot['Pyrometer'], color='orange')\n",
    "    sc2 = ax4.plot(setToPlot['seconds'], setToPlot['Power'], color='red')\n",
    "    sc2 = ax4.plot(setToPlot['seconds'], setToPlot['U RMS'], color='orange')\n",
    "    sc2 = ax4.plot(setToPlot['seconds'], setToPlot['I RMS'], color='purple')\n",
    "    sc2 = ax4.plot(setToPlot['seconds'], setToPlot['U RMS']/setToPlot['I RMS'], color='black')\n",
    "    sc2 = ax5.plot(setToPlot['seconds'], setToPlot['Density'], color='black')\n",
    "    sc2 = ax6.plot(setToPlot['seconds'], setToPlot['TravelDelta'], color='black')\n",
    "\n",
    "    ax4.set_ylim(0,10)\n",
    "    ax1.set_ylabel('Force')\n",
    "    ax2.set_ylabel('TravelRelativeTempCorrected')\n",
    "    ax3.set_ylabel('Pyrometer')\n",
    "    ax4.set_ylabel('Power')\n",
    "    ax5.set_ylabel('Density')\n",
    "    ax6.set_ylabel('TravelDelta')\n",
    "    ax1.grid(True)\n",
    "    ax2.grid(True)\n",
    "    ax3.grid(True)\n",
    "    ax4.grid(True)\n",
    "    ax5.grid(True)\n",
    "    ax6.grid(True)\n",
    "    ax1.set_title(title)\n",
    "    ax2.set_title(title)\n",
    "    ax3.set_title(title)\n",
    "    ax4.set_title(title)\n",
    "    ax5.set_title(title)\n",
    "    ax6.set_title(title)\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 4000x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 24452 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 73548 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 52292 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 99156 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 50040 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 160108 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 4000x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 23708 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 73272 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 53176 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 103836 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 50576 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 164716 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 4000x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 29848 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 69036 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 50332 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 96088 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 50216 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 152616 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 4000x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 25128 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 65144 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 48232 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 87288 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 54092 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 159304 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 4000x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 25208 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 75280 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 52068 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 87828 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 52436 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 139732 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 4000x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 30424 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 75004 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 53760 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 139848 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 52016 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 146880 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 4000x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 25332 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 71460 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 51832 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 131428 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 51416 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 145644 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 4000x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 26452 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 72572 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 52648 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 133320 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 52068 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 145924 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "for key in data.keys():\n",
    "    plot_data_Seconds(data[key], key)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 78,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 2000x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 194552 characters]",
      "text/plain": [
       "<Figure size 3000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(20, 6))\n",
    "fig, ax1 = plt.subplots( figsize=(30, 6))\n",
    "#sc = ax1.plot(data900['seconds'], data900['TravelDelta'], color='red')  \n",
    "#sc = ax1.plot(data1000['seconds'], data1000['TravelDelta'], color='green') \n",
    "sc = ax1.plot(data['100_1500_32']['seconds'], data['100_1500_32']['TravelDeltaOriginal']*1000, color='gray') \n",
    "sc = ax1.plot(data['100_1500_32']['seconds'], data['100_1500_32']['TravelDelta2'], color='red') \n",
    "ax1.set_ylabel('Швидкість ходу поршня, μm/с')\n",
    "#ax1.set_ylim(400, 1000)\n",
    "#ax1.set_xlim(300, 1400)\n",
    "ax1.set_title('Швидкість ходу поршня до і після усереднення')\n",
    "ax1.set_xlabel('час, с')\n",
    "ax1.grid(True)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 79,
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_data_TravelDelta(data, title):\n",
    "    setToPlot = data.copy()\n",
    "\n",
    "    plt.figure(figsize=(40, 6))\n",
    "    fig, ax1 = plt.subplots( figsize=(40, 6))\n",
    "    sc = ax1.plot(setToPlot['Pyrometer'], setToPlot['TravelDelta'], color='red')  \n",
    "    ax1.set_ylabel('TravelDelta')\n",
    "    ax1.set_title(title)\n",
    "    ax1.set_xlabel('Pyrometer')\n",
    "    ax1.grid(True)\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 80,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 4000x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 123344 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plot_data_TravelDelta(data['100_1500_32'], 'data100_1500_32')\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 81,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Kernel: 1**2 * RBF(length_scale=1) -> test MSE: 20.616154\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\Users\\arros\\miniconda3\\envs\\SPS\\Lib\\site-packages\\sklearn\\gaussian_process\\kernels.py:450: ConvergenceWarning: The optimal value found for dimension 0 of parameter k1__constant_value is close to the specified upper bound 1000000.0. Increasing the bound and calling fit again may find a better value.\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Kernel: 1**2 * Matern(length_scale=1, nu=1.5) -> test MSE: 13.887882\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\Users\\arros\\miniconda3\\envs\\SPS\\Lib\\site-packages\\sklearn\\gaussian_process\\_gpr.py:663: ConvergenceWarning: lbfgs failed to converge after 31 iteration(s) (status=2):\n",
      "ABNORMAL: \n",
      "\n",
      "You might also want to scale the data as shown in:\n",
      "    https://scikit-learn.org/stable/modules/preprocessing.html\n",
      "  _check_optimize_result(\"lbfgs\", opt_res)\n",
      "c:\\Users\\arros\\miniconda3\\envs\\SPS\\Lib\\site-packages\\sklearn\\gaussian_process\\kernels.py:450: ConvergenceWarning: The optimal value found for dimension 0 of parameter k1__constant_value is close to the specified upper bound 1000000.0. Increasing the bound and calling fit again may find a better value.\n",
      "  warnings.warn(\n",
      "c:\\Users\\arros\\miniconda3\\envs\\SPS\\Lib\\site-packages\\sklearn\\gaussian_process\\kernels.py:450: ConvergenceWarning: The optimal value found for dimension 0 of parameter k2__alpha is close to the specified upper bound 100000.0. Increasing the bound and calling fit again may find a better value.\n",
      "  warnings.warn(\n",
      "c:\\Users\\arros\\miniconda3\\envs\\SPS\\Lib\\site-packages\\sklearn\\gaussian_process\\kernels.py:450: ConvergenceWarning: The optimal value found for dimension 0 of parameter k1__constant_value is close to the specified upper bound 1000000.0. Increasing the bound and calling fit again may find a better value.\n",
      "  warnings.warn(\n",
      "c:\\Users\\arros\\miniconda3\\envs\\SPS\\Lib\\site-packages\\sklearn\\gaussian_process\\kernels.py:450: ConvergenceWarning: The optimal value found for dimension 0 of parameter k2__alpha is close to the specified upper bound 100000.0. Increasing the bound and calling fit again may find a better value.\n",
      "  warnings.warn(\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Kernel: 1**2 * RationalQuadratic(alpha=0.1, length_scale=1) -> test MSE: 43.311816\n",
      "Kernel: 1**2 * ExpSineSquared(length_scale=1, periodicity=3) -> test MSE: 2192807.782144\n",
      "Kernel: 1**2 * ExpSineSquared(length_scale=1, periodicity=3) -> test MSE: 2192807.782144\n",
      "Kernel: 1**2 * DotProduct(sigma_0=1) -> test MSE: 42.501157\n",
      "Best kernel selected: 1**2 * Matern(length_scale=1, nu=1.5) with MSE 13.887882\n",
      "Mean Squared Error (best model on test set): 13.887882\n",
      "Kernel: 1**2 * DotProduct(sigma_0=1) -> test MSE: 42.501157\n",
      "Best kernel selected: 1**2 * Matern(length_scale=1, nu=1.5) with MSE 13.887882\n",
      "Mean Squared Error (best model on test set): 13.887882\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "c:\\Users\\arros\\miniconda3\\envs\\SPS\\Lib\\site-packages\\sklearn\\gaussian_process\\kernels.py:440: ConvergenceWarning: The optimal value found for dimension 0 of parameter k2__sigma_0 is close to the specified lower bound 1e-05. Decreasing the bound and calling fit again may find a better value.\n",
      "  warnings.warn(\n"
     ]
    }
   ],
   "source": [
    "from sklearn.gaussian_process import GaussianProcessRegressor\n",
    "from sklearn.gaussian_process.kernels import RBF, Matern, RationalQuadratic, ExpSineSquared, DotProduct, ConstantKernel as C\n",
    "from sklearn.model_selection import train_test_split\n",
    "from sklearn.metrics import mean_squared_error\n",
    "from sklearn.preprocessing import StandardScaler\n",
    "from sklearn.pipeline import Pipeline\n",
    "from sklearn.compose import TransformedTargetRegressor\n",
    "\n",
    "# Concatenate all experiments into a single dataset\n",
    "D = pd.concat([data[key] for key in data.keys()], axis=0)\n",
    "\n",
    "# Select features and target\n",
    "X = D[['seconds','TravelRelativeTempCorrected', 'Pyrometer','PyrometerShifted','Force','Density']].copy()\n",
    "y = D['TravelRelativeTempCorrectedShifted'].copy()\n",
    "\n",
    "# Drop rows with missing target or features\n",
    "mask = y.notna() & X.notnull().all(axis=1)\n",
    "X = X[mask]\n",
    "y = y[mask]\n",
    "\n",
    "# Split into train / test sets (hold out 20% for evaluation)\n",
    "X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.20, random_state=42, shuffle=True)\n",
    "\n",
    "# Define candidate kernels with sensible bounds (scaling will help hyperparameters)\n",
    "kernels = [\n",
    "   C(1.0, (1e-6, 1e6)) * RBF(length_scale=1.0, length_scale_bounds=(1e-5, 1e5)),\n",
    "   C(1.0, (1e-6, 1e6)) * Matern(length_scale=1.0, length_scale_bounds=(1e-5,1e5), nu=1.5),\n",
    "   C(1.0, (1e-6, 1e6)) * RationalQuadratic(length_scale=1.0, length_scale_bounds=(1e-5,1e5), alpha=0.1),\n",
    "   C(1.0, (1e-6, 1e6)) * ExpSineSquared(length_scale=1.0, length_scale_bounds=(1e-5,1e5), periodicity=3.0, periodicity_bounds=(1e-3,1e3)),\n",
    "   C(1.0, (1e-6, 1e6)) * DotProduct(sigma_0=1.0)\n",
    "]\n",
    "\n",
    "# Helper wrapper to provide predict(..., return_std=True) using fitted scalers + GPR\n",
    "class WrappedGPR:\n",
    "    def __init__(self, x_scaler, gpr, y_scaler):\n",
    "        self.x_scaler = x_scaler\n",
    "        self.gpr = gpr\n",
    "        self.y_scaler = y_scaler\n",
    "    def predict(self, X, return_std=False):\n",
    "        import numpy as _np\n",
    "        import pandas as _pd\n",
    "\n",
    "        # If input is a DataFrame, preserve it so feature names are kept\n",
    "        if isinstance(X, _pd.DataFrame):\n",
    "            X_for_transform = X\n",
    "        else:\n",
    "            # Convert arrays/lists to numpy array first\n",
    "            X_arr = X.values if hasattr(X, 'values') else _np.asarray(X)\n",
    "            # If scaler was fitted on a DataFrame, recreate DataFrame with recorded names\n",
    "            if hasattr(self.x_scaler, 'feature_names_in_'):\n",
    "                X_for_transform = _pd.DataFrame(X_arr, columns=self.x_scaler.feature_names_in_)\n",
    "            else:\n",
    "                X_for_transform = X_arr\n",
    "\n",
    "        # Transform inputs with the fitted scaler (accepts DataFrame or ndarray)\n",
    "        Xs = self.x_scaler.transform(X_for_transform)\n",
    "\n",
    "        if return_std:\n",
    "            y_pred_s, y_std_s = self.gpr.predict(Xs, return_std=True)\n",
    "            y_pred = self.y_scaler.inverse_transform(y_pred_s.reshape(-1, 1)).ravel()\n",
    "            # Try to scale std back to original units if transformer exposes scale_\n",
    "            try:\n",
    "                y_std = y_std_s * self.y_scaler.scale_[0]\n",
    "            except Exception:\n",
    "                y_std = y_std_s\n",
    "            return y_pred, y_std\n",
    "        else:\n",
    "            y_pred_s = self.gpr.predict(Xs)\n",
    "            y_pred = self.y_scaler.inverse_transform(y_pred_s.reshape(-1, 1)).ravel()\n",
    "            return y_pred\n",
    "\n",
    "# Try each kernel inside a small pipeline that scales X and the target, evaluate on held-out test set\n",
    "best_mse = float('inf')\n",
    "best_kernel = None\n",
    "best_wrapped = None\n",
    "results = []\n",
    "# Keep optimizer restarts moderate for better tuning without huge runtime\n",
    "for k in kernels:\n",
    "    try:\n",
    "        # Base GPR that will be trained on scaled inputs\n",
    "        gpr_base = GaussianProcessRegressor(kernel=k, n_restarts_optimizer=10, alpha=1e-3, random_state=42)\n",
    "        reg_pipeline = Pipeline([('scaler', StandardScaler()), ('gpr', gpr_base)])\n",
    "        # Transform target (scale) so optimizer sees normalized y\n",
    "        model = TransformedTargetRegressor(regressor=reg_pipeline, transformer=StandardScaler())\n",
    "        model.fit(X_train, y_train)\n",
    "        # Get predictions on raw X_test (model handles transforms)\n",
    "        y_pred_k = model.predict(X_test)\n",
    "        mse_k = mean_squared_error(y_test, y_pred_k)\n",
    "        results.append((k, mse_k))\n",
    "        print(f'Kernel: {k} -> test MSE: {mse_k:.6f}')\n",
    "        if mse_k < best_mse:\n",
    "            best_mse = mse_k\n",
    "            best_kernel = k\n",
    "            # extract fitted components to build wrapper that supports return_std\n",
    "            fitted_x_scaler = model.regressor_.named_steps['scaler']\n",
    "            fitted_gpr = model.regressor_.named_steps['gpr']\n",
    "            fitted_y_scaler = model.transformer_\n",
    "            best_wrapped = WrappedGPR(fitted_x_scaler, fitted_gpr, fitted_y_scaler)\n",
    "    except Exception as e:\n",
    "        print(f'Kernel training failed for {k}: {e}')\n",
    "\n",
    "if best_wrapped is None:\n",
    "    raise RuntimeError('All kernel fits failed — check data or reduce kernel complexity')\n",
    "\n",
    "# Expose the wrapped model as `gpr` for downstream code (supports return_std)\n",
    "gpr = best_wrapped\n",
    "print(f'Best kernel selected: {best_kernel} with MSE {best_mse:.6f}')\n",
    "\n",
    "# Predictions and evaluation (for downstream plotting) — use wrapper to get mean\n",
    "y_pred = gpr.predict(X_test)\n",
    "mse = mean_squared_error(y_test, y_pred)\n",
    "print(f'Mean Squared Error (best model on test set): {mse:.6f}')\n",
    "\n",
    "# Reset indices so plotting code downstream works as expected\n",
    "X_test = X_test.reset_index(drop=True)\n",
    "y_test = y_test.reset_index(drop=True)\n",
    "y_pred = pd.Series(y_pred)\n"
   ]
  },
  {
   "cell_type": "markdown",
   "metadata": {},
   "source": []
  },
  {
   "cell_type": "code",
   "execution_count": 82,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1500x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 116580 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(15, 6))\n",
    "fig, ax1 = plt.subplots( figsize=(15, 6))\n",
    "for key in data.keys():\n",
    "    ax1.plot(data[key]['seconds'], data[key]['TravelRelativeTempCorrectedShifted'], color='grey')\n",
    "sc = ax1.plot(X_test['seconds'], y_pred, color='red', linestyle='None', marker='o', markersize=4)\n",
    "ax1.set_title('Поріваняння передбаченого моделлю ходу поршня з реальними даними')\n",
    "ax1.set_xlabel('час, с')\n",
    "ax1.set_ylabel('хід поршня, μм')\n",
    "ax1.grid(True)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 179,
   "metadata": {},
   "outputs": [],
   "source": [
    "max_rate = 32\n",
    "start_rate=25\n",
    "\n",
    "def calculate_TargetDensificationRateValue(value):\n",
    "    \n",
    "    value = value / 100\n",
    "    if value < 0.40:\n",
    "        return start_rate\n",
    "    elif 0.40 <= value < 0.65:\n",
    "        # Лінійне зростання від 20 до max_rate\n",
    "        return ((value - 0.40) / (0.65 - 0.40) * (max_rate - start_rate)) + start_rate\n",
    "\n",
    "    elif 0.65 <= value < 0.75:\n",
    "        return max_rate\n",
    "    elif 0.75 <= value < 0.97:\n",
    "        # Лінійне зменшення від max_rate/2 до 0\n",
    "        return (0.97 - value) / (0.97 - 0.75) * (max_rate/2)\n",
    "    else:\n",
    "        return 0\n",
    "\n",
    "def calculate_TargetDensificationRate(column):\n",
    "    result = []\n",
    "    for value in column:\n",
    "        result.append(calculate_TargetDensificationRateValue(value))\n",
    "    return pd.Series(result, index=column.index)\n",
    "\n",
    "def find_closest_index(column, target_value):\n",
    "    squared_diff = (column - target_value) ** 2\n",
    "    return squared_diff.idxmin()\n",
    "    \n",
    "# calculate avarage density around target density\n",
    "def calculate_average_density_around_target(value, window_=2, sift_=1):\n",
    "    values = []\n",
    "    for offset in range(-window_, window_ + 1):\n",
    "        values.append(value + offset+sift_)\n",
    "    return np.mean(calculate_TargetDensificationRate(pd.Series(values)))"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 180,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1500x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 31344 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# plot target densification rate vs density for values from 30 to 100\n",
    "plt.figure(figsize=(15, 6))\n",
    "fig, ax1 = plt.subplots( figsize=(15, 6))\n",
    "for density in range(30, 101):\n",
    "    target_rate = calculate_TargetDensificationRateValue(density)\n",
    "    ax1.plot(density, target_rate, color='red', marker='o')\n",
    "    ax1.plot(density, calculate_average_density_around_target(density), color='green', marker='x')\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 199,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "35.13066666666691\n",
      "27.05633333333344\n"
     ]
    },
    {
     "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>seconds</th>\n",
       "      <th>TravelRelativeTempCorrected</th>\n",
       "      <th>Pyrometer</th>\n",
       "      <th>PyrometerShifted</th>\n",
       "      <th>Force</th>\n",
       "      <th>Density</th>\n",
       "      <th>STD</th>\n",
       "    </tr>\n",
       "  </thead>\n",
       "  <tbody>\n",
       "    <tr>\n",
       "      <th>0</th>\n",
       "      <td>2.0</td>\n",
       "      <td>0.000000</td>\n",
       "      <td>972.0</td>\n",
       "      <td>977.0</td>\n",
       "      <td>16.0</td>\n",
       "      <td>48.065618</td>\n",
       "      <td>NaN</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>1</th>\n",
       "      <td>3.0</td>\n",
       "      <td>27.272139</td>\n",
       "      <td>977.0</td>\n",
       "      <td>982.0</td>\n",
       "      <td>16.0</td>\n",
       "      <td>48.232234</td>\n",
       "      <td>6.727524</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>2</th>\n",
       "      <td>4.0</td>\n",
       "      <td>55.079537</td>\n",
       "      <td>982.0</td>\n",
       "      <td>986.0</td>\n",
       "      <td>16.0</td>\n",
       "      <td>48.403313</td>\n",
       "      <td>6.310655</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>3</th>\n",
       "      <td>5.0</td>\n",
       "      <td>82.310561</td>\n",
       "      <td>986.0</td>\n",
       "      <td>990.0</td>\n",
       "      <td>16.0</td>\n",
       "      <td>48.572027</td>\n",
       "      <td>6.106005</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>4</th>\n",
       "      <td>6.0</td>\n",
       "      <td>109.979893</td>\n",
       "      <td>990.0</td>\n",
       "      <td>993.0</td>\n",
       "      <td>16.0</td>\n",
       "      <td>48.744665</td>\n",
       "      <td>5.825488</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>5</th>\n",
       "      <td>7.0</td>\n",
       "      <td>136.976438</td>\n",
       "      <td>993.0</td>\n",
       "      <td>996.0</td>\n",
       "      <td>16.0</td>\n",
       "      <td>48.914293</td>\n",
       "      <td>5.682761</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>6</th>\n",
       "      <td>8.0</td>\n",
       "      <td>164.315396</td>\n",
       "      <td>996.0</td>\n",
       "      <td>999.0</td>\n",
       "      <td>16.0</td>\n",
       "      <td>49.087279</td>\n",
       "      <td>5.554303</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>7</th>\n",
       "      <td>9.0</td>\n",
       "      <td>191.994128</td>\n",
       "      <td>999.0</td>\n",
       "      <td>1002.0</td>\n",
       "      <td>16.0</td>\n",
       "      <td>49.263666</td>\n",
       "      <td>5.439126</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>8</th>\n",
       "      <td>10.0</td>\n",
       "      <td>220.009419</td>\n",
       "      <td>1002.0</td>\n",
       "      <td>1004.0</td>\n",
       "      <td>16.0</td>\n",
       "      <td>49.443494</td>\n",
       "      <td>5.305688</td>\n",
       "    </tr>\n",
       "    <tr>\n",
       "      <th>9</th>\n",
       "      <td>11.0</td>\n",
       "      <td>247.250737</td>\n",
       "      <td>1004.0</td>\n",
       "      <td>1006.0</td>\n",
       "      <td>16.0</td>\n",
       "      <td>49.619617</td>\n",
       "      <td>5.224098</td>\n",
       "    </tr>\n",
       "  </tbody>\n",
       "</table>\n",
       "</div>"
      ],
      "text/plain": [
       "   seconds  TravelRelativeTempCorrected  Pyrometer  PyrometerShifted  Force  \\\n",
       "0      2.0                     0.000000      972.0             977.0   16.0   \n",
       "1      3.0                    27.272139      977.0             982.0   16.0   \n",
       "2      4.0                    55.079537      982.0             986.0   16.0   \n",
       "3      5.0                    82.310561      986.0             990.0   16.0   \n",
       "4      6.0                   109.979893      990.0             993.0   16.0   \n",
       "5      7.0                   136.976438      993.0             996.0   16.0   \n",
       "6      8.0                   164.315396      996.0             999.0   16.0   \n",
       "7      9.0                   191.994128      999.0            1002.0   16.0   \n",
       "8     10.0                   220.009419     1002.0            1004.0   16.0   \n",
       "9     11.0                   247.250737     1004.0            1006.0   16.0   \n",
       "\n",
       "     Density       STD  \n",
       "0  48.065618       NaN  \n",
       "1  48.232234  6.727524  \n",
       "2  48.403313  6.310655  \n",
       "3  48.572027  6.106005  \n",
       "4  48.744665  5.825488  \n",
       "5  48.914293  5.682761  \n",
       "6  49.087279  5.554303  \n",
       "7  49.263666  5.439126  \n",
       "8  49.443494  5.305688  \n",
       "9  49.619617  5.224098  "
      ]
     },
     "execution_count": 199,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# Virtual Experiment: Optimize Sintering Process\n",
    "# This code simulates a sintering process by iteratively predicting the optimal temperature\n",
    "# to achieve target densification rates at each time step\n",
    "\n",
    "# ============================================================================\n",
    "# Initial Setup\n",
    "# ============================================================================\n",
    "\n",
    "# Start from first data point of the reference experiment\n",
    "vexp_key = '100_1500_50'\n",
    "initial_state = data[vexp_key].head(1)\n",
    "print(data[vexp_key]['TravelDelta'].max())\n",
    "print(initial_state['TravelDelta'].iloc[0])\n",
    "vexp_weight = initial_state.attrs['weight']\n",
    "vexp_start_density = initial_state['Density'].iloc[0]\n",
    "prediction_features = initial_state[['seconds', 'TravelRelativeTempCorrected', 'Pyrometer', \n",
    "                                      'PyrometerShifted', 'Force', 'Density']]\n",
    "prediction_features = prediction_features.reset_index(drop=True)\n",
    "\n",
    "# Initialize simulation parameters\n",
    "current_time = prediction_features['seconds'].iloc[0]\n",
    "num_temperature_options = 15  # Number of temperature scenarios to evaluate at each step\n",
    "time_step = 1  # Seconds between predictions\n",
    "max_simulation_time = 1000  # Maximum simulation duration\n",
    "target_density = 96  # Target relative density percentage\n",
    "predicted_regime = pd.DataFrame()\n",
    "# Create multiple prediction scenarios (will be populated in loop)\n",
    "prediction_scenarios = pd.concat([prediction_features] * num_temperature_options, ignore_index=True)\n",
    "\n",
    "# ============================================================================\n",
    "# Simulation Loop\n",
    "# ============================================================================\n",
    "current_density = vexp_start_density  # Starting density percentage\n",
    "\n",
    "# Initialize prediction scenarios with different temperature options\n",
    "current_time += time_step\n",
    "for i in range(num_temperature_options):\n",
    "    prediction_scenarios.loc[i, 'seconds'] = current_time\n",
    "    # Temperature offset from -5 to +54 degrees relative to current temperature\n",
    "    prediction_scenarios.loc[i, 'PyrometerShifted'] = prediction_scenarios['Pyrometer'].iloc[i] + i - 5\n",
    "\n",
    "# Main simulation loop: continue until time limit or target density reached\n",
    "while current_time < max_simulation_time and current_density < target_density:\n",
    "    \n",
    "    # ========================================================================\n",
    "    #  Predict outcomes for all temperature scenarios\n",
    "    # ========================================================================\n",
    "    travel_predictions, prediction_std = gpr.predict(prediction_scenarios, return_std=True)\n",
    "    \n",
    "    current_travel = prediction_scenarios['TravelRelativeTempCorrected'].iloc[0]\n",
    "    \n",
    "    # Update current density based on predicted travel\n",
    "    current_density = calculate_densityForVirtualExperiment(current_travel, vexp_weight, vexp_start_density)\n",
    "    \n",
    "    # ========================================================================\n",
    "    # Select best temperature option\n",
    "    # ========================================================================\n",
    "    # Calculate target densification rate for current density\n",
    "    target_rate = calculate_TargetDensificationRateValue(current_density)\n",
    "    #calculate_average_density_around_target\n",
    "    #target_rate = calculate_average_density_around_target(current_density,2, sift_=1, max_rate=target_max_rate, start_rate = initial_state['TravelDelta'].iloc[0])\n",
    "    #print(f'Target rate: {target_rate}')\n",
    "    \n",
    "    # Find which scenario gives densification rate closest to target\n",
    "    predicted_rates_series = pd.Series(travel_predictions - current_travel)\n",
    "    #print(predicted_rates_series)\n",
    "    best_scenario_index = find_closest_index(predicted_rates_series, target_rate)\n",
    "\n",
    "    # ========================================================================\n",
    "    # Record the selected scenario in the regime\n",
    "    # ========================================================================\n",
    "    best_prediction = prediction_scenarios.iloc[best_scenario_index]\n",
    "    best_prediction_df = pd.DataFrame([best_prediction])\n",
    "\n",
    "    if predicted_regime.empty:\n",
    "        predicted_regime = best_prediction_df\n",
    "    else:\n",
    "        predicted_regime = pd.concat([predicted_regime, best_prediction_df], ignore_index=True)\n",
    "        predicted_regime.at[predicted_regime.index[-1], 'STD'] = prediction_std[best_scenario_index]\n",
    "    \n",
    "    # ========================================================================\n",
    "    # Update prediction scenarios for next time step\n",
    "    #'seconds', 'TravelRelativeTempCorrected', 'Pyrometer', 'PyrometerShifted', 'Force', 'Density'\n",
    "    # ========================================================================\n",
    "    best_scenario_pyromenter_shifted = prediction_scenarios['PyrometerShifted'].iloc[best_scenario_index]\n",
    "    best_scenario_travel = travel_predictions[best_scenario_index]\n",
    "    current_time += time_step\n",
    "    for i in range(num_temperature_options):\n",
    "        prediction_scenarios.loc[i, 'seconds'] = current_time\n",
    "        prediction_scenarios.loc[i, 'TravelRelativeTempCorrected'] = best_scenario_travel\n",
    "        prediction_scenarios.loc[i, 'Pyrometer'] = best_scenario_pyromenter_shifted\n",
    "        prediction_scenarios.loc[i, 'Density'] = calculate_densityForVirtualExperiment(\n",
    "            best_scenario_travel,\n",
    "            vexp_weight,\n",
    "            vexp_start_density\n",
    "        )\n",
    "        # Temperature offset\n",
    "        prediction_scenarios.loc[i, 'PyrometerShifted'] = best_scenario_pyromenter_shifted + (i-5)\n",
    "    \n",
    "    # Progress tracking\n",
    "    #print(f'Time: {current_time}s')\n",
    "    #print(f'Density: {current_density:.2f}%')\n",
    "\n",
    "# Display first few rows of the predicted regime\n",
    "predicted_regime.head(10)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 200,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "(-20.0, 45.0)"
      ]
     },
     "execution_count": 200,
     "metadata": {},
     "output_type": "execute_result"
    },
    {
     "data": {
      "text/plain": [
       "<Figure size 1500x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 92916 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(15, 6))\n",
    "fig, ax1 = plt.subplots( figsize=(15, 6))\n",
    "#heating rate\n",
    "\n",
    "for key in data.keys():\n",
    "    ax1.plot(data[key]['seconds'], data[key]['PyrometerShifted'] - data[key]['Pyrometer'], color='gray')\n",
    "sc = ax1.plot(predicted_regime['seconds'], predicted_regime['PyrometerShifted'] - predicted_regime['Pyrometer'], color='red') \n",
    "ax1.set_title('Швидкість нагріву в віртуальному експерименті в порівнянні з реальним даними')\n",
    "ax1.set_xlabel('час в секундах')\n",
    "ax1.set_ylabel('Швидкість °C/c')\n",
    "ax1.set_ylim(-20, 45 )\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 201,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1500x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 45772 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(15, 6))\n",
    "fig, ax1 = plt.subplots( figsize=(15, 6))\n",
    "\n",
    "#Density plot\n",
    "sc = ax1.plot(predicted_regime['seconds'], calculate_densityForVirtualExperiment(predicted_regime['TravelRelativeTempCorrected'], vexp_weight, vexp_start_density), color='red')\n",
    "sc = ax1.plot(data[vexp_key]['seconds'], data[vexp_key]['Density'], color='grey')\n",
    "#sc = ax1.plot(data['100_1500_50']['seconds'], calculate_densityForVirtualExperiment(data['100_1500_50']['TravelRelativeTempCorrected'], vexp_weight, vexp_start_density), color='green')\n",
    "\n",
    "\n",
    "#sc = ax1.plot(calulate_densityForVirtualExperiment(newRegime['TravelRelativeTempCorrected'], 6.5, 48), newRegime['STD'], color='blue') \n",
    "\n",
    "#ax1.set_title('title')\n",
    "ax1.set_xlabel('Час (секунди)')\n",
    "ax1.set_ylabel('Щільність')\n",
    "ax1.grid(True)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 202,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1500x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 107360 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(15, 6))\n",
    "fig, ax1 = plt.subplots( figsize=(15, 6))\n",
    "\n",
    "#densification rate\n",
    "sc = ax1.plot( calculate_densityForVirtualExperiment(predicted_regime['TravelRelativeTempCorrected'], 6.5, 48), predicted_regime['TravelRelativeTempCorrected'] - predicted_regime['TravelRelativeTempCorrected'].shift(1), color='red')\n",
    "sc = ax1.plot( calculate_densityForVirtualExperiment(predicted_regime['TravelRelativeTempCorrected'], 6.5, 48), calculate_TargetDensificationRate(calculate_densityForVirtualExperiment(predicted_regime['TravelRelativeTempCorrected'], 6.5, 48)), color='green')\n",
    "sc = ax1.plot(data[vexp_key]['Density'], data[vexp_key]['TravelDelta'], color='grey')\n",
    "\n",
    "#sc = ax1.plot(calulate_densityForVirtualExperiment(newRegime['TravelRelativeTempCorrected'], 6.5, 48), newRegime['STD'], color='blue') \n",
    "\n",
    "#ax1.set_title('title')\n",
    "ax1.set_xlabel('Щільність')\n",
    "ax1.set_ylabel('Швидкість ущільнення')\n",
    "ax1.grid(True)\n",
    "plt.show()\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 203,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1500x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 99896 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(15, 6))\n",
    "fig, ax1 = plt.subplots( figsize=(15, 6))\n",
    "\n",
    "#densification rate\n",
    "sc = ax1.plot(predicted_regime['seconds'], predicted_regime['TravelRelativeTempCorrected'] - predicted_regime['TravelRelativeTempCorrected'].shift(1), color='red')\n",
    "sc = ax1.plot(predicted_regime['seconds'], calculate_TargetDensificationRate(calculate_densityForVirtualExperiment(predicted_regime['TravelRelativeTempCorrected'], 6.5, 48)), color='green')\n",
    "sc = ax1.plot(data[vexp_key]['seconds'], data[vexp_key]['TravelDelta'], color='grey')\n",
    "\n",
    "#sc = ax1.plot(calulate_densityForVirtualExperiment(newRegime['TravelRelativeTempCorrected'], 6.5, 48), newRegime['STD'], color='blue') \n",
    "\n",
    "#ax1.set_title('title')\n",
    "ax1.set_xlabel('Час (секунди)')\n",
    "ax1.set_ylabel('Швидкість ущільнення')\n",
    "ax1.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 204,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1500x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 54420 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(15, 6))\n",
    "fig, ax1 = plt.subplots( figsize=(15, 6))\n",
    "\n",
    "#Temperature\n",
    "sc = ax1.plot(data[vexp_key]['seconds'], data[vexp_key]['Pyrometer'], color='grey')\n",
    "sc = ax1.plot(predicted_regime['seconds'], predicted_regime['Pyrometer'], color='red')\n",
    "\n",
    "ax1.set_title('Порівняння температури з єксперементальними даними')\n",
    "ax1.set_xlabel('Час, с')\n",
    "ax1.set_ylabel('Температура °C')\n",
    "ax1.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 205,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1500x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 61212 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(15, 6))\n",
    "fig, ax1 = plt.subplots( figsize=(15, 6))\n",
    "\n",
    "sc = ax1.plot(data[vexp_key]['seconds'], data[vexp_key]['TravelRelativeTempCorrectedShifted'], color='grey') \n",
    "sc = ax1.plot(predicted_regime['seconds'], predicted_regime['TravelRelativeTempCorrected'], color='red') \n",
    " \n",
    "ax1.set_title('Порівняння ходу поршня з єкспериментальними даними')\n",
    "ax1.set_xlabel('час, с')\n",
    "ax1.set_ylabel('хід поршня, μм')\n",
    "ax1.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 206,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 1500x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 46020 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(15, 6))\n",
    "fig, ax1 = plt.subplots( figsize=(15, 6))\n",
    "\n",
    "sc = ax1.plot(data[vexp_key]['TravelRelativeTempCorrectedShifted'], data[vexp_key]['Pyrometer'], color='grey') \n",
    "sc = ax1.plot(predicted_regime['TravelRelativeTempCorrected'], predicted_regime['Pyrometer'], color='red') \n",
    " \n",
    "\n",
    "ax1.set_title('title')\n",
    "ax1.set_xlabel('Microns')\n",
    "ax1.set_ylabel('Pyrometer')\n",
    "ax1.grid(True)\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 207,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "<Figure size 4000x600 with 0 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "data": {
      "image/png": "[encoded data, 61968 characters]",
      "text/plain": [
       "<Figure size 4000x600 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "plt.figure(figsize=(40, 6))\n",
    "fig, ax1 = plt.subplots( figsize=(40, 6))\n",
    "\n",
    "sc = ax1.plot(data[vexp_key]['seconds'], data[vexp_key]['Pyrometer'], color='grey') \n",
    "#sc = ax1.plot(dataN1100['seconds'], dataN1100['Pyrometer'], color='grey') \n",
    "sc = ax1.plot(predicted_regime['seconds'], predicted_regime['Pyrometer'], color='red') \n",
    " \n",
    "\n",
    "ax1.set_title('title')\n",
    "ax1.set_xlabel('seconds')\n",
    "ax1.set_ylabel('Pyrometer')\n",
    "ax1.grid(True)\n",
    "plt.show()"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "SPS",
   "language": "python",
   "name": "python3"
  },
  "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.13.5"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
