XIAN-FEM-2026June/3D opticsfem-master/generate_summary_ppt.py

262 lines
12 KiB
Python
Raw 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.

# -*- coding: utf-8 -*-
"""
Generate work-summary PPT styled like 组会/yh -散射边界条件.pptx
Run: python generate_summary_ppt.py
"""
from pathlib import Path
import subprocess
import sys
from pptx import Presentation
from pptx.util import Pt
from pptx.enum.text import PP_ALIGN
ROOT = Path(__file__).resolve().parent
ASSETS = ROOT / "ppt_assets"
REF_PPT = Path(r"e:\组会\yh -散射边界条件.pptx")
REF_IMGS = Path(r"c:\Users\Administrator\Desktop\ppt_assets_ref")
OUT_PATH = ROOT / "OpticsFEM_2D_to_3D_Summary.pptx"
LAYOUT_TITLE_CONTENT = 11 # 5_标题和内容 — same as reference deck
def delete_all_slides(prs):
while len(prs.slides) > 0:
sld_id = prs.slides._sldIdLst[0]
r_id = sld_id.rId
prs.part.drop_rel(r_id)
del prs.slides._sldIdLst[0]
def set_title(slide, text):
if slide.shapes.title:
slide.shapes.title.text = text
def add_textbox(slide, left, top, width, height, text, size=14, bold=False):
box = slide.shapes.add_textbox(left, top, width, height)
tf = box.text_frame
tf.word_wrap = True
p = tf.paragraphs[0]
p.text = text
p.font.size = Pt(size)
p.font.bold = bold
return box
def add_bullets(slide, left, top, width, height, items, size=13):
box = slide.shapes.add_textbox(left, top, width, height)
tf = box.text_frame
tf.word_wrap = True
for i, item in enumerate(items):
p = tf.paragraphs[0] if i == 0 else tf.add_paragraph()
p.text = item
p.font.size = Pt(size)
p.space_after = Pt(6)
def add_picture(slide, path, left, top, width=None, height=None):
path = Path(path)
if not path.exists():
print(f" [warn] missing image: {path}")
return None
if width and height:
return slide.shapes.add_picture(str(path), left, top, width=width, height=height)
if width:
return slide.shapes.add_picture(str(path), left, top, width=width)
if height:
return slide.shapes.add_picture(str(path), left, top, height=height)
return slide.shapes.add_picture(str(path), left, top)
def ensure_assets():
ASSETS.mkdir(parents=True, exist_ok=True)
# charts
subprocess.run([sys.executable, str(ASSETS / "make_charts.py")], check=True, cwd=ROOT)
# normE slices if not present
mesh = ROOT / "scat3D/Release/SBCmesh.dat"
outdir = ROOT / "scat3D/Release/OutFile"
plot_script = ROOT / "tools/plot_normE_slice.py"
if mesh.exists() and (outdir / "normE").exists() and plot_script.exists():
for plane, coord, name in [("z", 0.5, "normE_z050.png"), ("z", 0, "normE_z000.png"), ("y", 0.5, "normE_y050.png")]:
out = ASSETS / name
if not out.exists():
subprocess.run([
sys.executable, str(plot_script),
"--mesh", str(mesh), "--outdir", str(outdir),
"--plane", plane, "--coord", str(coord),
"--output", str(out),
], cwd=ROOT, check=False)
def build(prs):
delete_all_slides(prs)
# emu helpers — reference deck is 13.33" wide
from pptx.util import Inches
W = prs.slide_width
# --- 1 封面仿参考第1页布局---
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_TITLE_CONTENT])
set_title(slide, "组会汇报")
add_textbox(
slide, Inches(0), Inches(2.9), W, Inches(1.6),
"OpticsFEM 二维→三维扩展工作总结\n"
"一阶 Nedelec 边元 · 散射边界条件与本征频率问题\n"
"汇报人: 时间2026年6月",
size=22, bold=False,
)
add_picture(slide, REF_IMGS / "image5.png", Inches(7.2), Inches(1.5), width=Inches(5.5))
# --- 2 背景与目标 ---
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_TITLE_CONTENT])
set_title(slide, "项目背景与目标")
add_bullets(slide, Inches(0.35), Inches(1.35), Inches(5.8), Inches(5.5), [
"原有 OpticsFEM2D 三角网格 + 一阶边元FemType 03",
"目标:扩展至 3D 四面体网格,对标 MATLAB 参考代码",
"算例SBC 立方体模型εr=1.0/1.5,λ₀=0.8 m",
"散射assembly_equ + out + inc → Ax=b",
"本征assembly_equ → A·x=λ·B·x",
"交付C++ 散射全流程 + 本征矩阵与 MATLAB 对齐",
])
add_picture(slide, REF_IMGS / "image6.png", Inches(6.3), Inches(1.6), width=Inches(6.5))
# --- 3 SBC 物理(仿参考“散射边界条件模型”)---
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_TITLE_CONTENT])
set_title(slide, "散射边界条件SBC物理模型")
add_textbox(slide, Inches(0.35), Inches(1.8), Inches(5.5), Inches(4.5),
"散射边界条件Scattering Boundary Condition\n\n"
"• 出射边界:模拟只有沿外法向传播的出射波\n"
"• 入射激励:平面波 Einc=(1,0,0)\n"
"• 体积分curl-curl k₀²ε\n"
"• C++ 实现Assemble_SBC + assembly_inc/out\n"
"• 与 MATLAB main.m 流程一致", size=14)
add_picture(slide, REF_IMGS / "image8.png", Inches(1.5), Inches(4.8), width=Inches(3.5))
add_picture(slide, REF_IMGS / "image17.png", Inches(6.0), Inches(1.5), width=Inches(6.8))
# --- 4 2D vs 3D ---
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_TITLE_CONTENT])
set_title(slide, "二维与三维扩展对照")
add_picture(slide, ASSETS / "status_table.png", Inches(0.4), Inches(1.4), width=Inches(12.0))
add_textbox(slide, Inches(0.5), Inches(5.0), Inches(12), Inches(1.2),
"新增 FemType 43D 散射)与 53D 本征);共用 Mesh_3D + SBCmesh.dat",
size=13)
# --- 5 软件架构 ---
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_TITLE_CONTENT])
set_title(slide, "软件整体架构")
add_picture(slide, ASSETS / "workflow.png", Inches(0.5), Inches(1.35), width=Inches(12.2))
add_bullets(slide, Inches(0.5), Inches(5.2), Inches(12), Inches(1.5), [
"模块mesh · material · phy · kernel · solver · post · Interface",
"构建scat3D/(散射)与 eigen3D/(本征)独立 CMake 目录",
], size=12)
# --- 6 散射方程与流程(仿参考“方程”页)---
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_TITLE_CONTENT])
set_title(slide, "三维散射问题FemType = 4")
add_picture(slide, REF_IMGS / "image3.png", Inches(0.4), Inches(1.5), width=Inches(5.5))
add_picture(slide, REF_IMGS / "image4.png", Inches(6.2), Inches(1.5), width=Inches(6.5))
add_textbox(slide, Inches(0.5), Inches(5.5), Inches(12), Inches(1.2),
"方程 A·x=b | 配置 sbc3d.json | 返回码 4 | complexsolver SparseLU",
size=13, bold=True)
# --- 7 散射数值结果 ---
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_TITLE_CONTENT])
set_title(slide, "散射仿真结果 |E| 分布")
add_picture(slide, ASSETS / "normE_z050.png", Inches(0.4), Inches(1.35), width=Inches(6.0))
add_picture(slide, ASSETS / "metrics.png", Inches(6.6), Inches(1.35), width=Inches(6.2))
add_textbox(slide, Inches(0.5), Inches(5.6), Inches(12), Inches(0.8),
"z=0.5 m 切面 | |E| min=0.72 max=1.36 V/m | 残差 |r|≈6.2×10⁻¹³",
size=13)
# --- 8 多切面对比 ---
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_TITLE_CONTENT])
set_title(slide, "散射场多切面 |E|C++ Post 输出)")
add_picture(slide, ASSETS / "normE_z000.png", Inches(0.3), Inches(1.4), width=Inches(4.0))
add_picture(slide, ASSETS / "normE_z050.png", Inches(4.5), Inches(1.4), width=Inches(4.0))
add_picture(slide, ASSETS / "normE_y050.png", Inches(8.7), Inches(1.4), width=Inches(4.0))
add_textbox(slide, Inches(0.3), Inches(1.2), Inches(4), Inches(0.3), "z = 0", size=11, bold=True)
add_textbox(slide, Inches(4.5), Inches(1.2), Inches(4), Inches(0.3), "z = 0.5 m", size=11, bold=True)
add_textbox(slide, Inches(8.7), Inches(1.2), Inches(4), Inches(0.3), "y = 0.5 m", size=11, bold=True)
add_textbox(slide, Inches(0.5), Inches(5.8), Inches(12), Inches(0.6),
"可与 COMSOL 切面对比compare/compare_normE_zslice.m", size=12)
# --- 9 本征问题 ---
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_TITLE_CONTENT])
set_title(slide, "三维本征频率问题FemType = 5")
add_bullets(slide, Inches(0.35), Inches(1.4), Inches(5.5), Inches(5.5), [
"广义本征A·x = λ·B·x",
"A = curl-curl刚度B = ε 质量矩阵",
"边界:全 PMC与 MATLAB 3D一阶本征问题2 一致)",
"C++Assemble + Test_OutputMatrix",
"导出Ai/Aj/Av、Bi/Bj/BvCOO0-based",
"求解MATLAB eigs(A,B) + get_ele 绘图",
"待接C++ Run/Post",
])
add_picture(slide, REF_IMGS / "image27.png", Inches(6.0), Inches(1.5), width=Inches(6.8))
# --- 10 本征矩阵验证 ---
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_TITLE_CONTENT])
set_title(slide, "本征矩阵组装验证C++ vs MATLAB")
add_picture(slide, ASSETS / "metrics.png", Inches(0.4), Inches(1.4), width=Inches(6.5))
add_bullets(slide, Inches(6.8), Inches(1.5), Inches(6), Inches(5), [
"Av.txt 约 1.29×10⁶ 行非零元",
"C++ OutFile 与 MATLAB OutFile 逐行一致",
"Bi/Bj/Bv 约 43632 非零(质量矩阵)",
"FemType=5 返回码5",
"下一步:接入 Solver_EigenFreq",
], size=14)
# --- 11 求解器 ---
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_TITLE_CONTENT])
set_title(slide, "求解器体系")
add_picture(slide, REF_IMGS / "image12.png", Inches(0.4), Inches(1.5), width=Inches(5.5))
add_bullets(slide, Inches(6.2), Inches(1.5), Inches(6.5), Inches(5), [
"solver/:接口层(编进 OpticsFEM.exe",
"散射interface.cpp → complexsolver.exe",
"complexsolverEigen SparseLU / BiCGSTAB",
"路径Release/complex/complexsolver.exe",
"本征 3D当前 MATLAB eigs 验证",
"优势:无需 PETScCMake 一键编译",
], size=13)
# --- 12 总结 ---
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_TITLE_CONTENT])
set_title(slide, "总结与下一步")
add_bullets(slide, Inches(0.4), Inches(1.4), Inches(6), Inches(5.5), [
"【已完成】2D→3D 一阶 Nedelec 框架扩展",
"【已完成】3D SBC 散射端到端可运行、数值可靠",
"【已完成】3D 本征 A/B 组装与 MATLAB 严格对齐",
"【待完成】本征 C++ 求解与后处理接入",
"【待完成】PBC、二阶基等扩展MATLAB 已有)",
"【待完成】Test_Main 支持命令行指定 JSON",
], size=14)
add_picture(slide, ASSETS / "normE_z050.png", Inches(6.5), Inches(1.5), width=Inches(6.0))
# --- 13 致谢 ---
slide = prs.slides.add_slide(prs.slide_layouts[LAYOUT_TITLE_CONTENT])
set_title(slide, "下一步工作")
add_textbox(
slide, Inches(1.5), Inches(2.5), Inches(10), Inches(2.5),
"1. COMSOL 数值对比出图compare 脚本)\n"
"2. FemType=5 接入 Run/Post完成 C++ 本征闭环\n"
"3. 扩展 PBC / 二阶基边界条件\n"
"4. 算例自动化与文档完善\n\n"
"谢谢!",
size=22, bold=False,
)
def main():
print("Preparing assets...")
ensure_assets()
if not REF_PPT.exists():
raise FileNotFoundError(f"Reference PPT not found: {REF_PPT}")
print(f"Loading template: {REF_PPT}")
prs = Presentation(str(REF_PPT))
build(prs)
prs.save(str(OUT_PATH))
print(f"Saved: {OUT_PATH}")
if __name__ == "__main__":
main()