Sonlu elemanlar matrisleri için seyreklik yapısının hesaplanması


13

Soru: Sonlu elemanlar matrisinin seyreklik yapısını doğru ve verimli bir şekilde hesaplamak için hangi yöntemler mevcuttur?

Bilgi: Ben Poisson Basınç Denklemi çözücü üzerinde çalışıyorum, Galerkin yöntemi kuadratik Lagrange temelli, C ile yazılmış ve seyrek matris depolama ve KSP rutinleri için PETSc kullanarak. PETSc'yi verimli bir şekilde kullanmak için, belleği global sertlik matrisi için önceden ayırmam gerekiyor.

Şu anda, aşağıdaki gibi satır başına sıfır olmayanların sayısını tahmin etmek için bir sahte derleme yapıyorum (sözde kod)

int nnz[global_dim]
for E=1 to NUM_ELTS
  for i=1 to 6
    gi = global index of i 
    if node gi is free
      for j=1 to 6
        gj = global index of j
        if node gj is free 
          nnz[i]++

Bununla birlikte, bazı düğüm-düğüm etkileşimleri birden çok öğede meydana gelebileceğinden, bu nnz'yi fazla tahmin eder.

Bulduğum i, j etkileşimlerini takip etmeye çalıştım, ancak çok fazla bellek kullanmadan bunu nasıl yapacağımdan emin değilim. Ayrıca düğümler üzerinde döngü ve bu düğümde merkezli temel işlev desteğini bulmak olabilir, ama sonra her düğüm için tüm öğeleri aramak gerekir, ki bu verimsiz görünüyor.

Bazı yararlı bilgiler içeren bu son soruyu buldum , özellikle de yazan Stefano M'den

benim tavsiyem, bazı grafik teorik kavramları uygulayarak python veya C'ye uygulamak, yani matristeki elemanları bir grafikte kenarlar olarak düşünmek ve bitişiklik matrisinin sparite yapısını hesaplamaktır. Liste veya anahtar sözlüğü listesi yaygın seçimlerdir.

Bununla ilgili daha fazla ayrıntı ve kaynak arıyorum. Kuşkusuz çok fazla grafik teorisi bilmiyorum ve yararlı olabilecek tüm CS hilelerine aşina değilim (buna matematiksel açıdan yaklaşıyorum).

Teşekkürler!

Yanıtlar:


5

Hangi i, j etkileşimlerini bulabileceğinizi takip etme fikriniz işe yarayabilir, bence bu sizin ve Stefano M'nin bahsettiği "CS hilesi" dir. Bu, seyrek matrisinizi liste biçiminde oluşturmaya eşittir .

Emin değil bu zaten sizin bilinmektedir özür dilerim yüzden ne kadar CS: Bir de bağlantılı liste veri yapısı, her giriş saklar ondan sonra giriş ve öncesinde girişine bir işaretçi. Giriş eklemek ve silmek ucuzdur, ancak içindeki öğeleri bulmak o kadar kolay değildir - hepsine bakmak zorunda kalabilirsiniz.

Yani, her i düğümü için bağlantılı bir liste saklarsınız. Sonra tüm unsurları tekrarlarsınız; i ve j'nin bağlı olduğu iki düğüm bulursanız, i'nin bağlantılı listesine bakabilirsiniz. J zaten yoksa, listeye eklersiniz ve i'yi j'nin listesine eklersiniz. Bunları sırayla eklerseniz en kolayıdır.

Liste listenizi doldurduktan sonra, artık matrisin her satırında sıfır olmayan girişlerin sayısını biliyorsunuz: bu düğümün listesinin uzunluğu. Bu bilgi, PETSc'nin matris veri yapısında seyrek bir matrisi önceden konumlandırmak için tam olarak ihtiyacınız olan şeydir. O zaman artık listeye ihtiyacınız olmadığından liste listenizi serbest bırakabilirsiniz.

Ancak bu yaklaşım, sahip olduğunuz tek şeyin her bir öğenin içerdiği düğümlerin listesi olduğunu varsayar.

Bazı örgü üretim paketleri - örneğin Üçgen - sadece elemanların listesini ve içerdikleri düğümleri değil, aynı zamanda üçgenlemenizdeki her kenarın bir listesini de çıkarabilir. Bu durumda, sıfır olmayan giriş sayısını fazla tahmin etme riski taşımazsınız: parçalı doğrusal elemanlar için, her kenar size tam olarak 2 sertlik matrisi girişi verir. Parçalı ikinci dereceden kullanıyorsunuz, bu yüzden her kenar 4 giriş için sayılıyor, ancak fikri anlıyorsunuz. Bu durumda, sıralı bir dizi kullanarak kenar listesinden bir geçişle satır başına sıfır olmayan giriş sayısını bulabilirsiniz.

