Session management - Python API
一、概述
本文演示了将 Lumerical 工具与 Python 集成以开发复杂的自动化工作流程并执行高级数据处理/绘图的可行性。使用 Python API(一个称为 lumapi 的 Python 库)可以实现互操作性。此后,这些术语将互换使用。用户将开发管理 Lumerical 会话的方法,并学习从 Python 脚本初始化和编辑 Lumerical 模拟对象的技术。
应该可以将文件存储在任何工作目录中;但是,建议将 Lumerical 和 Python 文件放在同一个文件夹中。在导入之前设置 Python (Setting the Python Before Importing)中给出了附加环境路径的基本命令,但是对目录的复杂操作超出了本文的范围。要修改 Lumerical 工作目录,请在此处找到说明。
Script命令——cd
更改目录。 该目录是默认保存文件的位置。
示例:
移动到子目录“data”。
?pwd;
C:\demo
path=pwd;
cd(path+"\data");
?pwd;
C:\demo\data
连接到 lumapi.py 文件是启用 Lumerical-Python API 接口的关键。这是通过导入 lumapi 模块并初始化会话(initializing session)来完成的。初始化会话时,这将消耗 GUI 许可证。下面讨论访问模拟对象。使用脚本命令和传递数据在文章脚本命令作为方法和传递数据中进行了讨论。
二、导入模块
Python 路径已配置
为方便起见,Lumerical 的求解器附带了一个基本的 Python 3 发行版,允许用户立即开始使用; 通过从 CAD 脚本编辑器运行我们的任何示例,其中 lumapi 可以像任何模块一样加载。
import lumapi
许多用户希望将 lumapi 集成到他们自己的 Python 环境中。这就像导入 lumapi 模块一样简单;但是,默认情况下,python 不知道在哪里可以找到它。这可以通过修改搜索路径来解决。请参阅有关安装模块的 Python 基础指南installing modules。本质上,我们允许 Python 找到 lumapi 模块,方法是将其父目录包含在导入类将搜索的列表中。通常,一次性更新,请参阅操作系统特定目录的显式路径导入(explicit path import)。如果您还没有准备好或更新 Python 路径,那么以下任何一种方法都应该有效。
在导入之前添加 Python
要将 lumapi 目录临时添加到路径中,可以使用 sys.path.append() 方法。 如果您尚未将 lumapi 添加到搜索路径中,就会出现这种情况,并且在添加其他有用的 lsf、fsp、py 文件的目录时也很有用。 以下代码添加 lumapi 文件夹和当前文件目录。
import sys, os
sys.path.append("C:\\Program Files\\Lumerical\\v221\\api\\python\\") #Default windows lumapi path
sys.path.append("/opt/lumerical/v221/api/python/lumapi.py") #Default linux lumapi path
sys.path.append(os.path.dirname(__file__)) #Current directory
若在除了pycharm之外的IDE中运行时,因为缺乏必要的环境,需要先
Import sys,os
sys.path.append("D:\\ProgramFiles\\Lumerical\\v202\\api\\python\\")#Defaultwindowslumapipath
sys.path.append(os.path.dirname(__file__))#Currentdirectory
再import lumapi
以上代码笔记1有详解
显式导入explicit path import
如果您需要指定 lumapi 发行版的路径,那么 importlib.util() 是指向 lumapi 模块的最佳方法。 如果您正在处理不同的分支或比较 lumapi 版本,则可能会出现这种情况。
import importlib.util
#The default paths for windows and linux
spec_win = importlib.util.spec_from_file_location('lumapi', 'C:\\Program Files\\Lumerical\\v221\\api\\python\\lumapi.py')
spec_lin = importlib.util.spec_from_file_location('lumapi', "/opt/lumerical/v221/api/python/lumapi.py")
#Functions that perform the actual loading
lumapi = importlib.util.module_from_spec(spec_win) #windows
lumapi = importlib.util.module_from_spec(spec_lin) #linux
spec.loader.exec_module(lumapi)
三、开始会话
这就像调用 Lumerical 产品的相关构造函数并将其存储在一个对象中一样简单。
fdtd = lumapi.FDTD()
以上代码在Script File Editor中运行时,会打开一个新的FDTD Solutions界面。
您可以一次创建同一产品和不同产品的多个会话,只要它们都有唯一的名称。
mode1 = lumapi.MODE()
mode2 = lumapi.MODE()
device = lumapi.DEVICE()
每个产品的构造函数都支持以下命名的可选参数:
•hide(默认为 False):在启动时显示或隐藏 Lumerical GUI/CAD 环境
•文件名filename(默认为空):如果为空则启动新应用程序,如果提供 lsf 文件将运行脚本。 如果提供了项目文件名; 如果可以在路径中找到它,它将尝试加载项目。 请参阅 在导入之前设置 python 路径(setting the python path before importing) 这一部分,以添加文件夹或使用完整路径从其他目录加载文件。
# loads and runs script.lsf while hiding the application window
inc = lumapi.INTERCONNECT(filename="script.lsf", hide=True)
以上代码设置hide=True时,就能在隐藏界面的条件下运行脚本文件.lsf。
如果改成False,脚本文件内容如下:
运行以下代码:
则会打开一个新的FDTD 界面,添加了一个矩形。如下图所示。
导入方法
除了在 Python 中定义方法/函数外,用户还可以利用 lumapi 中的自动同步函数功能并导入在 Lumerical 脚本文件(.lsf 文件或格式)中预定义的函数。 使用“eval”命令执行脚本后,这些方法可以作为 lumapi 中的预定义方法调用。
以下是从脚本文件“testScript.lsf”和脚本格式字符串导入函数的示例。
fdtd = lumapi.FDTD()
# import function defined in script format string
# 以脚本格式字符串定义的导入函数
fdtd .eval("function helloWorld() { return \"hello world\"; }\nfunction returnFloat() { return 1.; }\nfunction addTest(a, b){ return a*b; }")
#上面这一句的return \"hello world\",\为转义符,输出就为return "hello world"
print(fdtd .helloWorld())
# import function defined in the script file "testScript.lsf"
code = open('C:/XXX/testScript.lsf', 'r').read()
fdtd .eval(code)
eval()函数功能就相当于能把一段包含脚本信息的字符串文本或.lsf文件,识别出来,然后打开fdtd窗口运行该段脚本。
但是第一步运行会报错
脚本也可以在构造函数中作为参数传递来定义方法:
def testAddingMethodsFromConstructor(self):
app = self.appConstructor(script="any_product_script_workspace_functions_available_in_python_test.lsf")
expectedMethods = {'helloWorld'}
expectedResults = ['hello world from script file']
results = []
results.append(app.helloWorld())
self.assertEqual(results, expectedResults)
app.close()
四、高级会话管理
当函数或内容管理器(context manager)的本地变量超出范围时,它们将被自动删除,当所有指向它的变量引用都被删除时,Lumerical 会话将自动关闭。
将会话包装在一个函数中
在 Python 中,如果您需要运行许多类似的实例,您可以使用函数; 例如,当扫过一些可选参数时。 有关如何返回重要结果的更多信息,请参阅数据传递部分。
def myFunction(someOptionalParameter):
fdtd = lumapi.FDTD()
...
return importantResult
使用“with”内容管理器
我们通过为 Python 中的 Lumerical 会话对象提供明确定义的入口和退出行为来支持 Python “with”语句。 如果“with”代码块中有任何错误,会话仍然会成功关闭(与函数不同)。 另请注意,您通常在 Lumerical 脚本环境中看到的任何错误消息都将显示在 Python 异常中。
with lumapi.FDTD(hide=True) as fdtd:
fdtd.addfdtd()
fdtd.setnamed("bad name") ## you will see
LumApiError: "in setnamed, no items matching the name 'bad name' can be found."
...
## fdtd still successfully closes
五、模拟对象
自 2019a 发布以来,Python API 支持使用构造函数(constructor)添加对象和从构造函数设置 sim-objects(模拟对象)。
使用构造函数添加模拟对象
添加对象时,其构造函数可用于在创建时设置属性值。
fdtd.addfdtd(dimension="2D", x=0.0e-9, y=0.0e-9, x_span=3.0e-6, y_span=1.0e-6)
笔记3-运行结果1
在 Python 中,不保证 dict 排序,因此如果有依赖于其他属性的属性,则需要有序 dict。 例如,在下面的 Python 行中,“覆盖全局监视器设置”(override global monitor setting)必须为真,然后才能设置“频点”(frequency points)。
from collections import OrderedDict
props = OrderedDict([("name", "power"),("override global monitor settings", True),("x", 0.),("y", 0.4e-6),
("monitor type", "linear x"),("frequency points", 10.0)])
fdtd.addpower(properties=props)
注意:OrderedDict位于collections
模块中,使用前需要导入
根据python官方文档, python3.6及之后Dict就都有序了。它们(OrderedDict)变得不那么重要了
如果把OrderedDict改成dict,虽然也能得到正确的结果,但是会弹出警告信息。
D:\Program Files\Lumerical\v202\api\python\lumapi.py:127: UserWarning: It is recommended to use an ordered dict for properties,as regular dict elements can be re-ordered by Python
warnings.warn(message)
如果您没有具有依赖关系的属性,则可以使用常规 Python 字典。
props = {"name": "power",
"x" : "0.0",
"y" : 0.4e-6",
"monitor type" : "linear x"}
fdtd.addpower(properties=props)
操作模拟对象
向 Lumerical 产品会话添加新对象时,会返回一个具有代表性的 Python 对象。 该对象可用于对 Lumerical 产品中的相应对
象进行更改。
rectangle = fdtd.addrect(x = 2e-6, y = 0.0, z = 0.0)
rectangle.x = -1e-6
rectangle.x_span = 10e-6
类似字典的访问
下面的 Python 代码行显示了 FDTD 矩形对象中类似 dict 的参数访问示例。
rectangle = fdtd.addrect(x = 2e-6, y = 0.0, z = 0.0)
rectangle["x"] = -1e-6
rectangle["x span"] = 10e-6
父类和子类的访问
Lumerical 产品中的对象树可以使用对象的父级或子级遍历。
device.addstructuregroup(name="A")#添加名为A的结构组
device.addrect(name="in A")#添加名为in A的矩形
device.addtogroup("A")#将上面那个矩形in A移动到结构组A里
device.addstructuregroup(name="B")#添加名为B的结构组
device.addtogroup("A")#将结构组B移动到结构组A里
bRect = device.addrect(name="in B")#添加名为in B的矩形
device.addtogroup("A::B")#将矩形in B移动到结构组A下面的结构组B里
# Go up two parents from the rectangle in "B" group#从“B”组的矩形中上去两个父母
aGroup = bRect.getParent().getParent()
# Print the names of all members of "A" group
for child in aGroup.getChildren():
print child["name"]
注意:
Python 会在变量从作用域中删除时自动删除它们,因此大多数时候您不需要手动关闭会话。 要明确地这样做,您可以使用调用关闭会话。
inc.close() #inc is the name of the active session
这段话会很快的关闭对话窗口,悬停效果失效。