Tính toán cấu trúc thưa thớt cho ma trận phần tử hữu hạn


13

Câu hỏi: Những phương pháp nào có sẵn để tính toán chính xác và hiệu quả cấu trúc thưa thớt của ma trận phần tử hữu hạn?

Thông tin: Tôi đang làm việc trên một bộ giải phương trình áp suất Poisson, sử dụng phương pháp của Galerkin với cơ sở Lagrange bậc hai, được viết bằng C và sử dụng PETSc để lưu trữ ma trận thưa thớt và các thói quen KSP. Để sử dụng PETSc hiệu quả, tôi cần phân bổ trước bộ nhớ cho ma trận độ cứng toàn cầu.

Hiện tại, tôi đang thực hiện một hội thảo giả để ước tính số lượng khác không trên mỗi hàng như sau (mã giả)

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

Tuy nhiên, điều này đánh giá quá cao nnz vì một số tương tác nút-nút có thể xảy ra trong nhiều yếu tố.

Tôi đã cân nhắc việc cố gắng theo dõi những tương tác mà tôi đã tìm thấy, nhưng tôi không chắc làm thế nào để làm điều này mà không sử dụng nhiều bộ nhớ. Tôi cũng có thể lặp qua các nút và tìm sự hỗ trợ của hàm cơ sở tập trung tại nút đó, nhưng sau đó tôi phải tìm kiếm tất cả các phần tử cho mỗi nút, có vẻ không hiệu quả.

Tôi tìm thấy này câu hỏi gần đây, trong đó có một số thông tin hữu ích, đặc biệt là từ Stefano M, người đã viết

Lời khuyên của tôi là triển khai nó trong python hoặc C, áp dụng một số khái niệm lý thuyết biểu đồ, tức là coi các phần tử trong ma trận là các cạnh trong biểu đồ và tính toán cấu trúc thưa thớt của ma trận kề. Danh sách danh sách hoặc từ điển của các khóa là lựa chọn phổ biến.

Tôi đang tìm kiếm thêm chi tiết và tài nguyên về điều này. Tôi thừa nhận không biết nhiều về lý thuyết đồ thị và tôi không quen với tất cả các thủ thuật CS có thể hữu ích (tôi đang tiếp cận vấn đề này từ phía toán học).

Cảm ơn!

Câu trả lời:


5

Ý tưởng của bạn về việc theo dõi các tương tác i, j mà bạn đã tìm thấy có thể hoạt động, tôi nghĩ đó là "trò lừa CS" mà bạn và Stefano M đang đề cập đến. Số tiền này để xây dựng ma trận thưa thớt của bạn trong danh sách định dạng danh sách .

Không chắc chắn bạn có bao nhiêu CS vì vậy tôi xin lỗi nếu điều này đã được biết đến với bạn: trong cấu trúc dữ liệu danh sách được liên kết , mỗi mục lưu trữ một con trỏ tới mục sau nó và mục trước. Thật rẻ khi thêm và xóa các mục từ, nhưng không đơn giản để tìm các mục trong đó - bạn có thể phải xem qua tất cả chúng.

Vì vậy, đối với mỗi nút i, bạn lưu trữ một danh sách được liên kết. Sau đó, bạn lặp qua tất cả các yếu tố; nếu bạn tìm thấy hai nút i và j được kết nối, bạn hãy tìm trong danh sách được liên kết của tôi. Nếu j chưa có ở đó, bạn thêm nó vào danh sách, và tương tự thêm i vào danh sách của j. Thật dễ dàng nếu bạn thêm chúng theo thứ tự.

Khi bạn đã điền danh sách danh sách của mình, bây giờ bạn sẽ biết số lượng mục nhập khác không trong mỗi hàng của ma trận: đó là độ dài của danh sách của nút đó. Thông tin này chính xác là những gì bạn cần để phân bổ một ma trận thưa thớt trong cấu trúc dữ liệu ma trận của PETSc. Sau đó, bạn có thể giải phóng danh sách danh sách của mình vì bạn không cần nó nữa.

Tuy nhiên, cách tiếp cận này giả định rằng tất cả những gì bạn có là danh sách các nút mà mỗi phần tử chứa.

Một số gói tạo lưới - ví dụ Tam giác - có thể xuất ra không chỉ một danh sách các phần tử và các nút mà chúng chứa, mà còn là danh sách của mọi cạnh trong tam giác của bạn. Trong trường hợp đó, bạn không có nguy cơ đánh giá quá cao số lượng mục nhập khác không: đối với các phần tử tuyến tính từng phần, mỗi cạnh cung cấp cho bạn chính xác 2 mục nhập ma trận độ cứng. Bạn đang sử dụng phương pháp bậc hai piecewise, vì vậy mỗi cạnh được tính cho 4 mục, nhưng bạn có ý tưởng. Trong trường hợp đó, bạn có thể tìm thấy số lượng mục nhập khác không trên mỗi hàng với một lần đi qua danh sách cạnh bằng một mảng thông thường.

