Modelo Brusselator de Reação-Difusão: mudanças entre as edições

De Física Computacional
Ir para navegação Ir para pesquisar
 
(256 revisões intermediárias por 3 usuários não estão sendo mostradas)
Linha 1: Linha 1:
''' Grupo: Carolina Lenzi, Eric Naiber e Vitória Xavier '''
''' Grupo: Carolina Lenzi, Eric Naiber e Vitória Xavier '''


[[Arquivo:PosAleatoriaReduced.gif|thumb|600px|'''Figura 1:''' Variação da concentração em um recipiente de 50x50. Áreas em amarelo correspondem a uma grande quantidade de reagente U. ]]
O objetivo deste trabalho é implementar o modelo de reação-difusão Brusselator em duas dimensões, frequentemente utilizado para estudar sistemas complexos químicos e biológicos. O modelo é um sistema não linear de equações diferenciais parciais e foi proposto em 1968 por Ilya Prigogine e seus colaboradores da Universidade Livre de Bruxelas. Desde então tem sido aplicado para analisar reações oscilatórias e autocatalíticas. O método computacional utilizado para implementar o modelo foi o método FTCS (''Forward Time Centered Space'').  
 
O objetivo deste trabalho é implementar o modelo de reação-difusão Brusselator em duas dimensões, frequentemente utilizado para estudar sistemas complexos químicos e biológicos. O modelo é um sistema não linear de equações diferenciais parciais e foi proposto em 1970 por Ilya Prigogine e seus colaboradores da Universidade Livre de Bruxelas. Desde então tem sido aplicado para analisar reações oscilatórias e autocatalíticas. O método computacional utilizado para implementar o modelo foi o método FTCS (''Forward Time Centered Space'').  


==Modelo de Brusselator==  
==Modelo de Brusselator==  


[[Arquivo:GifCertoReuced.gif|thumb|500px|'''Figura 2:''' Os gráficos mostram a variação da concentração de um dos reagentes, neste caso estamos avaliando U. No gráfico da direita a quantidade do reagente U (amarelo) é maior quando o ponto atinge um mínimo local (gráfico da esquerda). No gráfico da esquerda temos a variação total das concentrações no sistema, quando o ponto está em um mínimo local temos que a equação (1.c) é satisfeita, logo gerando uma concentração maior de U no sistema. ]]
O estudo de sistemas químicos e biológicos frequentemente requer o uso de modelos que caracterizam reações de reação-difusão. Um dos modelos mais utilizados é o modelo de Brusselator, que é utilizado para descrever o mecanismo químico de reação-difusão com oscilações não lineares. <ref>J. Tyson, Some further studies of nonlinear oscillations in chemical systems, J. Chem. Phys. 58 (1973) 3919</ref>. Turing observou que quando determinadas reações são associadas a difusão, é possível obter um padrão espacial estável, e isso leva a teoria de morfogênese<ref>Turing A. M., The chemical basis of morphogenesis. 1953. Bull. Math. Biol. 52, 153, discussion 119 (1990).</ref>. Além de processos de reação-difusão, o modelo Brusselator é observado em reações enzimáticas e na física de plasma e de lasers.


O estudo de sistemas químicos e biológicos frequentemente requer o uso de modelos que caracterizam reações de reação-difusão. Um dos modelos mais utilizados é o modelo de Brusselator, que é utilizado para descrever o mecanismo químico de reação-difusão com oscilações não lineares. [J. Tyson, Some further studies of nonlinear oscillations in chemical systems, J. Chem. Phys. 58 (1973) 3919.] Turing [ref?] observou que quando determinadas reações são associadas a difusão, é possível obter um padrão espacial estável, e isso leva a teoria de morfogênese. Além de processos de reação-difusão, o modelo Brusselator é observado em reações enzimáticas e na física de plasma e de lasers.
O mecanismo de Brusselator proposto por Prigogine<ref>I. Prigogine, R. Lefever, Symmetries breaking instabilities in dissipative systems II. J. Phys. Chem. 48, 1695–1700 (1968)</ref> é dado por:  
 
O mecanismo de Brusselator proposto por Prigogine (1970) é dado por [I. Prigogine, R. Lefever, Symmetries breaking instabilities in dissipative systems II. J. Phys. Chem. 48, 1695–1700 (1968)]:  


:<math>A \to U</math>        (1.a)
:<math>A \to U</math>        (1.a)
Linha 18: Linha 14:
:<math>U \to E</math> (1.d)
:<math>U \to E</math> (1.d)


Onde U e V são as espécies químicas de interesse. Assumimos A e B em excesso para que o sistema não atinja o equilíbrio.  Esse sistema químico foi importante para o avanço na área de sistemas complexos porque possibilita o uso de modelos matemáticos de duas dimensões, já que U e V são variáveis dependentes, e admite “limit-cycle oscilations”. [ R. Lefever and G. Nicolis, Chemical instabilities and sustained oscillations, J. Theor. Biol. 30 (1971) 267.].
Onde U e V são as espécies químicas de interesse. Assumimos A e B em excesso para que o sistema não atinja o estado de equilíbrio.  Esse sistema químico foi importante para o avanço na área de sistemas complexos porque possibilita o uso de modelos matemáticos de duas dimensões, já que U e V são variáveis dependentes, e admite oscilações de ciclo limite<ref>R. Lefever and G. Nicolis, Chemical instabilities and sustained oscillations, J. Theor. Biol. 30 (1971)</ref>.


As equações diferenciais parciais associadas com o sistema Brusselator são dadas por(G. Adomian, The diffusion-Brusselator equation. Comput. Math. Appl. 29, 1–3 (1995)):
As equações diferenciais parciais associadas com o sistema Brusselator<ref>G. Adomian, The diffusion-Brusselator equation. Comput. Math. Appl. 29, 1–3 (1995)</ref> são dadas por:


