Msc.Marc的python开发#1
Msc.Marc 是一款较为实用的有限元计算软件,但是本身自带的Mentat 前处理可谓十分不好用。当然我们可以选择Msc 公司推出的Patran 前处理程序,不过毕竟还是有一定学习曲线要求的,我暂时不太想换。那么怎么提高现有的蹩脚Mentat的建模效率呢?
其实Mentat 自带的procedure文件可以用来记录一些基本的大量重复的工作。但是在procedure 文件中不能有复杂的选择或循环等结构出现,这限制了procedure文件的功力。
Marc的开发人员早就考虑了这一点,同其他大型软件一样,Marc 早就留出了python 接口,方便我们用python进行批处理工作。
前期配置
我用的是Marc2015 + Visual studio 2012 + Intel visual fortran 2013 的配置
之所以用IVF,是因为我所用的一个子程序需要用Fortran开发,接入到Marc 提供的Ubeam 接口中。
PC上的python本来是3.8的,紧跟时代,各种包装备齐全,然而Marc的python接口自带python.exe,还是2.X版本的(具体什么版本我也没细看)导致装在PC上的python 没法用,各种包也没用。急得我在Marc 的核心python接口模块 py_mentat 所在位置安装了包,然而因为版本兼容问题,bug 不断。我只好暂时舍弃习惯的包,轻装上阵,只用python本体。好在目前接触的问题还比较简单,python本体就能解决了。
核心思想
Marc的python接口的核心思想其实很简单,那就是 一个换了python皮的procedure 文件 。或者说,把需要人工输入的命令汇集到python源文件中,并通过命令行和Marc进行交互,向Marc下各种命令,并获得Marc 的数据库中的各种数据。
核心交互函数及数据库函数
核心交互函数:
- py_send() #向Marc 发送命令的函数,参数一般是以 * 开头的字符串,代表不同的操作。例如:
- py_send("*new_mater standard *mater_option general:state:solid *mater_option general:skip_structural:off")
- py_send("*mater_name %s" % name)
- py_send("*mater_param general:mass_density 2.5e-9")
- py_send("*mater_option structural:type:elast_plast_ortho")
- py_send("*mater_option structural:type:hypo_elast")
- py_send("*mater_option structural:hypoelastic_method:ubeam")
- py_send("*mater_option structural:damping:on")
- py_send("*mater_param structural:rayleigh_damping_stiff_mult 0.0136764")
上面的代码是建立一种材料的必要操作指令,包括建立新材料,设置类型是standard,输入材料名字,设置密度,设置对称性,弹性行为,接入ubeam子程序接口,打开阻尼开关,设置阻尼系数。你可能会问,Marc 指令千千万万条,我怎么记住每个指令对应的代码呢?很简单,要想这些指令,可在先Marc 上用鼠标操作一遍,然后到procedure 文件里找到对应的指令即可。
- py_get_int() 和py_get_float() #这两个函数用来从Marc的数据库中抽取数据。括号中为提取参数,例如
- n = py_get_int(“nelements()”) #获取模型中的单元总数
- node1.x=py_get_float(“node_x(%d)”%node1.ID) #获取指定节点的整体x坐标
数据库函数:
- nnodes( ) #Number of nodes in database
- node_id(ARG1) #ID of ARG1-th node in database
- max_node_id( ) #Largest node ID in database
- node_x(arg1) #Global X-coordinate of node arg1
- node_y(arg1) #Global Y-coordinate of node arg1
- node_z(arg1) #Global Z-coordinate of node arg1
- nelements( ) Number of elements in database
- element_id(ARG1) ID of ARG1-th element in database
- max_element_id( ) Largest element id in database
- element_node_id(arg1,ARG2) ID of ARG2-th node of element arg1
更多的函数可以参考 Marc®Python 2015:Tutorial and Reference Manual
应用实例
下面的代码实现的功能是:从一个csv文件中读入截面的属性,并为每个材料起名字,在Mentat 中按顺序建立这些材料,并赋予相应的属性。然后根据一定的规则把材料和单元对应起来
from py_mentat import *
# import the py_mentat module, which is foundamental
class beam(object):
def __init__(self, string):
data = string.split(',')
self.Nfloor = int(data[0])
self.Nbeam = int(data[1])
self.name = 'F'+data[0]+'L'+data[1]
class column(object):
def __init__(self, string):
data = string.split(',')
self.Nfloor = int(data[0])
self.Ncolu = int(data[1])
self.name = 'F'+data[0]+'C'+data[1]
class node(object):
ID=0
x=0.0
y=0.0
z=0.0
def add_matl(name):
py_send("*new_mater standard *mater_option general:state:solid *mater_option general:skip_structural:off")
py_send("*mater_name %s" % name)
py_send("*mater_param general:mass_density 2.5e-9")
py_send("*mater_option structural:type:elast_plast_ortho")
py_send("*mater_option structural:type:hypo_elast")
py_send("*mater_option structural:hypoelastic_method:ubeam")
py_send("*mater_option structural:damping:on")
py_send("*mater_param structural:rayleigh_damping_stiff_mult 0.0136764")
return
def beam_add(beams):
# add elements for all materials
# take-in parameter:beams, a list containing all the beam elements in order
node_beams = {} # beam dictionary takes 'FXLX' as key
for i in range(len(beams)):
node_beams[beams[i].name]=[]
py_send("*renumber_all")
n = py_get_int("nelements()")
for i in range(1,n+1):
# acquire the ID of the nodes linked by one element, and do this procedure for each element
node1=node()
node1.ID=py_get_int("element_node_id(%d,%d)"%(i,1))
node2=node()
node2.ID=py_get_int("element_node_id(%d,%d)"%(i,2))
node1.x=py_get_float("node_x(%d)"%node1.ID)
node1.y=py_get_float("node_y(%d)"%node1.ID)
node1.z=py_get_float("node_z (%d)"%node1.ID)
node2.x=py_get_float("node_x(%d)"%node2.ID)
node2.y=py_get_float("node_y(%d)"%node2.ID)
node2.z=py_get_float("node_z (%d)"%node2.ID)
if (node1.z ==node2.z):# it's a beam
Nfloor = int(node1.z/4000)
if(node1.x==node2.x):
Nbeam = 4 + int(node1.x/5000) + int((node1.y+node2.y)/10000)*7
else:
Nbeam = 1 + int(node1.y/5000)*7 + int((node1.x+node2.x)/10000)
name="F%dL%d"%(Nfloor,Nbeam)
node_beams[name].append(i)
for key in node_beams:
py_send("*edit_mater %s"%key)
py_send("*add_mater_elements")
for j in range(len(node_beams[key])):
str = "%d " % node_beams[key][j]
py_send(str)
py_send(" # ")
return
def colu_add(columns):
# add elements for all materials
# take-in parameter:columns, a list containing all the column elements in order
node_columns = {} # beam dictionary takes 'FXCX' as key
for i in range(len(columns)):
node_columns[columns[i].name]=[]
py_send("*renumber_all")
n = py_get_int("nelements()")
for i in range(1,n+1):
node1=node()
node1.ID=py_get_int("element_node_id(%d,%d)"%(i,1))
node2=node()
node2.ID=py_get_int("element_node_id(%d,%d)"%(i,2))
node1.x=py_get_float("node_x(%d)"%node1.ID)
node1.y=py_get_float("node_y(%d)"%node1.ID)
node1.z=py_get_float("node_z (%d)"%node1.ID)
node2.x=py_get_float("node_x(%d)"%node2.ID)
node2.y=py_get_float("node_y(%d)"%node2.ID)
node2.z=py_get_float("node_z (%d)"%node2.ID)
if ((node1.x==node2.x)and(node1.y == node2.y)):# it's a column
Nfloor = int((node1.z+node2.z)/8000)+1
Ncolu = int(node1.x/5000)+4*int(node1.y/5000)+1
name="F%dC%d"%(Nfloor,Ncolu)
node_columns[name].append(i)
for key in node_columns:
py_send("*edit_mater %s"%key)
py_send("*add_mater_elements")
for j in range(len(node_columns[key])):
str = "%d " % node_columns[key][j]
py_send(str)
py_send(" # ")
return
def main():
beams = []
with open('E:\\02_research\\06_firstblood\\01_model_PKPM\\ExportExcel\\section_beam.csv') as file:
for content in file:
list = content.split(',')
if list[0] == 'Nfloor':
continue
new_beam = beam(content)
beams.append(new_beam)
file.close()
for i in range(len(beams)):
add_matl(beams[i].name)
beam_add(beams)
columns = []
with open('E:\\02_research\\06_firstblood\\01_model_PKPM\\ExportExcel\\section_colu.csv') as file:
for content in file:
list = content.split(',')
if list[0] == 'Nfloor':
continue
new_column = column(content)
columns.append(new_column)
for i in range(len(columns)):
add_matl(columns[i].name)
colu_add(columns)
return
if __name__ == '__main__':
py_connect("", 40007)
main()
py_disconnect()