Fidelity Pointwise 中用于 Python 的 Glyph API
2023 年 4 月 10 日? 11 分鐘閱讀
曾經希望您可以使用 Tcl/Tk 以外的某種語言編寫 Glyph 腳本來擴展或定制 Cadence 的 Fidelity Pointwise 軟件的功能嗎?Python 程序員:別再希望了!結合 2018 年 9 月發布的 Pointwise V18.2,我們開發并發布了一個包裝器 API,它以一種非常 Python 風格的方式提供對 Glyph 命令的完全訪問,這種方式對于 Tcl/Tk 腳本編寫者來說仍然非常熟悉。對于 Python 編碼人員來說,該界面看起來和感覺起來就像原生 Python,其明顯優勢是能夠使用任何社區開發的 Python 包的全部功能。
(在我們繼續之前,重要的是要注意,在本文中,Glyph 指的是 Pointwise 發布的基于 Tcl 的命令集。每當我們提到 Glyph 時,我們實際上指的是用于 Tcl/Tk 的 Glyph API。我們'我們將把 Python API 稱為 Python/Glyph。)

使用 Tkinter 和 matplotlib 的示例 Glyph/Python 腳本。
什么是字形 API?
從 Pointwise V18.0 R2(2016 年 11 月)開始,原始的 Glyph 接口得到增強,幾乎可以通過任何支持 TCP/IP 套接字通信的腳本語言(或與此相關的編譯語言)進行訪問。關鍵的添加是一個名為 Glyph Server 的組件,它允許外部進程連接到用戶指定的端口并與 Pointwise 交互以運行 Glyph 操作。最終結果是任何可以連接到運行 Pointwise 的主機上指定 TCP 端口的程序或腳本(在腳本菜單中啟用 Glyph 服務器選項)可以傳輸包含 Glyph 命令的消息并接收包含 Tcl 的消息格式化的返回值以及 Tcl 結果代碼。
在發布具有 Glyph Server 功能的 V18.0 R2 的同時,我們還在托管在 GitHub 上的 Glyph Script Exchange 上發布了 Python Glyph Client,它實現了 Python 的 TCP/IP 連接和基本消息處理。這建立了從 Python 腳本與正在運行的 Pointwise 實例進行通信的基線機制,但它沒有提供任何方式來將 Glyph 對象和列表表示為 Python 對象和容器——留給讀者作為練習。但這仍然沒有達到真正的 Python 的外觀和感覺,這就是 Python 的 Glyph API 的用武之地。

Pointwise Glyph 服務器的架構
Python 的 Glyph API
隨著 2018 年 9 月 V18.2 R2 的發布,我們擴展了 Python 客戶端包以包含適用于 Python 的 Glyph API,這使得 Python 中的 Glyph 腳本看起來和行為都像……Python。也就是說,不需要您的 Python 腳本構建一個 Glyph 命令字符串并將其發送到服務器,然后按如下所示處理結果。
from pointwise import GlyphClient
glf = GlyphClient(port=2807)
dim = 11
con1 = glf.eval("pw::Connector create") # con1 = "::pw::Connector_1"
glf.eval(con1 + " setDimension " + str(昏暗))#ugly
你現在可以寫類似的東西
from pointwise import GlyphClient from pointwise.glyphapi import * glf = GlyphClient(port=2807) pw = glf.get_glyphapi() dim = 11 con1 = pw.Connector() # con1 是一個 Python 對象! con1.setDimension(昏暗)#realpython
Python/Glyph 負責生成所需的 Glyph 命令字符串、發送請求、處理 Glyph 結果字符串和代碼,以及創建 Python 包裝器對象。事實上,它以這樣一種方式執行此操作,即使每個 Glyph 命令(過去的、現在的和將來的)都可以作為 Python 對象使用,其外觀和行為(大部分)與您期望的一樣。
例子
GitHub 項目包含 Python API 的一些具體示例用法,包括非常熟悉的 Backstep 教程的完整腳本版本(可在所有 Pointwise 版本附帶的教程工作簿中找到)。但是,為了稍微刺激一下您的胃口,這里有一個簡單的示例,它從點的循環中創建了一個方形的非結構化域。
from pointwise import GlyphClient
from pointwise.glyphapi import *
# 端口 0 是特殊的,因為它在本地啟動一個 Glyph 批處理
glf = GlyphClient(port=0)
pw = glf.get_glyphapi()
pw.Connector.setCalculateDimensionMethod("Spacing")
pw. Connector.setCalculateDimensionSpacing(.3)
# 從循環點列表創建一個連接器循環 points
= [(0, 0, 0), (10, 0, 0), (10, 10, 0), (0, 10 , 0)]
cons = []
with pw.Application.begin("Create") as creator:
for p1, p2 in zip(points, points[1:]+points[:1]):
seg = pw.SegmentSpline( )
seg.addPoint(p1)
seg.addPoint(p2)
con = pw.Connector()
con.addSegment(seg)
con.calculateDimension()
cons.append(con)
creator.end() #使用 pw.Application.begin("Create") 作為創建者
從連接器創建一個非結構化域: edge = pw.Edge.createFromConnectors(cons) dom = pw.DomainUnstructured() dom.addEdge(edge) creator.end()打印(dom)
細節:將 Python 映射到字形
關于如何使用 Python/Glyph 的完整細節在 GitHub 上,但這里有幾件事值得一提。該項目的主要目標之一是最小化或消除維護 Python 代碼與 Pointwise 和 Glyph 一致的需要。也就是說,隨著 Pointwise 和 Glyph 隨著新的對象類型和操作的發展,如果除了傳統的 Tcl API。
幸運的是,Python 語言包含許多特性,使我們能夠自動將 Glyph 對象類型和操作映射到具有真實屬性和方法的 Python 包裝器對象。也就是說,通過將 Python 類、對象、屬性和方法自動映射到 Glyph,不需要在 Python API 中定義單獨的類、屬性和方法。結果是 Python 中的所有 Glyph 對象和類都成為一個名為 GlyphObject 的特殊包裝類的實例,該包裝類負責在 Pointwise 中映射其關聯的具體 Glyph 對象的實際類型、屬性和操作的更精細細節。因此,沒有一個名為 Connector 或 DomainUnstructured 的 Python 類,因此沒有這些類型的實例,但是每個類都有一個 GlyphObject 實例知道如何將這些東西映射到 Glyph。
字形映射規則
上述示例中隱含了一些將 Python/Glyph 映射到 Glyph 的規則,但我們將在此處詳細介紹基本規則。在使用 Python/Glyph 之前,必須首先通過在“pointwise”包中實例化 GlyphClient 來建立與 Glyph 服務器的連接。(我們將此對象稱為“glf”。)請注意,在默認“localhost”上指定為端口“0”的連接將導致 Python/Glyph 啟動新的批處理 Glyph (tclsh) 進程并啟動 Glyph 服務器在任何可用端口上,然后在連接關閉時終止進程。
1. Python/Glyph API 的頂層始終是“glf.get_glyphapi()”返回的對象。使用該對象創建的所有后續 Python/Glyph 實例最終都鏈接到該頂級對象,因此也鏈接到它們所在的 Pointwise 工作空間。(我們將此對象稱為“pw”。)
Tcl/Tk: package require PWI_Glyph 2 # 建立 'pw' 命名空間 Python: glf = GlyphClient(port=0) pw = glf.get_glyphapi()
2. Glyph 類名對于 Python 和 Tcl 都是區分大小寫的,因此名稱必須完全匹配。
3. 所有字形類都是頂級(“pw”)對象的有效屬性。
Tcl/Tk:pw::Application Python:pw.Application
4. 任何公開靜態“創建”操作的 Glyph 類都可以使用語法“pw.GlyphClassName()”直接實例化。如果 create 操作接受參數,它們可以像任何其他參數一樣傳遞(參見規則 8)。
Tcl/Tk:設置 con [pw::Connector 創建] Python:con = pw.Connector()
5. 所有靜態 Glyph 類操作都在等效的 Python/Glyph 對象上調用。
Tcl/Tk:pw::Application getVersion Python:pw.Application.getVersion()
6. 返回 Glyph 對象的 Glyph 動作被包裝在 GlyphObject 的實例中,該實例以與關聯的 Glyph 對象一致的方式起作用。在此對象上只能調用實例操作,并且沒有隱式充當“setter/getter”方法(常見的 Python 習慣用法)的屬性。
7. Python/Glyph 對象上的實例方法被轉換為 Glyph 實例操作。
Tcl/Tk:設置昏暗 [$con getDimension] Python dim = con.getDimension()
8. 對于 Python 和 Tcl,命令參數可以是位置參數和/或關鍵字參數,但是映射它們的規則比人們想象的要復雜一些。
8a. Python 關鍵字參數用于所有 Glyph 標志參數。除了作為關鍵字參數之外,沒有其他方法可以指定 Glyph 標志。
Tcl/Tk:$crv smoothC1 -tolerance $tol Python:crv.smoothC1(tolerance=tol)
8b. 不接受參數的字形標志必須在 Python 中指定為值為 True 的關鍵字。
Tcl/Tk:$con1 join -keepDistribution $con2 Python:con1.join(con2, keepDistribution=True)
8c. 位置參數在 Tcl 中出現在最后,但在 Python 調用列表中必須出現在最前面。
Tcl/Tk:$con fitLSQ -tolerance $tol $refCon Python:con.fitLSQ(refCon,tolerance=tol)
8d。請注意,某些關鍵字參數可能看起來包含一個值,但仔細查看 Glyph 文檔會發現它們并不包含。在這些情況下,使用任何一種形式的 Python/Glyph 命令都可以,但請注意這是語法異常。
Tcl/Tk: $con getPosition -arc 0.5 Python: con.getPosition(0.5, arc=True) # 預期的形式 con.getPosition(arc=0.5) # 有效,但不正確
8e. 列表(或元組)可以作為參數傳遞,并轉換為 Tcl 列表,除非在某些情況下。(有關這些附加規則,請參閱 GitHub 主頁上的文檔。)
Tcl/Tk: $segment addPoint {0 0 0}
Python: segment.addPoint((0, 0, 0)) # 單個元組參數
高級 Python/字形列表
Python 語言提供了一些非常獨特的句法特性來處理對象和值的容器。有經驗的 Python 編碼人員會發現 Python/Glyph 列表處理并不像他們希望的那樣優雅。由于我們采用的自動一對一映射方案,Python/Glyph 腳本將傾向于相當接近地模仿 Glyph。如果您熟悉 Tcl/Tk 中的 Glyph 腳本,您會記得大多數處理集合或信息列表(例如,點或單元格)的操作只能使用循環一次檢索一個形式:
set elist [list]
for { set i 1 } { $i <= [$entity getObjectCount] } { incr i } {
lappend elist [$entity getObject $i]
}
這是 Pointwise 中的一個有意識的設計選擇,因為許多 Glyph 對象可能包含大量子元素,并且將元素列表轉換為它們的 Tcl(字符串)等價物往往效率非常低(內存方面)。對于上面的例子,等效的 Python 代碼通常是這樣的:
elist = [] for i in range(1, entity.getObjectCount()+1): elist.append(entity.getObject(i))
好吧……哎呀。但是,對于可能存在大量事物的集合(如點或單元格或檢查度量數據),請考慮將列表從 Glyph 轉換為 Tcl(字符串形式)以及從 Tcl 轉換為 Python 需要多少額外開銷(內存)。(請記住,所有 Glyph 對象都是通過 TCP/IP 連接作為字符串進行通信的。)當然,權衡是必須進行的 TCP/IP 往返次數才能以這種方式檢索完整的對象列表。
作為妥協,我們有近期的開發計劃,為通常不太大的對象/值列表添加許多直接的“getObjectList”操作到 Glyph。例如,在 Pointwise V18.2 R2 中,您將能夠檢索連接器的所有控制點或網格點:
con = pw.GridEntity.getByName("con-1")
segs = con.getSegments()
segpts = seg[0].getPoints()
conpts = con.getPoints() # 網格點在連接器上的位置
gridxyzs = con.getXYZs (grid=True) # 所有網格點的XYZ值
cpxyzs = con.getXYZs(control=True) # 所有控制點的XYZ值
這應該可以滿足大多數小型對象列表的要求,但是可能會包含點和單元格之類的大型列表仍然需要一次檢索一個。現在,具有一定 Tcl 信譽的精明 Python 編碼人員可能會認識到,可以使用類似以下內容的客戶端 API 直接檢索這些大型對象列表的全部或部分集合:
cmd = "set pts [list]\n"
cmd += "set dom [pw::GridEntity getByName" + dom.getName() + "]\n"
cmd += "for {set i 1} {$i < [$dom getPointCount] + 1} {incr i} {\n"
cmd += " lappend pts [$dom getPoint $i]\n"
cmd += "}\n"
cmd += "set pts\n"
結果= glf.eval(cmd)
# 'result' 現在是 Tcl 列表的原始字符串表示 {{x1 y1 z1} ...},
# 但我們可以通過一些內部知識將它轉換為 Python:
pts = dom._toPythonObj (result)
# pts 現在是實數列表的 python 列表 [[x1, y1, z1], ...]
公平警告,應謹慎使用此習語,注意非常大的集合將暫時需要大量內存用于服務器連接兩側的中間字符串表示。一個更可口的實現可能是通過重復使用與上述類似的技術來檢索塊中的列表。
獲取 Python/字形
Python/Glyph 包已經在 GitHub 上托管的 Glyph Script Exchange 上可用,還有一些示例可以幫助您入門。請注意,有一個外部包依賴項 numpy,它用于直接在 Python 中簡化某些實用程序函數的實現。您還可以使用 pip 和如下命令安裝 Python/Glyph 及其依賴項:
python -m pip 安裝 pointwise-glyph-client
如果您是現有客戶,請隨時下載并試用。它適用于 Python 2 或 3。歡迎所有反饋,您可以自由修改或擴展 API 以適合自己。與我們所有的 GitHub 項目一樣,我們始終歡迎通過社區進行改進!在我們共享各種腳本示例的Fidelity Pointwise Github頁面上了解更多信息。
如果您不是當前客戶,但想開始使用用 Python 編寫的宏和模板自動化您的網格生成過程,現在是申請免費試用的時候了。
致謝
在 Pointwise 產品開發團隊的首席工程師(和 Python 專家)Mike Jefferies 的指導下,德克薩斯 A&M 大學應用數學專業的 Tyler Anderson 作為夏季實習生項目實施了 Glyph 的 Python API 的重要部分。
本文由 David Garlisch 撰寫。
文章來源:cadence博客
工程師必備
- 項目客服
- 培訓客服
- 平臺客服
TOP






