:<math>\frac{\partial u}{\partial t} = a + u^2v - (b+1)u + D_u \left(\frac{\partial ^2 u}{\partial x^2} + \frac{\partial ^2 u}{\partial y^2} \right)</math>
:<math>\frac{\partial u}{\partial t} = a + u^2v - (b+1)u + D_u \left(\frac{\partial ^2 u}{\partial x^2} + \frac{\partial ^2 u}{\partial y^2} \right)</math>
:<math>\frac{\partial v}{\partial t} = bu - u^2v + D_v \left(\frac{\partial ^2 v}{\partial x^2} + \frac{\partial ^2 v}{\partial y^2}\right)</math>
:<math>\frac{\partial v}{\partial t} = bu - u^2v + D_v \left(\frac{\partial ^2 v}{\partial x^2} + \frac{\partial ^2 v}{\partial y^2}\right)</math>


onde <math>u(x, y, t)</math> e <math>v(x, y, t)</math> são as concentrações a serem investigadas em função de tempo e espaço, <math>a</math> e <math>b</math> são constantes relativas às concentrações dos reagentes A e B, e <math>D_u</math> e <math>D_v</math> constantes de difusão.
onde <math>u(x, y, t)</math> e <math>v(x, y, t)</math> são as concentrações a serem investigadas em função de tempo e espaço, <math>a</math> e <math>b</math> são constantes relativas às concentrações dos reagentes A e B, e <math>D_u</math> e <math>D_v</math> são as constantes de difusão de U e V.


A solução analítica do sistema reação-difusão Brusselator ainda não é conhecida e por isso há o interesse de explorá-la numericamente.
A solução analítica do sistema reação-difusão Brusselator ainda não é conhecida e por isso há o interesse de explorá-la numericamente.
Linha 33: Linha 29:
===Análise de ponto crítico===
===Análise de ponto crítico===


Considerando o sistema livre de difusão, quando <math>\partial x=\partial y=0</math>:
Considerando o sistema livre de difusão, quando <math>D_u = D_v = 0</math>:


:<math> \frac{du}{dt} = f(u, v) = a + u^2v - (b+1)u \qquad t < 0 \quad u(0) = U^0 </math>
:<math> \frac{du}{dt} = f(u, v) = a + u^2v - (b+1)u </math>


:<math> \frac{dv}{dt} = g(u, v) = bu - u^2v \qquad \qquad \qquad \, \, t < 0 \quad v(0) = V^0 </math>
:<math> \frac{dv}{dt} = g(u, v) = bu - u^2v </math>


 
Encontramos os pontos críticos do sistema igualando as derivadas à zero. Obtemos que o único ponto crítico é <math>(u^*, v^*) = \left ( a, \frac{b}{a} \right)</math>.
Onde <math>u = u(t)</math> e <math>v = v(t)</math> e <math>a</math> e <math>b</math> são constantes positivas e reais. A matriz jacobiana <math>J^*</math> no ponto crítico <math>(u^*, v^*)</math> é dada por
A matriz jacobiana <math>J^*</math> no ponto crítico <math>(u^*, v^*)</math> é dada por


:<math>
:<math>
J^* = \begin{bmatrix}
J^* = \begin{bmatrix}
\frac{\partial f}{\partial u} \Big |_{u^*, v^*} & \frac{\partial f}{\partial v} \Big |_{u^*, v^*} \\
\frac{\partial g}{\partial u} \Big |_{u^*, v^*} & \frac{\partial g}{\partial v} \Big |_{u^*, v^*}
\end{bmatrix}
=
\begin{bmatrix}
b-1 & a^2 \\
b-1 & a^2 \\
-b & -a^2
-b & -a^2
Linha 54: Linha 55:
:<math> \lambda ^2 + (1 - b + a^2)\lambda + a^2 = 0 </math>
:<math> \lambda ^2 + (1 - b + a^2)\lambda + a^2 = 0 </math>


Os autovalores claramente mostram dependência em <math>1-b+a^2</math> e no determinante <math>\Delta = (1-b+ a^2)^2 - 4a^2</math>. Esses autovalores governam a estabilidade do ponto crítico ou determinam a existência de um ciclo limite. As propriedades de estabilidade ou a existência de um ciclo limite estão sumarizadas na tabela abaixo, em relação a figura 1.
Os autovalores claramente mostram dependência em <math>1-b+a^2</math> e no determinante <math>\Delta = (1 - b + a^2)^2 - 4a^2</math>. Esses autovalores governam a estabilidade do ponto crítico e determinam a existência de um ciclo limite. Conforme discutido em Twizell<ref name='t'>Twizell, E. H., Gumel, A. B., & Cao, Q. (1999). Journal of Mathematical Chemistry, 26(4), 297–316 </ref>, quando <math>Re(\lambda) < 0 </math> o sistema é estável e não existe ciclo limite. Já para <math>Re(\lambda) > 0 </math> o sistema é instável e existe ciclo limite.
 
[[Arquivo:]]
 
Utilizando a teoria Hopf, é mostrado que o ponto crítico perde sua estabilidade quando A e B movem da região 2 para região 3, na figura 1, atravessando a curva <math>1-b+a^2 = 0</math>. Uma bifurcação Hopf ocorre quando ao passo que essa curva é atravessada e um ciclo limite estável existe para A e B nas regiões 1 e 2, mas não para A e B nas regiões 3 e 4.
 
Conclui-se que a curva <math>1-b+a^2 = 0</math> governa a estabilidade do sistema.
 


===Análise de ponto fixo===
===Análise de ponto fixo===


O estado estacionário do sistema pode ser encontrado igualando o coeficiente de difusão, e portanto as derivadas parciais, a zero. Percebe-se que esse sistema converge para os pontos fixos:
Ainda em Twizell<ref name='t'>Twizell, E. H., Gumel, A. B., & Cao, Q. (1999). Journal of Mathematical Chemistry, 26(4), 297–316 </ref>, foi feita a análise de ponto fixo. O único ponto fixo encontrado é <math>(u^*, v^*) = \left ( a, \frac{b}{a} \right)</math>. Manipulando a matriz Jacobiana nesse ponto e analisando os autovalores, obtém-se que a solução é atraída para o ponto <math>\left ( a, \frac{b}{a} \right)</math> se <math>1-b+a^2 > 0</math>. Caso contrário, a solução não converge.
 
