{
  "cells": [
    {
      "cell_type": "markdown",
      "id": "bed4637d-8e0c-42b4-9331-8a39ca2381a6",
      "metadata": {},
      "source": [
        "Copyright (c) 2025 Mitsuru Ohno  \n",
        "Use of this source code is governed by a BSD-3-style  \n",
        "license that can be found in the LICENSE file.  "
      ]
    },
    {
      "cell_type": "markdown",
      "id": "911d53c0",
      "metadata": {},
      "source": [
        "## 当ノートブックのワークフロー  \n",
        "複数のデータフレームを横断的に処理する事例。3成分で相互平衡になっている。  \n",
        "1. 未知の速度定数を含む、csvに書き込んだ反応式を読み込む。  \n",
        "2. 化学種の濃度の経時変化の実験データを読み込む。初期濃度を変化させた複数の条件での実験結果を用い、全体を最適化できる速度定数を求めることを目標とする。  \n",
        "2. 化学種ごとの微分型の反応速度式を作成する。速度定数が未知の素反応にはシンボリックな変数が割り振られる、  \n",
        "3. 作成した微分方程式を、数値解析可能な形式にする  \n",
        "4.  scipy.optimize.minimizeを使い、化学種ごとの濃度の経時変化が、実験値と近づくように、未知の速度定数を求める。本ノートブックでは、0に近い速度定数を持つ素反応も含まれることを想定し、速度定数を対数処理してから最適化するモード（def run_fitの引数をuse_log_fit=Trueにする）を用いた。  \n",
        "5. 経時変化を図示する  \n",
        "\n",
        "残念ながら、df2の結果を再現できていない。複数のデータフレームを横断的に処理する実行例として掲載する。  "
      ]
    },
    {
      "cell_type": "markdown",
      "id": "f793b762-0cca-45f9-ad15-a0c092ac36e6",
      "metadata": {},
      "source": [
        "## 反応式を記載したcsvファイルを指定する  "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "92b6caf1-fbe4-47c8-9bf7-15dc223b3b28",
      "metadata": {},
      "outputs": [],
      "source": [
        "file_path_rxn = './sample_data/ref5/sample_rxn_ref5.csv'  # CSVファイルのパスを指定"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "f1e2b04c",
      "metadata": {},
      "outputs": [],
      "source": [
        "import sys\n",
        "from pathlib import Path\n",
        "\n",
        "# examples/ から ../src を sys.path に追加（rxnfit を import するため）\n",
        "src_path = Path(__file__).resolve().parent.parent / 'src' if '__file__' in dir() else Path('.').resolve().parent / 'src'\n",
        "sys.path.insert(0, str(src_path))"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "95324112-077e-4f27-9529-2a86aaa179f2",
      "metadata": {},
      "source": [
        "## 反応速度式をscipy.integrate.solve_ivpで処理できる連立微分方程式にする  "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "75e2680b-f29a-4109-8707-97deb1943716",
      "metadata": {},
      "outputs": [],
      "source": [
        "from dataclasses import dataclass, field\n",
        "from typing import Optional\n",
        "\n",
        "import numpy as np\n",
        "import pandas as pd\n",
        "import matplotlib.pyplot as plt\n",
        "from scipy.integrate import solve_ivp\n",
        "\n",
        "from sympy import Symbol\n",
        "from sympy.core.symbol import Symbol as SympySymbol\n",
        "import inspect\n",
        "\n",
        "from rxnfit.build_ode import RxnODEbuild, create_system_rhs\n",
        "from rxnfit.solv_ode import SolverConfig, RxnODEsolver\n",
        "from rxnfit.expdata_reader import expdata_read, get_y0_from_expdata\n",
        "from rxnfit.expdata_fit_sci import ExpDataFitSci"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "e182c934",
      "metadata": {},
      "source": [
        "# 反応速度式の作成"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "aeb55f6f-83d3-4689-9921-c0f9c3c7216f",
      "metadata": {},
      "outputs": [],
      "source": [
        "builded_rxnode = RxnODEbuild(file_path_rxn)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "dc5a5d88-0b5d-4f67-bd1c-81209bae4d0a",
      "metadata": {
        "scrolled": true
      },
      "outputs": [],
      "source": [
        "builded_rxnode.get_ode_info(debug_info=True)"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "e98f2a67",
      "metadata": {},
      "outputs": [],
      "source": [
        "# 作成した微分方程式\n",
        "builded_rxnode.get_ode_system()[0]"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "1cfb1b8a",
      "metadata": {},
      "outputs": [],
      "source": [
        "# 速度定数の確認\n",
        "print(builded_rxnode.rate_consts_dict)\n",
        "\n",
        "check_type = [v for v in builded_rxnode.rate_consts_dict.values()]\n",
        "[type(e) for e in check_type]"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "a0f9e382",
      "metadata": {},
      "source": [
        "## 経時変化の実験データを読み込み　　\n",
        "### データフレーム化  "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "6d74af85",
      "metadata": {},
      "outputs": [],
      "source": [
        "df1 = pd.read_csv(f'./sample_data/ref5/ref5_df1.csv')\n",
        "df2 = pd.read_csv(f'./sample_data/ref5/ref5_df2.csv')\n",
        "df3 = pd.read_csv(f'./sample_data/ref5/ref5_df3.csv')\n",
        "df4 = pd.read_csv(f'./sample_data/ref5/ref5_df4.csv')\n",
        "\n",
        "# plot_datasets で名前指定する場合、df.attrs['name'] を設定（省略可）\n",
        "df1.attrs['name'] = 'df1'\n",
        "df2.attrs['name'] = 'df2'\n",
        "df3.attrs['name'] = 'df3'\n",
        "df4.attrs['name'] = 'df4'\n",
        "\n",
        "expdata_read([df1, df2, df3, df4])  # 複数データフレームのリストを渡すとまとめて読み込み可能"
      ]
    },
    {
      "cell_type": "markdown",
      "id": "6ef7e98f",
      "metadata": {},
      "source": [
        "### フィッティング  \n",
        "ExpDataFitSci でシンボリックな速度定数をフィッティング。  \n"
      ]
    },
    {
      "cell_type": "code",
      "execution_count": null,
      "id": "a303dde2",
      "metadata": {},
      "outputs": [],
      "source": [
        "builded_rxnode = RxnODEbuild(file_path_rxn)\n",
        "t_range = (float(df1.iloc[:, 0].min()), float(df1.iloc[:, 0].max()))\n",
        "fit_sci = ExpDataFitSci(builded_rxnode, [df1, df2, df3, df4], t_range)\n",
        "result, param_info, fit_metrics = fit_sci.run_fit(\n",
        "    p0=[1e-6, 1e-6, 1e-1, 1e-1, 1e-1, 1e-1], # 未知の速度定数の初期値  \n",
        "    use_log_fit=True, # k1, k2が0に近いと予想されるため、対数変換した値でフィットする  \n",
        "    lower_bound=1e-10,\n",
        ")  "
      ]
    },
    {
      "cell_type": "code",
      "execution_count": 30,
      "id": "4627b275",
      "metadata": {},
      "outputs": [
        {
          "name": "stderr",
          "output_type": "stream",
          "text": [
            "C:\\Users\\mt_oh\\AppData\\Local\\Temp\\ipykernel_15128\\3208552477.py:2: UserWarning: Integration failed for dataset 2.\n",
            "  fit_sci.plot_fitted_solution(\n"
          ]
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "  Failed DataFrame (dataset 2):\n",
            "   hr    oXy    mXy    pXy\n",
            "0   0  0.005  0.986  0.009\n",
            "1   1  0.006  0.973  0.021\n",
            "2   2  0.026  0.933  0.041\n",
            "3   3  0.020  0.918  0.062\n",
            "4   5  0.046  0.860  0.094\n",
            "\n",
            "=== Time-course plot ===\n"
          ]
        },
        {
          "data": {
            "image/png": "[encoded data, 110448 characters]",
            "text/plain": [
              "<Figure size 1200x800 with 4 Axes>"
            ]
          },
          "metadata": {},
          "output_type": "display_data"
        },
        {
          "name": "stdout",
          "output_type": "stream",
          "text": [
            "\n",
            "=== Concentration at the final time point ===\n",
            "Dataset 1:\n",
            "  oXy: 0.339460\n",
            "  mXy: 0.333333\n",
            "  pXy: 0.327208\n",
            "Dataset 3:\n",
            "  oXy: 0.326911\n",
            "  mXy: 0.332999\n",
            "  pXy: 0.339089\n",
            "Dataset 4:\n",
            "  oXy: 0.333944\n",
            "  mXy: 0.333666\n",
            "  pXy: 0.333389\n"
          ]
        }
      ],
      "source": [
        "# 経時変化を図示（plot_fitted_solution を使用）\n",
        "fit_sci.plot_fitted_solution(\n",
        "    expdata_df=[df1, df2, df3, df4], \n",
        "    plot_datasets=[\"df1\", \"df2\", \"df3\", \"df4\"], \n",
        "    species=['oXy', 'mXy', 'pXy'], \n",
        "    subplot_layout=(2,2)\n",
        ")"
      ]
    }
  ],
  "metadata": {
    "kernelspec": {
      "display_name": "venv312",
      "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.12.10"
    }
  },
  "nbformat": 4,
  "nbformat_minor": 5
}
