Skip to content

Laboratório 9 - Simulação Bidimensional de Dinâmica de Fluidos

Objetivo

Implementar rotinas em Assembly RISC-V para manipulação de matrizes bidimensionais e empacotamento/desempacotamento de valores.

Motivação

A dinâmica de fluidos computacional (CFD) fundamenta simulações meteorológicas, aerodinâmicas e animações gráficas realistas. Na primeira parte, analisamos a difusão simplificada em uma dimensão. Nesta etapa, estendemos o modelo para um espaço bidimensional matricial, onde cada ponto contém componentes vetoriais de velocidade horizontal (VX) e vertical (VY), além de parâmetros físicos locais.

Modelo Físico e Estrutura de Dados

Representação da Célula em Palavra de 32 Bits

Cada célula do reticulado é codificada em uma palavra única de 32 bits (word). A estrutura compactada organiza a componente de pressão/propriedade local nos bits mais significativos e os componentes vetoriais de velocidade com sinal nos bits inferiores:

| 31              20 | 19            10 | 9              0 |
+--------------------+------------------+------------------+
|      Pressure      |        VX        |        VY        |
+--------------------+------------------+------------------+
|      12 bits       |     10 bits      |     10 bits      |
+--------------------+------------------+------------------+
  • Pressure (bits 31:20): Campo escalar sem sinal de 12 bits (faixa de 0 a 4095).

  • VX (bits 19:10): Componente de velocidade horizontal com sinal em complemento de 2 (10 bits, faixa de -512 a +511).

  • VY (bits 9:0): Componente de velocidade vertical com sinal em complemento de 2 (10 bits, faixa de -512 a +511).

Nota sobre Desempacotamento e Empacotamento

Ao extrair VX e VY para registradores de 32 bits, é necessário realizar a extensão de sinal a partir do bit 9 (por exemplo, combinando slli e srai de 22 posições). Ao reempacotar valores negativos atualizados de volta na palavra de 32 bits, aplique uma máscara de 10 bits (& 0x3FF) em vx_new e vy_new antes de deslocá-los e combiná-los com or, evitando que bits 1 da extensão de sinal invadam os campos vizinhos.

Atualização por Difusão Discreta e Gradiente de Pressão

A matriz possui dimensão L x C, onde o índice de linha i (0 <= i < L) cresce de Norte para Sul (de cima para baixo) e o índice de coluna j (0 <= j < C) cresce de Oeste para Leste (da esquerda para a direita).

  • Condição de Contorno (Bordas Fixas): As células localizadas nas bordas da matriz (i = 0, i = L - 1, j = 0 ou j = C - 1) atuam como fronteiras estáticas. Elas não sofrem atualização física e devem ser copiadas integralmente e sem alterações da matriz atual para a matriz de destino a cada iteração.

  • Células Internas: Para cada célula estritamente interna na posição (i, j) (isto é, 1 <= i < L - 1 e 1 <= j < C - 1), consideram-se as quatro células ortogonalmente adjacentes (vizinhança de von Neumann):

  • Norte (north): posição (i - 1, j)

  • Sul (south): posição (i + 1, j)
  • Oeste (west): posição (i, j - 1)
  • Leste (east): posição (i, j + 1)

A atualização de cada célula interna combina a dissipação viscosa com a aceleração gerada pelo desbalanceamento de pressão local, empurrando o fluido de regiões de maior pressão para regiões de menor pressão:

1. Difusão Viscosa

A média das velocidades das quatro células vizinhas e a diferença em relação à velocidade da célula atual (i, j) são calculadas utilizando deslocamento aritmético à direita de 2 bits (srai de 2 posições, correspondente à divisão por 4 com arredondamento para \(-\infty\)):

avg_x = (vx_north + vx_south + vx_east + vx_west) >> 2
avg_y = (vy_north + vy_south + vy_east + vy_west) >> 2
difference_x = avg_x - vx_atual
difference_y = avg_y - vy_atual

O fator de amortecimento viscoso \(k\) é obtido a partir do valor global de viscosidade \(V\) (\(0 \le V \le 255\)) por meio de um deslocamento à direita de 5 bits (k = V >> 5, resultando em \(0 \le k \le 7\)). Esse fator atenua a variação de velocidade via deslocamento aritmético à direita (sra):

k = V >> 5
vx_difusao = vx_atual + (difference_x >> k)
vy_difusao = vy_atual + (difference_y >> k)

2. Força por Gradiente de Pressão