:<math> u = a </math>
:<math> v = \frac{b}{a} </math>
 
Em [twizell] a manipulação da matriz jacobiana nos pontos fixos resulta nos seguintes autovalores
 
:<math>\mu_1 = \frac{1+ \frac{1}{2} \ell (1-b+a^2) - \frac{1}{4}\ell^2a^2 }{1+ \frac{1}{2} \ell (1-b+a^2) + \frac{1}{4}\ell^2a^2} </math>
 
 
:<math>\mu_2 = \frac{1 - \frac{1}{2} \ell (1-b+a^2) - \frac{1}{4}\ell^2a^2}{1+ \frac{1}{2} \ell (1-b+a^2) + \frac{1}{4}\ell^2a^2} </math>
 
Onde fica claro que os denominadores dos autovalores são sempre positivos quando <math> 1 - b + a^2 > 0</math> and <math> \ell > 0 </math>. As inequações
 
:<math> |\mu_1| < 1 \quad </math> e <math> \quad |\mu_2| < 1 </math>
 
São verdadeiras sempre que <math> 1 - b + a^2 = 0</math>. Portanto, uma condição suficiente para o ponto fixo <math>\left(a, \frac{b}{a}\right)</math> atrair a sequência gerada pelo sistema é <math> 1 - b + a^2 > 0</math>.
 
Ainda em [Twizell] o modelo reação-difusão Brusselator foi discretizado e a análise dos pontos fixos concluiu que o sistema converge para <math>u(x, t) = a</math> e <math> v(x, t)= \frac{b}{a} </math>, sendo esse o único estado estacionário do sistema.
 
Concluiu que também que o sistema apresenta estado oscilatório quando
 
:<math> 1 - b + a < 0 </math>
 
Estado em que o sistema não converge para nenhum ponto.
 


==Método FTCS==
==Método FTCS==
Linha 141: Linha 110:
onde <math>K_u = \frac{D_u \Delta t}{(\Delta s)^2}</math> e <math>K_v = \frac{D_v \Delta t}{(\Delta s)^2}</math>.
onde <math>K_u = \frac{D_u \Delta t}{(\Delta s)^2}</math> e <math>K_v = \frac{D_v \Delta t}{(\Delta s)^2}</math>.


===Análise de estabilidade do método===
===Análise de estabilidade===
 
A análise de estabilidade do método FTCS pode ser feita com a análise local de von Neumann. Para isso precisamos linearizar as equações do modelo Brusselator e escrever as soluções em modos de Fourier, da seguinte forma:
 
:<math>
\delta u_{i, j}^{n+1} = \delta u_{i, j}^n + K_u \left( \delta u_{i+1, j}^n + \delta u_{i-1, j}^n + \delta u_{i, j+1}^n + \delta u_{i, j-1}^n - 4 \delta u_{i, j}^n  \right) + \Delta t f_u \delta u_{i, j}^n + \Delta t f_v \delta v_{i, j}^n
</math>
 
:<math>
\delta v_{i, j}^{n+1} = \delta v_{i, j}^n + K_v \left( \delta v_{i+1, j}^n + \delta v_{i-1, j}^n + \delta v_{i, j+1}^n + \delta v_{i, j-1}^n - 4 \delta v_{i, j}^n  \right) + \Delta t g_u \delta u_{i, j}^n + \Delta t g_v \delta v_{i, j}^n
</math>


:<math>
{\delta u^n \choose \delta v^n} = \xi ^n e^{i(k_x i \Delta x + k_y j \Delta y)} {\delta u_0 \choose \delta v_0}
</math>


Para que o método seja estável, é preciso que <math>|\xi| < 1</math>. Após inserir as soluções nas equações linearizadas e realizar manipulações algébricas, como feito por Scholz<ref name='s'>Scholz, Christian, Morphology of Experimental and Simulated Turing Patterns, 2009, p. 27-29.</ref>, obtemos
:<math>
\xi_\pm = \frac{1}{2} \left [ \beta \pm \sqrt{\beta ^2 - 4 (\Delta t)^2 a^2 b} \right ]
</math>
onde
:<math>\beta = 2 - 4 \gamma (K_u + K_v) + \Delta t (b - 1 - a^2)</math>
e
:<math>\gamma = sin^2\left( \frac{k_x \Delta s}{2} \right) + sin^2\left( \frac{k_y \Delta s}{2} \right)</math>


Os valores <math>\Delta t = 0.01</math> e <math>\Delta s = 1</math> satisfazem a condição de estabilidade, como mostrado em Scholz<ref name='s'>Scholz, Christian, Morphology of Experimental and Simulated Turing Patterns, 2009, p. 27-29.</ref>.


==Implementação==
===Implementação===


