Python 设计复杂的数据结构';依赖
我正在设计一个有限元库。对于给定的问题,使用的有限元网格可以有不同尺寸的元素(例如四面体和三角形),也可以组合相同尺寸的不同元素(例如四面体和六面体)。因此,我需要一个存储有限元信息的数据结构。最基本的信息是元素的连接性(定义元素的节点ID)。例如,我需要以某种方式存储三角形元素4连接到节点5、6和10 我的第一次尝试是创建一个索引为维度(0、1、2或3)并存储字典的列表。这些字典有字符串键(标识符),值是numpy数组(每行表示一个元素连接)。我需要这样做,因为给定维度的numpy数组根据字符串标识符具有不同的形状 这是一节课:Python 设计复杂的数据结构';依赖,python,design-patterns,Python,Design Patterns,我正在设计一个有限元库。对于给定的问题,使用的有限元网格可以有不同尺寸的元素(例如四面体和三角形),也可以组合相同尺寸的不同元素(例如四面体和六面体)。因此,我需要一个存储有限元信息的数据结构。最基本的信息是元素的连接性(定义元素的节点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(四边形)维度的元素。当提到“复杂数据结构的依赖关系”时,您可能会提到“图形”,您是否仔细检查了现有的元素是否符合您的需要?(如“路线问题”)
评论:该设计违背了程序的逻辑结构
我使用了给定的元素数据示例,并没有期望一下子得到全部信息
注释:每个元素都有一个唯一的维度
(三角形的尺寸始终为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]])
新的Future元素,仅显示类元素
可以扩展:
# 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)])
如果这更接近您的需要,请发表评论。可能有助于理解您最初为什么设计这样的数据结构。你在解决什么问题?我正在创建一个有限元库。这些numpy数组中的每一行都是元素连接(定义元素的节点ID)。对于给定的问题,使用的有限元网格可以有不同尺寸的元素(例如四面体和三角形),也可以组合相同尺寸的不同元素(适用于四面体和六面体的示例。但第一个数据结构仅处理元素的连接性。每个元素还指定了材质属性(我需要另一个数据结构来存储材质),其他数据也一样。请为您的问题提供一些显示更改的数据,一个适用于给定的
类
,另一个不适用。我的第一次尝试失败,缺少ma.MaskedArray
,它来自何处。@stovfl我不理解您的请求。但我发现您的尝试失败可能是因为这个类还可以处理屏蔽数组。所以你必须将numpy.ma导入为ma
。我将编辑我的问题。请阅读我要求的内容:我非常熟悉图形,这些绝对不是我需要的数据结构。谢谢你的回答。虽然很有趣,但设计与逻辑结构相反每个元素都有一个唯一的维度(三角形总是维度2,四面体总是维度3,节点维度0)。我设计的结构工作得很好。但是,正如我在问题中所说的,当我修改数据结构(例如添加元素)时,会出现问题,因为所有数据都是分散的(材料保存在不同的数据结构中)。我想我需要的是将数据保存在一起。@aaragon:更新了我对你评论的回答