# OpticsFEM × LASPCEM（Design.em）接口规范

| 项目 | 说明 |
|------|------|
| 版本 | v0.1（草案） |
| 日期 | 2026-06-02 |
| 适用范围 | `laspcem-case` 五个 HFSS/LASPCEM 算例 → `opticsfem-master` 三维矢量 FEM |
| 参考材料 | `C++代码后端-有限元接口.xmind`、`C++有限元程序接口及对应页面设计.pdf`、`二维有限元思维导图.xmind`、`opticsfem-master/Interface/FEM_Interface.*`、`测试数据集/*/case*.json` |

---

## 1. 目标与原则

### 1.1 目标

在**不改造 LASPCEM 前端与网格导出**的前提下，复用其求解输入：

- **`Design.em`**：物理模型、材料、边界、激励、频率（对应原「前端输入 JSON」角色）
- **`Design.em.mesh`**：二阶 Nedelec 四面体网格（对应原「网格 .dat / mesh.json」角色）

由 OpticsFEM 侧新增 **LASPCEM 适配层**，将上述文件转换为内部统一的 **OpticsFEM JSON + 网格文件**，再走现有或规划中的 3D 求解流程。

### 1.2 设计原则（对齐既有思维导图 / PDF）

| 原则 | 说明 |
|------|------|
| 单一 API 入口 | 延续 `OpticsFEM_API::OpticsFEM_All(OpticsFEMData)`，对外仍为一个 DLL 接口 |
| JSON 为内核语言 | 适配层输出符合 `Phy/Material/Mesh/Solver` 已实现的 JSON 字段；`.em` 不直接进入组装器 |
| 前后端解耦 | 页面 / 脚本只提交「案例目录 + 输入模式」；`.em` 解析在 C++ 适配模块完成 |
| 案例可回归 | 以 `laspcem-case` 五例为验收基线，逐例对比场分布或 S 参数（允许数值容差） |

---

## 2. 现有 OpticsFEM 接口（基线）

### 2.1 调用约定

```cpp
struct OpticsFEMData {
    double test1;
    double test2;
    char* data;   // UTF-8 JSON 字符串，单行或紧凑格式
};

class OpticsFEM_API {
public:
    static int OpticsFEM_All(OpticsFEMData data);
    int OpticsFEM_Test(OpticsFEMData data);
};
```

### 2.2 `FemType` 路由（二维，已实现）

| FemType | 问题类型 | 主要 JSON 依赖 |
|---------|----------|----------------|
| 0 | 本征模式 `EigenMode` | `NbrMode`, `searchValue`, `lambda0`, … |
| 1 | 本征频率 `EigenFreq` | `NbrMode`, `searchValue`, `EletricType`, … |
| 2 | 散射 `Scatter` | `lambda`, `sbc`/`port`/`pml`/… |
| 3 | 散射（按频率） | `freq`, `EletricType`, … |

读取链路（现状）：

1. `json::parse(data.data)` → `FemType`, `MeshFile`
2. `Phy_WaveOpticsModel::Test_ReadData(str)`
3. `MaterialLib::Test_ReadData(str)`
4. `Mesh_2D::GetMesh(meshFile, str)` — **仅 2D `.dat`**

### 2.3 二维 JSON 核心字段（摘自 `测试数据集` / `Test_ReadData.cpp`）

**公共**

- `FemType`, `EletricType`, `NbrBoundary`, `BoundaryFlag[]`
- `NbrDomain`, `matType[]`, `epsilonrR/I`, `murR/I`, `sigma`, `chiheR/I`, `chiehR/I`, `n`, `k`
- `MeshFile`, `OutFile`

**边界扩展（按 `js.contains` 可选）**

- `sbc`, `ef`, `mag`, `scd`, `pbc`, `mpd`, `epd`, `bele`, `pml`, `port`, `beam`

**求解**

- 本征：`NbrMode`, `searchType`, `searchValue`, `solverType`, `maxIterNum`, `tol`, `tolType`, `lambda0`
- 散射：`lambda` 或 `freq`

