作为一个工程师,我经常想在某一行修改输入文件。问题是:为了找到该行并修改一个值,我必须编写一个文件解析器来过滤掉该行。不幸的是,作为一名工程师,写一个文件解析器并不是我想花时间的。此外,不仅LS-Dyna输入文件,而且其他FEM文件格式通常都是专有的,因此不存在用于交互的标准接口。
当然,可以通过前处理软件修改部分关键字。前处理软件让修改关键字顺序或删除行间注释被,不会再输出同一个文件名文件。另外,如果只想做一点改变,那么使用前处理软件通常是一件很麻烦的事情。QD-CAE库,是一个更轻、更直接、更易于使用的解决方案。
qd python库在版本0.7.0中支持LS-Dyna输入文件(也称为Keyfiles)的操作。主要目的是建立一个文件或操作一个现有的文件,同时保留其整个结构。我们试图实现最通用的方法,因为无法获取内部编码手册,使得理解文件格式比较困难,但这些问题目前得到了很好的解决。
关键字的读取方式如下:
>>> from qd.cae.dyna import *
>>>
>>> # read a keyfile
>>> kf = KeyFile("path/to/keyfile",
read_keywords=True,
parse_mesh=True,
load_includes=True)
read_keywords将读取文件中的所有关键字。parse_mesh选项解析文本网格数据,并在后台将节点和单元添加到mesh数据库中。在解析时还检查网格的一致性。最后,使用load_includes选项还可以加载includes并通过KeyFile.get_includes() 功能。
Keyword类可用于处理几乎所有的关键字。该类保存关键字的文本,并提供处理文本信息的舒适方法。这允许它再次保存一个相同的文件,包括注释,这非常方便。可以很容易地检查文件中的所有关键字:
>>> kf.keys()
['*BOUNDARY_SPC_SET_ID', '*CONSTRAINED_INTERPOLATION_SPOTWELD', '*CONTACT_AUTOMATIC_SINGLE_SURFACE_ID', '*DATABASE_CROSS_SECTION_PLANE_ID', '*ELEMENT_SHELL', '*END', '*HOURGLASS_TITLE', '*INCLUDE', '*INITIAL_VELOCITY', '*KEYWORD', '*NODE', '*PART', '*PART_CONTACT', '*PART_INERTIA_CONTACT', '*SECTION_SHELL_TITLE', '*SET_NODE_LIST_TITLE', '*SET_PART_LIST_TITLE']
由于同一类型可以有多个关键字,因此可以通过以下方式获得特定类型的所有关键字的列表:
>>> # get all part keywords
>>> part_keywords = kf["*PART"]
>>>
>>> # Check the number of part keywords
>>> len(part_keywords)
7
>>> # select the first part_keyword
>>> kw = part_keywords[0]
>>> print(kw)
$-------------------------------------------------------------------------------
$ Parts, Sections, and Materials
$-------------------------------------------------------------------------------
*PART
$# title
engine part number one
$# pid secid mid eosid hgid grav adpopt tmid
2000001 2000001 2000017
现在有多种方法可以操纵上述关键字。大多数关键字的字段大小为10个字符,但不幸的是,有时它也是8个字符或其倍数。没有通用的方法来检查这一点,因此在出现问题时,请控制它并使用Keyword.set_field_size. 这里的数据格式表交标准,所以我们可以简单地从名称或索引中设置pid。
>>> # set a pid by name
>>> kw["pid"] = 500
>>> # set by indexing
>>> kw[1,0] = 500
由于我们没有内部编码手册,QD-CAE库不知道“pid”字段实际在哪里。幸运的是,人们倾向于很好地记录他们的文件,这样我们就可以在上面的注释行中搜索名称“pid”,并修改下面的字段。顺便说一下,字段是左对齐还是右对齐都无关紧要。
访问pid字段的另一种方法是使用索引。pid在第二个卡和第一个字段中,标准大小为10个字符。由于编程中的计数从0开始,我们也可以用卡1和字段0的索引来处理此字段。方括号是指向更通用函数的快捷方式,也可用于轻松添加新字段。
>>> kw.set_card_valueByIndex(iCard=2, iField=0, value=123, name="custom")
>>> print(kw)
$-------------------------------------------------------------------------------
$ Parts, Sections, and Materials
$-------------------------------------------------------------------------------
*PART
$# title
engine part number one
$# pid secid mid eosid hgid grav adpopt tmid
2000001 2000001 2000017
$custom
123
了解了QD-CAE库不仅可以设置字段,还提供设置名称的选项。这里的值格式为左对齐,这是我们不喜欢的。该库还提供格式化实用程序。首先,我们将全局格式设置为right并重新格式化卡。
>>> Keyword.field_alignment = Keyword.align.right
>>> Keyword.name_alignment = Keyword.align.right
>>> kw.reformat_all(skip_cards=[0])
>>> print(kw)
$-------------------------------------------------------------------------------
$ Parts, Sections, and Materials
$-------------------------------------------------------------------------------
*PART
$# title
engine part number one
$ pid secid mid eosid hgid grav adpopt tmid
2000001 2000001 2000017
$ custom
123
有更多的方法来控制格式,所以这只是一个小例子。在重新格式化时,我们必须跳过每一张带有非统一字段的卡片(这里是卡片0)。卡0在整行上有一个name字段(dyna行限制总是80个字符,但我们不在乎)。如果我们像以前一样设置字段,名称将自动裁剪以适合10个字符的标准字段大小。可以通过手动指定字段大小来覆盖此行为:
>>> kw.set_card_valueByIndex(0, 0,
value="Yay Im extra long but Im not cropped!",
field_size=80)
>>> print(kw)
$-------------------------------------------------------------------------------
$ Parts, Sections, and Materials
$-------------------------------------------------------------------------------
*PART
$# title
Yay Im extra long but Im not cropped!
$# pid secid mid eosid hgid grav adpopt tmid
2000001 2000001 2000017
$ custom
123
请注意字段现在是如何与前面定义的字段右对齐。
网格相关数据有特定的关键字。
仅当KeyFile构造函数中的parse_mesh=True选项时才使用它们。如果网格没有被解析,那么所有的坐标都是相同的,否则它们会因浮点精度而变化。
如果parse_mesh=True,则网格数据不会以文本形式保存在关键字中,而是保存在内部网格数据库中。如果调用str(keyword),则数据将再次在内部转换为字符串。可以使用这些类轻松添加示例节点:
>>> # get the first node keyword
>>> kw = kf["*NODE"][0]
>>> # to the NodeKeyword one can simply add another node
>>> node = kw.add_node(3515, x=0, y=0, z=0)
>>> nodes_of_keyword = kw.get_nodes()
>>> # Since kf is a FEMFile, we can access the mesh similar to a D3plot
>>> all_nodes = kf.get_nodes()
作为一个信息,无论是网格关键字还是网格数据都不能删除,因为为此我们必须重写引擎的一部分,而我们根本没有时间去做(毕竟我们没有为此获得报酬)。解析网格时要小心,因为数据块中的每条注释行或空行都会终止解析,而后面的所有数据都将被卸载。
对于include management,我们在后台还有两个类:
加载每个*INCLUDE_PATH
,将自动搜索每个*INCLUDE_PATH
中表示的每个路径。可以很容易地添加一个新的IncludePathKeyword,如下所示:
>>> # add a new keyword with a path
>>> kw = kf.add_keyword("*INCLUDE_PATH")
>>> kw.append_line("test/folder")
>>> # print the dirs
>>> kw.get_include_dirs()
['test/folder']
您可以从各自的*include或直接从KeyFile获取all include文件。
>>> # get the includes of a single include statement
>>> kw = kf["*INCLUDE"][0]
>>> kw.get_includes()
[<qd.cae.dyna_cpp.QD_KeyFile object at 0x0000021EE379BA78>]
>>> # get all include files
>>> len( kf.get_includes )
6
include的每个关键字都不会加载到父文件中,因此,如果从include中搜索关键字,则必须搜索include文件(也许我们会更改此设置)。但是网格被加载到父网格数据库中以确保一致性(网格关键字仍在include文件中,但它们使用的是父网格数据库)。
我们可以轻松地修改现有文件并创建相同的副本。为了确保文件完全相同,我们不解析网格。因此,我们也不需要加载include,这节省了我们的时间。
>>> # load a file
>>> kf = KeyFile("path/to/keyfile", parse_mesh=False, load_includes=False)
>>> # modify the first part keyword
>>> kw = kf["*PART"][0]
>>> kw["pid"] = 20003
>>> # write the file again
>>> kf.save("path/to/modified_keyfile")
linux shell上的一个差异显示,文件只在这一行上不同
diff path/to/keyfile path/to/modified_keyfile
105965c105965
< 28 28 26016102 2 0 0
---
> 20003 28 26016102 2 0 0
我们的工具和软件应该是这样的:快速、简单和直接。
目前QD-CAE的仓库地址为:https://github.com/qd-cae/qd-cae-python,为了防止世界崩溃,本站备份版本,兑换获取提取密码。
好在精选、乐于分享
我要推荐