# OpticsFEM 完整使用说明与代码介绍 | 项目 | 说明 | |------|------| | 文档版本 | v3.0 | | 编制日期 | 2026-06-09 | | 适用代码 | **`3D opticsfem-master/`**(三维版,主算例 FemType=4 散射 + FemType=5 本征频率) | | 适用平台 | Windows x64,**Visual Studio 2026(18)**,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 | 依赖 | 说明 | |---------|------|------| | **4(3D 散射)** | `complex/complexsolver.exe` | **CMake 自动编译**(Eigen SparseLU),求解 **A·x=b** | | **5(3D 本征频率)** | 暂无(矩阵导出阶段) | 当前仅 `Assemble` + `Test_OutputMatrix`;完整求解需 `real_solver/`、`complex_solver/` | | 0–3(2D 遗留) | `complex/complexsolver.exe` 等 | 本征问题另需 `real_solver/`、`complex_solver/` | 散射求解器通过**临时 `.dat` 文件**与主程序交换 CSR 格式矩阵,由 `system()` 启动。 --- ## 2. 目录与文件总览 ``` 3D opticsfem-master/ ├── CMakeLists.txt # CMake:OpticsFEM + complexsolver ├── CMakeSettings.json # VS CMake 设置(x64-Release) ├── sbc3d.json # ★ FemType=4 散射算例配置 ├── eigen3d.json # ★ FemType=5 本征频率算例配置 ├── SBCmesh.dat # ★ 三维四面体网格(散射与本征共用) ├── Interface/ # 对外 API(FemType 路由) ├── test/ # Test_Main.cpp 入口、JSON 解析 ├── complex/ # complexsolver 源码(Eigen 稀疏求解) ├── compare/ # MATLAB:COMSOL 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` 中完成。注释块(第 39–58 行)保留了手动分步调用的旧版写法。 --- ### 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 与 Nedelec(1 阶)基函数及 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 │ ├── kernel(Assemble:体积 + 边界积分) ├── function(BF + 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 ← JSON(PMC/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 ──► Phy(sbc 边界/入射场) ──► MaterialLib(epsilonrR 等) SBCmesh.dat ──► Mesh_3D(四面体 + 三角边界) ──► Assemble ──► 稀疏矩阵 A, 向量 b ──► complexsolver ──► 解向量 x ──► Post ──► OutFile/Ex, Ey, Ez, normE ``` **FemType = 5(三维本征频率):** ``` eigen3d.json ──► Phy(PMC/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 = 2(2D 遗留):** ``` 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 2026(18),工作负载「使用 C++ 的桌面开发」 | | 构建工具 | CMake ≥ 3.8(VS 自带,见下方 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 稀疏矩阵 COO(0-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 0–3,2D 遗留) #### 步骤 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.json(FemType=4)或 bele.json(FemType=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` | 频率 GHz(FemType=3,内部换算 λ = 0.299792458/freq) | #### 边界扩展块(2D 遗留,FemType 0–3 可选) | 块名 | 主要字段 | 用途 | |------|----------|------| | `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 = 2,2D 遗留) ```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.dat(Mesh_3D,FemType = 4 / 5) 见上文 [SBCmesh.dat 网格格式](#sbcmeshdat-网格格式mesh_3d)。 ### 6.3 二维网格 `.dat` 文件(Mesh_2D,FemType 0–3) 由 `Mesh_2D::GetMesh()` 顺序解析,字段顺序固定: ``` NbrVertex Vertex (每行 x y,z 读入时置 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/PBC(FemType=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.dat(FemType=4/5) ├── OpticsFEM_3D_Scatter ← FemType=4:A·x=b │ ├── Assemble(体积 + SBC) │ ├── Solver_LdaDom → complexsolver │ └── Post_3D_Scatter → Ex/Ey/Ez/normE └── OpticsFEM_3D_EigenFreq ← FemType=5:A·x=λB·x ├── Assemble(A 刚度 + B 质量 + PEC/PBC) ├── Test_OutputMatrix → Ai/Aj/Av, Bi/Bj/Bv └── (待接)Solver_EigenFreq → Post_3D_EigenFreq ``` --- ## 附录 B:FemType 与 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.json;A/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`。*