### 2.4 二维网格 `.dat`（`Mesh_2D::GetMesh`）

顺序读取关键字：`NbrVertex` → `Vertex` → `NbrEdge` → `Edge` → `NbrTri` → `Tri` → `EdgeOfTri` → `DomainOfTri` → `NbrEdges` → `CoonOfEdges` → `DomainOfEdges` → `normal` → `CopyOfEdges` → …

> **与 LASPCEM 无直接兼容**；3D 需单独定义 `Mesh_3D` 读入格式（见 §5）。

---

## 3. LASPCEM 输入文件规范

### 3.1 文件对与路径约定

每个算例在求解完成后，在 **`out/<工程名>/1_Result/`** 下生成一对文件（推荐作为适配入口）：

| 文件 | 角色 |
|------|------|
| `Design.em` | 前端 + 求解配置（HOFEM 脚本） |
| `Design.em.mesh` | 网格（由 `mesh_filename` 引用，须与 `.em` 同目录） |

五例标准路径见 **§7 案例对照表**。

> 说明：同目录下可能存在 `.../1_Result/<工程>/1_Result/` 与 `_cur` 副本；**默认使用顶层 `1_Result`**，自适应加密后以日志 `READING INPUT FILE... Design.em` 所指路径为准。

### 3.2 `Design.em` 结构（章节）

| 章节 | 关键变量 | 用途 |
|------|----------|------|
| Physic & formulation | `physics`, `basis_functions`, `variational_order`, `geometrical_order` | 确认波动方程 + Nedelec 阶次 |
| Geometry & Mesh | `geometry_units`, `mesh_format`, `mesh_filename` | 单位与网格文件名 |
| Frequency | `Freq_distribution_num`, `Freq_distribution_type`, `Freq_distribution_info` | 频点扫描；`type=4` 为单频点 |
| Material | `num_materials`, `material_name_i`, `permittivity_i`, … | 材料库 |
| Boundary | `num_boundary_conditions`, `bound_mark_i`, `bound_type_i` | 面标记与 BC |
| Excitation | `num_*_excitations`, `general_*`, `lumped_*`, `exterior_*` | 波端口 / 集总 / 平面波 |
| IIEE | `iiee_truncation_method`, … | 积分方程加速（FEM027 等） |

### 3.3 `Design.em.mesh` 结构（ASCII，二阶四面体）

根据 `FEM001` 样例解析，格式草案如下：

```
<nVertex>
<nEdge>
<pad0>          # 样例为 0
<pad1>          # 样例为 0
<Vertex> × nVertex
    每行: x y z   (科学计数, geometry_units 一致, 样例为 mm)
<Tet> × nTet
    每行: v0 v1 v2 v3  e0 e1 e2 e3 e4 e5  0 0 0
          └─4 顶点索引(1-based)─┘ └─6 边索引─┘  └占位┘
```

- `variational_order = 2` 时，每单元 6 条边 DOF，与行内 6 个边号一致。
- 后续可能还有三角面 / 边界标记块（需在适配器首版用 LASPCEM 日志或 `Design_innerPartsIDs.dat` 交叉验证）。

**禁止**假定与 `project_*.dat` 行格式相同；必须经 **`EmMeshImporter`** 转为 OpticsFEM 3D 网格（§5.2）。

---

## 4. 适配架构

```
┌─────────────┐     ┌──────────────────┐     ┌─────────────────────┐
│ 前端/脚本    │────▶│ OpticsFEM_All     │────▶│ 3D FEM 内核          │
│ casePath    │     │ + LASPCEM 分支    │     │ (EigenMode/Freq/     │
│ InputMode   │     └────────┬─────────┘     │  Scatter 3D)         │
└─────────────┘              │               └─────────────────────┘
                             ▼
                    ┌──────────────────┐
                    │ LaspcemAdapter    │
                    │ · EmParser        │
                    │  · EmMeshImporter │
                    │  · EmToJson       │
                    └────────┬─────────┘
                             ▼
              ┌──────────────────────────────┐
              │ 内部: opticsfem_case.json   │
              │       mesh_3d.dat|json      │
              └──────────────────────────────┘
```

