40 KiB
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.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 全流程 |
关键函数:
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:
# 若 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.exeeigen3D/Release/OpticsFEM.exe
也可使用单一 build/ 目录(见 CMakeSettings.json),但切换算例时需重新编译并注意 OutFile 覆盖。
5.3 运行前准备(FemType = 4,三维散射)
步骤 1:指定 JSON 配置文件
test/Test_Main.cpp 默认读取 sbc3d.json:
std::ifstream fd("sbc3d.json");
更换算例时修改文件名;修改后须重新编译 scat3D。
步骤 2:部署输入文件
将 JSON 及 MeshFile 指定的网格文件复制到 scat3D/Release/(与 exe 同目录):
Copy-Item sbc3d.json, SBCmesh.dat -Destination scat3D\Release\
步骤 3:确认求解器
scat3D/Release/
├── OpticsFEM.exe
├── sbc3d.json
├── SBCmesh.dat
└── complex/
└── complexsolver.exe ← cmake --build 后自动生成
步骤 4:执行
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:
std::ifstream fd("eigen3d.json");
修改后须重新编译 eigen3D(可与 scat3D 并存,互不干扰)。
步骤 2:部署输入文件
Copy-Item eigen3d.json, SBCmesh.dat -Destination eigen3D\Release\
步骤 3:执行
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:执行
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 散射)
- 编译
scat3DRelease(见 5.2 节) - 确认
Test_Main.cpp读取sbc3d.json,复制sbc3d.json、SBCmesh.dat到scat3D/Release/ - 确认
sbc3d.json中"FemType": 4 - 运行
OpticsFEM.exe - 检查
OutFile/下四个场文件
与 COMSOL 对比见 compare/README.md。
5.5b 快速验证(eigen3d 三维本征频率)
- 编译
eigen3DRelease,Test_Main.cpp改为读取eigen3d.json - 复制
eigen3d.json、SBCmesh.dat到eigen3D/Release/ - 确认
"FemType": 5 - 运行
OpticsFEM.exe,应返回 5 - 检查
OutFile/下Ai/Aj/Av、Bi/Bj/Bv六个文件
5.6 快速验证(bele 二维算例,遗留)
- 从
../测试数据集/bele/复制bele.json和project_3.dat到build/Release/ - 修改
Test_Main.cpp中fd.open("bele.json"),重新编译 - 部署
complex/complexsolver.exe - 运行
OpticsFEM.exe - 检查
OutFile/下四个场文件
5.7 集成到其他程序
方式 A — 独立可执行文件(当前模式)
从文件读取 JSON,调用 API,适合本地验证。
方式 B — 动态库(预留)
取消 FEM_Interface.h 底部 extern "C" 注释,将 CMakeLists 中 add_library(OpticsFEM SHARED ...) 启用,编译为 DLL 供 C#/Python 等调用。
方式 C — 直接调用 API
#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)
{
"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)
{
"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 遗留)
{
"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 网格格式。
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 数据结构
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 库时启用:
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。