{
 "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",
    "逐次反応と併発反応が組み合わさった系の事例\n",
    "1. 未知の速度定数を含む、csvに書き込んだ反応式を読み込む。  \n",
    "2. 化学種の濃度の経時変化の実験データを読み込む。実験データには欠損を含んでもよい。  \n",
    "2. RxnIVPsolv(\"sample_data.csv\")でインスタンス化し、化学種ごとの微分型の反応速度式を作成する。速度定数が未知の素反応にはシンボリックな変数が割り振られる。  \n",
    "3. 作成した微分方程式を、数値解析可能な形式にする  \n",
    "4.  scipy.optimize.minimizeを使い、化学種ごとの濃度の経時変化が、実験値と近づくように、未知の速度定数を求める： get_ode_system()で必要なオブジェクトを取得。  \n",
    "5. 経時変化を図示する： matplotlibで結果をプロット  \n",
    "\n",
    "もしエラーが発生した場合は、debug_ode_system()メソッドで詳細な情報を確認できる。  \n",
    "\n",
    "## 引用文献  \n",
    "3) Kentaro TAMAKI, Seiichi YADA, Shiro KUDO, Reaction of 3- (1-Naphthyloxy) -2-hydroxy-1-propyltosylate with Isopropylamine, Journal of Synthetic Organic Chemistry, Japan, 1972, Volume 30, Issue 2, Pages 175-178, Released on J-STAGE November 13, 2009, Online ISSN 1883-6526, Print ISSN 0037-9980, https://doi.org/10.5059/yukigoseikyokaishi.30.175, https://www.jstage.jst.go.jp/article/yukigoseikyokaishi1943/30/2/30_2_175/_article/-char/en  \n",
    "\n",
    "- 文献中表1 アセトニトリル溶媒のデータ、および式 [1] の反応式を用いた。  \n",
    "- 併発反応と逐次反応が共存する系でのフィッティングを例示した。  "
   ]
  },
  {
   "cell_type": "markdown",
   "id": "f793b762-0cca-45f9-ad15-a0c092ac36e6",
   "metadata": {},
   "source": [
    "## 反応式を記載したcsvファイルを指定する  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "92b6caf1-fbe4-47c8-9bf7-15dc223b3b28",
   "metadata": {},
   "outputs": [],
   "source": [
    "file_path_rxn = './sample_data/ref3/sample_rxn_ref3AN.csv'  # CSVファイルのパスを指定"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "95324112-077e-4f27-9529-2a86aaa179f2",
   "metadata": {},
   "source": [
    "## 反応速度式をscipy.integrate.solve_ivpで処理できる連立微分方程式にする  "
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "75e2680b-f29a-4109-8707-97deb1943716",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import pandas as pd\n",
    "\n",
    "from rxnfit import RxnODEbuild, SolverConfig, RxnODEsolver\n",
    "from rxnfit.expdata_reader import expdata_read\n",
    "from rxnfit.expdata_fit_sci import ExpDataFitSci\n"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "e182c934",
   "metadata": {},
   "source": [
    "# 反応速度式の作成"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 3,
   "id": "aeb55f6f-83d3-4689-9921-c0f9c3c7216f",
   "metadata": {},
   "outputs": [],
   "source": [
    "builded_rxnode = RxnODEbuild(file_path_rxn)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "dc5a5d88-0b5d-4f67-bd1c-81209bae4d0a",
   "metadata": {
    "scrolled": true
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "number of species: 3\n",
      "unique species: ['Tos', 'Prop', 'Nep']\n",
      "rate constant: {'k1': k1, 'k2': k2, 'k3': k3}\n",
      "\n",
      "=== debug info ===\n",
      "Successfully created function for Tos with args: ['t', 'Tos', 'Prop', 'Nep']\n",
      "Successfully created function for Prop with args: ['t', 'Tos', 'Prop', 'Nep']\n",
      "Successfully created function for Nep with args: ['t', 'Tos', 'Prop', 'Nep']\n",
      "order of args: ['t', 'Tos', 'Prop', 'Nep']\n",
      "system of ODE: {'Tos': '-1/1*k1*Tos(t)-1/1*k2*Tos(t)', 'Prop': '1/1*k1*Tos(t)+1/1*k3*Nep(t)', 'Nep': '1/1*k2*Tos(t)-1/1*k3*Nep(t)'}\n"
     ]
    }
   ],
   "source": [
    "builded_rxnode.get_ode_info(debug_info=True)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "e98f2a67",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Successfully created function for Tos with args: ['t', 'Tos', 'Prop', 'Nep']\n",
      "Successfully created function for Prop with args: ['t', 'Tos', 'Prop', 'Nep']\n",
      "Successfully created function for Nep with args: ['t', 'Tos', 'Prop', 'Nep']\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[Eq(Derivative(Tos(t), t), -k1*Tos(t) - k2*Tos(t)),\n",
       " Eq(Derivative(Prop(t), t), k1*Tos(t) + k3*Nep(t)),\n",
       " Eq(Derivative(Nep(t), t), k2*Tos(t) - k3*Nep(t))]"
      ]
     },
     "execution_count": 5,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 作成した微分方程式\n",
    "builded_rxnode.get_ode_system()[0]"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 6,
   "id": "1cfb1b8a",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "{'k1': k1, 'k2': k2, 'k3': k3}\n"
     ]
    },
    {
     "data": {
      "text/plain": [
       "[sympy.core.symbol.Symbol, sympy.core.symbol.Symbol, sympy.core.symbol.Symbol]"
      ]
     },
     "execution_count": 6,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "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": 7,
   "id": "6d74af85",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "[([array([ 15,  30,  60, 120, 240]),\n",
       "   array([ 15,  30,  60, 120, 240]),\n",
       "   array([ 15,  30,  60, 120, 240])],\n",
       "  [array([0.24, 0.22, 0.13, 0.04, 0.01]),\n",
       "   array([0.03 , 0.06 , 0.07 , 0.03 , 0.001]),\n",
       "   array([0.02, 0.05, 0.11, 0.22, 0.27])])]"
      ]
     },
     "execution_count": 7,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "file_path_data = './sample_data/ref3/sample_timecourse_ref3AN.csv' # データファイルのパス\n",
    "df1 = pd.read_csv(file_path_data)\n",
    "\n",
    "expdata_read([df1,])  # 複数データフレームのリストを渡すとまとめて読み込み可能"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "6ef7e98f",
   "metadata": {},
   "source": [
    "### フィッティング  \n",
    "ExpDataFitSci でシンボリックな速度定数をフィッティング。  \n"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 8,
   "id": "73ee1c7b",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "text/plain": [
       "['k1', 'k2', 'k3']"
      ]
     },
     "execution_count": 8,
     "metadata": {},
     "output_type": "execute_result"
    }
   ],
   "source": [
    "# 速度定数の入力順を確認する  \n",
    "builded_rxnode.get_symbolic_rate_const_keys()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 9,
   "id": "a303dde2",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Successfully created function for Tos with args: ['t', 'Tos', 'Prop', 'Nep']\n",
      "Successfully created function for Prop with args: ['t', 'Tos', 'Prop', 'Nep']\n",
      "Successfully created function for Nep with args: ['t', 'Tos', 'Prop', 'Nep']\n",
      "Optimization success: True\n",
      "Fitted rate constants:\n",
      "  k1 = 1e-10\n",
      "  k2 = 0.0151172\n",
      "  k3 = 0.0365403\n",
      "Residual sum of squares: 0.00134838  R²: 0.985376\n"
     ]
    }
   ],
   "source": [
    "# ExpDataFitSci でフィッティング（t_range, df_list 必須）\n",
    "t_range = (float(df1.iloc[:, 0].min()), float(df1.iloc[:, 0].max()))\n",
    "fit_sci = ExpDataFitSci(builded_rxnode, [df1], t_range)\n",
    "result, param_info, fit_metrics = fit_sci.run_fit(p0={\"k1\": 0.001, \"k2\": 0.001, \"k3\": 0.001})  # initial guesses for symbolic rate constants"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 10,
   "id": "4b1e4ca9",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=== Time-course plot ===\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 47448 characters]",
      "text/plain": [
       "<Figure size 600x400 with 1 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\n",
      "=== Concentration at the final time point ===\n",
      "0:\n",
      "  Tos: 0.007999\n",
      "  Prop: 0.276395\n",
      "  Nep: 0.005607\n"
     ]
    }
   ],
   "source": [
    "# 経時変化を図示（plot_fitted_solution を使用）\n",
    "fit_sci.plot_fitted_solution(expdata_df=df1)"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.14.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