建议新增源文件：

- `opticsfem-master/Interface/LaspcemAdapter.h|.cpp`
- `opticsfem-master/mesh/Mesh_3D_Laspcem.cpp`（或扩展现有 `Mesh_3D_Interface.cpp`）

---

## 5. OpticsFEM 侧扩展接口

### 5.1 对外 JSON 包装（调用 `.em` 时）

在 `OpticsFEMData.data` 中增加 **包装对象**（兼容原纯 JSON 调用）：

```json
{
  "InputMode": "laspcem",
  "CaseId": "FEM001_RecHorn",
  "EmPath": "Z:/.../laspcem-case/FEM001_RecHorn/out/FEM001-RectHorn/1_Result/Design.em",
  "WorkDir": "Z:/.../output/FEM001_run1",
  "OutFile": "./OutFile",
  "OverwriteConverted": false
}
```

| 字段 | 类型 | 必填 | 说明 |
|------|------|------|------|
| `InputMode` | string | 是 | 固定 `"laspcem"`；缺省或其它值走原 JSON 路径 |
| `EmPath` | string | 是 | `Design.em` 绝对或相对路径 |
| `WorkDir` | string | 否 | 转换产物目录；默认 `EmPath` 所在目录 |
| `CaseId` | string | 否 | 五例 ID，用于加载内置映射缺省值 |
| `OutFile` | string | 是 | 结果输出目录（与原 API 一致） |
| `OverwriteConverted` | bool | 否 | 是否强制重新解析 `.em` |

**返回值扩展**（`OpticsFEM_All`）：

| 返回值 | 含义 |
|--------|------|
| 0 | 失败 |
| 1–3 | 原 2D FemType 成功 |
| 10 | LASPCEM → 3D 本征频率成功（规划） |
| 11 | LASPCEM → 3D 散射成功 |
| 12 | 仅完成转换，未求解（调试） |

### 5.2 适配器输出：内部 `opticsfem_case.json`

适配器根据 `Design.em` 生成，字段 **超集** 于二维 JSON，并增加 3D 专用项：

```json
{
  "FemType": 11,
  "Dimension": 3,
  "InputSource": "laspcem",
  "SourceEm": "Design.em",
  "EletricType": 2,
  "ElementOrder": 2,
  "GeometryUnits": "mm",
  "NbrDomain": 3,
  "matType": [0, 0, 0],
  "epsilonrR": [1.0, 1.0, 1.0],
  "epsilonrI": [0.0, 0.0, 0.0],
  "murR": [1.0, 1.0, 0.999991],
  "murI": [0.0, 0.0, 0.0],
  "sigma": [0.0, 1e30, 5.8e7],
  "NbrBoundary": 6,
  "BoundaryFlag": [0, 1, 0, 0, 2, 7],
  "freq": 8.43e9,
  "MeshFile": "mesh_3d_converted.dat",
  "OutFile": "./OutFile",
  "laspcem": {
    "bound_map": [{"mark":0,"type":"NULL"}, {"mark":1,"type":"PEC"}],
    "excitations": {"waveport_general": 1}
  }
}
```

说明：

- `FemType: 11` 为本文建议的 **LASPCEM 3D 散射** 专用路由（实现前可用 `FemType: 2` + `Dimension: 3` 过渡）。
- `freq`：由 `Freq_distribution_info` 首项（MHz）× `1e6` 得到 Hz（五例均为单频 `Freq_distribution_type=4`）。
- `laspcem` 子对象存放 **无法直接映射** 的原始信息，供调试与后续扩展。

### 5.3 三维网格输出 `mesh_3d_converted.dat`（建议）

对齐 `3d光学fem完整实现_f4164ab1.plan.md`，采用关键字文本或 JSON：

```
NbrVertex
<n>
Vertex
x y z
...
NbrEdge
<n>
Edge
i j
...
NbrTet
<n>
Tet
v1 v2 v3 v4
EdgeOfTet
e1 e2 e3 e4 e5 e6
DomainOfTet
<domainId per tet>
NbrTri
<n>
Tri
...
DomainOfTri
...
NormOfFace
nx ny nz
```

索引规则：

- LASPCEM `.mesh` 若为 **1-based**，导入 OpticsFEM 时统一转为 **0-based**（与二维 `DomainOfTri` +1 逻辑相反，需在适配器文档与代码中固定一种约定并在五例测试中锁定）。

---

## 6. 字段映射规范

### 6.1 问题类型判定

| LASPCEM 特征 | OpticsFEM `FemType` | 备注 |
|--------------|---------------------|------|
| `physics = wave_equation` + 端口/平面波激励 | **11**（3D Scatter） | 五例均属此类 |
| 无激励 + 腔体本征（未在五例出现） | 10（3D EigenFreq） | 预留 |
| `iiee_truncation_method = true` | 仍 FEM 主求解，IIEE 仅加速 | 不单独改变 FemType |

### 6.2 频率

| Design.em | OpticsFEM |
|-----------|-----------|
| `Freq_distribution_type = {4}` 单频 | 单频散射 |
| `Freq_distribution_info = { fMHz, fMHz, 1 }` | `freq = fMHz × 1e6`（Hz） |
| 波长需求 | `lambda = c0 / freq`（`c0 = 299792458` m/s，与 `Solver_LdaDom::GetSolver2` 一致） |

### 6.3 材料 `material_name_i` → `matType` / 电磁参数

| LASPCEM | 条件 | `matType` | OpticsFEM 字段 |
|---------|------|-----------|----------------|
| Vacuum | `permittivity=1`, 无损耗 | 0 | `epsilonrR=1`, `sigma=0` |
| PEC | `electric_conductivity ≥ 1e20` 或名称 PEC | 0 | `sigma=1e30`（或边界 PEC 处理） |
| 各向同性介质 | `definition_type = Isotropic` | 0 | `epsilonrR`, `murR`, `sigma` 或 Tanδ 换算 |
| 各向异性 | `definition_type = Anisotropic` | **2**（对角）或 **3**（全张量，扩展） | `epsilonrR` 取 3×3 对角；非对角项进 `laspcem.anisotropic` |

**Tanδ → 损耗**：`epsilonrI = epsilonrR * tanδ`（各向异性时对角元分别处理）。

**域 ID**：由 `.mesh` 单元块或 `MESH/Design_innerPartsIDs.dat` 提供；无域表时，按材料名绑定默认域序号（适配器配置表）。

### 6.4 边界 `bound_type` → `BoundaryFlag`

| bound_type | bound_mark | BoundaryFlag | OpticsFEM 结构 |
|------------|------------|--------------|----------------|
| NULL | m | 不占用边界数组 | — |
| PMC | m | **0** | 内置 PMC 列表 |
| PEC | m | **1** | 内置 PEC 列表 |
| ABC | m | **2** | `sbc`（吸收边界，类型待定义） |
| FCBC | m | **7**（扩展） | 有限电导面；`laspcem.fcbc={sigma,mur}` |
| GEN | m | **8**（扩展） | 广义波端口；映射 `port` 或 `laspcem.waveport` |
| LPO | m | **9**（扩展） | 集总端口；`laspcem.lumped={R,X,integ}` |

> 二维已有：`0=PMC, 1=PEC, 2=SBC, 3=ELE, 4=PBC, 8=MAG, 9=SCD`。三维 LASPCEM 扩展标志 **7–9** 需在 `Phy_WaveOpticsModel::Test_ReadData` 3D 分支中实现。

### 6.5 激励

