2017-04-01 105 views
10

我正在设计一个有限元库的过程。对于给定的问题,所使用的有限元网格可以具有不同尺寸的元素(例如四面体和三角形),并且可以组合相同尺寸的不同元素(例如四面体和六面体)。因此,我需要一个存储有限元素信息的数据结构。最基本的信息是元素的连通性(定义元素的节点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数组旁边存储额外的信息(例如元组),但我不知道这是否好。设计软件时所做的选择可能会让我们的生活过得更悲惨,现在我开始意识到这一点。

UPDATE

使用上述类,一个示例可以是如下:其中,所述数据结构已经被用来存储0(节点)的元素,1(行)

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]]))])] 

和2(四边形)尺寸。

+0

可能有助于理解你为什么最初设计了这样的数据结构。你解决什么问题? – plalx

+0

我正在创建一个有限元素库。这些numpy数组中的每一行都是元素连接(定义元素的节点ID)。对于一个给定的问题,所使用的有限元网格可以具有不同尺寸的元素(例如四面体和三角形),并且可以组合相同维度的不同元素(适用于例如四面体和六面体)。但是,该第一数据结构仅处理元素的连接性,每个元素也被分配一个材料属性(为此我需要另一个数据结构来存储材料),其他数据也是一样的 – aaragon

+0

请提供一些数据给你的问题,显示**变化**,一个它与给定的'class'一起工作,其中一个不适合我的第一次尝试失败,因为缺少'ma.MaskedArray',它出现在哪里。 – stovfl

回答

0

当说到“复杂的数据结构的依赖性”时,你可能会谈论“图”,你仔细检查过现有的graph theory是否符合你的需求? (如“路线问题”)

+0

我对图很熟悉,而且这些绝对不是我需要的数据结构。 – aaragon

2

评论:设计违背了程序的逻辑结构。

我使用了给定的Element数据示例,并没有期望一次获得整个图片。

评论:每个元件具有独特的尺寸 (三角形一直维度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)]) 

请评论,如果这是更接近您的需求。

+0

感谢您的回答。虽然有趣,但该设计违背了程序的逻辑结构。每个元素都有一个唯一的维度(三角形总是维度2,因为四面体总是维度3和维度0)。我设计的结构工作得很好。但是,正如我在问题中所说的,当我修改数据结构(例如通过添加元素)时会出现问题,因为所有数据都是分散的(材料保存在不同的数据结构中)。我想我需要的是保持数据在一起。 – aaragon

+0

@aaragon:更新了我对您评论的回复 – stovfl