今天我們來學習如何利用少於200行的Python script,自動生成一個LS-DYNA模型,並自動提交求解。
這個模型會有兩個物件,在LS-DYNA裡我們叫他們做part。值得一提的是,這個part是LS-DYNA裡的part,並非是ANSA裡做為container的part。聽不太懂?!那正常,因為我們一開始也時常搞錯...
第一個part我們叫它做plate,由一個QUAD4 element組成。另一個part我們叫它做box,由六個QUAD4 element組成。box將會有個初速向下,去撞擊固定在地上的plate。
這個project總共分為八個部份:
為減輕大家學習的難度,我們這個project先只在單一function內完成所有事項,並在material及property的建立先使用預設值(註1),等大家比較熟悉ANSA API了,我們再試著重覆或需要做細部設定的地方找出來,寫成function或class。此外,這個project,我們會使用numpy及SciPy(註2)。
我們試著盡量逐行講解,讓大家能夠打好基礎。今天我們先講解第一到第三部份,[Day07]繼續講解第四到第八部份。
首先,我們從ANSA內import兩個所需的module,base及constants。
from ansa import base, constants
接著建立一個deck,
deck = constants.LSDYNA
再來,我們呼叫base.SetCurrentDeck,把deck傳進去,這步是告訴ANSA,把GUI環境內的deck設為此deck。如果只是寫一個NO-GUI的script,那麼這個設定不是必須的。但是因為之後我們會想在GUI內,先觀察我們產生的plate、box及其它設定是否如我們所想,所以我們先在前面做這個設定。
base.SetCurrentDeck(deck)
完成基本設定後,我們可以準備創建plate。plate是一個LS-DYNA的QUAD4 element,由四個node組成。
我們可以將這個小節拆成三個step:
node Entity,命名分別node1~node4。element Entity,是由node1~node4所組成,命名為plate_shell。set來裝載plate_shell,命名為plate_set。這個set的用途是之後方便用來做接觸及邊界條件設定。我們逐個step來看。
透過base.CreateEntity來創建node Entity。base.CreateEntity的基本介紹可以參考Day03的說明。
element_type經由GUI介面可以得知其名稱為NODE。fields是此Entity真正包含的內容,需為dict型態,key是LS-DYNA卡片內各列的參數名,value則是我們想賦予的值。此處NID為node這種Entity的id,XYZ則為座標值。
依照這個原則,我們可以建立四個node Entity,其可以組成邊長為100的正方形。
node1 = base.CreateEntity(
deck, 'NODE', {'NID': 1, 'X': 0, 'Y': 0, 'Z': 0})
node2 = base.CreateEntity(
deck, 'NODE', {'NID': 2, 'X': 100, 'Y': 0, 'Z': 0})
node3 = base.CreateEntity(
deck, 'NODE', {'NID': 3, 'X': 100, 'Y': 100, 'Z': 0})
node4 = base.CreateEntity(
deck, 'NODE', {'NID': 4, 'X': 0, 'Y': 100, 'Z': 0})
shell的element type為ELEMENT_SHELL。因為我們想建立的是QUAD4,所以fields的type內需指定為QUAD,至於PID是指property id,因為我們還沒產生,所以可以先隨便指定一個數字,ANSA若發現這是未使用的PID,會幫我們建立一個相對應的property Entity及material Entity,我們此處給1。element id我們也指定為1,N1~N4則分別指定為step1所產生的node1~node4 Entity。最後,命名此Entity為plate_shell。
plate_shell = base.CreateEntity(deck, 'ELEMENT_SHELL', {'TYPE': 'QUAD',
'PID': 1,
'EID': 1,
'N1': node1,
'N2': node2,
'N3': node3,
'N4': node4})
set的element type為SET。我們建立一個名為plate_set的Entity,其fields內的Name則給定一個plate的名字。接著我們透過base.AddToSet將step2產生的plate_shell放進plate_set內。
plate_set = base.CreateEntity(deck, 'SET', {'Name': 'plate'})
base.AddToSet(plate_set, plate_shell)
box是由六個QUAD4 element組成,步驟與plate很像,我們也可以將此小節拆成三個步驟:
node Entity,命名分別node10001~node10008。element Entity,是由node10001~node10008所組成,命名為box_shell1~box_shell6,並用一個list裝載他們,命名為box_shell。set來裝載box_shell,命名為box_set。這個set一樣是方便之後用來做contact設定。node10001~node10008 可以組成邊長50mm的正立方體。我們將box的底部預設為離地5mm,所以將node10001~node100004的z設為5(註3)。
# box bottom layer
node10001 = base.CreateEntity(
deck, 'NODE', {'NID': 10001, 'X': 25, 'Y': 25, 'Z': 5})
node10002 = base.CreateEntity(
deck, 'NODE', {'NID': 10002, 'X': 75, 'Y': 25, 'Z': 5})
node10003 = base.CreateEntity(
deck, 'NODE', {'NID': 10003, 'X': 75, 'Y': 75, 'Z': 5})
node10004 = base.CreateEntity(
deck, 'NODE', {'NID': 10004, 'X': 25, 'Y': 75, 'Z': 5})
# box top layer
node10005 = base.CreateEntity(
deck, 'NODE', {'NID': 10005, 'X': 25, 'Y': 25, 'Z': 55})
node10006 = base.CreateEntity(
deck, 'NODE', {'NID': 10006, 'X': 75, 'Y': 25, 'Z': 55})
node10007 = base.CreateEntity(
deck, 'NODE', {'NID': 10007, 'X': 75, 'Y': 75, 'Z': 55})
node10008 = base.CreateEntity(
deck, 'NODE', {'NID': 10008, 'X': 25, 'Y': 75, 'Z': 55})
六個element entity分別命名為box_shell1~box_shell6,pid都指定為2,由ANSA自動產生property及material Entity,EID則分別為 10001~10006。各個Entity的N1~N4則可能需要大家畫個圖,自己看座標填入適當的node Entity。最後再將box_shell1~box_shell6都裝入box_shell這個list。
box_shell1 = base.CreateEntity(deck, 'ELEMENT_SHELL', {'TYPE': 'QUAD',
'PID': 2,
'EID': 10001,
'N1': node10004,
'N2': node10003,
'N3': node10002,
'N4': node10001})
box_shell2 = base.CreateEntity(deck, 'ELEMENT_SHELL', {'TYPE': 'QUAD',
'PID': 2,
'EID': 10002,
'N1': node10001,
'N2': node10002,
'N3': node10006,
'N4': node10005})
box_shell3 = base.CreateEntity(deck, 'ELEMENT_SHELL', {'TYPE': 'QUAD',
'PID': 2,
'EID': 10003,
'N1': node10002,
'N2': node10003,
'N3': node10007,
'N4': node10006})
box_shell4 = base.CreateEntity(deck, 'ELEMENT_SHELL', {'TYPE': 'QUAD',
'PID': 2,
'EID': 10004,
'N1': node10004,
'N2': node10001,
'N3': node10005,
'N4': node10008})
box_shell5 = base.CreateEntity(deck, 'ELEMENT_SHELL', {'TYPE': 'QUAD',
'PID': 2,
'EID': 10005,
'N1': node10003,
'N2': node10004,
'N3': node10008,
'N4': node10007})
box_shell6 = base.CreateEntity(deck, 'ELEMENT_SHELL', {'TYPE': 'QUAD',
'PID': 2,
'EID': 10006,
'N1': node10005,
'N2': node10006,
'N3': node10007,
'N4': node10008})
box_shells = [box_shell1, box_shell2, box_shell3,
box_shell4, box_shell5, box_shell6]
建立一個名為box_set的Entity,其fields內的Name則給定一個box的名字。接著我們透過base.AddToSet將step2產生的box_shell放進box_set內。
值得注意的是base.AddToSet除了支援放入單一的Entity,也可以放入一個內含多個Entity的list,所以我們可以直接將box_shell放進box_set。
box_set = base.CreateEntity(deck, 'SET', {'Name': 'box'})
base.AddToSet(box_set, box_shells)
註1:理論上,LS-DYNA是沒有預設單位的,所有輸入的數字都反映了使用者想模擬的世界。但因為這邊我們利用了ANSA自動產生material及property的功能,所以這個模擬世界的單位,將會是ANSA預設的ton/mm/sec。
註2:ANSA共附了numpy、SciPy、OpenSSL、H5py及randomcolor等五個third-party package。
註3:聰明的你可能會發現,這樣設定,相距不是5啊?沒錯,嚴格來說,plate及box的預設厚度皆為1mm,實際相距會是(5-2*1/2)=4mm。這樣都被你發現,果然是行家呀!