O método foi implementado em Python, considerando <math>\Delta t = 0.1, \Delta s = 1, N_x = N_y = 50</math>, variando as constantes <math>a</math> e <math>b</math> e as condições iniciais do problema.
A seguir, o trecho do código relativo à implementação do método na linguagem Python. O código completo encontra-se no Github [https://github.com/RicGary/MetCompC/tree/main/Brusselator]


<source lang="python">
<source lang="python">
import numpy as np
# u_n, v_n -> concentracao dos reagentes no tempo n (matriz Nx x Ny)
import matplotlib.pyplot as plt
# u_n1, v_n1 -> concentracao dos reagentes no tempo n+1
import imageio
 
from random import randint
while t < t_max:


# Constantes
    for i in range(Nx):
Nx = Ny = 50
        i_e = (i - 1) % Nx # vizinho a esquerda de 0 é o da ultima posicao
Largura = 1
        i_d = (i + 1) % Nx  # vizinho a direita da ultima posicao é o zero


# Valores iniciais | Padrão de teste: U0 = 2 & V0 = 1 -> Pisca
        for j in range(Ny):
# U0 = V0 = 1 -> Fica variando as piscadas entre horizontal e vertical
            j_e = (j - 1) % Ny
u0 = 1
            j_d = (j + 1) % Ny
v0 = 2


t = 0
            # calcular u e v no tempo n+1
t_max = 30
            u_n1[i, j] = u_n[i, j] + dt * f(u_n[i, j], v_n[i, j], b) \
dt = 0.1
                        + ku * (u_n[i_e, j] + u_n[i_d, j] + u_n[i, j_e] + u_n[i, j_d] - 4 * u_n[i, j])
ds = 1
            v_n1[i, j] = v_n[i, j] + dt * g(u_n[i, j], v_n[i, j], b) \
                        + kv * (v_n[i_e, j] + v_n[i_d, j] + v_n[i, j_e] + v_n[i, j_d] - 4 * v_n[i, j])


# a = 1, b = 3
    # atualizar u_n e v_n
a = 1
    for i in range(Nx):
b = 1.7
        for j in range(Ny):
            u_n[i, j] = u_n1[i, j]
            v_n[i, j] = v_n1[i, j]
 
    t += dt
</source>


# Constantes dos reagentes e da estabilidade
==Resultados==
Du = 0.1
Esta seção se dedica ao resultados das simulações realizadas, que mostram o caráter oscilatório do Brusselator ao longo do tempo e também como se dá a difusão dos reagentes em um recipiente em duas dimensões.
Dv = 1
As constantes utilizadas foram identificadas abaixo para plotar os gráficos, exceto quando indicado o contrário.
ku = Du * dt / (ds ** 2)
kv = Dv * dt / (ds ** 2)


# Constantes para gerar o Gif
{| class="wikitable" style="margin-left: auto; margin-right: 0px;" style="text-align:center;"
gif_passo_total = 0.1 # Intervalo de tempo entre imagens
|- style="text-align:left;"
gif_passo_inicial = 0 # Inicializador
! colspan="6" style="text-align:center; font-weight:bold; font-size:medium;" | Tabela de Constantes e Valores
figura = 1 # Nome das figuras
|- style="font-weight:bold;"
fig_names = []  # Armazenando nome das figuras
| Símbolo
fig_atual = 0 # Figura atual
| Nome
fig_total = t_max / dt  # Quantia de figuras
| Valor
size = Nx - 1 # Tamanho do range
|-
plot_start = 0  # Começa a plotar a partir deste tempo
| <math>N_x</math>
| style="text-align:left;" | Dimensão analisada ao longo do eixo x
| 50
|-
| <math>N_y</math>
| style="text-align:left;" | Dimensão analisada ao longo do eixo y
| 50
|-
| <math>a</math>
| style="text-align:left;" | Constante relativa à concentração do reagente A
| 1
|-
| <math>b</math>
| style="text-align:left;" | Constante relativa à concentração do reagente B
| 1.7
|-
| <math>D_u</math>
| style="text-align:left;" | Constante de difusão do reagente U
| 0.5
|-
| <math>D_v</math>
| style="text-align:left;" | Constante de difusão do reagente V
| 1
|-
| <math>u_0</math>
| style="text-align:left;" | Concentração de u no tempo inicial (t=0)
| 1
|-
| <math>v_0</math>
| style="text-align:left;" | Concentração de v no tempo inicial (t=0)
| 1
|-
| <math>dt</math>
| style="text-align:left;" | Passo de tempo entre iterações
| 0.01
|-
| <math>ds</math>
| style="text-align:left;" | Unidade de avanço dos eixos no espaço
| 1
|-
|}


As posições das condições iniciais foram escolhidas arbitrariamente, tendo um total de 6 modos que serão explicados na sequência, sendo eles:
# Condição em formato do sinal "+".
# Condição de borda.
# Condição aleatória.
# Condição de nove pontos centrais.
# Condição da borda completa.


# Pedaço da equação sem derivada parcial
===Simulação===
def f(u, v):
Nas figuras abaixo temos a variação das concentrações dos reagentes ao longo do tempo e os diagramas de fase. Para <math>a = 1</math> e <math>b = 1.7</math> notamos que a solução do sistema converge para <math>u(t) = 1</math> e <math>v(t) = 1.7</math>. Esse resultado está de acordo com o esperado, pois o ponto <math>\left(1, 1.7\right)</math> é um ponto fixo atrator (satisfaz que <math>1-b+a^2 > 0</math>), conforme discutido na seção de análise de estabilidade do Brusselator. Notamos também, pelo diagrama de fase, que mesmo alterando as condições iniciais do problema, a solução converge para o estado estacionário.
    return a - (b + 1) * u + u * u * v




# Pedaço da equação sem derivada parcial
[[Arquivo:Sol_bru_b1.png|thumb|center|790px|'''Figura 1''': Solução do Brusselator para a = 1 e b = 1.7.]]
def g(u, v):
    return b * u - u * u * v




# vetores no tempo n
Para <math>a = 1</math> e <math>b = 3</math>, temos que <math>1-b+a^2 < 0</math>, portanto a solução do sistema não converge. O que observamos é um comportamento periódico causado pela existência do ciclo limite.
u_n = np.zeros((Nx, Ny))
v_n = np.zeros((Nx, Ny))


# vetores no tempo n+1
u_n1 = np.zeros((Nx, Ny))
v_n1 = np.zeros((Nx, Ny))


# Condicoes novas
[[Arquivo:Sol_bru_b3.png|thumb|center|790px|'''Figura 2''': Solução do Brusselator para a = 1 e b = 3.]]


"""
Podemos pensar nas funções de concentração <math>u</math> e <math>v</math> como ondas que sofrem interferência destrutiva, pois estão fora de fase. A animação abaixo mostra este comportamento, observe o reagente <math>U</math>, representado pela cor amarela, no gráfico da direita. Note que quando o ponto do gráfico da esquerda chega ao mínimo local, o valor de <math>U</math> é alto e o de <math>V</math> muito baixo, fazendo com que o gráfico da direita fique muito amarelo.
Esta parte você pode tirar as aspas para gerar uma condição inicial desejada, se quiser pode ativar todas.
A mais interessante na minha opinião é a condição em uma posição aleatória.
"""


# Condição em formato de cruz (U0)
"""
for i in range(Largura):
    # Meio
    u_n[int(Nx / 2), int(Ny / 2)] = u0


    # Laterais
[[Arquivo:AnaliseMid.gif|thumb|center|1300px|'''Figura 3''': Comportamento do reagente.]]
    #      X                  Y
    u_n[int(Nx / 2) + 1, int(Ny / 2)] = u0
    u_n[int(Nx / 2) - 1, int(Ny / 2)] = u0


    # Alturas
    #      X                  Y
    u_n[int(Nx / 2), int(Ny / 2) + 1] = u0
    u_n[int(Nx / 2), int(Ny / 2) - 1] = u0
"""


# Bordas (V0)
É interessante pensar no gráfico da esquerda como a análise em um ponto específico dentro do recipiente, por exemplo, se <math>Nx=Ny=50</math> estamos analisando o ponto <math>(10,10)</math>. Tendo isso em mente conseguimos analisar os outros 3 cantos da figura, já que, por simetria da posição inicial escolhida, os cantos são iguais.
"""for i in range(Largura):
    # Sup Esq
    v_n[0, 0] = v0


    # Sup Dir
    v_n[0, Nx - 1] = v0


    # Inf Esq
[[Arquivo:ZoomGraph.jpg|thumb|center|800px|'''Figura 4''': Análise de um ponto.]]
    v_n[Nx - 1, 0] = v0


    # Inf Dir
----
    v_n[Nx - 1, Nx - 1] = v0"""


# Aleatório, 10 lugares
===Condições Iniciais===
"""
Realizamos as simulações variando espacialmente as condições iniciais, para verificar os diferentes padrões formados pelo sistema.
for _ in range(randint(int(Nx / 5), Nx)):
 
====Condição em Formato do Sinal "+"====
 
O reagente <math>u_0</math> é distribuído no centro formando um sinal de "+".
 
[[Arquivo:CruzBorda.gif|thumb|right|338px|'''Figura 4''': Comportamento em formato de "+" para o reagente u. Para o reagente v foi utilizado a condição de borda.]]
 
<source lang="python">
 
# u_n [Nx, Ny]
 
# Centro
u_n[int(Nx / 2), int(Ny / 2)] = u0
 
 
# Lateral do sinal
#      X                  Y
u_n[int(Nx / 2) + 1, int(Ny / 2)] = u0
u_n[int(Nx / 2) - 1, int(Ny / 2)] = u0
 
 
# Altura do sinal
#      X                  Y
u_n[int(Nx / 2), int(Ny / 2) + 1] = u0
u_n[int(Nx / 2), int(Ny / 2) - 1] = u0
 
 
 
 
 
</source>
 
----
 
====Condição de borda====
 
O reagente <math>v_0</math> foi distribuído nos 4 cantos do recipiente.
 
[[Arquivo:CruzBordaB3.gif|thumb|right|338px|'''Figura 5''': Analisando u com condição de borda "+". Para o reagente v foi utilizado a condição de borda. Foi utilizado b=3 para mostrar a diferença na simulação.]]
 
<source lang="python">
 
# u_n [Nx, Ny]
 
# Sup Esq
v_n[0, 0] = v0
 
 
# Sup Dir
v_n[0, Nx - 1] = v0
 
 
# Inf Esq
v_n[Nx - 1, 0] = v0
 
 
# Inf Dir
v_n[Nx - 1, Nx - 1] = v0
 
</source>
 
----
 
====Condição aleatória====
 
Os reagentes são aleatoriamente distribuídos ao longo do recipiente, a quantidade de focos de reagente também é aleatória para <math>u_0</math> e <math>v_0</math>.
 
[[Arquivo:AleatorioResize.gif|thumb|right|360px|'''Figura 6''': Posição aleatória.]]
 
<source lang="python">
 
from random import *
 
# u_n [Nx, Ny]
 
aleatorio = randint(int(Nx / 5)
 
 
# Aleatório para u
for _ in range(aleatorio, Nx)):
     u_n[randint(0, size), randint(0, size)] = u0
     u_n[randint(0, size), randint(0, size)] = u0
for _ in range(randint(int(Nx / 5), Nx)):
    v_n[randint(0, size), randint(0, size)] = v0
"""


# Nove pontos centrais (u0)
mid = int(Nx / 2)  # Centro
mov = int(Nx / 4)  # Movendo para cima e para os lados
u_n[mid, mid] = u_n[mid + mov, mid + mov] = u_n[mid + mov, mid] = u_n[mid, mid + mov] = u_n[mid + mov, mid - mov] = u0
u_n[mid - mov, mid - mov] = u_n[mid - mov, mid] = u_n[mid, mid - mov] = u_n[mid - mov, mid + mov] = u0


# Toda a borda (v0)
# Aleatório para v
for i in range(Nx):
for _ in range(aleatorio, Nx)):
     v_n[0, i] = v0
     v_n[randint(0, size), randint(0, size)] = v0
    v_n[i, 0] = v0
    v_n[Nx - 1, i] = v0
    v_n[i, Nx - 1] = v0


