2017-04-01 58 views
10

Sonlu elemanlar kütüphanesi tasarlama aşamasındayım. Belirli bir problem için, kullanılan sonlu eleman örgüsü farklı boyutlarda elemanlara sahip olabilir (örneğin tetrahedra ve üçgenler) ve aynı boyuttaki farklı unsurları birleştirmek de mümkündür (örneğin tetrahedra ve hexahedra). Bu nedenle, sonlu elemanların bilgilerini saklayan bir veri yapısına ihtiyacım var. En temel bilgi, elemanların bağlantısıdır (elemanı tanımlayan düğüm kimlikleri). Örneğin, üçgen elemanın (4) düğümlerin 5, 6 ve 10'a bağlı olduğunu bir şekilde kaydetmem gerekiyor.Karmaşık veri yapısının bağımlılıklarını tasarlama

İlk denemem indeksi boyutu (0,1,2 veya 3) olan bir liste oluşturmaktı. sözlükleri depolar. Bu sözlüklerin dize anahtarları (tanımlayıcıları) vardır ve değerler, saydam dizilerdir (her satır bir eleman bağlantısını temsil eder). Bunu yapmak zorundayım çünkü belirli bir boyut için numol dizileri dize tanımlayıcılarına bağlı olarak farklı şekillere sahiptir.

Bu

sınıftır:

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) 

sınıf güzel çalışıyor ve sorunsuz belirli boyutun tüm öğeleri döngü beni tanır. Bununla birlikte, ayrı olarak depolanan her öğe ile ilişkili başka veriler de vardır, örneğin onun malzemesi. Bu nedenle, diğer veriye başvurmak için aynı veri yapısını kullanmaya karar verdim. Bu amaçla, tüm yapıyı numpy dizileri olmadan geri döndürmek için sınıfın strip işlevini kullanıyorum.

Asıl veri yapısının dinamik olduğu ve değiştirdiğimde sorun, ona bağlı olan diğer tüm yapıları değiştirmem gerekiyor. Gerçekten bu sınıfı tasarlarken yanlış yöne gittiğimi düşünüyorum. Belki de bu probleme yaklaşmanın daha basit bir yolu var mı? Numune dizilerinin yanında ek bilgi saklamayı düşündüm (örnek olarak), ama bunun iyi olup olmadığını bilmiyorum. Yazılım tasarlarken yapılan seçimler hayatımızı daha sonra sefil hale getirebilir ve şimdi bunu anlamaya başlıyorum. Yukarıdaki sınıfını kullanma

UPDATE

, bir örnek aşağıdaki gibi olabilir: veri yapısı 0 (düğüm) elemanlarını, 1 (hat) depolamak için kullanılmaktadır

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

ve 2 (dörtgen) boyutlar.

+0

Bu veri yapısını neden ilk başta böyle tasarladığınızı anlamanıza yardımcı olabilir. Hangi problemi çözüyorsun? – plalx

+0

Sonlu eleman kitaplığı oluşturuyorum. Bu numol dizilerindeki her satır, bir eleman bağlantısıdır (öğeyi tanımlayan düğüm kimlikleri). Belirli bir problem için, kullanılan sonlu eleman örgüsü farklı boyutlarda elemanlara sahip olabilir (örneğin, tetrahedra ve üçgenler) ve aynı boyuttaki farklı unsurları birleştirmek de mümkündür (örnek olarak tetrahedra ve hexahedra'ya uyar. Fakat bu ilk veri yapısı sadece elementlerin bağlanabilirlikleri: Her elemanın aynı zamanda bir malzeme özelliği (malzemelerin depolanması için başka bir veri yapısına ihtiyacım var) ve diğer veriler için de aynı şekilde atanır. – aaragon

+0

Lütfen sorunuza ** değişimini gösteren bir miktar veri verin **, bir Bu verilen "class" ile çalışır ve biri uymayan değişti. İlk denemem başarısız oldu ma.MaskedArray', nerede geldi? – stovfl

cevap

0

"Karmaşık veri yapısının bağımlılıkları" dediğinizde, muhtemelen "grafik" hakkında konuşabilirsiniz, mevcut herhangi bir graph theory gereksinimlerinizi karşılayıp karşılamadığınızı iki kez kontrol ettiniz mi?

+0

Grafiklere aşina olduğumdan daha fazlasıyım ve bunlar kesinlikle burada ihtiyacım olan veri yapısı değil. – aaragon

2

Yorum ("Güzergah sorunları" gibi): tasarım programının mantıksal yapısı aykırı.

Verilen Element verileri örneğini kullandım ve tüm resmi bir seferde almayı beklemiyordum.

Yorum: her bir elemanı, (a tetrahedron her zaman 3 ve bir düğüm boyutu 0 boyut olduğu gibi üçgen her zaman 2, boyut edilmiştir) benzersiz bir boyut sahiptir.

Maalesef, "... farklı boyutlardaki öğelerden ...". Elemanı " ile ' farklı boyutlar' Ben Öneri uyarlanmış olması

Yorum. Veri yapısı değiştirdiğinde ... sorunu (örneğin ilave elemanlar ile)

ortaya çıkar

sürece bir çözüm üzerinde düşünme edemez bu soruna, için bir Veri örnek göstermezler olarak.


Benim Öneri:

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) 

Kullanımı: En Örneğin Bina Eleman

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

Yeni Gelecek Eleman, sadece class Element göstermek uzatıldı olabilir: eğer bu

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

yorum yapın ihtiyaçlarınıza daha yakın.

+0

Cevabınız için teşekkür ederiz. İlginç olsa da, tasarım programın mantıksal yapısına aykırı. Her elemanın benzersiz bir boyutu vardır (bir üçgenin her zaman boyut 2, bir tetrahedron her zaman boyut 3 ve bir düğüm boyutu 0'dır). Tasarladığım yapı oldukça iyi çalışıyor. Ancak, soruda da belirttiğim gibi, veri yapısını (örneğin, elemanlar ekleyerek) değiştirdiğimde sorun ortaya çıkmaktadır, çünkü tüm veriler dağılmıştır (materyaller farklı bir veri yapısında tutulur). Sanırım ihtiyacım olan şey verileri bir arada tutmak. – aaragon

+0

@aaragon: Cevabınızı yorumunuza güncelledi – stovfl

İlgili konular