유한 요소 행렬에 대한 희소성 구조 계산


13

질문 : 유한 요소 행렬의 희소 구조를 정확하고 효율적으로 계산하기 위해 어떤 방법을 사용할 수 있습니까?

정보 : 저는 2 중 라그랑주 단위로 Galerkin의 방법을 사용하고 C로 작성하고 희소 행렬 저장 및 KSP 루틴에 PETSc를 사용하여 포아송 압력 방정식 솔버를 작업하고 있습니다. PETSc를 효율적으로 사용하려면 전역 강성 매트릭스를위한 메모리를 미리 할당해야합니다.

현재 행당 0이 아닌 수를 다음과 같이 추정하기 위해 모의 어셈블리를 수행하고 있습니다 (의사 코드)

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

그러나 일부 노드-노드 상호 작용이 여러 요소에서 발생할 수 있기 때문에 nnz를 과대 평가합니다.

내가 찾은 i, j 상호 작용을 추적하려고 시도했지만 많은 메모리를 사용하지 않고이 작업을 수행하는 방법을 잘 모르겠습니다. 또한 노드를 반복하고 해당 노드를 중심으로 한 기본 함수의 지원을 찾을 수 있지만 각 노드의 모든 요소를 ​​검색해야하므로 비효율적입니다.

나는 발견 특히 썼다 스테파노 M에서, 몇 가지 유용한 정보를 포함 최근의 질문에,

내 조언은 파이썬이나 C에서 그것을 구현하여 일부 그래프 이론적 개념을 적용하는 것입니다. 목록 또는 키 사전이 일반적으로 선택됩니다.

이에 대한 자세한 내용과 리소스를 찾고 있습니다. 나는 많은 그래프 이론을 알지 못했고, 유용 할 수있는 모든 CS 트릭에 익숙하지 않습니다 (수학적 측면에서 접근하고 있습니다).

감사!

답변:


5

내가 찾은 i, j 상호 작용을 추적하려는 아이디어는 효과가 있다고 생각합니다. 이것이 여러분과 Stefano M이 말하는 "CS 트릭"이라고 생각합니다. 이것은 리스트 형식 목록으로 희소 행렬을 구성합니다 .

CS가 얼마나 있는지 잘 모르므로 이것이 이미 알려진 경우 사과드립니다. 링크 된 목록 데이터 구조에서 모든 항목은 항목과 그 이전 항목에 대한 포인터를 저장합니다. 항목을 추가하고 삭제하는 것이 저렴하지만 항목을 찾기가 쉽지는 않습니다. 모든 항목을 살펴 봐야 할 수도 있습니다.

따라서 각 노드 i에 대해 링크 된 목록을 저장합니다. 그런 다음 모든 요소를 ​​반복합니다. 두 개의 노드 i와 j가 연결되어 있으면 i의 연결된 목록으로 이동합니다. j가 없으면 목록에 추가하고 j를 j의 목록에 추가하십시오. 순서대로 추가하면 가장 쉽습니다.

목록 목록을 채운 후에는 이제 매트릭스의 각 행에서 0이 아닌 항목의 수를 알 수 있습니다. 이는 해당 노드 목록의 길이입니다. 이 정보는 PETSc의 행렬 데이터 구조에서 희소 행렬을 미리 할당하는 데 필요한 것입니다. 그런 다음 더 이상 필요하지 않으므로 목록 목록을 비울 수 있습니다.

그러나이 방법은 각 요소에 포함 된 노드의 목록 만 있다고 가정합니다.

일부 메쉬 생성 패키지 ( 예 : 삼각형) 는 요소 목록과 포함 된 노드뿐만 아니라 삼각 측량의 모든 모서리 목록도 출력 할 수 있습니다. 이 경우 0이 아닌 항목 수를 과대 평가할 위험이 없습니다. 구간 별 선형 요소의 경우 각 모서리에 정확히 2 개의 강성 행렬 항목이 제공됩니다. 조각 별 이차 법을 사용하므로 각 모서리는 4 개의 항목으로 계산되지만 아이디어를 얻습니다. 이 경우 일반 배열을 사용하여 에지 목록을 한 번 통과하여 행당 0이 아닌 항목 수를 찾을 수 있습니다.

