Você está na página 1de 14

Universidade de Brasília

APÊNDICE A

APÊNDICE A - CÓDIGO DE IMPLEMENTAÇÃO DO MODELO LATTICE
BOLTZMANN COM OPERADOR DE COLISÃO BGK
O código implementado nesta dissertação foi baseado no trabalho realizado anteriormente
pelo professor Raúl Durand, co-orientador desta dissertação. Este código foi escrito na
linguagem Python, comentários nesta linguagem são antecedidos pelo símbolo # e são
escritos em inglês evitando caracteres especiais como acentos. A seguir apresenta-se o código
com comentários traduzidos ao português.
""" Modulo LBM: Contém o LBM com operador de colisão BGK e tempo de
relação único em uma malha d2q9, condições de contorno de Zou e He
(1997)"""
# Importar funções matemáticas para cálculos
try: from numpypy import empty
except: pass
from numpy import empty
# Pesos de ponderação dos vetores de malha
w = [4.0 /9.0,1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0, 1.0 / 9.0,
1.0 / 36.0, 1.0 / 36.0, 1.0 / 36.0, 1.0 / 36.0]
# Direções dos vetores de velocidade
cx = [0, 1, 0, -1, 0, 1, -1, -1, 1]
cy = [0, 0, 1, 0, -1, 1, 1, -1, -1]
# Definição da função de equilíbrio
def eq_fun(i, rho, vx, vy, fx=0.0, fy=0.0, tau=0.0):
vx = vx + tau * fx / rho
vy = vy + tau * fy / rho
uc = vx * cx[i] + vy * cy[i]
uu = vx ** 2 + vy ** 2
feq = w[i] * rho * (1.0 + 3.0 * uc + 4.5 * uc * uc - 1.5 * uu)
return feq
# Definição da classe célula
class Cell():
def __init__(self):
self.posi = 0 #Posição
self.posj = 0
self.vx = 0.0 #Velocidades
self.vy = 0.0
self.fx = 0.0
self.fy = 0.0
self.rho = 0.0 # Densidade
self.F = [] # Funções de distribuição
self.is_solid = 0 # Definição de nó sólido
self.has_vel_bc = False # Condições de contorno
self.vx_bc = 0.0
self.vy_bc = 0.0
self.has_rho_bc = False
self.rho_bc = 0.0

105

top = CltCell() Células nos contornos self.vx = vx self.set_dens_bc(rho) def set_state(self. vx.0): for i in range(9): self.0. vx.is_solid = 1 # Métodos de condição de contorno no nó def set_vel_bc(self.left = CltCell() self.0): for c in self: c.ny = ny self.rho = rho self. fy. vy=0.set_vel_bc(vx.tmpF = empty((nx. nx. rho=0. tau) self.pvel_cells = CltCell() # List of BC cells 106 . vy=0.set_state(rho.rho_bc = rho # Definição da classe grupo de células.0.0): """Sets constant pressure BC""" self.0. rho.vx_bc = vx self.is_solid = 1 def set_vel_bc(self. fy=0. rho=0.0.rho = self. ny): self.0.ny.cells = CltCell() # Lista de todas as células self. fx. fx=0.0. fx=0.0.ny.0. vy) def set_dens_bc(self.bottom = CltCell() self. tau) # Definição da classe malha class Lattice(): def __init__(self. vy.0.right = CltCell() self.0): for c in self: c. tau=0. vx=0.F[i] = eq_fun(i. rho=0. vy.solids = CltCell() # List of solid cells self.vy = self.F = empty((nx.9)) # Função de distribuição self. vx=0. inicialização e condições de contorno class CltCell(list): def set_solid(self): for c in self: c.vy = vy # Método de definição de um nó como sendo sólido def set_solid(self): self.9)) # Função de distribuição tem self.nx = nx self.has_vel_bc = True self.0.0.vx = self. vx=0.0): self.0): for c in self: c. vy=0. tau=0.vy_bc = vy def set_dens_bc(self. vy=0. fx.Universidade de Brasília APÊNDICE A # Método para Inicialização das funções de distribuição def set_state(self.0. rho=0. fy.has_rho_bc = True self. fy=0. vx=0.

