比热容数据快捷处理分析工具

本文介绍基于纯 HTML + JS 打造的的比热数据处理分析工具

将本文附近代码保存为 CPAnalyzer.html,然后双击在浏览器中打开即可,在最左侧导入

将 比热的数据(Sample Temp (Kelvin)Samp HC (J/mole-K) 两列,)复制粘贴到左侧输入框。

在左侧设置好化学式原子数(n)。

勾选启用晶格声子基线扣除,选择需要的模型(推荐复杂体系使用德拜+爱因斯坦模型)。拖动参数滑块,在右上方图表中观察基线是否贴合高温区的无相变顺磁尾巴。

自动双约束寻优工作站

如果不想手动盲猜,点击底部的"高级自动约束寻优"!在弹出的工作站中:

  1. 输入理论目标磁熵:比如你确信你的体系是S=1/2,直接选择 Rln2。

  2. 圈定高温对齐区间:比如 150K ~ 200K。

  3. 点击执行:引擎会瞬间启动百次搜索与局部退火算法!它会尝试成千上万种德拜和爱因斯坦温度的组合,既保证在高温区符合实验测点,又保证最终积分出来的磁熵完美落在 R\ln2 的水平线上。

窗口展示效果如下

不同拟合模型

德拜模型

爱因斯坦模型

双德拜模型,即将体系内轻重原子分离

混合模型

自动搜索窗口

通过自动拟合后的结果

完整代码如下