# Criando listas separadas para plotar os gráficos.
</source>
lista_pu = []
lista_pv = []


# Algumas listas são extras, não precisam realmente estar ali, estão apenas para organização.
----
lista_t = []
lista_u = []
lista_v = []
lista_indices = []
indice = 0


# Plot de concentração de Nx , Ny
====Condição de nove pontos centrais====
lista_mesh_u = np.zeros((Nx, Ny))
lista_mesh_v = np.zeros((Nx, Ny))


# Calculando concentrações com FTCS
No centro divide 9 pontos igualmente espaçados de tamanho <math>N_x/4</math>, para <math>u_0</math>. Foi utilizado para <math>u_0</math> na figura 3.
while t < t_max:


    for i in range(Nx):
[[Arquivo:9PontosBorda.gif|thumb|right|384px|'''Figura 7''': Utilizando a condição de borda para v.]]
        i_e = (i - 1) % Nx  # vizinho a esquerda de 0 é o da ultima posicao
        i_d = (i + 1) % Nx  # vizinho a direita da ultima posicao é o zero


        for j in range(Ny):
<source lang="python">
            j_e = (j - 1) % Ny
            j_d = (j + 1) % Ny


            u_n1[i, j] = u_n[i, j] + dt * f(u_n[i, j], v_n[i, j]) \
