Add 3D eigen frequency (FemType=5) and update docs for scatter+eigen workflows.

Support OpticsFEM_3D_EigenFreq assembly with A/B matrix export, add eigen3d.json, and document scat3D/eigen3D build layout alongside FemType=4 scattering.

Co-authored-by: Cursor <cursoragent@cursor.com>
This commit is contained in:
hpnickk-ai 2026-06-09 15:23:53 +08:00
parent 54279fe532
commit db3ea489fe
11 changed files with 424 additions and 102 deletions

7
.gitignore vendored
View File

@ -1,4 +1,11 @@
build/
build1/
scat3D/
eigen3D/
3D opticsfem-master/scat3D/
3D opticsfem-master/eigen3D/
3D opticsfem-master/build/
3D opticsfem-master/build1/
*.exe
*.obj
*.pdb

View File

@ -1,7 +1,24 @@
################################################################################
# 此 .gitignore 文件已由 Microsoft(R) Visual Studio 自动创建。
################################################################################
# CMake / VS 本地构建目录(勿提交)
/build/
/build1/
/scat3D/
/eigen3D/
/out/
/.vs
/out/build/x64-debug
/build/x64-Debug
# 编译产物
*.exe
*.obj
*.pdb
*.lib
*.exp
*.ilk
*.tlog
*.lastbuildstate
*.recipe
# 大型运行输出(本地验证用)
**/OutFile/

View File

