{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "metadata": {},
   "outputs": [],
   "source": [
    "import os\n",
    "import glob\n",
    "import shutil\n",
    "\n",
    "def clear_folder_make_ess_pv(folder_path):\n",
    "    if os.path.isdir(folder_path):\n",
    "        shutil.rmtree(folder_path)\n",
    "    os.makedirs(folder_path)\n",
    "    os.makedirs(os.path.join(folder_path,'ess'))\n",
    "    os.makedirs(os.path.join(folder_path,'pv'))\n",
    "\n",
    "folder_path = 'plots'\n",
    "clear_folder_make_ess_pv(folder_path)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "import seaborn as sns\n",
    "import numpy as np\n",
    "import pandas as pd\n",
    "from EnergySystem import EnergySystem\n",
    "from config import pv_config, grid_config, ess_config\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Version 0.0.2\n"
     ]
    }
   ],
   "source": [
    "import json\n",
    "\n",
    "print(\"Version 0.0.2\")\n",
    "\n",
    "with open('config.json', 'r') as f:\n",
    "    js_data = json.load(f)\n",
    "\n",
    "data = pd.read_csv('combined_data.csv')\n",
    "time_interval = js_data[\"time_interval\"][\"numerator\"] / js_data[\"time_interval\"][\"denominator\"]\n",
    "\n",
    "pv_loss = js_data[\"pv\"][\"loss\"]\n",
    "pv_cost_per_kW = js_data[\"pv\"][\"cost_per_kW\"]\n",
    "pv_lifetime = js_data[\"pv\"][\"lifetime\"]\n",
    "\n",
    "ess_loss = js_data[\"ess\"][\"loss\"]\n",
    "ess_cost_per_kW = js_data[\"ess\"][\"cost_per_kW\"]\n",
    "ess_lifetime = js_data[\"ess\"][\"lifetime\"]\n",
    "\n",
    "grid_loss = js_data[\"grid\"][\"loss\"]\n",
    "sell_price = js_data[\"grid\"][\"sell_price\"] #kWh\n",
    "grid_capacity = js_data[\"grid\"][\"capacity\"] #kWh\n",
    "\n",
    "pv_begin = js_data[\"pv_capacities\"][\"begin\"]\n",
    "pv_end = js_data[\"pv_capacities\"][\"end\"]\n",
    "pv_groups = js_data[\"pv_capacities\"][\"groups\"]\n",
    "\n",
    "ess_begin = js_data[\"ess_capacities\"][\"begin\"]\n",
    "ess_end = js_data[\"ess_capacities\"][\"end\"]\n",
    "ess_groups = js_data[\"ess_capacities\"][\"groups\"]\n",
    "\n",
    "annot_unmet = js_data[\"annotated\"][\"unmet_prob\"]\n",
    "annot_benefit = js_data[\"annotated\"][\"benefit\"]\n",
    "annot_cost = js_data[\"annotated\"][\"cost\"]\n",
    "\n",
    "title_unmet = js_data[\"plot_title\"][\"unmet_prob\"]\n",
    "title_cost = js_data[\"plot_title\"][\"cost\"]\n",
    "title_benefit = js_data[\"plot_title\"][\"benefit\"]\n",
    "\n",
    "figure_size = (js_data[\"figure_size\"][\"length\"], js_data[\"figure_size\"][\"height\"])\n",
    "\n",
    "pv_capacities = np.linspace(pv_begin, pv_end, pv_groups)\n",
    "ess_capacities = np.linspace(ess_begin, ess_end, ess_groups)\n",
    "results = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
    "affords = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
    "costs = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n",
    "overload_cnt = pd.DataFrame(index=pv_capacities, columns= ess_capacities)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "metadata": {},
   "outputs": [],
   "source": [
    "hour_demand = []\n",
    "for index, row in data.iterrows():\n",
    "    time = row['time']\n",
    "    demand = row['demand']\n",
    "    if time.endswith('00'):\n",
    "        hour_demand.append(demand)\n",
    "plt.figure(figsize=(10,8))\n",
    "plt.plot(hour_demand)\n",
    "plt.ylabel('Demand Power / kW')\n",
    "plt.savefig('plots/demand.png')\n",
    "plt.close()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "metadata": {},
   "outputs": [],
   "source": [
    "def cal_profit(es: EnergySystem, saved_money):\n",
    "    profit = saved_money - es.ess.get_cost_per_year() - es.pv.get_cost_per_year()\n",
    "    return profit"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "ess_capacity:0.0\n",
      "pv_capacity:0.0\n"
     ]
    },
    {
     "name": "stderr",
     "output_type": "stream",
     "text": [
      "/home/stud/hanzhang/simple-pv-simulator/EnergySystem.py:52: RuntimeWarning: invalid value encountered in scalar divide\n",
      "  soc = self.ess.storage / self.ess.capacity\n",
      "/home/stud/hanzhang/simple-pv-simulator/EnergySystem.py:95: RuntimeWarning: invalid value encountered in scalar divide\n",
      "  log = f\"index: {index}, time: {time}, SoC:{self.ess.storage / self.ess.capacity}%, storage: {self.ess.storage}, pv_gen:{generated_pv_power}, power_demand: {factory_demand}, overload_cnt:{self.overload_cnt}, day:{int(index/96) + 1}\"\n",
      "/home/stud/hanzhang/simple-pv-simulator/EnergySystem.py:49: RuntimeWarning: invalid value encountered in scalar divide\n",
      "  soc = self.ess.storage / self.ess.capacity\n",
      "/home/stud/hanzhang/simple-pv-simulator/EnergySystem.py:120: RuntimeWarning: invalid value encountered in scalar divide\n",
      "  self.spring_week_soc.append(self.ess.storage / self.ess.capacity)\n"
     ]
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "pv_capacity:0.0\n",
      "pv_capacity:0.0\n",
      "pv_capacity:0.0\n",
      "pv_capacity:0.0\n",
      "ess_capacity:11111.111111111111\n",
      "pv_capacity:11111.111111111111\n",
      "pv_capacity:11111.111111111111\n",
      "pv_capacity:11111.111111111111\n",
      "pv_capacity:11111.111111111111\n",
      "pv_capacity:11111.111111111111\n",
      "ess_capacity:22222.222222222223\n",
      "pv_capacity:22222.222222222223\n",
      "pv_capacity:22222.222222222223\n",
      "pv_capacity:22222.222222222223\n",
      "pv_capacity:22222.222222222223\n",
      "pv_capacity:22222.222222222223\n",
      "ess_capacity:33333.333333333336\n",
      "pv_capacity:33333.333333333336\n",
      "pv_capacity:33333.333333333336\n",
      "pv_capacity:33333.333333333336\n",
      "pv_capacity:33333.333333333336\n",
      "pv_capacity:33333.333333333336\n",
      "ess_capacity:44444.444444444445\n",
      "pv_capacity:44444.444444444445\n",
      "pv_capacity:44444.444444444445\n",
      "pv_capacity:44444.444444444445\n",
      "pv_capacity:44444.444444444445\n",
      "pv_capacity:44444.444444444445\n",
      "ess_capacity:55555.555555555555\n",
      "pv_capacity:55555.555555555555\n",
      "pv_capacity:55555.555555555555\n",
      "pv_capacity:55555.555555555555\n",
      "pv_capacity:55555.555555555555\n",
      "pv_capacity:55555.555555555555\n",
      "ess_capacity:66666.66666666667\n",
      "pv_capacity:66666.66666666667\n",
      "pv_capacity:66666.66666666667\n",
      "pv_capacity:66666.66666666667\n",
      "pv_capacity:66666.66666666667\n",
      "pv_capacity:66666.66666666667\n",
      "ess_capacity:77777.77777777778\n",
      "pv_capacity:77777.77777777778\n",
      "pv_capacity:77777.77777777778\n",
      "pv_capacity:77777.77777777778\n",
      "pv_capacity:77777.77777777778\n",
      "pv_capacity:77777.77777777778\n",
      "ess_capacity:88888.88888888889\n",
      "pv_capacity:88888.88888888889\n",
      "pv_capacity:88888.88888888889\n",
      "pv_capacity:88888.88888888889\n",
      "pv_capacity:88888.88888888889\n",
      "pv_capacity:88888.88888888889\n",
      "ess_capacity:100000.0\n",
      "pv_capacity:100000.0\n",
      "pv_capacity:100000.0\n",
      "pv_capacity:100000.0\n",
      "pv_capacity:100000.0\n",
      "pv_capacity:100000.0\n"
     ]
    }
   ],
   "source": [
    "for ess_capacity in ess_capacities:\n",
    "    print(f\"ess_capacity:{ess_capacity}\")\n",
    "    for pv_capacity in pv_capacities:\n",
    "        print(f\"pv_capacity:{pv_capacity}\")\n",
    "        pv = pv_config(capacity=pv_capacity, \n",
    "                        cost_per_kW=pv_cost_per_kW,\n",
    "                        lifetime=pv_lifetime, \n",
    "                        loss=pv_loss)\n",
    "        ess = ess_config(capacity=ess_capacity, \n",
    "                            cost_per_kW=ess_cost_per_kW, \n",
    "                            lifetime=ess_lifetime, \n",
    "                            loss=ess_loss,\n",
    "                            charge_power=ess_capacity,\n",
    "                            discharge_power=ess_capacity)\n",
    "        grid = grid_config(capacity=grid_capacity, \n",
    "                            grid_loss=grid_loss,\n",
    "                            sell_price= sell_price)\n",
    "        energySystem = EnergySystem(pv_type=pv, \n",
    "                                    ess_type=ess, \n",
    "                                    grid_type= grid)\n",
    "        benefit = energySystem.simulate(data, time_interval)\n",
    "        results.loc[pv_capacity,ess_capacity] = cal_profit(energySystem, benefit)\n",
    "        affords.loc[pv_capacity,ess_capacity] = energySystem.afford\n",
    "        overload_cnt.loc[pv_capacity,ess_capacity] = energySystem.overload_cnt\n",
    "        costs.loc[pv_capacity,ess_capacity] = energySystem.ess.capacity * energySystem.ess.cost_per_kW + energySystem.pv.capacity * energySystem.pv.cost_per_kW\n",
    "        pv_generated = energySystem.day_generated\n",
    "        ess_generated = energySystem.hour_stored\n",
    "        ess_generated_2 = energySystem.hour_stored_2\n",
    "    plt.figure(figsize=(10,8));\n",
    "    plt.plot(ess_generated)\n",
    "    plt.xlabel('day #')\n",
    "    plt.ylabel('SoC %')\n",
    "    plt.title(f'14:00 ESS SoC \\n PV cap:{pv_capacity}, ESS cap:{ess_capacity}')\n",
    "    plt.savefig(f'plots/ess/1400-{pv_capacity}-{ess_capacity}.png')\n",
    "    plt.close()\n",
    "    plt.figure(figsize=(10,8));\n",
    "    plt.plot(ess_generated_2)\n",
    "    plt.xlabel('day #')\n",
    "    plt.ylabel('SoC%')\n",
    "    plt.title(f'08:00 ESS SoC \\n PV cap:{pv_capacity}, ESS cap:{ess_capacity}')\n",
    "    plt.savefig(f'plots/ess/0800-{pv_capacity}-{ess_capacity}.png')\n",
    "    plt.close()\n",
    "        # print(energySystem.unmet)\n",
    "        # spring_week_start = energySystem.season_start\n",
    "        # spring_week_end = spring_week_start + energySystem.week_length\n",
    "        # summer_week_start = energySystem.season_start + 1 * energySystem.season_step\n",
    "        # summer_week_end = summer_week_start + energySystem.week_length\n",
    "        # autumn_week_start = energySystem.season_start + 2 * energySystem.season_step\n",
    "        # autumn_week_end = autumn_week_start + energySystem.week_length\n",
    "        # winter_week_start = energySystem.season_start + 3 * energySystem.season_step\n",
    "        # winter_week_end = winter_week_start+ energySystem.week_length\n",
    "\n",
    "        # spring_consume_data = []\n",
    "        # summer_consume_data = []\n",
    "        # autumn_consume_data = []\n",
    "        # winter_consume_data = []\n",
    "        # for index, row in data.iterrows():\n",
    "            # if index in range(spring_week_start, spring_week_end):\n",
    "                # spring_consume_data.append(row['demand'])\n",
    "        #     elif index in range(summer_week_start, summer_week_end):\n",
    "        #         summer_consume_data.append(row['demand'])\n",
    "        #     elif index in range(autumn_week_start, autumn_week_end):\n",
    "        #         autumn_consume_data.append(row['demand'])\n",
    "        #     elif index in range(winter_week_start, winter_week_end):\n",
    "        #         winter_consume_data.append(row['demand'])\n",
    "\n",
    "        # spring_week_time = list(range(spring_week_start, spring_week_end))\n",
    "        # summer_week_time = list(range(summer_week_start, summer_week_end))\n",
    "        # autumn_week_time = list(range(autumn_week_start, autumn_week_end))\n",
    "        # winter_week_time = list(range(winter_week_start, winter_week_end))\n",
    "\n",
    "        # spring_pv_generated = energySystem.spring_week_gen\n",
    "        # summer_pv_generated = energySystem.summer_week_gen\n",
    "        # autumn_pv_generated = energySystem.autumn_week_gen\n",
    "        # winter_pv_generated = energySystem.winter_week_gen\n",
    "\n",
    "        # spring_soc = energySystem.spring_week_soc\n",
    "        # summer_soc = energySystem.summer_week_soc\n",
    "        # autumn_soc = energySystem.autumn_week_soc\n",
    "        # winter_soc = energySystem.winter_week_soc\n",
    "\n",
    "\n",
    "        # fig, ax1 = plt.subplots()\n",
    "\n",
    "        # plt.plot(spring_week_time, spring_pv_generated, label = 'pv generation')\n",
    "        # plt.plot(spring_week_time, spring_consume_data, label = 'factory consume')\n",
    "        # plt.ylabel('Power / kW')\n",
    "        # plt.xlabel('15 min #')\n",
    "        # plt.title(f'ess: {energySystem.ess.capacity/1000 } MWh pv: {energySystem.pv.capacity/1000 } MW spring week generate condition')\n",
    "        # plt.legend()\n",
    "        # plt.savefig(f'plots/{energySystem.ess.capacity}-{energySystem.pv.capacity}-spring.png')\n",
    "        # plt.close()\n",
    "\n",
    "        # plt.plot(summer_week_time, summer_pv_generated, label = 'pv generation')\n",
    "        # plt.plot(summer_week_time, summer_consume_data, label = 'factory consume')\n",
    "        # plt.ylabel('Power / kW')\n",
    "        # plt.xlabel('15 min #')\n",
    "        # plt.title(f'ess: {energySystem.ess.capacity/1000 } MWh pv: {energySystem.pv.capacity/1000 } MW summer week generate condition')\n",
    "        # plt.legend()\n",
    "        # plt.savefig(f'plots/{energySystem.ess.capacity}-{energySystem.pv.capacity}-summer.png')\n",
    "        # plt.close()\n",
    "\n",
    "        # plt.plot(autumn_week_time, autumn_pv_generated, label = 'pv generation')\n",
    "        # plt.plot(autumn_week_time, autumn_consume_data, label = 'factory consume')\n",
    "        # plt.ylabel('Power / kW')\n",
    "        # plt.xlabel('15 min #')\n",
    "        # plt.title(f'ess: {energySystem.ess.capacity/1000 } MWh pv: {energySystem.pv.capacity/1000 } MW autumn week generate condition')\n",
    "        # plt.legend()\n",
    "        # plt.savefig(f'plots/{energySystem.ess.capacity}-{energySystem.pv.capacity}-autumn.png')\n",
    "        # plt.close()\n",
    "\n",
    "        # plt.plot(winter_week_time, winter_pv_generated, label = 'pv generation')\n",
    "        # plt.plot(winter_week_time, winter_consume_data, label = 'factory consume')\n",
    "        # plt.ylabel('Power / kW')\n",
    "        # plt.xlabel('15 min #')\n",
    "        # plt.title(f'ess: {energySystem.ess.capacity/1000 } MWh pv: {energySystem.pv.capacity/1000 } MW winter week generate condition')\n",
    "        # plt.legend()\n",
    "        # plt.savefig(f'plots/{energySystem.ess.capacity}-{energySystem.pv.capacity}-winter.png')\n",
    "        # plt.close()\n",
    "\n",
    "    # plt.figure();\n",
    "    # plt.plot(pv_generated)\n",
    "    # plt.xlabel('day #')\n",
    "    # plt.ylabel('Electricity kWh')\n",
    "    # plt.title(f'PV generated pv cap:{pv_capacity}, ess cap:{ess_capacity}')\n",
    "    # plt.savefig(f'plots/pv/{pv_capacity}-{ess_capacity}.png')\n",
    "    # plt.close()\n",
    "\n",
    "\n",
    "        # plt.show()\n",
    "\n",
    "\n",
    "        \n",
    "\n",
    "# results = results.astype(float)\n",
    "\n",
    "\n",
    "# pv = pv_config(capacity=100000,cost_per_kW=200,lifetime=25,loss=0.95)\n",
    "# ess = ess_config(capacity=100000,cost_per_kW=300,lifetime=25,loss=0.95,charge_power=100000,discharge_power=100000)\n",
    "# grid = grid_config(price_schedule=price_schedule, capacity=5000, grid_loss=0.95, sell_price=0.4)\n",
    "# grid = grid_config(capacity=50000, grid_loss=0.95, sell_price=0.4)\n",
    "\n",
    "\n",
    "    # print(benefit)\n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 7,
   "metadata": {},
   "outputs": [],
   "source": [
    "def save_data(data, filename):\n",
    "    data.to_csv(filename+'.csv')\n",
    "    data.to_json(filename + '.json')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 79692 characters]",
      "text/plain": [
       "<Figure size 1000x900 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "import matplotlib.ticker as ticker\n",
    "\n",
    "if not os.path.isdir('data'):\n",
    "    os.makedirs('data')\n",
    "\n",
    "save_data(results, f'data/{pv_begin}-{pv_end}-{pv_groups}-{ess_begin}-{ess_end}-{ess_groups}-results')\n",
    "save_data(costs, f'data/{pv_begin}-{pv_end}-{pv_groups}-{ess_begin}-{ess_end}-{ess_groups}-costs')\n",
    "save_data(overload_cnt, f'data/{pv_begin}-{pv_end}-{pv_groups}-{ess_begin}-{ess_end}-{ess_groups}-overload_cnt')\n",
    "df=results\n",
    "df = df.astype(float)\n",
    "df.index = df.index / 1000\n",
    "df.columns = df.columns / 1000\n",
    "min_value = df.min().min()\n",
    "max_value = df.max().max()\n",
    "max_scale = max(abs(min_value/1000), abs(max_value/1000))\n",
    "plt.figure(figsize=figure_size)\n",
    "cmap = sns.color_palette(\"coolwarm\", as_cmap=True)\n",
    "ax = sns.heatmap(df/1000, fmt=\".1f\", cmap=cmap, vmin=-max_scale, vmax=max_scale, annot=annot_benefit)\n",
    "# ax.yaxis.set_major_formatter(ticker.FormatStrFormatter('%.1f'))\n",
    "plt.title(title_benefit)\n",
    "plt.gca().invert_yaxis()\n",
    "plt.xlabel('ESS Capacity (MWh)')\n",
    "plt.ylabel('PV Capacity (MW)')\n",
    "plt.savefig('plots/benefit.png')"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 71000 characters]",
      "text/plain": [
       "<Figure size 1000x900 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "\n",
    "\n",
    "df = costs\n",
    "df = df.astype(int)\n",
    "df.index = df.index / 1000\n",
    "df.columns = df.columns / 1000\n",
    "\n",
    "plt.figure(figsize=figure_size)\n",
    "sns.heatmap(df/1000000,  fmt=\".1f\", cmap='viridis', annot=annot_cost)\n",
    "plt.title(title_cost)\n",
    "plt.gca().invert_yaxis()\n",
    "plt.xlabel('ESS Capacity (MWh)')\n",
    "plt.ylabel('PV Capacity (MW)')\n",
    "plt.savefig('plots/costs.png')\n",
    "\n",
    "    # pv = pv_config(capacity=100000,cost_per_kW=200,lifetime=25,loss=0.95)\n",
    "    # ess = ess_config(capacity=100000,cost_per_kW=300,lifetime=25,loss=0.95,charge_power=100000,discharge_power=100000)\n",
    "    # grid = grid_config(price_schedule=price_schedule, capacity=5000, grid_loss=0.95, sell_price=0.4)\n",
    "    # grid = grid_config(capacity=50000, grid_loss=0.95, sell_price=0.4)\n",
    "\n",
    "\n",
    "    # print(benefit)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 164212 characters]",
      "text/plain": [
       "<Figure size 1000x900 with 2 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "from matplotlib.colors import LinearSegmentedColormap\n",
    "df = overload_cnt\n",
    "df = df.astype(int)\n",
    "df.index = df.index / 1000\n",
    "df.columns = df.columns / 1000\n",
    "min_value = df.min().min()\n",
    "max_value = df.max().max()\n",
    "max_scale = max(abs(min_value/1000), abs(max_value/1000))\n",
    "\n",
    "plt.figure(figsize=figure_size)\n",
    "cmap = LinearSegmentedColormap.from_list(\"\", [\"white\", \"blue\"])\n",
    "ax = sns.heatmap(df/(4*24*365), fmt=\".00%\", cmap=cmap, vmin=0, vmax=1, annot=annot_unmet)\n",
    "cbar = ax.collections[0].colorbar\n",
    "cbar.set_ticks([0, 0.25, 0.5, 0.75, 1])\n",
    "cbar.set_ticklabels(['0%', '25%', '50%', '75%', '100%'])\n",
    "cbar.ax.yaxis.set_major_formatter(ticker.FuncFormatter(lambda x, pos: f'{x:.0%}'))\n",
    "\n",
    "X, Y = np.meshgrid(np.arange(df.shape[1]), np.arange(df.shape[0]))\n",
    "\n",
    "CS = ax.contour(X, Y, df, levels=np.linspace(df.min().min(), df.max().max(), 20), colors='black', alpha=0.5)\n",
    "\n",
    "ax.clabel(CS, inline=True, fontsize=10)\n",
    "\n",
    "\n",
    "plt.title(title_unmet)\n",
    "plt.gca().invert_yaxis()\n",
    "plt.xlabel('ESS Capacity (MWh)')\n",
    "plt.ylabel('PV Capacity (MW)')\n",
    "plt.savefig('plots/unmet.png')"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3",
   "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.11.9"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 2
}
