Passenger Bird

Optuna-for-vexis v1.0 を読む: CAD可否ゲート付きCAE最適化パイプラインの実装

Optuna-for-vexis v1.0 の実装を、RunnerからFreeCAD/VEXIS連携、失敗ハンドリング、レポート出力までコードベースで解説。

#CAE #Optuna #FreeCAD #VEXIS #設計最適化 #Python

はじめに

このリポジトリの v1.0 ラインは、単なる「Optunaでパラメータ探索」ではなく、CADの成立判定CAE実行の不安定さ対策を最初から組み込んだ構成になっています。

この記事では、scripts/run_v1.pysrc/v1 の実装を追いながら、次の点を解説します。

  • どうやって「無駄試行」を減らしているか
  • FreeCAD/VEXIS をどう安全に回しているか
  • 失敗時にどこまで情報を残して再現可能にしているか

まず何を最適化しているのか

config/v1_0_limitations.yaml では、20次元の設計変数(例: CROWN-D-L, SHOULDER-ANGLE-OUT, HEIGHT)が定義されています。
config/optimizer_config.yaml の既定は多目的最適化で、ターゲット値付きの特徴量最適化です。

  • 目的: click_ratio, peak_force のターゲット誤差を最小化
  • 制約ドメイン: physical(実寸)指定に対応
  • 離散化: 角度と非角度で刻みを分離(既定: 0.001 / 0.01

ここで重要なのは、設定ファイルは実寸系、内部計算は比率系という切り分けです。

全体アーキテクチャ

実装上の流れはおおむね次です。

runner -> search_space -> objective -> (cad_gate + geometry_adapter + cae_evaluator) -> persistence/reporting

主な責務は以下です。

  • src/v1/runner.py
    • 設定読み込み、サンプラー組み立て、Optuna study 実行
  • src/v1/search_space.py
    • 離散化込みの探索空間生成
    • FeasibilityAwareSampler で事前リジェクト
  • src/v1/objective.py
    • 制約違反 / CAD不成立 / CAE失敗を統一的に処理
  • src/v1/geometry_adapter.py
    • FreeCADサブプロセスでSTEP生成
  • src/v1/cae_evaluator.py
    • VEXIS実行監視、CSV読込、メトリクス算出
  • src/v1/persistence.py, src/v1/reporting.py
    • trial JSON、summary、Markdownレポート生成

実行入口と設定の分離

実行コマンドはシンプルです。

python scripts/run_v1.py \
  --config config/optimizer_config.yaml \
  --limits config/v1_0_limitations.yaml

run_v1.pysrc/v1 を動的ロードして v1.runner.main() を呼び出します。
CLIでは --max-trials, --dry-run, --resume, --version も利用可能です。

設定ファイルを2枚に分けているのも実用的です。

  • optimizer_config.yaml: サンプラー、目的、ログ、パス
  • v1_0_limitations.yaml: FreeCAD制約、CADゲート、CAE監視、ペナルティ

この分離のおかげで、探索戦略だけ替える実験と、形状制約だけ替える実験を独立して回せます。

キモ1: 可行性を「学習」と「事前リジェクト」で二重に効かせる

この実装の肝は、可行性情報を2系統で使う点です。

  1. constraints_func でサンプラーに可行境界を学習させる
  2. FeasibilityAwareSampler で不成立点を提案段階で弾く

objective 側は各trialで trial.user_attrs["v1_0_feasibility_violation"] を記録します。
search_space.make_constraints_func() はその値を読み、TPE/NSGA系の可行性バイアスに使います。

さらに FeasibilityAwareSampler は、MLゲート予測で不成立なら再サンプリングします(rejection_max_retries 既定 50)。
リトライが尽きたときも、候補を返して penalty 記録へ進む設計です。

キモ2: 実寸ベースで定義しつつ、内部は比率+格子で安定化

freecad.constraints_domain: physical の場合、runnerbase_value で割って比率へ変換します。
さらに normalize_bounds_to_sampling_grid() で境界をサンプリング格子に揃え、境界ノイズによる不整合を抑えます。

search_space.py の実装では次を丁寧に扱っています。

  • 物理刻みを角度/非角度で分ける
  • Optunaの離散範囲判定(Decimal由来)に通るよう正規化
  • 物理値への逆変換時も刻みへスナップ

このあたりは tests/v1/test_physical_discretization.pytests/v1/test_constraints_lattice.py で検証されています。

キモ3: FreeCADは別Pythonで回す

geometry_adapter.py は FreeCAD処理を専用プロセスに分離しています。
理由はシンプルで、ABIや依存衝突で最適化本体を巻き込まないためです。

実処理は freecad_worker.py 側で行います。

  • FCStdを開く
  • スケッチ制約へ ratio を適用(実寸化+離散化付き)
  • 再計算とサーフェス妥当性チェック
  • STEP書き出し

失敗時は GeometryError を返し、objective 側で cad_infeasible penalty に落とします。

キモ4: VEXIS実行は「進捗監視つき」

cae_evaluator.py は VEXISログを逐次読みながら、進捗と異常を監視します。

  • solverログ開始待ちタイムアウト
  • 進捗停滞タイムアウト
  • ハードタイムアウト
  • エラーマーカー検出(例: ERROR TERMINATION, FATAL ERROR

また、vexis/input の既存STEPをいったん退避し、当該trialのSTEPだけを投入する実装になっています。
これで「他ファイルを拾って別ジョブを回す」事故を防いでいます。

キモ5: 失敗を握りつぶさず、失敗理由ごとに保存

objective.py は失敗ステージを明示して user_attrs に残します。

  • hard_constraint
  • cad_gate
  • geometry_generation
  • cae_evaluation

ペナルティは constraints.penalty_value() で計算されます。

penalty = weight * (base_penalty + alpha * distance_from_bounds)

これにより、単に「失敗した」ではなく、どこで落ちたかを後から集計できます。

出力と可観測性

1回の実行で主に次が出ます。

  • output/trials/trial_<id>/trial_info.json
  • output/summary_v1_0.json
  • output/report_v1_0.md
  • output/report_assets/*.png(履歴、2目的ならPareto)

report_v1_0.md は「実寸パラメータ列」付きのイテレーション表を生成するため、設計レビューにもそのまま使えます。

このリポジトリ内の実行ログから見えること

output 配下のログを見ると、挙動の傾向がはっきり出ています。

  • output/e2e_v1_10success_20260214_025051/report_v1_0.md
    • CAE成功 10 / 10
    • Sampler: RANDOM
    • CAD gate: disabled
  • output/report_v1_0.md(2026-02-17生成)
    • CAE成功 1 / 20
    • 失敗理由: ml_infeasible 多数 + solver progress stall

つまり、実運用で効くのは次の調整です。

  • CADゲートの閾値と学習データの整合
  • solver監視閾値(stall/hard timeout)の現実的な設定
  • 探索空間(20次元)の絞り込み

まとめ

optuna-for-vexis v1.0 は、Optunaの探索部分だけでなく、CAD/CAE実務で発生する失敗を前提に組んだ最適化基盤になっています。

  • 可行性学習 + 事前リジェクトで試行効率を上げる
  • FreeCAD/VEXISは分離実行で壊れ方を局所化する
  • trial単位で失敗理由を残し、次の改善に繋げる

「理論上は回る」ではなく「長時間バッチでも壊れにくい」方向に寄せた実装として、実務向けの参考になるコードだと感じます。