# Nove pontos centrais (u0)
                        + ku * (u_n[i_e, j] + u_n[i_d, j] + u_n[i, j_e] + u_n[i, j_d] - 4 * u_n[i, j])
mid = int(Nx / 2); mov = int(Nx / 4)
            v_n1[i, j] = v_n[i, j] + dt * g(u_n[i, j], v_n[i, j]) \
                        + kv * (v_n[i_e, j] + v_n[i_d, j] + v_n[i, j_e] + v_n[i, j_d] - 4 * v_n[i, j])


            # Lista i, j
# Meio & direita
u_n[mid, mid] = u0
u_n[mid + mov, mid + mov] = u0
# Meio & esquerda
u_n[mid + mov, mid] = u0
u_n[mid, mid + mov] = u0
# Meio, p/baixo & p/lados
u_n[mid + mov, mid - mov] = u0
u_n[mid - mov, mid - mov] = u0
# Meio, p/cima & p/lados
u_n[mid - mov, mid] = u0
u_n[mid, mid - mov] = u0
u_n[mid - mov, mid + mov] = u0


            lista_mesh_u[i, j] = u_n1[i, j]
</source>
            lista_mesh_v[i, j] = v_n1[i, j]


    lista_u.append(u_n1[0][0])
----
    lista_v.append(v_n1[0][0])


    # atualizar u_n e v_n
====Condição da borda completa====
    for i in range(Nx):
        for j in range(Ny):
            u_n[i, j] = u_n1[i, j]
            v_n[i, j] = v_n1[i, j]


    # Criar o Gif, caso não queira o gif, apenas apague esta parte
Completa toda a borda do recipiente com reagente <math>v_0</math>. Foi utilizado para <math>v_0</math> na figura 3.
    if t > plot_start:
        if gif_passo_inicial > gif_passo_total:
            gif_passo_inicial = 0
            plt.imshow(lista_mesh_u, interpolation='none')
            plt.title(f'$u_0$ = {u0} | $v_0$ = {v0} | a = {a} | b = {b} | t: {round(t, 2)}s')


            # Para funcionar você deve colocar onde será salvo as imagens geradas para o gif.
[[Arquivo:9PontosB3.gif|thumb|right|359px|'''Figura 8''': Utilizando a condição de borda para v e b=3.]]
            plt.savefig(f'C:/Users/ericn/PycharmProjects/MetCompC/Brusselator/Figuras/{figura}.png')
            # Para funcionar você deve colocar onde foram salvas as imagens geradas para o gif.
            fig_names.append(f'C:/Users/ericn/PycharmProjects/MetCompC/Brusselator/Figuras/{figura}.png')
            fig_atual = figura
            print(f'{round(fig_atual / fig_total * 100, 4)}%')


    # Para fazer outro plot
<source lang="python">
    if gif_passo_inicial > gif_passo_total:
        lista_indices.append(indice)


    indice += 1
# v_n = [Nx, Ny]
    gif_passo_inicial += dt


    figura += 1


    t += dt
# Toda a borda (v0)
    lista_t.append(t)


    print(f'{round(t / t_max * 100, 3)}%')


with imageio.get_writer('BrusselatorGif.gif', mode='I') as writer:
for i in range(Nx):
    print('Gifando')
    for filename in fig_names:
        image = imageio.imread(filename)
        writer.append_data(image)


# Plotar UxT animado
    # Completa primeira coluna e primeira linha
nome_plot = []
     v_n[0, i] = v0
for i in lista_indices:
     v_n[i, 0] = v0
    plt.plot(lista_t, lista_u, color='red', label=f'$u_0$ = {u0}')
     plt.plot(lista_t, lista_v, color='blue', label=f'$v_0$ = {v0}')
    plt.scatter(lista_t[i], lista_u[i], color='black')
    plt.xlabel('tempo')
    plt.ylabel('concentração')
    plt.title(f'Taxa de variação das concentrações. t = {lista_t[i]}')
     plt.xticks([i for i in range(0, 51, 5)])
    plt.legend()
    plt.grid(True)
    # Para funcionar você deve colocar onde será salvo as imagens geradas para o gif.
    plt.savefig(f'C:/Users/ericn/PycharmProjects/MetCompC/Brusselator/PlotUT/{i}.png')
    # Para funcionar você deve colocar onde foram salvas as imagens geradas para o gif.
    nome_plot.append(f'C:/Users/ericn/PycharmProjects/MetCompC/Brusselator/PlotUT/{i}.png')
    plt.cla()
    print(f'{round(i/lista_indices[-1]*100, 3)}%')


    # Completa última coluna e última linha
    v_n[Nx - 1, i] = v0
    v_n[i, Nx - 1] = v0


with imageio.get_writer('BrusselatorUTGif.gif', mode='I') as writer:
</source>
    print('Gifando')
    for filename in nome_plot:
        image = imageio.imread(filename)
        writer.append_data(image)


==Referências==


</source>
<references/>

Edição atual tal como às 03h33min de 15 de março de 2022

Grupo: Carolina Lenzi, Eric Naiber e Vitória Xavier