复制代码
<!DOCTYPE html>
<html lang="zh-CN">
<head>
    <meta charset="UTF-8">
    <meta name="viewport" content="width=device-width, initial-scale=1.0">
    <title>固体比热数据交互分析仪 - 终极修复版</title>
    <script src="https://cdn.tailwindcss.com"></script>
    <script src="https://cdn.jsdelivr.net/npm/echarts@5.5.0/dist/echarts.min.js"></script>
    <style>
        ::-webkit-scrollbar { width: 6px; height: 6px; }
        ::-webkit-scrollbar-track { background: #f1f5f9; }
        ::-webkit-scrollbar-thumb { background: #cbd5e1; border-radius: 3px; }
        ::-webkit-scrollbar-thumb:hover { background: #94a3b8; }
        input[type=range] { accent-color: #8b5cf6; }
        /* 屏蔽只读框的默认灰色 */
        input:read-only { background-color: #f8fafc; color: #334155; border-color: #cbd5e1; }
    </style>
</head>
<body class="bg-slate-100 text-slate-800 font-sans h-screen w-screen flex overflow-hidden relative">

    <!-- 左侧控制面板 (固定宽度) -->
    <aside class="w-[350px] bg-white border-r border-slate-300 flex flex-col h-full shadow-lg z-20 shrink-0">
        
        <!-- Header -->
        <header class="bg-indigo-600 text-white p-4 shrink-0 shadow-md">
            <h1 class="text-base font-bold flex items-center gap-2">
                <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M9 19v-6a2 2 0 00-2-2H5a2 2 0 00-2 2v6a2 2 0 002 2h2a2 2 0 002-2zm0 0V9a2 2 0 012-2h2a2 2 0 012 2v10m-6 0a2 2 0 002 2h2a2 2 0 002-2m0 0V5a2 2 0 012-2h2a2 2 0 012 2v14a2 2 0 01-2 2h-2a2 2 0 01-2-2z"></path></svg>
                比热数据综合分析站
            </h1>
        </header>

        <!-- 滚动控制区 -->
        <div class="flex-1 overflow-y-auto">
            
            <!-- 1. 数据输入 -->
            <div class="p-4 border-b border-slate-200">
                <h2 class="font-bold text-xs mb-2 text-indigo-700">1. 粘贴比热数据</h2>
                <div class="text-[10px] text-slate-500 mb-2 bg-slate-50 p-1.5 rounded border border-slate-200 leading-relaxed">
                    <strong>要求格式 (支持直接带表头复制):</strong><br/>
                    <code>Sample Temp (Kelvin)    Samp HC (J/mole-K)</code>
                </div>
                <textarea id="dataInput" class="w-full h-16 p-2 text-[10px] font-mono border border-slate-300 rounded focus:ring-1 focus:ring-indigo-500 outline-none resize-none mb-2 shadow-inner" placeholder="201.07    183.62"></textarea>
                <div class="flex items-center justify-between text-xs">
                    <label class="font-bold text-slate-700">化学式原子数 (n):</label>
                    <input type="number" id="nAtoms" value="1" step="0.1" class="w-16 p-1 border border-slate-300 rounded text-center shadow-sm">
                </div>
            </div>

            <!-- 2. 数据处理与低温外推 -->
            <div class="p-4 border-b border-slate-200 bg-slate-50">
                <div class="flex items-center justify-between mb-3">
                    <h2 class="font-bold text-xs text-indigo-700">2. 插值与极低温外推 (Cp/T vs T²)</h2>
                </div>
                
                <div class="flex flex-col gap-2 text-[11px] mb-3">
                    <label class="flex items-center gap-2">
                        <input type="checkbox" id="useInterpolation" checked class="rounded text-indigo-600"> 
                        <span class="font-bold text-slate-700">线性插值重采样 (步长:</span>
                        <input type="number" id="interpStep" value="0.5" step="0.1" min="0.01" class="w-12 p-0.5 border rounded text-center"> K)
                    </label>
                    
                    <label class="flex items-center gap-2 text-orange-600">
                        <input type="checkbox" id="forceNonNegative" checked class="rounded text-orange-600"> 
                        <span class="font-bold">约束: 限制磁比热 C_mag ≥ 0</span>
                    </label>

                    <div class="h-px bg-slate-200 my-1"></div>

                    <label class="flex items-center gap-2">
                        <input type="checkbox" id="autoFitLowT" checked class="rounded text-blue-600"> 
                        <span class="font-bold text-slate-700">自动拟合低温参数 (T²区:</span>
                        <input type="number" id="t2Min" value="0" class="w-10 p-0.5 border rounded text-center">-
                        <input type="number" id="t2Max" value="50" class="w-10 p-0.5 border rounded text-center">)
                    </label>
                    <div class="flex items-center gap-2 mt-1">
                        <span class="font-bold text-slate-700">绘图 T² 上限:</span>
                        <input type="number" id="t2PlotMax" value="100" class="w-16 p-0.5 border rounded text-center text-blue-700" placeholder="Auto">
                    </div>
                </div>

                <div class="bg-white p-2 rounded border border-slate-200 grid grid-cols-2 gap-2 shadow-sm">
                    <div class="flex flex-col">
                        <span class="text-[10px] text-slate-500">γ [J/(mol·K²)]</span>
                        <input type="number" id="gammaInput" value="0" step="0.0001" readonly class="w-full p-1 border rounded text-xs font-mono font-bold">
                    </div>
                    <div class="flex flex-col">
                        <span class="text-[10px] text-slate-500">β [J/(mol·K⁴)]</span>
                        <input type="number" id="betaInput" value="0" step="0.00001" readonly class="w-full p-1 border rounded text-xs font-mono font-bold">
                    </div>
                    <div class="col-span-2 text-[10px] text-slate-500 mt-1 border-t pt-1">
                        低频参考 Θ_D ≈ <span id="thetaLowVal" class="font-bold text-blue-600">--</span> K
                    </div>
                </div>
            </div>

            <!-- 3. 晶格声子基线扣除 -->
            <div class="p-4 border-b border-slate-200">
                <label class="flex items-center gap-2 mb-3 cursor-pointer">
                    <input type="checkbox" id="enableLattice" checked class="rounded text-orange-600">
                    <h2 class="font-bold text-xs text-orange-700">3. 晶格声子背景模型扣除</h2>
                </label>

                <div id="latticeControls" class="space-y-3">
                    <select id="modelType" class="w-full p-1.5 text-xs border border-slate-300 rounded font-bold text-slate-700 shadow-sm">
                        <option value="single_debye">单德拜模型 (1 Debye)</option>
                        <option value="double_debye">双德拜模型 (2 Debye)</option>
                        <option value="debye_einstein">德拜 + 爱因斯坦模型 (D + E)</option>
                    </select>

                    <!-- 动态物理模型展示面板 -->
                    <div id="modelDescMain" class="p-2 bg-slate-50 rounded border border-slate-200 text-[10px] text-slate-600 shadow-inner transition-all duration-200">
                        <!-- 动态内容将被注入到这里 -->
                    </div>

                    <div class="bg-orange-50/30 p-3 rounded border border-orange-100 shadow-inner">
                        <!-- P1 -->
                        <div class="mb-3">
                            <div class="flex justify-between items-center text-xs mb-1">
                                <label id="lblParam1" class="font-bold text-slate-700">Θ_D1 (K)</label>
                                <input type="number" id="numParam1" class="w-16 p-1 border border-orange-300 rounded text-center text-orange-700 font-bold bg-white" value="300" min="10" max="1500" step="0.1">
                            </div>
                            <input type="range" id="param1" min="10" max="1500" value="300" step="0.1" class="w-full">
                        </div>
                        
                        <!-- P2 -->
                        <div id="divParam2" class="mb-3" style="display:none;">
                            <div class="flex justify-between items-center text-xs mb-1">
                                <label id="lblParam2" class="font-bold text-slate-700">Θ_2 (K)</label>
                                <input type="number" id="numParam2" class="w-16 p-1 border border-orange-300 rounded text-center text-orange-700 font-bold bg-white" value="150" min="10" max="1500" step="0.1">
                            </div>
                            <input type="range" id="param2" min="10" max="1500" value="150" step="0.1" class="w-full">
                        </div>

                        <!-- W -->
                        <div id="divWeight" style="display:none;">
                            <div class="flex justify-between items-center text-xs mb-1">
                                <label class="font-bold text-slate-700">模型1权重 (w)</label>
                                <input type="number" id="numWeight" class="w-16 p-1 border border-orange-300 rounded text-center text-orange-700 font-bold bg-white" value="0.5" min="0" max="1" step="0.01">
                            </div>
                            <input type="range" id="weight" min="0" max="1" step="0.01" value="0.5" class="w-full">
                        </div>
                    </div>
                </div>
            </div>

            <!-- 4. 磁熵参考标度 -->
            <div class="p-4 border-b border-slate-200 bg-red-50/20">
                <h2 class="font-bold text-xs mb-2 text-red-700">4. 磁熵绘图理论标度</h2>
                <div class="flex flex-col gap-2 text-xs">
                    <div class="flex items-center justify-between">
                        <span class="font-bold text-slate-700">目标熵 S:</span>
                        <select id="sRefType" class="p-1.5 border border-slate-300 rounded shadow-sm w-36">
                            <option value="none">无(Y轴自适应)</option>
                            <option value="Rln2">R·ln(2) [S=1/2]</option>
                            <option value="Rln3">R·ln(3) [S=1]</option>
                            <option value="Rln4">R·ln(4) [S=3/2]</option>
                            <option value="Rln5">R·ln(5) [S=2]</option>
                            <option value="Rln6">R·ln(6) [S=5/2]</option>
                            <option value="custom">自定义数值</option>
                        </select>
                    </div>
                    <div id="customSRefDiv" class="flex items-center justify-between hidden mt-1">
                        <span class="font-medium text-slate-500">数值 (J/mol·K):</span>
                        <input type="number" id="sRefCustom" value="5.76" step="0.1" class="w-20 p-1 border border-slate-300 rounded text-center">
                    </div>
                </div>
            </div>

        </div>

        <!-- 高级寻优入口 (固定在底部) -->
        <div class="p-4 bg-indigo-50 shrink-0 border-t border-indigo-100 shadow-[0_-4px_6px_-1px_rgba(0,0,0,0.05)]">
            <button id="openAdvancedBtn" class="w-full bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-3 px-4 rounded shadow-md transition flex justify-center items-center gap-2">
                <svg class="w-5 h-5" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"></path></svg>
                高级自动约束寻优
            </button>
        </div>
    </aside>

    <!-- 右侧图表主区 (硬核百分比布局,根除塌陷) -->
    <main class="flex-1 h-full p-2 flex flex-col gap-2 relative bg-slate-200">
        
        <!-- 上半部分 2 图 (高 50%) -->
        <div class="flex gap-2" style="height: 50%;">
            <!-- 图1 -->
            <div class="bg-white rounded shadow-sm border border-slate-300 flex-1 relative flex flex-col">
                <div class="h-8 flex items-center px-3 border-b border-slate-100 shrink-0">
                    <div class="w-2 h-2 rounded-full bg-slate-500 mr-2"></div>
                    <h3 class="font-bold text-slate-700 text-xs">1. 比热总览与声子基线 (Cp vs T)</h3>
                </div>
                <!-- 图表容器挂载点 (强制绝对定位填充) -->
                <div class="flex-1 w-full relative"><div id="chartMain" style="position: absolute; top:0; bottom:0; left:0; right:0;"></div></div>
            </div>
            
            <!-- 图2 -->
            <div class="bg-white rounded shadow-sm border border-slate-300 flex-1 relative flex flex-col">
                <div class="h-8 flex items-center px-3 border-b border-slate-100 shrink-0">
                    <div class="w-2 h-2 rounded-full bg-orange-500 mr-2"></div>
                    <h3 class="font-bold text-slate-700 text-xs">2. 提取的磁比热异常 (Cmag vs T)</h3>
                </div>
                <div class="flex-1 w-full relative"><div id="chartCmag" style="position: absolute; top:0; bottom:0; left:0; right:0;"></div></div>
            </div>
        </div>

        <!-- 下半部分 2 图 (高 50%) -->
        <div class="flex gap-2" style="height: 50%;">
            <!-- 图3 -->
            <div class="bg-white rounded shadow-sm border border-slate-300 flex-1 relative flex flex-col">
                <div class="h-8 flex items-center px-3 border-b border-slate-100 shrink-0">
                    <div class="w-2 h-2 rounded-full bg-blue-500 mr-2"></div>
                    <h3 class="font-bold text-slate-700 text-xs">3. 极低温外推检验 (Cp/T vs T²)</h3>
                </div>
                <div class="flex-1 w-full relative"><div id="chartLowT" style="position: absolute; top:0; bottom:0; left:0; right:0;"></div></div>
            </div>
            
            <!-- 图4 -->
            <div class="bg-white rounded shadow-sm border border-slate-300 flex-1 relative flex flex-col">
                <div class="h-8 flex items-center justify-between px-3 border-b border-slate-100 shrink-0">
                    <div class="flex items-center">
                        <div class="w-2 h-2 rounded-full bg-red-500 mr-2"></div>
                        <h3 class="font-bold text-slate-700 text-xs">4. 积分磁熵推演 (Smag vs T)</h3>
                    </div>
                    <div class="text-[10px] text-slate-600 bg-red-50 px-2 py-0.5 rounded border border-red-100 z-10">
                        当前最高 S<sub>mag</sub> = <span id="maxEntropy" class="font-bold text-red-600 text-sm">0.00</span>
                    </div>
                </div>
                <div class="flex-1 w-full relative"><div id="chartEntropy" style="position: absolute; top:0; bottom:0; left:0; right:0;"></div></div>
            </div>
        </div>
    </main>

    <!-- 高级功能 Modal -->
    <div id="advancedModal" class="fixed inset-0 z-50 bg-slate-900/40 backdrop-blur-sm hidden flex items-center justify-center p-6">
        <div class="bg-white w-full max-w-6xl h-full max-h-[800px] rounded-xl shadow-2xl flex flex-col overflow-hidden border border-slate-400">
            
            <!-- Modal Header -->
            <header class="bg-indigo-800 text-white px-6 py-3 flex items-center justify-between shrink-0">
                <div class="flex items-center gap-3">
                    <svg class="w-6 h-6 text-indigo-300" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M19.428 15.428a2 2 0 00-1.022-.547l-2.387-.477a6 6 0 00-3.86.517l-.318.158a6 6 0 01-3.86.517L6.05 15.21a2 2 0 00-1.806.547M8 4h8l-1 1v5.172a2 2 0 00.586 1.414l5 5c1.26 1.26.367 3.414-1.415 3.414H4.828c-1.782 0-2.674-2.154-1.414-3.414l5-5A2 2 0 009 10.172V5L8 4z"></path></svg>
                    <h2 class="text-lg font-bold">磁熵与比热 - 启发式双约束自动寻优拟合引擎</h2>
                </div>
                <button id="closeAdvancedBtn" class="text-indigo-200 hover:text-white transition">
                    <svg class="w-8 h-8" fill="none" stroke="currentColor" viewBox="0 0 24 24"><path stroke-linecap="round" stroke-linejoin="round" stroke-width="2" d="M6 18L18 6M6 6l12 12"></path></svg>
                </button>
            </header>

            <div class="flex flex-1 overflow-hidden">
                <!-- Modal Sidebar -->
                <div class="w-80 bg-slate-50 border-r border-slate-300 p-5 flex flex-col gap-4 overflow-y-auto">
                    
                    <div class="bg-white p-3 rounded shadow-sm border border-slate-200">
                        <label class="block text-xs font-bold text-indigo-800 mb-2 border-b pb-1">① 目标拟合模型</label>
                        <div class="flex items-center justify-between text-xs mb-2">
                            <span class="text-slate-600">原子数(n):</span>
                            <input type="number" id="advNAtoms" step="0.1" class="w-16 p-1 border rounded text-center">
                        </div>
                        <select id="advModelType" class="w-full p-1.5 text-xs border rounded font-bold mb-2">
                            <option value="single_debye">单德拜模型</option>
                            <option value="double_debye">双德拜模型</option>
                            <option value="debye_einstein">德拜 + 爱因斯坦模型</option>
                        </select>
                        
                        <!-- 高级动态物理模型展示面板 -->
                        <div id="modelDescAdv" class="p-2 bg-slate-50 rounded border border-slate-200 text-[10px] text-slate-600 shadow-inner">
                            <!-- 动态内容将被注入 -->
                        </div>
                    </div>

                    <div class="bg-white p-3 rounded shadow-sm border border-slate-200">
                        <label class="block text-xs font-bold text-red-800 mb-2 border-b pb-1">② 理论磁熵约束 (S_mag)</label>
                        <div class="flex items-center gap-2 mb-2">
                            <input type="number" id="advTargetS" step="0.01" class="w-full p-1.5 border rounded font-mono text-center font-bold text-red-700">
                        </div>
                        <div class="grid grid-cols-3 gap-1 text-[10px]">
                            <button class="bg-red-50 hover:bg-red-100 text-red-700 py-1 rounded border" onclick="document.getElementById('advTargetS').value=(8.31446*Math.log(2)).toFixed(3)">Rln2</button>
                            <button class="bg-red-50 hover:bg-red-100 text-red-700 py-1 rounded border" onclick="document.getElementById('advTargetS').value=(8.31446*Math.log(3)).toFixed(3)">Rln3</button>
                            <button class="bg-red-50 hover:bg-red-100 text-red-700 py-1 rounded border" onclick="document.getElementById('advTargetS').value=(8.31446*Math.log(4)).toFixed(3)">Rln4</button>
                            <button class="bg-red-50 hover:bg-red-100 text-red-700 py-1 rounded border" onclick="document.getElementById('advTargetS').value=(8.31446*Math.log(5)).toFixed(3)">Rln5</button>
                            <button class="bg-red-50 hover:bg-red-100 text-red-700 py-1 rounded border" onclick="document.getElementById('advTargetS').value=(8.31446*Math.log(6)).toFixed(3)">Rln6</button>
                        </div>
                    </div>

                    <div class="bg-white p-3 rounded shadow-sm border border-slate-200">
                        <label class="block text-xs font-bold text-orange-800 mb-2 border-b pb-1">③ 高温对齐区间 (K)</label>
                        <div class="flex items-center gap-2">
                            <input type="number" id="advFitTMin" value="150" class="w-full p-1 border rounded text-center text-sm font-mono">
                            <span class="text-slate-500">-</span>
                            <input type="number" id="advFitTMax" value="200" class="w-full p-1 border rounded text-center text-sm font-mono">
                        </div>
                    </div>

                    <div class="bg-white p-3 rounded shadow-sm border border-slate-200">
                        <label class="block text-xs font-bold text-slate-700 mb-2 border-b pb-1">④ 寻优配置</label>
                        <div class="flex items-center justify-between text-xs mb-1">
                            <span class="text-slate-600">迭代代数:</span>
                            <select id="advIters" class="w-32 p-1.5 border rounded font-medium">
                                <option value="50">50代 (快速)</option>
                                <option value="200" selected>200代 (推荐)</option>
                                <option value="500">500代 (深度)</option>
                            </select>
                        </div>
                    </div>

                    <div class="mt-auto space-y-2">
                        <!-- 操作按钮区 -->
                        <div class="flex gap-2">
                            <button id="runAutoFitBtn" class="flex-1 bg-indigo-600 hover:bg-indigo-700 text-white font-bold py-2.5 rounded shadow transition text-sm">
                                开始自动寻优
                            </button>
                            <button id="stopAutoFitBtn" class="w-20 bg-rose-600 hover:bg-rose-700 text-white font-bold py-2.5 rounded shadow transition text-sm hidden">
                                ⏹ 停止
                            </button>
                        </div>
                        <button id="applyAdvancedBtn" class="w-full bg-emerald-600 hover:bg-emerald-700 text-white font-bold py-2.5 rounded shadow transition hidden text-sm">
                            应用这套参数并返回主页
                        </button>
                    </div>
                </div>

                <!-- Modal Chart -->
                <div class="flex-1 bg-white p-4 relative flex flex-col">
                    <div class="absolute top-4 left-4 z-10 bg-white/90 p-3 rounded shadow-md border border-slate-200 text-xs">
                        <h4 class="font-bold text-indigo-800 mb-2 border-b pb-1">寻优状态监视器</h4>
                        <div class="grid grid-cols-2 gap-x-4 gap-y-1.5 font-mono">
                            <div class="text-slate-600">适应度(Loss):</div><div id="advLoss" class="font-bold text-slate-800">--</div>
                            <div class="text-orange-700">Θ_D1:</div><div id="advResP1" class="font-bold">--</div>
                            <div class="text-orange-700">Θ_2/E:</div><div id="advResP2" class="font-bold">--</div>
                            <div class="text-orange-700">权重w:</div><div id="advResW" class="font-bold">--</div>
                            <div class="text-red-700 mt-1 pt-1 border-t">结果S:</div><div id="advResS" class="font-bold mt-1 pt-1 border-t text-red-600">--</div>
                        </div>
                    </div>
                    <div class="flex-1 w-full relative"><div id="chartAdvanced" style="position: absolute; top:0; bottom:0; left:0; right:0;"></div></div>
                </div>
            </div>
        </div>
    </div>

    <script>
        // --- 核心数学计算 ---
        const R = 8.314462618; 

        // --- 物理模型动态文档 (全展开、无省略号公式) ---
        const MODEL_DESCRIPTIONS = {
            'single_debye': `
                <div class="font-bold text-slate-800 mb-1 text-center">【单德拜模型】连续弹性波假设</div>
                <div class="font-mono text-indigo-700 bg-indigo-50/80 p-2 rounded mb-1 text-[10px] leading-relaxed border border-indigo-100 text-left">
                    C<sub>lat</sub> = 9nR(T/Θ<sub>D</sub>)³ &int;<sub class="-ml-1 text-[8px]">0</sub><sup class="text-[8px]">Θ<sub>D</sub>/T</sup> [x⁴eˣ/(eˣ-1)²]dx
                </div>
                <ul class="list-none space-y-0.5 opacity-90 pl-1 text-[10px] leading-snug">
                    <li>• <strong>n</strong>: 原胞原子数; <strong>R</strong>: 理想气体常数</li>
                    <li>• <strong>Θ<sub>D</sub></strong>: 德拜温度,反映声学支最高截断频率</li>
                    <li>• <strong>适用</strong>: 简单晶体,低频声学支占据绝对主导</li>
                </ul>
            `,
            'double_debye': `
                <div class="font-bold text-slate-800 mb-1 text-center">【双德拜模型】双声学支混合假设</div>
                <div class="font-mono text-indigo-700 bg-indigo-50/80 p-1.5 rounded mb-1 text-[10px] leading-relaxed border border-indigo-100 text-left">
                    C<sub>lat</sub> = w &middot; C<sub>D</sub>(Θ<sub>D1</sub>) + (1-w) &middot; C<sub>D</sub>(Θ<sub>D2</sub>)<br/>
                    <span class="text-[9px] opacity-75 text-slate-500">* C<sub>D</sub> 为上方单德拜标准积分公式</span>
                </div>
                <ul class="list-none space-y-0.5 opacity-90 pl-1 text-[10px] leading-snug">
                    <li>• <strong>Θ<sub>D1</sub> / Θ<sub>D2</sub></strong>: 分别对应高低两种声学支色散频率</li>
                    <li>• <strong>w</strong>: 模型1所占声子态密度的权重比例</li>
                    <li>• <strong>适用</strong>: 包含质量差异悬殊的原子的复杂化合物</li>
                </ul>
            `,
            'debye_einstein': `
                <div class="font-bold text-slate-800 mb-1 text-center">【德拜+爱因斯坦】广义权重展开式</div>
                <div class="font-mono text-indigo-700 bg-indigo-50/80 p-1.5 rounded mb-1 text-[9px] leading-relaxed border border-indigo-100 text-left px-2">
                    C<sub>lat</sub> = <br/>
                    &nbsp;&nbsp;w &middot; 9nR(T/Θ<sub>D</sub>)³ &int;<sub class="-ml-1 text-[8px]">0</sub><sup class="text-[8px]">Θ<sub>D</sub>/T</sup> [x⁴eˣ/(eˣ-1)²]dx <br/>
                    &nbsp;&nbsp;+ (1-w) &middot; 3nR(Θ<sub>E</sub>/T)² [e<sup>(Θ<sub>E</sub>/T)</sup>/(e<sup>(Θ<sub>E</sub>/T)</sup>-1)²]
                </div>
                <ul class="list-none space-y-0.5 opacity-90 pl-1 text-[10px] leading-snug">
                    <li>• <strong>广义权重 (w)</strong>: 经验调节参数。严格理论下期望值为 1/n,实际分析中允许自由浮动以拟合真实 DOS 混合程度。该公式严格保证高温极限定律。</li>
                    <li>• <strong>Θ<sub>D</sub></strong>: 德拜温度 (对应低频连续色散声学支)</li>
                    <li>• <strong>Θ<sub>E</sub></strong>: 爱因斯坦温度 (对应高频局域光学支)</li>
                </ul>
            `
        };

        function debyeIntegral(limit) {
            if (limit <= 0) return 0;
            const nSteps = 50; 
            const h = limit / nSteps;
            let sum = 0;
            for (let i = 0; i <= nSteps; i++) {
                let x = i * h;
                let y = 0;
                if (x > 1e-5) {
                    let expNegX = Math.exp(-x);
                    y = (Math.pow(x, 4) * expNegX) / Math.pow(1 - expNegX, 2);
                }
                let weight = (i === 0 || i === nSteps) ? 1 : (i % 2 === 0 ? 2 : 4);
                sum += weight * y;
            }
            return (h / 3) * sum;
        }

        function calcDebyeCv(T, thetaD, nAtoms) {
            if (T <= 0 || thetaD <= 0) return 0;
            return 9 * nAtoms * R * Math.pow(T / thetaD, 3) * debyeIntegral(thetaD / T);
        }

        function calcEinsteinCv(T, thetaE, nAtoms) {
            if (T <= 0 || thetaE <= 0) return 0;
            const x = thetaE / T;
            if (x > 100) return 0; 
            let expNegX = Math.exp(-x);
            return 3 * nAtoms * R * Math.pow(x, 2) * expNegX / Math.pow(1 - expNegX, 2);
        }

        function linearInterpolate(xArray, yArray, xi) {
            let n = xArray.length;
            if (xi <= xArray[0]) return yArray[0];
            if (xi >= xArray[n - 1]) return yArray[n - 1];
            let low = 0, high = n - 1;
            while (low <= high) {
                let mid = Math.floor((low + high) / 2);
                if (xArray[mid] < xi) low = mid + 1;
                else high = mid - 1;
            }
            let i = high; 
            let x0 = xArray[i], x1 = xArray[i+1];
            return yArray[i] + (yArray[i+1] - yArray[i]) * (xi - x0) / (x1 - x0);
        }

        // --- 安全 DOM 获取 ---
        const getEl = (id) => document.getElementById(id);
        const bindEvent = (el, type, handler) => {
            if (el) el.addEventListener(type, handler);
        };

        const ui = {
            dataInput: getEl('dataInput'), nAtoms: getEl('nAtoms'),
            useInterpolation: getEl('useInterpolation'), interpStep: getEl('interpStep'), forceNonNegative: getEl('forceNonNegative'),
            autoFitLowT: getEl('autoFitLowT'), t2Min: getEl('t2Min'), t2Max: getEl('t2Max'), t2PlotMax: getEl('t2PlotMax'),
            gammaInput: getEl('gammaInput'), betaInput: getEl('betaInput'), thetaLowVal: getEl('thetaLowVal'),
            enableLattice: getEl('enableLattice'), latticeControls: getEl('latticeControls'), 
            modelType: getEl('modelType'), modelDescMain: getEl('modelDescMain'),
            param1: getEl('param1'), numParam1: getEl('numParam1'),
            param2: getEl('param2'), numParam2: getEl('numParam2'), divParam2: getEl('divParam2'), lblParam2: getEl('lblParam2'),
            weight: getEl('weight'), numWeight: getEl('numWeight'), divWeight: getEl('divWeight'),
            sRefType: getEl('sRefType'), sRefCustom: getEl('sRefCustom'), customSRefDiv: getEl('customSRefDiv'), maxEntropy: getEl('maxEntropy')
        };

        const advUI = {
            modal: getEl('advancedModal'), openBtn: getEl('openAdvancedBtn'), closeBtn: getEl('closeAdvancedBtn'),
            runBtn: getEl('runAutoFitBtn'), stopBtn: getEl('stopAutoFitBtn'), applyBtn: getEl('applyAdvancedBtn'),
            nAtoms: getEl('advNAtoms'), modelType: getEl('advModelType'), modelDescAdv: getEl('modelDescAdv'), targetS: getEl('advTargetS'),
            fitTMin: getEl('advFitTMin'), fitTMax: getEl('advFitTMax'), iters: getEl('advIters'),
            resLoss: getEl('advLoss'), resP1: getEl('advResP1'), resP2: getEl('advResP2'), resW: getEl('advResW'), resS: getEl('advResS')
        };

        // --- 全局状态 ---
        let rawData = [], gridData = [], calcData = [];
        let fitParams = { gamma: 0, beta: 0 };
        let charts = {};

        // 默认数据
        const initialData = "Sample Temp (Kelvin)\tSamp HC (J/mole-K)\n201.07122\t183.62491\n177.86576\t169.60842\n154.37558\t150.58813\n130.94854\t129.51363\n130.56572\t131.9599\n128.97674\t128.07355\n127.23678\t127.10045\n125.50972\t125.68587\n123.78234\t124.27806\n122.05464\t123.05592\n120.32494\t121.88481\n118.57919\t121.98924\n116.84722\t123.97255\n115.10291\t138.2341\n113.37812\t141.74983\n111.65512\t132.78091\n109.92332\t126.16805\n108.16925\t121.27112\n106.43654\t117.01644\n104.70779\t113.28561\n102.95869\t110.27529\n101.22849\t107.01971\n99.50132\t103.85109\n97.77832\t100.85733\n96.04843\t97.98861\n94.32259\t95.09093\n92.60597\t92.03379\n90.86414\t89.28305\n89.13783\t86.38211\n87.40416\t83.38169\n85.64937\t80.7099\n83.91135\t77.83788\n82.17027\t75.03278\n80.42113\t72.39602\n80.31531\t72.79102\n70.9147\t57.74955\n62.44569\t45.04394\n54.99743\t34.54643\n48.40993\t25.57195\n42.60544\t18.82431\n37.48575\t13.47575\n32.97917\t9.51555\n29.01615\t6.50666\n25.52791\t4.46807\n22.46445\t2.99481\n19.76773\t2.0205\n17.3907\t1.33152\n15.30542\t0.92472\n13.46876\t0.62927\n11.85473\t0.45551\n10.43623\t0.30392\n9.09842\t0.24276\n7.98989\t0.17838\n7.01319\t0.14296\n6.15107\t0.10356\n5.40679\t0.08005\n4.74876\t0.06143\n4.17084\t0.04768\n3.66435\t0.03808\n3.22184\t0.03032\n2.83505\t0.02473\n2.50231\t0.01974\n2.21449\t0.01801\n1.96926\t0.01332";

        // 核心求值引擎
        function quickEvaluate(p1, p2, w, useLattice, overrideNAtoms=null, overrideModel=null) {
            const nAtoms = overrideNAtoms !== null ? overrideNAtoms : (parseFloat(ui.nAtoms?.value) || 1);
            const modelType = overrideModel !== null ? overrideModel : (ui.modelType?.value || 'single_debye');
            const forcePositive = ui.forceNonNegative?.checked || false;
            let cumulativeEntropy = 0;
            let tmpCalcData = [];

            for (let i = 0; i < gridData.length; i++) {
                const d = gridData[i];
                let c_lat = 0;
                
                if (useLattice) {
                    if (modelType === 'single_debye') c_lat = calcDebyeCv(d.t, p1, nAtoms);
                    else if (modelType === 'double_debye') c_lat = w * calcDebyeCv(d.t, p1, nAtoms) + (1 - w) * calcDebyeCv(d.t, p2, nAtoms);
                    else if (modelType === 'debye_einstein') c_lat = w * calcDebyeCv(d.t, p1, nAtoms) + (1 - w) * calcEinsteinCv(d.t, p2, nAtoms);
                }
                
                let c_mag = d.cp - c_lat - fitParams.gamma * d.t;
                if (forcePositive) c_mag = Math.max(0, c_mag);
                
                if (i > 0) {
                    const prev_d = gridData[i - 1];
                    const prev_c_mag = tmpCalcData[i - 1].c_mag;
                    cumulativeEntropy += 0.5 * ((c_mag / d.t) + (prev_c_mag / prev_d.t)) * (d.t - prev_d.t);
                } else {
                    cumulativeEntropy += (c_mag / d.t) * d.t; 
                }
                tmpCalcData.push({ t: d.t, c_lat, c_mag, s_mag: cumulativeEntropy, cp: d.cp });
            }
            return tmpCalcData;
        }

        // CSV 导出
        function exportToCSV(dataArray) {
            const targetData = (dataArray && Array.isArray(dataArray)) ? dataArray : calcData;
            if (!targetData || targetData.length === 0) { alert("暂无数据可导出!"); return; }
            let csvContent = "data:text/csv;charset=utf-8,\uFEFF"; 
            csvContent += "T (K),Cp_Total (J/mol.K),C_Lattice (J/mol.K),C_Mag (J/mol.K),S_Mag (J/mol.K)\n";
            targetData.forEach(d => {
                csvContent += `${(d.t||0).toFixed(4)},${(d.cp||0).toFixed(4)},${(d.c_lat||0).toFixed(4)},${(d.c_mag||0).toFixed(4)},${(d.s_mag||0).toFixed(4)}\n`;
            });
            const link = document.createElement("a");
            link.setAttribute("href", encodeURI(csvContent));
            link.setAttribute("download", "HeatCapacity_Analysis.csv");
            document.body.appendChild(link);
            link.click();
            document.body.removeChild(link);
        }

        // 初始化 ECharts
        function initCharts() {
            ['chartMain', 'chartCmag', 'chartLowT', 'chartEntropy', 'chartAdvanced'].forEach(id => {
                const el = document.getElementById(id);
                if(el) {
                    charts[id] = echarts.init(el);
                    if(id !== 'chartAdvanced') {
                        new ResizeObserver(() => { if(charts[id]) charts[id].resize(); }).observe(el.parentElement);
                    }
                }
            });
            const elAdv = document.getElementById('chartAdvanced');
            if(elAdv) {
                new ResizeObserver(() => { if(charts.chartAdvanced && !advUI.modal.classList.contains('hidden')) charts.chartAdvanced.resize(); }).observe(elAdv.parentElement);
            }
        }

        // 数据解析
        function processData() {
            if(!ui.dataInput) return;
            const lines = ui.dataInput.value.split('\n');
            let data = [];
            lines.forEach(line => {
                const trimmed = line.trim();
                if (!trimmed || !/^[0-9.-]/.test(trimmed)) return;
                const parts = trimmed.split(/[\t\s,]+/).filter(Boolean);
                if (parts.length >= 2) {
                    const t = parseFloat(parts[0]), cp = parseFloat(parts[1]);
                    if (!isNaN(t) && !isNaN(cp) && t > 0) data.push({ t, cp, t2: t * t, cp_t: cp / t });
                }
            });
            data.sort((a, b) => a.t - b.t);
            rawData = data.filter((item, index, arr) => index === 0 || item.t > arr[index-1].t);
            if(rawData.length === 0) return;

            gridData = [];
            if (ui.useInterpolation && ui.useInterpolation.checked) {
                const step = Math.max(0.01, parseFloat(ui.interpStep?.value) || 0.5); 
                const tMin = rawData[0].t, tMax = rawData[rawData.length - 1].t;
                const xArr = rawData.map(d => d.t), yArr = rawData.map(d => d.cp);
                for (let T = tMin; T <= tMax; T += step) {
                    let cp = linearInterpolate(xArr, yArr, T);
                    gridData.push({ t: T, cp: cp, t2: T*T, cp_t: cp/T });
                }
                if (gridData[gridData.length-1].t < tMax) {
                    gridData.push({ t: tMax, cp: rawData[rawData.length-1].cp, t2: tMax*tMax, cp_t: rawData[rawData.length-1].cp/tMax });
                }
            } else { gridData = [...rawData]; }
        }

        function processLowT() {
            let gamma = 0, beta = 0;
            if (ui.autoFitLowT && ui.autoFitLowT.checked) {
                const tMin2 = parseFloat(ui.t2Min?.value) || 0, tMax2 = parseFloat(ui.t2Max?.value) || 50;
                const fitData = rawData.filter(d => d.t2 >= tMin2 && d.t2 <= tMax2);
                if (fitData.length > 2) {
                    const n = fitData.length;
                    let sx=0, sy=0, sxy=0, sxx=0;
                    fitData.forEach(d => { sx+=d.t2; sy+=d.cp_t; sxy+=d.t2*d.cp_t; sxx+=d.t2*d.t2; });
                    const denom = n * sxx - sx * sx;
                    if(denom !== 0) { beta = (n * sxy - sx * sy) / denom; gamma = (sy - beta * sx) / n; }
                }
                if(ui.gammaInput) ui.gammaInput.value = gamma.toFixed(4);
                if(ui.betaInput) ui.betaInput.value = beta.toFixed(5);
            } else {
                gamma = parseFloat(ui.gammaInput?.value) || 0;
                beta = parseFloat(ui.betaInput?.value) || 0;
            }
            fitParams = { gamma, beta };
            if(ui.thetaLowVal) ui.thetaLowVal.innerText = beta > 0 ? Math.pow((1944 * (parseFloat(ui.nAtoms?.value)||1)) / beta, 1/3).toFixed(1) : '--';
        }

        function calculateMain() {
            calcData = quickEvaluate(
                parseFloat(ui.numParam1?.value)||300, 
                parseFloat(ui.numParam2?.value)||150, 
                parseFloat(ui.numWeight?.value)||0.5, 
                ui.enableLattice?.checked
            );
            if(ui.maxEntropy) ui.maxEntropy.innerText = calcData.length ? calcData[calcData.length-1].s_mag.toFixed(3) : '0.00';
        }

        // --- 制图核心 ---
        function renderMainCharts() {
            if(rawData.length === 0) return;
            
            const tbConfig = { 
                show: true, feature: { 
                    dataZoom: { yAxisIndex: 'none', title:{zoom:'框选缩放',back:'还原'} }, 
                    restore: { title:'复位' },
                    myExportCsv: {
                        show: true, title: '📥 导出全套分析数据 (CSV)', 
                        icon: 'path://M14,2L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2H14M18,20V9H13V4H6V20H18M12,19L8,15H10.5V12H13.5V15H16L12,19Z', 
                        onclick: () => exportToCSV(calcData)
                    }
                }, 
                iconStyle: { borderColor: '#475569' }, itemSize: 13, top: 0, right: 10 
            };
            const gridConfig = { left: '10%', right: '8%', bottom: '15%', top: '15%' };
            const axSty = { fontSize: 10 };

            if(charts.chartMain) charts.chartMain.setOption({ toolbox: tbConfig, tooltip: { trigger: 'axis' }, legend: { data: ['测点', '插值', '基线'], top: 2, itemWidth: 10, itemHeight: 6, textStyle: {fontSize: 10} }, grid: gridConfig, xAxis: { type: 'value', name: 'T', nameGap: 10, axisLabel: axSty }, yAxis: { type: 'value', name: 'Cp', axisLabel: axSty }, series: [ { name: '测点', type: 'scatter', symbolSize: 3, data: rawData.map(d=>[d.t, d.cp]), itemStyle: { color: '#0f172a' } }, { name: '插值', type: 'line', data: calcData.map(d=>[d.t, d.cp]), symbol: 'none', lineStyle: { color: '#94a3b8', width: 1 } }, { name: '基线', type: 'line', data: calcData.map(d=>[d.t, d.c_lat]), symbol: 'none', lineStyle: { color: '#f97316', width: 2, type: 'dashed' } } ] }, true);

            if(charts.chartCmag) charts.chartCmag.setOption({ toolbox: tbConfig, tooltip: { trigger: 'axis' }, legend: { data: ['Cmag'], top: 2, itemWidth: 10, itemHeight: 6, textStyle: {fontSize: 10} }, grid: gridConfig, xAxis: { type: 'value', name: 'T', nameGap: 10, axisLabel: axSty }, yAxis: { type: 'value', name: 'Cmag', axisLabel: axSty }, series: [ { name: 'Cmag', type: 'line', data: calcData.map(d=>[d.t, d.c_mag]), symbol: 'none', areaStyle: { color: 'rgba(249, 115, 22, 0.2)' }, lineStyle: { color: '#f97316', width: 2 }, markLine: { data: [{ yAxis: 0, lineStyle: {color: '#cbd5e1'} }], symbol: ['none','none'] } } ] }, true);

            const pMax = parseFloat(ui.t2PlotMax?.value), aMax = isNaN(pMax) ? Infinity : pMax;
            const lMaxX = Math.min(aMax, (parseFloat(ui.t2Max?.value)||50)*1.5);
            if(charts.chartLowT) charts.chartLowT.setOption({ toolbox: tbConfig, tooltip: { trigger: 'axis' }, legend: { data: ['实验', '拟合'], top: 2, itemWidth: 10, itemHeight: 6, textStyle: {fontSize: 10} }, grid: gridConfig, xAxis: { type: 'value', name: 'T²', nameGap: 10, axisLabel: axSty }, yAxis: { type: 'value', name: 'Cp/T', scale: true, axisLabel: axSty }, series: [ { name: '实验', type: 'scatter', symbolSize: 3, data: rawData.filter(d=>d.t2<=aMax).map(d=>[d.t2, d.cp_t]), itemStyle: { color: '#3b82f6' } }, { name: '拟合', type: 'line', data: [[0,fitParams.gamma],[lMaxX,fitParams.gamma+fitParams.beta*lMaxX]], symbol: 'none', lineStyle: { color: '#1e3a8a', width: 2 } } ] }, true);

            let refVal = null, mOpt = undefined;
            if(ui.sRefType && ui.sRefType.value !== 'none') {
                refVal = ui.sRefType.value === 'custom' ? parseFloat(ui.sRefCustom?.value||0) : R * Math.log(parseInt(ui.sRefType.value.replace('Rln','')));
                mOpt = { symbol: ['none','none'], data: [{ yAxis: refVal, lineStyle: {color: '#b91c1c', type:'dashed'}, label: {formatter:`${refVal.toFixed(2)}`, position:'insideStartTop', color:'#b91c1c', fontSize:10} }] };
            }
            let sMax = 0;
            for(let i=0; i<calcData.length; i++) if(calcData[i].s_mag > sMax) sMax = calcData[i].s_mag;
            const yM = refVal !== null ? Math.max(sMax*1.1, refVal*1.2) : null;
            if(charts.chartEntropy) charts.chartEntropy.setOption({ toolbox: tbConfig, tooltip: { trigger: 'axis' }, grid: gridConfig, xAxis: { type: 'value', name: 'T', nameGap: 10, axisLabel: axSty }, yAxis: { type: 'value', name: 'Smag', max: yM, axisLabel: axSty }, series: [ { name: 'Smag', type: 'line', data: calcData.map(d=>[d.t, d.s_mag]), symbol: 'none', areaStyle: { color: 'rgba(220, 38, 38, 0.2)' }, lineStyle: { color: '#dc2626', width: 2 }, markLine: mOpt } ] }, true);
        }

        // --- 全局驱动器 ---
        function triggerUpdate() {
            try {
                if(ui.numParam1 && ui.param1) ui.numParam1.value = ui.param1.value;
                if(ui.numParam2 && ui.param2) ui.numParam2.value = ui.param2.value;
                if(ui.numWeight && ui.weight) ui.numWeight.value = ui.weight.value;
                if(ui.divParam2 && ui.modelType) ui.divParam2.style.display = ui.modelType.value === 'single_debye' ? 'none' : 'block';
                if(ui.divWeight && ui.modelType) ui.divWeight.style.display = ui.modelType.value === 'single_debye' ? 'none' : 'block';
                if(ui.customSRefDiv && ui.sRefType) ui.customSRefDiv.style.display = ui.sRefType.value === 'custom' ? 'flex' : 'none';

                // 动态更新展示卡片
                if (ui.modelDescMain && ui.modelType) {
                    ui.modelDescMain.innerHTML = MODEL_DESCRIPTIONS[ui.modelType.value];
                }

                processData();
                if(rawData.length === 0) return;
                processLowT();
                calculateMain();
                renderMainCharts();
            } catch(e) { console.error("Update Error:", e); }
        }

        // UI 绑定
        const sync1 = (e)=>{ if(ui.param1) ui.param1.value=e.target.value; if(ui.numParam1) ui.numParam1.value=e.target.value; triggerUpdate(); };
        const sync2 = (e)=>{ if(ui.param2) ui.param2.value=e.target.value; if(ui.numParam2) ui.numParam2.value=e.target.value; triggerUpdate(); };
        const syncW = (e)=>{ if(ui.weight) ui.weight.value=e.target.value; if(ui.numWeight) ui.numWeight.value=e.target.value; triggerUpdate(); };
        
        bindEvent(ui.param1, 'input', sync1); bindEvent(ui.numParam1, 'change', sync1);
        bindEvent(ui.param2, 'input', sync2); bindEvent(ui.numParam2, 'change', sync2);
        bindEvent(ui.weight, 'input', syncW); bindEvent(ui.numWeight, 'change', syncW);

        ['dataInput', 'nAtoms', 'useInterpolation', 'interpStep', 'forceNonNegative', 't2Min', 't2Max', 't2PlotMax', 'modelType', 'sRefType', 'sRefCustom', 'gammaInput', 'betaInput'].forEach(id => {
            bindEvent(ui[id], 'change', triggerUpdate);
            if(['dataInput', 't2Min', 't2Max', 't2PlotMax'].includes(id)) bindEvent(ui[id], 'input', triggerUpdate);
        });

        bindEvent(ui.autoFitLowT, 'change', e => { 
            if(ui.gammaInput) ui.gammaInput.readOnly = e.target.checked; 
            if(ui.betaInput) ui.betaInput.readOnly = e.target.checked; 
            triggerUpdate(); 
        });
        bindEvent(ui.enableLattice, 'change', e => { 
            if(ui.latticeControls) {
                ui.latticeControls.style.opacity = e.target.checked ? '1' : '0.4'; 
                ui.latticeControls.style.pointerEvents = e.target.checked ? 'auto' : 'none'; 
            }
            triggerUpdate(); 
        });

        // --- 高级寻优模块 ---
        let advActiveData = [];
        let advBestParams = {p1:300, p2:150, w:0.5, loss: Infinity};
        let isSearching = false, shouldStop = false;

        // 高级窗口物理模型同步更新
        bindEvent(advUI.modelType, 'change', () => {
            if(advUI.modelDescAdv) advUI.modelDescAdv.innerHTML = MODEL_DESCRIPTIONS[advUI.modelType.value];
        });

        bindEvent(advUI.openBtn, 'click', () => {
            if(advUI.nAtoms && ui.nAtoms) advUI.nAtoms.value = ui.nAtoms.value;
            if(advUI.modelType && ui.modelType) {
                advUI.modelType.value = ui.modelType.value;
                if(advUI.modelDescAdv) advUI.modelDescAdv.innerHTML = MODEL_DESCRIPTIONS[ui.modelType.value];
            }
            if(ui.sRefType && ui.sRefType.value !== 'none' && ui.sRefType.value !== 'custom') {
                if(advUI.targetS) advUI.targetS.value = (R * Math.log(parseInt(ui.sRefType.value.replace('Rln', '')))).toFixed(3);
            } else if (ui.sRefType && ui.sRefType.value === 'custom') { 
                if(advUI.targetS && ui.sRefCustom) advUI.targetS.value = ui.sRefCustom.value; 
            }
            if(advUI.modal) advUI.modal.classList.remove('hidden');
        });

        bindEvent(advUI.closeBtn, 'click', () => { shouldStop = true; if(advUI.modal) advUI.modal.classList.add('hidden'); });
        bindEvent(advUI.stopBtn, 'click', () => { shouldStop = true; });

        bindEvent(advUI.runBtn, 'click', async () => {
            if(isSearching) return;
            isSearching = true; shouldStop = false;
            if(advUI.runBtn) { advUI.runBtn.classList.add('hidden'); }
            if(advUI.stopBtn) { advUI.stopBtn.classList.remove('hidden'); }
            if(advUI.applyBtn) { advUI.applyBtn.classList.add('hidden'); }

            const targetS = Math.max(parseFloat(advUI.targetS?.value) || 5.76, 1e-5);
            const tMin = parseFloat(advUI.fitTMin?.value) || 150;
            const tMax = parseFloat(advUI.fitTMax?.value) || 200;
            const iters = parseInt(advUI.iters?.value) || 200;
            const nAtoms = parseFloat(advUI.nAtoms?.value) || 1;
            const mType = advUI.modelType?.value || 'single_debye';

            advBestParams = { p1: parseFloat(ui.numParam1?.value)||300, p2: parseFloat(ui.numParam2?.value)||150, w: parseFloat(ui.numWeight?.value)||0.5, loss: Infinity };
            let tempRadius = mType === 'single_debye' ? 200 : 300; 

            for(let i=0; i<iters; i++) { 
                if(shouldStop) break;
                let candidates = [];
                for(let j=0; j<25; j++) {
                    let cp1 = Math.max(50, Math.min(1500, advBestParams.p1 + (Math.random()*2-1)*tempRadius));
                    let cp2 = Math.max(50, Math.min(1500, advBestParams.p2 + (Math.random()*2-1)*tempRadius));
                    let cw = mType==='single_debye' ? 1.0 : Math.max(0, Math.min(1, advBestParams.w + (Math.random()*2-1)*0.2));
                    if(mType==='debye_einstein' && cp2 < 50) cp2 = 50; 
                    candidates.push({p1:cp1, p2:cp2, w:cw});
                }
                
                for(let c of candidates) {
                    let res = quickEvaluate(c.p1, c.p2, c.w, true, nAtoms, mType);
                    let cpLoss = 0, count = 0;
                    for(let d of res) {
                        if(d.t >= tMin && d.t <= tMax) {
                            const tc = Math.max(d.cp - fitParams.gamma*d.t, 1e-5);
                            cpLoss += Math.pow((d.c_lat - tc)/tc, 2); count++;
                        }
                    }
                    cpLoss = count > 0 ? Math.sqrt(cpLoss/count) : 1000;
                    const finalS = res.length > 0 ? res[res.length-1].s_mag : 0;
                    const sLoss = Math.abs(finalS - targetS) / targetS;
                    const loss = cpLoss * 5.0 + sLoss * 1.0;
                    if(loss < advBestParams.loss) { advBestParams = { p1: c.p1, p2: c.p2, w: c.w, loss: loss }; }
                }
                tempRadius *= 0.95; 

                if(i % 5 === 0 || i === (iters - 1)) {
                    if(advUI.resLoss) advUI.resLoss.innerText = advBestParams.loss.toFixed(4);
                    if(advUI.resP1) advUI.resP1.innerText = advBestParams.p1.toFixed(1);
                    if(advUI.resP2) advUI.resP2.innerText = mType==='single_debye'? '--': advBestParams.p2.toFixed(1);
                    if(advUI.resW) advUI.resW.innerText = mType==='single_debye'? '--': advBestParams.w.toFixed(2);
                    
                    advActiveData = quickEvaluate(advBestParams.p1, advBestParams.p2, advBestParams.w, true, nAtoms, mType);
                    if(advUI.resS) advUI.resS.innerText = advActiveData[advActiveData.length-1].s_mag.toFixed(3);
                    
                    if(charts.chartAdvanced) {
                        charts.chartAdvanced.setOption({
                            toolbox: { show: true, feature: { myExportCsv: { show: true, title: '📥 导出此优解CSV', icon: 'path://M14,2L20,8V20A2,2 0 0,1 18,22H6A2,2 0 0,1 4,20V4A2,2 0 0,1 6,2H14M18,20V9H13V4H6V20H18M12,19L8,15H10.5V12H13.5V15H16L12,19Z', onclick: ()=>exportToCSV(advActiveData) } }, top: 0, right: 10 },
                            tooltip: { trigger: 'axis', textStyle: {fontSize: 10} }, legend: { data: ['总比热 Cp', '拟合基线 Clat', '拟合过程磁熵'], bottom: 0, textStyle: {fontSize: 10} },
                            grid: [ { left: '10%', right: '10%', top: '10%', height: '40%' }, { left: '10%', right: '10%', top: '60%', height: '30%' } ],
                            xAxis: [ { type: 'value', gridIndex: 0, axisLabel:{show:false} }, { type: 'value', name:'T(K)', nameLocation:'middle', nameGap:20, gridIndex: 1, axisLabel:{fontSize:10} } ],
                            yAxis: [ { type: 'value', name: 'Cp', gridIndex: 0, axisLabel:{fontSize:10} }, { type: 'value', name: 'Smag', gridIndex: 1, axisLabel:{fontSize:10} } ],
                            series: [
                                { name: '总比热 Cp', type: 'scatter', symbolSize: 3, data: advActiveData.map(d=>[d.t, d.cp]), xAxisIndex: 0, yAxisIndex: 0, itemStyle:{color:'#94a3b8'} },
                                { name: '拟合基线 Clat', type: 'line', data: advActiveData.map(d=>[d.t, d.c_lat]), xAxisIndex: 0, yAxisIndex: 0, lineStyle:{color:'#f97316', width:2}, markArea: { itemStyle:{color:'rgba(249,115,22,0.1)'}, data:[ [{xAxis: tMin}, {xAxis: tMax}] ] } },
                                { name: '拟合过程磁熵', type: 'line', data: advActiveData.map(d=>[d.t, d.s_mag]), xAxisIndex: 1, yAxisIndex: 1, lineStyle:{color:'#ef4444'}, markLine: { data: [{yAxis: targetS, lineStyle:{color:'#b91c1c', type:'dashed'}}], symbol: ['none','none'] } }
                            ]
                        }, true);
                    }
                    await new Promise(r => setTimeout(r, 20)); 
                }
            }

            if(advUI.runBtn) { advUI.runBtn.innerHTML = `重新开始寻优`; advUI.runBtn.classList.remove('hidden'); }
            if(advUI.stopBtn) { advUI.stopBtn.classList.add('hidden'); }
            if(advUI.applyBtn) { advUI.applyBtn.classList.remove('hidden'); }
            isSearching = false;
        });

        bindEvent(advUI.applyBtn, 'click', () => {
            if(advBestParams.loss !== Infinity) {
                if(ui.nAtoms && advUI.nAtoms) ui.nAtoms.value = advUI.nAtoms.value;
                if(ui.modelType && advUI.modelType) ui.modelType.value = advUI.modelType.value;
                
                if(ui.param1) ui.param1.value = advBestParams.p1; 
                if(ui.numParam1) ui.numParam1.value = advBestParams.p1.toFixed(1);
                
                if(ui.modelType && ui.modelType.value !== 'single_debye') {
                    if(ui.param2) ui.param2.value = advBestParams.p2; 
                    if(ui.numParam2) ui.numParam2.value = advBestParams.p2.toFixed(1);
                    if(ui.weight) ui.weight.value = advBestParams.w; 
                    if(ui.numWeight) ui.numWeight.value = advBestParams.w.toFixed(2);
                }
                triggerUpdate(); 
            }
            if(advUI.modal) advUI.modal.classList.add('hidden');
        });

        // 启动
        window.onload = () => {
            if(ui.dataInput) ui.dataInput.value = initialData;
            initCharts();
            setTimeout(triggerUpdate, 50); 
        };
    </script>
</body>
</html>