LightTools 二次开发:把参数扫描做成可恢复、可追踪的仿真任务


扫描十个透镜间距,写一个循环就能开始;扫描一千组、夜间运行八小时,并且第二天能回答“哪组模型、哪些随机设置产生了这张接收器图”,才算建立了工程流程。API 调通只是第一步,任务身份和结果可信度往往决定整个批次是否有价值。

LightTools 提供与外部工具交换数据、进行自动化的接口;官方课程包含 COM/.NET 和数据访问流程。具体对象路径、命令和许可仍应以安装版本帮助为准。LightTools API 官方课程说明

一、显式绑定会话,避免改到另一份模型

桌面上可能同时打开多份模型。只连接“任意运行中的 LightTools”,会让一个合法 API 调用作用于错误会话。批次开始应确认进程、模型身份与工作副本路径,并把三者写进任务日志;进程号只在当前进程生命周期内有意义,不能作为跨重启的永久任务编号。

ltapy 1.0.0 文档展示了按 PID 连接的形式:

1
2
3
import ltapy.session
session = ltapy.session.Session(pid=4711)
lt = session.lt

这里 4711 只是示例,必须换成目标进程。ltapy 是第三方包装层,文档年代和默认 LightTools 版本较早;这段代码用于说明会话选择方法,不代表它未经适配就支持任意当前安装。选择原生 COM、.NET 还是 Python 包装,应先做一个最小兼容性样例。ltapy 会话与错误处理

批量执行建议由工具自己管理独立会话和工作副本,避免与人的交互编辑混用。若复用用户已有会话,脚本不应在结束时擅自关闭整个程序,也不能假设窗口中当前选中的对象一直不变。

二、数据键是定位结果,不是永远有效的身份证

很多脚本从对象树复制一段路径后就长期使用。问题在于模型重建、对象删除重建、组件插入顺序或版本变动,都可能改变定位结果。显示名称也可能重复。一个读到数值的调用,仍然可能读错接收器。

建议把业务名称映射到“对象类型、父对象身份、预期量纲和唯一性条件”。每次打开或重建模型后重新解析;缓存键只在明确的会话和模型状态内有效。若找到了零个或两个候选,都应停止当前任务并报告,而不是随便取第一个。

还需要做写后读回。例如请求设置间距 12.5 mm 后,读取同一业务参数,按单位转换后比较;只确认 API 返回成功不能排除路径指向错误。读回相等也只证明参数层面一致,不能代替几何更新和追迹后的结果验收。

ltapy 的核心接口把部分非零状态转换成 APIError,说明原生状态处理和包装层异常语义可能不同。适配层必须明确“数据值”和“状态码”分别是什么,不能把一个错误码当作有效照度读数继续优化。ltapy 核心接口

三、把版本差异留在薄适配层

不要在业务代码各处散落版本专用数据键。可以定义自己的桥接协议:连接、确认模型、加载候选、应用输入、触发追迹、确认完成、导出网格、读取追迹摘要。下方代码是我们自己的接口设计,里面的方法名不是 LightTools 官方 API。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
from typing import Protocol

class SimulationBridge(Protocol):
def confirm_model(self, expected_hash: str) -> None: ...
def apply_inputs(self, inputs: dict) -> None: ...
def run_and_wait(self, trace_spec: dict, timeout_s: float) -> None: ...
def export_receiver(self, output_path: str) -> None: ...
def validate_trace(self) -> dict: ...

def execute(bridge: SimulationBridge, job: dict, receiver_path: str):
bridge.confirm_model(job["model_sha256"])
bridge.apply_inputs(job["inputs"])
bridge.run_and_wait(job["trace"], timeout_s=1800)
bridge.export_receiver(receiver_path)
diagnostics = bridge.validate_trace()
if not diagnostics["complete"]:
raise RuntimeError("追迹未通过完成校验")
return diagnostics

安装版本适配层负责实现这些方法,且应使用本机帮助里真实存在的命令和结果状态。这样,升级造成数据路径变化时,只需要替换一层,而不会连同任务去重、结果存储和优化算法一起重写。

四、命令返回、追迹结束、数据可读是三件事

一个“开始追迹”命令返回,不应被自动解释成结果已就绪。实际接口可能同步阻塞,也可能只提交操作;必须在当前版本确认其语义。完成判据至少应包含:本次追迹处于终止状态、无失败标志、接收器与任务对应、有效采样量和输出尺寸符合预期。