O objetivo deste trabalho é implementar o modelo de reação-difusão Brusselator em duas dimensões, frequentemente utilizado para estudar sistemas complexos químicos e biológicos. O modelo é um sistema não linear de equações diferenciais parciais e foi proposto em 1968 por Ilya Prigogine e seus colaboradores da Universidade Livre de Bruxelas. Desde então tem sido aplicado para analisar reações oscilatórias e autocatalíticas. O método computacional utilizado para implementar o modelo foi o método FTCS (Forward Time Centered Space).

Modelo de Brusselator

O estudo de sistemas químicos e biológicos frequentemente requer o uso de modelos que caracterizam reações de reação-difusão. Um dos modelos mais utilizados é o modelo de Brusselator, que é utilizado para descrever o mecanismo químico de reação-difusão com oscilações não lineares. [1]. Turing observou que quando determinadas reações são associadas a difusão, é possível obter um padrão espacial estável, e isso leva a teoria de morfogênese[2]. Além de processos de reação-difusão, o modelo Brusselator é observado em reações enzimáticas e na física de plasma e de lasers.

O mecanismo de Brusselator proposto por Prigogine[3] é dado por:

(1.a)
(1. b)
(1.c)
(1.d)

Onde U e V são as espécies químicas de interesse. Assumimos A e B em excesso para que o sistema não atinja o estado de equilíbrio. Esse sistema químico foi importante para o avanço na área de sistemas complexos porque possibilita o uso de modelos matemáticos de duas dimensões, já que U e V são variáveis dependentes, e admite oscilações de ciclo limite[4].

As equações diferenciais parciais associadas com o sistema Brusselator[5] são dadas por:

onde e são as concentrações a serem investigadas em função de tempo e espaço, e são constantes relativas às concentrações dos reagentes A e B, e e são as constantes de difusão de U e V.

A solução analítica do sistema reação-difusão Brusselator ainda não é conhecida e por isso há o interesse de explorá-la numericamente.

Análise da estabilidade do sistema

Análise de ponto crítico

Considerando o sistema livre de difusão, quando :

Encontramos os pontos críticos do sistema igualando as derivadas à zero. Obtemos que o único ponto crítico é . A matriz jacobiana no ponto crítico é dada por


Os autovalores de são os valores que satisfazem a equação caracterísitca

Os autovalores claramente mostram dependência em e no determinante . Esses autovalores governam a estabilidade do ponto crítico e determinam a existência de um ciclo limite. Conforme discutido em Twizell[6], quando o sistema é estável e não existe ciclo limite. Já para o sistema é instável e existe ciclo limite.

Análise de ponto fixo

Ainda em Twizell[6], foi feita a análise de ponto fixo. O único ponto fixo encontrado é . Manipulando a matriz Jacobiana nesse ponto e analisando os autovalores, obtém-se que a solução é atraída para o ponto se . Caso contrário, a solução não converge.

Método FTCS

O FTCS (Forward Time Centered Space) é um método de diferença finita que utiliza a derivada à direita ("para frente") no tempo e a derivada segunda centralizada no espaço para discretizar as variáveis. As derivadas no tempo e no espaço bidimensional ficam:


Substituindo nas equações do Brusselator

onde e são as funções que representam a reação sem difusão.


Utilizamos discretização do tipo


Utilizando a notação , assumindo e rearranjando os termos, reescrevemos as equações como


onde e .

Análise de estabilidade

A análise de estabilidade do método FTCS pode ser feita com a análise local de von Neumann. Para isso precisamos linearizar as equações do modelo Brusselator e escrever as soluções em modos de Fourier, da seguinte forma:

Para que o método seja estável, é preciso que . Após inserir as soluções nas equações linearizadas e realizar manipulações algébricas, como feito por Scholz[7], obtemos

onde

e

Os valores e satisfazem a condição de estabilidade, como mostrado em Scholz[7].

Implementação

A seguir, o trecho do código relativo à implementação do método na linguagem Python. O código completo encontra-se no Github [1]

# u_n, v_n -> concentracao dos reagentes no tempo n (matriz Nx x Ny)
# u_n1, v_n1 -> concentracao dos reagentes no tempo n+1

while t < t_max:

    for i in range(Nx):
        i_e = (i - 1) % Nx  # vizinho a esquerda de 0 é o da ultima posicao
        i_d = (i + 1) % Nx  # vizinho a direita da ultima posicao é o zero

        for j in range(Ny):
            j_e = (j - 1) % Ny
            j_d = (j + 1) % Ny

            # calcular u e v no tempo n+1
            u_n1[i, j] = u_n[i, j] + dt * f(u_n[i, j], v_n[i, j], b) \
                         + ku * (u_n[i_e, j] + u_n[i_d, j] + u_n[i, j_e] + u_n[i, j_d] - 4 * u_n[i, j])
            v_n1[i, j] = v_n[i, j] + dt * g(u_n[i, j], v_n[i, j], b) \
                         + kv * (v_n[i_e, j] + v_n[i_d, j] + v_n[i, j_e] + v_n[i, j_d] - 4 * v_n[i, j])

    # atualizar u_n e v_n
    for i in range(Nx):
        for j in range(Ny):
            u_n[i, j] = u_n1[i, j]
            v_n[i, j] = v_n1[i, j]

    t += dt

Resultados

Esta seção se dedica ao resultados das simulações realizadas, que mostram o caráter oscilatório do Brusselator ao longo do tempo e também como se dá a difusão dos reagentes em um recipiente em duas dimensões. As constantes utilizadas foram identificadas abaixo para plotar os gráficos, exceto quando indicado o contrário.

Tabela de Constantes e Valores
Símbolo Nome Valor
Dimensão analisada ao longo do eixo x 50
Dimensão analisada ao longo do eixo y 50
Constante relativa à concentração do reagente A 1
Constante relativa à concentração do reagente B 1.7
Constante de difusão do reagente U 0.5
Constante de difusão do reagente V 1
Concentração de u no tempo inicial (t=0) 1
Concentração de v no tempo inicial (t=0) 1
Passo de tempo entre iterações 0.01
Unidade de avanço dos eixos no espaço 1

