這一期的HyperMesh寶典是最重要的一期,
我們來說說「二次開發之函數」~

 

 

 

 
 

什麼是函數?

 
 

 

二次開發有意思的主要的地方就是可以編寫自訂函數,而調用別人已經編寫調試好的套裝程式可以大大降低二次開發的難度。

簡單地說函數就是打包好了的作為一個整體執行的一系列程式語句的集合,比方說下面的語句是用來刪除模型中所有可見的幾何體:

 

 

 

只需要改成如下形式就變成了一個函數:

 

 

 

有實際使用價值的函數未必要很長,而且實際上是恰恰相反,好的函數應該盡可能地短。 Utility 介面下,opti tab 頁的 Del All Opt Entities 功能是被使用者使用的頻率最高的二次開發功能之一。但是它的代碼大概也就10條命令,思路和上面寫的幾乎一模一樣:

 

 

 

 

 

在本文的後半部分我們會介紹如何安裝 tcllib 這個包,裡面會有很多原始程式碼。你會發現很多函數都只有短短幾行,函數之間互相調用。函數可以把複雜的程式按照邏輯關係分解為不同的步驟,讓程式容易編寫也容易理解。

上面的例子沒有參數,也有很多函數是帶參數的。例如下面這個例子是為了在腳本運行的時候暫時關閉圖像介面交互,也是被人使用頻率最高的功能之一。該函數通過臨時關閉不必要的圖形交互功能顯著加速腳本的執行速度。該腳本只帶一個參數,on 或者 off

 

 

 

 
 

代碼重用

 
 

 

有了函數後每次遇到同樣的問題時就可以直接調用已經調試好的函數而不必每次都重複實現,不僅降低了程式設計的難度,也顯著減少了出錯的可能性。這也是函數存在最主要的價值——代碼重用。我們總是盡可能避免在不同的地方重複實現相同的功能,比如接下來介紹的 getdist 函數以及 角度/弧度轉換函數,雖然只有一句也非常值得寫成一個函數。

好的函式定義應當是功能單一,邏輯結構清晰,執行結果不依賴外部條件。比如在很多程式裡都會存在求兩個點之間的距離的需求,我們可以寫成一個函數反復調用:

 

 

 

這裡的函數參數清單為6個座標分量,如果輸入是兩個節點 id 呢?我們先使用節點 id 號獲取6個座標,然後還是調用上面定義好的函數來實現其餘功能而不是重新實現一遍 getdist 已經實現的功能。

 

 

 

【HyperMesh寶典】二次開發之函數 2020-01
 
 

函數接受清單作為參數

 
 

 

函數也接受清單作為參數,比如下面這個例子中把一系列的單元 id 號進行分解,把相連的單元作為一組輸出。請注意這裡的輸出 output_list 也是一個列表類型。通常如果需要返回多個值,建議將輸出作為一個列表返回。

 

 

 

運行程式前的模型如下:

 

運行函數後再輸入:

*createmark elems 1 "all"

set e_list [hm_getmark elems 1]

set sep_ids [seperate_elems $e_list]

得到輸出:

{301 302 303 304 305 306 307 308 309 310 311 312}

{101 102 103 104 105 106 107 108 109 110 111 112}

{401 402 403 404 405 406 407 408 409 410 411 412}

{201 202 203 204 205 206 207 208 209 210 211 212}

這樣就實現了把複雜問題分而治之的目的。接下來對每個孔分別進行處理就容易多了,比如我們來創建一些 RBE2,這裡需要先從單元 id 號找到對應的節點 id 號,然後才能創建。

 

 

 

 

 
 

函數接受陣列名稱和字典名作為參數

 

 

此外,函數也可以接受陣列名稱和字典名作為參數,這種用法對於參數較多的情況特別方便,因為只需要一個陣列或者字典的名稱就可以引用所有陣列或字典裡的鍵了。下面這個例子裡通過傳入一個字典名來保存函數中創建的所有內容。

通常情況函數都會使用值傳遞,因為使用值傳遞時 tcl 解譯器總是先把參數值在另外的記憶體中備份一份供函數內部使用而不是直接操縱參數的原始值,所以,參數的原始值不會有被修改的危險(因此,函數無論是第幾次調用結果都不會有差別)。而upvar 表示這裡使用的是引用傳遞而不是值傳遞,函數會直接指向原始的字典記憶體,如果還有別的函數也同時使用該字典,那麼程式的運行結果會變得無法預測。

 

 

 

程式輸出如下:

=> force_mag:123.500

=> theta_lst:45 90 135 180 225 270 315 360

=> spc_id:4

=> sys_id:1

=> base_x:1000

=> base_y:0

=> base_z:0

 

這裡把與使用者交互的部分放在了一個函數裡面,後續的腳本只需要使用 dict get 命名就可以很方便地獲取字典中的相應內容。也就是說資料的輸入和資料的處理實現了完全解耦,處理資料登錄的函數只需要瞭解要收集哪些資料以及存放在字典的什麼鍵下而不需要關心這些資料的用途;而使用這些資料的函數也只需要知道各個值保存在字典的哪個鍵下而不必再費心去關心資料獲取的過程。這就是函數化程式設計的思路,也就是讓程式的各個模組盡可能地解耦。

 

 
 

參數不確定如何定義函數

 
 

 