nx): for j in range(self.append(c) if j == ny .posj = j c.0): for c in self.cells[s] # Método para inicializar as funções de distribuição no domínio def set_state(self.F c. rho=0. r): for i in range(self.posi = i c. y.0 # Inicialização das funções distribuição para zero for j in range(ny): for i in range(nx): c = Cell() c.cell_ij(i.vx = (f[0] * cx[0] + f[1] * cx[1] + f[2] * cx[2] + f[3] * cx[3] + f[4] * cx[4] + f[5] * cx[5] + f[6] * cx[6] + f[7] * cx[7] + f[8] * cx[8]) / c.Universidade de Brasília APÊNDICE A self.append(c) # Lista de nós no contorn0 if i == 0: self.is_solid: continue f = c. vy.0. j): s=j*self. fx.bottom. tau=0.1: self. vx=0.y) ** 2 if cir <= r ** 2: self.F 107 .posi == self. fx=0.set_solid() # Metodo para calcular as variáveis macroscópicas def update(self): for c in self.1: self. fy.0 self.j.cells: if c.tau = 0.fy = 0.5 # Realaxation parameter self.vy = (f[0] * cy[0] + f[1] * cy[1] + f[2] * cy[2] + f[3] * cy[3] + f[4] * cy[4] + f[5] * cy[5] + f[6] * cy[6] + f[7] * cy[7] + f[8] * cy[8]) / c.0.append(c) if j == 0: self.rho c. vy=0.nx+i return self. i.0.set_state(rho.1: # Velocidade contorno direito f = c.top.right. fy=0.append(c) # Método para mostrar uma célula na malha def cell_ij(self.0.cells: c.rho = sum(f) c.cells.fx = 0. tau) # Método para definer regiões circulares sólidas def solid_circle(self.0.:] self. x.x) ** 2 + (j .pvel_cells: if c.prho_cells = CltCell() self.append(c) if i == nx .j). vx.ny): cir = (i .is_solid: continue if c.F[i.nx .rho # Método para aplicar condições de contorno de Zou e He (1997) def apply_bc(self): for c in self.F = self.left.