Với cách tiếp cận đó, bạn phải đọc qua một tệp lớn hơn từ đĩa cứng, điều này thực sự có thể chậm hơn so với sử dụng danh sách thành phần nếu tính toán thực tế của bạn không lớn. Tuy nhiên, tôi nghĩ rằng nó đơn giản hơn.


Cảm ơn. Tôi có sẵn một danh sách cạnh, vì vậy tôi có thể sẽ sử dụng phương pháp thứ hai của bạn ngay bây giờ, nhưng tôi có thể quay lại và thử phương pháp đầu tiên, chỉ để làm bẩn tay tôi với các danh sách được liên kết và như vậy (cảm ơn vì phần giới thiệu ... Tôi ' tôi chỉ học một lớp CS cơ bản và trong khi tôi biết lập trình, tôi không biết nhiều về cấu trúc dữ liệu và thuật toán)
John Edwardson

Vui vẻ giúp đỡ! Tôi đã chọn được rất nhiều kiến ​​thức về CS của mình từ đây: Books.google.com/books?vdn=0262032937 - vì tình yêu của Chúa, hãy đọc về phân tích khấu hao. Lập trình danh sách liên kết của riêng bạn hoặc cấu trúc dữ liệu cây tìm kiếm nhị phân trong C là giá trị rắc rối.
Daniel Shapero

5

Nếu bạn chỉ định lưới của bạn là DMPlex và bố cục dữ liệu của bạn dưới dạng Vật nuôi, thì DMCreateMatrix () sẽ tự động cung cấp cho bạn ma trận được phân chia chính xác. Dưới đây là các ví dụ của PETSc cho Bài toán PoissonBài toán Stokes .


2

Nâng cao

Cá nhân tôi không biết bất kỳ cách rẻ tiền nào để làm điều này vì vậy tôi chỉ đơn giản là đánh giá quá cao con số tức là sử dụng một giá trị hợp lý lớn cho tất cả các hàng.

Ví dụ, đối với một lưới có cấu trúc hoàn hảo được làm bằng các phần tử hex 8 nút tuyến tính, nnzs trên mỗi hàng trong cả hai khối chéo và tắt là dof * 27. Đối với hầu hết các lưới hex được tạo tự động hoàn toàn không có cấu trúc, số lượng hiếm khi vượt quá dof * 54. Đối với các vòi tuyến tính, tôi chưa bao giờ có nhu cầu vượt quá dof * 30. Đối với một số mắt lưới có các yếu tố tỷ lệ khung hình thấp / hình dạng rất xấu, bạn có thể phải sử dụng các giá trị lớn hơn một chút.

Hình phạt là mức tiêu thụ bộ nhớ cục bộ (trên xếp hạng) nằm trong khoảng từ 2x-5x, do đó bạn có thể phải sử dụng nhiều nút tính toán trên cụm của mình hơn bình thường.

Btw Tôi đã thử sử dụng các danh sách có thể tìm kiếm nhưng thời gian để xác định cấu trúc thưa thớt hơn nhiều so với lắp ráp / giải quyết. Nhưng việc thực hiện của tôi rất đơn giản và không sử dụng thông tin về các cạnh.

Tùy chọn khác là sử dụng các thói quen như DMMeshCreateExodus như trong ví dụ này .


0

Bạn đang tìm cách liệt kê tất cả các kết nối (gi, gj) duy nhất, trong đó đề xuất đặt tất cả chúng vào một thùng chứa kết hợp (không trùng lặp) và sau đó đếm số lượng thẻ của nó - trong C ++, đây sẽ là một cặp std :: set <std :: <int, int >>. Trong mã giả của bạn, bạn sẽ thay thế "nnz [i] ++" bằng "s.insert [cặp (gi, gj)]", và sau đó số nonzeros cuối cùng là s.size (). Nó sẽ chạy trong thời gian O (n-log-n), trong đó n là số lượng khác không.

Vì có thể bạn đã biết phạm vi của gi có thể, bạn có thể "chơi" bảng theo chỉ số gi để cải thiện hiệu suất. Điều này thay thế tập hợp của bạn bằng một std :: vector <std :: set <int >>. Bạn điền vào đó với "v [gi] .insert (gj)", sau đó tổng số lượng khác không đến từ tổng v [gi] .size () cho tất cả các gi. Điều này sẽ chạy trong thời gian O (n-log-k), trong đó k là số lượng ẩn số cho mỗi phần tử (sáu đối với bạn - về cơ bản là hằng số cho hầu hết các mã pde, trừ khi bạn nói về phương pháp hp).

(Lưu ý - muốn đây là nhận xét về câu trả lời đã chọn, nhưng quá dài - xin lỗi!)


0

ET×

ETôijT= ={1Tôif dof jetôiement Tôi0etôiSewhere
Một= =EETETETE
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.