我正在设计有限元素库。对于给定的问题,所使用的有限元网格可以具有不同尺寸的元素(例如四面体和三角形),并且也可以组合相同尺寸的不同元素(例如四面体和六面体)。因此,我需要一个存储有限元信息的数据结构。最基本的信息是元素的连接性(定义元素的节点ID)。例如,我需要以某种方式存储三角形元素4连接到节点5,6和10。
我的第一次尝试是创建一个列表,其索引是维度(0,1,2或3)并存储字典。这些字典具有字符串键(标识符),值为numpy数组(每行代表元素连接)。我需要这样做,因为给定维度的numpy数组具有不同的形状,具体取决于字符串标识符。
这是班级:
import os
from collections import OrderedDict
import numpy.ma as ma
flatten = lambda l: [item for sublist in l for item in sublist]
class ElementData(list):
def __init__(self, *args, **kwargs):
self.reset()
super(ElementData, self).__init__(*args, **kwargs)
def __iter__(self):
for k, v in self[self.idx].items():
for i, e in enumerate(v):
yield (k,i,e) if not ma.is_masked(e) else (k,i, None)
self.reset()
def __call__(self, idx):
self.idx = idx-1
return self
def __getitem__(self, index):
if index >= len(self):
self.expand(index)
return super(ElementData, self).__getitem__(index)
def __setitem__(self, index, value):
if index >= len(self):
self.expand(index)
list.__setitem__(self, index, value)
def __str__(self):
return "Element dimensions present: {}\n".format([i for i in range(len(self)) if self[i]]) + super(ElementData, self).__str__()
def keys(self):
return flatten([list(self[i].keys()) for i in range(len(self))])
def reset(self):
self.idx = -1
self.d = -1
def expand(self, index):
self.d = max(index, self.d)
for i in range(index + 1 - len(self)):
self.append(OrderedDict())
def strip(self, value=None):
if not callable(value):
saved_value, value = value, lambda k,v: saved_value
return ElementData([OrderedDict({k:value(k, v) for k,v in i.items()}) for i in super(ElementData, self).__iter__()])
def numElements(self, d):
def elementsOfDimension(d):
# loop over etypes
nelems = 0
for v in self[d].values():
nelems += v.shape[0] if not isinstance(v, ma.MaskedArray) else v.shape[0] - v.mask.any(axis=1).sum()
return nelems
# compute the number of all elements
if d == -1:
nelems = 0
for i in range(self.d+1):
nelems += elementsOfDimension(i)
return nelems
else: # of specific dimension only
return elementsOfDimension(d)
该类运行良好,它允许我无缝循环遍历特定维度的所有项目。但是,还有其他数据与单独存储的每个元素相关联,例如其材料。因此,我决定使用相同的数据结构来引用其他属性。为此,我使用类的strip
函数,在没有numpy数组的情况下返回整个结构。
我的问题是原始数据结构是动态的,如果我改变它,我必须修改依赖于它的每个其他结构。我真的觉得我在设计这门课时走错了方向。也许有一种更简单的方法可以解决这个问题?我想在numpy数组旁边存储额外的信息(例如,作为元组),但我不知道这是否好。在设计软件时做出的选择可以让我们的生活在以后变得悲惨,现在我开始意识到这一点。
更新
使用上面的类,可以是以下一个例子:
Element dimensions present: [0, 1, 2]
[OrderedDict([('n1', array([[0],
[1],
[3]]))]), OrderedDict([('l2', array([[1, 2]]))]), OrderedDict([('q4', array([[0, 1, 5, 4],
[5, 1, 2, 6],
[6, 2, 3, 7],
[7, 3, 0, 4],
[4, 5, 6, 7]]))])]
其中数据结构用于存储0(节点),1(线)和2(四边形)维度的元素。
答案 0 :(得分:2)
评论:设计违背了程序的逻辑结构。
我使用了给定的元素数据示例,并没有期望立刻得到整个图片。
评论:每个元素都有唯一的维度 (三角形总是尺寸2, 因为四面体总是尺寸为3和 节点维度0)。
抱歉,我误解了问题" ...不同维度的元素......"同 "元素具有不同的维度"。我改编了我的提案。
评论:...修改数据结构时出现问题 (例如通过添加元素)
只要您没有显示此问题的数据示例, 我无法思考解决方案。
我的提案:
class Dimension(object):
"""
Base class for all Dimensions
Dimension has no knowledge to what the data belongs to
"""
def __init__(self, data=None):
pass
class Element(object):
"""
Base class for all Elements
Hold on class Dimension(object):
"""
def __init__(self, dimension=None):
pass
class Triangle(Element):
def __init__(self, dimension):
super().__init__(dimension=dimension)
class Tetrahedron(Element):
def __init__(self, dimension):
super().__init__(dimension=dimension)
class Node(Element):
def __init__(self, dimension):
super().__init__(dimension=dimension)
用法:构建示例元素
node = Node(dimension=[0,1,3])
line = Triangle(dimension=[0,2])
quad = Tetrahedron(dimension=[[0, 1, 5, 4], [5, 1, 2, 6], [6, 2, 3, 7], [7, 3, 0, 4], [4, 5, 6, 7]])
新未来元素,仅显示class Element
可以扩展:
# New future dimensions - No changes to class Element() required
class FutureNodTriTet(Element):
def __init__(self, dimension):
super().__init__(dimension=dimension)
future_NTT = FutureNodTriTet(dimension=[0, (1,3), (4,5,6)])
请评论这是否更接近您的需求。
答案 1 :(得分:0)
当说“复杂数据结构依赖”时,你可能会谈到“图形”,你是否仔细检查现有的graph theory是否适合你的需求? (如“路线问题”)