0.f[4]) f8 = f[8] = f[6] + (1.is_solid: continue if c.0) * rho * vx f5 = f[5] = f[7] + (1.0 / 6.rho = c.Universidade de Brasília APÊNDICE A vx = c.vy_bc rho = c.vx = c.5 * (f[1] .0) * rho * vx .F vx = c.0 / 6.(1.0 / 3.1: # Velocidade contorno superior f = c.1: # Pressão contorno direito f = c.vx) f1 = f[1] = f[3] + (2.f[3]) for c in self.5 * rho * vy .0 + vy) f[4] = f[2] .vx = c.vx = c.(1.0.posj == self.0 / 6.rho = (f[0] + f[1] + f[3] + 2.0 / 3.posi == self.posi == 0: # Velocidade contorno esquerdo f = c.5 * rho * vx .0 * (f[1] + f[5] + f[8])) / (1.0 + (f[0] + f[2] + f[4] + 2.nx .0) * rho * vy .0) * rho * vx + 0.rho = (f[0] + f[2] + f[4] + 2.0 .vy = 0.0) * rho * vy f[7] = f[5] .(2.0) * rho * vy f[5] = f[7] + (1.0.5 * rho * vx .vx_bc vy = c.0 / 3.vx = .(1.5 * rho * vx + 0.0) * rho * vx + 0.vy = c.0.0 * (f[1] + f[5] + f[8])) / rho c.vx_bc vy = c.5 * (f[2] .f[4]) f[7] = f[5] .(1.vy = c.0 f[3] = f[1] .0 * (f[2] + f[5] + f[6])) / (1.vy_bc rho = c.posj == 0: # Velocidade contorno inferior f = c.0 / 6.5 * rho * vy .0) * rho * vy + 0.F vx = c.5 * (f[2] .0) * rho * vy + 0.0 / 6.0 + vx) f[3] = f[1] .1.vy = c.5 * (f[1] .vx = c.(1.5 * rho * vy + 0.f[3]) f[8] = f[6] .0) * rho * vx f[6] = f[8] .vy) f[2] = f[4] + (2.0) * rho * vx f[6] = f[8] .(2.0) * rho * vx .0.f[3]) f[6] = f[8] + (1.(2.0 / 3.5 * (f[2] .vy_bc rho = c.5 * (f[2] f[4]) f[7] = f[5] .5 * rho * vy + 0.rho = (f[0] + f[1] + f[3] + 2.5 * (f[2] .0 / 6.0.0 / 6.5 * (f[1] .prho_cells: if c.vx_bc vy = c.f[3]) if c.f[4]) if c.0 * (f[3] + f[6] + f[7])) / (1.rho_bc vx = c.0 / 6.0.0 / 6.5 * (f[2] f[4]) 108 .0 / 3.0 * (f[4] + f[7] + f[8])) / (1.0) * rho * vy .0) * rho * vx + 0.f[4]) if c.F rho = c.0 / 6.ny .5 * (f[1] .0.F vx = c.0) * rho * vx .5 * rho * vx + 0.0 .vx_bc vy = c.vy_bc rho = c.0.(1.rho = (f[0] + f[2] + f[4] + 2.vy = c.

0 / 6.posi == 0: # Pressão contorno esquerdo f = c.posj == self. c.vx = 0. f[8] = f[8].0 f[2] = f[4] + (2.0) * rho * vx . f[4] = f[4].0 / 6. f[6] 109 . tau) f[i] = (1.rho = c.0) * rho * vy f[5] = f[7] + (1. fy fEq = eq_fun(i.ny .(f[0] + f[1] + f[3] + 2.5 * (f[2] f[4]) f[8] = f[6] + (1.(1.rho. fx.posj == 0: # Pressão contorno inferior f = c. f[1] f[2].F rho = c.0.5 * (f[1] f[3]) f[8] = f[6] .0.0) * rho * vy f[7] = f[5] .rho_bc vy = c.cells: if c.0 / 3.rho = c.F f[1].1: # Pressão contorno superior f = c.vx = 0. c.5 * (f[1] f[3]) # Método para executar o passo de colisão def collide(self): for c in self.F rho = c.vx.5 * (f[1] f[3]) f[6] = f[8] + (1.0) * rho * vx f[5] = f[7] + (1.(f[0] + f[2] + f[4] + 2.0 * (f[3] + f[6] + f[7])) / rho c.0) * rho * vy .0 .0 / 6. c.rho = c.vy = 0. fy.0 / 6.0) * rho * vx + 0.tau fx = self.0 / tau) * f[i] + fEq / tau def bounce_back(self): # Condição de reflexão para nós sólidos for c in self.rho_bc vy = c.0 / 6.vx = 1.0 / 3.0.is_solid: continue for i in range(9): f = c. f[5] f[6].5 * (f[2] f[4]) if c.0) * rho * vy + 0.vy = .(2.solids: f = c.1.vy = 1.0 * (f[2] + f[5] + f[6])) / rho c.fx fy = self.0 / 3. f[3] = f[3].F tau = self. f[2] f[5].1.vy.(1.0 f[4] = f[2] .5 * (f[1] f[3]) if c.0 + (f[0] + f[1] + f[3] + 2.rho_bc vx = c.Universidade de Brasília APÊNDICE A if c.0 / 6.0 f[1] = f[3] + (2.0 .0 . f[7] = f[7].0 * (f[4] + f[7] + f[8])) / rho c.0) * rho * vy + 0.F rho = c.0) * rho * vy .

vtk'.write("DATASET STRUCTURED_POINTS\n") # Dataset structure f.pvel_cells.has_rho_bc: self.:.update() self.write("SCALARS Density float\n") # Density scalar field f.F[i.rho) + "\n") f.tmpF[:.write("LOOKUP_TABLE densities\n") for c in self.cells: f.nx idx_j = (j + cy[k]) % self.write("DIMENSIONS " + str(nx) + " " + str(ny) + " " + str(1) + "\n") f. nit=1.write("SCALARS Geom float\n") # Solid cells f.write("TimeStep = " + str(nout) + "\n") # Header f.write(str(c.i.vy) + " 0.is_solid: self.k] self.write(nout) nout = nout+1 # Método escrever arquivos de saída em formato vtk def write(self.write("ORIGIN 0 0 0 \n") f.ny): for k in range(9): idx_i = (i + cx[k]) % self.solids.is_solid) + "\n") f.tmpF[idx_i.write("LOOKUP_TABLE solids\n") for c in self.cells: f.:] = self.0\n") f. if i % out == 0: self.Universidade de Brasília APÊNDICE A # Método para propagação def stream(self): for i in range(self."\r".:] # Método para solução def solve(self.apply_bc() self.0\n") # File Version f.write("ASCII\n") # Format f.append(c) if c.:.write(str(c.stream() print "it: ".ny size = nx*ny f.nx ny = self.vx) + " " + str(c.write("SPACING 1 1 1 \n") f. nout): """Writes the output files""" f = open('output'+str(nout)+'.F[:.bounce_back() self.nx): for j in range(self. k] = self.ny self.collide() self.write(str(c.close() 110 .append(c) if c.write("POINT_DATA " + str(size) + "\n") # Dataset attributes f.cells: # Identifica nós sólidos e no contorno if c.write("VECTORS Velocity float\n") # Velocity vectorial field for c in self.write("# vtk DataFile Version 3. idx_j.j. out=1): for c in self.append(c) nout = 0 for i in range(nit): self. 'w') # Escreve arquivo nx = self.has_vel_bc: self.prho_cells.cells: f.

bottom. out=N_t) 111 .set_dens_bc(rho=1.0 # Parâmetro de relaxação nu_lb = (tau .Universidade de Brasília APÊNDICE B APÊNDICE B .'\n'.N_x.0) / 2.\ 'tau:'.0) # Solução lat.0 # Reynolds number [-] # Definição de tempo de relaxação e calculo de los pâmetros de discretização tau = 1. \ 'u_lb:'.0 # Half-way BB vx = u_lb * (1 .2.'N_x:'.0.'\t'. tau.'N_t:'. vx=u_lb. tau) # Definir contorno superior e inferior como sendo sólidos lat.solve(nit=1000000.(y .0. nu_lb # Definir a malha nx = N_x ny = N_x + 2 # para incluir os nós sólidos lat = Lattice(nx. vy=0.right.'\t'.5) ** 2 / a ** 2) return vx # Definição de condição de contorno de densidade na saída lat.set_solid() lat.5) / 3 # Viscosidade do método N_x = 20 # Resolução N_t = int(N_x ** 2 / (Re * nu_lb) #Tamanho do passo de tempo u_lb = N_x/N_t # Velocidade lattice definida a priori # Imprimir parâmetros na tela print 'Re:'.0.set_solid() # Inicialização das funções de distribuição de partículas lat. '\n'.a . '\t'.'nu_lb:'.set_state(rho=1.u_lb.N_t. ny.0) # Definição de condição de contorno de velocidade na entrada def initial_vx(y): a = (ny .CÓDIGO PARA SIMULAÇÃO DE FLUXO POISEUILLE # Importar modulo lbm from flbm import * # Definição do numero de Reynolds Re = 5.top. Re.

.

0) lat. nu_lb # Definir a malha nx = N_x * 10 ny = N_x * 6 + 2 lat = Lattice(nx.set_solid() lat.0) # Definição de condição de contorno de velocidade na entrada def initial_vx(y): a = (ny .(y . r) # Inicialização das funções de distribuição de partículas lat.2.solid_circle(obsX. obsY.CÓDIGO PARA SIMULAÇÃO DE FLUXO PASSANDO POR UM CILINDRO Importar modulo lbm from flbm import * # Definição do numero de Reynolds Re = 5.5) ** 2 / a ** 2) return vx # Definição de condição de contorno de densidade na saída lat. tau. out=N_t) 113 .0.right.0.top. vx=u_lb.set_dens_bc(rho=1.u_lb.'nu_lb:'.solve(nit=1000000.set_state(rho=1. Re.Universidade de Brasília APÊNDICE C APÊNDICE C.0 # Reynolds number [-] # Definição de tempo de relaxação e calculo de los pâmetros de discretização tau = 1. '\t'. tau) # Definir contorno superior e inferior como sendo sólidos lat.0. \ 'u_lb:'.0 # Parâmetro de relaxação nu_lb = (tau .a .\ 'tau:'.'N_x:'.bottom. '\n'.0 # Half-way BB vx = u_lb * (1 .'\n'.N_x. vy=0.0) # Solução lat.03 # Velocidade lattice definida a priori N_x = int(Re * nu_lb / u_lb) # Resolução N_t = int(N_x / u_lb) #Tamanho do passo de tempo # Imprimir parâmetros na tela print 'Re:'.N_t.set_solid() # Definição do cilindro circular obsX = 2 * N_x obsY = ny/2 r = int(N_x / 2.'N_t:'.'\t'.0) / 2. ny.'\t'.5) / 3 # Viscosidade do método u_lb = 0.

.

n_y=301.:) = y .2)==0.1 . n_t=zeros(n_x.l)=1. if mod(i.:) = x .Universidade de Brasília APÊNDICE D.x) ^ 2 + (l . py(c. % Definição do raio das partículas r =15. end if x+r<0 || x-r>n_x continue end if y+r<0 || y-r>n_y continue end for k=1:n_x for l=1:n_y cir = (k . y=y+L. n_t(k. % Definição do tamanho do domínio n_x=601.1 APÊNDICE D. n_ym=round(n_y/2)+15. for i=-20:20 for j=-20:20 x=n_xm+L*i. if cir <= r^2. % Definir o centro do domínio n_xm=round(n_x/2)+15.5) L=35. y=n_ym+2*L*j.CÓDIGO PARA GERAÇÃO DE ARRANJOS DE PARTÍCULAS CIRCULARES DISTRIBUÍDAS REGULARMENTE Os códigos para geração de geometrias foram escritos e executados em Matlab ®.1)*size(n_t. end end % Cálculo da porosidade n=sum(n_t(:)==0)/(size(n_t.2)) % Escrever arquivo de dados csvwrite('L35'. end end end c=c+1.1. px(c. comentários aparecem precedidos pelo símbolo %.y) ^ 2. 115 .p). % Definição de L (Figura 5.1. c=0.n_y).

.

y=randi(n_y).j)=1. c=0. n_t(i.2 APÊNDICE D.1)*size(n_t. n_y=301. r_max=30.y) ^ 2. f=0. while n >= n_0 % Funções de distribuição de probabilidade uniforme x=randi(n_x). n_t=zeros(n_x.2)). % Cálculo da Porosidade inicial n=sum(n_t(:)==0)/(size(n_t.y)==1 f=0. if cir <= r ^ 2.j)==1 || i>=599 || i<=2.y) ^ 2. break end cir = (i . r=randi([r_min. % Definição de raio máximo e mínimo da partícula r_min=8.x) ^ 2 + (j .Universidade de Brasília APÊNDICE D. break end end end end for i=1:n_x if f==0 break end for j=1:n_y cir = (i . % Evitar posições que produzam instabilidade numéricas if n_t(i.CÓDIGO PARA GERAÇÃO DE ARRANJOS DE PARTÍCULAS CIRCULARES DISTRIBUÍDAS ALEATORIAMENTE % Definição da porosidade n_0=0.n_y). não há superposição if cir <= (r+4)^2.95. f=1. % Condição de comprimento de canal mínimo. for i=1:n_x for j=1:n_y if n_t(x.x) ^ 2 + (j . % Definição do domínio n_x=601.r_max]).2 . end end end if f==0 117 .

pr).1)*size(n_t. rr(c.:) = r. 118 .:) = x.:) = y. rx(c.2)) end end % Escrever arquivo de saída csvwrite('rn65'. ry(c.2 continue else c=c+1.Universidade de Brasília APÊNDICE D. n=sum(n_t(:)==0)/(size(n_t.