@ -139,6 +139,27 @@ int OpticsFEM_API::OpticsFEM_All(OpticsFEMData data)
fem.Post(outFile);
return 4;
}
else if (FemType == 5)
{
Mesh_3D mesh3d;
OpticsFEM_3D_EigenFreq fem;
Solver_EigenFreq solver;
Post_3D_EigenFreq post;
solver.GetSolver(str);
mesh3d.GetMesh(meshFile, str);
fem.GetMaterial(&matLab);
fem.GetMesh(&mesh3d);
fem.GetPhy(&phy);
fem.GetSolver(&solver);
fem.GetPost(&post);
fem.Assemble();
string outFile = js.at("OutFile");
fem.Test_OutputMatrix(outFile);
return 5;
}
else
{
std::cout << "err" << std::endl;

View File

@ -2,9 +2,9 @@
| 项目 | 说明 |
|------|------|
| 文档版本 | v2.0 |
| 编制日期 | 2026-06-08 |
| 适用代码 | **`3D opticsfem-master/`**(三维版,主算例 FemType=4 |
| 文档版本 | 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/` |
@ -31,17 +31,20 @@
**OpticsFEM3D** 是一套基于 C++ 实现的**三维矢量有限元FEM光学电磁仿真内核**。程序采用 **一阶 Nedelec 边元** 离散麦克斯韦方程,通过 JSON 配置物理模型、材料与边界条件,通过 `.dat` 文本文件读入四面体网格,计算结果以文本文件输出。
> **当前主算例**`FemType = 4`,三维 SBC 散射,配置文件 `sbc3d.json`,网格 `SBCmesh.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`** |
| 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 设计原则
@ -62,7 +65,8 @@
| FemType | 依赖 | 说明 |
|---------|------|------|
| **43D 散射,推荐)** | `complex/complexsolver.exe` | **CMake 会从 `complex/complexsolver.cpp` 自动编译**Eigen SparseLU无需 PETSc |
| **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()` 启动。
@ -75,8 +79,9 @@
3D opticsfem-master/
├── CMakeLists.txt # CMakeOpticsFEM + complexsolver
├── CMakeSettings.json # VS CMake 设置x64-Release
├── sbc3d.json # ★ FemType=4 默认算例配置
├── SBCmesh.dat # ★ 三维四面体网格
├── sbc3d.json # ★ FemType=4 散射算例配置
├── eigen3d.json # ★ FemType=5 本征频率算例配置
├── SBCmesh.dat # ★ 三维四面体网格(散射与本征共用)
├── Interface/ # 对外 APIFemType 路由)
├── test/ # Test_Main.cpp 入口、JSON 解析
├── complex/ # complexsolver 源码Eigen 稀疏求解)
@ -84,18 +89,19 @@
├── phy/ # 物理模型与边界条件
├── material/ # 材料库
├── mesh/ # Mesh_2D + Mesh_3D 读写
├── kernel/ # 2D/3D 组装(含 Assemble_Scatter_3D_Boundary
├── kernel/ # 2D/3D 组装(散射 SBC + 本征 A/B
├── solver/ # 数值求解器接口
├── post/ # Post_3D_Scatter 场重构与输出
├── post/ # Post_3D_Scatter / Post_3D_EigenFreq
├── function/ # Nedelec 基函数与高斯积分
├── common/ # 公共常量
├── parser/ # 表达式解析器
├── nlohmann/ # JSON 库
├── Eigen/ # 线性代数库
└── build/ # CMake 构建产物(本地生成,不上传)
├── scat3D/ # 推荐FemType=4 本地 CMake 构建(不上传)
└── eigen3D/ # 推荐FemType=5 本地 CMake 构建(不上传)
```
**源码统计(不含 build/**
**源码统计(不含 scat3D/、eigen3D/、build/ 等构建目录**
| 类别 | 数量 | 说明 |
|------|------|------|
@ -132,7 +138,7 @@ public:
};
```
**返回值:** 0 = FemType 无法识别1 = 本征模式2 = 本征频率3 = 2D 散射;**4 = 3D 散射完成**。
**返回值:** 0 = FemType 无法识别1 = 2D 本征模式2 = 2D 本征频率3 = 2D 散射;**4 = 3D 散射完成****5 = 3D 本征频率矩阵导出完成**。
---
@ -140,7 +146,7 @@ public:
| 文件 | 说明 |
|------|------|
| `Test_Main.cpp` | 进程 `main()` 入口:从 `bele.json` 读取整行 JSON封装为 `OpticsFEMData`,调用 `OpticsFEM_All()` |
| `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 路径未直接使用) |
@ -204,7 +210,7 @@ public:
| `Mesh_Interface.cpp` | `Mesh_2D::GetMesh()`:顺序解析 `.dat` 网格文件 |
| `Mesh_Find.cpp` | 域/PBC 索引查找:边/节点所属域、PBC 源/目标映射 |
**Mesh_3D** 已在头文件中声明,但 `OpticsFEM_All()` 当前未接入 3D 求解分支
**Mesh_3D** 已接入 `FemType=4`(散射)与 `FemType=5`(本征频率),读入 `SBCmesh.dat` 等三维四面体网格
---
@ -350,7 +356,8 @@ 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 4 ──► OpticsFEM_3D_Scatter ──► Solver_LdaDom ──► Post_3D_Scatter
└── FemType 5 ──► OpticsFEM_3D_EigenFreq ──► Solver_EigenFreq ──► Post_3D_EigenFreq
└── Mesh_3D ← SBCmesh.dat
@ -375,6 +382,22 @@ Test_Main.cpp
└─ 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二维散射遗留
```
@ -403,7 +426,7 @@ main()
### 4.4 数据流
**FemType = 4当前主算例**
**FemType = 4三维散射**
```
sbc3d.json ──► Physbc 边界/入射场)
@ -414,6 +437,19 @@ SBCmesh.dat ──► Mesh_3D四面体 + 三角边界)
──► 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 遗留):**
```
@ -441,26 +477,31 @@ project_3.dat ──► Mesh_2D网格拓扑
### 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"
mkdir build -Force
cd build
cmake .. -G "Visual Studio 18 2026" -A x64
cmake --build . --config Release
# 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
```
**产物路径:** `build/Release/OpticsFEM.exe`
**产物路径:**
- `build/Release/OpticsFEM.exe`
- `build/Release/complex/complexsolver.exe`FemType=4 必需CMake 自动编译)
- `scat3D/Release/OpticsFEM.exe` + `scat3D/Release/complex/complexsolver.exe`
- `eigen3D/Release/OpticsFEM.exe`
### 5.3 运行前准备FemType = 4推荐
也可使用单一 `build/` 目录(见 `CMakeSettings.json`),但切换算例时需重新编译并注意 OutFile 覆盖。
### 5.3 运行前准备FemType = 4三维散射
#### 步骤 1指定 JSON 配置文件
@ -470,22 +511,20 @@ cmake --build . --config Release
std::ifstream fd("sbc3d.json");
```
更换算例时,修改文件名或把目标 JSON 复制为 `sbc3d.json`。修改后须**重新编译**。
更换算例时修改文件名;修改后须**重新编译 scat3D**。
#### 步骤 2部署输入文件
将 JSON 及 `MeshFile` 指定的网格文件复制到 **`build/Release/`**(与 exe 同目录):
将 JSON 及 `MeshFile` 指定的网格文件复制到 **`scat3D/Release/`**(与 exe 同目录):
```powershell
Copy-Item sbc3d.json, SBCmesh.dat -Destination build\Release\
Copy-Item sbc3d.json, SBCmesh.dat -Destination scat3D\Release\
```
#### 步骤 3确认求解器
FemType=4 只需:
```
Release/
scat3D/Release/
├── OpticsFEM.exe
├── sbc3d.json
├── SBCmesh.dat
@ -496,7 +535,7 @@ Release/
#### 步骤 4执行
```powershell
cd build/Release
cd scat3D/Release
.\OpticsFEM.exe
```
@ -508,6 +547,48 @@ cd build/Release
---
### 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 配置文件
@ -560,18 +641,26 @@ cd build/Release
|------|------|
| 更换 JSON | 修改 `Test_Main.cpp``fd.open()` 文件名,或将目标 JSON 复制为当前文件名 |
| 更换网格 | 确保 JSON 中 `MeshFile` 与实际 `.dat` 文件名一致 |
| 更换问题类型 | 修改 JSON 中 `FemType`0/1/2/3/4程序自动路由 |
| 更换问题类型 | 修改 JSON 中 `FemType`0/1/2/3/4/5),程序自动路由 |
### 5.5 快速验证sbc3d 三维 SBC 算例
### 5.5 快速验证sbc3d 三维 SBC 散射
1. 编译 Release见 5.2 节)
2. 复制 `sbc3d.json`、`SBCmesh.dat` 到 `build/Release/`
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/`
@ -602,7 +691,7 @@ data.test2 = 0;
data.data = (char*)jsonStr.data();
int ret = OpticsFEM_API::OpticsFEM_All(data);
// ret: 1=本征模式, 2=本征频率, 3=2D散射, 4=3D散射, 0=错误
// ret: 1=2D本征模式, 2=2D本征频率, 3=2D散射, 4=3D散射, 5=3D本征矩阵导出, 0=错误
```
---
@ -618,7 +707,7 @@ int ret = OpticsFEM_API::OpticsFEM_All(data);
| 字段 | 类型 | 说明 |
|------|------|------|
| `FemType` | int | 0=本征模式, 1=本征频率, 2=2D散射(λ), 3=2D散射(f), **4=3D散射(λ)** |
| `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 | 材料物理域数量 |
@ -630,9 +719,10 @@ int ret = OpticsFEM_API::OpticsFEM_All(data);
| 字段 | 说明 |
|------|------|
| `NbrMode` | 求解模态数量 |
| `searchValue` | 特征值搜索目标 |
| `lambda0` | 真空波长(本征模式 FemType=0 |
| `NbrMode` | 求解模态数量FemType 0/1/5 |
| `searchValue` | 特征值搜索目标FemType 0/1/5 |
| `searchType`, `solverType`, `maxIterNum`, `tol`, `tolType` | 特征值求解器参数FemType 5 JSON 已预留) |
| `lambda0` | 参考波长FemType 0/5 |
#### 散射问题专用字段
@ -690,6 +780,30 @@ int ret = OpticsFEM_API::OpticsFEM_All(data);
**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
@ -734,7 +848,7 @@ int ret = OpticsFEM_API::OpticsFEM_All(data);
---
### 6.2 三维网格 SBCmesh.datMesh_3DFemType = 4
### 6.2 三维网格 SBCmesh.datMesh_3DFemType = 4 / 5
见上文 [SBCmesh.dat 网格格式](#sbcmeshdat-网格格式mesh_3d)。
@ -863,16 +977,18 @@ extern "C" {
| 序号 | 文件 | 阅读目标 |
|------|------|----------|
| 1 | `test/Test_Main.cpp` | 入口,默认读 `sbc3d.json` |
| 2 | `Interface/FEM_Interface.cpp` | FemType 路由(**FemType=4 → 3D** |
| 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` 总控 |
| 6 | `kernel/Assemble_Scatter_3D_Boundary.cpp` | 3D SBC 边界积分 |
| 7 | `kernel/Assemble_Scatter_Equation.cpp` | 四面体体积方程 |
| 8 | `complex/complexsolver.cpp` | Eigen 稀疏线性求解 |
| 9 | `post/Post_CalEletric.cpp` | `Post_3D_Scatter::GetElectric` |
| 10 | `post/Post_Output.cpp` | 写入 OutFile |
| 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 |
### 调试建议
@ -891,7 +1007,7 @@ extern "C" {
| 运行无输出、无 OutFile | 缺少 `complexsolver.exe` 或路径错误 | 检查 `complex/` 目录及工作目录 |
| 无法打开 `sbc3d.json` | 工作目录不含 JSON | 复制到 `Release/` 或在其中运行 |
| 无法打开 `SBCmesh.dat` | `MeshFile` 路径不匹配 | 确保 `.dat` 与 exe 同目录 |
| 无法打开 `bele.json` | 2D 算例文件缺失 | 从 `测试数据集/bele/` 复制 |
| 无法打开 `eigen3d.json` | 本征算例 JSON 缺失 | 复制到 `eigen3D/Release/` 并确认 Test_Main 文件名 |
| 控制台打印 `err` | JSON 缺少或错误 `FemType` | 检查 JSON 完整性 |
| 编译警告 C4819 | Eigen 头文件编码 | 不影响功能,可忽略 |
| BELE 表达式报错 | 表达式语法错误或变量未定义 | 检查 muparser 支持的函数(如 `sin`, `pi`, `x` |
@ -904,11 +1020,15 @@ extern "C" {
OpticsFEM_API
├── Phy_WaveOpticsModel ← JSON 边界/激励
├── MaterialLib ← JSON 材料
├── Mesh_3D ← SBCmesh.datFemType=4
└── OpticsFEM_3D_Scatter ← 3D 散射驱动
├── Assemble体积 + SBC 边界)
├── Solver_LdaDom → complexsolver
└── Post_3D_Scatter → OutFile
├── 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
```
---
@ -922,6 +1042,7 @@ OpticsFEM_API
| 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** |
---
@ -929,9 +1050,10 @@ OpticsFEM_API
| 版本 | 日期 | 修订内容 |
|------|------|----------|
| 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` + `SBCmesh.dat`FemType=4。*
*本文档基于 `3D opticsfem-master` 当前代码状态编制。三维主算例:`sbc3d.json`(散射 FemType=4+ `eigen3d.json`(本征 FemType=5共用 `SBCmesh.dat`。*

View File

@ -7,60 +7,106 @@
| FemType | 说明 | 网格 | 状态 |
|---------|------|------|------|
| 03 | 二维问题(本征/散射) | `Mesh_2D` | 遗留接口,与 2D 版相同 |
| **4** | **三维一阶散射SBC** | **`Mesh_3D`** | **当前主算例** |
| **4** | **三维一阶散射SBC** | **`Mesh_3D`** | **完整:组装 → 求解 → 后处理** |
| **5** | **三维一阶本征频率** | **`Mesh_3D`** | **组装 + A/B 矩阵导出Run/Post 待接)** |
## 快速开始FemType = 4
三维主算例共用网格 **`SBCmesh.dat`**,散射与本征分别使用 `sbc3d.json`、`eigen3d.json`。
### 环境
## 推荐构建目录
为避免散射与本征互相覆盖 exe 和 OutFile建议使用**两个独立 CMake 构建目录**
| 目录 | 用途 | 配置文件 |
|------|------|----------|
| `scat3D/` | FemType=4 散射 | `sbc3d.json` |
| `eigen3D/` | FemType=5 本征频率 | `eigen3d.json` |
旧目录 `build/`、`build1/` 为早期本地构建,可保留或删除,**不必上传 Git**。
## 环境
- Windows 10/11 x64
- Visual Studio 202618工作负载使用 C++ 的桌面开发
- CMake ≥ 3.8(随 VS 安装)
### 编译
`cmake` 不在 PATH 中:
```powershell
$env:Path += ";C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin"
```
## 编译
```powershell
cd "3D opticsfem-master"
# 若 cmake 不在 PATH 中,追加 VS 2026 自带 CMake
$env:Path += ";C:\Program Files\Microsoft Visual Studio\18\Community\Common7\IDE\CommonExtensions\Microsoft\CMake\CMake\bin"
# 散射FemType=4
cmake -B scat3D -G "Visual Studio 18 2026" -A x64
cmake --build scat3D --config Release
mkdir build
cd build
cmake .. -G "Visual Studio 18 2026" -A x64
cmake --build . --config Release
# 本征频率FemType=5
cmake -B eigen3D -G "Visual Studio 18 2026" -A x64
cmake --build eigen3D --config Release
```
产物:
产物(每个构建目录各一份)
- `build/Release/OpticsFEM.exe`
- `build/Release/complex/complexsolver.exe`CMake 自动编译)
- `scat3D/Release/OpticsFEM.exe` 或 `eigen3D/Release/OpticsFEM.exe`
- `*/Release/complex/complexsolver.exe`FemType=4 散射求解必需,CMake 自动编译)
### 运行 sbc3d 算例
## 运行散射算例FemType = 4
1. 修改 `test/Test_Main.cpp`,确保读取 `sbc3d.json`(当前默认),重新编译 `scat3D`
2. 部署输入文件:
```powershell
# 复制输入文件到 exe 同目录
Copy-Item ..\sbc3d.json, ..\SBCmesh.dat -Destination Release\
cd Release
Copy-Item sbc3d.json, SBCmesh.dat -Destination scat3D\Release\
cd scat3D\Release
.\OpticsFEM.exe
```
结果输出到 `Release/OutFile/``Ex`、`Ey`、`Ez`、`normE`。
3. 控制台应打印 `OpticsFEM_All returned 4`
4. 结果在 `OutFile/``Ex`、`Ey`、`Ez`、`normE`。
### 输入文件
## 运行本征频率算例FemType = 5
| 文件 | 说明 |
|------|------|
| `sbc3d.json` | 算例配置,`FemType` 必须为 **4** |
| `SBCmesh.dat` | 三维四面体网格(顶点、四面体、边、三角边界等) |
1. 修改 `test/Test_Main.cpp` 中 JSON 文件名为 `eigen3d.json`,重新编译 `eigen3D`
2. 部署输入文件:
```powershell
Copy-Item eigen3d.json, SBCmesh.dat -Destination eigen3D\Release\
cd eigen3D\Release
.\OpticsFEM.exe
```
3. 控制台应打印 `OpticsFEM_All returned 5`
4. 当前输出 `OutFile/` 下 A/B 稀疏矩阵 COO`Ai/Aj/Av`、`Bi/Bj/Bv`0-based供与 MATLAB `eigs(A,B)` 对比验证。
> **说明**FemType=5 的 `Run()`(特征值求解)与 `Post()`(场重构)尚未接入主流程;矩阵组装与边界处理已完成。
## 输入文件
| 文件 | FemType | 说明 |
|------|---------|------|
| `sbc3d.json` | 4 | 散射配置,含 `sbc` 边界块与 `lambda` |
| `eigen3d.json` | 5 | 本征频率配置,含 `NbrMode`、`searchValue` 等 |
| `SBCmesh.dat` | 4 / 5 | 三维四面体网格(顶点、四面体、边、三角边界等) |
## 物理形式简述
| 问题 | 方程形式 | 矩阵 |
|------|----------|------|
| 散射 (4) | **A·x = b**(给定 λ/k₀ | A = curl-curl k₀²ε + SBCb 来自入射边界 |
| 本征 (5) | **A·x = λ·B·x** | A = curl-curl刚度B = ε·质量 |
体积分核函数相同,散射将刚度与质量合并进 A 并加边界激励;本征拆成 A、B 求特征值。
## 详细文档
- [OpticsFEM_完整使用说明与代码介绍.md](./OpticsFEM_完整使用说明与代码介绍.md) — 模块说明、JSON 字段、FemType=4 专章
- [compare/README.md](./compare/README.md) — 与 COMSOL 的 normE 切面对比
- [OpticsFEM_完整使用说明与代码介绍.md](./OpticsFEM_完整使用说明与代码介绍.md) — 模块说明、JSON 字段、FemType=4/5 专章
- [compare/README.md](./compare/README.md) — 与 COMSOL 的 normE 切面对比(散射)
## 仓库说明
- 只需上传**源码**`build/` 由 CMake 本地生成,不必提交。
- 散射算例FemType=4`complexsolver.exe` 可由 CMake 从 `complex/complexsolver.cpp` 编译,无需单独 PETSc 版求解器。
- 仅上传**源码**与算例 JSON`scat3D/`、`eigen3D/`、`build/`、`build1/` 为本地 CMake 产物,不上传
- FemType=4 的 `complexsolver.exe` 由 CMake 从 `complex/complexsolver.cpp` 编译,无需单独 PETSc 版求解器。

View File

@ -1,6 +1,6 @@
# normE 切面对比COMSOL vs OpticsFEM
**z = 0.5 m** 平面上对比 COMSOL 与 C++ OpticsFEM 的 |E| 热图。
**z = 0.5 m** 平面上对比 COMSOL 与 C++ OpticsFEM 的 |E| 热图**散射算例 FemType=4**
## 目录
@ -18,14 +18,14 @@
## 使用步骤
### 1. 运行 C++ 求解
### 1. 运行 C++ 散射求解
```powershell
cd "3D opticsfem-master\build\Release"
cd "3D opticsfem-master\scat3D\Release"
.\OpticsFEM.exe
```
确认生成 `OutFile/normE`
确认生成 `OutFile/normE`(需已部署 `sbc3d.json``SBCmesh.dat`,见根目录 README
### 2. 导出 COMSOL 切面

View File

@ -0,0 +1,33 @@
{
"FemType": 5,
"EletricType": 2,
"NbrBoundary": 14,
"BoundaryFlag": [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0],
"NbrDomain": 2,
"domainType": [2, 2],
"domainIndex": [0, 1],
"matType": [0, 0],
"epsilonrR": [1.0, 1.5],
"epsilonrI": [0.0, 0.0],
"murR": [1.0, 1.0],
"murI": [0.0, 0.0],
"chiheR": [0.0, 0.0],
"chiehR": [0.0, 0.0],
"chiheI": [0.0, 0.0],
"chiehI": [0.0, 0.0],
"sigma": [0.0, 0.0],
"n": [1.0, 1.0],
"k": [0.0, 0.0],
"MeshFile": "SBCmesh.dat",
"OutFile": "./OutFile",
"NbrMode": 6,
"searchType": 0,
"searchValue": 374740572.5,
"solverType": 0,
"maxIterNum": 40,
"tol": 1.0e-6,
"tolType": 0,
"lambda0": 0.8,
"lambda": 0.0,
"freq": 0.0
}

View File

@ -165,6 +165,8 @@ public:
void Assemble();
void Test_OutputMatrix(const std::string& outDir = "./OutFile");
private:
void Assemble_WaveEquation();
void Assemble_PEC_PBC();

View File

@ -288,7 +288,7 @@ void OpticsFEM_3D_EigenFreq::Assemble_WaveEquation()
//material
int domain = _mMesh->GetDomainOfTet(n);
Matrix3cd epsr = _mMatLib->GetEpsr(domain);
Matrix3cd invMur = _mMatLib->GetEpsr(domain).inverse();
Matrix3cd invMur = _mMatLib->GetMur(domain).inverse();
//mapping
VectorXi MappingIndex = VectorXi::Zero(dof);

View File

@ -512,10 +512,16 @@ void OpticsFEM_2D_Scatter::Post(string file)
}
/*
3D_EigenFreq
3D_EigenFreq - volume assembly_equ sparse A (curl-curl) and B (eps mass)
*/
void OpticsFEM_3D_EigenFreq::Assemble()
{
_mDof = _mMesh->GetNbrEdge();
_mTripleA_real.clear();
_mTripleB_real.clear();
_mTripleA_complex.clear();
_mTripleB_complex.clear();
_mIsReal = _mMatLib->IsReal();
if (_mIsReal)
{
@ -533,11 +539,15 @@ void OpticsFEM_3D_EigenFreq::Assemble()
if (_mIsReal)
{
_mA_real.resize(_mDof, _mDof);
_mB_real.resize(_mDof, _mDof);
_mA_real.setFromTriplets(_mTripleA_real.begin(), _mTripleA_real.end());
_mB_real.setFromTriplets(_mTripleB_real.begin(), _mTripleB_real.end());
}
else
{
_mA_complex.resize(_mDof, _mDof);
_mB_complex.resize(_mDof, _mDof);
_mA_complex.setFromTriplets(_mTripleA_complex.begin(), _mTripleA_complex.end());
_mB_complex.setFromTriplets(_mTripleB_complex.begin(), _mTripleB_complex.end());
}
@ -546,7 +556,24 @@ void OpticsFEM_3D_EigenFreq::Assemble()
{
this->Assemble_PEC_PBC();
}
else
{
if (_mIsReal)
{
_mP_real.resize(_mDof, _mDof);
_mP_real.setIdentity();
}
else
{
_mP_complex.resize(_mDof, _mDof);
_mP_complex.setIdentity();
}
}
std::cout << "[OpticsFEM_3D_EigenFreq] Assemble done: DOF=" << _mDof
<< " nnz(A)=" << (_mIsReal ? _mA_real.nonZeros() : _mA_complex.nonZeros())
<< " nnz(B)=" << (_mIsReal ? _mB_real.nonZeros() : _mB_complex.nonZeros())
<< std::endl;
}
/*
@ -685,6 +712,53 @@ void OpticsFEM_3D_Scatter::Test_OutputMatrix(const std::string& outDir)
}
}
void OpticsFEM_3D_EigenFreq::Test_OutputMatrix(const std::string& outDir)
{
EnsureOutputDir(outDir);
const std::string prefix = outDir + "/";
if (_mIsReal)
{
std::ofstream outAi(prefix + "Ai.txt"), outAj(prefix + "Aj.txt"), outAv(prefix + "Av.txt");
std::ofstream outBi(prefix + "Bi.txt"), outBj(prefix + "Bj.txt"), outBv(prefix + "Bv.txt");
for (const auto& t : _mTripleA_real)
{
outAi << t.row() << '\n';
outAj << t.col() << '\n';
outAv << t.value() << '\n';
}
for (const auto& t : _mTripleB_real)
{
outBi << t.row() << '\n';
outBj << t.col() << '\n';
outBv << t.value() << '\n';
}
std::cout << "[OpticsFEM_3D_EigenFreq] exported A/B COO to " << outDir << std::endl;
}
else
{
std::ofstream outAi(prefix + "Ai.txt"), outAj(prefix + "Aj.txt");
std::ofstream outAv_real(prefix + "Av_real.txt"), outAv_imag(prefix + "Av_imag.txt");
std::ofstream outBi(prefix + "Bi.txt"), outBj(prefix + "Bj.txt");
std::ofstream outBv_real(prefix + "Bv_real.txt"), outBv_imag(prefix + "Bv_imag.txt");
for (const auto& t : _mTripleA_complex)
{
outAi << t.row() << '\n';
outAj << t.col() << '\n';
outAv_real << t.value().real() << '\n';
outAv_imag << t.value().imag() << '\n';
}
for (const auto& t : _mTripleB_complex)
{
outBi << t.row() << '\n';
outBj << t.col() << '\n';
outBv_real << t.value().real() << '\n';
outBv_imag << t.value().imag() << '\n';
}
std::cout << "[OpticsFEM_3D_EigenFreq] exported A/B COO to " << outDir << std::endl;
}
}
/*
3D_Scatter2
prism

View File

@ -6,7 +6,7 @@
int main()
{
std::ifstream fd("sbc3d.json");
std::ifstream fd("sbc3d.json"); // FemType=4 散射;本征请改为 eigen3d.json 并编译 eigen3D 目录
if (!fd.is_open())
{
std::cout << "cannot open sbc3d.json" << std::endl;