이 방법을 사용하면 하드 디스크에서 여분의 큰 파일을 읽어야합니다. 실제 계산이 그렇게 크지 않으면 실제로 요소 목록을 사용하는 것보다 느릴 수 있습니다. 그럼에도 불구하고, 나는 그것이 더 간단하다고 생각합니다.


감사. 사용할 수있는 엣지 목록이 있으므로 지금은 두 번째 방법을 사용할 것입니다.하지만 돌아가서 첫 번째 방법을 시도해보십시오. 연결된 목록과 같은 내 손을 더럽 히기 위해 (소개에 대한 감사합니다 ... ve는 기본 CS 클래스 만 수강했고 프로그래밍에 대한 지식을 습득하는 동안 데이터 구조와 알고리즘에 대해 알아야
할만

도와 줄 수있어서 기뻐! 나는 이것으로부터 많은 CS 지식을 얻었습니다 : books.google.com/books?isbn=0262032937-하나님의 사랑에 대한 할부 상환 분석에 대해 읽으십시오. C에서 자체 링크 목록 또는 이진 검색 트리 데이터 구조를 프로그래밍하는 것은 문제가 있습니다.
Daniel Shapero

5

메쉬를 DMPlex로 지정하고 데이터 레이아웃을 PetscSection으로 지정하면 DMCreateMatrix ()가 올바르게 사전 할당 된 행렬을 자동으로 제공합니다. 다음은 포아송 문제스토크 문제에 대한 PETSc 예입니다 .


2

공감

나는 개인적 으로이 작업을 수행하는 저렴한 방법을 알지 못하므로 단순히 숫자를 과대 평가합니다. 즉, 모든 행에 대해 상당히 큰 값을 사용하십시오.

예를 들어, 선형 8 노드 육각 요소로 구성된 완벽하게 구조화 된 메쉬의 경우 대각선 블록과 오프 대각선 블록의 행당 nnz는 dof * 27입니다. 완전하게 구조화되지 않은 자동 생성 된 16 진 메쉬의 경우 거의 dof * 54를 초과하지 않습니다. 선형 테트의 경우 dof * 30을 넘어 설 필요가 없었습니다. 모양이 매우 좋지 않거나 종횡비가 낮은 일부 메쉬의 경우 약간 더 큰 값을 사용해야 할 수도 있습니다.

페널티는 로컬 (순위) 메모리 소비가 2x-5x 사이이므로 평소보다 더 많은 계산 노드를 클러스터에서 사용해야 할 수도 있습니다.

Btw 검색 가능한 목록을 사용하려고했지만 희소 구조를 결정하는 데 걸리는 시간은 어셈블리 / 해결보다 컸습니다. 그러나 내 구현은 매우 간단했으며 가장자리에 대한 정보를 사용하지 않았습니다.

다른 옵션은 예에 표시된 것처럼 DMMeshCreateExodus와 같은 루틴을 사용하는 것 입니다.


0

모든 고유 (gi, gj) 연결을 열거하려고합니다.이 연결을 모두 (중복되지 않은) 연관 컨테이너에 배치하고 카디널리티를 계산하는 것이 좋습니다 .C ++에서는 std :: set <std :: pair <int, int>>. 의사 코드에서 "nnz [i] ++"를 "s.insert [pair (gi, gj)]"로 바꾸고 0이 아닌 마지막 수는 s.size ()입니다. O (n-log-n) 시간으로 실행해야합니다. 여기서 n은 0이 아닌 수입니다.

아마도 가능한 gi의 범위를 이미 알고 있으므로 gi 인덱스로 테이블을 "재생"하여 성능을 향상시킬 수 있습니다. 이것은 세트를 std :: vector <std :: set <int>>로 바꿉니다. "v [gi] .insert (gj)"로 채우면 0이 아닌 총 수는 모든 gi에 대한 v [gi] .size ()를 합산 한 것입니다. 이것은 O (n-log-k) 시간에 실행되어야합니다. 여기서 k는 요소 당 알 수없는 수입니다 (여러분은 6 개-hp-methods에 대해 이야기하지 않는 한 대부분의 pde 코드에 대해 상수 임).

(참고-선택한 답변에 대한 의견이 되길 원했지만 너무 길었습니다. 죄송합니다.)


0

ET×

EijT={1if dof jelement i0elsewhere
A=EETET이자형이자형
당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.