# E3 — 红宝石荧光压力测量（plugins/ruby_pressure/）

> **本目录职责**：拟合红宝石 R1/R2 荧光峰，通过 Mao 公式计算压力（GPa）。
> 只允许修改 `ruby_module.py` 和 `__init__.py`。
> **禁止修改 `红宝石拟合_最优解.py`**（只调用）。
> 继承 PluginInterface（见 `plugins/CLAUDE.md`）。
> 本模块为**内置模块**，随软件发布，首次启动默认未勾选。

---

## 插件元信息

```python
PluginInfo(
    plugin_id    = "ruby_pressure_v1",
    name         = "红宝石荧光压力测量",
    version      = "1.0.0",
    requires_stop = False   # 快照或导入CSV后自动触发
)
```

---

## 物理背景

```
P = (A/B) × ((1 + B×Δλ/R1₀)^B − 1)   [GPa]
Δλ = λ_R1 − λ_R1₀
```

## 压力标度

| 标度名 | A | B | R1₀(nm) |
|--------|---|---|---------|
| `mao_nonhydrostatic`（**默认**） | 1904.0 | 5.0 | 694.22 |
| `mao_hydrostatic` | 1904.0 | 7.665 | 694.22 |
| `dewaele` | 1920.0 | 9.61 | 694.24 |
| `dorogokupets` | 1876.0 | 10.71 | 694.24 |

---

## 目录结构

```
plugins/ruby_pressure/
├── __init__.py              # from .ruby_module import RubyPressurePlugin
├── ruby_module.py           # 插件主类（调用拟合文件）
└── 红宝石拟合_最优解.py      # ⛔ 禁止修改（只调用）
```

`红宝石拟合_最优解C++.txt` 不放入此目录，仅存档备查。

---

## 核心数据结构（RubyFitResult）

```python
@dataclass
class RubyFitResult:
    R1_nm:          float; R1_err: float
    R2_nm:          float | None; fwhm_R1: float; fwhm_R2: float | None
    P_GPa:          float; P_err: float; pressure_scale: str
    model:          str    # "Lorentzian" | "Pseudo-Voigt"（AIC最优）
    r_squared:      float; aic: float; snr: float
    fit_wl:         np.ndarray; fit_int: np.ndarray   # 500点拟合曲线
    raw_wl:         np.ndarray; raw_int: np.ndarray   # ROI内原始数据
    roi_nm:         tuple[float, float]
```

---

## ruby_module.py 接口

```python
class RubyPressurePlugin(PluginInterface):

    def validate_input(self, plugin_input):
        """波长范围须覆盖 690–698nm（或用户自定义ROI），ROI内数据点 ≥ 20。"""

    def run(self, plugin_input) -> PluginOutput:
        """流程：截取ROI → _do_fit() → RubyFitResult → PluginOutput。
        summary 示例："R1=694.856nm  P=5.234±0.018 GPa  R²=0.999"
        """

    def get_ui_widget(self) -> QWidget:
        """返回参数控件：压力标度下拉框 + ROI输入 + 结果显示 + [立即计算] + [保存结果CSV]。"""

def _do_fit(
    wl: np.ndarray, intensities: np.ndarray,
    pressure_scale: str,
    roi: tuple[float, float]
) -> RubyFitResult:
    """适配层，调用 红宝石拟合_最优解.py。
    接口不兼容时在此写适配代码，不改原文件。
    原文件只接受文件路径时：用 tempfile 写临时CSV → 调用 → 读结果 → 删除。
    导入失败（缺 scipy）→ raise PluginLoadError("缺少依赖，请执行: pip install scipy")
    """
```

---

## 红宝石拟合_最优解.py 已知接口（开发前阅读原文件核实）

| 函数 | 说明 |
|------|------|
| `load_spectrum(filepath)` | 从CSV加载谱线 |
| `ruby_pressure(lambda_r1, scale)` | 由R1峰位计算压力 |
| `ruby_pressure_gradient(lambda_r1, scale)` | dP/dλ（误差传播用） |
| `PRESSURE_SCALES` | 压力标度参数字典 |

**拟合主函数名以原文件实际定义为准，读文件后填入 `_do_fit` 适配层。**

---

## 触发时机

| 触发方式 | 是否自动 |
|---------|---------|
| 用户点击快照（S8.snapshot）且已勾选 | ✅ 自动 |
| 导入外部CSV后且已勾选 | ✅ 自动 |
| 插件面板点击「立即计算」 | ✅ 手动 |
| 实时采集帧中 | ❌ 不触发 |

---

## 导出 CSV 格式

```
# 红宝石压力测量报告
# 测量时间: 2026-03-25 14:30:22
# 压力标度: mao_nonhydrostatic (A=1904, B=5.0, R1_0=694.22nm)
R1峰位(nm), R1误差(nm), R2峰位(nm), FWHM_R1(nm), 压力(GPa), 压力误差(GPa)
694.856, 0.003, 693.421, 0.48, 5.234, 0.018
```

---

## 约束

- **禁止修改 `红宝石拟合_最优解.py`**
- 压力标度从 UI 读取，不硬编码在 `run()` 中
- ROI 默认 690–698nm，用户可在 UI 自定义
- 禁止访问 `spectrum_ops/`、`Driver/`、`manager/`


---

## 进度文件（必须维护）

本模块进度记录：**`plugins/ruby_pressure/PROGRESS.md`**

每完成一个文件立即更新，未更新 `PROGRESS.md` 前不得开始下一个文件。
发现其他模块的问题，记入"跨模块问题"栏，不得顺手修改。

本模块待完成文件清单：
- [ ] `__init__.py`
- [ ] `ruby_module.py`（E3 主逻辑）
- [ ] `红宝石拟合_最优解.py`（只读引用，不修改）

---

## Agent 状态上报（必须执行）

**本 Agent ID**：`agent-ruby`
**状态文件**：`{项目根目录}/.agents/agent-ruby.status.json`
**上报协议**：参阅 `references/agent_protocol.md`

### 关键时机

| 时机 | status 值 |
|------|----------|
| 开始新阶段 | `running` |
| 完成一个文件/功能 | 更新 step + progress |
| 需要用户授权（删除/覆盖/架构决策）| `waiting` + wait_reason |
| 全部完成 | `done`，progress=100 |
| 遇到无法解决的错误 | `error` + 错误说明 |

**写状态样板代码**：参见 `references/agent_protocol.md`

---

## ⛔ Git 提交禁令

**本 Agent 禁止执行任何 git 操作**（`git add`、`git commit`、`git push` 等）。

完成工作后只需：
1. 更新本模块 `PROGRESS.md`
2. 更新根目录 `PROGRESS.md` 的阶段进度
3. 将状态文件写为 `done`（100%）

**Git 提交由总管 Agent 统一执行。**
