{
 "cells": [
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "2a0c6b30",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Import necessary libraries\n",
    "import numpy as np\n",
    "import matplotlib.pyplot as plt\n",
    "from scipy.optimize import minimize\n",
    "from scipy.sparse import diags\n",
    "from scipy.sparse.linalg import spsolve\n",
    "import warnings\n",
    "warnings.filterwarnings('ignore')\n",
    "\n",
    "plt.rcParams['font.sans-serif'] = ['DejaVu Sans']\n",
    "plt.rcParams['axes.unicode_minus'] = False"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0fffdbe4",
   "metadata": {},
   "source": [
    "# 一维对流-扩散方程参数拟合\n",
    "\n",
    "## 问题描述\n",
    "\n",
    "我们要求解一维偏微分方程：\n",
    "\n",
    "$$\\frac{\\partial C}{\\partial t} = a \\frac{\\partial^2 C}{\\partial x^2} - b \\frac{\\partial C}{\\partial x}$$\n",
    "\n",
    "其中：\n",
    "- $a$ 是扩散系数（正数）\n",
    "- $b$ 是对流系数（可正可负）\n",
    "\n",
    "**边界条件：**\n",
    "- $C(0,t) = 1$ 当 $T_{fill} < t < T_{close}$\n",
    "- $C(0,t) = 0$ 当 $t < T_{fill}$ 或 $t > T_{close}$\n",
    "- $C(\\infty,t) = 0$ （无穷远边界）\n",
    "\n",
    "**时间范围：** $t \\in [-0.5, 2]$\n",
    "\n",
    "**观测数据：** 在某个位置（如 $x=L$）的离散观测数据 $C(L,t)$\n",
    "\n",
    "**目标：** 通过拟合观测数据来估计参数 $a$ 和 $b$。"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 33,
   "id": "b55760d1",
   "metadata": {},
   "outputs": [],
   "source": [
    "def solver(a, b, L, T_start, T_end, T_fill, T_close, nx, nt):\n",
    "\n",
    "    T_total = T_end - T_start\n",
    "    dx = L / (nx - 1)\n",
    "    dt = T_total / nt\n",
    "    x = np.linspace(0, L, nx)\n",
    "    t = np.linspace(T_start, T_end, nt + 1)\n",
    "    \n",
    "    # 检查稳定性条件\n",
    "    r_diff = a * dt / (dx**2)\n",
    "    r_conv = b * dt / dx\n",
    "    max_r_conv = 0.5\n",
    "    max_r_diff = 0.4\n",
    "\n",
    "    if abs(r_conv) > max_r_conv or abs(r_diff) > max_r_diff:\n",
    "        print(f\"不稳定 r_diff = {r_diff:.4f} r_conv = {r_conv:.4f} a = {a} b = {b} dx = {dx} dt = {dt}\")\n",
    "    \n",
    "    C = np.zeros((nt + 1, nx))\n",
    "    \n",
    "    t_fill_idx = np.argmin(np.abs(t - T_fill))\n",
    "    t_close_idx = np.argmin(np.abs(t - T_close))\n",
    "    C[t_fill_idx:t_close_idx, 0] = 1.0\n",
    "\n",
    "    # 使用混合格式：对流项用upwind，扩散项用中心差分\n",
    "    alpha = a * dt / (2 * dx**2)  # 扩散项系数\n",
    "    \n",
    "    if b >= 0:  # 正向对流\n",
    "        # 使用向后差分 (upwind)\n",
    "        beta = b * dt / dx\n",
    "        # 构建对流项系数矩阵\n",
    "        conv_main = np.ones(nx) * beta\n",
    "        conv_lower = np.ones(nx-1) * (-beta)\n",
    "        conv_upper = np.zeros(nx-1)\n",
    "    else:  # 负向对流\n",
    "        # 使用向前差分 (upwind)\n",
    "        beta = -b * dt / dx\n",
    "        conv_main = np.ones(nx) * (-beta)\n",
    "        conv_lower = np.zeros(nx-1)\n",
    "        conv_upper = np.ones(nx-1) * beta\n",
    "    \n",
    "    # 构建左侧矩阵 A (隐式项)\n",
    "    main_diag_A = np.ones(nx) * (1 + 2 * alpha) + conv_main * 0.5\n",
    "    upper_diag_A = np.ones(nx-1) * (-alpha) + conv_upper * 0.5\n",
    "    lower_diag_A = np.ones(nx-1) * (-alpha) + conv_lower * 0.5\n",
    "    \n",
    "    # 构建右侧矩阵 B (显式项)\n",
    "    main_diag_B = np.ones(nx) * (1 - 2 * alpha) - conv_main * 0.5\n",
    "    upper_diag_B = np.ones(nx-1) * alpha - conv_upper * 0.5\n",
    "    lower_diag_B = np.ones(nx-1) * alpha - conv_lower * 0.5\n",
    "    \n",
    "    A = diags([lower_diag_A, main_diag_A, upper_diag_A], [-1, 0, 1], shape=(nx, nx), format='csr')\n",
    "    B = diags([lower_diag_B, main_diag_B, upper_diag_B], [-1, 0, 1], shape=(nx, nx), format='csr')\n",
    "    \n",
    "    # 左边界条件 x=0: C(0,t) = boundary_value(t)\n",
    "    A[0, :] = 0\n",
    "    A[0, 0] = 1\n",
    "    B[0, :] = 0\n",
    "    \n",
    "    # 右边界条件 x=L: dC/dx = 0 (Neumann边界条件)\n",
    "    A[-1, :] = 0\n",
    "    A[-1, -1] = 1\n",
    "    A[-1, -2] = -1\n",
    "    B[-1, :] = 0\n",
    "    \n",
    "    for n in range(nt):\n",
    "        current_time = t[n+1]\n",
    "        \n",
    "        # 确定边界值\n",
    "        if T_fill <= current_time < T_close:\n",
    "            boundary_value = 1.0\n",
    "        else:\n",
    "            boundary_value = 0.0\n",
    "        \n",
    "        # 计算右侧向量\n",
    "        rhs = B @ C[n, :]\n",
    "        \n",
    "        # 应用边界条件\n",
    "        rhs[0] = boundary_value  # 左边界\n",
    "        rhs[-1] = 0  # 右边界的Neumann条件\n",
    "        \n",
    "        # 求解线性系统\n",
    "        try:\n",
    "            C[n+1, :] = spsolve(A, rhs)\n",
    "        except Exception as e:\n",
    "            print(f\"求解器在时间 {current_time:.4f} 时遇到困难: {str(e)}\")\n",
    "            C[n+1, :] = C[n, :]  # 使用前一时刻的解\n",
    "        \n",
    "        # 确保物理合理性\n",
    "        C[n+1, :] = np.maximum(C[n+1, :], 0)  # 浓度非负\n",
    "        \n",
    "        # 右边界的Neumann条件 dC/dx = 0\n",
    "        C[n+1, -1] = C[n+1, -2]\n",
    "    \n",
    "    return x, t, C"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 108,
   "id": "9eecacfa",
   "metadata": {},
   "outputs": [],
   "source": [
    "def estimation(observed_data, time_points, L, nx, nt):\n",
    "\n",
    "    def obj_func(params):\n",
    "        a, b = params\n",
    "        try:\n",
    "            if a <= 0:\n",
    "                return 1e6\n",
    "\n",
    "            x, t, C = solver(a=a, b=b, L=L * 2, \n",
    "                            T_start=time_points[0], T_end=time_points[-1],\n",
    "                            T_fill=-3, T_close=98,\n",
    "                            nx=nx, nt=nt)\n",
    "\n",
    "            obs_idx = np.argmin(np.abs(x - L))\n",
    "            model_prediction = C[:, obs_idx]\n",
    "            model_prediction = np.interp(time_points, t, model_prediction)\n",
    "            tstart_idx = np.argmin(np.abs(time_points - 0))\n",
    "            tend_idx = np.argmin(np.abs(time_points - 40))\n",
    "            mse1 = np.mean((model_prediction[tstart_idx:tend_idx] - observed_data[tstart_idx:tend_idx])**2)\n",
    "            tstart_idx = np.argmin(np.abs(time_points - 100))\n",
    "            tend_idx = np.argmin(np.abs(time_points - 140))\n",
    "            mse2 = np.mean((model_prediction[tstart_idx:tend_idx] - observed_data[tstart_idx:tend_idx])**2)\n",
    "            return mse1 + mse2\n",
    "        except Exception as e:\n",
    "            print(f\"计算错误：{str(e)}\")\n",
    "            return 1e6\n",
    "\n",
    "    print(\"开始拟合...\")\n",
    "    result = minimize(obj_func, x0=[0.1, 0.8], \n",
    "                     method='L-BFGS-B', bounds=[(0.001, 0.4), (0.7, 0.9)],\n",
    "                     options={'disp': True, 'maxiter': 100})\n",
    "    \n",
    "    params = result.x\n",
    "\n",
    "    print(f\"\\n拟合完成!\")\n",
    "    print(f\"估计的参数：D = {params[0]:.6f}, v = {params[1]:.6f}\")\n",
    "    print(f\"最终目标函数值：{result.fun:.8f}\")\n",
    "    print(f\"优化成功：{result.success}\")\n",
    "\n",
    "    return params"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 77,
   "id": "9a5e447c",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_results(x, t, C, observed_data, time_points, \n",
    "                L):\n",
    "    \n",
    "    fig, ((ax1, ax2)) = plt.subplots(1, 2, figsize=(15, 6))\n",
    "    \n",
    "    # 1. 浓度场的时空分布\n",
    "    im1 = ax1.contourf(x, t, C, levels=10, cmap='viridis')\n",
    "    ax1.set_xlabel('空间位置 x')\n",
    "    ax1.set_ylabel('时间 t')\n",
    "    ax1.set_title('浓度场 C(x,t) 的时空分布')\n",
    "    plt.colorbar(im1, ax=ax1, label='浓度 C')\n",
    "    \n",
    "    # 在x=L处画一条线\n",
    "    ax1.axvline(x=L, color='red', linestyle='--', alpha=0.7, label=f'观测位置 x={L}')\n",
    "    ax1.legend()\n",
    "    \n",
    "    # 2. 在x=L处的拟合对比\n",
    "    x_idx = np.argmin(np.abs(x - L))\n",
    "    model_at_L = C[:, x_idx]  # 模型在x=L处的预测\n",
    "    ax2.plot(t, model_at_L, 'b-', linewidth=2, label='模型预测')\n",
    "    ax2.plot(time_points, observed_data, 'ro', markersize=6, label='观测数据')\n",
    "    ax2.set_xlabel('时间 t')\n",
    "    ax2.set_ylabel(f'浓度 C({L},t)')\n",
    "    ax2.set_title(f'在 x={L} 处的拟合对比')\n",
    "    ax2.legend()\n",
    "    ax2.grid(True, alpha=0.3)\n",
    "    \n",
    "    plt.tight_layout()\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 109,
   "id": "e3e6444d",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "开始拟合...\n",
      "\n",
      "拟合完成!\n",
      "估计的参数：D = 0.073044, v = 0.802147\n",
      "最终目标函数值：0.00141410\n",
      "优化成功：True\n"
     ]
    }
   ],
   "source": [
    "time_points = np.array([-6.21452, -1.38528, 3.6556, 8.67724, 13.67964, 18.70128, 23.72292, 28.7638, 33.78544, 38.78784, 43.80948, 48.83112, 53.85276, 58.8744, 63.8768, 68.89844, 73.92008, 78.92248, 83.94412, 88.86956, 93.67956, 98.58576, 103.58816, 108.57132, 113.65068, 118.69156, 123.34764, 128.02296, 133.0446, 138.02776, 143.03016, 148.01332, 153.03496, 158.03736, 163.03976, 168.02292, 173.02532, 178.02772])\n",
    "observed_data = np.array([0.004, 0.004, 0.004, 0.004, 0.206, 0.79, 0.978, 0.995, 0.996, 0.999, 1, 0.998, 0.998, 1.001, 1, 1.001, 1.002, 1.001, 1.003, 1.002, 1.003, 1.002, 1.004, 1.004, 1, 0.233, 0.031, 0.013, 0.009, 0.006, 0.007, 0.008, 0.004, 0.004, 0.005, 0.005, 0.003, 0.005])\n",
    "\n",
    "# 检查数据有效性\n",
    "if len(time_points) != len(observed_data):\n",
    "    raise ValueError(\"时间点和观测数据的长度必须相同\")\n",
    "\n",
    "if np.any(time_points[1:] <= time_points[:-1]):\n",
    "    raise ValueError(\"时间点必须单调递增\")\n",
    "\n",
    "if time_points[0] > 0:\n",
    "    raise ValueError(\"时间点必须包含 t=0 或更早的时间\")\n",
    "\n",
    "params_fill, params_close = estimation(\n",
    "    observed_data, time_points, L=15.4, nx=301, nt=5000\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 101,
   "id": "2beea685",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 81724 characters]",
      "text/plain": [
       "<Figure size 1500x600 with 3 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "x, t, C = solver(\n",
    "    a = 0.07502, b = 0.805, \n",
    "    L=15.4*2, T_start=time_points[0], T_end=time_points[-1], T_fill=-2.8,\n",
    "    T_close=98, nx=301, nt=5000\n",
    ")\n",
    "\n",
    "plot_results(x, t, C, observed_data, time_points, L=15.4)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 106,
   "id": "339a769c",
   "metadata": {},
   "outputs": [],
   "source": [
    "def analyze_time_parameter_sensitivity(observed_data, time_points, L, nx, nt, fixed_a=0.01):\n",
    "    \"\"\"\n",
    "    分析 T_fill 和 T_close 参数的敏感性\n",
    "    \n",
    "    参数：\n",
    "    observed_data: 观测数据\n",
    "    time_points: 时间点\n",
    "    L: 观测位置\n",
    "    nx: 空间网格点数\n",
    "    fixed_a: 固定的扩散系数\n",
    "    \"\"\"\n",
    "    \n",
    "    print(\"=\" * 60)\n",
    "    print(\"T_fill 和 T_close 参数敏感性分析\")\n",
    "    print(\"=\" * 60)\n",
    "    \n",
    "    # T_fill 敏感性分析 (分析起始段数据：0-40时间范围)\n",
    "    print(\"1. T_fill 敏感性分析...\")\n",
    "    \n",
    "    # 定义T_fill的变化范围\n",
    "    T_fill_range = np.linspace(-4, -2, 10)  # 从-4到-2的范围\n",
    "    mse_T_fill = []\n",
    "    \n",
    "    for T_fill in T_fill_range:\n",
    "        try:\n",
    "            x, t, C = solver(fixed_a, b=0.8, L=L * 2, \n",
    "                            T_start=time_points[0], T_end=time_points[-1],\n",
    "                            T_fill=T_fill, T_close=100,\n",
    "                            nx=nx, nt=nt)\n",
    "\n",
    "            obs_idx = np.argmin(np.abs(x - L))\n",
    "            tstart_idx = np.argmin(np.abs(time_points - 0))\n",
    "            tend_idx = np.argmin(np.abs(time_points - 40))\n",
    "            model_prediction = C[:, obs_idx]\n",
    "            model_prediction = np.interp(time_points, t, model_prediction)\n",
    "            mse = np.mean((model_prediction[tstart_idx:tend_idx] - observed_data[tstart_idx:tend_idx])**2)\n",
    "            mse_T_fill.append(mse)\n",
    "            \n",
    "        except Exception as e:\n",
    "            print(f\"T_fill = {T_fill:.2f} 时计算失败: {str(e)}\")\n",
    "            mse_T_fill.append(1e6)\n",
    "    \n",
    "    # T_close 敏感性分析 (分析终止段数据：100-140时间范围)\n",
    "    print(\"2. T_close 敏感性分析...\")\n",
    "    \n",
    "    # 定义T_close的变化范围\n",
    "    T_close_range = np.linspace(97, 99, 10)  # 从97到99的范围\n",
    "    mse_T_close = []\n",
    "    \n",
    "    for T_close in T_close_range:\n",
    "        try:\n",
    "            x, t, C = solver(fixed_a, b=0.8, L=L * 2, \n",
    "                            T_start=time_points[0], T_end=time_points[-1],\n",
    "                            T_fill=0, T_close=T_close,\n",
    "                            nx=nx, nt=nt)\n",
    "\n",
    "            obs_idx = np.argmin(np.abs(x - L))\n",
    "            tstart_idx = np.argmin(np.abs(time_points - 100))\n",
    "            tend_idx = np.argmin(np.abs(time_points - 140))\n",
    "            model_prediction = C[:, obs_idx]\n",
    "            model_prediction = np.interp(time_points, t, model_prediction)\n",
    "            mse = np.mean((model_prediction[tstart_idx:tend_idx] - observed_data[tstart_idx:tend_idx])**2)\n",
    "            mse_T_close.append(mse)\n",
    "            \n",
    "        except Exception as e:\n",
    "            print(f\"T_close = {T_close:.2f} 时计算失败: {str(e)}\")\n",
    "            mse_T_close.append(1e6)\n",
    "    \n",
    "    # 可视化敏感性分析结果\n",
    "    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(15, 12))\n",
    "    \n",
    "    # 1. T_fill 敏感性曲线\n",
    "    ax1.plot(T_fill_range, mse_T_fill, 'b-o', linewidth=2, markersize=6)\n",
    "    ax1.set_xlabel('T_fill')\n",
    "    ax1.set_ylabel('均方误差 MSE')\n",
    "    ax1.set_title('T_fill 参数敏感性分析\\n(基于 0-40 时间段的拟合)')\n",
    "    ax1.grid(True, alpha=0.3)\n",
    "    ax1.set_yscale('log')  # 使用对数坐标便于观察\n",
    "    \n",
    "    # 找到最优T_fill\n",
    "    min_idx_fill = np.argmin(mse_T_fill)\n",
    "    optimal_T_fill = T_fill_range[min_idx_fill]\n",
    "    ax1.axvline(optimal_T_fill, color='red', linestyle='--', \n",
    "                label=f'最优值: {optimal_T_fill:.2f}')\n",
    "    ax1.legend()\n",
    "    \n",
    "    # 2. T_close 敏感性曲线\n",
    "    ax2.plot(T_close_range, mse_T_close, 'g-o', linewidth=2, markersize=6)\n",
    "    ax2.set_xlabel('T_close')\n",
    "    ax2.set_ylabel('均方误差 MSE')\n",
    "    ax2.set_title('T_close 参数敏感性分析\\n(基于 100-140 时间段的拟合)')\n",
    "    ax2.grid(True, alpha=0.3)\n",
    "    ax2.set_yscale('log')  # 使用对数坐标便于观察\n",
    "    \n",
    "    # 找到最优T_close\n",
    "    min_idx_close = np.argmin(mse_T_close)\n",
    "    optimal_T_close = T_close_range[min_idx_close]\n",
    "    ax2.axvline(optimal_T_close, color='red', linestyle='--', \n",
    "                label=f'最优值: {optimal_T_close:.2f}')\n",
    "    ax2.legend()\n",
    "    \n",
    "    # 3. 展示最优T_fill的拟合效果\n",
    "    print(f\"3. 绘制最优参数的拟合效果...\")\n",
    "    \n",
    "    # 使用最优T_fill绘制起始段拟合\n",
    "    x_opt, t_opt, C_opt_fill = solver(fixed_a, b=0.8, L=L * 2, \n",
    "                                     T_start=time_points[0], T_end=time_points[-1],\n",
    "                                     T_fill=optimal_T_fill, T_close=100,\n",
    "                                     nx=nx, nt=nt)\n",
    "    obs_idx = np.argmin(np.abs(x_opt - L))\n",
    "    model_pred_fill = C_opt_fill[:, obs_idx]\n",
    "    model_pred_fill = np.interp(time_points, t_opt, model_pred_fill)\n",
    "    \n",
    "    # 重点关注起始段\n",
    "    start_mask = (time_points >= -10) & (time_points <= 50)\n",
    "    ax3.plot(time_points[start_mask], observed_data[start_mask], 'ro', \n",
    "             markersize=6, label='观测数据')\n",
    "    ax3.plot(time_points[start_mask], model_pred_fill[start_mask], 'b-', \n",
    "             linewidth=2, label=f'模型预测 (T_fill={optimal_T_fill:.2f})')\n",
    "    ax3.axvline(optimal_T_fill, color='red', linestyle='--', alpha=0.7, \n",
    "                label=f'T_fill = {optimal_T_fill:.2f}')\n",
    "    ax3.set_xlabel('时间')\n",
    "    ax3.set_ylabel('浓度')\n",
    "    ax3.set_title('最优 T_fill 的起始段拟合效果')\n",
    "    ax3.legend()\n",
    "    ax3.grid(True, alpha=0.3)\n",
    "    \n",
    "    # 4. 展示最优T_close的拟合效果\n",
    "    # 使用最优T_close绘制终止段拟合\n",
    "    x_opt, t_opt, C_opt_close = solver(fixed_a, b=0.8, L=L * 2, \n",
    "                                      T_start=time_points[0], T_end=time_points[-1],\n",
    "                                      T_fill=0, T_close=optimal_T_close,\n",
    "                                      nx=nx, nt=nt)\n",
    "    obs_idx = np.argmin(np.abs(x_opt - L))\n",
    "    model_pred_close = C_opt_close[:, obs_idx]\n",
    "    model_pred_close = np.interp(time_points, t_opt, model_pred_close)\n",
    "    \n",
    "    # 重点关注终止段\n",
    "    end_mask = (time_points >= 90) & (time_points <= 150)\n",
    "    ax4.plot(time_points[end_mask], observed_data[end_mask], 'ro', \n",
    "             markersize=6, label='观测数据')\n",
    "    ax4.plot(time_points[end_mask], model_pred_close[end_mask], 'g-', \n",
    "             linewidth=2, label=f'模型预测 (T_close={optimal_T_close:.2f})')\n",
    "    ax4.axvline(optimal_T_close, color='red', linestyle='--', alpha=0.7, \n",
    "                label=f'T_close = {optimal_T_close:.2f}')\n",
    "    ax4.set_xlabel('时间')\n",
    "    ax4.set_ylabel('浓度')\n",
    "    ax4.set_title('最优 T_close 的终止段拟合效果')\n",
    "    ax4.legend()\n",
    "    ax4.grid(True, alpha=0.3)\n",
    "    \n",
    "    plt.tight_layout()\n",
    "    plt.show()\n",
    "    \n",
    "    # 打印敏感性分析结果\n",
    "    print(\"=\" * 60)\n",
    "    print(\"敏感性分析结果总结\")\n",
    "    print(\"=\" * 60)\n",
    "    print(f\"最优 T_fill:  {optimal_T_fill:.3f} (MSE = {mse_T_fill[min_idx_fill]:.6e})\")\n",
    "    print(f\"最优 T_close: {optimal_T_close:.3f} (MSE = {mse_T_close[min_idx_close]:.6e})\")\n",
    "    \n",
    "    # 计算敏感性指标\n",
    "    # 对于T_fill\n",
    "    mse_T_fill_clean = [mse for mse in mse_T_fill if mse < 1e5]\n",
    "    if len(mse_T_fill_clean) > 1:\n",
    "        sensitivity_T_fill = (max(mse_T_fill_clean) - min(mse_T_fill_clean)) / min(mse_T_fill_clean)\n",
    "        print(f\"T_fill 敏感性指标: {sensitivity_T_fill:.2f} (变化范围的相对差异)\")\n",
    "    \n",
    "    # 对于T_close\n",
    "    mse_T_close_clean = [mse for mse in mse_T_close if mse < 1e5]\n",
    "    if len(mse_T_close_clean) > 1:\n",
    "        sensitivity_T_close = (max(mse_T_close_clean) - min(mse_T_close_clean)) / min(mse_T_close_clean)\n",
    "        print(f\"T_close 敏感性指标: {sensitivity_T_close:.2f} (变化范围的相对差异)\")\n",
    "    \n",
    "    print(\"\\n解释:\")\n",
    "    print(\"- 敏感性指标越大，说明参数对模型结果的影响越敏感\")\n",
    "    print(\"- MSE曲线越陡峭，说明参数需要更精确的估计\")\n",
    "    print(\"- 最优值附近的平坦程度反映了参数估计的鲁棒性\")\n",
    "    \n",
    "    return {\n",
    "        'T_fill_range': T_fill_range,\n",
    "        'mse_T_fill': mse_T_fill,\n",
    "        'optimal_T_fill': optimal_T_fill,\n",
    "        'T_close_range': T_close_range,\n",
    "        'mse_T_close': mse_T_close,\n",
    "        'optimal_T_close': optimal_T_close\n",
    "    }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 107,
   "id": "fc5b176f",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "开始运行时间参数敏感性分析...\n",
      "使用固定扩散系数: a = 0.075020\n",
      "分析数据点数: 38\n",
      "\n",
      "==================================================\n",
      "1. 单独参数敏感性分析\n",
      "==================================================\n",
      "============================================================\n",
      "T_fill 和 T_close 参数敏感性分析\n",
      "============================================================\n",
      "1. T_fill 敏感性分析...\n",
      "2. T_close 敏感性分析...\n",
      "3. 绘制最优参数的拟合效果...\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 188544 characters]",
      "text/plain": [
       "<Figure size 1500x1200 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "============================================================\n",
      "敏感性分析结果总结\n",
      "============================================================\n",
      "最优 T_fill:  -3.111 (MSE = 4.252703e-04)\n",
      "最优 T_close: 97.889 (MSE = 1.015257e-03)\n",
      "T_fill 敏感性指标: 5.25 (变化范围的相对差异)\n",
      "T_close 敏感性指标: 2.96 (变化范围的相对差异)\n",
      "\n",
      "解释:\n",
      "- 敏感性指标越大，说明参数对模型结果的影响越敏感\n",
      "- MSE曲线越陡峭，说明参数需要更精确的估计\n",
      "- 最优值附近的平坦程度反映了参数估计的鲁棒性\n"
     ]
    }
   ],
   "source": [
    "# 运行 T_fill 和 T_close 的敏感性分析\n",
    "print(\"开始运行时间参数敏感性分析...\")\n",
    "\n",
    "# 使用已有的数据进行分析\n",
    "# 使用已估计的扩散系数作为固定参数\n",
    "fixed_diffusion_coeff = 0.07502  # 使用之前估计的扩散系数\n",
    "\n",
    "print(f\"使用固定扩散系数: a = {fixed_diffusion_coeff:.6f}\")\n",
    "print(f\"分析数据点数: {len(observed_data)}\")\n",
    "\n",
    "# 1. 单独敏感性分析\n",
    "print(\"\\n\" + \"=\"*50)\n",
    "print(\"1. 单独参数敏感性分析\")\n",
    "print(\"=\"*50)\n",
    "\n",
    "sensitivity_results = analyze_time_parameter_sensitivity(\n",
    "    observed_data, time_points, L=15.4, nx=301, nt=5000,\n",
    "    fixed_a=fixed_diffusion_coeff\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 111,
   "id": "898bc87c",
   "metadata": {},
   "outputs": [],
   "source": [
    "def analyze_diffusion_coefficient_sensitivity(observed_data, time_points, L, nx, nt, \n",
    "                                            estimated_a, estimated_b, \n",
    "                                            a_range_factor=0.3, num_points=20):\n",
    "    \"\"\"\n",
    "    分析扩散系数 a (D) 的敏感性和置信度\n",
    "    \n",
    "    参数：\n",
    "    observed_data: 观测数据\n",
    "    time_points: 时间点\n",
    "    L: 观测位置\n",
    "    nx, nt: 网格参数\n",
    "    estimated_a: 估计的扩散系数\n",
    "    estimated_b: 估计的对流系数（固定）\n",
    "    a_range_factor: 敏感性分析的范围因子（±30%默认）\n",
    "    num_points: 分析点数\n",
    "    \n",
    "    返回：\n",
    "    sensitivity_analysis: 敏感性分析结果字典\n",
    "    \"\"\"\n",
    "    \n",
    "    print(\"=\" * 60)\n",
    "    print(\"扩散系数 D (a) 敏感性和置信度分析\")\n",
    "    print(\"=\" * 60)\n",
    "    print(f\"估计的扩散系数: a = {estimated_a:.6f}\")\n",
    "    print(f\"固定的对流系数: b = {estimated_b:.6f}\")\n",
    "    print(f\"分析范围: ±{a_range_factor*100}%\")\n",
    "    \n",
    "    # 定义扩散系数的变化范围\n",
    "    a_min = estimated_a * (1 - a_range_factor)\n",
    "    a_max = estimated_a * (1 + a_range_factor)\n",
    "    a_range = np.linspace(a_min, a_max, num_points)\n",
    "    \n",
    "    # 计算每个扩散系数下的MSE\n",
    "    mse_values = []\n",
    "    valid_solutions = []\n",
    "    \n",
    "    print(f\"\\\\n计算 {num_points} 个扩散系数值的MSE...\")\n",
    "    \n",
    "    for i, a_test in enumerate(a_range):\n",
    "        try:\n",
    "            # 使用固定的对流系数和测试的扩散系数\n",
    "            x, t, C = solver(a=a_test, b=estimated_b, L=L * 2, \n",
    "                            T_start=time_points[0], T_end=time_points[-1],\n",
    "                            T_fill=-3, T_close=98,\n",
    "                            nx=nx, nt=nt)\n",
    "\n",
    "            obs_idx = np.argmin(np.abs(x - L))\n",
    "            model_prediction = C[:, obs_idx]\n",
    "            model_prediction = np.interp(time_points, t, model_prediction)\n",
    "            \n",
    "            # 计算两个时间段的MSE（与原拟合目标函数一致）\n",
    "            tstart_idx = np.argmin(np.abs(time_points - 0))\n",
    "            tend_idx = np.argmin(np.abs(time_points - 40))\n",
    "            mse1 = np.mean((model_prediction[tstart_idx:tend_idx] - observed_data[tstart_idx:tend_idx])**2)\n",
    "            \n",
    "            tstart_idx = np.argmin(np.abs(time_points - 100))\n",
    "            tend_idx = np.argmin(np.abs(time_points - 140))\n",
    "            mse2 = np.mean((model_prediction[tstart_idx:tend_idx] - observed_data[tstart_idx:tend_idx])**2)\n",
    "            \n",
    "            total_mse = mse1 + mse2\n",
    "            mse_values.append(total_mse)\n",
    "            valid_solutions.append(True)\n",
    "            \n",
    "            if (i + 1) % 5 == 0:\n",
    "                print(f\"  进度: {i+1}/{num_points}, 当前 a = {a_test:.6f}, MSE = {total_mse:.6e}\")\n",
    "                \n",
    "        except Exception as e:\n",
    "            print(f\"  a = {a_test:.6f} 时计算失败: {str(e)}\")\n",
    "            mse_values.append(np.inf)\n",
    "            valid_solutions.append(False)\n",
    "    \n",
    "    mse_values = np.array(mse_values)\n",
    "    valid_solutions = np.array(valid_solutions)\n",
    "    \n",
    "    # 找到最小MSE和相应的扩散系数\n",
    "    valid_mse = mse_values[valid_solutions]\n",
    "    valid_a_range = a_range[valid_solutions]\n",
    "    \n",
    "    if len(valid_mse) == 0:\n",
    "        print(\"错误：没有有效的解！\")\n",
    "        return None\n",
    "        \n",
    "    min_mse_idx = np.argmin(valid_mse)\n",
    "    optimal_a = valid_a_range[min_mse_idx]\n",
    "    min_mse = valid_mse[min_mse_idx]\n",
    "    \n",
    "    print(f\"\\\\n从敏感性分析得到的最优扩散系数: a = {optimal_a:.6f}\")\n",
    "    print(f\"对应的最小MSE: {min_mse:.6e}\")\n",
    "    \n",
    "    # 计算置信区间（基于MSE增加的阈值）\n",
    "    # 使用卡方分布的近似：MSE增加不超过原值的某个倍数\n",
    "    confidence_thresholds = [1.1, 1.2, 1.5, 2.0]  # MSE增加10%, 20%, 50%, 100%\n",
    "    confidence_intervals = {}\n",
    "    \n",
    "    for threshold in confidence_thresholds:\n",
    "        threshold_mse = min_mse * threshold\n",
    "        within_threshold = valid_mse <= threshold_mse\n",
    "        \n",
    "        if np.any(within_threshold):\n",
    "            a_within_threshold = valid_a_range[within_threshold]\n",
    "            ci_lower = np.min(a_within_threshold)\n",
    "            ci_upper = np.max(a_within_threshold)\n",
    "            ci_width = ci_upper - ci_lower\n",
    "            relative_width = ci_width / optimal_a * 100\n",
    "            \n",
    "            confidence_intervals[threshold] = {\n",
    "                'lower': ci_lower,\n",
    "                'upper': ci_upper, \n",
    "                'width': ci_width,\n",
    "                'relative_width': relative_width\n",
    "            }\n",
    "            \n",
    "            print(f\"MSE增加{(threshold-1)*100:.0f}%的置信区间: [{ci_lower:.6f}, {ci_upper:.6f}] (相对宽度: {relative_width:.1f}%)\")\n",
    "    \n",
    "    # 计算敏感性指标\n",
    "    # 1. 在最优点附近的MSE梯度\n",
    "    optimal_idx = np.where(valid_a_range == optimal_a)[0][0]\n",
    "    if optimal_idx > 0 and optimal_idx < len(valid_a_range) - 1:\n",
    "        left_mse = valid_mse[optimal_idx - 1]\n",
    "        right_mse = valid_mse[optimal_idx + 1]\n",
    "        left_a = valid_a_range[optimal_idx - 1]\n",
    "        right_a = valid_a_range[optimal_idx + 1]\n",
    "        \n",
    "        # 数值梯度（MSE对a的导数）\n",
    "        gradient = (right_mse - left_mse) / (right_a - left_a)\n",
    "        # 相对敏感性（归一化的梯度）\n",
    "        relative_sensitivity = abs(gradient) * optimal_a / min_mse\n",
    "        \n",
    "        print(f\"\\\\n敏感性指标:\")\n",
    "        print(f\"  MSE梯度: {gradient:.2e} (MSE单位/扩散系数单位)\")\n",
    "        print(f\"  相对敏感性: {relative_sensitivity:.2f} (无量纲)\")\n",
    "    else:\n",
    "        gradient = np.nan\n",
    "        relative_sensitivity = np.nan\n",
    "        print(f\"\\\\n无法计算敏感性指标（最优点在边界）\")\n",
    "    \n",
    "    # 可视化敏感性分析结果\n",
    "    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(15, 12))\n",
    "    \n",
    "    # 1. MSE vs 扩散系数曲线\n",
    "    ax1.plot(valid_a_range, valid_mse, 'b-o', linewidth=2, markersize=4)\n",
    "    ax1.axvline(optimal_a, color='red', linestyle='--', linewidth=2, \n",
    "                label=f'最优值: a = {optimal_a:.6f}')\n",
    "    ax1.axvline(estimated_a, color='green', linestyle=':', linewidth=2, \n",
    "                label=f'估计值: a = {estimated_a:.6f}')\n",
    "    \n",
    "    # 添加置信区间\n",
    "    for threshold, ci in confidence_intervals.items():\n",
    "        if threshold == 1.2:  # 只显示20%置信区间避免图形过于复杂\n",
    "            ax1.axvspan(ci['lower'], ci['upper'], alpha=0.2, color='orange',\n",
    "                       label=f'MSE+{(threshold-1)*100:.0f}%置信区间')\n",
    "    \n",
    "    ax1.set_xlabel('扩散系数 a')\n",
    "    ax1.set_ylabel('均方误差 MSE')\n",
    "    ax1.set_title('扩散系数敏感性分析')\n",
    "    ax1.set_yscale('log')\n",
    "    ax1.legend()\n",
    "    ax1.grid(True, alpha=0.3)\n",
    "    \n",
    "    # 2. 相对误差分析\n",
    "    relative_errors = np.abs(valid_a_range - optimal_a) / optimal_a * 100\n",
    "    ax2.plot(relative_errors, valid_mse, 'g-o', linewidth=2, markersize=4)\n",
    "    ax2.axhline(min_mse, color='red', linestyle='--', alpha=0.7, label='最小MSE')\n",
    "    \n",
    "    # 标记置信区间\n",
    "    for threshold, ci in confidence_intervals.items():\n",
    "        threshold_mse = min_mse * threshold\n",
    "        ax2.axhline(threshold_mse, color='orange', linestyle=':', alpha=0.7,\n",
    "                   label=f'MSE+{(threshold-1)*100:.0f}%阈值')\n",
    "        break  # 只显示一个阈值\n",
    "    \n",
    "    ax2.set_xlabel('相对误差 (%)')\n",
    "    ax2.set_ylabel('均方误差 MSE')\n",
    "    ax2.set_title('相对误差 vs MSE')\n",
    "    ax2.set_yscale('log')\n",
    "    ax2.legend()\n",
    "    ax2.grid(True, alpha=0.3)\n",
    "    \n",
    "    # 3. 使用最优扩散系数的拟合效果对比\n",
    "    x_opt, t_opt, C_opt = solver(a=optimal_a, b=estimated_b, L=L * 2, \n",
    "                                T_start=time_points[0], T_end=time_points[-1],\n",
    "                                T_fill=-3, T_close=98, nx=nx, nt=nt)\n",
    "    obs_idx = np.argmin(np.abs(x_opt - L))\n",
    "    model_pred_opt = C_opt[:, obs_idx]\n",
    "    model_pred_opt = np.interp(time_points, t_opt, model_pred_opt)\n",
    "    \n",
    "    ax3.plot(time_points, observed_data, 'ro', markersize=6, label='观测数据')\n",
    "    ax3.plot(time_points, model_pred_opt, 'b-', linewidth=2, \n",
    "             label=f'最优拟合 (a={optimal_a:.6f})')\n",
    "    \n",
    "    if abs(optimal_a - estimated_a) > 1e-6:\n",
    "        x_est, t_est, C_est = solver(a=estimated_a, b=estimated_b, L=L * 2, \n",
    "                                    T_start=time_points[0], T_end=time_points[-1],\n",
    "                                    T_fill=-3, T_close=98, nx=nx, nt=nt)\n",
    "        model_pred_est = C_est[:, obs_idx]\n",
    "        model_pred_est = np.interp(time_points, t_est, model_pred_est)\n",
    "        ax3.plot(time_points, model_pred_est, 'g--', linewidth=2, \n",
    "                 label=f'原估计 (a={estimated_a:.6f})')\n",
    "    \n",
    "    ax3.set_xlabel('时间')\n",
    "    ax3.set_ylabel('浓度')\n",
    "    ax3.set_title('拟合效果对比')\n",
    "    ax3.legend()\n",
    "    ax3.grid(True, alpha=0.3)\n",
    "    \n",
    "    # 4. 置信区间总结\n",
    "    ax4.axis('off')\n",
    "    y_pos = 0.9\n",
    "    ax4.text(0.05, y_pos, '置信度分析总结', fontsize=16, weight='bold', transform=ax4.transAxes)\n",
    "    y_pos -= 0.1\n",
    "    \n",
    "    ax4.text(0.05, y_pos, f'最优扩散系数: {optimal_a:.6f}', fontsize=12, transform=ax4.transAxes)\n",
    "    y_pos -= 0.08\n",
    "    ax4.text(0.05, y_pos, f'原估计扩散系数: {estimated_a:.6f}', fontsize=12, transform=ax4.transAxes)\n",
    "    y_pos -= 0.08\n",
    "    ax4.text(0.05, y_pos, f'差异: {abs(optimal_a - estimated_a):.6f} ({abs(optimal_a - estimated_a)/estimated_a*100:.2f}%)', \n",
    "             fontsize=12, transform=ax4.transAxes)\n",
    "    y_pos -= 0.12\n",
    "    \n",
    "    ax4.text(0.05, y_pos, '置信区间 (MSE增加阈值):', fontsize=14, weight='bold', transform=ax4.transAxes)\n",
    "    y_pos -= 0.08\n",
    "    \n",
    "    for threshold, ci in confidence_intervals.items():\n",
    "        if y_pos > 0.1:\n",
    "            ax4.text(0.05, y_pos, f'  MSE+{(threshold-1)*100:.0f}%: [{ci[\"lower\"]:.6f}, {ci[\"upper\"]:.6f}] (±{ci[\"relative_width\"]:.1f}%)', \n",
    "                     fontsize=11, transform=ax4.transAxes)\n",
    "            y_pos -= 0.08\n",
    "    \n",
    "    if not np.isnan(relative_sensitivity):\n",
    "        y_pos -= 0.05\n",
    "        ax4.text(0.05, y_pos, f'相对敏感性指标: {relative_sensitivity:.2f}', fontsize=12, weight='bold', transform=ax4.transAxes)\n",
    "        y_pos -= 0.08\n",
    "        if relative_sensitivity < 1:\n",
    "            sensitivity_level = \"低敏感性 (参数估计较稳定)\"\n",
    "        elif relative_sensitivity < 5:\n",
    "            sensitivity_level = \"中等敏感性\"\n",
    "        else:\n",
    "            sensitivity_level = \"高敏感性 (需要精确数据)\"\n",
    "        ax4.text(0.05, y_pos, f'敏感性水平: {sensitivity_level}', fontsize=11, transform=ax4.transAxes)\n",
    "    \n",
    "    plt.tight_layout()\n",
    "    plt.show()\n",
    "    \n",
    "    # 返回分析结果\n",
    "    sensitivity_analysis = {\n",
    "        'a_range': valid_a_range,\n",
    "        'mse_values': valid_mse,\n",
    "        'optimal_a': optimal_a,\n",
    "        'min_mse': min_mse,\n",
    "        'confidence_intervals': confidence_intervals,\n",
    "        'gradient': gradient,\n",
    "        'relative_sensitivity': relative_sensitivity,\n",
    "        'estimated_a': estimated_a\n",
    "    }\n",
    "    \n",
    "    return sensitivity_analysis"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 112,
   "id": "98c423ee",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "开始分析扩散系数 D (a) 的敏感性和置信度...\n",
      "使用已存在的拟合参数: a = 0.073044, b = 0.802147\n",
      "============================================================\n",
      "扩散系数 D (a) 敏感性和置信度分析\n",
      "============================================================\n",
      "估计的扩散系数: a = 0.073044\n",
      "固定的对流系数: b = 0.802147\n",
      "分析范围: ±40.0%\n",
      "\\n计算 25 个扩散系数值的MSE...\n",
      "  进度: 5/25, 当前 a = 0.053566, MSE = 1.634108e-03\n",
      "  进度: 10/25, 当前 a = 0.065740, MSE = 1.442192e-03\n",
      "  进度: 15/25, 当前 a = 0.077914, MSE = 1.425519e-03\n",
      "  进度: 20/25, 当前 a = 0.090088, MSE = 1.542552e-03\n",
      "  进度: 25/25, 当前 a = 0.102262, MSE = 1.762572e-03\n",
      "\\n从敏感性分析得到的最优扩散系数: a = 0.073044\n",
      "对应的最小MSE: 1.414102e-03\n",
      "MSE增加10%的置信区间: [0.058435, 0.090088] (相对宽度: 43.3%)\n",
      "MSE增加20%的置信区间: [0.053566, 0.097392] (相对宽度: 60.0%)\n",
      "MSE增加50%的置信区间: [0.043827, 0.102262] (相对宽度: 80.0%)\n",
      "MSE增加100%的置信区间: [0.043827, 0.102262] (相对宽度: 80.0%)\n",
      "\\n敏感性指标:\n",
      "  MSE梯度: -2.06e-05 (MSE单位/扩散系数单位)\n",
      "  相对敏感性: 0.00 (无量纲)\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 242312 characters]",
      "text/plain": [
       "<Figure size 1500x1200 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\\n============================================================\n",
      "扩散系数敏感性分析完成！\n",
      "============================================================\n",
      "\\n关键结果总结:\n",
      "  原估计扩散系数: 0.073044\n",
      "  敏感性分析最优值: 0.073044\n",
      "  相对差异: 0.00%\n",
      "  最小MSE: 1.414102e-03\n",
      "  相对敏感性指标: 0.00\n",
      "  → 参数估计稳定性: 高 (低敏感性)\n",
      "\\n置信度评估:\n",
      "  标准置信区间 (MSE+20%): [0.053566, 0.097392]\n",
      "  相对不确定性: ±30.0%\n",
      "  置信度评级: 低置信度\n"
     ]
    }
   ],
   "source": [
    "# 运行扩散系数 D (a) 的敏感性分析\n",
    "print(\"开始分析扩散系数 D (a) 的敏感性和置信度...\")\n",
    "\n",
    "# 从之前的拟合结果获取参数\n",
    "# 假设您有 params_fill 和 params_close 或其他拟合结果\n",
    "try:\n",
    "    # 尝试获取已存在的拟合参数\n",
    "    if 'params_fill' in locals() and 'params_close' in locals():\n",
    "        estimated_a = params_fill  # 扩散系数\n",
    "        estimated_b = params_close  # 对流系数\n",
    "        print(f\"使用已存在的拟合参数: a = {estimated_a:.6f}, b = {estimated_b:.6f}\")\n",
    "    else:\n",
    "        # 使用默认值（您可以根据实际情况修改）\n",
    "        estimated_a = 0.075  # 从您的代码中看到的值\n",
    "        estimated_b = 0.805  # 从您的代码中看到的值\n",
    "        print(f\"使用默认参数: a = {estimated_a:.6f}, b = {estimated_b:.6f}\")\n",
    "        print(\"提示: 如果您有最新的拟合结果，请修改上面的estimated_a和estimated_b值\")\n",
    "    \n",
    "    # 执行敏感性分析\n",
    "    diffusion_sensitivity = analyze_diffusion_coefficient_sensitivity(\n",
    "        observed_data, time_points, L=15.4, nx=301, nt=5000,\n",
    "        estimated_a=estimated_a, estimated_b=estimated_b,\n",
    "        a_range_factor=0.4,  # ±40%的范围\n",
    "        num_points=25        # 25个测试点\n",
    "    )\n",
    "    \n",
    "    if diffusion_sensitivity is not None:\n",
    "        print(\"\\\\n\" + \"=\"*60)\n",
    "        print(\"扩散系数敏感性分析完成！\")\n",
    "        print(\"=\"*60)\n",
    "        \n",
    "        # 提取关键结果\n",
    "        optimal_a = diffusion_sensitivity['optimal_a']\n",
    "        min_mse = diffusion_sensitivity['min_mse']\n",
    "        confidence_intervals = diffusion_sensitivity['confidence_intervals']\n",
    "        relative_sensitivity = diffusion_sensitivity['relative_sensitivity']\n",
    "        \n",
    "        print(f\"\\\\n关键结果总结:\")\n",
    "        print(f\"  原估计扩散系数: {estimated_a:.6f}\")\n",
    "        print(f\"  敏感性分析最优值: {optimal_a:.6f}\")\n",
    "        print(f\"  相对差异: {abs(optimal_a - estimated_a)/estimated_a*100:.2f}%\")\n",
    "        print(f\"  最小MSE: {min_mse:.6e}\")\n",
    "        \n",
    "        if not np.isnan(relative_sensitivity):\n",
    "            print(f\"  相对敏感性指标: {relative_sensitivity:.2f}\")\n",
    "            if relative_sensitivity < 1:\n",
    "                print(\"  → 参数估计稳定性: 高 (低敏感性)\")\n",
    "            elif relative_sensitivity < 5:\n",
    "                print(\"  → 参数估计稳定性: 中等\")\n",
    "            else:\n",
    "                print(\"  → 参数估计稳定性: 低 (高敏感性，需要更精确的数据)\")\n",
    "        \n",
    "        print(f\"\\\\n置信度评估:\")\n",
    "        if len(confidence_intervals) > 0:\n",
    "            # 使用20%MSE增加作为标准置信区间\n",
    "            if 1.2 in confidence_intervals:\n",
    "                ci = confidence_intervals[1.2]\n",
    "                print(f\"  标准置信区间 (MSE+20%): [{ci['lower']:.6f}, {ci['upper']:.6f}]\")\n",
    "                print(f\"  相对不确定性: ±{ci['relative_width']/2:.1f}%\")\n",
    "                \n",
    "                if ci['relative_width'] < 10:\n",
    "                    confidence_level = \"高置信度\"\n",
    "                elif ci['relative_width'] < 30:\n",
    "                    confidence_level = \"中等置信度\"\n",
    "                else:\n",
    "                    confidence_level = \"低置信度\"\n",
    "                    \n",
    "                print(f\"  置信度评级: {confidence_level}\")\n",
    "            else:\n",
    "                print(\"  未能计算标准置信区间\")\n",
    "        else:\n",
    "            print(\"  警告: 未能计算任何置信区间\")\n",
    "            \n",
    "except Exception as e:\n",
    "    print(f\"敏感性分析出错: {str(e)}\")\n",
    "    print(\"请检查数据和参数设置\")"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "ea7e502d",
   "metadata": {},
   "source": [
    "# 化学非平衡模型：多速率多物质传递模型\n",
    "\n",
    "## 问题描述\n",
    "\n",
    "多相耦合系统，包含流体相浓度 $C(x,t)$ 和固体相浓度 $S(x,t)$：\n",
    "\n",
    "**流体相方程：**\n",
    "$$\\frac{\\partial C}{\\partial t} = a \\frac{\\partial^2 C}{\\partial x^2} - b \\frac{\\partial C}{\\partial x} - \\frac{\\partial S}{\\partial t}$$\n",
    "\n",
    "**固体相方程（双位点一阶动力学吸附）：**\n",
    "$$ S=S_{1}+S_{2}+S_{3}+S_{4}$$\n",
    "$$ \\frac{\\partial S_{1}}{\\partial t} = c_1 \\cdot C - d_1 \\cdot S_{1}$$\n",
    "$$ \\frac{\\partial S_{2}}{\\partial t} = c_2 \\cdot C - d_2 \\cdot S_{2}$$\n",
    "$$ \\frac{\\partial S_{3}}{\\partial t} = c_3 \\cdot C - d_3 \\cdot S_{3}$$\n",
    "$$ S_{4} = e \\cdot C$$\n",
    "\n",
    "其中：\n",
    "- $a, b$ 是已知的扩散和对流系数\n",
    "- $c_i, d_i, e$ 是需要拟合的参数\n",
    "- $c_i$ 表示吸附速率系数\n",
    "- $d_i$ 表示释放速率系数\n",
    "- $e$ 表示瞬时吸附比例\n",
    "\n",
    "边界条件：$C(0,t) = 1$, $T_{fill}<t<T_{close}$，观测数据：$C(L,t)$"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 2,
   "id": "8de67c7d",
   "metadata": {},
   "outputs": [],
   "source": [
    "def solver_coupled(a, b, c1, d1, c2, d2, e, L, T_start, T_end, T_fill, T_close, nx, nt):\n",
    "\n",
    "    T_total = T_end - T_start\n",
    "    dx = L / (nx - 1)\n",
    "    dt = T_total / nt\n",
    "    x = np.linspace(0, L, nx)\n",
    "    t = np.linspace(T_start, T_end, nt + 1)\n",
    "    \n",
    "    r_diff = a * dt / (dx**2)\n",
    "    r_conv = b * dt / dx\n",
    "    max_r_conv = 0.5\n",
    "    max_r_diff = 0.4\n",
    "    \n",
    "    if abs(r_conv) > max_r_conv or abs(r_diff) > max_r_diff:\n",
    "        print(f\"双位点耦合系统不稳定 r_diff = {r_diff:.4f} r_conv = {r_conv:.4f}\")\n",
    "        print(f\"a = {a} b = {b} dx = {dx} dt = {dt}\")\n",
    "    \n",
    "    C = np.zeros((nt + 1, nx))\n",
    "    S1 = np.zeros((nt + 1, nx))\n",
    "    S2 = np.zeros((nt + 1, nx))\n",
    "    S3 = np.zeros((nt + 1, nx))\n",
    "    S = np.zeros((nt + 1, nx))  # 总固体相浓度 S = S1 + S2 + S3\n",
    "\n",
    "    t_fill_idx = np.argmin(np.abs(t - T_fill))\n",
    "    t_close_idx = np.argmin(np.abs(t - T_close))\n",
    "    C[t_fill_idx:t_close_idx, 0] = 1.0\n",
    "    \n",
    "    # 使用半隐式格式求解耦合系统\n",
    "    # 对扩散项和对流项使用隐式，对耦合项使用显式\n",
    "    \n",
    "    alpha = a * dt / (2 * dx**2)  # 扩散项系数\n",
    "    \n",
    "    if b >= 0:  # 正向对流\n",
    "        beta = b * dt / dx\n",
    "        conv_main = np.ones(nx) * beta\n",
    "        conv_lower = np.ones(nx-1) * (-beta)\n",
    "        conv_upper = np.zeros(nx-1)\n",
    "    else:  # 负向对流\n",
    "        beta = -b * dt / dx\n",
    "        conv_main = np.ones(nx) * (-beta)\n",
    "        conv_lower = np.zeros(nx-1)\n",
    "        conv_upper = np.ones(nx-1) * beta\n",
    "    \n",
    "    main_diag_A_C = np.ones(nx) * (1 + 2 * alpha) + conv_main * 0.5\n",
    "    upper_diag_A_C = np.ones(nx-1) * (-alpha) + conv_upper * 0.5\n",
    "    lower_diag_A_C = np.ones(nx-1) * (-alpha) + conv_lower * 0.5\n",
    "    \n",
    "    main_diag_B_C = np.ones(nx) * (1 - 2 * alpha) - conv_main * 0.5\n",
    "    upper_diag_B_C = np.ones(nx-1) * alpha - conv_upper * 0.5\n",
    "    lower_diag_B_C = np.ones(nx-1) * alpha - conv_lower * 0.5\n",
    "    \n",
    "    A_C = diags([lower_diag_A_C, main_diag_A_C, upper_diag_A_C], \n",
    "                [-1, 0, 1], shape=(nx, nx), format='csr')\n",
    "    B_C = diags([lower_diag_B_C, main_diag_B_C, upper_diag_B_C], \n",
    "                [-1, 0, 1], shape=(nx, nx), format='csr')\n",
    "    \n",
    "    A_C[0, :] = 0\n",
    "    A_C[0, 0] = 1\n",
    "    B_C[0, :] = 0\n",
    "    \n",
    "    A_C[-1, :] = 0\n",
    "    A_C[-1, -1] = 1\n",
    "    A_C[-1, -2] = -1\n",
    "    B_C[-1, :] = 0\n",
    "    \n",
    "    # 时间步进（双位点半隐式求解）\n",
    "    for n in range(nt):\n",
    "        current_time = t[n+1]\n",
    "        \n",
    "        # 当前时间步的值\n",
    "        C_n = C[n, :].copy()\n",
    "        S1_n = S1[n, :].copy()\n",
    "        S2_n = S2[n, :].copy()\n",
    "        S3_n = S3[n, :].copy()\n",
    "        S_n = S[n, :].copy()\n",
    "        \n",
    "        dS1_dt = c1 * C_n - d1 * S1_n\n",
    "        S1_new = S1_n + dt * dS1_dt\n",
    "        \n",
    "        dS2_dt = c2 * C_n - d2 * S2_n\n",
    "        S2_new = S2_n + dt * dS2_dt\n",
    "\n",
    "        S3_new = e * C_n\n",
    "        dS3_dt = (S3_new - S3_n) / dt  # 近似\n",
    "        S_new = S1_new + S2_new + S3_new\n",
    "        # 耦合项 -dS/dt\n",
    "        dS_dt = dS1_dt + dS2_dt + dS3_dt\n",
    "        coupling_term = -dS_dt\n",
    "        # 更新固体相\n",
    "        S1[n+1, :] = S1_new\n",
    "        S2[n+1, :] = S2_new\n",
    "        S3[n+1, :] = S3_new\n",
    "        S[n+1, :] = S_new\n",
    "        # 物理合理性\n",
    "        S1[n+1, :] = np.maximum(S1[n+1, :], 0)\n",
    "        S2[n+1, :] = np.maximum(S2[n+1, :], 0)\n",
    "        S3[n+1, :] = np.maximum(S3[n+1, :], 0)\n",
    "        S[n+1, :] = np.maximum(S[n+1, :], 0)\n",
    "        # 右侧向量\n",
    "        rhs_C = B_C @ C_n + dt * coupling_term\n",
    "        \n",
    "        if T_fill <= current_time < T_close:\n",
    "            boundary_value = 1.0\n",
    "        else:\n",
    "            boundary_value = 0.0\n",
    "        \n",
    "        # 应用边界条件\n",
    "        rhs_C[0] = boundary_value  # 左边界\n",
    "        rhs_C[-1] = 0  # 右边界的Neumann条件\n",
    "        \n",
    "        # 求解流体相浓度\n",
    "        try:\n",
    "            C[n+1, :] = spsolve(A_C, rhs_C)\n",
    "        except Exception as e:\n",
    "            print(f\"双位点耦合求解器在时间 {current_time:.4f} 时遇到困难: {str(e)}\")\n",
    "            C[n+1, :] = C_n  # 使用前一时刻的解\n",
    "        \n",
    "        # 确保物理合理性\n",
    "        C[n+1, :] = np.maximum(C[n+1, :], 0)  # 浓度非负\n",
    "        \n",
    "        # 右边界的Neumann条件 dC/dx = 0\n",
    "        C[n+1, -1] = C[n+1, -2]\n",
    "    \n",
    "    return x, t, C, S, S1, S2, S3"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 86,
   "id": "41144b31",
   "metadata": {},
   "outputs": [],
   "source": [
    "def estimation_coupled(observed_data, time_points, known_a, known_b, \n",
    "                               L, T_fill, T_close, nx, nt, initial_params, bounds):\n",
    "    \n",
    "    def objective_function(params):\n",
    "        c, d, e = params\n",
    "        \n",
    "        try:\n",
    "            # # 确保参数为正数和合理范围\n",
    "            # if any(p <= 0 for p in params):\n",
    "            #     return 1e6\n",
    "            \n",
    "            # 求解双位点耦合PDE系统\n",
    "            x, t, C, S, S1, S2, S3 = solver_coupled(\n",
    "                a=known_a, b=known_b, c1=0.003353, d1=0, c2=c, d2=d, e=e,\n",
    "                L=L*2,  # 扩展域长度\n",
    "                T_start=time_points[0], T_end=time_points[-1],\n",
    "                T_fill=T_fill, T_close=T_close,\n",
    "                nx=nx, nt=nt\n",
    "            )\n",
    "            \n",
    "            # 在x=L处提取流体相浓度解\n",
    "            obs_idx = np.argmin(np.abs(x - L))\n",
    "            model_prediction = C[:, obs_idx]\n",
    "            \n",
    "            # 插值到观测时间点\n",
    "            model_prediction = np.interp(time_points, t, model_prediction)\n",
    "            \n",
    "            # # 分别计算起始段和终止段的MSE\n",
    "            # tstart_idx = np.argmin(np.abs(time_points - 0))\n",
    "            # tend_idx = np.argmin(np.abs(time_points - 50))\n",
    "            # mse = np.mean((model_prediction[tstart_idx:tend_idx] - observed_data[tstart_idx:tend_idx])**2)\n",
    "            \n",
    "            # tstart_idx = np.argmin(np.abs(time_points - 110))\n",
    "            # tend_idx = np.argmin(np.abs(time_points - 160))\n",
    "            # mse += np.mean((model_prediction[tstart_idx:tend_idx] - observed_data[tstart_idx:tend_idx])**2)\n",
    "\n",
    "            mse = np.mean((model_prediction - observed_data)**2)\n",
    "\n",
    "            return mse\n",
    "\n",
    "        except Exception as e:\n",
    "            print(f\"双位点耦合系统计算错误：参数 c={c:.6f}, d={d:.6f}, e={e:.6f}, 错误：{str(e)}\")\n",
    "            return 1e6\n",
    "    \n",
    "    print(\"开始双位点耦合系统参数估计...\")\n",
    "    print(f\"已知参数：a={known_a}, b={known_b}\")\n",
    "\n",
    "    result = minimize(objective_function, initial_params, \n",
    "                     method='L-BFGS-B', bounds=bounds,\n",
    "                     options={'disp': True, 'maxiter': 50})\n",
    "    \n",
    "    estimated_params = result.x\n",
    "    \n",
    "    print(f\"\\n双位点耦合系统优化完成!\")\n",
    "    print(f\"估计的参数：c = {estimated_params[0]:.6f}, d = {estimated_params[1]:.6f}, e = {estimated_params[2]:.6f}\")\n",
    "    print(f\"最终目标函数值：{result.fun:.8f}\")\n",
    "    print(f\"优化成功：{result.success}\")\n",
    "    \n",
    "    return estimated_params"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 4,
   "id": "d0df48e2",
   "metadata": {},
   "outputs": [],
   "source": [
    "def plot_coupled(x, t, C, S, S1, S2, S3, observed_data, time_points, estimated_params, \n",
    "                        known_params, true_params=None, L=1.0):\n",
    "    \"\"\"\n",
    "    可视化双位点耦合系统拟合结果\n",
    "    \n",
    "    参数：\n",
    "    x, t: 空间和时间网格\n",
    "    C, S: 流体相和总固体相浓度矩阵\n",
    "    S1, S2: 位点1和位点2固体相浓度矩阵\n",
    "    observed_data: 观测数据\n",
    "    time_points: 观测时间点\n",
    "    estimated_params: 估计的参数 [c, d, e, f]\n",
    "    known_params: 已知参数 [a, b]\n",
    "    true_params: 真实参数（如果已知）[c_true, d_true, e_true, f_true]\n",
    "    L: 观测位置\n",
    "    \"\"\"\n",
    "    \n",
    "    fig = plt.figure(figsize=(20, 16))\n",
    "    \n",
    "    # 创建3x3的子图布局以容纳更多信息\n",
    "    gs = fig.add_gridspec(3, 3, hspace=0.3, wspace=0.3)\n",
    "    \n",
    "    # 1. 流体相浓度场的时空分布\n",
    "    ax1 = fig.add_subplot(gs[0, 0])\n",
    "    im1 = ax1.contourf(x, t, C, levels=50, cmap='viridis')\n",
    "    ax1.set_xlabel('x')\n",
    "    ax1.set_ylabel('t')\n",
    "    ax1.set_title('C(x,t)')\n",
    "    plt.colorbar(im1, ax=ax1, label='C')\n",
    "    ax1.axvline(x=L, color='red', linestyle='--', alpha=0.7, label=f'Exp. x={L}')\n",
    "    ax1.legend()\n",
    "    \n",
    "    # 2. 总固体相浓度场的时空分布\n",
    "    ax2 = fig.add_subplot(gs[0, 1])\n",
    "    im2 = ax2.contourf(x, t, S, levels=50, cmap='plasma')\n",
    "    ax2.set_xlabel('x')\n",
    "    ax2.set_ylabel('t')\n",
    "    ax2.set_title('S(x,t) = S1+S2')\n",
    "    plt.colorbar(im2, ax=ax2, label='S')\n",
    "    ax2.axvline(x=L, color='red', linestyle='--', alpha=0.7, label=f'Exp. x={L}')\n",
    "    ax2.legend()\n",
    "    \n",
    "    # 3. 在x=L处的拟合对比\n",
    "    ax3 = fig.add_subplot(gs[0, 2])\n",
    "    # 找到最接近观测位置的网格点\n",
    "    obs_idx = np.argmin(np.abs(x - L))\n",
    "    model_at_L = C[:, obs_idx]  # 模型在x=L处的预测\n",
    "    \n",
    "    # 插值到观测时间点进行对比\n",
    "    model_interp = np.interp(time_points, t, model_at_L)\n",
    "    \n",
    "    ax3.plot(t, model_at_L, 'b-', linewidth=2, label='model C(x=L,t)')\n",
    "    ax3.plot(time_points, observed_data, 'ro', markersize=6, label='Exp. data')\n",
    "#     ax3.plot(time_points, model_interp, 'g--', linewidth=2, label='模型预测（插值）')\n",
    "    ax3.set_xlabel('t')\n",
    "    ax3.set_ylabel(f'C({L},t)')\n",
    "    ax3.set_title(f'Comparison at x={L}')\n",
    "    ax3.legend()\n",
    "    ax3.grid(True, alpha=0.3)\n",
    "    \n",
    "    # 4. 位点1固体相浓度场\n",
    "    ax4 = fig.add_subplot(gs[1, 0])\n",
    "    im4 = ax4.contourf(x, t, S1, levels=50, cmap='Oranges')\n",
    "    ax4.set_xlabel('x')\n",
    "    ax4.set_ylabel('t')\n",
    "    ax4.set_title('S1(x,t)')\n",
    "    plt.colorbar(im4, ax=ax4, label='S1')\n",
    "    ax4.axvline(x=L, color='red', linestyle='--', alpha=0.7, label=f'Exp. x={L}')\n",
    "    ax4.legend()\n",
    "    \n",
    "    # 5. 位点2固体相浓度场\n",
    "    ax5 = fig.add_subplot(gs[1, 1])\n",
    "    im5 = ax5.contourf(x, t, S2, levels=50, cmap='Blues')\n",
    "    ax5.set_xlabel('x')\n",
    "    ax5.set_ylabel('t')\n",
    "    ax5.set_title('S2(x,t)')\n",
    "    plt.colorbar(im5, ax=ax5, label='S2')\n",
    "    ax5.axvline(x=L, color='red', linestyle='--', alpha=0.7, label=f'Exp. x={L}')\n",
    "    ax5.legend()\n",
    "    \n",
    "    # 6. 位点3固体相浓度场\n",
    "    ax6 = fig.add_subplot(gs[1, 2])\n",
    "    im6 = ax6.contourf(x, t, S3, levels=50, cmap='Greens')\n",
    "    ax6.set_xlabel('x')\n",
    "    ax6.set_ylabel('t')\n",
    "    ax6.set_title('S3(x,t)')\n",
    "    plt.colorbar(im6, ax=ax6, label='S3')\n",
    "    ax6.axvline(x=L, color='red', linestyle='--', alpha=0.7, label=f'Exp. x={L}')\n",
    "    ax6.legend()\n",
    "    \n",
    "    # 9. 参数总结和拟合质量\n",
    "    ax9 = fig.add_subplot(gs[2, 2])\n",
    "    ax9.axis('off')\n",
    "    \n",
    "    # 显示参数信息\n",
    "    y_pos = 0.95\n",
    "    ax9.text(0.05, y_pos, 'Results', fontsize=14, weight='bold', transform=ax9.transAxes)\n",
    "    y_pos -= 0.08\n",
    "    \n",
    "    # 已知参数\n",
    "    ax9.text(0.05, y_pos, f'Known Parameters:', fontsize=12, weight='bold', transform=ax9.transAxes)\n",
    "    y_pos -= 0.06\n",
    "    ax9.text(0.05, y_pos, f'Diffusion Coefficient a = {known_params[0]:.6f}', \n",
    "            fontsize=10, transform=ax9.transAxes)\n",
    "    y_pos -= 0.05\n",
    "    ax9.text(0.05, y_pos, f'Convection Coefficient b = {known_params[1]:.6f}', \n",
    "            fontsize=10, transform=ax9.transAxes)\n",
    "    y_pos -= 0.08\n",
    "    \n",
    "    # 估计参数\n",
    "    ax9.text(0.05, y_pos, f'Estimated:', fontsize=12, weight='bold', transform=ax9.transAxes)\n",
    "    y_pos -= 0.06\n",
    "    ax9.text(0.05, y_pos, f'c = {estimated_params[0]:.6f}', \n",
    "            fontsize=10, transform=ax9.transAxes)\n",
    "    y_pos -= 0.05\n",
    "    ax9.text(0.05, y_pos, f'd = {estimated_params[1]:.6f}', \n",
    "            fontsize=10, transform=ax9.transAxes)\n",
    "    y_pos -= 0.05\n",
    "    ax9.text(0.05, y_pos, f'e = {estimated_params[2]:.6f}', \n",
    "            fontsize=10, transform=ax9.transAxes)\n",
    "    y_pos -= 0.05\n",
    "\n",
    "    \n",
    "    # 计算拟合质量指标\n",
    "    y_pos -= 0.03\n",
    "    ax9.text(0.05, y_pos, f'Quality:', fontsize=12, weight='bold', transform=ax9.transAxes)\n",
    "    y_pos -= 0.06\n",
    "    \n",
    "    # 计算R²和RMSE\n",
    "    ss_res = np.sum((observed_data - model_interp) ** 2)\n",
    "    ss_tot = np.sum((observed_data - np.mean(observed_data)) ** 2)\n",
    "    r_squared = 1 - (ss_res / ss_tot) if ss_tot > 0 else 0\n",
    "    rmse = np.sqrt(np.mean((observed_data - model_interp) ** 2))\n",
    "    \n",
    "    ax9.text(0.05, y_pos, f'R² = {r_squared:.4f}', fontsize=10, transform=ax9.transAxes)\n",
    "    y_pos -= 0.05\n",
    "    ax9.text(0.05, y_pos, f'RMSE = {rmse:.6f}', fontsize=10, transform=ax9.transAxes)\n",
    "    \n",
    "    plt.show()\n",
    "    \n",
    "    # 返回拟合质量指标\n",
    "    return {'R_squared': r_squared, 'RMSE': rmse}"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 87,
   "id": "f7298183",
   "metadata": {},
   "outputs": [],
   "source": [
    "observed_data = np.array([0,0.000 ,0.000 ,0.000 ,0.000 ,0.000 ,0.013 ,0.428 ,0.764 ,0.800 ,0.784 ,0.812 ,0.851 ,0.852 ,0.794 ,0.824 ,0.789 ,0.772 ,0.787 ,0.800 ,0.781 ,0.796 ,0.783 ,0.830 ,0.802 ,0.819 ,0.836 ,0.808 ,0.829 ,0.777 ,0.570 ,0.228 ,0.027 ,0.011 ,0.004 ,0.000 ,0.000 ,0.000 ,0.000 ,0.000 ,0.000 \n",
    "                          ])\n",
    "time_points = np.array([-5,0.061024694,4.408124949,8.869087815,13.79708268,18.04351075,22.75233146,27.06693134,31.81421072,36.21094439,40.5145203,45.13533512,49.59976572,54.36378782,58.72126919,63.21015813,67.69760222,72.20460694,76.50184354,81.28733438,85.37345769,90.1958657,94.55729479,99.00398667,103.7065259,108.0496445,112.6294644,117.3834332,121.6957778,126.4112878,130.7924945,135.0899365,139.7641626,143.9845594,148.3859799,153.3234365,157.6919828,162.1869148,166.6214022,171.1149373,175.3788775\n",
    "                        ])\n",
    "known_a = 0.073\n",
    "known_b = 0.799792262\n",
    "known_L = 15.4\n",
    "T_fill = 0\n",
    "T_close = 107"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 89,
   "id": "ee62e424",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "开始双位点耦合系统参数估计...\n",
      "已知参数：a=0.073, b=0.799792262\n",
      "RUNNING THE L-BFGS-B CODE\n",
      "\n",
      "           * * *\n",
      "\n",
      "Machine precision = 2.220D-16\n",
      " N =            3     M =           10\n",
      "\n",
      "At X0         0 variables are exactly at the bounds\n",
      "\n",
      "At iterate    0    f=  3.05262D-02    |proj g|=  9.82167D-01\n",
      "\n",
      "At iterate    1    f=  1.38170D-02    |proj g|=  7.14813D-02\n",
      "\n",
      "At iterate    2    f=  1.31918D-02    |proj g|=  3.54935D-02\n",
      "\n",
      "At iterate    3    f=  1.30692D-02    |proj g|=  2.30718D-02\n",
      "\n",
      "At iterate    4    f=  1.29642D-02    |proj g|=  2.82772D-02\n",
      "\n",
      "At iterate    5    f=  1.24745D-02    |proj g|=  6.57087D-02\n",
      "\n",
      "At iterate    6    f=  1.13844D-02    |proj g|=  5.91012D-02\n",
      "\n",
      "At iterate    7    f=  1.03044D-02    |proj g|=  3.93234D-02\n",
      "\n",
      "At iterate    8    f=  1.02340D-02    |proj g|=  1.68133D-02\n",
      "\n",
      "At iterate    9    f=  1.02161D-02    |proj g|=  1.76650D-02\n",
      "\n",
      "At iterate   10    f=  1.01208D-02    |proj g|=  8.85359D-03\n",
      "\n",
      "At iterate   11    f=  1.01017D-02    |proj g|=  2.86792D-03\n",
      "\n",
      "At iterate   12    f=  1.00985D-02    |proj g|=  4.90425D-03\n",
      "\n",
      "At iterate   13    f=  1.00818D-02    |proj g|=  1.19795D-02\n",
      "\n",
      "At iterate   14    f=  4.25538D-03    |proj g|=  4.35401D-01\n",
      "\n",
      "At iterate   15    f=  3.71392D-03    |proj g|=  1.28348D-01\n",
      "\n",
      "At iterate   16    f=  2.20072D-03    |proj g|=  5.57833D-01\n",
      "\n",
      "At iterate   17    f=  1.89625D-03    |proj g|=  2.15621D-01\n",
      "\n",
      "At iterate   18    f=  1.64532D-03    |proj g|=  3.04824D-01\n",
      "\n",
      "At iterate   19    f=  9.40283D-04    |proj g|=  2.42656D-01\n",
      "\n",
      "At iterate   20    f=  6.97553D-04    |proj g|=  7.10890D-02\n",
      "\n",
      "At iterate   21    f=  6.71129D-04    |proj g|=  8.05285D-03\n",
      "\n",
      "At iterate   22    f=  6.68024D-04    |proj g|=  4.75859D-04\n",
      "\n",
      "双位点耦合系统优化完成!\n",
      "At iterate   23    f=  6.68024D-04    |proj g|=  2.51234D-05\n",
      "\n",
      "估计的参数：c = 0.007986, d = 0.000000, e = 0.388891\n",
      "最终目标函数值：0.00066802\n",
      "优化成功：True\n",
      "\n",
      "           * * *\n",
      "\n",
      "Tit   = total number of iterations\n",
      "Tnf   = total number of function evaluations\n",
      "Tnint = total number of segments explored during Cauchy searches\n",
      "Skip  = number of BFGS updates skipped\n",
      "Nact  = number of active bounds at final generalized Cauchy point\n",
      "Projg = norm of the final projected gradient\n",
      "F     = final function value\n",
      "\n",
      "           * * *\n",
      "\n",
      "   N    Tit     Tnf  Tnint  Skip  Nact     Projg        F\n",
      "    3     23     38     24     0     1   2.512D-05   6.680D-04\n",
      "  F =   6.6802392458270067E-004\n",
      "\n",
      "CONVERGENCE: REL_REDUCTION_OF_F_<=_FACTR*EPSMCH             \n"
     ]
    }
   ],
   "source": [
    "initial_guess_coupled = [0.001, 0.1, 0.1]  # [c, d, e] 的初始猜测\n",
    "bounds_coupled = ((0, 1), (0, 1), (0.01, 0.99)) \n",
    "\n",
    "# initial_guess_coupled = [-0.1, -0.1, 0.3]  # [c, d, e] 的初始猜测\n",
    "# bounds_coupled = ((-2, 2), (-2, 2), (0.1, 0.9)) \n",
    "\n",
    "params_coupled = estimation_coupled(\n",
    "    observed_data=observed_data, \n",
    "    time_points=time_points,  # 使用您的实际时间点\n",
    "    known_a=known_a, \n",
    "    known_b=known_b,\n",
    "    L=known_L,  # 观测位置\n",
    "    T_fill=T_fill, \n",
    "    T_close=T_close,\n",
    "    nx=301, \n",
    "    nt=5000,\n",
    "    initial_params=initial_guess_coupled, \n",
    "    bounds=bounds_coupled\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 90,
   "id": "e84d5523",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "\\n使用估计参数重新求解双位点耦合系统...\n",
      "\\n绘制双位点耦合系统拟合结果...\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 230028 characters]",
      "text/plain": [
       "<Figure size 2000x1600 with 12 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "# 使用估计的参数重新求解双位点耦合系统\n",
    "print(\"\\\\n使用估计参数重新求解双位点耦合系统...\")\n",
    "x, t, C, S, S1, S2, S3 = solver_coupled(\n",
    "    a=known_a, b=known_b, \n",
    "    # c1=0.011339, d1=0, c2=0, d2=0, e=0.388905,\n",
    "    c1=0.003353, d1=0, c2=params_coupled[0], d2=params_coupled[1], e=params_coupled[2],\n",
    "    L=known_L*2,\n",
    "    T_start=time_points[0], T_end=time_points[-1],\n",
    "    T_fill=T_fill, T_close=T_close,\n",
    "    nx=301, nt=5000\n",
    ")\n",
    "\n",
    "# 可视化双位点耦合系统结果\n",
    "print(\"\\\\n绘制双位点耦合系统拟合结果...\")\n",
    "fit_metrics = plot_coupled(\n",
    "    x, t, C, S, S1, S2, S3,\n",
    "    observed_data, time_points, \n",
    "    estimated_params=params_coupled, known_params=[known_a, known_b], L=known_L\n",
    ")"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "480df963",
   "metadata": {},
   "outputs": [],
   "source": [
    "def time_sensitivity(observed_data, time_points, L, nx, nt, a, b, params_coupled):\n",
    "\n",
    "    T_fill_range = np.linspace(-5, -0, 5)\n",
    "    mse_T_fill = []\n",
    "\n",
    "    print(\"1. T_fill 敏感性分析...\")\n",
    "    \n",
    "    for T_fill in T_fill_range:\n",
    "        try:\n",
    "            x, t, C, S, S1, S2 = solver_coupled(a=a, b=b, c=params_coupled[0], \n",
    "                            d=params_coupled[1], e=params_coupled[2], f=params_coupled[3],\n",
    "                            L=L*2, T_start=time_points[0], T_end=time_points[-1],\n",
    "                            T_fill=T_fill, T_close=100,\n",
    "                            nx=nx, nt=nt)\n",
    "\n",
    "            obs_idx = np.argmin(np.abs(x - L))\n",
    "            tstart_idx = np.argmin(np.abs(time_points - 0))\n",
    "            tend_idx = np.argmin(np.abs(time_points - 50))\n",
    "            model_prediction = C[:, obs_idx]\n",
    "            model_prediction = np.interp(time_points, t, model_prediction)\n",
    "            mse = np.mean((model_prediction[tstart_idx:tend_idx] - observed_data[tstart_idx:tend_idx])**2)\n",
    "            mse_T_fill.append(mse)\n",
    "            \n",
    "        except Exception as e:\n",
    "            print(f\"T_fill = {T_fill:.2f} 时计算失败: {str(e)}\")\n",
    "            mse_T_fill.append(1e6)\n",
    "    \n",
    "    print(\"2. T_close 敏感性分析...\")\n",
    "\n",
    "    T_close_range = np.linspace(110, 120, 10)\n",
    "    mse_T_close = []\n",
    "    \n",
    "    for T_close in T_close_range:\n",
    "        try:\n",
    "            x, t, C, S, S1, S2 = solver_coupled(a=a, b=b, c=params_coupled[0], \n",
    "                            d=params_coupled[1], e=params_coupled[2], f=params_coupled[3],\n",
    "                            L=L*2, T_start=time_points[0], T_end=time_points[-1],\n",
    "                            T_fill=0, T_close=T_close,\n",
    "                            nx=nx, nt=nt)\n",
    "\n",
    "            obs_idx = np.argmin(np.abs(x - L))\n",
    "            tstart_idx = np.argmin(np.abs(time_points - 110))\n",
    "            tend_idx = np.argmin(np.abs(time_points - 160))\n",
    "            model_prediction = C[:, obs_idx]\n",
    "            model_prediction = np.interp(time_points, t, model_prediction)\n",
    "            mse = np.mean((model_prediction[tstart_idx:tend_idx] - observed_data[tstart_idx:tend_idx])**2)\n",
    "            mse_T_close.append(mse)\n",
    "            \n",
    "        except Exception as e:\n",
    "            print(f\"T_close = {T_close:.2f} 时计算失败: {str(e)}\")\n",
    "            mse_T_close.append(1e6)\n",
    "    \n",
    "    # 可视化敏感性分析结果\n",
    "    fig, ((ax1, ax2), (ax3, ax4)) = plt.subplots(2, 2, figsize=(15, 12))\n",
    "    \n",
    "    # 1. T_fill 敏感性曲线\n",
    "    ax1.plot(T_fill_range, mse_T_fill, 'b-o', linewidth=2, markersize=6)\n",
    "    ax1.set_xlabel('T_fill')\n",
    "    ax1.set_ylabel('均方误差 MSE')\n",
    "    ax1.set_title('T_fill 参数敏感性分析\\n(基于 0-40 时间段的拟合)')\n",
    "    ax1.grid(True, alpha=0.3)\n",
    "    ax1.set_yscale('log')  # 使用对数坐标便于观察\n",
    "    \n",
    "    # 找到最优T_fill\n",
    "    min_idx_fill = np.argmin(mse_T_fill)\n",
    "    optimal_T_fill = T_fill_range[min_idx_fill]\n",
    "    ax1.axvline(optimal_T_fill, color='red', linestyle='--', \n",
    "                label=f'最优值: {optimal_T_fill:.2f}')\n",
    "    ax1.legend()\n",
    "    \n",
    "    # 2. T_close 敏感性曲线\n",
    "    ax2.plot(T_close_range, mse_T_close, 'g-o', linewidth=2, markersize=6)\n",
    "    ax2.set_xlabel('T_close')\n",
    "    ax2.set_ylabel('均方误差 MSE')\n",
    "    ax2.set_title('T_close 参数敏感性分析\\n(基于 100-140 时间段的拟合)')\n",
    "    ax2.grid(True, alpha=0.3)\n",
    "    ax2.set_yscale('log')  # 使用对数坐标便于观察\n",
    "    \n",
    "    # 找到最优T_close\n",
    "    min_idx_close = np.argmin(mse_T_close)\n",
    "    optimal_T_close = T_close_range[min_idx_close]\n",
    "    ax2.axvline(optimal_T_close, color='red', linestyle='--', \n",
    "                label=f'最优值: {optimal_T_close:.2f}')\n",
    "    ax2.legend()\n",
    "    \n",
    "    # 3. 展示最优T_fill的拟合效果\n",
    "    print(f\"3. 绘制最优参数的拟合效果...\")\n",
    "    \n",
    "    # 使用最优T_fill绘制起始段拟合\n",
    "    x_opt, t_opt, C_opt_fill, _, _, _ = solver_coupled(a=a, b=b, c=params_coupled[0], \n",
    "                            d=params_coupled[1], e=params_coupled[2], f=params_coupled[3],\n",
    "                            L=L*2, T_start=time_points[0], T_end=time_points[-1],\n",
    "                            T_fill=optimal_T_fill, T_close=100,\n",
    "                            nx=nx, nt=nt)\n",
    "    obs_idx = np.argmin(np.abs(x_opt - L))\n",
    "    model_pred_fill = C_opt_fill[:, obs_idx]\n",
    "    model_pred_fill = np.interp(time_points, t_opt, model_pred_fill)\n",
    "    \n",
    "    # 重点关注起始段\n",
    "    start_mask = (time_points >= 0) & (time_points <= 50)\n",
    "    ax3.plot(time_points[start_mask], observed_data[start_mask], 'ro', \n",
    "             markersize=6, label='观测数据')\n",
    "    ax3.plot(time_points[start_mask], model_pred_fill[start_mask], 'b-', \n",
    "             linewidth=2, label=f'模型预测 (T_fill={optimal_T_fill:.2f})')\n",
    "    ax3.axvline(optimal_T_fill, color='red', linestyle='--', alpha=0.7, \n",
    "                label=f'T_fill = {optimal_T_fill:.2f}')\n",
    "    ax3.set_xlabel('时间')\n",
    "    ax3.set_ylabel('浓度')\n",
    "    ax3.set_title('最优 T_fill 的起始段拟合效果')\n",
    "    ax3.legend()\n",
    "    ax3.grid(True, alpha=0.3)\n",
    "    \n",
    "    # 4. 展示最优T_close的拟合效果\n",
    "    # 使用最优T_close绘制终止段拟合\n",
    "    x_opt, t_opt, C_opt_close, _, _, _ = solver_coupled(a=a, b=b, c=params_coupled[0], \n",
    "                            d=params_coupled[1], e=params_coupled[2], f=params_coupled[3],\n",
    "                            L=L*2, T_start=time_points[0], T_end=time_points[-1],\n",
    "                            T_fill=0, T_close=optimal_T_close,\n",
    "                            nx=nx, nt=nt)\n",
    "    obs_idx = np.argmin(np.abs(x_opt - L))\n",
    "    model_pred_close = C_opt_close[:, obs_idx]\n",
    "    model_pred_close = np.interp(time_points, t_opt, model_pred_close)\n",
    "    \n",
    "    # 重点关注终止段\n",
    "    end_mask = (time_points >= 100) & (time_points <= 150)\n",
    "    ax4.plot(time_points[end_mask], observed_data[end_mask], 'ro', \n",
    "             markersize=6, label='观测数据')\n",
    "    ax4.plot(time_points[end_mask], model_pred_close[end_mask], 'g-', \n",
    "             linewidth=2, label=f'模型预测 (T_close={optimal_T_close:.2f})')\n",
    "    ax4.axvline(optimal_T_close, color='red', linestyle='--', alpha=0.7, \n",
    "                label=f'T_close = {optimal_T_close:.2f}')\n",
    "    ax4.set_xlabel('时间')\n",
    "    ax4.set_ylabel('浓度')\n",
    "    ax4.set_title('最优 T_close 的终止段拟合效果')\n",
    "    ax4.legend()\n",
    "    ax4.grid(True, alpha=0.3)\n",
    "    \n",
    "    plt.tight_layout()\n",
    "    plt.show()\n",
    "    \n",
    "    # 打印敏感性分析结果\n",
    "    print(\"=\" * 60)\n",
    "    print(\"敏感性分析结果总结\")\n",
    "    print(\"=\" * 60)\n",
    "    print(f\"最优 T_fill:  {optimal_T_fill:.3f} (MSE = {mse_T_fill[min_idx_fill]:.6e})\")\n",
    "    print(f\"最优 T_close: {optimal_T_close:.3f} (MSE = {mse_T_close[min_idx_close]:.6e})\")\n",
    "    \n",
    "    # 计算敏感性指标\n",
    "    # 对于T_fill\n",
    "    mse_T_fill_clean = [mse for mse in mse_T_fill if mse < 1e5]\n",
    "    if len(mse_T_fill_clean) > 1:\n",
    "        sensitivity_T_fill = (max(mse_T_fill_clean) - min(mse_T_fill_clean)) / min(mse_T_fill_clean)\n",
    "        print(f\"T_fill 敏感性指标: {sensitivity_T_fill:.2f} (变化范围的相对差异)\")\n",
    "    \n",
    "    # 对于T_close\n",
    "    mse_T_close_clean = [mse for mse in mse_T_close if mse < 1e5]\n",
    "    if len(mse_T_close_clean) > 1:\n",
    "        sensitivity_T_close = (max(mse_T_close_clean) - min(mse_T_close_clean)) / min(mse_T_close_clean)\n",
    "        print(f\"T_close 敏感性指标: {sensitivity_T_close:.2f} (变化范围的相对差异)\")\n",
    "    \n",
    "    return {\n",
    "        'T_fill_range': T_fill_range,\n",
    "        'mse_T_fill': mse_T_fill,\n",
    "        'optimal_T_fill': optimal_T_fill,\n",
    "        'T_close_range': T_close_range,\n",
    "        'mse_T_close': mse_T_close,\n",
    "        'optimal_T_close': optimal_T_close\n",
    "    }"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "889ea663",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "开始运行时间参数敏感性分析...\n",
      "1. T_fill 敏感性分析...\n",
      "2. T_close 敏感性分析...\n",
      "2. T_close 敏感性分析...\n",
      "3. 绘制最优参数的拟合效果...\n",
      "3. 绘制最优参数的拟合效果...\n"
     ]
    },
    {
     "data": {
      "image/png": "[encoded data, 177576 characters]",
      "text/plain": [
       "<Figure size 1500x1200 with 4 Axes>"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    },
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "============================================================\n",
      "敏感性分析结果总结\n",
      "============================================================\n",
      "最优 T_fill:  -10.000 (MSE = 7.507974e-03)\n",
      "最优 T_close: 108.889 (MSE = 1.403888e-03)\n",
      "T_fill 敏感性指标: 3.60 (变化范围的相对差异)\n",
      "T_close 敏感性指标: 18.60 (变化范围的相对差异)\n"
     ]
    }
   ],
   "source": [
    "# 运行 T_fill 和 T_close 的敏感性分析\n",
    "print(\"开始运行时间参数敏感性分析...\")\n",
    "\n",
    "sensitivity_results = time_sensitivity(\n",
    "    observed_data, time_points, L=15.4, nx=301, nt=5000,\n",
    "    a=known_a, b=known_b, params_coupled=params_coupled\n",
    ")"
   ]
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "pycuda_3_10",
   "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.10.13"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