As posições das condições iniciais foram escolhidas arbitrariamente, tendo um total de 6 modos que serão explicados na sequência, sendo eles:

  1. Condição em formato do sinal "+".
  2. Condição de borda.
  3. Condição aleatória.
  4. Condição de nove pontos centrais.
  5. Condição da borda completa.

Simulação

Nas figuras abaixo temos a variação das concentrações dos reagentes ao longo do tempo e os diagramas de fase. Para e notamos que a solução do sistema converge para e . Esse resultado está de acordo com o esperado, pois o ponto é um ponto fixo atrator (satisfaz que ), conforme discutido na seção de análise de estabilidade do Brusselator. Notamos também, pelo diagrama de fase, que mesmo alterando as condições iniciais do problema, a solução converge para o estado estacionário.


Figura 1: Solução do Brusselator para a = 1 e b = 1.7.


Para e , temos que , portanto a solução do sistema não converge. O que observamos é um comportamento periódico causado pela existência do ciclo limite.


Figura 2: Solução do Brusselator para a = 1 e b = 3.

Podemos pensar nas funções de concentração e como ondas que sofrem interferência destrutiva, pois estão fora de fase. A animação abaixo mostra este comportamento, observe o reagente , representado pela cor amarela, no gráfico da direita. Note que quando o ponto do gráfico da esquerda chega ao mínimo local, o valor de é alto e o de muito baixo, fazendo com que o gráfico da direita fique muito amarelo.


Figura 3: Comportamento do reagente.


É interessante pensar no gráfico da esquerda como a análise em um ponto específico dentro do recipiente, por exemplo, se estamos analisando o ponto . Tendo isso em mente conseguimos analisar os outros 3 cantos da figura, já que, por simetria da posição inicial escolhida, os cantos são iguais.


Figura 4: Análise de um ponto.

Condições Iniciais

Realizamos as simulações variando espacialmente as condições iniciais, para verificar os diferentes padrões formados pelo sistema.

Condição em Formato do Sinal "+"

O reagente é distribuído no centro formando um sinal de "+".

Figura 4: Comportamento em formato de "+" para o reagente u. Para o reagente v foi utilizado a condição de borda.
# u_n [Nx, Ny]

# Centro
u_n[int(Nx / 2), int(Ny / 2)] = u0


# Lateral do sinal
#       X                   Y
u_n[int(Nx / 2) + 1, int(Ny / 2)] = u0
u_n[int(Nx / 2) - 1, int(Ny / 2)] = u0


# Altura do sinal
#       X                   Y
u_n[int(Nx / 2), int(Ny / 2) + 1] = u0
u_n[int(Nx / 2), int(Ny / 2) - 1] = u0

Condição de borda

O reagente foi distribuído nos 4 cantos do recipiente.

Figura 5: Analisando u com condição de borda "+". Para o reagente v foi utilizado a condição de borda. Foi utilizado b=3 para mostrar a diferença na simulação.
# u_n [Nx, Ny]

# Sup Esq
v_n[0, 0] = v0


# Sup Dir
v_n[0, Nx - 1] = v0


# Inf Esq
v_n[Nx - 1, 0] = v0


# Inf Dir
v_n[Nx - 1, Nx - 1] = v0

Condição aleatória

Os reagentes são aleatoriamente distribuídos ao longo do recipiente, a quantidade de focos de reagente também é aleatória para e .

Figura 6: Posição aleatória.
from random import *

# u_n [Nx, Ny]

aleatorio = randint(int(Nx / 5)


# Aleatório para u
for _ in range(aleatorio, Nx)):
    u_n[randint(0, size), randint(0, size)] = u0


# Aleatório para v
for _ in range(aleatorio, Nx)):
    v_n[randint(0, size), randint(0, size)] = v0

Condição de nove pontos centrais

No centro divide 9 pontos igualmente espaçados de tamanho , para . Foi utilizado para na figura 3.

Figura 7: Utilizando a condição de borda para v.
# Nove pontos centrais (u0)
mid = int(Nx / 2); mov = int(Nx / 4)

# Meio & direita
u_n[mid, mid] = u0
u_n[mid + mov, mid + mov] = u0
# Meio & esquerda
u_n[mid + mov, mid] = u0
u_n[mid, mid + mov] = u0
# Meio, p/baixo & p/lados
u_n[mid + mov, mid - mov] = u0
u_n[mid - mov, mid - mov] = u0
# Meio, p/cima & p/lados
u_n[mid - mov, mid] = u0
u_n[mid, mid - mov] = u0
u_n[mid - mov, mid + mov] = u0

Condição da borda completa

Completa toda a borda do recipiente com reagente . Foi utilizado para na figura 3.

Figura 8: Utilizando a condição de borda para v e b=3.
# v_n = [Nx, Ny]


# Toda a borda (v0)


for i in range(Nx):

    # Completa primeira coluna e primeira linha
    v_n[0, i] = v0
    v_n[i, 0] = v0

    # Completa última coluna e última linha
    v_n[Nx - 1, i] = v0
    v_n[i, Nx - 1] = v0

Referências

  1. J. Tyson, Some further studies of nonlinear oscillations in chemical systems, J. Chem. Phys. 58 (1973) 3919
  2. Turing A. M., The chemical basis of morphogenesis. 1953. Bull. Math. Biol. 52, 153, discussion 119 (1990).
  3. I. Prigogine, R. Lefever, Symmetries breaking instabilities in dissipative systems II. J. Phys. Chem. 48, 1695–1700 (1968)
  4. R. Lefever and G. Nicolis, Chemical instabilities and sustained oscillations, J. Theor. Biol. 30 (1971)
  5. G. Adomian, The diffusion-Brusselator equation. Comput. Math. Appl. 29, 1–3 (1995)
  6. 6,0 6,1 Twizell, E. H., Gumel, A. B., & Cao, Q. (1999). Journal of Mathematical Chemistry, 26(4), 297–316
  7. 7,0 7,1 Scholz, Christian, Morphology of Experimental and Simulated Turing Patterns, 2009, p. 27-29.