diff --git "a/docs/06_TEST/TEST_02_\343\202\267\343\203\237\343\203\245\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263\345\256\237\350\241\214\350\250\230\351\214\262.md" "b/docs/06_TEST/TEST_02_\343\202\267\343\203\237\343\203\245\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263\345\256\237\350\241\214\350\250\230\351\214\262.md" index 2b3f1bc..6c868f3 100644 --- "a/docs/06_TEST/TEST_02_\343\202\267\343\203\237\343\203\245\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263\345\256\237\350\241\214\350\250\230\351\214\262.md" +++ "b/docs/06_TEST/TEST_02_\343\202\267\343\203\237\343\203\245\343\203\254\343\203\274\343\202\267\343\203\247\343\203\263\345\256\237\350\241\214\350\250\230\351\214\262.md" @@ -93,6 +93,7 @@ | `output/offaxis_led_sweep/{summary.csv,offaxis_comparison.png}`・`_placement_check/cutaway_*.png` | TEST_17 | — | — | 条件別集約 CSV/解析図(輝度マップ 2 行 + a1・重心・構造 CoV の内面積依存を軸上と重ね描き)/レンダ前 3D 確認の半割り断面 10 枚 | `scripts/build_offaxis_comparison.py`・`show_scene_cutaway.py` の出力.レンダ前 3D 確認(CLAUDE.md 必須ルール)の記録を兼ねる | | `output/led_placement_sweep/` (255 ディレクトリ) | TEST_18 | `configs/_tmp_led_placement/scene_*.yaml`(`scripts/sweep_led_placement.py` が生成.同内面積ペア 球 φ ∈ {200,270,340,500}(r ∈ {100,135,170,250}) ↔ 立方体 L ∈ {141,187,234,340} で,LED をキャビティ中心から見た極角 θ=0〜120°(13 段階)に置く位置スイープ・θ=60/90/120° の向き 3 通り(板向き+バッフル/壁法線向き+バッフル/真下向き)・θ=90° の輪に N=1〜4 灯(総光束保存)・seed 違いの再レンダ,追加実験の方位角 φ=15〜40°(立方体)と真下向き N=2/4/8 灯.材質・spp=1024・d=16 据え置き.Newton cuda_ad_rgb・mitsuba 3.7.1・`--workers 2` で 1 条件 5〜6 秒) | `configs/eval_baseline_dng_target_shape.yaml` | 配置依存の幅(θ 全域の構造 CoV max−min)は球 0.015〜0.023・立方体 0.025〜0.071.球は θ≈30° が軸上より均一(φ340: 0.0193→0.0057).対向 2 灯で構造 CoV 0.005〜0.010 と形状差が消える.真下向きはバッフル無しで板向きと同等 — [TEST_18](TEST_18_照明配置依存性の球と立方体の比較.md) 参照 | **配置依存は球が立方体の 1/2〜1/3**(仮説成立).図なし評価(`--no-figures`)なので各条件に figures/ は無い.`row.json` が条件ごとの集約行(並列・再開用) | | `output/spp_noise_sweep/` (72 ディレクトリ + `summary.csv` / `spp_summary_table.csv` / `spp_noise.png`) | TEST_19 | `configs/_tmp_spp_noise/scene_*.yaml`(`scripts/sweep_spp_noise.py` が TEST_18 の 6 条件の YAML を流用し spp と seed だけ書き換えて生成.球 φ340 軸上/θ=90°・立方体 L=234 軸上/θ=90°・球 φ500 θ=90°・立方体 L=340 θ=90° × spp 256〜8192 × seed 2.Newton GPU 0・cuda・逐次) | `configs/eval_baseline_dng_target_shape.yaml` | GPU 時間は spp に比例(1024 で 5.1 秒),固定費 0.8 秒.ノイズは 1/√spp 則に ±2% で一致.構造 CoV は 1024 で安定,画像全体 min/max は暗い条件で 2048〜4096 が必要 — [TEST_19](TEST_19_sppと計算時間ノイズ指標安定性.md) 参照 | 段階別の壁時計(`mi.render` は `dr.sync_thread` で同期)と seed 差を row.json に記録.`build_spp_noise_comparison.py` で図・表 | +| `output/spp_noise_shapes6/` (72 ディレクトリ + `summary.csv` / `spp_time_table_mean_sd.csv` / `shapes6_geometry_panel.png` / `shapes6_render_panel.png` / `geometry/`) | TEST_19 追試 | `configs/_tmp_spp_noise_shapes6/scene_*.yaml`(`sweep_spp_noise.py --set shapes6` が TEST_18 の YAML を流用.LED θ=0 で球 φ270/340/500・立方体 L=187/234/340 × spp 256〜8192 × seed 2.Newton GPU 0・cuda・逐次) | `configs/eval_baseline_dng_target_shape.yaml` | 本編と同じく GPU 時間は spp に比例(1024 で 5.0±0.4 秒),固定費 0.7 秒.標準偏差は平均の 8〜10% で,球が立方体より 15〜20% 遅い — [TEST_19](TEST_19_sppと計算時間ノイズ指標安定性.md)「追試」参照 | スライド用(6 種類の形状の平均).`build_spp_shapes6_summary.py` で表とパネル図 | | `output/led_placement_sweep_rho081/` (60 ディレクトリ + 解析出力) | TEST_18 | `configs/_tmp_led_placement_rho081/scene_*.yaml`(`sweep_led_placement.py --material calibrated --key-subset` が生成.内壁を TEST_14 の校正材質 純 diffuse ρ=0.81 に置き換えた主要 60 条件=位置スイープ ペア 1・3,多灯 N=2/4・真下向き ペア 3) | 同上 | 配置依存の幅 球 0.030 vs 立方体 0.077〜0.098.軸上は両形状とも大きく改善(旧材質の光沢が作るリングが消える)— [TEST_18](TEST_18_照明配置依存性の球と立方体の比較.md) 結果 7 | 主結論が材質に依らないことの確認.解析は `build_led_placement_comparison.py --material calibrated` | | `output/real_vs_sim/` (`sim_rho081_spp4096/`・`sim_single_{bottom,left,right}_rho081_spp4096/` + `real_vs_sim_*.{png,csv}`・`shapes_{legacy,rho081}.{png,csv}`・`bsdf_grid_vs_real.csv`) | TEST_20 | `configs/_tmp_real_vs_sim/scene_*.yaml`(`scene_baseline.yaml` の内壁を TEST_14 の校正材質 純 diffuse ρ=0.81 に置き換え,全灯と単灯 3 灯(`led_bottom/left/right_*` のみ)を spp 4096 でレンダ.Newton GPU 0・cuda) | — (`compare_real_vs_sim_metrics.py` / `compare_real_vs_sim_shapes.py` が luminance.npy と実機 DNG を同じ処理で直接比較) | 全灯の画像全体 min は実機 0.727 vs シミュ 0.787(輪帯平均は 0.873 vs 0.874 で一致).形は 4 構成とも「左上が暗い」傾きがシミュで半分,単灯のピークのずれも半分以下 — [TEST_20](TEST_20_実機とシミュの形の突き合わせと配光の検討.md) 結果 1・2 | 実機 DNG(`reference_measurement/quantitative/` 全灯・`lightsim/raw/` 単灯)とシミュを同じノイズ処理で突き合わせる基準データ.採用材質の比較は既存 `output/full_base_fix`・`output/singles_fix/` を流用 | | `output/wall_bsdf_spot/` (228 ディレクトリ + `shape_fit_a.csv` / `shape_fit_b.csv` / `wall_bsdf_heatmap.png` / `spot_fwhm.png`) | TEST_20 | `configs/_tmp_wall_bsdf_spot/scene_*.yaml`(`scripts/sweep_wall_bsdf_spot.py` がサーバ上で生成.フェーズ A: 内壁 blendbsdf の ρ ∈ {0.85, 0.81} × ω ∈ {0〜0.70} × α ∈ {0.02〜0.6} × 4 構成 = 208 条件・spp 2048.フェーズ B: 採用材質のまま LED を全光束一致の spot(FWHM 30〜120°)× 4 構成 = 20 条件・spp 4096.Newton GPU 0・cuda・`--workers 2`) | — (`build_shape_fit_comparison.py` が実機と直接比較) | ω を上げると単灯ピークは実機に届く(ω=0.15)がお椀・傾きが消え ω≥0.3 で形が崩れる.spot FWHM 45〜60° で 4 構成の差分 RMS 平均 0.034(面光源 0.036)と最良 — [TEST_20](TEST_20_実機とシミュの形の突き合わせと配光の検討.md) 結果 3・4 | 単灯ピークのずれは壁の光沢ではなく LED 配光で説明できることの根拠.図なし・`row.json` が条件ごとの記録 | @@ -157,6 +158,7 @@ | 球ロフト円形光源版レンダ・評価 (TEST_11 追補) | `$env:DRJIT_LIBLLVM_PATH = "C:\Program Files\LLVM\bin\LLVM-C.dll"; uv run sm-render --scene configs/scene_sphere_r100_loft_disk.yaml --output output/sphere_r100_loft_disk/` → `uv run sm-evaluate --image output/sphere_r100_loft_disk/luminance.npy --config configs/eval_baseline_dng_target_shape.yaml --output output/sphere_r100_loft_disk/` | | 単灯再検証レンダ・集計 (TEST_12 追補) | `$env:DRJIT_LIBLLVM_PATH = "C:\Program Files\LLVM\bin\LLVM-C.dll"; uv run sm-render --scene configs/_tmp_fix_{bottom,left,right}.yaml --output output/singles_fix/{bottom,left,right}/` → `uv run python scripts/build_singles_fix_summary.py` | | spp スイープ (TEST_19) | `uv run python scripts/sweep_spp_noise.py --prepare-only` → `uv run sm-remote push` → `uv run sm-remote run --name spp --gpu 0 --threads 16 -- python scripts/sweep_spp_noise.py` → `uv run sm-remote pull spp_noise_sweep` → `uv run python scripts/build_spp_noise_comparison.py` | +| spp スイープ追試・6 形状 (TEST_19) | `uv run python scripts/sweep_spp_noise.py --set shapes6 --prepare-only` → `uv run sm-remote push --include configs/_tmp_led_placement --include configs/_tmp_spp_noise_shapes6` → `uv run sm-remote run --name shapes6 --gpu 0 --threads 16 -- python scripts/sweep_spp_noise.py --set shapes6 --spps 256 512 1024 2048 4096 8192` → `uv run sm-remote pull spp_noise_shapes6` → `uv run python scripts/build_spp_shapes6_summary.py` | | 実機 vs シミュ 形の突き合わせ (TEST_20) | `uv run python scripts/compare_real_vs_sim_metrics.py --sim output/real_vs_sim/sim_rho081_spp4096/luminance.npy --tag rho081` → `uv run python scripts/compare_real_vs_sim_shapes.py --sim-set {legacy,rho081}` | | 壁反射特性・spot スイープ (TEST_20) | `uv run sm-remote push --only scripts` → `uv run sm-remote run --name wall --gpu 0 --threads 16 -- python scripts/sweep_wall_bsdf_spot.py --phase all --workers 2` → `uv run sm-remote pull wall_bsdf_spot` → `uv run python scripts/build_shape_fit_comparison.py` | | 照明配置スイープ (TEST_18) | `uv run sm-remote push` → `uv run sm-remote run --name place --gpu 0 --threads 16 -- python scripts/sweep_led_placement.py --workers 2` → `uv run sm-remote pull led_placement_sweep` → `uv run python scripts/build_led_placement_comparison.py`(手元で幾何だけ確認するなら `--prepare-only`) | diff --git "a/docs/06_TEST/TEST_19_spp\343\201\250\350\250\210\347\256\227\346\231\202\351\226\223\343\203\216\343\202\244\343\202\272\346\214\207\346\250\231\345\256\211\345\256\232\346\200\247.md" "b/docs/06_TEST/TEST_19_spp\343\201\250\350\250\210\347\256\227\346\231\202\351\226\223\343\203\216\343\202\244\343\202\272\346\214\207\346\250\231\345\256\211\345\256\232\346\200\247.md" index 3d5baa7..4646265 100644 --- "a/docs/06_TEST/TEST_19_spp\343\201\250\350\250\210\347\256\227\346\231\202\351\226\223\343\203\216\343\202\244\343\202\272\346\214\207\346\250\231\345\256\211\345\256\232\346\200\247.md" +++ "b/docs/06_TEST/TEST_19_spp\343\201\250\350\250\210\347\256\227\346\231\202\351\226\223\343\203\216\343\202\244\343\202\272\346\214\207\346\250\231\345\256\211\345\256\232\346\200\247.md" @@ -78,6 +78,36 @@ (TEST_18 の min の値のうち球 φ500・立方体 L=340 はその分だけ低めに出ている.順位は変わらない) - 補正なしの平滑化 min/max は spp を 32 倍にしても収束せず,補正の必要性を裏付ける +## 追試 — LED を軸上にそろえた 6 形状での計算時間 (Follow-up: Six Shapes) + +発表スライドで「6 種類の形状の平均」と書くと,上の 6 条件は実際には 4 形状 × LED 位置 2 通り +(θ=0°/90°)の混在なので説明と合わない.そこで LED を θ=0°(軸上)にそろえ,形状だけを 6 種類に +変えて計算時間を測り直した(2026-10-05). + +- 形状: 球 φ270・φ340・φ500(r=135/170/250)+ 立方体 L=187・L=234・L=340.上下で同じ内面積の組 + (TEST_18 の対応).φ は球の内径,L は立方体の一辺 [mm] +- それ以外(1 灯・板向き・バッフル付き・旧材質・512²・max_depth=16・spp 256〜8192 × seed 2・ + Newton GPU 0・逐次)は本編と同じ.72 レンダ +- `sweep_spp_noise.py --set shapes6` で実行.出力は `output/spp_noise_shapes6/`(本編の結果は上書きしない) + +平均±標準偏差(n=12=6 形状 × seed 2). + +| spp | 全体 [s] | GPU(`mi.render`)[s] | CPU 固定費 [s] | GPU の割合 | +| --- | --- | --- | --- | --- | +| 256 | 1.9±0.3 | 1.2±0.1 | 0.8±0.2 | 60% | +| 512 | 3.1±0.2 | 2.4±0.2 | 0.7±0.1 | 77% | +| 1024 | 5.7±0.5 | 5.0±0.4 | 0.7±0.1 | 88% | +| 2048 | 10.7±1.1 | 10.0±1.0 | 0.7±0.1 | 93% | +| 4096 | 20.4±1.9 | 19.7±1.9 | 0.7±0.1 | 97% | +| 8192 | 40.1±3.2 | 39.4±3.1 | 0.7±0.1 | 98% | + +- **本編の結論はそのまま成り立つ**: GPU 時間は spp に比例(1024 で 5.0 秒),固定費は 0.7〜0.8 秒で一定 +- **GPU 時間の標準偏差は平均の 8〜10%**.ばらつきのほとんどは球と立方体の差で,**球が立方体より + 15〜20% 遅い**(1024 で球 5.3〜5.5 秒・立方体 4.6〜4.7 秒).同じ形状ならサイズを変えても時間は + ほぼ変わらない(立方体 L=187〜340 で 4.58〜4.67 秒).球のメッシュの三角形が多いことが一因と考えられる(未検証) +- スライド用に 6 形状の 3D 配置図(`shapes6_geometry_panel.png`)とレンダ結果(`shapes6_render_panel.png`, + spp=8192)を 2×3 で並べた図を作った.配置図は各形状が自動で拡大されるので,サイズの違いはラベルで示す + ## 結論と推奨 (Conclusions) - **標準 spp**: 構造 CoV・方位フーリエ・重心で比べる実験は **1024** のまま(5.9 秒/条件).画像全体 @@ -122,6 +152,27 @@ 出力: `output/spp_noise_sweep/`(レンダ別 72 ディレクトリ + `summary.csv` + `spp_summary_table.csv` + `spp_noise.png`). +追試(6 形状): + +```bash +# YAML 生成(本編と同じく _tmp_led_placement が前提) +uv run python scripts/sweep_spp_noise.py --set shapes6 --prepare-only + +# サーバで実行(_tmp は push 対象外なので --include で送る) +uv run sm-remote push --include configs/_tmp_led_placement --include configs/_tmp_spp_noise_shapes6 +uv run sm-remote run --name shapes6 --gpu 0 --threads 16 -- python scripts/sweep_spp_noise.py --set shapes6 --spps 256 512 1024 2048 4096 8192 +uv run sm-remote pull spp_noise_shapes6 + +# 配置図の撮影(6 形状.c = sphere_d270 sphere_d340 sphere_d500 cube_L187 cube_L234 cube_L340) +uv run sm-visualize --scene configs/_tmp_spp_noise_shapes6/scene_${c}_th000_spp1024_s0.yaml --no-bake --style slide --screenshot output/spp_noise_shapes6/geometry/${c}.png + +# 表(平均±標準偏差)とパネル図 +uv run python scripts/build_spp_shapes6_summary.py +``` + +出力: `output/spp_noise_shapes6/`(レンダ別 72 ディレクトリ + `summary.csv` + `spp_time_table_mean_sd.csv` + +`shapes6_geometry_panel.png` + `shapes6_render_panel.png` + `geometry/`). + ## 参照 (References) - [TEST_18_照明配置依存性の球と立方体の比較](TEST_18_照明配置依存性の球と立方体の比較.md): 流用した条件と指標の定義 diff --git a/docs/PROGRESS.md b/docs/PROGRESS.md index aaaf797..49ba40e 100644 --- a/docs/PROGRESS.md +++ b/docs/PROGRESS.md @@ -107,3 +107,4 @@ - **TEST_19 spp と計算時間・ノイズ・指標の安定性 (2026-09-14)**: ユーザー発案「GPU で速くなったので spp を上げてノイズと計算時間の関係を測りたい.全体のうち GPU が何秒かも知りたい」.TEST_18 の 6 条件を spp 256〜8192 × seed 2 で回し,段階別の壁時計(`mi.render` は `dr.sync_thread` で同期)を記録した.**結果**: GPU 時間は spp に厳密に比例(1024 で 5.1 秒),CPU 側の固定費は 0.8 秒で一定(PLY 書き出し・評価・保存)=spp ≥ 1024 で 1 割以下なので CPU 側の最適化はここまで.ノイズは全条件で 1/√spp 則に ±2% で一致(レンダ側に別のノイズ源は無い.ノイズ量は生の輝度で決まり,オフ軸は軸上の 1.5 倍).構造 CoV は 1024 で安定(8192 との差 ≤0.002)だが,画像全体 min/max 比は暗い大キャビティで 1024 だと 0.01〜0.02 過小評価で 2048〜4096 で収束.補正なしの平滑化 min/max は 8192 でも収束せず,輪帯平均 min/max は spp では改善しない(方位平均の問題).**推奨**: 構造 CoV の実験は 1024 のまま,min/max 比を暗い条件まで比べるなら 2048〜4096.**失敗パターン**: ① `--only scripts` の push では新しい src モジュール(fullimage.py)が無くて落ちた → 全体を push / ② サンプラー再起動の `pkill -f` が自分自身を殺して nvidia-smi の記録が残らなかった(結論には影響なし).16384 はユーザー都合で未実施. - [x] **TEST_20 実機とシミュの形の突き合わせと配光の検討 — 単灯ピークのずれは壁の光沢ではなく LED 配光で説明できる (2026-09-15)**: 実機を作る前にシミュが ISO 基準(min ≥ 0.9)の参考になるかを確かめるため,実機 DNG(全灯 1 枚・単灯 3 枚)とシミュを**同じノイズ処理**(メディアン→ガウス→平均正規化,画像全体 min はノイズ補正付き)で突き合わせた.評価の決め手は min 等の集約指標ではなく**輝度マップの形(全灯 + 単灯 3 灯)**とした(ユーザー方針).**結果 ①**: 同心円方向(お椀・20 分割プロファイル)は TEST_14 の ρ≈0.81 で最大差 0.011 とよく合い,輪帯平均の min は 0.001 差.しかし画像全体の min はシミュが 0.06 高い=実機の方位方向の非対称(上が暗い・左右 6%)をシミュが半分しか出さないため.TEST_14 のグリッド 59 条件を当てても ω・α では埋まらない(ρ を下げるとお椀が深くなるだけ).**結果 ②**: 4 構成すべてで差分は「左上が暗く右下が明るい」対角の傾き(実機 8〜12% vs シミュ 3〜5%),単灯の明部が点灯基板の反対側へ寄る量は向きは合うが実機の半分以下(左 +0.65 vs +0.25,右 −1.00 vs −0.28).右単灯だけはほぼ一致.**結果 ③(壁 ω・α スイープ 208 条件)**: ω を上げると単灯ピークは ω=0.15 で実機に届くが,同時にお椀と傾きが消えて形全体は崩れる(ω≥0.3 で差分 RMS 1.4〜2 倍).α は ω≥0.3 でしか効かない.ω・α では「ピークのずれ」と「お椀・傾き」を同時に合わせられない.**結果 ④(spot 配光 20 条件)**: 採用材質のまま LED を全光束一致の spot にして FWHM を狭めると単灯ピークが実機に近づき(30° で左が一致),傾きも実機側へ寄る.**FWHM 45〜60° が全体のバランス点**(差分 RMS 平均 0.034 vs 面光源 0.036)で,新しい基準候補は「採用材質 ρ=0.85・ω=0.05・α=0.1 + spot 45〜60°」.**未解決**: 全構成に共通する左上暗の傾きはどの設定でも半分しか出ない.下・左基板で大きく右で小さいので基板の位置・向き(または出力差)が第一候補.次は spot 45〜60° で基板の向き・位置を振る.**方法論の学び**: min だけで材質を選ぶと ρ を下げて帳尻を合わせる誤りに陥る.形で見ることで「材質で合う成分(お椀)」と「光源・幾何で合わせる成分(方位)」を分離できた.単灯 3 灯は方位方向の診断に必須.**失敗パターン**: ① `--only scripts` の push では新規 src が無い(TEST_19 と同じ)/ ② `configs/_tmp_*` は push 対象外なのでスイープ用 YAML はサーバ上で生成する設計にした / ③ 同名ジョブのログは追記なので `grep exit` の待ち合わせが旧 run に当たる.成果物: `output/real_vs_sim/`・`output/wall_bsdf_spot/`,`scripts/compare_real_vs_sim_{metrics,shapes}.py`・`sweep_wall_bsdf_spot.py`・`build_shape_fit_comparison.py`,記録 [TEST_20](06_TEST/TEST_20_実機とシミュの形の突き合わせと配光の検討.md). +- **TEST_19 追試: LED を軸上にそろえた 6 形状での計算時間 (2026-10-05)**: 発表スライドへの指摘「形状を 6 種類に増やした理由と 6 種類の形状の画像」を受けた追試.本編の 6 条件は 4 形状 × LED 位置 2 通りの混在で「6 種類の形状」と説明できないため,LED を θ=0 にそろえて球 φ270/340/500・立方体 L=187/234/340 で spp 256〜8192 × seed 2 を測り直した(`sweep_spp_noise.py --set shapes6`,出力は `output/spp_noise_shapes6/` で本編は上書きしない).**結果**: 本編と同じく GPU 時間は spp に比例(1024 で 5.0±0.4 秒),固定費 0.7 秒.標準偏差は平均の 8〜10% で,その大半は球が立方体より 15〜20% 遅いことによる(同形状ならサイズでほぼ変わらない).スライド用に表(平均±標準偏差)と 6 形状の配置図・レンダのパネル図を `build_spp_shapes6_summary.py` で作成.**失敗パターン**: `sm-remote push` の `--include` は 1 つずつ指定する(2 つ並べると引数エラー).`push ... | tail && run` だとパイプの終了コードが tail のものになり,push 失敗のまま run が走る.記録 [TEST_19](06_TEST/TEST_19_sppと計算時間ノイズ指標安定性.md)「追試」. diff --git a/scripts/build_spp_shapes6_summary.py b/scripts/build_spp_shapes6_summary.py new file mode 100644 index 0000000..8eabfbc --- /dev/null +++ b/scripts/build_spp_shapes6_summary.py @@ -0,0 +1,89 @@ +"""spp スイープ追試(--set shapes6)の計算時間表と 6 形状のパネル図を作る(TEST_19 追試). + +入力: + output/spp_noise_shapes6/summary.csv sweep_spp_noise.py --set shapes6 の集約 + output/spp_noise_shapes6/<条件>_spp8192_s0/render.png + output/spp_noise_shapes6/geometry/<形状>.png sm-visualize --no-bake --style slide の撮影 +出力: + spp_time_table_mean_sd.csv spp ごとの平均±標準偏差(n = 6 形状 × seed 2) + shapes6_geometry_panel.png 6 形状の 3D 配置図(2×3) + shapes6_render_panel.png 6 形状のレンダ結果(spp=8192,2×3) + +実行方法: + uv run python scripts/build_spp_shapes6_summary.py +""" + +from __future__ import annotations + +from pathlib import Path + +import matplotlib.pyplot as plt +import pandas as pd + +ROOT = Path(__file__).resolve().parents[1] +BASE = ROOT / "output" / "spp_noise_shapes6" + +# (条件名, 形状名, 表示ラベル).上段が球,下段が同じ内面積の立方体 +SHAPES = [ + ("sphere_d270_th000", "sphere_d270", "球 φ270"), + ("sphere_d340_th000", "sphere_d340", "球 φ340"), + ("sphere_d500_th000", "sphere_d500", "球 φ500"), + ("cube_L187_th000", "cube_L187", "立方体 L=187"), + ("cube_L234_th000", "cube_L234", "立方体 L=234"), + ("cube_L340_th000", "cube_L340", "立方体 L=340"), +] + + +def write_table() -> pd.DataFrame: + """spp ごとの計算時間(平均±標準偏差)を CSV に書く.""" + d = pd.read_csv(BASE / "summary.csv") + d["t_fixed"] = d.t_total - d.t_render + rows = [] + for spp, x in d.groupby("spp"): + rows.append({ + "spp": spp, + "n": len(x), + "合計時間[s]": f"{x.t_total.mean():.1f}±{x.t_total.std():.1f}", + "GPU処理[s]": f"{x.t_render.mean():.1f}±{x.t_render.std():.1f}", + "CPU処理[s]": f"{x.t_fixed.mean():.1f}±{x.t_fixed.std():.1f}", + "GPU処理の割合[%]": f"{100 * x.t_render.mean() / x.t_total.mean():.0f}", + "GPU SD/平均[%]": f"{100 * x.t_render.std() / x.t_render.mean():.0f}", + }) + table = pd.DataFrame(rows) + table.to_csv(BASE / "spp_time_table_mean_sd.csv", index=False, encoding="utf-8-sig") + print(table.to_string(index=False)) + print() + print(d.groupby(["condition", "spp"]).t_render.mean().unstack().round(2)) + return table + + +def draw_panel(images: list[Path], out_path: Path, crop: bool) -> None: + """6 枚の画像を 2×3 に並べてラベルを付ける.""" + fig, axes = plt.subplots(2, 3, figsize=(10, 7)) + for ax, image, (_, _, label) in zip(axes.ravel(), images, SHAPES, strict=True): + img = plt.imread(image) + if crop: + # sm-visualize のスクリーンショットは左右の余白が広いので切り詰める + h, w = img.shape[:2] + img = img[int(h * 0.05):int(h * 0.97), int(w * 0.15):int(w * 0.85)] + ax.imshow(img) + ax.set_title(label, fontsize=16) + ax.axis("off") + fig.tight_layout() + fig.savefig(out_path, dpi=200) + plt.close(fig) + print("saved", out_path) + + +def main() -> None: + """表と 2 枚のパネル図を作る.""" + plt.rcParams["font.family"] = ["Yu Gothic", "Meiryo", "sans-serif"] + write_table() + draw_panel([BASE / f"{cond}_spp8192_s0" / "render.png" for cond, _, _ in SHAPES], + BASE / "shapes6_render_panel.png", crop=False) + draw_panel([BASE / "geometry" / f"{shape}.png" for _, shape, _ in SHAPES], + BASE / "shapes6_geometry_panel.png", crop=True) + + +if __name__ == "__main__": + main() diff --git a/scripts/sweep_spp_noise.py b/scripts/sweep_spp_noise.py index 8af4d4f..8b10ac3 100644 --- a/scripts/sweep_spp_noise.py +++ b/scripts/sweep_spp_noise.py @@ -17,6 +17,9 @@ (ノイズ補正あり / なし)・ノイズ場の極値 - 併走する nvidia-smi のサンプリング(sm-remote run の外で回す)は解析側で突き合わせる +--set shapes6(スライド用の追試): LED を軸上(θ=0)にそろえ,形状だけを 6 種類にする + 球 φ270/340/500(r=135/170/250)+ 立方体 L=187/234/340.出力は output/spp_noise_shapes6/ + 実行方法: uv run python scripts/sweep_spp_noise.py --prepare-only uv run sm-remote run --name spp --gpu 0 --threads 16 -- python scripts/sweep_spp_noise.py @@ -64,6 +67,15 @@ ("sphere_d500_th090", "sphere_r250_th090_board_n1"), ("cube_L340_th090", "cube_L340_th090_board_n1"), ] +# --set shapes6: LED 位置を θ=0 にそろえ形状だけを変える 6 条件 +CONDITIONS_SHAPES6 = [ + ("sphere_d270_th000", "sphere_r135_th000_board_n1"), + ("sphere_d340_th000", "sphere_r170_th000_board_n1"), + ("sphere_d500_th000", "sphere_r250_th000_board_n1"), + ("cube_L187_th000", "cube_L187_th000_board_n1"), + ("cube_L234_th000", "cube_L234_th000_board_n1"), + ("cube_L340_th000", "cube_L340_th000_board_n1"), +] SPPS = [256, 512, 1024, 2048, 4096, 8192, 16384] SEEDS = [0, 1] @@ -244,7 +256,14 @@ parser.add_argument("--prepare-only", action="store_true", help="YAML の生成だけ行う") parser.add_argument("--spps", type=int, nargs="*", default=None, help="実行する spp を絞る") parser.add_argument("--conditions", nargs="*", default=None, help="実行する条件名を絞る") + parser.add_argument("--set", choices=["default", "shapes6"], default="default", + help="条件セット(shapes6: θ=0 で形状 6 種類.出力先も別)") args = parser.parse_args() + if args.set == "shapes6": + global CONDITIONS, TMP_DIR, OUTPUT_BASE + CONDITIONS = CONDITIONS_SHAPES6 + TMP_DIR = ROOT / "configs" / "_tmp_spp_noise_shapes6" + OUTPUT_BASE = ROOT / "output" / "spp_noise_shapes6" log_path = ROOT / "output" / "_sweep_spp_noise.log" log_path.parent.mkdir(parents=True, exist_ok=True)