XIAN-FEM-2026June/3D opticsfem-master/OpticsFEM_完整使用说明与代码介绍.md

1060 lines
40 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# OpticsFEM 完整使用说明与代码介绍
| 项目 | 说明 |
|------|------|
| 文档版本 | v3.0 |
| 编制日期 | 2026-06-09 |
| 适用代码 | **`3D opticsfem-master/`**(三维版,主算例 FemType=4 散射 + FemType=5 本征频率) |
| 适用平台 | Windows x64**Visual Studio 202618**MSVC |
| 关联文档 | `compare/README.md`COMSOL 对比)、上级目录 2D 版 `opticsfem-master/` |
---
## 目录
1. [程序概述](#1-程序概述)
2. [目录与文件总览](#2-目录与文件总览)
3. [各模块代码详解](#3-各模块代码详解)
4. [软件架构与执行流程](#4-软件架构与执行流程)
5. [完整使用说明](#5-完整使用说明)
6. [输入输出文件规范](#6-输入输出文件规范)
7. [对外 API 与集成方式](#7-对外-api-与集成方式)
8. [测试算例与数据集](#8-测试算例与数据集)
9. [代码阅读路径](#9-代码阅读路径)
10. [常见问题排查](#10-常见问题排查)
---
## 1. 程序概述
### 1.1 程序定位
**OpticsFEM3D** 是一套基于 C++ 实现的**三维矢量有限元FEM光学电磁仿真内核**。程序采用 **一阶 Nedelec 边元** 离散麦克斯韦方程,通过 JSON 配置物理模型、材料与边界条件,通过 `.dat` 文本文件读入四面体网格,计算结果以文本文件输出。
> **当前三维主算例**
> - **FemType = 4**:三维 SBC 散射,`sbc3d.json`,网格 `SBCmesh.dat`,完整求解流程。
> - **FemType = 5**:三维本征频率,`eigen3d.json`,同一网格,当前完成 A/B 矩阵组装与导出。
### 1.2 支持的问题类型
| FemType | 问题类型 | 驱动类 | 网格 | 求解器 | 后处理 | 状态 |
|---------|----------|--------|------|--------|--------|------|
| 0 | 本征模式2D 遗留) | `OpticsFEM_2D_EigenMode` | `Mesh_2D` | `Solver_EigenMode` | `Post_2D_EigenMode` | 遗留 |
| 1 | 本征频率2D 遗留) | `OpticsFEM_2D_EigenFreq` | `Mesh_2D` | `Solver_EigenFreq` | `Post_2D_EigenFreq` | 遗留 |
| 2 | 2D 散射(按波长 λ) | `OpticsFEM_2D_Scatter` | `Mesh_2D` | `Solver_LdaDom` | `Post_2D_Scatter` | 遗留 |
| 3 | 2D 散射(按频率 f | `OpticsFEM_2D_Scatter` | `Mesh_2D` | `Solver_LdaDom` | `Post_2D_Scatter` | 遗留 |
| **4** | **3D 一阶散射SBC按 λ)** | **`OpticsFEM_3D_Scatter`** | **`Mesh_3D`** | **`Solver_LdaDom`** | **`Post_3D_Scatter`** | **完整** |
| **5** | **3D 一阶本征频率** | **`OpticsFEM_3D_EigenFreq`** | **`Mesh_3D`** | **`Solver_EigenFreq`** | **`Post_3D_EigenFreq`** | **组装+矩阵导出** |
### 1.3 设计原则
- **单一 API 入口**:外部只需调用 `OpticsFEM_All()`,无需感知内部分支。
- **JSON 为配置语言**:物理、材料、边界、求解参数均通过 JSON 传递。
- **前后端解耦**`Test_Main.cpp` 可替换为 GUI、脚本或 DLL 宿主,接口不变。
- **模块化分层**:网格 → 物理/材料 → 组装 → 求解 → 后处理,各层独立。
### 1.4 第三方依赖(源码内嵌)
| 依赖 | 路径 | 用途 |
|------|------|------|
| Eigen | `Eigen/` | 稠密/稀疏矩阵运算337 个头文件header-only |
| nlohmann/json | `nlohmann/` | JSON 解析 |
| muparserX 派生库 | `parser/` | BELE、SBC、端口等边界表达式求值 |
### 1.5 运行时外部依赖
| FemType | 依赖 | 说明 |
|---------|------|------|
| **43D 散射)** | `complex/complexsolver.exe` | **CMake 自动编译**Eigen SparseLU求解 **A·x=b** |
| **53D 本征频率)** | 暂无(矩阵导出阶段) | 当前仅 `Assemble` + `Test_OutputMatrix`;完整求解需 `real_solver/`、`complex_solver/` |
| 032D 遗留) | `complex/complexsolver.exe` 等 | 本征问题另需 `real_solver/`、`complex_solver/` |
散射求解器通过**临时 `.dat` 文件**与主程序交换 CSR 格式矩阵,由 `system()` 启动。
---
## 2. 目录与文件总览
```
3D opticsfem-master/
├── CMakeLists.txt # CMakeOpticsFEM + complexsolver
├── CMakeSettings.json # VS CMake 设置x64-Release
├── sbc3d.json # ★ FemType=4 散射算例配置
├── eigen3d.json # ★ FemType=5 本征频率算例配置
├── SBCmesh.dat # ★ 三维四面体网格(散射与本征共用)
├── Interface/ # 对外 APIFemType 路由)
├── test/ # Test_Main.cpp 入口、JSON 解析
├── complex/ # complexsolver 源码Eigen 稀疏求解)
├── compare/ # MATLABCOMSOL vs OpticsFEM 切面对比
├── phy/ # 物理模型与边界条件
├── material/ # 材料库
├── mesh/ # Mesh_2D + Mesh_3D 读写
├── kernel/ # 2D/3D 组装(散射 SBC + 本征 A/B
├── solver/ # 数值求解器接口
├── post/ # Post_3D_Scatter / Post_3D_EigenFreq
├── function/ # Nedelec 基函数与高斯积分
├── common/ # 公共常量
├── parser/ # 表达式解析器
├── nlohmann/ # JSON 库
├── Eigen/ # 线性代数库
├── scat3D/ # 推荐FemType=4 本地 CMake 构建(不上传)
└── eigen3D/ # 推荐FemType=5 本地 CMake 构建(不上传)
```
**源码统计(不含 scat3D/、eigen3D/、build/ 等构建目录):**
| 类别 | 数量 | 说明 |
|------|------|------|
| 业务源文件 `.cpp` | 约 35 个 | 组装、求解、后处理等核心逻辑 |
| 业务头文件 `.h` | 约 20 个 | 类声明与接口 |
| parser 模块 | 约 89 个 | muparserX 表达式引擎 |
| Eigen 第三方 | 337 个 | 仅头文件,不参与业务修改 |
| **合计参与编译** | 约 70+ `.cpp` | 链接为单一 `OpticsFEM.exe` |
---
## 3. 各模块代码详解
### 3.1 Interface/ — 对外 API
| 文件 | 说明 |
|------|------|
| `FEM_Interface.h` | 定义 `OpticsFEMData` 结构体与 `OpticsFEM_API` 类;预留 `extern "C"` DLL 导出注释 |
| `FEM_Interface.cpp` | **核心调度器**:解析 JSON 中 `FemType`,创建对应 FEM 驱动/求解器/后处理对象,执行 Assemble → Run → Post 全流程 |
**关键函数:**
```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); // 连通性测试
};
```
**返回值:** 0 = FemType 无法识别1 = 2D 本征模式2 = 2D 本征频率3 = 2D 散射;**4 = 3D 散射完成****5 = 3D 本征频率矩阵导出完成**。
---
### 3.2 test/ — 入口与数据解析
| 文件 | 说明 |
|------|------|
| `Test_Main.cpp` | 进程 `main()` 入口:从 JSON 文件(默认 `sbc3d.json`)读取整行 JSON封装为 `OpticsFEMData`,调用 `OpticsFEM_All()`。本征算例改为 `eigen3d.json` 后须重新编译 |
| `Test_ReadData.cpp` | 实现 `Phy_WaveOpticsModel::Test_ReadData()``MaterialLib::Test_ReadData()`,将 JSON 字段映射到内存对象 |
| `Test_OutputData.cpp` | 调试用途:将组装后的稀疏矩阵 A/B/P 输出到文本文件 |
| `interfaceClass.h` | 遗留的 `FemInput` 结构体,记录预期配置字段(当前 JSON 路径未直接使用) |
**注意:** `Test_Main.cpp` 中声明的 `Phy_WaveOpticsModel`、`MaterialLib` 等对象在 `main()` 内未被直接使用;实际实例化在 `FEM_Interface.cpp` 中完成。注释块(第 3958 行)保留了手动分步调用的旧版写法。
---
### 3.3 phy/ — 物理模型与边界条件
| 文件 | 说明 |
|------|------|
| `Phy_Base.h` | `Phy_WaveOpticsModel` 类声明:存储 PMC/PEC/PBC/PML/SBC/ELE/MAG/SCD/MPD/EPD/BELE/端口/高斯光束等边界数据及访问接口 |
| `Phy_Base.cpp` | 构造函数与各边界查询 getter 实现 |
| `Phy_Interface.cpp` | `GetPhy()` 占位桩 |
**BoundaryFlag 编码(`Test_ReadData.cpp`**
| 值 | 边界类型 |
|----|----------|
| 0 | PMC理想磁导体 |
| 1 | PEC理想电导体 |
| 2 | SBC散射边界条件 |
| 3 | ELE电场 Dirichlet 边界) |
| 4 | PBC周期边界成对计数 |
| 8 | MAG磁场边界 |
| 9 | SCD面电流密度 |
**支持的 JSON 边界扩展块:** `sbc`、`ef`、`mag`、`scd`、`pbc`、`mpd`、`epd`、`bele`、`pml`、`port`、`beam`(均为可选,按 `js.contains()` 判定是否解析)。
---
### 3.4 material/ — 材料库
| 文件 | 说明 |
|------|------|
| `Material_Base.h` | `Material`(单材料张量属性)与 `MaterialLib`(按物理域索引的材料库) |
| `Material_Base.cpp` | 材料属性 setter/getter |
| `Material_Interface.cpp` | `MaterialLib::SetMat()`、`SetNumberMat()`,材料类型分发(各向同性 ε/μ 或 n,k 折射率) |
**材料 JSON 字段:**
| 字段 | 类型 | 说明 |
|------|------|------|
| `NbrDomain` | int | 物理域数量 |
| `matType` | int[] | 0 = ε/μ 张量1 = n,k 折射率 |
| `epsilonrR/I` | double[] | 相对介电常数实部/虚部 |
| `murR/I` | double[] | 相对磁导率 |
| `sigma` | double[] | 电导率 |
| `chiheR/I`, `chiehR/I` | double[] | 磁电耦合张量 |
| `n`, `k` | double[] | 折射率matType=1 时,ε = (n+ik)²) |
---
### 3.5 mesh/ — 网格
| 文件 | 说明 |
|------|------|
| `Mesh_Base.h` | `Mesh_2D`(三角形、边、边界域)与 `Mesh_3D`(四面体、棱柱,部分实现)数据结构及查询 API |
| `Mesh_Base.cpp` | 顶点、边、单元、域编号等基本访问器 |
| `Mesh_Interface.cpp` | `Mesh_2D::GetMesh()`:顺序解析 `.dat` 网格文件 |
| `Mesh_Find.cpp` | 域/PBC 索引查找:边/节点所属域、PBC 源/目标映射 |
**Mesh_3D** 已接入 `FemType=4`(散射)与 `FemType=5`(本征频率),读入 `SBCmesh.dat` 等三维四面体网格。
---
### 3.6 kernel/ — FEM 组装
| 文件 | 说明 |
|------|------|
| `Assemble_Base.h` | 声明全部 `OpticsFEM_*` 驱动类2D 本征模式/频率/散射3D 本征频率/散射) |
| `Assemble_Base.cpp` | 依赖注入(`GetMaterial`、`GetMesh` 等),各驱动的 `Run()`/`Post()` 实现 |
| `Assemble_kernel.cpp` | 各问题类型顶层 `Assemble()`:实/复矩阵选择、DOF 规模、边界分发 |
| `Assemble_EigenMode_Equation.cpp` | 2D 本征模式体积积分curl-curl + 质量矩阵) |
| `Assemble_EigenMode_Boundary.cpp` | 本征模式 PEC/PBC 约束 |
| `Assemble_EigenFreq_Equation.cpp` | 2D/3D 本征频率体积积分 |
| `Assemble_EigenFreq_Boundary.cpp` | 本征频率 PEC/PBC |
| `Assemble_Scatter_Equation.cpp` | 散射问题驱动麦克斯韦弱形式体积积分 |
| `Assemble_Scatter_2D_Boundary.cpp` | 2D 边界项SBC、BELE、PML、PEC/ELE、PBC、端口、MPD/EPD、MAG、SCD |
| `Assemble_Scatter_3D_Boundary.cpp` | 3D 边界组装SBC、PEC/ELE部分实现 |
**Assemble 阶段输出:** 稀疏矩阵 **A**、右端向量 **b**、预处理矩阵 **P**(实数或复数,由 PML/SBC/复材料等条件自动判定)。
---
### 3.7 solver/ — 数值求解
| 文件 | 说明 |
|------|------|
| `Solver_Base.h` | `Solver_EigenMode`、`Solver_EigenFreq`、`Solver_LdaDom` 类及稀疏矩阵参数结构 |
| `Solver_Base.cpp` | 简单 getter`GetNbrMode`、`GetLda0`、`GetElectricType` 等) |
| `Solver_Interface.cpp` | JSON 求解参数解析,`SetParam`/`Run` 实现,调用特征值或线性求解器 |
| `eigen_solver.h` | 广义特征值求解 C API 声明(实/复 CSR 格式) |
| `eigen_solver.cpp` | 将矩阵写入 `./real_solver/``./complex_solver/` 临时文件,启动外部特征值求解器,读回结果 |
| `interface.h` | `solveRealLinearEqu`、`solveComplexLinearEqu` 声明 |
| `interface.cpp` | 通过临时 `.dat` 文件调用 `complex/complexsolver.exe` 等外部线性求解器 |
| `framework.h` | Windows DLL 风格求解器接口头 |
**求解器分层:**
| 层级 | 模块 | 适用问题 | 运行时依赖 |
|------|------|----------|------------|
| 特征值 | `eigen_solver.cpp` | FemType 0, 1 | `real_solver/real`, `complex_solver/complex` |
| 线性(实) | `interface.cpp` | 实散射 | `real/realsolver.exe` |
| 线性(复) | `interface.cpp` | 复散射 | `complex/complexsolver.exe` |
当前工程通过宏 `EIGENSOLVER_STATIC``eigen_solver.cpp` 静态编入可执行文件,**不再依赖** `lib/eigensolver.lib`
---
### 3.8 post/ — 后处理
| 文件 | 说明 |
|------|------|
| `Post_Base.h` | `Post_2D_EigenMode`、`Post_2D_EigenFreq`、`Post_2D_Scatter` 及 3D 后处理类声明 |
| `Post_Base.cpp` | `GetMesh`/`GetSolver`/`GetResult`/`GetPhy` 接线 |
| `Post_CalEletric.cpp` | 利用 Nedelec 基函数将边/顶点 DOF 重构为顶点 Ex/Ey/Ez |
| `Post_GetEb.cpp` | 在网格顶点处用 muparser 求值 BELE 解析背景场 |
| `Post_Output.cpp` | 写入 `neff`/`freq`/`Ex`/`Ey`/`Ez`/`normE` 文本文件 |
| `Post_Power.cpp` | `GetPower()` 占位(本征模式返回 0 |
---
### 3.9 function/ — 基函数与高斯积分
| 文件 | 说明 |
|------|------|
| `BF.h` / `BF.cpp` | `BF` 分发类:按单元类型选择并求值基函数 |
| `BF_Line.cpp` | 一维 Lagrange 基函数及梯度/curl |
| `BF_Triangle.cpp` | 二维三角形 Lagrange 与 Nedelec1 阶)基函数及 curl |
| `BF_Quadrangle.cpp` | 二维四边形 Lagrange/Nedelec 基函数 |
| `BF_Tetrahedron.cpp` | 三维四面体 Nedelec 基函数及 curl |
| `BF_Prism.cpp` | 三维棱柱 Nedelec 基函数及 curl |
| `Gauss.h` / `Gauss.cpp` | `Gauss` 类:按单元类型与阶次选择积分规则 |
| `Gauss_Line.h` | 线段高斯点/权重 |
| `Gauss_Triangle.h` | 三角形高斯点/权重 |
| `Gauss_Quadrangle.h` | 四边形高斯点/权重 |
| `Gauss_Tetrahedron.h` | 四面体高斯点/权重 |
| `Gauss_Prism.h` | 棱柱高斯点/权重 |
---
### 3.10 common/ — 公共定义
| 文件 | 说明 |
|------|------|
| `define.h` | 几何/网格/基函数/材料/物理常量(`c_const`、`Pi`、单元类型、边界标志等) |
| `util.h` / `util.cpp` | 数值 clamp、快速排序、唯一索引等网格/组装辅助工具 |
---
### 3.11 parser/ — 数学表达式解析器muparserX
共约 **89 个** `.cpp`/`.h` 文件,为 vendored **muparserX** 分支,用于求值 BELE、SBC、端口等边界上的字符串表达式`"sin(2*pi*x)"`)。
| 分组 | 代表文件 | 作用 |
|------|----------|------|
| 核心引擎 | `mpParser.*`, `mpParserBase.*`, `mpRPN.*`, `mpTokenReader.*`, `mpScriptTokens.*` | 表达式 → RPN → 求值 |
| 值系统 | `mpValue.*`, `mpValueCache.*`, `mpVariable.*`, `mpValReader.*` | 类型化值存储、变量、缓存 |
| 函数库 | `mpFuncCommon/Cmplx/NonCmplx/Matrix/Str.*` | 内置数学/字符串/矩阵函数 |
| 运算符 | `mpOprtBinCommon/Assign/Shortcut/Cmplx/NonCmplx/Matrix/Index/PostfixCommon.*` | 二元/一元/后缀运算符 |
| 注册包 | `mpPackageCommon/Cmplx/NonCmplx/Matrix/Str/Unit.*` | 函数与运算符注册 |
| 插件接口 | `mpICallback.*`, `mpIOprt.*`, `mpIPackage.*`, `mpIValue.*`, `mpIToken.*`, `mpIValReader.*` | 扩展接口 |
| 辅助 | `mpError.*`, `mpIfThenElse.*`, `mpMatrix.*`, `mpTest.*`, `mpDefines.h`, `mpCompat.h`, `mpFwdDecl.h`, `mpTypes.h`, `mpStack.h`, `suSortPred.h`, `suStringTokens.h`, `utGeneric.h` | 错误处理、条件分支、矩阵类型、诊断 |
**一般用户无需修改此模块。**
---
### 3.12 nlohmann/ — JSON 库
| 文件 | 说明 |
|------|------|
| `json.hpp` | nlohmann JSON 单头文件完整实现 |
| `json_fwd.hpp` | 前向声明,加速编译 |
---
### 3.13 Eigen/ — 线性代数库
337 个头文件header-only 第三方库。主要模块:`Core`、`Dense`、`Sparse`、`SparseCore`、`Eigenvalues`、`LU`、`QR`、`SVD`、`Geometry` 等。全项目矩阵运算与稀疏组装均依赖 Eigen。
**一般用户无需修改此模块。**
---
### 3.14 根目录构建文件
| 文件 | 说明 |
|------|------|
| `CMakeLists.txt` | 定义 `OpticsFEM` 可执行目标列出全部源文件分组PARSER/COMMON/GAUSS/BF/MESH/MATERIAL/PHY/SOLVER/POST/KERNEL/TEST/INTERFACE设置 C++17 与 `EIGENSOLVER_STATIC` |
| `CMakeSettings.json` | Visual Studio 中 CMake 配置(生成器、架构等) |
---
## 4. 软件架构与执行流程
### 4.1 模块依赖关系
```
Test_Main.cpp
FEM_Interface.cpp ──► Phy / Material / Mesh读入
├── FemType 0 ──► OpticsFEM_2D_EigenMode ──► Solver_EigenMode ──► Post_2D_EigenMode
├── FemType 1 ──► OpticsFEM_2D_EigenFreq ──► Solver_EigenFreq ──► Post_2D_EigenFreq
├── FemType 2/3 ► OpticsFEM_2D_Scatter ──► Solver_LdaDom ──► Post_2D_Scatter
├── FemType 4 ──► OpticsFEM_3D_Scatter ──► Solver_LdaDom ──► Post_3D_Scatter
└── FemType 5 ──► OpticsFEM_3D_EigenFreq ──► Solver_EigenFreq ──► Post_3D_EigenFreq
└── Mesh_3D ← SBCmesh.dat
├── kernelAssemble体积 + 边界积分)
├── functionBF + Gauss 数值积分)
└── parser边界表达式求值
```
### 4.2 完整调用序列FemType=4三维 SBC 散射)
```
Test_Main.cpp
└─ 读取 sbc3d.json
└─ OpticsFEM_All(data)
└─ [FemType == 4]
├─ Phy / Material ← JSON含 sbc 块)
├─ Mesh_3D::GetMesh("SBCmesh.dat")
├─ OpticsFEM_3D_Scatter::Assemble()
│ ├─ Assemble_WaveEquation()
│ └─ Assemble_SBC() SBCType 0 出射 + 1 入射
├─ Run() → complex/complexsolver.exe
└─ Post("OutFile") → Ex, Ey, Ez, normE
```
### 4.2b 完整调用序列FemType=5三维本征频率
```
Test_Main.cpp
└─ 读取 eigen3d.json
└─ OpticsFEM_All(data)
└─ [FemType == 5]
├─ Phy / Material ← JSONPMC/PEC/PBC 边界)
├─ Mesh_3D::GetMesh("SBCmesh.dat")
├─ OpticsFEM_3D_EigenFreq::Assemble()
│ ├─ Assemble_WaveEquation() A=curl-curl, B=ε·质量
│ └─ Assemble_PEC_PBC() 边界约束矩阵 P
└─ Test_OutputMatrix("OutFile") → Ai/Aj/Av, Bi/Bj/Bv
Run/Post 待接入eigs 求 λ,再重构 Ex/Ey/Ez/freq
```
### 4.3 完整调用序列FemType=2二维散射遗留
```
main()
└─ OpticsFEM_API::OpticsFEM_All(data)
├─ json::parse(data.data)
├─ Phy_WaveOpticsModel::Test_ReadData(str)
├─ MaterialLib::Test_ReadData(str)
├─ Mesh_2D::GetMesh(meshFile, str)
└─ [FemType == 2]
├─ Solver_LdaDom::GetSolver(str)
├─ OpticsFEM_2D_Scatter::GetMaterial / GetMesh / GetPhy / GetSolver / GetPost
├─ OpticsFEM_2D_Scatter::Assemble()
│ ├─ Assemble_WaveEquation() 体积积分
│ ├─ Assemble_PEC_ELE() 理想导体/电边界
│ ├─ Assemble_PBC() 周期边界
│ ├─ Assemble_BELE() 边界等效源
│ ├─ Assemble_PML() 完美匹配层
│ └─ Assemble_Port() 等 端口激励
├─ OpticsFEM_2D_Scatter::Run()
│ └─ Solver_LdaDom::Run() → solveComplexLinearEqu()
└─ OpticsFEM_2D_Scatter::Post(outFile)
├─ GetElectric() DOF → 顶点 Ex/Ey/Ez
└─ OutputData() 写入 OutFile/
```
### 4.4 数据流
**FemType = 4三维散射**
```
sbc3d.json ──► Physbc 边界/入射场)
──► MaterialLibepsilonrR 等)
SBCmesh.dat ──► Mesh_3D四面体 + 三角边界)
──► Assemble ──► 稀疏矩阵 A, 向量 b
──► complexsolver ──► 解向量 x
──► Post ──► OutFile/Ex, Ey, Ez, normE
```
**FemType = 5三维本征频率**
```
eigen3d.json ──► PhyPMC/PEC/PBC
──► MaterialLib
SBCmesh.dat ──► Mesh_3D
──► Assemble ──► 稀疏矩阵 A刚度, B质量
──► Test_OutputMatrix ──► OutFile/Ai,Aj,Av,Bi,Bj,Bv
(后续 Run: eigs(A,B) → λ=k₀²Post → freq, Ex/Ey/Ez
```
**物理对应关系:** 散射体积分 `A_scatter ≈ A_eigen k₀²·B_eigen`(同一网格与 Nedelec 基函数下)。
**FemType = 22D 遗留):**
```
bele.json ──► Phy_WaveOpticsModel边界/激励)
──► MaterialLib材料参数
──► MeshFile 路径
project_3.dat ──► Mesh_2D网格拓扑
──► Assemble ──► 稀疏矩阵 A, 向量 b
──► Solver ──► 解向量 x
──► Post ──► OutFile/Ex, Ey, Ez, normE
```
---
## 5. 完整使用说明
### 5.1 环境要求
| 组件 | 要求 |
|------|------|
| 操作系统 | Windows 10/11 x64 |
| 编译器 | Visual Studio 202618工作负载「使用 C++ 的桌面开发」 |
| 构建工具 | CMake ≥ 3.8VS 自带,见下方 PATH |
| C++ 标准 | C++17 |
### 5.2 编译步骤
推荐使用**两个独立构建目录**,避免散射与本征互相覆盖 exe 和 OutFile
```powershell
# 若 cmake 不在 PATH 中,追加 VS 2026 自带 CMake 路径
$env:Path += ";C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin"
cd "3D opticsfem-master"
# FemType=4 散射
cmake -B scat3D -G "Visual Studio 18 2026" -A x64
cmake --build scat3D --config Release
# FemType=5 本征频率
cmake -B eigen3D -G "Visual Studio 18 2026" -A x64
cmake --build eigen3D --config Release
```
**产物路径:**
- `scat3D/Release/OpticsFEM.exe` + `scat3D/Release/complex/complexsolver.exe`
- `eigen3D/Release/OpticsFEM.exe`
也可使用单一 `build/` 目录(见 `CMakeSettings.json`),但切换算例时需重新编译并注意 OutFile 覆盖。
### 5.3 运行前准备FemType = 4三维散射
#### 步骤 1指定 JSON 配置文件
`test/Test_Main.cpp` 默认读取 **`sbc3d.json`**
```cpp
std::ifstream fd("sbc3d.json");
```
更换算例时修改文件名;修改后须**重新编译 scat3D**。
#### 步骤 2部署输入文件
将 JSON 及 `MeshFile` 指定的网格文件复制到 **`scat3D/Release/`**(与 exe 同目录):
```powershell
Copy-Item sbc3d.json, SBCmesh.dat -Destination scat3D\Release\
```
#### 步骤 3确认求解器
```
scat3D/Release/
├── OpticsFEM.exe
├── sbc3d.json
├── SBCmesh.dat
└── complex/
└── complexsolver.exe ← cmake --build 后自动生成
```
#### 步骤 4执行
```powershell
cd scat3D/Release
.\OpticsFEM.exe
```
控制台应打印 `OpticsFEM_All returned 4`
#### 步骤 5查看结果
检查 `OutFile/` 是否生成:`Ex`、`Ey`、`Ez`、`normE`。
---
### 5.3c 运行前准备FemType = 5三维本征频率
#### 步骤 1指定 JSON 配置文件
编辑 `test/Test_Main.cpp`
```cpp
std::ifstream fd("eigen3d.json");
```
修改后须**重新编译 eigen3D**(可与 scat3D 并存,互不干扰)。
#### 步骤 2部署输入文件
```powershell
Copy-Item eigen3d.json, SBCmesh.dat -Destination eigen3D\Release\
```
#### 步骤 3执行
```powershell
cd eigen3D/Release
.\OpticsFEM.exe
```
控制台应打印 `OpticsFEM_All returned 5`
#### 步骤 4查看矩阵输出
`OutFile/` 下导出 A/B 稀疏矩阵 COO0-based
| 文件 | 含义 |
|------|------|
| `Ai.txt`, `Aj.txt`, `Av.txt` | 刚度矩阵 A |
| `Bi.txt`, `Bj.txt`, `Bv.txt` | 质量矩阵 Bε 加权) |
可与 MATLAB `3D一阶本征问题2``export_ab_matrix.m` 输出对比验证。
> **当前限制**`Run()`(广义特征值求解)与 `Post()`场重构、freq 输出)尚未接入 `FEM_Interface.cpp` 的 FemType=5 分支。
---
### 5.3b 运行前准备FemType 032D 遗留)
#### 步骤 1指定 JSON 配置文件
编辑 `test/Test_Main.cpp``fd.open(...)` 的文件名。
#### 步骤 2部署输入文件
将 JSON 及 JSON 中 `MeshFile` 指定的 `.dat` 网格文件复制到 `build/Release/` 目录(与 `OpticsFEM.exe` 同目录)。
#### 步骤 3部署外部求解器
**散射算例FemType 2/3/4最小目录**
```
Release/
├── OpticsFEM.exe
├── *.json # sbc3d.jsonFemType=4或 bele.jsonFemType=2
├── *.dat # SBCmesh.dat 或 project_3.dat
└── complex/
└── complexsolver.exe
```
**本征算例FemType 0/1另需**
```
Release/
├── real_solver/real # 实数特征值求解器
└── complex_solver/complex # 复数特征值求解器
```
#### 步骤 4执行
```powershell
cd build/Release
.\OpticsFEM.exe
```
#### 步骤 5查看结果
检查 JSON 中 `OutFile` 指定目录(默认 `./OutFile`)是否生成:
- 散射:`Ex`、`Ey`、`Ez`、`normE`
- 本征模式:上述文件 + `neff`
- 本征频率:上述文件 + `freq`
### 5.4 切换算例
| 操作 | 方法 |
|------|------|
| 更换 JSON | 修改 `Test_Main.cpp``fd.open()` 文件名,或将目标 JSON 复制为当前文件名 |
| 更换网格 | 确保 JSON 中 `MeshFile` 与实际 `.dat` 文件名一致 |
| 更换问题类型 | 修改 JSON 中 `FemType`0/1/2/3/4/5程序自动路由 |
### 5.5 快速验证sbc3d 三维 SBC 散射)
1. 编译 `scat3D` Release见 5.2 节)
2. 确认 `Test_Main.cpp` 读取 `sbc3d.json`,复制 `sbc3d.json`、`SBCmesh.dat` 到 `scat3D/Release/`
3. 确认 `sbc3d.json``"FemType": 4`
4. 运行 `OpticsFEM.exe`
5. 检查 `OutFile/` 下四个场文件
与 COMSOL 对比见 `compare/README.md`
### 5.5b 快速验证eigen3d 三维本征频率)
1. 编译 `eigen3D` Release`Test_Main.cpp` 改为读取 `eigen3d.json`
2. 复制 `eigen3d.json`、`SBCmesh.dat` 到 `eigen3D/Release/`
3. 确认 `"FemType": 5`
4. 运行 `OpticsFEM.exe`,应返回 5
5. 检查 `OutFile/``Ai/Aj/Av`、`Bi/Bj/Bv` 六个文件
### 5.6 快速验证bele 二维算例,遗留)
1.`../测试数据集/bele/` 复制 `bele.json``project_3.dat``build/Release/`
2. 修改 `Test_Main.cpp``fd.open("bele.json")`,重新编译
3. 部署 `complex/complexsolver.exe`
4. 运行 `OpticsFEM.exe`
5. 检查 `OutFile/` 下四个场文件
### 5.7 集成到其他程序
**方式 A — 独立可执行文件(当前模式)**
从文件读取 JSON调用 API适合本地验证。
**方式 B — 动态库(预留)**
取消 `FEM_Interface.h` 底部 `extern "C"` 注释,将 CMakeLists 中 `add_library(OpticsFEM SHARED ...)` 启用,编译为 DLL 供 C#/Python 等调用。
**方式 C — 直接调用 API**
```cpp
#include "Interface/FEM_Interface.h"
std::string jsonStr = "..."; // 紧凑 JSON 字符串
OpticsFEMData data;
data.test1 = 0;
data.test2 = 0;
data.data = (char*)jsonStr.data();
int ret = OpticsFEM_API::OpticsFEM_All(data);
// ret: 1=2D本征模式, 2=2D本征频率, 3=2D散射, 4=3D散射, 5=3D本征矩阵导出, 0=错误
```
---
## 6. 输入输出文件规范
### 6.1 JSON 配置文件
- **格式**:单行 UTF-8 紧凑 JSON`getline()` 读整行)
- **必填公共字段**`FemType`, `NbrBoundary`, `BoundaryFlag`, `NbrDomain`, `MeshFile`, `OutFile`
#### 公共字段说明
| 字段 | 类型 | 说明 |
|------|------|------|
| `FemType` | int | 0=2D本征模式, 1=2D本征频率, 2=2D散射(λ), 3=2D散射(f), **4=3D散射(λ)**, **5=3D本征频率** |
| `NbrBoundary` | int | 边界数量3D 为三角面边界条数2D 为边界面条数) |
| `BoundaryFlag` | int[] | 每条边界的类型编码(见 3.3 节) |
| `NbrDomain` | int | 材料物理域数量 |
| `MeshFile` | string | 网格 `.dat` 文件路径 |
| `OutFile` | string | 结果输出目录 |
| `EletricType` | int | 0=Et, 1=Ez, 2=完整 E散射/本征频率) |
#### 本征问题专用字段
| 字段 | 说明 |
|------|------|
| `NbrMode` | 求解模态数量FemType 0/1/5 |
| `searchValue` | 特征值搜索目标FemType 0/1/5 |
| `searchType`, `solverType`, `maxIterNum`, `tol`, `tolType` | 特征值求解器参数FemType 5 JSON 已预留) |
| `lambda0` | 参考波长FemType 0/5 |
#### 散射问题专用字段
| 字段 | 说明 |
|------|------|
| `lambda` | 真空波长FemType=2 或 **4** |
| `freq` | 频率 GHzFemType=3内部换算 λ = 0.299792458/freq |
#### 边界扩展块2D 遗留FemType 03 可选)
| 块名 | 主要字段 | 用途 |
|------|----------|------|
| `bele` | `index`, `Ebx/y/z`, `curlEbx/y/z` | 背景等效场边界 |
| `ef` | `index`, `E0x/y/z` | 电场 Dirichlet 激励 |
| `pml` | `index`, `PMLType`, `PMLData` | 完美匹配层 |
| `sbc` | `SBCType`, `Index`, `E0x/y/z`, `kx/y/z` | 散射边界(**FemType=4 必填** |
| `pbc` | `srcIndex`, `dstIndex`, `phiR`, `phiI` | 周期边界 |
| `port` | `PORTinc`, `PORTout`, `Einc`, `Eout` | 波导端口 |
#### sbc3d 算例 JSON 摘要FemType = 4
```json
{
"FemType": 4,
"EletricType": 2,
"lambda": 0.8,
"NbrBoundary": 14,
"BoundaryFlag": [0, 2, 2, ...],
"sbc": {
"Index": [1, 2, 3, 4, 5, 14],
"SBCType": [0, 0, 0, 1, 0, 0],
"E0x": ["1", "1", "1", "1", "1", "1"],
"E0y": ["0", "0", "0", "0", "0", "0"],
"E0z": ["0", "0", "0", "0", "0", "0"],
"kx": [0, 0, 0, 0, 0, 0],
"ky": [0, 0, 0, 0, 0, 0],
"kz": [0, 0, 0, 0, 0, 0]
},
"NbrDomain": 2,
"domainType": [2, 2],
"matType": [0, 0],
"epsilonrR": [1.0, 1.5],
"epsilonrI": [0.0, 0.0],
"MeshFile": "SBCmesh.dat",
"OutFile": "./OutFile"
}
```
**SBCType 含义FemType=4**
| 值 | 含义 |
|----|------|
| 0 | 出射 SBC吸收边界 |
| 1 | 入射 SBC平面波激励`E0x/y/z` 指定) |
**BoundaryFlag 编码(三角面边界):** 0=PMC, 1=PEC, **2=SBC**, 3=ELE, 4=PBC, …
#### eigen3d 算例 JSON 摘要FemType = 5
```json
{
"FemType": 5,
"EletricType": 2,
"NbrBoundary": 14,
"BoundaryFlag": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"NbrDomain": 2,
"matType": [0, 0],
"epsilonrR": [1.0, 1.5],
"epsilonrI": [0.0, 0.0],
"murR": [1.0, 1.0],
"MeshFile": "SBCmesh.dat",
"OutFile": "./OutFile",
"NbrMode": 6,
"searchType": 0,
"searchValue": 374740572.5,
"lambda0": 0.8
}
```
本算例为全 PMC 边界(`BoundaryFlag` 全 0与 MATLAB `3D一阶本征问题2` 对齐。方程 **A·x = λ·B·x**,λ = k₀²。
#### SBCmesh.dat 网格格式Mesh_3D
文本格式按块顺序读取1-based 索引,读入后转 0-based
| 块名 | 内容 |
|------|------|
| `NbrVertex` / `Vertex` | 顶点坐标 (x,y,z) |
| `NbrTet` / `Tet` | 四面体顶点连接 |
| `DomainOfTet` | 体域编号 |
| `NbrEdge` / `Edge` | 边列表 |
| `EdgeOfTet` | 四面体六条边局部编号 |
| `NbrTri` / `Tri` | 三角边界元 |
| `DomainOfTri` | 边界面域编号 |
| `ConnOfTri` | 三角面与边的连接 |
| `NbrQuad` / `Quad` | 四边形面元(若有) |
#### bele 算例 JSON 摘要FemType = 22D 遗留)
```json
{
"FemType": 2,
"EletricType": 2,
"lambda": 1,
"NbrBoundary": 13,
"BoundaryFlag": [0, 0, 3, 0, ...],
"bele": {
"index": [4],
"Eby": "sin(2*pi*x)",
"Ebz": "cos(2*pi*x)"
},
"ef": { "index": [1], "E0y": ["0.5"], "E0z": ["0.3"] },
"pml": { "index": [1,2,3,5], "PMLType": [1,1,1,1], ... },
"NbrDomain": 5,
"matType": [0,0,0,0,0],
"epsilonrR": [1.0, 1.0, 1.0, 1.0, 1.0],
"MeshFile": "project_3.dat",
"OutFile": "./OutFile"
}
```
详细字段定义参见上级目录 `OpticsFEM_LASPCEM_接口规范.md`
---
### 6.2 三维网格 SBCmesh.datMesh_3DFemType = 4 / 5
见上文 [SBCmesh.dat 网格格式](#sbcmeshdat-网格格式mesh_3d)。
### 6.3 二维网格 `.dat` 文件Mesh_2DFemType 03
`Mesh_2D::GetMesh()` 顺序解析,字段顺序固定:
```
NbrVertex
Vertex (每行 x yz 读入时置 0
NbrEdge
Edge (每行 顶点索引0 顶点索引1
NbrTri
Tri (每行 顶点索引0 1 2
EdgeOfTri (每三角形 3 条边索引)
DomainOfTri (每三角形物理域编号,文件内 0-based读入后 +1
NbrEdges
CoonOfEdges (边界边连接信息)
DomainOfEdges (边界边所属域)
normal (边界法向,块大小由 JSON 中 NbrBoundary 决定)
NbrCopyOfEdges
CopyOfEdges
NbrCopyOfVertexs
CopyOfVertexs
```
---
### 6.3 输出文件格式
#### 散射问题(`Post_2D_Scatter::OutputData`
| 文件名 | 格式 | 内容 |
|--------|------|------|
| `Ex` | 首行 `//`,随后每行 `实部 虚部` | 各顶点 Ex |
| `Ey` | 同上 | 各顶点 Ey |
| `Ez` | 同上 | 各顶点 Ez |
| `normE` | 首行 `//`,随后每行一个浮点数 | 各顶点 \|E\| |
#### 本征模式
额外输出 `neff`:每行 `实部 虚部`(有效折射率)。多模态时 `Ex/Ey/Ez/normE``//` 分隔各模态块。
#### 本征频率
额外输出 `freq`:每行 `实部 虚部`(特征频率)。
---
## 7. 对外 API 与集成方式
### 7.1 数据结构
```cpp
struct OpticsFEMData {
double test1; // 保留
double test2; // 保留
char* data; // 指向 UTF-8 JSON 字符串(需保证生命周期覆盖调用期间)
};
```
### 7.2 接口函数
| 函数 | 说明 | 返回值 |
|------|------|--------|
| `OpticsFEM_All(data)` | 读配置 → 组装 → 求解 → 后处理 | 0/1/2/3 |
| `OpticsFEM_Test(data)` | 向 `OutFile + "test"` 写入 `"test success"` | 1 |
### 7.3 DLL 导出(预留)
`FEM_Interface.h` 底部注释代码可在编译为 SHARED 库时启用:
```cpp
extern "C" {
_declspec(dllexport) int OpticsFEM_ALL(OpticsFEMData data) {
return OpticsFEM_API::OpticsFEM_All(data);
}
}
```
---
## 8. 测试算例与数据集
测试数据位于上级目录 **`测试数据集/`**,源码树内**不包含**算例文件。
### 8.1 散射边界条件算例
| 文件夹 | JSON | 网格 | 测试内容 |
|--------|------|------|----------|
| `bele/` | `bele.json` | `project_3.dat` | 背景等效场边界 + PML |
| `pml_xy/` | `pml_xy.json` | `project_1.dat` | XY 方向 PML |
| `epd/` | `epd.json` | `project_4.dat` | 电偶极子源 |
| `mpd/` | `mpd.json` | `project_4.dat` | 磁偶极子源 |
| `mag/` | `mag.json` | `project_4.dat` | 磁场边界 |
| `scd/` | `scd.json` | `project_4.dat` | 面电流密度 |
| `port/` | `port.json` | `meshData_Port.txt` | 波导端口 |
### 8.2 波导/光纤本征模算例
| 文件夹 | 说明 |
|--------|------|
| `条形波导/case1` | 条形波导本征模 |
| `脊波导/case2` | 脊波导 |
| `槽波导/case3` | 槽波导 |
| `SPP波导/case4` | 表面等离激元波导 |
| `光子晶体波导/case5` | 光子晶体波导 |
| `阶跃折射率光纤/case6` | 阶跃折射率光纤 |
| `空芯光纤/case7` | 空芯光纤 |
| `多模光纤/case8` | 多模光纤 |
| `多芯光纤/case9` | 多芯光纤 |
| `光子晶体光纤/case10` | 光子晶体光纤 |
| `一维光子晶体/case11` | 一维光子晶体 |
| `方格光子晶体/case12` | 方格光子晶体 |
| `衍射光栅/case13` | 衍射光栅 |
| `表面等离激元线光栅/case14` | SPP 线光栅 |
| `scatter_modal/` | 散射模态 |
每个本征算例通常包含:`caseN.json`(或 `mesh.json`)、`project_*.dat` 网格,部分含 `.brep` 几何源文件。
---
## 9. 代码阅读路径
建议按以下顺序阅读,建立从入口到输出的完整认知:
| 序号 | 文件 | 阅读目标 |
|------|------|----------|
| 1 | `test/Test_Main.cpp` | 入口,默认读 `sbc3d.json`(本征改为 `eigen3d.json` |
| 2 | `Interface/FEM_Interface.cpp` | FemType 路由(**4→3D散射**, **5→3D本征** |
| 3 | `test/Test_ReadData.cpp` | JSON → Phy/Material`sbc` 块) |
| 4 | `mesh/Mesh_Interface.cpp` | `Mesh_3D::GetMesh` 读 SBCmesh.dat |
| 5 | `kernel/Assemble_kernel.cpp` | `OpticsFEM_3D_Scatter` / `OpticsFEM_3D_EigenFreq` 总控 |
| 6 | `kernel/Assemble_Scatter_3D_Boundary.cpp` | 3D SBC 边界积分FemType=4 |
| 7 | `kernel/Assemble_Scatter_Equation.cpp` | 散射四面体体积方程FemType=4 |
| 8 | `kernel/Assemble_EigenFreq_Equation.cpp` | 本征 A/B 体积积分FemType=5 |
| 9 | `kernel/Assemble_EigenFreq_Boundary.cpp` | 本征 PEC/PBCFemType=5 |
| 10 | `complex/complexsolver.cpp` | Eigen 稀疏线性求解FemType=4 |
| 11 | `post/Post_CalEletric.cpp` | `Post_3D_Scatter::GetElectric` |
| 12 | `post/Post_Output.cpp` | 写入 OutFile |
### 调试建议
-`FEM_Interface.cpp``FemType` 分支入口设断点,确认路由正确。
- 散射分支已调用 `Test_OutputMatrix()`,可在 Assemble 后检查矩阵非零元。
- Post 完成后检查 `OutFile/` 目录内容。
---
## 10. 常见问题排查
| 现象 | 可能原因 | 处理措施 |
|------|----------|----------|
| `cmake` 无法识别 | CMake 未加入 PATH | 使用 VS 自带 CMake 完整路径 |
| `LNK1181: eigensolver.lib` | 旧版仍链接外部库 | 确认 `EIGENSOLVER_STATIC` 已启用 |
| 运行无输出、无 OutFile | 缺少 `complexsolver.exe` 或路径错误 | 检查 `complex/` 目录及工作目录 |
| 无法打开 `sbc3d.json` | 工作目录不含 JSON | 复制到 `Release/` 或在其中运行 |
| 无法打开 `SBCmesh.dat` | `MeshFile` 路径不匹配 | 确保 `.dat` 与 exe 同目录 |
| 无法打开 `eigen3d.json` | 本征算例 JSON 缺失 | 复制到 `eigen3D/Release/` 并确认 Test_Main 文件名 |
| 控制台打印 `err` | JSON 缺少或错误 `FemType` | 检查 JSON 完整性 |
| 编译警告 C4819 | Eigen 头文件编码 | 不影响功能,可忽略 |
| BELE 表达式报错 | 表达式语法错误或变量未定义 | 检查 muparser 支持的函数(如 `sin`, `pi`, `x` |
---
## 附录 A核心类关系图
```
OpticsFEM_API
├── Phy_WaveOpticsModel ← JSON 边界/激励
├── MaterialLib ← JSON 材料
├── Mesh_3D ← SBCmesh.datFemType=4/5
├── OpticsFEM_3D_Scatter ← FemType=4A·x=b
│ ├── Assemble体积 + SBC
│ ├── Solver_LdaDom → complexsolver
│ └── Post_3D_Scatter → Ex/Ey/Ez/normE
└── OpticsFEM_3D_EigenFreq ← FemType=5A·x=λB·x
├── AssembleA 刚度 + B 质量 + PEC/PBC
├── Test_OutputMatrix → Ai/Aj/Av, Bi/Bj/Bv
└── 待接Solver_EigenFreq → Post_3D_EigenFreq
```
---
## 附录 BFemType 与 JSON 关键参数对照
| FemType | 关键 JSON 参数 | 输出特征量 |
|---------|----------------|------------|
| 0 | `lambda0`, `NbrMode`, `searchValue` | `neff`, Ex/Ey/Ez |
| 1 | `lambda0`, `NbrMode`, `searchValue`, `EletricType` | `freq`, Ex/Ey/Ez |
| 2 | `lambda`, 边界块 | Ex/Ey/Ez/normE |
| 3 | `freq`, 边界块 | Ex/Ey/Ez/normE |
| **4** | **`lambda`, `sbc` 块, `SBCmesh.dat`** | **Ex/Ey/Ez/normE** |
| **5** | **`NbrMode`, `searchValue`, `lambda0`, `SBCmesh.dat`** | **Ai/Aj/Av, Bi/Bj/Bv**(当前);后续 **freq, Ex/Ey/Ez** |
---
## 附录 C文档修订记录
| 版本 | 日期 | 修订内容 |
|------|------|----------|
| v3.0 | 2026-06-09 | 新增 FemType=5 三维本征频率scat3D/eigen3D 双构建目录eigen3d.jsonA/B 矩阵导出 |
| v2.0 | 2026-06-08 | 适配 3D 版FemType=4、sbc3d 算例、SBCmesh 格式、CMake complexsolver |
| v1.0 | 2026-06-03 | 初版2D opticsfem-master |
---
*本文档基于 `3D opticsfem-master` 当前代码状态编制。三维主算例:`sbc3d.json`(散射 FemType=4+ `eigen3d.json`(本征 FemType=5共用 `SBCmesh.dat`。*