Bu yaklaşımla, gerçek hesaplamanız o kadar büyük değilse, öğe listesini kullanmaktan daha yavaş olabilecek sabit diskten ekstra büyük bir dosya okumalısınız. Yine de, daha basit olduğunu düşünüyorum.


Teşekkürler. Mevcut bir kenar listesi var, bu yüzden muhtemelen ikinci yönteminizi şimdilik kullanacağım, ancak geri dönüp ilk yöntemi deneyebilirim, sadece bağlantılı listeler ve böyle ellerimi kirletmek için (giriş için teşekkürler ... '' sadece temel bir CS sınıfı aldım ve programlama konusunda
bilgili

Memnuniyetle yardım ettim! CS bilgimden birçoğunu buradan aldım: books.google.com/books?isbn=0262032937 - Tanrı sevgisi için itfa edilmiş analiz hakkında bilgi edinin. Kendi bağlantılı listenizi veya ikili arama ağacı veri yapısını C olarak programlamak zahmete değer.
Daniel Shapero

5

Kafesinizi bir DMPlex ve veri düzeninizi bir PetscSection olarak belirtirseniz, DMCreateMatrix () size otomatik olarak doğru şekilde önceden yerleştirilmiş matrisi verecektir. Poisson Problemi ve Stokes Problemi için PETSc örnekleri .


2

Upvoted

Şahsen bunu yapmanın ucuz bir yolunu bilmiyorum, bu yüzden sadece sayıyı abartmak yani tüm satırlar için oldukça büyük bir değer kullanmak.

Örneğin, doğrusal 8 düğümlü hex elemanlarından oluşan mükemmel yapılandırılmış bir ağ için, hem çapraz hem de çapraz çapraz bloklardaki satır başına nnz'ler dof * 27'dir. En tamamen yapılandırılmamış otomatik olarak oluşturulan altıgen ağlar için sayı nadiren dof * 54'ü aşıyor. Doğrusal ağlarda dof * 30'un ötesine geçme ihtiyacım olmadı. Çok kötü şekilli / düşük en boy oranı elemanlarına sahip bazı ağlar için biraz daha büyük değerler kullanmanız gerekebilir.

Ceza, yerel (sıralı) bellek tüketiminin 2x-5x arasında olmasıdır, bu nedenle kümenizde normalden daha fazla işlem düğümü kullanmanız gerekebilir.

Btw aranabilir listeler kullanmayı denedim ama sparite yapısını belirlemek için geçen zaman montaj / çözmek daha fazla oldu. Ancak uygulamam çok basitti ve kenarlar hakkında bilgi kullanmadı.

Diğer seçenek, bu örnekte gösterildiği gibi DMMeshCreateExodus gibi rutinleri kullanmaktır .


0

Tüm benzersiz (gi, gj) bağlantıları numaralandırmayı düşünüyorsunuz, bu da hepsini (çoğaltılmayan) ilişkisel bir kaba yerleştirmeyi ve ardından kardinalitesini saymayı önerir - C ++ 'da bu bir std :: set <std :: pair <int, int>>. Sahte kodunuzda, "nnz [i] ++" ifadesini "s.insert [pair (gi, gj)]" ile değiştirirsiniz ve ardından sıfır olmayan son sayı s.size () olur. O (n-log-n) zamanında çalışmalıdır, burada n sıfır olmayan sayıdır.

Muhtemelen olası gi aralığını zaten bildiğiniz için, performansı artırmak için tabloyu gi endeksi ile "gösterebilirsiniz". Bu, kümenizi bir std :: vector <std :: set <int>> ile değiştirir. Bunu "v [gi] .insert (gj)" ile doldurursanız, toplam sıfır olmayanların sayısı tüm gi'ler için v [gi] .size () toplanmasıyla gelir. Bu, O (n-log-k) zamanında çalışmalıdır; burada k, öğe başına bilinmeyen sayısıdır (sizin için altı - hp yöntemlerinden bahsetmediğiniz sürece, çoğu pde kodu için sabittir).

(Not - bunun seçilen yanıt için bir yorum olmasını istedi, ancak çok uzun oldu - üzgünüm!)


0

Times dofs boyut öğelerinin seyrek matrisinden başlayın . Matris aradığınız uzamsal desene sahip. Uygulanmasında unutmayın i tanımlanan neden daha kolaydır, bu yerine . × E T i j = { 1 i f d o f j e l e m e n t i 0 e l s e w h e r e A = EET×

EijT={1if dof jelement i0elsewhere
E T E T EA=EETETETE
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.