1046 lines
56 KiB
Python
1046 lines
56 KiB
Python
#!/usr/bin/env python3
|
||
# -*- coding: utf-8 -*-
|
||
"""Build the AFEM group meeting PPTX deck -- Chinese version."""
|
||
|
||
from pptx import Presentation
|
||
from pptx.util import Inches, Pt, Emu, Cm
|
||
from pptx.dml.color import RGBColor
|
||
from pptx.enum.text import PP_ALIGN, MSO_ANCHOR
|
||
from pptx.enum.shapes import MSO_SHAPE
|
||
from pptx.oxml.ns import qn
|
||
|
||
# Color palette (Nature-style restrained)
|
||
WHITE = RGBColor(0xFF, 0xFF, 0xFF)
|
||
BLACK = RGBColor(0x1A, 0x1A, 0x1A)
|
||
DARK_GRAY = RGBColor(0x33, 0x33, 0x33)
|
||
BODY_GRAY = RGBColor(0x44, 0x44, 0x44)
|
||
CAPTION = RGBColor(0x88, 0x88, 0x88)
|
||
LIGHT_LINE = RGBColor(0xDD, 0xDD, 0xDD)
|
||
LIGHTER_LINE = RGBColor(0xEE, 0xEE, 0xEE)
|
||
ACCENT_BLUE = RGBColor(0x2C, 0x5F, 0x8A)
|
||
ACCENT_TEAL = RGBColor(0x3A, 0x7B, 0x7B)
|
||
ACCENT_WARM = RGBColor(0x8B, 0x45, 0x2C)
|
||
ACCENT_GREEN = RGBColor(0x3A, 0x7B, 0x4F)
|
||
HIGHLIGHT_BG = RGBColor(0xE8, 0xF0, 0xF8)
|
||
WARN_BG = RGBColor(0xFE, 0xF3, 0xE8)
|
||
TABLE_HDR = RGBColor(0xE8, 0xF0, 0xF8)
|
||
TABLE_ALT = RGBColor(0xF5, 0xF7, 0xFA)
|
||
|
||
SLIDE_W = Inches(13.333)
|
||
SLIDE_H = Inches(7.5)
|
||
|
||
TITLE_SIZE = Pt(28)
|
||
SUBHEAD_SIZE = Pt(18)
|
||
BODY_SIZE = Pt(14)
|
||
SMALL_SIZE = Pt(12)
|
||
CAPTION_SIZE = Pt(8)
|
||
TAKEAWAY_SIZE = Pt(11)
|
||
|
||
prs = Presentation()
|
||
prs.slide_width = SLIDE_W
|
||
prs.slide_height = SLIDE_H
|
||
blank_layout = prs.slide_layouts[6]
|
||
|
||
|
||
def add_blank_slide():
|
||
return prs.slides.add_slide(blank_layout)
|
||
|
||
def set_slide_bg(slide, color=WHITE):
|
||
bg = slide.background
|
||
fill = bg.fill
|
||
fill.solid()
|
||
fill.fore_color.rgb = color
|
||
|
||
def add_rect(slide, left, top, width, height, fill_color=None, line_color=None, line_width=None):
|
||
shape = slide.shapes.add_shape(MSO_SHAPE.RECTANGLE, left, top, width, height)
|
||
shape.line.fill.background()
|
||
if fill_color:
|
||
shape.fill.solid()
|
||
shape.fill.fore_color.rgb = fill_color
|
||
else:
|
||
shape.fill.background()
|
||
if line_color:
|
||
shape.line.color.rgb = line_color
|
||
shape.line.fill.solid()
|
||
if line_width:
|
||
shape.line.width = line_width
|
||
return shape
|
||
|
||
def add_textbox(slide, left, top, width, height, text="", font_size=BODY_SIZE,
|
||
font_color=BODY_GRAY, bold=False, alignment=PP_ALIGN.LEFT,
|
||
font_name='Microsoft YaHei', anchor=MSO_ANCHOR.TOP, line_spacing=1.3):
|
||
txbox = slide.shapes.add_textbox(left, top, width, height)
|
||
txbox.text_frame.word_wrap = True
|
||
tf = txbox.text_frame
|
||
tf.paragraphs[0].alignment = alignment
|
||
tf.paragraphs[0].space_before = Pt(0)
|
||
tf.paragraphs[0].space_after = Pt(0)
|
||
tf.paragraphs[0].line_spacing = line_spacing
|
||
run = tf.paragraphs[0].add_run()
|
||
run.text = text
|
||
run.font.size = font_size
|
||
run.font.color.rgb = font_color
|
||
run.font.bold = bold
|
||
run.font.name = font_name
|
||
rPr = run._r.get_or_add_rPr()
|
||
rPr.set(qn('a:eaTypeface'), font_name)
|
||
return txbox
|
||
|
||
def add_multiline_textbox(slide, left, top, width, height, lines, font_size=BODY_SIZE,
|
||
font_color=BODY_GRAY, font_name='Microsoft YaHei',
|
||
line_spacing=1.5, alignment=PP_ALIGN.LEFT):
|
||
txbox = slide.shapes.add_textbox(left, top, width, height)
|
||
txbox.text_frame.word_wrap = True
|
||
tf = txbox.text_frame
|
||
for i, line_data in enumerate(lines):
|
||
if isinstance(line_data, str):
|
||
text, is_bold, fs, clr = line_data, False, font_size, font_color
|
||
elif len(line_data) == 2:
|
||
text, is_bold = line_data
|
||
fs, clr = font_size, font_color
|
||
elif len(line_data) == 3:
|
||
text, is_bold, fs = line_data
|
||
clr = font_color
|
||
else:
|
||
text, is_bold, fs, clr = line_data
|
||
if i == 0:
|
||
p = tf.paragraphs[0]
|
||
else:
|
||
p = tf.add_paragraph()
|
||
p.alignment = alignment
|
||
p.space_before = Pt(2)
|
||
p.space_after = Pt(2)
|
||
p.line_spacing = line_spacing
|
||
run = p.add_run()
|
||
run.text = text
|
||
run.font.size = fs
|
||
run.font.color.rgb = clr
|
||
run.font.bold = is_bold
|
||
run.font.name = font_name
|
||
rPr = run._r.get_or_add_rPr()
|
||
rPr.set(qn('a:eaTypeface'), font_name)
|
||
return txbox
|
||
|
||
def add_bullet_textbox(slide, left, top, width, height, bullets, font_size=BODY_SIZE,
|
||
font_color=BODY_GRAY, font_name='Microsoft YaHei',
|
||
bullet_char="-", line_spacing=1.5):
|
||
txbox = slide.shapes.add_textbox(left, top, width, height)
|
||
txbox.text_frame.word_wrap = True
|
||
tf = txbox.text_frame
|
||
for i, bullet_text in enumerate(bullets):
|
||
if i == 0:
|
||
p = tf.paragraphs[0]
|
||
else:
|
||
p = tf.add_paragraph()
|
||
p.alignment = PP_ALIGN.LEFT
|
||
p.space_before = Pt(3)
|
||
p.space_after = Pt(3)
|
||
p.line_spacing = line_spacing
|
||
run_marker = p.add_run()
|
||
run_marker.text = f"{bullet_char} "
|
||
run_marker.font.size = font_size
|
||
run_marker.font.color.rgb = ACCENT_BLUE
|
||
run_marker.font.name = font_name
|
||
rPr = run_marker._r.get_or_add_rPr()
|
||
rPr.set(qn('a:eaTypeface'), font_name)
|
||
run_text = p.add_run()
|
||
run_text.text = bullet_text
|
||
run_text.font.size = font_size
|
||
run_text.font.color.rgb = font_color
|
||
run_text.font.name = font_name
|
||
rPr2 = run_text._r.get_or_add_rPr()
|
||
rPr2.set(qn('a:eaTypeface'), font_name)
|
||
return txbox
|
||
|
||
def add_top_bar(slide):
|
||
add_rect(slide, Inches(0), Inches(0), SLIDE_W, Pt(3), fill_color=ACCENT_BLUE)
|
||
|
||
def add_slide_number(slide, num):
|
||
add_textbox(slide, Inches(11.8), Inches(7.05), Inches(1.2), Inches(0.35),
|
||
text=str(num), font_size=Pt(9), font_color=CAPTION,
|
||
alignment=PP_ALIGN.RIGHT)
|
||
|
||
def add_source_label(slide, text, left=None, top=None):
|
||
if left is None:
|
||
left = Inches(0.6)
|
||
if top is None:
|
||
top = Inches(6.95)
|
||
add_textbox(slide, left, top, Inches(6), Inches(0.35),
|
||
text=text, font_size=CAPTION_SIZE, font_color=CAPTION)
|
||
|
||
def add_takeaway_bar(slide, text):
|
||
add_rect(slide, Inches(0.6), Inches(6.55), Inches(12.1), Inches(0.38),
|
||
fill_color=HIGHLIGHT_BG)
|
||
add_textbox(slide, Inches(0.75), Inches(6.55), Inches(11.85), Inches(0.38),
|
||
text=f">> {text}", font_size=TAKEAWAY_SIZE, font_color=ACCENT_BLUE,
|
||
bold=False, anchor=MSO_ANCHOR.MIDDLE)
|
||
|
||
def add_slide_title(slide, title_text):
|
||
add_top_bar(slide)
|
||
add_textbox(slide, Inches(0.6), Inches(0.35), Inches(12.1), Inches(0.7),
|
||
text=title_text, font_size=TITLE_SIZE, font_color=BLACK, bold=True)
|
||
add_rect(slide, Inches(0.6), Inches(1.05), Inches(1.5), Pt(2), fill_color=ACCENT_BLUE)
|
||
|
||
def add_kpi_box(slide, left, top, width, height, value, label, color=ACCENT_BLUE):
|
||
add_rect(slide, left, top, width, height, fill_color=HIGHLIGHT_BG)
|
||
add_textbox(slide, left + Inches(0.1), top + Inches(0.08), width - Inches(0.2), Inches(0.4),
|
||
text=value, font_size=Pt(22), font_color=color, bold=True,
|
||
alignment=PP_ALIGN.CENTER)
|
||
add_textbox(slide, left + Inches(0.1), top + Inches(0.5), width - Inches(0.2), Inches(0.35),
|
||
text=label, font_size=Pt(10), font_color=CAPTION,
|
||
alignment=PP_ALIGN.CENTER)
|
||
|
||
|
||
# ======================================================================
|
||
# SLIDE 1: TITLE
|
||
# ======================================================================
|
||
slide = add_blank_slide()
|
||
set_slide_bg(slide, WHITE)
|
||
add_rect(slide, Inches(0), Inches(0), SLIDE_W, Inches(0.08), fill_color=ACCENT_BLUE)
|
||
add_rect(slide, Inches(0), Inches(0), Inches(0.08), SLIDE_H, fill_color=ACCENT_BLUE)
|
||
|
||
add_textbox(slide, Inches(1.2), Inches(1.6), Inches(10.5), Inches(1.4),
|
||
text="AFEM:基于 GNN + PPO 强化学习\n的自适应网格细化方法",
|
||
font_size=Pt(38), font_color=BLACK, bold=True, line_spacing=1.3)
|
||
|
||
add_textbox(slide, Inches(1.2), Inches(3.2), Inches(10.5), Inches(0.9),
|
||
text="二维 Helmholtz 电磁散射问题的智能网格优化 -- 算法流程与创新汇总",
|
||
font_size=Pt(18), font_color=BODY_GRAY)
|
||
|
||
add_rect(slide, Inches(1.2), Inches(4.2), Inches(3.0), Pt(2), fill_color=ACCENT_BLUE)
|
||
|
||
meta_lines = [
|
||
("组会汇报 | 2025 年 5 月", False, Pt(14), CAPTION),
|
||
("", False, Pt(8), CAPTION),
|
||
("物理场景:二维 Helmholtz 方程 / 圆形介质散射体 / SBC 吸收边界", False, Pt(12), CAPTION),
|
||
("方法栈:GNN (Message Passing) / PPO / 连续尺寸场 / 残差型误差估计", False, Pt(12), CAPTION),
|
||
]
|
||
add_multiline_textbox(slide, Inches(1.2), Inches(4.5), Inches(10.5), Inches(1.6),
|
||
meta_lines, line_spacing=1.5)
|
||
add_slide_number(slide, 1)
|
||
|
||
|
||
# ======================================================================
|
||
# SLIDE 2: BACKGROUND
|
||
# ======================================================================
|
||
slide = add_blank_slide()
|
||
set_slide_bg(slide, WHITE)
|
||
add_slide_title(slide, "研究背景:为什么自适应网格细化很重要")
|
||
|
||
left_bullets = [
|
||
"Helmholtz 方程描述电磁波在介质中的散射与传播,是电磁兼容、隐身设计、天线仿真等领域的基础方程",
|
||
"有限元 (FEM) 求解精度高度依赖网格质量:网格过粗导致数值色散/污染效应;网格过密浪费计算资源",
|
||
"高频 (k >> 1) 下污染效应严重:kh > 0.5 时 FEM 解定性错误,后续误差指示子完全不可靠",
|
||
"核心挑战:如何用最少的网格单元达到目标精度?在误差大的区域加密,误差小的区域保持稀疏",
|
||
]
|
||
add_bullet_textbox(slide, Inches(0.6), Inches(1.35), Inches(6.0), Inches(3.2),
|
||
left_bullets, font_size=SMALL_SIZE)
|
||
|
||
add_rect(slide, Inches(7.2), Inches(1.35), Inches(5.5), Inches(3.2), fill_color=HIGHLIGHT_BG)
|
||
physics_lines = [
|
||
("物理方程", True, Pt(14), ACCENT_BLUE),
|
||
("", False, Pt(4), BODY_GRAY),
|
||
("nabla^2 u_scat + k^2 * eps_r * u_scat = k^2 * (1-eps_r) * u_inc", True, Pt(13), ACCENT_TEAL),
|
||
("", False, Pt(4), BODY_GRAY),
|
||
("入射波:沿 -x 方向的平面波 u_inc = exp(i*k*x)", False, Pt(11), BODY_GRAY),
|
||
("散射体:圆形介质柱(eps_r 随机采样)", False, Pt(11), BODY_GRAY),
|
||
("边界条件:SBC 吸收边界 du/dn = i*k*u", False, Pt(11), BODY_GRAY),
|
||
("计算域:可配矩形域 [Lx, Ly]", False, Pt(11), BODY_GRAY),
|
||
]
|
||
add_multiline_textbox(slide, Inches(7.4), Inches(1.5), Inches(5.1), Inches(2.8),
|
||
physics_lines, line_spacing=1.3)
|
||
|
||
kpis = [
|
||
("kh > 1.4", "高频下典型 kh 值\n(远超 0.5 安全线)", ACCENT_WARM),
|
||
("400 -> 20,000", "网格单元数变化范围\n(初始 -> 最大上限)", ACCENT_BLUE),
|
||
("[2, 20]", "训练波数 k 覆盖范围\n(涵盖中频到高频)", ACCENT_TEAL),
|
||
]
|
||
for i, (val, label, clr) in enumerate(kpis):
|
||
add_kpi_box(slide, Inches(0.6 + i * 4.2), Inches(4.95), Inches(3.8), Inches(1.1),
|
||
val, label, color=clr)
|
||
|
||
add_takeaway_bar(slide, "Helmholtz 高频求解的核心矛盾:精度 vs 效率。需要智能网格细化策略来平衡二者。")
|
||
add_source_label(slide, "参考文献:Ainsworth & Oden, A Posteriori Error Estimation in Finite Element Analysis, 2000")
|
||
add_slide_number(slide, 2)
|
||
|
||
|
||
# ======================================================================
|
||
# SLIDE 3: KNOWLEDGE GAP
|
||
# ======================================================================
|
||
slide = add_blank_slide()
|
||
set_slide_bg(slide, WHITE)
|
||
add_slide_title(slide, "知识缺口与技术瓶颈")
|
||
|
||
add_rect(slide, Inches(0.6), Inches(1.35), Inches(5.7), Inches(2.5), fill_color=None,
|
||
line_color=LIGHT_LINE, line_width=Pt(1))
|
||
add_textbox(slide, Inches(0.8), Inches(1.4), Inches(5.3), Inches(0.4),
|
||
text="传统自适应方法的局限", font_size=SUBHEAD_SIZE, font_color=ACCENT_WARM, bold=True)
|
||
trad_bullets = [
|
||
"基于误差指示子的 h-adaptivity 细化规则完全由人工设计",
|
||
"细化判据固定(如设定误差阈值),无法适应不同 PDE 的物理特征",
|
||
"SOLVE-ESTIMATE-MARK-REFINE 循环不考虑长期回报(每一步仅看当前误差)",
|
||
"无法学习特定问题的网格模式,无法迁移到新 PDE 配置",
|
||
]
|
||
add_bullet_textbox(slide, Inches(0.8), Inches(1.85), Inches(5.3), Inches(1.8),
|
||
trad_bullets, font_size=Pt(11))
|
||
|
||
add_rect(slide, Inches(7.0), Inches(1.35), Inches(5.7), Inches(2.5), fill_color=None,
|
||
line_color=ACCENT_BLUE, line_width=Pt(1.5))
|
||
add_textbox(slide, Inches(7.2), Inches(1.4), Inches(5.3), Inches(0.4),
|
||
text="本工作的目标", font_size=SUBHEAD_SIZE, font_color=ACCENT_BLUE, bold=True)
|
||
goal_bullets = [
|
||
"用强化学习 (RL) 替代人工规则,自动发现最优细化策略",
|
||
"GNN 处理变长拓扑:每个三角形单元是一个独立的 RL agent",
|
||
"连续尺寸场输出 -> 概率性元素选择 -> 非均匀自适应网格",
|
||
"物理预算约束 + 误差驱动奖励 -> 计算资源集中在物理关键区域",
|
||
]
|
||
add_bullet_textbox(slide, Inches(7.2), Inches(1.85), Inches(5.3), Inches(1.8),
|
||
goal_bullets, font_size=Pt(11), bullet_char=">")
|
||
|
||
add_textbox(slide, Inches(0.6), Inches(4.2), Inches(12.1), Inches(0.4),
|
||
text="本次汇报的核心创新(相较前序工作)", font_size=SUBHEAD_SIZE,
|
||
font_color=BLACK, bold=True)
|
||
|
||
innovations = [
|
||
("[1] 无量纲化残差误差估计", "真空波数 k 归一化残差+相位/空间特征+GVN,介质内 eta 不被压低", ACCENT_BLUE),
|
||
("[2] Score-based 连续尺寸场", "score = -x_i 纯排序 + 物理预算约束 + Reverse Dörfler 动作掩码", ACCENT_TEAL),
|
||
("[3] L2 聚合奖励设计", "sqrt(sum eta_child^2) <= eta_parent 保证 r_local >= 0,永不惩罚细化", ACCENT_GREEN),
|
||
("[4] 尺度不变性架构", "N_init x domain_area + lambda 无量纲化特征 + ln 压缩 + 前渐近区约束", ACCENT_WARM),
|
||
]
|
||
for i, (title, desc, clr) in enumerate(innovations):
|
||
y = Inches(4.7 + i * 0.6)
|
||
add_rect(slide, Inches(0.6), y, Pt(3), Inches(0.45), fill_color=clr)
|
||
add_textbox(slide, Inches(0.85), y - Inches(0.02), Inches(3.0), Inches(0.45),
|
||
text=title, font_size=Pt(13), font_color=clr, bold=True)
|
||
add_textbox(slide, Inches(3.8), y - Inches(0.02), Inches(8.7), Inches(0.45),
|
||
text=desc, font_size=Pt(11), font_color=BODY_GRAY)
|
||
|
||
add_takeaway_bar(slide, "核心思路:让网格细化的每一步都具有明确的物理语义,而非纯数据驱动的黑箱映射")
|
||
add_slide_number(slide, 3)
|
||
|
||
|
||
# ======================================================================
|
||
# SLIDE 4: SYSTEM OVERVIEW
|
||
# ======================================================================
|
||
slide = add_blank_slide()
|
||
set_slide_bg(slide, WHITE)
|
||
add_slide_title(slide, "系统架构:RL 自适应网格细化闭环管线")
|
||
|
||
stages = [
|
||
("物理问题\n采样", ACCENT_BLUE),
|
||
("初始网格\n生成", ACCENT_BLUE),
|
||
("GNN\n观测", ACCENT_TEAL),
|
||
("Actor\n动作", ACCENT_TEAL),
|
||
("尺寸场\n排序", ACCENT_WARM),
|
||
("预算\n选择", ACCENT_WARM),
|
||
("网格\n细化", ACCENT_GREEN),
|
||
("FEM\n求解", ACCENT_GREEN),
|
||
("误差\n估计", ACCENT_GREEN),
|
||
("Reward\n计算", ACCENT_GREEN),
|
||
]
|
||
|
||
y_center = Inches(2.6)
|
||
box_w = Inches(1.1)
|
||
box_h = Inches(0.85)
|
||
gap = (Inches(12.1) - box_w * 10) / 9
|
||
|
||
for i, (label, clr) in enumerate(stages):
|
||
x = Inches(0.6) + i * (box_w + gap)
|
||
add_rect(slide, x, y_center, box_w, box_h, fill_color=HIGHLIGHT_BG,
|
||
line_color=clr, line_width=Pt(1.5))
|
||
add_textbox(slide, x, y_center + Inches(0.05), box_w, box_h - Inches(0.1),
|
||
text=label, font_size=Pt(11), font_color=clr, bold=True,
|
||
alignment=PP_ALIGN.CENTER, anchor=MSO_ANCHOR.MIDDLE)
|
||
if i < len(stages) - 1:
|
||
arrow_x = x + box_w
|
||
add_textbox(slide, arrow_x, y_center + Inches(0.22), gap, Inches(0.35),
|
||
text=">", font_size=Pt(16), font_color=LIGHT_LINE, bold=True,
|
||
alignment=PP_ALIGN.CENTER)
|
||
|
||
add_textbox(slide, Inches(6.0), Inches(3.55), Inches(1.5), Inches(0.35),
|
||
text="<-- 下一轮迭代(多步 rollout)", font_size=Pt(10), font_color=ACCENT_TEAL,
|
||
alignment=PP_ALIGN.CENTER)
|
||
|
||
# RL modeling
|
||
add_textbox(slide, Inches(0.6), Inches(4.1), Inches(6.0), Inches(0.35),
|
||
text="RL 问题建模", font_size=SUBHEAD_SIZE, font_color=BLACK, bold=True)
|
||
rl_lines = [
|
||
("Agent = 每个三角形单元(数量动态变化,约 400 -> 20,000)", False, Pt(11), BODY_GRAY),
|
||
("State = GNN 节点 14 维特征(几何 + PDE 残差 + 振幅 + 相位方向 + 物理参数)", False, Pt(11), BODY_GRAY),
|
||
("Action = 1 维连续标量 x_i -> score = -x_i 排序 -> top-k 选择细化单元", False, Pt(11), BODY_GRAY),
|
||
("Reward = 零和预算审查: refined 获 r_local+0.3x(eta/mu-1)-0.06; unrefined r=0", False, Pt(11), BODY_GRAY),
|
||
]
|
||
add_multiline_textbox(slide, Inches(0.6), Inches(4.5), Inches(6.0), Inches(2.0),
|
||
rl_lines, line_spacing=1.6)
|
||
|
||
# PPO training
|
||
add_textbox(slide, Inches(7.2), Inches(4.1), Inches(5.5), Inches(0.35),
|
||
text="PPO 训练配置", font_size=SUBHEAD_SIZE, font_color=BLACK, bold=True)
|
||
train_lines = [
|
||
("双 GNN 架构:Policy / Value 各自独立 MessagePassingBase", False, Pt(11), BODY_GRAY),
|
||
("2 层消息传递 + GVN 全局虚拟节点 (注意力门控广播),inner 残差 + LayerNorm,latent_dim=64", False, Pt(11), BODY_GRAY),
|
||
("DiagGaussian 连续动作分布,log_std 可学习,clamp [-4, -1]", False, Pt(11), BODY_GRAY),
|
||
("256 步 Rollout,5 Epochs,GAE lambda=0.95,lr=3e-4,梯度裁剪 0.5", False, Pt(11), BODY_GRAY),
|
||
]
|
||
add_multiline_textbox(slide, Inches(7.2), Inches(4.5), Inches(5.5), Inches(2.0),
|
||
train_lines, line_spacing=1.6)
|
||
|
||
add_takeaway_bar(slide, "闭环 RL 管线:物理求解 -> GNN 感知 -> 策略决策 -> 网格操作 -> 误差反馈 -> 策略更新")
|
||
add_slide_number(slide, 4)
|
||
|
||
|
||
# ======================================================================
|
||
# SLIDE 5: INNOVATION 1 - Non-dimensionalized residual error
|
||
# ======================================================================
|
||
slide = add_blank_slide()
|
||
set_slide_bg(slide, WHITE)
|
||
add_slide_title(slide, "创新 [1]:无量纲化残差误差估计 -- 消除几何尺度偏差")
|
||
|
||
add_textbox(slide, Inches(0.6), Inches(1.25), Inches(5.8), Inches(0.35),
|
||
text="前序问题:原始残差包含 h_K、h_e 等几何尺度,不同区域不可直接比较", font_size=Pt(13), font_color=ACCENT_WARM)
|
||
add_textbox(slide, Inches(0.6), Inches(1.55), Inches(5.8), Inches(0.35),
|
||
text="解决方案:改用真空波数 k 归一化,介质内残差不再被 sqrt(eps_r) 压低", font_size=Pt(13), font_color=ACCENT_BLUE)
|
||
|
||
formulas = [
|
||
("内部残差 r_int",
|
||
"(h_K/k) * sqrt(V) * |k^2*eps_r*u + k^2*(eps_r-1)*u_inc|_K",
|
||
"单元内部 PDE 残差;真空波数 k 归一化;SBC 条件保留 k_local"),
|
||
("梯度跳变 r_jump",
|
||
"sqrt(1/2 * sum_{e in dK} (h_e/k) * |[[grad u * n]]|^2_e)",
|
||
"相邻单元梯度跳变;h_e/k 使细化后跳变自然衰减"),
|
||
("SBC 边界 r_sbc",
|
||
"(h_bnd/k) * |du/dn - i*k_local*u|",
|
||
"Sommerfeld 吸收边界残差,仅在边界单元非零"),
|
||
]
|
||
|
||
for i, (name, formula, desc) in enumerate(formulas):
|
||
x = Inches(0.6 + i * 4.1)
|
||
add_rect(slide, x, Inches(2.0), Inches(3.85), Inches(1.65), fill_color=HIGHLIGHT_BG)
|
||
add_textbox(slide, x + Inches(0.15), Inches(2.05), Inches(3.55), Inches(0.3),
|
||
text=name, font_size=Pt(13), font_color=ACCENT_BLUE, bold=True)
|
||
add_textbox(slide, x + Inches(0.15), Inches(2.35), Inches(3.55), Inches(0.65),
|
||
text=formula, font_size=Pt(11), font_color=BLACK)
|
||
add_textbox(slide, x + Inches(0.15), Inches(3.05), Inches(3.55), Inches(0.5),
|
||
text=desc, font_size=Pt(10), font_color=CAPTION)
|
||
|
||
add_rect(slide, Inches(0.6), Inches(3.95), Inches(12.1), Inches(0.7), fill_color=None,
|
||
line_color=ACCENT_BLUE, line_width=Pt(1.5))
|
||
add_textbox(slide, Inches(0.8), Inches(4.0), Inches(3.5), Inches(0.55),
|
||
text="逐单元误差指示子", font_size=Pt(15), font_color=BLACK, bold=True,
|
||
anchor=MSO_ANCHOR.MIDDLE)
|
||
add_textbox(slide, Inches(4.0), Inches(4.0), Inches(3.5), Inches(0.55),
|
||
text="eta_K = sqrt(r_int^2 + r_jump^2 + r_sbc^2)", font_size=Pt(15),
|
||
font_color=ACCENT_BLUE, bold=True, anchor=MSO_ANCHOR.MIDDLE)
|
||
add_textbox(slide, Inches(7.5), Inches(4.0), Inches(5.0), Inches(0.55),
|
||
text="三项均严格无量纲\n跨介质、跨频率公平可比", font_size=Pt(13),
|
||
font_color=ACCENT_GREEN, anchor=MSO_ANCHOR.MIDDLE)
|
||
|
||
add_textbox(slide, Inches(0.6), Inches(4.85), Inches(12.1), Inches(0.3),
|
||
text="量纲分析验证", font_size=SUBHEAD_SIZE, font_color=BLACK, bold=True)
|
||
da_lines = [
|
||
("k_local ~ [L]^-1, h_e ~ [L], |jump|^2 ~ [L]^-2 => h_e/k * |jump|^2 ~ [L]^2 * [L]^-2 = 1 严格无量纲", False, Pt(11), BODY_GRAY),
|
||
("GNN 输入用 log10 压缩的特征;Reward 用原始 eta_K(不经 log 压缩),两者公式一致,物理语义对齐", False, Pt(11), BODY_GRAY),
|
||
]
|
||
add_multiline_textbox(slide, Inches(0.6), Inches(5.15), Inches(12.1), Inches(0.8),
|
||
da_lines, line_spacing=1.5)
|
||
|
||
add_takeaway_bar(slide, "真空波数 k 归一化使介质内残差自然放大 ~sqrt(eps_r) 倍,为 RL agent 提供正确的介质内/外优先级信号")
|
||
add_slide_number(slide, 5)
|
||
|
||
|
||
# ======================================================================
|
||
# SLIDE 6: INNOVATION 2 - 12D enhanced input features
|
||
# ======================================================================
|
||
slide = add_blank_slide()
|
||
set_slide_bg(slide, WHITE)
|
||
add_slide_title(slide, "创新 [2]:14 维增强输入特征 -- 赋予 GNN 振幅与相位方向感知")
|
||
|
||
add_textbox(slide, Inches(0.6), Inches(1.25), Inches(12.1), Inches(0.35),
|
||
text="前序 11 维 -> 现 12 维,新增 dist_to_interface。全部尺度相关特征均以真空波长 lambda=2*pi/k 无量纲化", font_size=Pt(13), font_color=ACCENT_BLUE)
|
||
|
||
# Feature table — compact layout to avoid overflow
|
||
row_h = Inches(0.30)
|
||
table_top = Inches(1.65)
|
||
cols = [Inches(0.6), Inches(2.0), Inches(5.5), Inches(9.8)]
|
||
col_w = [Inches(1.4), Inches(3.5), Inches(4.3), Inches(3.1)]
|
||
headers = ["维度", "特征名称", "物理含义", "归一化"]
|
||
|
||
for j, (cx, hdr, w) in enumerate(zip(cols, headers, col_w)):
|
||
add_rect(slide, cx, table_top, w, row_h, fill_color=TABLE_HDR)
|
||
add_textbox(slide, cx + Inches(0.06), table_top, w - Inches(0.12), row_h,
|
||
text=hdr, font_size=Pt(9), font_color=BLACK, bold=True,
|
||
anchor=MSO_ANCHOR.MIDDLE)
|
||
|
||
features = [
|
||
("volume", "无量纲单元面积", "volume / lambda^2"),
|
||
("internal_residual", "内部残差(k_local 无量纲化 + log10)", "--"),
|
||
("gradient_jump", "梯度跳变残差(k_local 无量纲化 + log10)", "--"),
|
||
("sbc_residual", "SBC 边界残差(k_local 无量纲化 + log10)", "--"),
|
||
("element_penalty", "单元惩罚系数 lambda", "--"),
|
||
("timestep", "当前 rollout 步数", "--"),
|
||
("wave_number", "Helmholtz 波数 k", "--"),
|
||
("k_local_sqrt_vol", "k x sqrt(eps_r) x sqrt(volume)", "--"),
|
||
("is_sbc_boundary", "是否与 SBC 边界相邻 (0/1)", "--"),
|
||
("dist_to_interface", "到介质边界的带符号距离 [新增]", "sign(d)*ln(1+|d|/lambda)"),
|
||
("epsilon_r", "单元中点介电常数(内=eps_r, 外=1.0)", "--"),
|
||
("total_solution_magnitude", "散射场复数解的振幅", "--"),
|
||
]
|
||
|
||
for i, (name, meaning, norm) in enumerate(features):
|
||
y = table_top + row_h + i * row_h
|
||
bg = TABLE_ALT if i % 2 == 1 else WHITE
|
||
is_new = "[新增]" in meaning
|
||
cells = [name, meaning, norm]
|
||
for j, (cx, cell_text, w) in enumerate(zip(cols, cells, col_w)):
|
||
add_rect(slide, cx, y, w, row_h, fill_color=bg, line_color=LIGHTER_LINE, line_width=Pt(0.5))
|
||
clr = ACCENT_TEAL if is_new and j == 1 else BODY_GRAY
|
||
bld = is_new and j == 1
|
||
add_textbox(slide, cx + Inches(0.06), y, w - Inches(0.12), row_h,
|
||
text=cell_text, font_size=Pt(8), font_color=clr, bold=bld,
|
||
anchor=MSO_ANCHOR.MIDDLE)
|
||
|
||
# Edge feature note — positioned after table (table bottom = 1.65 + 0.30 + 12*0.30 = 5.55")
|
||
add_textbox(slide, Inches(0.6), Inches(5.65), Inches(12.1), Inches(0.25),
|
||
text="边特征 (1 维):euclidean_distance / lambda -- 相邻单元中点无量纲距离 | 合计:14 (节点) + 1 (边) = 15 维图特征",
|
||
font_size=Pt(9), font_color=BODY_GRAY)
|
||
|
||
add_takeaway_bar(slide, "全部与尺度相关的特征均以 lambda 做无量纲归一化;dist_to_interface 用 sign·ln(1+|d|) 对数压缩,近场线性、远场自然压缩,与残差 log10 风格统一")
|
||
add_slide_number(slide, 6)
|
||
|
||
|
||
# ======================================================================
|
||
# SLIDE 7: INNOVATION 3 - Score-based sizing field
|
||
# ======================================================================
|
||
slide = add_blank_slide()
|
||
set_slide_bg(slide, WHITE)
|
||
add_slide_title(slide, "创新 [3]:Score-based 连续尺寸场 + 物理预算约束 + 动作掩码")
|
||
|
||
add_textbox(slide, Inches(0.6), Inches(1.25), Inches(5.7), Inches(0.35),
|
||
text="前序方案:S_i = N_base x Softplus(x_i) / Softplus(0) x median_area", font_size=Pt(12), font_color=ACCENT_WARM)
|
||
add_textbox(slide, Inches(0.6), Inches(1.55), Inches(5.7), Inches(0.35),
|
||
text="--> 依赖 median_area 基准,域缩放后语义漂移 (1x1 -> 2x2 基准 x4)", font_size=Pt(10), font_color=CAPTION)
|
||
add_textbox(slide, Inches(6.9), Inches(1.25), Inches(5.6), Inches(0.35),
|
||
text="当前方案:score = -x_i 纯排序 + 物理预算约束", font_size=Pt(12), font_color=ACCENT_BLUE)
|
||
add_textbox(slide, Inches(6.9), Inches(1.55), Inches(5.6), Inches(0.35),
|
||
text="--> score 排序丢失面积语义,但获得尺度不变性", font_size=Pt(10), font_color=CAPTION)
|
||
|
||
add_rect(slide, Inches(0.6), Inches(2.1), Inches(12.1), Inches(3.1), fill_color=HIGHLIGHT_BG)
|
||
add_textbox(slide, Inches(0.8), Inches(2.15), Inches(5.0), Inches(0.3),
|
||
text="细化选择算法", font_size=Pt(14), font_color=BLACK, bold=True)
|
||
|
||
algo_steps = [
|
||
("Step 1: 物理预算",
|
||
"A_budget_i = 1/2 x (lambda_local_i / 6)^2 仅用于 N_budget 计算\nN_budget = max(N_phys, ceil(5 x N_init)) rho_min=5.0,至少 5 倍初始单元数"),
|
||
("Step 2: Score 排序",
|
||
"score = -x_i (Actor 输出标量)\nx 越小 -> 优先级越高,纯排序,不设正负门槛"),
|
||
("Step 3: 双过滤器",
|
||
"eligible = {i | area_i > V_min_safeguard AND i in Reverse_Dorfler_set}\narea_floor: 纯数值底线 (1e-10 x domain_area)\nReverse Dorfler: 能量尾部淘汰 (eps_noise=0.01, >=20% floor)"),
|
||
("Step 4: Top-k 选择",
|
||
"num = min(|eligible|, N_current//4, remaining//3) (自适应 cap, 增速 N//4)\nselected = top-k by score -> 1-to-4 切分细化"),
|
||
]
|
||
|
||
for i, (title, content) in enumerate(algo_steps):
|
||
y = Inches(2.55 + i * 0.63)
|
||
add_textbox(slide, Inches(0.9), y, Inches(2.0), Inches(0.55),
|
||
text=title, font_size=Pt(11), font_color=ACCENT_BLUE, bold=True)
|
||
add_textbox(slide, Inches(2.9), y, Inches(9.5), Inches(0.55),
|
||
text=content, font_size=Pt(10), font_color=BODY_GRAY)
|
||
|
||
add_rect(slide, Inches(0.6), Inches(5.45), Inches(12.1), Inches(0.95), fill_color=None,
|
||
line_color=ACCENT_BLUE, line_width=Pt(0.5))
|
||
add_textbox(slide, Inches(0.8), Inches(5.5), Inches(11.7), Inches(0.85),
|
||
text="为什么用 Reverse Dörfler 而非 P95 硬阈值?P95 在重尾分布下会被奇异点推至极高,一刀切屏蔽大片中等误差区域。Reverse Dörfler 基于能量累积 (L2 范数平方和),自适应于任意分布形态,剔除确认无价值的底部噪声,保留 >=20% 单元确保 Agent 选择空间。",
|
||
font_size=Pt(11), font_color=BODY_GRAY)
|
||
|
||
add_takeaway_bar(slide, "Score-based 排序 + 物理预算 + Reverse Dörfler 掩码:三层保障确保细化资源只投入到物理上需要的地方")
|
||
add_slide_number(slide, 7)
|
||
|
||
|
||
# ======================================================================
|
||
# SLIDE 8: INNOVATION 4 - L2 aggregation reward
|
||
# ======================================================================
|
||
slide = add_blank_slide()
|
||
set_slide_bg(slide, WHITE)
|
||
add_slide_title(slide, "创新 [4]:L2 聚合奖励设计 -- 保证非负,永不惩罚细化")
|
||
|
||
add_rect(slide, Inches(0.6), Inches(1.25), Inches(12.1), Inches(0.85), fill_color=HIGHLIGHT_BG)
|
||
add_textbox(slide, Inches(0.8), Inches(1.3), Inches(11.7), Inches(0.75),
|
||
text="核心洞察:对 1-to-4 切分,用 L2 聚合 sqrt(sum eta_child^2) <= eta_parent 天然成立 -- 因为平方后 int 项 1->1/4 而 jump/sbc 项 1->1。\n如果用 L1 sum,sum eta_child > eta_parent(因 jump/sbc 项不变),会导致「细化=惩罚」。L2 聚合从根本上避免了这一结构性负偏置。",
|
||
font_size=Pt(12), font_color=BLACK)
|
||
|
||
add_rect(slide, Inches(0.6), Inches(2.35), Inches(7.5), Inches(1.85), fill_color=None,
|
||
line_color=ACCENT_BLUE, line_width=Pt(1.5))
|
||
add_textbox(slide, Inches(0.8), Inches(2.4), Inches(7.1), Inches(0.3),
|
||
text="逐步奖励计算", font_size=Pt(14), font_color=BLACK, bold=True)
|
||
reward_lines = [
|
||
("r_local_i = log(eta_old_i + eps) - log( sqrt(sum_{j:M[j]=i} eta_new_j^2) + eps )", True, Pt(13), ACCENT_BLUE),
|
||
("", False, Pt(4), BODY_GRAY),
|
||
("- 纯 int 主导区: eta_parent^2 = int^2, sum eta_child^2 = int^2/4 -> r_local = log(2) = +0.69 (强正奖励)", False, Pt(11), BODY_GRAY),
|
||
("- 纯 jump/sbc 主导区: eta_parent^2 = jump^2, sum eta_child^2 = jump^2 -> r_local = 0 (中性)", False, Pt(11), BODY_GRAY),
|
||
("- 永不惩罚细化 -- 与 L1 sum 方案根本不同", False, Pt(11), BODY_GRAY),
|
||
]
|
||
add_multiline_textbox(slide, Inches(0.8), Inches(2.7), Inches(7.1), Inches(1.4),
|
||
reward_lines, line_spacing=1.35)
|
||
|
||
add_rect(slide, Inches(8.5), Inches(2.35), Inches(4.2), Inches(1.85), fill_color=WARN_BG)
|
||
add_textbox(slide, Inches(8.7), Inches(2.4), Inches(3.8), Inches(0.3),
|
||
text="epsilon_dynamic 动态截断", font_size=Pt(14), font_color=BLACK, bold=True)
|
||
ed_lines = [
|
||
("eps = max(0.05 x mean(eta_new), 1e-6)", True, Pt(11), ACCENT_WARM),
|
||
("", False, Pt(4), BODY_GRAY),
|
||
("自适应钳制,切断远场", False, Pt(11), BODY_GRAY),
|
||
("低 eta 区的 reward hacking", False, Pt(11), BODY_GRAY),
|
||
("", False, Pt(4), BODY_GRAY),
|
||
("防止 log(0) 数值爆炸,", False, Pt(11), BODY_GRAY),
|
||
("锚定当前误差分布而非", False, Pt(11), BODY_GRAY),
|
||
("固定阈值", False, Pt(11), BODY_GRAY),
|
||
]
|
||
add_multiline_textbox(slide, Inches(8.7), Inches(2.7), Inches(3.8), Inches(1.4),
|
||
ed_lines, line_spacing=1.2)
|
||
|
||
add_textbox(slide, Inches(0.6), Inches(4.45), Inches(6.0), Inches(0.3),
|
||
text="动作惩罚与元素上限", font_size=SUBHEAD_SIZE, font_color=BLACK, bold=True)
|
||
pen_lines = [
|
||
("penalty_i = lambda x (n_i-1) + (lambda_limit/N_old) x 1[达到上限], lambda=0.06, lambda_limit=10000", False, Pt(12), BODY_GRAY),
|
||
("lambda 仅为 r_local 均值的约 1/6,轻微抑制网格膨胀,不影响主要学习信号", False, Pt(11), CAPTION),
|
||
]
|
||
add_multiline_textbox(slide, Inches(0.6), Inches(4.8), Inches(6.0), Inches(0.7),
|
||
pen_lines, line_spacing=1.5)
|
||
|
||
add_textbox(slide, Inches(7.2), Inches(4.45), Inches(5.5), Inches(0.3),
|
||
text="Actor 奖励设计原则", font_size=SUBHEAD_SIZE, font_color=BLACK, bold=True)
|
||
glob_lines = [
|
||
("global_bonus 被 Helmholtz 污染误差污染", False, Pt(12), BODY_GRAY),
|
||
("E_new > E_old 可发生在正确细化后", False, Pt(11), BODY_GRAY),
|
||
("惩罚 Agent 做对的事 → 策略崩塌 (x<0→0.01)", False, Pt(11), BODY_GRAY),
|
||
("修正: global_bonus 仅诊断, 不注入 Actor reward", False, Pt(11), CAPTION),
|
||
]
|
||
add_multiline_textbox(slide, Inches(7.2), Inches(4.8), Inches(5.5), Inches(0.7),
|
||
glob_lines, line_spacing=1.5)
|
||
|
||
add_takeaway_bar(slide, "零和预算审查: 奖金 0.3*(eta/mu-1) 全场求和为零 (Doerfler 准则 RL 对偶); unrefined r=0; global_bonus 仅诊断")
|
||
add_slide_number(slide, 8)
|
||
|
||
|
||
# ======================================================================
|
||
# SLIDE 9: REWARD CALIBRATION
|
||
# ======================================================================
|
||
slide = add_blank_slide()
|
||
set_slide_bg(slide, WHITE)
|
||
add_slide_title(slide, "奖励标度校准:随机策略下各分量量级实测")
|
||
|
||
add_textbox(slide, Inches(0.6), Inches(1.25), Inches(12.1), Inches(0.35),
|
||
text="随机策略下 1,321 个 refined-parent 样本实测(score-based 尺寸场)", font_size=Pt(12), font_color=CAPTION)
|
||
|
||
kpi_data = [
|
||
("+0.364", "r_local (L2 聚合)", "局部误差改善,主体信号"),
|
||
("+0.045", "penalty (lambda=0.02)", "仅占 r_local 的约 1/8"),
|
||
("+0.069", "alpha x Delta_logE (alpha=0.2)", "全局改善信号,约 r_local/5"),
|
||
("+0.387", "净奖励 net reward", "r_local >> penalty [check]"),
|
||
]
|
||
|
||
for i, (val, label, desc) in enumerate(kpi_data):
|
||
x = Inches(0.6 + i * 3.1)
|
||
add_rect(slide, x, Inches(1.7), Inches(2.85), Inches(1.2), fill_color=HIGHLIGHT_BG)
|
||
add_textbox(slide, x + Inches(0.1), Inches(1.75), Inches(2.65), Inches(0.4),
|
||
text=val, font_size=Pt(24), font_color=ACCENT_BLUE, bold=True,
|
||
alignment=PP_ALIGN.CENTER)
|
||
add_textbox(slide, x + Inches(0.1), Inches(2.15), Inches(2.65), Inches(0.3),
|
||
text=label, font_size=Pt(11), font_color=BLACK, bold=True,
|
||
alignment=PP_ALIGN.CENTER)
|
||
add_textbox(slide, x + Inches(0.1), Inches(2.45), Inches(2.65), Inches(0.35),
|
||
text=desc, font_size=Pt(9), font_color=CAPTION,
|
||
alignment=PP_ALIGN.CENTER)
|
||
|
||
add_textbox(slide, Inches(0.6), Inches(3.2), Inches(12.1), Inches(0.3),
|
||
text="设计验证", font_size=SUBHEAD_SIZE, font_color=BLACK, bold=True)
|
||
|
||
design_checks = [
|
||
("[OK] r_local >> penalty", "局部 credit assignment 不被惩罚信号淹没,agent 能清晰感知细化 -> 误差下降的因果关系"),
|
||
("[OK] alpha x Delta_logE = r_local / 5", "全局信号提供趋势引导但不主导局部决策,避免 loss of local credit assignment"),
|
||
("[OK] r_local >= 0 保证", "L2 聚合天然保证非负,网络永远不会因细化而受到惩罚"),
|
||
]
|
||
for i, (check, detail) in enumerate(design_checks):
|
||
add_textbox(slide, Inches(0.8), Inches(3.5 + i * 0.45), Inches(2.8), Inches(0.35),
|
||
text=check, font_size=Pt(12), font_color=ACCENT_GREEN, bold=True)
|
||
add_textbox(slide, Inches(3.6), Inches(3.5 + i * 0.45), Inches(9.1), Inches(0.35),
|
||
text=detail, font_size=Pt(11), font_color=BODY_GRAY)
|
||
|
||
add_textbox(slide, Inches(0.6), Inches(5.1), Inches(12.1), Inches(0.3),
|
||
text="奖励信号链", font_size=SUBHEAD_SIZE, font_color=BLACK, bold=True)
|
||
|
||
flow_steps = [
|
||
("FEM 求解", "eta_K per element", ACCENT_BLUE),
|
||
("L2 聚合", "log(eta_old / sqrt(sum_chi^2))", ACCENT_TEAL),
|
||
("+ eps_dynamic", "截断保护", ACCENT_WARM),
|
||
("- penalty", "lambda x (n-1) 防膨胀", ACCENT_WARM),
|
||
("+ global", "alpha x Delta_logE 仅细化单元", ACCENT_GREEN),
|
||
("-> r_i", "送入 PPO GAE", ACCENT_BLUE),
|
||
]
|
||
|
||
for i, (step_name, step_desc, clr) in enumerate(flow_steps):
|
||
x = Inches(0.6 + i * 2.05)
|
||
add_rect(slide, x, Inches(5.45), Inches(1.8), Inches(0.7), fill_color=HIGHLIGHT_BG,
|
||
line_color=clr, line_width=Pt(1))
|
||
add_textbox(slide, x + Inches(0.1), Inches(5.48), Inches(1.6), Inches(0.3),
|
||
text=step_name, font_size=Pt(11), font_color=clr, bold=True,
|
||
alignment=PP_ALIGN.CENTER)
|
||
add_textbox(slide, x + Inches(0.1), Inches(5.78), Inches(1.6), Inches(0.3),
|
||
text=step_desc, font_size=Pt(9), font_color=CAPTION,
|
||
alignment=PP_ALIGN.CENTER)
|
||
if i < len(flow_steps) - 1:
|
||
add_textbox(slide, x + Inches(1.8), Inches(5.6), Inches(0.25), Inches(0.3),
|
||
text=">", font_size=Pt(14), font_color=LIGHT_LINE, bold=True,
|
||
alignment=PP_ALIGN.CENTER)
|
||
|
||
add_takeaway_bar(slide, "奖励各分量量级经过标定,满足 r_local >> penalty 且 alpha x Delta_logE 适度,agent 能学到细化 = 有益的信息")
|
||
add_slide_number(slide, 9)
|
||
|
||
|
||
# ======================================================================
|
||
# SLIDE 10: SCALE INVARIANCE
|
||
# ======================================================================
|
||
slide = add_blank_slide()
|
||
set_slide_bg(slide, WHITE)
|
||
add_slide_title(slide, "创新 [5]:尺度不变性架构 -- 从 1x1 到 2x2 的泛化")
|
||
|
||
add_textbox(slide, Inches(0.6), Inches(1.25), Inches(12.1), Inches(0.4),
|
||
text="问题:1x1 域训练 -> 2x2 域测试时,中心介质处网格未加密,远场误差显著增大", font_size=Pt(14), font_color=ACCENT_WARM)
|
||
|
||
add_textbox(slide, Inches(0.6), Inches(1.75), Inches(12.1), Inches(0.3),
|
||
text="根因分析(双重漂移)", font_size=SUBHEAD_SIZE, font_color=BLACK, bold=True)
|
||
|
||
roots = [
|
||
("N_init 不随 domain area 缩放", "4x 面积用同数量单元 -> h 2x, area 4x", "N_init *= domain_area"),
|
||
("特征绝对值漂移", "volume/edge/dist 值随 domain 线性或平方放大", "全部用 lambda 无量纲化"),
|
||
("dist 远场 OOD", "2x2 域远角 dist/lambda 可达训练域 3x", "sign·ln(1+|d|/lambda) 对数压缩"),
|
||
]
|
||
|
||
for i, (problem, cause, fix) in enumerate(roots):
|
||
x = Inches(0.6 + i * 4.1)
|
||
add_rect(slide, x, Inches(2.1), Inches(3.85), Inches(1.3), fill_color=HIGHLIGHT_BG)
|
||
add_textbox(slide, x + Inches(0.1), Inches(2.13), Inches(3.65), Inches(0.3),
|
||
text=problem, font_size=Pt(13), font_color=ACCENT_WARM, bold=True)
|
||
add_textbox(slide, x + Inches(0.1), Inches(2.45), Inches(3.65), Inches(0.4),
|
||
text=f"原因: {cause}", font_size=Pt(10), font_color=BODY_GRAY)
|
||
add_textbox(slide, x + Inches(0.1), Inches(2.85), Inches(3.65), Inches(0.4),
|
||
text=f"--> {fix}", font_size=Pt(11), font_color=ACCENT_GREEN)
|
||
|
||
add_rect(slide, Inches(0.6), Inches(3.65), Inches(7.5), Inches(2.05), fill_color=None,
|
||
line_color=ACCENT_BLUE, line_width=Pt(1))
|
||
add_textbox(slide, Inches(0.8), Inches(3.7), Inches(7.1), Inches(0.3),
|
||
text="四项联动改进 = 完整的尺度不变性", font_size=Pt(14), font_color=BLACK, bold=True)
|
||
k_mesh_lines = [
|
||
("1. N_init = N_base x (k/k_ref)^k_exponent x domain_area (exponent/k_ref 可配,保证每单位面积密度一致)", False, Pt(12), BODY_GRAY),
|
||
("2. volume -> volume / lambda^2, euclidean_distance -> euclidean_distance / lambda", False, Pt(12), BODY_GRAY),
|
||
("3. dist_to_interface -> sign(d)*ln(1+|d|/lambda) (近场线性、远场对数压缩,与 log10 残差风格一致)", False, Pt(12), BODY_GRAY),
|
||
("4. 介质区前渐近区边缘约束: 强制迭代细化至 h <= lambda_d/N (N=1.5)", False, Pt(12), BODY_GRAY),
|
||
("--> 四项联动:N_init 修 h 漂移 + lambda 归一化修特征绝对值 + tanh 修远场 OOD", False, Pt(11), CAPTION),
|
||
]
|
||
add_multiline_textbox(slide, Inches(0.8), Inches(4.0), Inches(7.1), Inches(1.5),
|
||
k_mesh_lines, line_spacing=1.3)
|
||
|
||
add_textbox(slide, Inches(8.5), Inches(3.7), Inches(4.2), Inches(0.3),
|
||
text="N_init 缩放效果示例", font_size=Pt(13), font_color=BLACK, bold=True)
|
||
k_table_lines = [
|
||
("exponent 可配: ^2 = 理论最优, ^1.5 = 工程折中", False, Pt(10), BODY_GRAY),
|
||
("N_init 始终 = COMSOL 目标的 30-50%", False, Pt(10), BODY_GRAY),
|
||
("", False, Pt(4), BODY_GRAY),
|
||
("改前: 无 domain_area 缩放", True, Pt(10), ACCENT_WARM),
|
||
("-> 换 domain size 后 N_init 不变", False, Pt(10), CAPTION),
|
||
("-> h 随 domain 缩放,特征 OOD", False, Pt(10), CAPTION),
|
||
]
|
||
add_multiline_textbox(slide, Inches(8.5), Inches(4.0), Inches(4.2), Inches(1.7),
|
||
k_table_lines, line_spacing=1.3)
|
||
|
||
add_takeaway_bar(slide, "N_init x domain_area + lambda 无量纲化 + ln 对数压缩:三项联动使模型可物理一致地泛化到任意尺寸测试域")
|
||
add_slide_number(slide, 10)
|
||
|
||
|
||
# ======================================================================
|
||
# SLIDE 11: DUAL GNN ARCHITECTURE
|
||
# ======================================================================
|
||
slide = add_blank_slide()
|
||
set_slide_bg(slide, WHITE)
|
||
add_slide_title(slide, "双 GNN 架构与 PPO 训练细节")
|
||
|
||
add_textbox(slide, Inches(0.6), Inches(1.3), Inches(12.1), Inches(0.35),
|
||
text="图观测 -> MessagePassingBase (Policy/Value 各自独立) -> Actor/Critic 头", font_size=Pt(13), font_color=BLACK, bold=True)
|
||
|
||
add_rect(slide, Inches(0.6), Inches(1.8), Inches(5.8), Inches(3.0), fill_color=HIGHLIGHT_BG)
|
||
add_textbox(slide, Inches(0.8), Inches(1.85), Inches(5.4), Inches(0.3),
|
||
text="MessagePassingBase (x2, Policy / Value 各自独立基座)", font_size=Pt(13), font_color=ACCENT_BLUE, bold=True)
|
||
|
||
gnn_items = [
|
||
("节点嵌入", "Linear(14 -> 64)"),
|
||
("边嵌入", "Linear(1 -> 64)"),
|
||
("MP Step 1", "EdgeModule: MLP([src|dst|edge_attr]) -> 64d"),
|
||
("", "NodeModule: MLP([node|scatter_mean(入边)]) -> 64d"),
|
||
("", "+ inner 残差 + LayerNorm"),
|
||
("MP Step 2", "同 Step 1,堆叠 2 层"),
|
||
("GVN 全局虚拟节点", "h_V = Σ(η_v/Ση)·h_v (η_K 加权池化)"),
|
||
("", "α = σ(W[h_v||h_V]),h_v += scale·α ⊙ W_V·h_V"),
|
||
("输出", "节点隐向量 (num_nodes, 64)"),
|
||
]
|
||
|
||
for i, (label, detail) in enumerate(gnn_items):
|
||
y = Inches(2.25 + i * 0.32)
|
||
if label:
|
||
add_textbox(slide, Inches(0.9), y, Inches(1.6), Inches(0.28),
|
||
text=label, font_size=Pt(10), font_color=ACCENT_BLUE, bold=True)
|
||
add_textbox(slide, Inches(2.5), y, Inches(3.7), Inches(0.28),
|
||
text=detail, font_size=Pt(10), font_color=BODY_GRAY)
|
||
|
||
add_rect(slide, Inches(7.0), Inches(1.8), Inches(5.7), Inches(1.4), fill_color=None,
|
||
line_color=ACCENT_TEAL, line_width=Pt(1))
|
||
add_textbox(slide, Inches(7.2), Inches(1.85), Inches(5.3), Inches(0.3),
|
||
text="Actor 头(策略网络)", font_size=Pt(13), font_color=ACCENT_TEAL, bold=True)
|
||
actor_items = [
|
||
("MLP: 2 层 Tanh (64 -> 64 -> 64)", False, Pt(11), BODY_GRAY),
|
||
("Linear(64 -> 1): 输出 x_i (连续标量)", False, Pt(11), BODY_GRAY),
|
||
("log_std: 可学习参数,初始化 -2.0 (std = 0.135)", False, Pt(11), BODY_GRAY),
|
||
("DiagGaussian(mu, sigma): 每节点独立动作分布", False, Pt(11), BODY_GRAY),
|
||
]
|
||
add_multiline_textbox(slide, Inches(7.2), Inches(2.2), Inches(5.3), Inches(0.9),
|
||
actor_items, line_spacing=1.3)
|
||
|
||
add_rect(slide, Inches(7.0), Inches(3.4), Inches(5.7), Inches(1.4), fill_color=None,
|
||
line_color=ACCENT_GREEN, line_width=Pt(1))
|
||
add_textbox(slide, Inches(7.2), Inches(3.45), Inches(5.3), Inches(0.3),
|
||
text="Critic 头(价值网络)", font_size=Pt(13), font_color=ACCENT_GREEN, bold=True)
|
||
critic_items = [
|
||
("MLP: 2 层 Tanh (64 -> 64 -> 1)", False, Pt(11), BODY_GRAY),
|
||
("输出: V_i(s) 逐节点价值 (num_agents, 1)", False, Pt(11), BODY_GRAY),
|
||
("spatial value function: 不做聚合,保持逐节点", False, Pt(11), BODY_GRAY),
|
||
("GAE 中用 scatter_add 做子->父投影,处理变长拓扑", False, Pt(11), BODY_GRAY),
|
||
]
|
||
add_multiline_textbox(slide, Inches(7.2), Inches(3.75), Inches(5.3), Inches(0.9),
|
||
critic_items, line_spacing=1.3)
|
||
|
||
add_textbox(slide, Inches(0.6), Inches(5.1), Inches(12.1), Inches(0.3),
|
||
text="PPO 关键设计", font_size=SUBHEAD_SIZE, font_color=BLACK, bold=True)
|
||
|
||
ppo_details = [
|
||
("单路 GAE", "scatter_add 将子单元值聚合回父单元,无需多路 GAE", ACCENT_BLUE),
|
||
("log_std clamp", "每步 optimizer.step() 后 clamp 到 [-4.0, -1.0],std in [0.018, 0.368]", ACCENT_TEAL),
|
||
("熵正则", "entropy_coefficient=0.001,防止 log_std 过早收敛到下限", ACCENT_GREEN),
|
||
("梯度裁剪", "max_grad_norm=0.5,稳定训练过程", ACCENT_WARM),
|
||
]
|
||
for i, (tag, desc, clr) in enumerate(ppo_details):
|
||
x = Inches(0.6 + i * 3.1)
|
||
add_rect(slide, x, Inches(5.45), Inches(2.85), Inches(0.85), fill_color=HIGHLIGHT_BG)
|
||
add_textbox(slide, x + Inches(0.1), Inches(5.5), Inches(2.65), Inches(0.3),
|
||
text=tag, font_size=Pt(13), font_color=clr, bold=True, alignment=PP_ALIGN.CENTER)
|
||
add_textbox(slide, x + Inches(0.1), Inches(5.8), Inches(2.65), Inches(0.4),
|
||
text=desc, font_size=Pt(10), font_color=BODY_GRAY, alignment=PP_ALIGN.CENTER)
|
||
|
||
add_takeaway_bar(slide, "双 GNN 各自独立建模 + DiagGaussian 连续动作 + scatter_add 单路 GAE -> 适合变长 agent 拓扑的 RL 训练框架")
|
||
add_slide_number(slide, 11)
|
||
|
||
|
||
# ======================================================================
|
||
# SLIDE 12: TRAINING OBSERVATIONS
|
||
# ======================================================================
|
||
slide = add_blank_slide()
|
||
set_slide_bg(slide, WHITE)
|
||
add_slide_title(slide, "训练观察与诊断:奖励稀疏性与大波数泛化")
|
||
|
||
add_rect(slide, Inches(0.6), Inches(1.3), Inches(5.8), Inches(2.4), fill_color=WARN_BG)
|
||
add_textbox(slide, Inches(0.8), Inches(1.35), Inches(5.4), Inches(0.35),
|
||
text="观察 1: 75% rollout 步骤零 reward", font_size=Pt(14), font_color=ACCENT_WARM, bold=True)
|
||
obs1_lines = [
|
||
("4 步 rollout 中,第 0 步细化后介质区已达标 (h/lambda = 13 > N=15 参考线)", False, Pt(11), BODY_GRAY),
|
||
("步 1-3 全为零 reward,75% 的 FEM 求解白白浪费", False, Pt(11), BODY_GRAY),
|
||
("原因: 1-to-4 切分太粗,一步即达标,不存在差一点的中间状态", False, Pt(11), BODY_GRAY),
|
||
("偶尔的 spike (reward ~60) 来自随机探索中极负的 x_i 触发第二步细化", False, Pt(11), BODY_GRAY),
|
||
("--> 步 0 的 reward 信号足够训练「在哪里细化」的判断,但多步策略无法学习", False, Pt(11), CAPTION),
|
||
]
|
||
add_multiline_textbox(slide, Inches(0.8), Inches(1.7), Inches(5.4), Inches(1.85),
|
||
obs1_lines, line_spacing=1.35)
|
||
|
||
add_rect(slide, Inches(7.0), Inches(1.3), Inches(5.7), Inches(2.4), fill_color=WARN_BG)
|
||
add_textbox(slide, Inches(7.2), Inches(1.35), Inches(5.3), Inches(0.35),
|
||
text="观察 2: 高 k 扇形阴影区网格偏粗", font_size=Pt(14), font_color=ACCENT_WARM, bold=True)
|
||
obs2_lines = [
|
||
("k in [2,20] 训练,小 k 尚可,大 k 效果不佳", False, Pt(11), BODY_GRAY),
|
||
("介质后方 +x 方向扇形区域网格偏粗,误差较大", False, Pt(11), BODY_GRAY),
|
||
("根本原因: 污染效应 -> 初始 kh > 0.5 时 FEM 解定性错误 (GIGO)", False, Pt(11), BODY_GRAY),
|
||
("粗网格 -> 错误解 -> 不可靠 eta -> 垃圾 GNN 特征 -> 垃圾动作", False, Pt(11), BODY_GRAY),
|
||
("2 层 GNN 感受野仅约 10 个单元,网络不知道自己在介质后方", False, Pt(11), BODY_GRAY),
|
||
]
|
||
add_multiline_textbox(slide, Inches(7.2), Inches(1.7), Inches(5.3), Inches(1.85),
|
||
obs2_lines, line_spacing=1.35)
|
||
|
||
add_textbox(slide, Inches(0.6), Inches(4.0), Inches(12.1), Inches(0.3),
|
||
text="训练日志解读 (k in [2,20], 随机 PDE, 4 步 rollout)", font_size=SUBHEAD_SIZE, font_color=BLACK, bold=True)
|
||
|
||
log_lines = [
|
||
("loss ~ 0.10-0.18, explained_var ~ 0.65-0.78", "Critic 对价值函数的解释力中等偏上,尚可但非极强"),
|
||
("reward 间歇性 spike (0 -> 13 -> 60 -> 0)", "随机探索 + GAE 信度传播,信号稀疏但偶尔强正奖励"),
|
||
("agent 数量在 100-3500 间大幅波动", "取决于 PDE 随机采样和细化触发情况"),
|
||
("loss/ev 趋于平台期", "可能是 k^2 与 N=15 互斥的问题(已用 k^1.5 修复)"),
|
||
]
|
||
for i, (log, interpret) in enumerate(log_lines):
|
||
add_textbox(slide, Inches(0.8), Inches(4.35 + i * 0.42), Inches(4.0), Inches(0.35),
|
||
text=log, font_size=Pt(11), font_color=ACCENT_BLUE, bold=True)
|
||
add_textbox(slide, Inches(5.0), Inches(4.35 + i * 0.42), Inches(7.7), Inches(0.35),
|
||
text=interpret, font_size=Pt(11), font_color=BODY_GRAY)
|
||
|
||
add_takeaway_bar(slide, "训练瓶颈非算法设计问题,而是物理前提 (污染效应 GIGO) 和多步细化粒度 (1-to-4 太粗) 的工程限制")
|
||
add_slide_number(slide, 12)
|
||
|
||
|
||
# ======================================================================
|
||
# SLIDE 13: INNOVATION SUMMARY
|
||
# ======================================================================
|
||
slide = add_blank_slide()
|
||
set_slide_bg(slide, WHITE)
|
||
add_slide_title(slide, "创新点汇总与可复用价值")
|
||
|
||
innovations = [
|
||
("[1]", "无量纲化\n残差误差估计",
|
||
"真空波数 k 归一化残差\n介质内 η 不再被压低\nGNN+Reward 统一使用 k 归一化",
|
||
ACCENT_BLUE),
|
||
("[2]", "Score-based\n连续尺寸场",
|
||
"score = -x_i 纯排序\n物理预算 N_budget 约束\nReverse Dörfler 双过滤器掩码",
|
||
ACCENT_TEAL),
|
||
("[3]", "L2 聚合\n奖励设计",
|
||
"sqrt(sum eta_child^2) <= eta_parent 天然成立\n永不惩罚细化 (r_local >= 0)\nint 主导区强正奖励约 +0.69",
|
||
ACCENT_GREEN),
|
||
("[4]", "尺度不变性\n架构",
|
||
"N_init x domain_area 缩放\nlambda 无量纲化全部特征\nsign·ln 对数压缩 + 前渐近区约束",
|
||
ACCENT_WARM),
|
||
("[5]", "双 GNN +\n变长拓扑 RL",
|
||
"Policy/Value 独立 GNN 基座\nscatter_add 单路 GAE\nDiagGaussian + log_std clamp",
|
||
RGBColor(0x5B, 0x3A, 0x8B)),
|
||
]
|
||
|
||
for i, (num, title, desc, clr) in enumerate(innovations):
|
||
x = Inches(0.6 + i * 2.5)
|
||
add_rect(slide, x, Inches(1.35), Inches(2.3), Inches(3.1), fill_color=HIGHLIGHT_BG)
|
||
add_rect(slide, x, Inches(1.35), Inches(2.3), Pt(3), fill_color=clr)
|
||
add_textbox(slide, x + Inches(0.15), Inches(1.5), Inches(2.0), Inches(0.7),
|
||
text=title, font_size=Pt(13), font_color=clr, bold=True,
|
||
alignment=PP_ALIGN.LEFT, line_spacing=1.2)
|
||
add_textbox(slide, x + Inches(0.15), Inches(2.3), Inches(2.0), Inches(2.0),
|
||
text=desc, font_size=Pt(10), font_color=BODY_GRAY, line_spacing=1.4)
|
||
|
||
add_textbox(slide, Inches(0.6), Inches(4.7), Inches(12.1), Inches(0.3),
|
||
text="可复用价值(超越本项目的通用方法贡献)", font_size=SUBHEAD_SIZE, font_color=BLACK, bold=True)
|
||
|
||
reuse_items = [
|
||
("L2 聚合 + 父子映射", "适用于任何分裂型变长 agent RL 场景(网格细化、树搜索、层次化决策)"),
|
||
("真空波数 k 归一化方法", "残差归一化用 k₀ 非 k_local,介质内物理信号不再被压低"),
|
||
("Score-based + 预算约束选择", "适用于资源受限的排序-选择问题:传感器部署、计算资源分配、实验设计优化"),
|
||
("Reverse Dörfler 动作掩码", "能量尾部淘汰的思想可推广到任何需要排除低信号样本的场景"),
|
||
]
|
||
for i, (tag, desc) in enumerate(reuse_items):
|
||
add_textbox(slide, Inches(0.8), Inches(5.05 + i * 0.42), Inches(2.8), Inches(0.35),
|
||
text=tag, font_size=Pt(11), font_color=ACCENT_BLUE, bold=True)
|
||
add_textbox(slide, Inches(3.7), Inches(5.05 + i * 0.42), Inches(9.0), Inches(0.35),
|
||
text=desc, font_size=Pt(11), font_color=BODY_GRAY)
|
||
|
||
add_slide_number(slide, 13)
|
||
|
||
|
||
# ======================================================================
|
||
# SLIDE 14: LIMITATIONS
|
||
# ======================================================================
|
||
slide = add_blank_slide()
|
||
set_slide_bg(slide, WHITE)
|
||
add_slide_title(slide, "局限性与未解决问题")
|
||
|
||
limitations = [
|
||
("污染效应 (GIGO: Garbage-In-Garbage-Out)",
|
||
[
|
||
"高 k 下初始 kh > 0.5 时 FEM 解定性错误,误差指示子 eta_K 完全不可靠",
|
||
"RL 无法在错误解的基础上学到正确策略 -- 这是物理前提而非算法问题",
|
||
"缓解: N_init x domaine_area 使真空始终 >= 12 单元/lambda,但高 k 下余量有限",
|
||
]),
|
||
("GNN 感受野受限",
|
||
[
|
||
"2 层消息传递,每个节点感受野仅约 10 个单元,无法感知全局几何结构",
|
||
"介质后方扇形阴影区:GNN 不知道自己在介质背后,小 k 学到的真空不需细化被错误泛化",
|
||
"需要: 更多几何上下文特征(入射波方向、与介质相对位置)或更深的 GNN",
|
||
]),
|
||
("1-to-4 切分粒度",
|
||
[
|
||
"一步细化即可达标 (每波长单元数 >= N=15 参考线),多步 rollout 中 75% 步骤零 reward",
|
||
"高 eps_r 介质区可能需要 2-3 步细化,但 PPO GAE 在 4 步序列中传播稀疏信号效率极低",
|
||
"需要: 更细粒度的切分方案(如 1-to-2 边切分)或递减的 N_per_wavelength 目标",
|
||
]),
|
||
("泛化到更多散射体配置",
|
||
[
|
||
"当前仅在单个圆形介质柱上训练;多散射体、非圆形、复杂材料的泛化未经验证",
|
||
"训练波数 [2,20] 覆盖范围有限,更高 k 需要更深的初始网格和更强的特征表达",
|
||
"需要: 更丰富的 PDE 问题分布、课程学习、域随机化策略",
|
||
]),
|
||
]
|
||
|
||
for i, (title, points) in enumerate(limitations):
|
||
x = Inches(0.6 + (i % 2) * 6.3)
|
||
y = Inches(1.3 + (i // 2) * 2.8)
|
||
add_rect(slide, x, y, Inches(5.9), Inches(2.45), fill_color=None,
|
||
line_color=LIGHT_LINE, line_width=Pt(1))
|
||
add_rect(slide, x + Pt(1), y + Pt(1), Pt(3), Inches(0.35), fill_color=ACCENT_WARM)
|
||
add_textbox(slide, x + Inches(0.2), y + Inches(0.05), Inches(5.3), Inches(0.35),
|
||
text=title, font_size=Pt(14), font_color=ACCENT_WARM, bold=True)
|
||
for j, point in enumerate(points):
|
||
add_textbox(slide, x + Inches(0.2), y + Inches(0.45 + j * 0.45), Inches(5.3), Inches(0.4),
|
||
text=f"- {point}", font_size=Pt(10), font_color=BODY_GRAY)
|
||
|
||
add_slide_number(slide, 14)
|
||
|
||
|
||
# ======================================================================
|
||
# SLIDE 15: SUMMARY & DISCUSSION
|
||
# ======================================================================
|
||
slide = add_blank_slide()
|
||
set_slide_bg(slide, WHITE)
|
||
add_top_bar(slide)
|
||
add_rect(slide, Inches(0.6), Inches(2.0), Pt(4), Inches(4.0), fill_color=ACCENT_BLUE)
|
||
|
||
add_textbox(slide, Inches(0.85), Inches(2.0), Inches(11.5), Inches(1.0),
|
||
text="总 结", font_size=Pt(36), font_color=BLACK, bold=True)
|
||
|
||
summary_points = [
|
||
"提出了一套完整的 RL 自适应网格细化框架:从物理建模、误差估计、状态表征、动作空间到奖励设计的全链路创新",
|
||
"真空波数 k 归一化残差使介质内 η 自然放大,Agent 获得正确的物理优先级信号",
|
||
"Score-based 尺寸场 + 物理预算约束 + Reverse Dörfler 掩码实现了资源感知的细化单元选择",
|
||
"L2 聚合奖励设计从数学上保证了细化奖励非负,从根本上避免了 L1 sum 的结构性负偏置",
|
||
"sign(d)*ln(1+|d|/lambda) 对数压缩 + lambda 归一化全部特征实现了域尺寸的尺度不变泛化",
|
||
]
|
||
|
||
for i, point in enumerate(summary_points):
|
||
add_textbox(slide, Inches(0.85), Inches(3.1 + i * 0.42), Inches(0.4), Inches(0.35),
|
||
text=f"{i+1}.", font_size=Pt(14), font_color=ACCENT_BLUE, bold=True)
|
||
add_textbox(slide, Inches(1.25), Inches(3.1 + i * 0.42), Inches(11.2), Inches(0.35),
|
||
text=point, font_size=Pt(13), font_color=BODY_GRAY)
|
||
|
||
add_rect(slide, Inches(0.85), Inches(5.4), Inches(11.5), Inches(0.05), fill_color=LIGHT_LINE)
|
||
add_textbox(slide, Inches(0.85), Inches(5.6), Inches(11.5), Inches(0.4),
|
||
text="讨论与后续方向", font_size=SUBHEAD_SIZE, font_color=BLACK, bold=True)
|
||
|
||
discussion_points = [
|
||
"如何处理污染效应 (GIGO)?-> 更高阶 FEM (p-refinement) + 显式 kh 特征 + 更深的初始网格",
|
||
"如何提升多步细化效率?-> 递减的 N_per_wavelength 目标 + 更细粒度切分 (1-to-2) + 课程学习",
|
||
"如何拓展到更复杂场景?-> 多散射体、三维 Helmholtz、Maxwell 方程组、时域问题",
|
||
]
|
||
|
||
for i, point in enumerate(discussion_points):
|
||
add_textbox(slide, Inches(0.85), Inches(6.05 + i * 0.35), Inches(0.35), Inches(0.3),
|
||
text=">", font_size=Pt(12), font_color=ACCENT_TEAL, bold=True)
|
||
add_textbox(slide, Inches(1.2), Inches(6.05 + i * 0.35), Inches(11.2), Inches(0.3),
|
||
text=point, font_size=Pt(12), font_color=BODY_GRAY)
|
||
|
||
add_textbox(slide, Inches(8.5), Inches(7.0), Inches(4.5), Inches(0.4),
|
||
text="谢谢!欢迎讨论。", font_size=Pt(18), font_color=ACCENT_BLUE, bold=True,
|
||
alignment=PP_ALIGN.RIGHT)
|
||
add_slide_number(slide, 15)
|
||
|
||
# Save
|
||
output_path = "/public/home/dxw/Codes/afem/output/final_presentation_cn.pptx"
|
||
prs.save(output_path)
|
||
print(f"PPTX saved to {output_path}")
|
||
print(f"Slides: {len(prs.slides)}")
|