固定等待十秒再读数据会把机器性能和模型复杂度偷偷写进正确性条件。应使用明确完成状态;若只能轮询,就给出有界间隔、总期限和错误检查。不要仅以“文件存在”判定成功,因为它可能是上一组参数留下的旧文件。

超时更需要定义所有权。外层 Python 或 C# 停止等待,不代表一个阻塞的 COM 调用或追迹已经停止。超时任务应进入“状态未知,需要核对”的分支,不能立即在同一会话中提交下一组输入。隔离的工作进程便于监督和恢复,但重启方式仍需遵守软件许可及安装要求。

五、任务身份要覆盖所有影响结果的输入

只用“参数行号”命名文件是不够的。模型更新后,同一行号已不是同一任务。建议对一份规范化清单计算内容哈希,清单包括模型及依赖版本、参数与单位、接收器配置、光线数量、采样方式、随机设置以及求解器版本。

1
2
3
4
5
6
7
8
import hashlib
import json

def job_identity(spec):
payload = json.dumps(spec, ensure_ascii=False,
sort_keys=True, separators=(",", ":"),
allow_nan=False).encode("utf-8")
return hashlib.sha256(payload).hexdigest()

这段函数要求调用方先规范化输入:12.5 mm 和 0.0125 m 若希望视为同一任务,需要先转换;字符串 12.5 和数值 12.5 也不能混用。浮点序列化策略应保持一致,跨语言调度时尤其要明确。哈希能识别清单变化,不能证明模型物理设置正确。

依赖身份最好记录实际文件内容摘要或不可变的受控修订;一个可被覆盖的网络路径,甚至一个手工填写的版本名称,都不足以保证输入没有变化。

随机种子也不能被过度承诺:只有安装版本确实暴露并支持的控制方式才能记录为“已设置”,否则写明不可控,并用重复批次估计波动。即使种子相同,求解器或硬件实现变化也不自动保证逐位一致。

六、先保留原始数据,再提交成功标志

一组任务使用独立目录,先保存原始网格、追迹诊断和日志,完成尺寸、单位、有限值及任务身份校验后,再写提交清单。临时文件写完后在同一文件系统内用替换操作提交,可以减少读取半截 JSON 的机会;整个任务目录的一致性仍需由成功标志和哈希清单约束。

多个 worker 可能同时领取同一任务时,内容哈希本身不会阻止冲突。每次尝试应有独立暂存目录,同一任务的最终提交需要锁、租约配合 fencing token,或存储端条件写入;过期执行者不能覆盖新执行者已经提交的版本。已提交结果保持不可变,成功标志在文件齐全之后写入,不能拿共享目录中的一个标志代替并发控制。

重跑时分三类:已提交且清单完整,直接复用;只有中间文件,进入恢复或重新执行;执行状态未知,先确认旧会话,避免重复追迹。API 路径不存在、模型打不开这类确定性错误不应无限重试;连接瞬断可以有限重试,但重试是否安全取决于操作有没有副作用。

最后用五种故障注入检查框架:错误 PID、错误接收器名、只写一半输出、追迹超过期限、同一任务重复提交。正式优化器应该只接收已经提交的结果,而不能从一个不断变化的输出文件夹里随手抓取最新图片。

参考与验证边界

本文验证对象是任务设计与纯 Python 数据处理逻辑,没有在真实 LightTools 会话中执行追迹。接口适配、数据键、完成状态和许可证并行能力,需要在实际版本中单独验收。


 上一篇
LightTools 接收器数据分析:网格、蒙特卡洛噪声与优化收益怎样分开 LightTools 接收器数据分析:网格、蒙特卡洛噪声与优化收益怎样分开
网格更细、云图更平滑,并不自动意味着照明设计更准确。通过命中数、能量积分、独立重复与配对差值算例,建立 LightTools 接收器数据后处理和优化结果验收的方法。
下一篇 
CATIA 装配二次开发:实例、引用与可追溯 BOM,怎样避免数量翻倍 CATIA 装配二次开发:实例、引用与可追溯 BOM,怎样避免数量翻倍
同一零件在装配中出现多次时,实例路径、零件引用与业务料号不能混为一谈。本文从装配树展开和数量聚合出发,分析重复统计、缺失引用、配置状态和 BOM 可追溯性。
  目录