¿Cuáles son algunos buenos tipos de datos para el código CFD FVM centrado en células no estructurado?

12

Estoy interesado en un consejo para estructuras de datos eficientes para la exploración celular en CFD de volumen finito no estructurado basado en células.

Un ejemplo que encontré (en el código dolfyn cfd) es el siguiente (mostraré el segmento relevante) Entonces tenemos una matriz NFaces donde se almacena el número de caras para cada celda. Luego, la matriz CFace que asigna el número de cara local a la celda al número de cara 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}

El código se basa en la cara, por lo tanto, hay un tipo de datos de cara que almacena el número de serie de dos celdas que se encuentra entre Cara (k)% celda1 y Cara (k)% celda2.

Cualquier comentario sobre esto o sugerencias para un enfoque alternativo son bienvenidos

John Travolta
fuente

Respuestas:

9

La estructura que muestra es una opción común y equivalente a almacenar adyacencias de cara de celda en un formato de matriz CSR, con las celdas fantasmas de límite en un lugar especial. Sin embargo, tenga en cuenta que los métodos de FV también pueden formularse para consistir en su totalidad o casi en su totalidad en el recorrido de la cara donde cada cara se visita solo una vez (reconstruir para enfrentar el centroide / punto de cuadratura desde ambos lados, resolver el problema de Riemann, distribuir el flujo de nuevo en el residuo en las celdas ) Puede "falsificar" eso al usar su recorrido basado en celdas y omitir cualquiera de las dos celdas que están debajo de la "diagonal" en la matriz dispersa, pero una alternativa popular es almacenar(leftCell, rightCell) = support(face), en cuyo caso las caras se convierten en entidades de primera clase. Eso es útil porque normalmente necesita un lugar para almacenar puntos de cuadratura de cara (centroides), caras normales. También puede colocar partes de reconstrucción (como mínimos cuadrados) en las estructuras de datos basadas en caras. El recorrido de la cara es aparentemente amigable con la vectorización porque todos los tamaños son regulares, pero por otro lado, hay salidas superpuestas, por lo que debe organizar el recorrido para evitar colocarlo en un bucle interno. Con esta estructura de datos más orientada a las caras, es natural ordenar los números de las caras para que cada tipo de condición de límite se pueda aplicar utilizando un recorrido contiguo de caras (también amigable con la vectorización).

Si elige esta estructura de datos, recuerde ordenar las caras para que el recorrido reutilice los datos de la celda en la memoria caché tanto como sea posible. Vea cualquiera de los documentos PETSc-FUN3D para el análisis de rendimiento de pedidos faciales y optimizaciones relacionadas.

Jed Brown
fuente
Si realiza un bucle sobre las caras, necesitará obtener información de leftCell y rightCell para calcular los flujos, por ejemplo, la cara 1 tiene leftCell 1 y rightCell 10, la cara 2 tiene leftCell 6 y rightCell 31, ... saltando a través de la memoria . ¿Cómo sería eso amigable con la vectorización?
Chris
Como se mencionó anteriormente (y discutido en los documentos PETSc-FUN3D), usted ordena que las caras reutilicen el caché. El resultado es como un recorrido de celda "unilateral" en el que cada cara se visita solo una vez.
Jed Brown
3

Sé que esta pregunta ya está respondida, pero aquí hay un almacenamiento en bucle basado en una sola cara similar que se implementa en la biblioteca OpenFOAM C ++:

Cada celda tiene un índice (ID) en una lista de celdas. Se definen dos listas para todas las caras: "propietario interno de la cara" y "vecino de la cara". La longitud de ambas listas de caras corresponde al número de caras internas en la malla. El propietario de una cara será la celda con la ID más baja en la lista de celdas (opuesta para la cara vecina) Las caras fronterizas se escriben en último lugar y tienen normales orientadas hacia afuera (desde el dominio de la solución) y, por supuesto, solo una celda propietaria. El área de la cara normal está orientada para que se vea hacia afuera desde la celda del propietario hacia la celda vecina.

Esto funciona bien, por ejemplo, para el cálculo de flujo. El flujo se evalúa una vez por cara, y se agrega a la suma de caras totales para las celdas propietarias, y se deduce de las celdas vecinas (la suma / deducción se decide en función de la orientación del área de la cara normal). Las caras de límite se ordenan y almacenan en la parte inferior de la lista de caras, lo que permite que las condiciones de límite se definan como sectores de la lista de caras (etiqueta de inicio, etiqueta final del parche de límite), simplificando así la implementación de las condiciones de límite, también como una mejora de la eficiencia del proceso de actualización para las condiciones de contorno, ya que depende de la solución provista por las operaciones en las caras internas.

Dado que las caras de límite se aglomeran en parches, la comunicación entre procesos se define para parches acoplados (procesador) y se predefinen. Esto significa que tan pronto como haya un bucle sobre la malla de límites, las funciones de acceso de nivel superior evocan llamadas MPI envueltas, haciendo que dicho código se paralelice "automáticamente", si se basa en la conectividad basada en la cara explicada anteriormente.

tmarico
fuente
No hay problema, me alegra ver que esta descripción es útil para alguien ... :) ¿Estás trabajando con OpenFOAM también?
tmaric
Solía ​​hacerlo un poco en el pasado. Generalmente tiendo a alejarme de las tendencias aceptadas e intento reinventar la rueda. Ese es mi Tao.
Johntra Volta
1
Tu Tao es lo opuesto al Tao de la informática: "No reinventes la rueda". Pero puedo entenderlo, ¡es atractivo hacer cosas desde cero! :)
tmaric