お客様からよくある声
光学設計ソフトウェア「Ansys Zemax OpticStudio」(以下、Zemax)には
「CODEV Converter」というデータ変換機能が標準搭載されており、
レンズデータをCODEV(※)形式に変換できます。
(※光学設計ソフトウェア「CODEV」を指します(以下、CODEV))
しかし実際に使ってみると、
- 材料名(ガラス名)がZemaxとCODE Vで微妙に異なる
- その結果、変換途中でエラーが出て止まってしまう
といったトラブルに悩まれるお客様が多いのが実情です。
そこで今回、ZemaxとCODEVの材料名を事前に突合し、
不一致をリストアップするPythonスクリプトを作ってみました。
このスクリプトを使えば、変換前にどの材料名が
「完全一致/近似一致/どちらかにしか存在しないか」を把握でき、
後工程での自動置換や変換精度向上に役立ちます。
最終的にはここで得られた対応関係を活用し、
Zemaxデータを自動修正 → CODEV Converterを起動 → エラーなく変換完了
までの一連処理を自動化することを目標としています。
この記事でやること
- Zemaxの.agf(ガラスカタログ)と、CODEVの.xml(ガラス名リスト)を読み込み
- 「完全一致/近似一致/Zemaxのみ/CODEVのみ」へ分類
- 一覧をCSVで出力(後工程での自動置換に使える)
対象ファイル形式のポイント
- Zemax :行頭がNMの行に材料IDが出ます(例:NM N-BK7)。
- CODEV :<GlassName>...</GlassName>//タグ内にガラス名が入ります。
近似一致の考え方(表記ゆれの吸収の仕方)
コンバーター実行の前に以下のようなゆるい正規化で突合精度を上げます:
- 大文字統一・ハイフン除去(N-BK7 → NBK7)
- 先頭E-/J-接頭辞の無視
- 先頭アルファベット+ゼロ詰め番号のゼロ落とし(LAH50050 → LAH550のような型番整形)
実務上ありがちな表記差を吸収し、
「ほぼ同じだが記法が違う」というものを近似一致として拾います。
コア処理(抜粋)
ここからが実際の処理方法の紹介です。
1. .agfから材料IDを抽出
import re
def extract_nm_from_agf(file_path):
nm_ids = set()
with open(file_path, 'r', encoding='utf-8', errors='ignore') as f:
for line in f:
if line.lstrip().startswith("NM"):
parts = re.split(r'[,\s]+', line.strip())
if len(parts) >= 2:
nm_ids.add(parts[1]) # 例: "N-BK7"
return sorted(nm_ids)
2. CODEV .xmlからを抽出
import xml.etree.ElementTree as ET
def extract_glassnames_from_xml(file_path):
names = set()
tree = ET.parse(file_path)
root = tree.getroot()
for elem in root.findall('.//GlassName'):
if elem.text:
names.add(elem.text.strip())
return sorted(names)
3. 簡易正規化(近似一致用)
import re
def normalize_name(name: str) -> str:
name = name.upper().replace("-", "")
name = re.sub(r"^[EJ]-?", "", name) # E- / J- 接頭辞の無視
name = re.sub(r"([A-Z]+)0+(\d+)", r"\1\2", name) # ゼロ詰め番号のゼロ落とし
return name
4. 2つのリストの比較 → 4分類
def compare_two_lists(zemax_list, codev_list):
zemax_set, codev_set = set(zemax_list), set(codev_list)
exact = sorted(zemax_set & codev_set)
# 近似一致のための正規化マップ
zemax_only = sorted(zemax_set - codev_set)
codev_only = sorted(codev_set - zemax_set)
normalized_z = {normalize_name(n): n for n in zemax_only}
normalized_c = {normalize_name(n): n for n in codev_only}
partial_matches, remaining_z, remaining_c = [], [], []
for nz, oz in normalized_z.items():
if nz in normalized_c:
partial_matches.append((oz, normalized_c[nz]))
else:
remaining_z.append(oz)
for nc, oc in normalized_c.items():
if nc not in normalized_z:
remaining_c.append(oc)
return exact, partial_matches, remaining_z, remaining_c
5. 一括比較とCSV出力
import os
import pandas as pd
def compare_all_by_filename(zemax_folder, codev_folder, output_csv):
zemax_files = {os.path.splitext(f)[0]: os.path.join(zemax_folder, f)
for f in os.listdir(zemax_folder) if f.lower().endswith(".agf")}
codev_files = {os.path.splitext(f)[0]: os.path.join(codev_folder, f)
for f in os.listdir(codev_folder) if f.lower().endswith(".xml")}
all_keys = sorted(set(zemax_files.keys()) | set(codev_files.keys()))
records = []
for name in all_keys:
zemax_list = extract_nm_from_agf(zemax_files.get(name)) if name in zemax_files else []
codev_list = extract_glassnames_from_xml(codev_files.get(name)) if name in codev_files else []
exact, partial, z_only, c_only = compare_two_lists(zemax_list, codev_list)
for v in exact:
records.append({"ファイル名": name, "一致種別": "完全一致", "Zemax": v, "CODEV": v})
for z, c in partial:
records.append({"ファイル名": name, "一致種別": "近似一致", "Zemax": z, "CODEV": c})
for z in z_only:
records.append({"ファイル名": name, "一致種別": "Zemaxのみ", "Zemax": z, "CODEV": ""})
for c in c_only:
records.append({"ファイル名": name, "一致種別": "CODEVのみ", "Zemax": "", "CODEV": c})
pd.DataFrame(records).to_csv(output_csv, index=False, encoding="utf-8-sig")
print(f"✔ 比較結果を {output_csv} に出力しました")
実行結果例
下記のような構成のcsvファイルが生成されます。
| ファイル名 | 一致種別 | Zemax | CODEV |
|---|---|---|---|
| HIKARI | 近似一致 | J-SK5 | JSK5 |
| HIKARI | 近似一致 | SSK1 | JSSK1 |
| HOYA | 完全一致 | FDS1 | FDS1 |
| ZEON | Zemaxのみ | ZEONEX_T62R_2017 | |
| ZEON | CODEVのみ | T62R |
- 完全一致:そのまま通る可能性が高い
- 近似一致:自動置換候補(マッピング表へ)
- 片側のみ:供給カタログ差 or 命名差の要調査
よくある表記差(例)
今回試してみた結果、CODEVの方は材料名の文字数制限がかなり厳しいみたいなので
正式名称でなく省略した名前が採用されることが多いようです。
- N-BK7 ↔ NBK7(ハイフンの有無)
- E-FK5 ↔ FK5(接頭辞E-の有無)
- LAH50-000 ↔ LAH50(ゼロ詰め・サフィックス差)
次の一歩:完全自動化までのロードマップ
今回は材料名の比較のみでしたが、最終的には以下の流れで
変換の実効までを完全自動化したいですね。
-
マッピング表作成
近似一致や手動確認の結果から、Zemax名 → CODE V名の対応CSVを作成。 -
Zemaxモデルの材料名一括置換(ZOS-API)
・ レンズファイル(.zmx)読み込み
・材料名をマッピングに従い置換し、強制書き換え -
純正「CODE V Converter.exe」を自動起動
・ZOS-API もしくはsubprocess等で実行
・変換ログを取得し、未解決材料をレポート -
回帰テスト
サンプル設計群に対して一括変換+差分検証で壊れていないかを担保
ここまでをワンボタン化できると日々の変換運用が非常に楽に!
まとめ
- 変換失敗の主要因である材料名不一致を事前に見える化。
- 完全一致/近似一致/片側のみに分類し、置換の優先順位を決められる。
- 今後はこの結果を使って自動置換→純正コンバーター起動までを繋ぎ込み予定。
問い合わせ
本記事は前処理スクリプトの要点のみの紹介でした。
スクリプト全文作成/導入支援/カスタマイズをご希望の方は、
サイバネットシステム光学エンジニアリングサービスまでお問い合わせください。
本件とは関係なく、光学設計・解析・光学教育などのご依頼もぜひ!
※本記事は筆者個人の見解であり、所属組織の公式見解を示すものではありません。