| LASPCEM 块 | 条件 | OpticsFEM |
|------------|------|-----------|
| `num_waveport_excitations` 第三项 > 0 | `general_*` + `bound_type=GEN` | `port` 或 `laspcem.waveport.general` |
| `num_waveport` 第四项 > 0 | `lumped_*` + `LPO` | `laspcem.lumped`（电阻、积分线坐标） |
| `num_exterior_excitations` 第一项 > 0 | `exterior_*` 平面波 | `sbc` 入射波 + `bound_type=ABC` 面 |
| 多入射角 `exterior_type=Multiple` | FEM049 | `laspcem.exterior.scan[]`，首版可只取第一组角度 |

### 6.6 单元阶次

| Design.em | OpticsFEM |
|-----------|-----------|
| `variational_order = 2` | `ElementOrder = 2`，组装二阶 Nedelec（20 DOF/四面体，见规划文档） |
| `geometrical_order = 2` | 几何二阶映射到 `Mesh_3D` 高阶几何节点（可选） |

---

## 7. 五案例对照表

统一入口目录：`laspcem-case/<CaseId>/out/<Project>/1_Result/`

| CaseId | Project | Design.em / .mesh | 频率 (GHz) | 材料数 | 边界要点 | 激励要点 | 建议 OpticsFEM 路由 |
|--------|---------|-------------------|------------|--------|----------|----------|---------------------|
| **FEM001_RecHorn** | FEM001-RectHorn | `.../1_Result/Design.em` | 8.43 | 3（Vacuum, PEC, copper） | PEC/PMC/ABC/FCBC/**GEN** | 广义波端口 ×1 | FemType **11**, freq=8.43e9 |
| **FEM009_Patch_MetalSurface** | FEM009-Patch_MetalSurface | 同上 | 2.80 | 4 | 含 **FCBC**（Groiss SR） | 广义波端口 ×1 | FemType **11** |
| **FEM013_MountPatch** | FEM013-MountPatch | 同上 | 2.45 | 3（含 FR4） | 含 **LPO** | 集总波端口 ×1 | FemType **11** + `laspcem.lumped` |
| **FEM027_HalfAmygdala_FEIE** | FEM027_HalfAmygdala_FEIE | 同上 | 0.30 | 2 | ABC + **IIEE/MLFMA** | **平面波** Single | FemType **11** + `sbc` 平面波 |
| **FEM049_Anisotropic** | FEM049 | 同上 | 3.00 | 5（3 各向异性块） | ABC | **多角度平面波** Multiple | FemType **11** + 各向异性材料 |

**完整路径示例（FEM001）**：

```
Z:\home\项目文件\西电-合作\laspcem-case\FEM001_RecHorn\out\FEM001-RectHorn\1_Result\Design.em
Z:\home\项目文件\西电-合作\laspcem-case\FEM001_RecHorn\out\FEM001-RectHorn\1_Result\Design.em.mesh
```

**页面设计（PDF）建议暴露字段**：

| 页面控件 | 绑定 |
|----------|------|
| 算例选择下拉 | `CaseId` 五选一 → 自动填充 `EmPath` |
| 频率只读 | 解析 `Freq_distribution_info` |
| 边界列表 | 解析 `num_boundary_conditions` |
| 材料表 | 解析 `num_materials` |
| 输出目录 | `OutFile` |
| 运行 | 调用 `OpticsFEM_All`，`InputMode=laspcem` |

---

## 8. C++ 实现要点（与思维导图节点对应）

### 8.1 接口层 `FEM_Interface.cpp`

```cpp
int OpticsFEM_API::OpticsFEM_All(OpticsFEMData data) {
    json js = json::parse(data.data);
    if (js.value("InputMode", "") == "laspcem") {
        LaspcemAdapter adapter;
        std::string jsonPath, meshPath;
        adapter.Convert(js.at("EmPath"), js.value("WorkDir", ""), jsonPath, meshPath);
        // 将 jsonPath 内容读回 data 或直接传内部结构
        return RunFromInternalJson(jsonPath, meshPath);
    }
    // 原有 FemType 0–3 逻辑
}
```

### 8.2 `LaspcemAdapter::Convert` 步骤

1. 解析 `Design.em`（键值 + `{ ... }` 数组块，`#`/`--` 注释行忽略）
2. 校验 `mesh_filename` 存在且为 `Design.em.mesh`
3. `EmMeshImporter::Load(mesh)` → `Mesh_3D`
4. `EmToJson::Build(em, meshMeta)` → `opticsfem_case.json`
5. `Mesh_3D::Export(mesh_3d_converted.dat)`
6. 写 manifest：`case.converted.json`（记录源路径、哈希、转换时间）

### 8.3 与二维思维导图差异

| 二维 | LASPCEM 3D |
|------|------------|
| 三角网格 + 边 DOF 混合 | 纯四面体 Nedelec |
| `Mesh_2D::GetMesh` | `Mesh_3D::GetMeshFromLaspcem`（新增） |
| TM/TE `EletricType` | 固定 `EletricType=2`（全矢量） |
| 无 IIEE | `iiee_*` 记入 `laspcem`，首版可忽略 |

---

## 9. 错误码与日志

| 代码 | 场景 |
|------|------|
| E001 | `EmPath` 不存在 |
| E002 | `Design.em.mesh` 缺失 |
| E003 | `.em` 键缺失（如无 `Freq_distribution_info`） |
| E004 | 网格段行数与声明不符 |
| E005 | 不支持的 `bound_type` |
| E006 | 各向异性材料未实现 |
| E007 | `FemType` 3D 求解器未就绪 |

日志：转换阶段写 `WorkDir/adapter.log`；求解阶段沿用 `_SolverPip_0.log` 风格。

---

## 10. 验收与测试计划

| 步骤 | 内容 |
|------|------|
| T1 | 五例 `Convert()` 成功，生成 `opticsfem_case.json` + `mesh_3d_converted.dat` |
| T2 | 网格守恒：顶点数、四面体数与 LASPCEM 一致 |
| T3 | 材料/边界条数与 `Design.em` 一致 |
| T4 | FEM001 远场 / S 参数与 LASPCEM `export/*.csv` 对比（容差待定） |
| T5 | FEM049 各向异性 ε 张量对角元与 `.em` 一致 |

---

## 11. 版本路线

| 版本 | 内容 |
|------|------|
| v0.1 | 本文档 + 五例路径与映射表 |
| v0.2 | `EmParser` / `EmMeshImporter` 原型，FEM001 网格贯通 |
| v0.3 | 边界 GEN/LPO/平面波 + FEM013/FEM027 |
| v0.4 | 各向异性 FEM049 + IIEE 忽略说明 |
| v1.0 | `OpticsFEM_All` 正式返回码 11，页面联调 |

---

## 12. 附录 A：`Design.em` 键名索引（解析器必支持）

```
physics, basis_functions, variational_unknown, geometrical_order, variational_order,
geometry_units, mesh_format, mesh_filename,
Freq_distribution_num, Freq_distribution_type, Freq_distribution_info,
num_materials, material_name_*, definition_type_*, permittivity_*, permeability_*,
electric_loss_type_*, dielectric_loss_tangent_*, electric_conductivity_*,
num_boundary_conditions, bound_mark_*, bound_type_*, bound_conduc_*, bound_mur_*,
num_interior_excitations, num_exterior_excitations, num_waveport_excitations,
general_*, lumped_*, exterior_*,
iiee_truncation_method, iiee_truncation_aceleration, iiee_truncation_error
```

## 13. 附录 B：与 `测试数据集` 命名对照

| 测试数据集 | LASPCEM 五例 |
|------------|--------------|
| `case1.json` | `Design.em` |
| `project_3299_15.dat` | `Design.em.mesh` |
| `mesh.json`（辅助） | `MESH/Mesh_Statistics.dat`、`tetmaps.dat`（可选校验） |

---

*文档结束。实现时以 `opticsfem-master` 源码与五例实文件为准；若 LASPCEM 升级导致 `.mesh` 增段，须同步修订 §3.3。*
