[Day07]承接[Day06]的內容,繼續講解第四到第八部份。
接觸在ANSA內也是一種Entity。我們建立一個contact的Entity,其element type是CONTACT。fields內的Name,取名為box drop,TYPE則輸入常用的AUTOMATIC_SURFACE_TO_SURFACE。
至於contact的master及slave的type(即MSTYP及SSTYP),我們都選擇用part set,此時先前建立的plate_set及box_set就派上用場了。我們利用Entity的_id這個attribute,將plate_set的id指定給MSID,box_set的id指定給SSID。
contact = base.CreateEntity(deck, 'CONTACT', {'Name': 'box drop',
'TYPE': 'AUTOMATIC_SURFACE_TO_SURFACE',
'SSID': box_set._id,
'MSID': plate_set._id,
'SSTYP': '2: Part set',
'MSTYP': '2: Part set'})
我們利用base.CreateEntity建立邊界條件及初始速度。沒錯,在ANSA裡,這些東西也是Entity。
邊界條件是固定整個plate,element type是BOUNDARY_SPC(SET),fields的NSID設定為plate_set的id,c則設定為123456,即三個平移及三個旋轉自由度都固定。
初始速度是賦予整個box一個初速,element type是INITIAL_VELOCITY_SET,fields的VZ設為-500,即向下500mm/s的初速。
# BOUNDARY_SPC(SET)
base.CreateEntity(deck, 'BOUNDARY_SPC(SET)',
{'NSID': plate_set._id, 'c': '123456'})
# INITIAL_VELOCITY_SET
base.CreateEntity(deck, 'INITIAL_VELOCITY_SET',
{'NSID': box_set._id, 'VZ': -500})
我們分別要設定*CONTROL_TERMINATION及*DATABASE_D3PLOT兩張卡片。CONTROL跟DATABASE開頭的控制卡片,如果是手動在GUI環境內可以輕鬆設定,但是自動化卻也搞了我們一陣子才成功,在此無私分享啦!
*CONTROL_TERMINATION是用來告訴LS-DYNA,這個模擬的世界你想模擬多長時間。依照一貫的思路,我們可能起手式就會想要找出element type,然候把想輸入的值包一包丟進fields。
但很不幸的,對於CONTROL跟DATABASE這兩類卡片,並不能這樣。原因是CONTROL下還有很多種類,TERMINATION只是其中一種,所以我們的作法是在建立control Entity的時候,先把想要的種類設成ON。具體的作法是建立一個ct_fields的dict,key是TERMINATION,value是ON,然候傳入base.CreateEntity去建立一個control的ent,命名為ct_ent。
再來我們透過ct_ent的set_entity_values來定義結束時間ENDTIM為1.5E-2秒,問題應該就解決了吧?抱歉,這邊是另外一個坑呀,這樣做竟然行不通呀!
經過我們一番努力之後,發現真正的作法是要將想輸入的值都prefix TERMINATION_,這就是為什麼我們要做ct_fields.update的原因。雖然現在看只是寥寥數字,但字字都是汗水,實打實的乾貨。
# *CONTROL_TERMINATION
ct_fields = {'TERMINATION': 'ON'}
ct_ent = base.CreateEntity(deck, 'CONTROL', ct_fields)
ct_fields_ = {'ENDTIM': 1.5E-2}
ct_fields.update({'TERMINATION_' + k: v
for k, v in ct_fields_.items()})
ct_ent.set_entity_values(deck, fields=ct_fields)
*DATABASE_D3PLOT是用來告訴LS-DYNA,這個模擬的世界你想多久輸出一次數據。我們依樣畫葫蘆,將DT設為2E-4秒。
# *DATABASE_D3PLOT
db_fields = {'D3PLOT': 'ON'}
db_ent = base.CreateEntity(deck, 'DATABASE', db_fields)
db_fields_ = {'DT': 2E-4}
db_fields.update({'D3PLOT_' + k: v
for k, v in db_fields_.items()})
db_ent.set_entity_values(deck, fields=db_fields)
到目前為止,我們已經完成了所有LS-DYNA設定。
雖然上面我們所產生的Entity都確實存在ANSA內,但是我們必須明確告訴ANSA,哪一些東西是想要輸出的。
如果Entity是material或property,我們需要base.GetEntity先取得該Entity再利用Entity的set_entity_values method將DEFINED設為YES。
如果Entity是control或是邊界條件這類型的,則要透過base.SetEntityVisibilityValues將其設為on(註1)。
# Visibility
plate_mat = base.GetEntity(deck, '__MATERIALS__', 1)
plate_mat.set_entity_values(deck, {'DEFINED': 'YES'})
plate_sec = base.GetEntity(deck, '__PROPERTIES__', 1)
plate_sec.set_entity_values(deck, {'DEFINED': 'YES'})
box_mat = base.GetEntity(deck, '__MATERIALS__', 2)
box_mat.set_entity_values(deck, {'DEFINED': 'YES'})
box_sec = base.GetEntity(deck, '__PROPERTIES__', 2)
box_sec.set_entity_values(deck, {'DEFINED': 'YES'})
keys = {'CONTACT',
'INITIAL_VELOCITY_SET',
'BOUNDARY_SPC(SET)'}
base.SetEntityVisibilityValues(deck, {key: 'on'
for key in keys})
接下來我們可以輸出k檔,準備呼叫LS-DYNA求解。這邊我們引入Python內建的pathlib module內的Path。Path(__file__).parent可以找出當前檔案所處資料夾,再利用特有的/連結'box_drop.k,最後透過as_posix取得路徑後,使用base.OutputLSDyna輸出k檔。
from pathlib import Path
output_lsdyna_path = Path(__file__).parent / 'box_drop.k'
lsdyna_filename = output_lsdyna_path.as_posix()
base.OutputLSDyna(filename=lsdyna_filename)
最後,我們透過subprocess.run呼叫求解的command,執行的指令會類似:
/path/to/smp-dyna_s i=/path/to/box_drop.k ncpu=10 memory=1500m d=nodump
以上command是指使用/path/to/smp-dyna_s這個solver,使用10個cpu及1500m memory來求解/path/to/box_drop.k這個檔案,並且不寫出dump檔。
由於我們是使用Ubuntu系統,Windows的用戶需要注意路徑的設置。
import subprocess
solver_path = f'{Path.home()}/LS-DYNA/13.0/smp-dyna_s'
lsdyna_file_path = f'i=' + lsdyna_filename
ncpu = 'ncpu=10'
memory = 'memory=1500m'
dump = 'd=nodump'
commands = [solver_path,
lsdyna_file_path,
ncpu,
memory,
dump]
c = ' '.join(commands)
print(c)
subprocess.run(commands)
至此,你已經自動產生一個box drop的project了。
下圖是我們用LS-PrePost錄的gif動畫。
註1:可能有人會發現,這邊的on是小寫的。雖然我們測過ON也是可以,但說明文件內是用小寫,保險起見我們還是跟著說明走。有趣的是,如果你把control或database那邊的ON改成on就不行了呀...