很多情況下我們在定義函數的時候無法確定參數的個數,或者只能確定一部分參數,剩餘部分只有在調用函數的時候才能確定,這時我們可以按照下面的格式定義函數的參數清單:

 

 

 

接下來我們可以使用任意個參數調用 max

max 1 2

max 3 4 5

max 4 5 7 9

或者還可以使用如下方式來定義 max 函數

 

 

 

這時候函數體裡面就免去了 lindex 進行輸出,同樣也很優雅。

函數參數還可以有預設值,請參考下例(這個例子也是很常用的):

 

 

程式說明:

最後的兩行注釋是測試語句,在這種簡單的函式定義的時候我們可以直接把測試語句也用注釋的方式寫到裡面去,如果函數眾多或者很複雜,可以使用 tcltest 模組進行單元測試。

【HyperMesh寶典】二次開發之函數 2020-02

 

 
 

應用實例:求解器工況創建

 

 

最後我們來講一個關於求解器工況創建的函數作為例子。先給出腳本:

 

 

 

這裡的難點是 command.tcl 檔記錄了太多的命令,很難從裡面挑出需要的命令,大家可以按照以下方法進行甄別。

 

①、 打開一個已經施加好 spc 和 force 兩個 load collector 的模型(OptiStruct 範本)

 

②、 選擇 edit/command file 打開命令記錄視窗,並清空 command.tcl 檔後保存。

 

③、 在底部命令列執行 hm_writeviewcommand 0 以免記錄一些無用的視圖操作命令

 

④、 在 model browser 手工操作一次,命令記錄有83條之多(你的可能稍有不同),而且這些命令是沒有文檔可以查詢的。

 

⑤、 把記錄的命令複製到文字檔 ls1.txt 中保存。

 

⑥、 重複1-5,但是這次要選擇不同的 spc 和載荷 load collector

 

⑦、 把記錄的命令複製到文字檔 ls2.txt 中保存。

 

⑧、 在 notepad++ 打開兩個文件,把 ls2.txt 檔中的所有 id=5(你的可能是其它數位)改成 ls1.txt 中的值。

 

⑨、 用開源的文本比較軟體 winmerge 對兩個文字檔進行比較。忽略 *endnotehistorystate 之類的歷史記錄命令,你很容易就能得到真正有用的那幾句命令了(我們針對默認 loadstep 設置只更改了分析類型、SPC、Load 三項,命令記錄對應 ID 號為 4709、4145、4147)。分析類型對應的 id 號因為兩個檔中是一樣的,你需要改成不同的分析類型才能進行有效區分。

 

為確保萬無一失,把這些命令複製到命令視窗運行一下(因為 id 號每次會變化,可以按照上圖腳本中的方法臨時獲取)。這裡再次建議大家親自動手上機實踐一下,光看文字可能不會有很深的體會,只有碰幾次壁才能真正懂得這裡面的精髓。

 

 
 

如何使用函式程式庫?

 

 

一個人的知識、能力和時間都是有限的,在二次開發的過程中實際上大部分功能都是通過調用別人已經寫好的函數或者你自己之前寫好的函數實現的。如果只是調用一些簡單的函數我們可以直接使用 souce 命令。souce 命令的效果和把被 source 的檔內容直接複製到相應位置的效果是完全一致的。對於複雜的包,通常會以 package 的形式存在,而且會自帶名字空間。需要使用 package require packagename 的方式來調用包。接下來我們以tcl中非常常用的 tcllib 包的安裝使用為例告訴大家如何下載/安裝/使用外部包。

 

1、下載安裝 tcllib 到本地目錄

點擊下載

 

2、按照 readme.txt 裡面的步驟進行安裝

例如我的電腦上安裝在 C:\Tcl\lib

安裝完成後的目錄名稱為 tcllib1.18

 

3、使用時需要在調用 tcllib 的腳本中加上

set auto_path [linsert $auto_path 0 {C:\Tcl\lib}]

或者

lappend auto_path {C:\Tcl\lib}

注意:路徑永遠只使用絕對路徑!!!

然後就可以使用 tcllib 了,例如:

package require math::linearalgebra

如果沒有出錯資訊,那麼恭喜你 tcllib 已經安裝成功啦~

也可以直接在HyperMesh的命令列簡單測試一下:

目前 tcllib 包裡面包含了400多個函數,包括線性代數、微積分、csv、網路工具、集合資料類型等等。相信能為你的程式設計提供很大的幫助,而且這些都是帶著 tcl 原始程式碼和説明資訊來的(在 activetcl 的幫助中查找),對你學習 tcl 是寶貴的資料。唯一一點不好的就是這個包不是 tcl 默認安裝的,如果你的程式使用了 tcllib,你的腳本拷貝到另外一台電腦後可能會無法執行。

在二次開發部分的最後一段,給大家推薦一下 tcl 單元測試的包 tcltest,因為很多人認識 tcl 語言的原因並不是 HyperMesh 的關係,而是作為一個自動化測試語言。

如果你覺得還想更進一步 tcltest 包,你還可以打開幫助文件看一看說明以及 tcllib 安裝文件下面的很多 .test 文件

(tcllib\tcllib-trunk\modules\math)

 
arrow
arrow

    Altair Taiwan 發表在 痞客邦 留言(0) 人氣()