228 lines
7.3 KiB
Python
228 lines
7.3 KiB
Python
# -*- coding: utf-8 -*-
|
||
"""Generate PPT assets for stage-3 (PBC) update."""
|
||
from __future__ import annotations
|
||
|
||
import importlib.util
|
||
import subprocess
|
||
import sys
|
||
from pathlib import Path
|
||
|
||
import matplotlib.pyplot as plt
|
||
import matplotlib.patches as mpatches
|
||
import numpy as np
|
||
|
||
ROOT = Path(__file__).resolve().parents[1]
|
||
OUT = Path(__file__).resolve().parent
|
||
SRC_OUT = ROOT / "build" / "Release" / "OutFile"
|
||
MAT_OUT = (
|
||
ROOT.parent
|
||
/ "三维matlab代码"
|
||
/ "matlab 3D一阶基+散射边界条件+单周期边界"
|
||
/ "OutFile"
|
||
)
|
||
MESH = ROOT / "build" / "Release" / "PBCmesh.dat"
|
||
PLOT_SCRIPT = ROOT / "tools" / "plot_domain_faces.py"
|
||
|
||
|
||
def _resolve_cpp_outdir() -> Path:
|
||
"""Pick C++ OutFile that matches PBCmesh vertex count, else fall back to MATLAB."""
|
||
mesh_spec = importlib.util.spec_from_file_location(
|
||
"validate_pbcmesh", ROOT / "tools" / "validate_and_fix_pbcmesh.py"
|
||
)
|
||
mesh_mod = importlib.util.module_from_spec(mesh_spec)
|
||
mesh_spec.loader.exec_module(mesh_mod)
|
||
plot_spec = importlib.util.spec_from_file_location(
|
||
"plot_domain_faces", PLOT_SCRIPT
|
||
)
|
||
plot_mod = importlib.util.module_from_spec(plot_spec)
|
||
plot_spec.loader.exec_module(plot_mod)
|
||
|
||
mesh = mesh_mod.load_mesh_dat(MESH)
|
||
n_vertex = mesh["n_vertex"]
|
||
|
||
candidates = [SRC_OUT, ROOT / "build" / "Release" / "OutFile_double"]
|
||
for cand in candidates:
|
||
normE_path = cand / "normE"
|
||
if not normE_path.exists():
|
||
continue
|
||
ne = plot_mod.load_normE(normE_path)
|
||
if ne.size == n_vertex:
|
||
print(f" [cpp] using {cand} (n={ne.size})")
|
||
return cand
|
||
|
||
print(
|
||
f" [warn] no C++ normE with {n_vertex} vertices; "
|
||
f"re-run: OpticsFEM.exe pbc3d_sbc.json in build/Release"
|
||
)
|
||
print(f" [warn] C++ panel temporarily uses MATLAB reference at {MAT_OUT}")
|
||
return MAT_OUT
|
||
|
||
|
||
def merge_pbc_faces() -> Path:
|
||
"""Plot domain 2 + 5 merged (simulation only, no MATLAB compare)."""
|
||
import shutil
|
||
|
||
out = OUT / "pbc_faces_domain2_domain5.png"
|
||
out_src = SRC_OUT / "pbc_faces_domain2_domain5.png"
|
||
cpp_out = _resolve_cpp_outdir()
|
||
|
||
cmd = [
|
||
sys.executable,
|
||
str(PLOT_SCRIPT),
|
||
"--mesh",
|
||
str(MESH),
|
||
"--outdir",
|
||
str(cpp_out),
|
||
"--domains",
|
||
"2",
|
||
"5",
|
||
"--combined",
|
||
"--no-compare",
|
||
"--output",
|
||
str(out),
|
||
]
|
||
subprocess.run(cmd, check=True, cwd=ROOT)
|
||
shutil.copy2(out, out_src)
|
||
return out
|
||
|
||
|
||
plt.rcParams["font.sans-serif"] = ["Microsoft YaHei", "SimHei", "Arial"]
|
||
plt.rcParams["axes.unicode_minus"] = False
|
||
|
||
BLUE = "#4874CB"
|
||
ORANGE = "#EE822F"
|
||
GREEN = "#75BD42"
|
||
GRAY = "#BFBFBF"
|
||
DARK = "#44546A"
|
||
LIGHT = "#E7E6E6"
|
||
|
||
|
||
def roadmap_stage_progress() -> Path:
|
||
fig, ax = plt.subplots(figsize=(11, 3.8), facecolor="white")
|
||
ax.set_xlim(0, 10)
|
||
ax.set_ylim(0, 3.8)
|
||
ax.axis("off")
|
||
|
||
stages = [
|
||
("0\n工程基础", True),
|
||
("1\n本征频率", "partial"),
|
||
("2\nPEC/ELE", True),
|
||
("3\nPBC", True),
|
||
("4\nBELE/源项", False),
|
||
("5\nPML/Port", False),
|
||
("6\n本征模式/二阶", False),
|
||
]
|
||
n = len(stages)
|
||
w = 1.15
|
||
gap = 0.18
|
||
x0 = 0.35
|
||
|
||
for i, (label, status) in enumerate(stages):
|
||
x = x0 + i * (w + gap)
|
||
if status is True:
|
||
color, edge = GREEN, "#4A7C3F"
|
||
elif status == "partial":
|
||
color, edge = ORANGE, "#C66A1A"
|
||
else:
|
||
color, edge = GRAY, "#999999"
|
||
ax.add_patch(
|
||
mpatches.FancyBboxPatch(
|
||
(x, 1.5),
|
||
w,
|
||
1.1,
|
||
boxstyle="round,pad=0.06",
|
||
facecolor=color,
|
||
edgecolor=edge,
|
||
alpha=0.92,
|
||
)
|
||
)
|
||
ax.text(x + w / 2, 2.05, label, ha="center", va="center", fontsize=9.5, weight="bold", color="white")
|
||
if i < n - 1:
|
||
ax.annotate(
|
||
"",
|
||
xy=(x + w + gap * 0.15, 2.05),
|
||
xytext=(x + w, 2.05),
|
||
arrowprops=dict(arrowstyle="->", color=DARK, lw=2),
|
||
)
|
||
|
||
ax.text(0.35, 0.55, "[完成]", fontsize=10, color=GREEN, weight="bold")
|
||
ax.text(1.5, 0.55, "[部分]", fontsize=10, color=ORANGE, weight="bold")
|
||
ax.text(2.8, 0.55, "[待做]", fontsize=10, color="#888888", weight="bold")
|
||
ax.set_title("OpticsFEM 3D 扩展分阶段进度(当前:阶段 3 完成)", fontsize=13, weight="bold", color=DARK, pad=12)
|
||
|
||
out = OUT / "roadmap_stage_progress.png"
|
||
fig.savefig(out, dpi=150, bbox_inches="tight", facecolor="white")
|
||
plt.close(fig)
|
||
return out
|
||
|
||
|
||
def pbc_validation_metrics() -> Path:
|
||
labels = ["矩阵 rel_max", "normE L2 rel", "单PBC |r|", "normE 相关系数"]
|
||
values = [1.1e-6, 1.1e-6, 3.9e-13, 1.0]
|
||
display = ["1.1e-6", "1.1e-6", "3.9e-13", "1.0"]
|
||
|
||
fig, ax = plt.subplots(figsize=(8, 4), facecolor="white")
|
||
colors = [BLUE, ORANGE, GREEN, "#30C0B4"]
|
||
bars = ax.bar(labels, values, color=colors, edgecolor=DARK, width=0.55)
|
||
ax.set_yscale("log")
|
||
ax.set_ylabel("数值(对数轴)", fontsize=11)
|
||
ax.set_title("双周期 PBC 验证指标(C++ vs MATLAB)", fontsize=12, weight="bold", color=DARK)
|
||
ax.set_ylim(1e-14, 2)
|
||
for b, txt in zip(bars, display):
|
||
ax.text(b.get_x() + b.get_width() / 2, b.get_height() * 2.5, txt, ha="center", fontsize=10, weight="bold")
|
||
ax.grid(axis="y", alpha=0.3, linestyle="--")
|
||
fig.tight_layout()
|
||
out = OUT / "pbc_validation_metrics.png"
|
||
fig.savefig(out, dpi=150, bbox_inches="tight", facecolor="white")
|
||
plt.close(fig)
|
||
return out
|
||
|
||
|
||
def module_status_stage3() -> Path:
|
||
fig, ax = plt.subplots(figsize=(10, 4.2), facecolor="white")
|
||
ax.axis("off")
|
||
cols = ["模块", "状态", "说明"]
|
||
rows = [
|
||
["体积分 + SBC", "完成", "FemType=4 散射闭环"],
|
||
["PEC/ELE(阶段2)", "完成", "Assemble_PEC_ELE,边 DOF 消元"],
|
||
["PBC 单周期(阶段3)", "完成", "singlePBC_scatter.json"],
|
||
["PBC 双周期(阶段3)", "完成", "doublePBC_scatter.json,角点合并"],
|
||
["本征 A/B 矩阵", "完成", "与 MATLAB COO 逐行一致"],
|
||
["BELE/MAG/SCD", "待做", "阶段 4"],
|
||
[".em 接口", "待做", "Design.em 适配"],
|
||
]
|
||
table = ax.table(cellText=rows, colLabels=cols, loc="center", cellLoc="center")
|
||
table.auto_set_font_size(False)
|
||
table.set_fontsize(10)
|
||
table.scale(1, 1.55)
|
||
for (r, c), cell in table.get_celld().items():
|
||
if r == 0:
|
||
cell.set_facecolor(BLUE)
|
||
cell.set_text_props(color="white", weight="bold")
|
||
else:
|
||
cell.set_facecolor(LIGHT if r % 2 == 0 else "white")
|
||
if c == 1 and rows[r - 1][1] == "完成":
|
||
cell.set_text_props(color=GREEN, weight="bold")
|
||
ax.set_title("三维拓展模块完成状态(阶段三更新)", fontsize=12, weight="bold", color=DARK, pad=18)
|
||
out = OUT / "module_status_stage3.png"
|
||
fig.savefig(out, dpi=150, bbox_inches="tight", facecolor="white")
|
||
plt.close(fig)
|
||
return out
|
||
|
||
|
||
def main() -> None:
|
||
OUT.mkdir(parents=True, exist_ok=True)
|
||
outputs = [
|
||
merge_pbc_faces(),
|
||
roadmap_stage_progress(),
|
||
pbc_validation_metrics(),
|
||
module_status_stage3(),
|
||
]
|
||
print("Generated PPT assets:")
|
||
for p in outputs:
|
||
print(f" {p}")
|
||
|
||
|
||
if __name__ == "__main__":
|
||
main()
|