2017-04-01 108 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