Quais são alguns bons tipos de dados para código CFD FVM centrado em célula não estruturado?

12

Estou interessado em um conselho para estruturas de dados eficientes para navegação celular em CFD de volume finito baseado em célula não estruturado.

Um exemplo que encontrei (no código dolfyn cfd) é o seguinte (mostrarei o segmento relevante) Listing } Portanto, temos uma matriz NFaces em que o número de faces de cada célula é armazenado. Em seguida, a matriz CFace, que mapeia o número da face local para a célula para o número da face global.

\begin{listing}do ip=1,Ncel         ...         do j=1,NFaces(ip)           k   = CFace(ip,j)           ipp = Face(k)%cell1           inn = Face(k)%cell2           if( inn > 0 )then             ! internal\end{listing}

O código é baseado em face, portanto, existe um tipo de dados de face que armazena o número de série de duas células entre ele (Face) (%) cell1 e Face (k)% cell2.

Quaisquer comentários ou sugestões para abordagens alternativas são bem-vindos.

John Travolta
fonte

Respostas:

9

A estrutura que você mostra é uma escolha comum e equivalente ao armazenamento de adjacências da face da célula em um formato de matriz CSR, com as células fantasmas de limite em um local especial. No entanto, observe que os métodos de FV também podem ser formulados para consistir total ou quase totalmente na travessia da face, onde cada face é visitada apenas uma vez (reconstrua para o ponto centróide / quadratura de face de ambos os lados, resolva o problema de Riemann, distribua o fluxo de volta ao resíduo nas células ) Você pode "fingir" isso usando sua passagem por célula e ignorando duas células abaixo da "diagonal" na matriz esparsa, mas uma alternativa popular é armazenar(leftCell, rightCell) = support(face), nesse caso, as faces se tornam entidades de primeira classe. Isso é útil porque você normalmente precisa de um local para armazenar pontos de quadratura da face (centróides), normais da face. Você também pode colocar partes de reconstrução (como mínimos quadrados) nas estruturas de dados baseadas em face. O deslocamento da face é aparentemente favorável à vetorização, porque todos os tamanhos são regulares, mas, por outro lado, existem saídas sobrepostas; portanto, você precisa organizar o deslocamento para evitar colocá-lo em um loop interno. Com essa estrutura de dados mais voltada para a face, é natural ordenar os números das faces para que cada tipo de condição de contorno possa ser aplicado usando uma passagem contígua das faces (também compatível com a vetorização).

Se você escolher essa estrutura de dados, lembre-se de classificar as faces para que o percurso reutilize os dados da célula no cache o máximo possível. Consulte qualquer um dos documentos PETSc-FUN3D para análise de desempenho de pedidos de faces e otimizações relacionadas.

Jed Brown
fonte
Se você percorrer as faces, precisará obter informações de um leftCell e rightCell para calcular os fluxos, digamos que a face 1 tenha leftCell 1 e rightCell 10, a face 2 tenha leftCell 6 e rightCell 31, ... pulando a memória . Como isso seria amigável com a vetorização?
22412 chris
Como mencionado acima (e discutido nos documentos PETSc-FUN3D), você solicita que as faces reutilizem o cache. O resultado é como uma passagem de célula "unilateral" na qual cada face é visitada apenas uma vez.
Jed Brown
3

Sei que esta pergunta já foi respondida, mas aqui está um armazenamento em loop baseado em uma única face, implementado na biblioteca OpenFOAM C ++:

Cada célula possui um índice (ID) em uma cellList. Duas listas são definidas para todas as faces: "proprietário interno da face" e "vizinho da face". O comprimento de ambas as listas de faces corresponde ao número de faces internas na malha. Um proprietário de rosto será a célula com o ID mais baixo na lista de células (ao contrário do vizinho do rosto). As faces de limite são escritas por último e possuem normais orientados para o exterior (do domínio da solução) e, é claro, apenas uma célula proprietária. A área da face normal é orientada de modo a olhar para fora da célula proprietária para a célula vizinha.

Isso funciona bem para, por exemplo, cálculo de fluxo. O fluxo é avaliado uma vez por face e é adicionado à soma do total de faces das células proprietárias e deduzido das células vizinhas (a soma / dedução é decidida com base na orientação da área da face normal). As faces de limite são classificadas e armazenadas na parte inferior da lista de faces, permitindo que as condições de contorno sejam definidas como fatias da lista de faces (etiqueta inicial, etiqueta final da amostra), simplificando assim a implementação das condições de fronteira, bem como como eficiência inhancing do processo de atualização para as condições de contorno, uma vez que depende da solução fornecida pelas operações nas faces internas.

Como as faces de limite são aglomeradas em patches, a comunicação entre processos é definida para patches acoplados (processadores) e predefinidos. Isso significa que, assim que houver um loop na malha de limite, as funções de acesso de nível superior acionam chamadas MPI agrupadas, tornando esse código "automaticamente" paralelizado, se depender da conectividade baseada em face explicada acima.

tmaric
fonte
Não tem problema, fico feliz em ver que essa descrição é útil para alguém .. :) Você também está trabalhando com o OpenFOAM?
tmaric 6/12/12
Eu costumava, um pouco no passado. Geralmente, costumo ficar longe das tendências aceitas e tento reinventar a roda. Esse é o meu Tao.
Johntra Volta 6/12/12
1
Seu Tao é o oposto do Tao da Ciência da Computação: "Não reinvente a roda". Mas eu entendo, é atraente fazer coisas do zero! :)
tmaric 6/12/12