O gradiente simétrico entre células opostas acelera o fluido ao longo dos eixos cartesianos (de Oeste para Leste no eixo \(X\) e de Norte para Sul no eixo \(Y\)). Como a pressão é representada em 12 bits sem sinal (\(0\) a \(4095\)) e os vetores de velocidade operam em 10 bits com sinal (\(-512\) a \(+511\)), a diferença de pressão é atenuada por um deslocamento aritmético fixo à direita de 4 posições (srai de 4 posições):

grad_px = (pressure_west - pressure_east) >> 4
grad_py = (pressure_north - pressure_south) >> 4

3. Combinação e Saturação (Clamping)

As velocidades resultantes somam a componente de difusão à aceleração do gradiente de pressão e passam por saturação (clamping) para garantir que permaneçam estritamente dentro do intervalo representável de 10 bits em complemento de dois (-512 a +511):

vx_calc = vx_difusao + grad_px
vy_calc = vy_difusao + grad_py
vx_new = max(-512, min(511, vx_calc))
vy_new = max(-512, min(511, vy_calc))

A componente escalar Pressure da célula atual (i, j) não sofre alteração e deve ser preservada intacta nos bits mais significativos (31:20) durante a recombinação da palavra de 32 bits escrita na matriz de destino (grid_next).

Buffers Duplos (Ping-Pong Buffering)

A atualização síncrona do reticulado exige duas matrizes em memória (grid_current e grid_next). Durante uma iteração, todas as leituras (da célula atual e de seus quatro vizinhos) devem ocorrer exclusivamente em grid_current, enquanto os novos estados reempacotados (incluindo a cópia das bordas) são gravados em grid_next. Ao final de cada iteração completa sobre toda a malha, os ponteiros base das duas matrizes são alternados (swap).

Entradas e Saídas

Entrada (stdin):

  • 1ª linha: Dois inteiros separados por espaço, L C (3 <= L, C <= 64), indicando respectivamente o número de linhas e o número de colunas da matriz.

  • 2ª linha: Dois inteiros separados por espaço, T V (T >= 1, 0 <= V <= 255), correspondendo ao número total de iterações temporais e ao valor global de viscosidade.

  • Próximas L linhas: Cada linha contém C valores hexadecimais de 8 dígitos precedidos por 0x (formato 0xXXXXXXXX), separados por um espaço simples, representando o estado inicial das células daquela linha.

Saída (stdout):

  • Deve imprimir a matriz resultante após as T iterações, contendo L linhas com C valores cada.

  • Cada célula deve ser formatada em hexadecimal com exatos 8 dígitos (letras A–F maiúsculas) e prefixo 0x (0xXXXXXXXX), separados por um espaço simples entre colunas adjacentes e finalizando cada linha com uma quebra de linha (\n).

Exemplos

Caso Base (Malha 3x3, Iteração Única, Difusão Pura com k = 2)

Neste exemplo, T = 1 e V = 80 (logo k = 80 >> 5 = 2). Apenas a célula central (1, 1) possui velocidade inicial não nula (0x00019000 => Pressure = 0, VX = 100, VY = 0), enquanto todas as células da borda valem 0x00000000.

3 3
1 80
0x00000000 0x00000000 0x00000000
0x00000000 0x00019000 0x00000000
0x00000000 0x00000000 0x00000000
--------------------------------
0x00000000 0x00000000 0x00000000
0x00000000 0x00012C00 0x00000000
0x00000000 0x00000000 0x00000000

Caso de Teste (Difusão + Gradiente de Pressão com k = 2)

3 3
1 80
0x00002814 0x04005028 0x00002814
0x04005028 0x02019014 0x01005028
0x00002814 0x01005028 0x00002814
--------------------------------
0x00002814 0x04005028 0x00002814
0x04005028 0x02014C1C 0x01005028
0x00002814 0x01005028 0x00002814

Entrega

O arquivo report gerado pelo simulador deve ser submetido no Classroom da disciplina, nomeado como {RA}_lab9.report.

Warning

  • Qualquer alteração no arquivo de report será considerado fraude
  • O uso de ferramentas de IA deve ser reportado, indicando como foi utilizado e em quais partes do código.
  • Está é uma atividade individual, o qual deve ser desenvolvido individualmente, qualquer forma de cópia ou plágio será penalizada. Portanto, atividades que apresentarem semelhanças injustificadas serão atribuídas nota zero para todos os envolvidos