Neste capítulo vamos mostrar um uso de várias espécies de turtles em NetLogo, assim como a capacidade dos indivíduos de estas mudarem de espécie. Introduziremos também as listas e explicaremos como se usam. Fá-lo-emos usando o modelo do gás de rede para demonstrar algumas características da transição de fase líquido vapor, assim como da tensão superficial dos líquidos.
O gás de rede é um modelo onde os agentes são patches de dois tipos: –ocupados por uma partícula (pretos) e desocupados (brancos), os quais são referenciados por turtles de duas espécies: –ocupados e livres, as quais funcionam como etiquetas dos patches. Tal permite-nos aplicar código NetLogo somente aos patches com uma certa característica, sem estar constantemente a verificar se todos os patches satisfazem essa característica ou não (ask patches with [ variavel = valor ]), o que permite acelerar o programa.
Numa substância real as partículas interagem entre si, quer por pontes de hidrogénio, quer por forças de Van der Waals, no gás de rede modelamos as interacções por proximidade geométrica: os patches pretos ("partículas") interagem, se forem adjacentes na horizontal ou na vertical. Consequentemente cada patch preto pode interagir com quatro vizinhos, no máximo. Atribuímos a cada uma destas interacções a energia -1 (podemos interpretá-la como a energia média de interacção num sistema de unidades da energia conveniente).
Com o gás de rede pretendemos modelar um fluido contido num recipiente fechado, com volume constante, imerso num banho que mantém a temperatura do fluido constante.
Nestas condições as partículas do fluido estão em equilíbrio térmico e estão constantemente a transitar entre os vários níveis de energia (-4, -3, -2, -1 e 0), cf. diagrama da direita. No entanto pela física estatística a transição entre os vários níveis de energia é feita com diferentes probabilidades:
As regras anteriores, mediante a escolha conveniente de um sistema de unidades para a temperatura (aquele onde K = 1), traduzem-se no seguinte guião para os patches:
Com este programa podemos variar a quantidade de partículas (ou densidade, número de partículas por unidade de área) e a temperatura do sistema de forma independente. Consequentemente este programa vai permitir investigar o diagrama de fases densidade-temperatura do gás de rede, o qual possui as mesmas características do diagrama de fases das substâncias simples correspondente às fases líquido e vapor.
O leitor é agora convidado a interagir com este modelo através do seguinte applet:
Para correr este modelo no ambiente NetLogo, basta seguir o link gasderede, se tiver instalado o software.
Neste applet podemos estudar como é que o estado final do fluido depende do estado inicial escolhendo um dos três estados (aleatorio, gota ou interface) no botão estado-inicial para diferentes temperaturas e densidades escolhidas nos cursores respectivos e premindo de seguida o botão preparar. Qualquer uma das três escolhas vai criar um número de patches ocupados com a densidade escolhida. Por exemplo para a temperatura de 0.30 e densidade de 50% obtemos respectivamente os seguintes estados iniciais (aleatório, gota e interface):
A evolução no tempo do sistema é mostrada através do gráfico EM.
O leitor tem à sua disposição mais dois botões densidade_automatica e temperatura_automatica os quais desenham respectivamente a energia média de equilíbrio por partícula em função da densidade para a temperatura seleccionada no cursor temperatura e a energia média por partícula em função da temperatura para a densidade seleccionada no cursor densidade. Para limpar os gráficos, basta premir o botão limpar.
O estado inicial é irrelevante para a obtenção do estado de equilíbrio: –a baixas temperaturas o fluido condensa, a altas temperaturas o fluido evapora independentemente do estado inicial:
conforme atestam os seguintes exemplos:
Para temperaturas suficientemente altas, por forma a que o fluido esteja no estado gasoso, a mera variação da densidade permite fazer o sistema passar de um estado onde a energia por partícula é próxima de 0 (a baixas densidades) para um estado onde a energia média por partícula é próxima de -2 (densidades elevadas), cf. gráfico da direita para a temperatura = 0.70.
A forma do gráfico não é surpreendente, pois para temperaturas altas e densidades baixas as hipóteses de existirem partículas vizinhas são bastante baixas, por outro lado, para densidades altas, não há espaço para que as partículas estejam no estado "gasoso", pelo que as partículas são confinadas ao estado "condensado" , onde interagem com as vizinhas.
Os fluidos macroscópicos apresentam transições de fase. A água por exemplo passa do estado líquido ao estado gasoso a 100°C. A essa temperatura a energia interna do sistema fechado composto por água no estado líquido e no estado gasoso aumenta à medida que esta evapora, apesar da temperatura se manter constante. Este fenómeno encontra-se representado esquematicamente na curva a azul do gráfico da esquerda. Esta subida na vertical só é observada para sistemas macroscópicos, i.e. compostos por muitas partículas. Para sistemas compostos por relativamente poucas partículas, a subida da energia interna não é tão acentuada no ponto de ebulição, observando-se apenas uma inflecção no ponto de ebulição, cf. curva a vermelho no gráfico da esquerda. O gás de rede, para cada densidade, também apresenta um ponto de ebulição. Por exemplo para a densidade = 50%, o ponto de ebulição é por volta de temperatura = .55, como pode ser visto no gráfico da direita:
É igualmente visível a existência do ponto crítico quando densidade = 50% e temperatura = .55, como podemos ver no gráfico da direita, pois para esta densidade o sistema ferve à temperatura mais alta.
Neste gráfico estão representadas para temperatura = .55 as curvas cinzenta, vermelha e laranja que correspondem respectivamente à energia média por partícula em função da temperatura para as densidades 50%, 90% e 10%. A recta azul é a recta que corta temperatura = .55.
Para obter este gráfico seleccione densidade = 50% prima temperatura_automatica e deixe desenhar a curva cinzenta, depois seleccione densidade = 90% prima temperatura_automatica, mas não prima limpar e deixe desenhar a curva vermelha, por fim repita o mesmo processo para densidade = 10%.
O modelo está dividido nas seguintes secções:
tempo | contém o número de iterações (tentativas de troca) já decorridas |
energia | contém a energia média por partícula do sistema |
particulas | contém o número de partículas (patches pretos) |
patches: ligacoes | propriedade de cada patch que contem o número de ligações disponíveis, i.e. o número de patches pretos adjacentes na horizontal ou na vertical |
preparar | limpa e inicia todas as variáveis, cria o número de partículas correspondente à densidade escolhida e coloca-as no estado inicial escolhido pelo utilizador (aleatório, gota, ou interface). |
executar | itera as regras de transformação dos patches, desenha o gráfico da evolução da energia média por partícula em função do tempo e mostra a energia média instantânea no monitor. |
densidade_automatica | itera as regras de transformação dos patches e desenha o gráfico da energia média de equilíbrio por partícula em função da densidade para a temperatura fixada no cursor temperatura. |
temperatura_automatica | itera as regras de transformação dos patches, desenha o gráfico da evolução da energia média de equilíbrio por partícula em função da temperatura para a densidade fixada no cursor densidade. |
prepara-aleatorio | cria o estado inicial aleatorio. |
prepara-gota | cria o estado inicial gota. |
prepara-interface | cria o estado inicial interface. |
trocar | itera as regras de transformação dos patches e é chamada pela rotina executar. |
preparar-grafico | inicia o gráfico da energia média. |
grafico | marca os pontos no gráfico da energia média. |
calcula-energia-media | calcula a energia média de equilíbrio por partícula e é chamada pelas rotinas densidade_automatica e temperatura_automatica. |
globals [ tempo energia particulas cor ] breed [ ocupados ocupado ] breed [ livres livre ] patches-own [ ligacoes ] to preparar locals [ patches-ocupados ] ct cp set-current-plot "EM" clear-plot set tempo 0 ask patches [ set pcolor white sprout-livres 1 [ ht ] ] if estado-inicial = "aleatorio" [ prepara-aleatorio ] if estado-inicial = "gota" [ prepara-gota ] if estado-inicial = "interface" [ prepara-interface ] ask patches [ set ligacoes count neighbors4 with [ pcolor = black ] ] set patches-ocupados patches-from ocupados [ patch-here ] set energia sum values-from patches-ocupados [ligacoes] / (-2 * particulas) display preparar-grafico grafico end to prepara-aleatorio ask patches [ if random-float 100 < densidade [ set pcolor black ask livres-here [ set breed ocupados ] ] ] set particulas count ocupados end to prepara-gota locals [ lado ] set particulas (count patches) * densidade / 100 set lado int ((sqrt particulas - 1) / 2) ask patches with [ abs pxcor <= lado and abs pycor <= lado ][ set pcolor black ask livres-here [ set breed ocupados ] ] ask n-of (particulas - (2 * lado + 1) ^ 2) patches with [ (abs pxcor = lado + 1 and abs pycor <= lado + 1) or (abs pxcor <= lado + 1 and abs pycor = lado + 1) ][ set pcolor black ask livres-here [ set breed ocupados ] ] end to prepara-interface locals [ altura ] set particulas (count patches) * densidade / 100 set altura int (particulas / world-width) ask patches with [ pycor < altura + min-pycor ][ set pcolor black ask livres-here [ set breed ocupados ] ] ask n-of (particulas - altura * world-width) patches with [ pycor = altura + min-pycor ][ set pcolor black ask livres-here [ set breed ocupados ] ] end to executar locals [ ocupado1 livre1 patches-ocupados ] no-display set ocupado1 one-of ocupados set livre1 one-of livres trocar ocupado1 livre1 every 0.1 [ display set patches-ocupados patches-from ocupados [ patch-here ] set energia sum values-from patches-ocupados [ligacoes] / (-2 * particulas) grafico ] end to trocar [ ocupado1 livre1 ] locals [ diferenca ] set diferenca ligacoes-of livre1 - ligacoes-of ocupado1 if random-float 1.0 < exp (diferenca / temperatura) [ ask livre1 [ ask neighbors4 [ set ligacoes ligacoes + 1 ] ask patch-here [ set pcolor black ] set breed ocupados ] ask ocupado1 [ ask neighbors4 [ set ligacoes ligacoes - 1 ] ask patch-here [ set pcolor white ] set breed livres ] ] set tempo tempo + 1 end to preparar-grafico set-current-plot "EM" set-current-plot-pen "eixo" auto-plot-off plotxy 0 -2 plotxy 100000000 -2 auto-plot-on end to grafico set-current-plot "EM" set-current-plot-pen "epp" plotxy tempo energia end to temperatura_automatica set estado-inicial "gota" set-current-plot "energia / temperatura" set-plot-pen-color blue ppu plotxy .55 -.5 ppd plotxy .55 -2 if cor = 0 [ set cor 5 ] set-plot-pen-color cor set temperatura 0.45 while [ temperatura < 0.65 ][ preparar calcula-energia-media set-current-plot "energia / temperatura" if temperatura = .45 [ ppu plotxy temperatura energia ppd ] plotxy temperatura energia set temperatura temperatura + .01 ] set cor cor + 10 end to densidade_automatica set estado-inicial "gota" set-current-plot "energia / densidade" clear-plot set densidade 1 while [ densidade < 100 ][ preparar calcula-energia-media set-current-plot "energia / densidade" plotxy densidade energia set densidade densidade + 1 ] end to calcula-energia-media locals [ lista ] set lista [] while [ length lista < 50 ][ executar every 0.1 [ display ifelse length lista < 30 [ set lista lput energia lista ][ ifelse (energia > sum lista / 30) and (length lista = 30) [ set lista but-first lista set lista lput energia lista ][ set lista lput energia lista ] ] ] ] set lista sublist lista 30 49 set energia sum lista / 20 end
Vejamos em detalhe as componentes lógicas novas do código:
to preparar locals [ patches-ocupados ] ct cp set-current-plot "EM" clear-plot set tempo 0 ask patches [ set pcolor white sprout-livres 1 [ ht ] ] if estado-inicial = "aleatorio" [ prepara-aleatorio ] if estado-inicial = "gota" [ prepara-gota ] if estado-inicial = "interface" [ prepara-interface ] ask patches [ set ligacoes count neighbors4 with [ pcolor = black ] ] set patches-ocupados patches-from ocupados [ patch-here ] set energia sum values-from patches-ocupados [ligacoes] / (-2) set energia energia / particulas display preparar-grafico grafico end
Esta rotina começa por limpar turtles e patches que possam existir de execuções anteriores do programa com os comandos ct e cp e por limpar o gráfico da energia média (EM) com os comandos:
set-current-plot "EM" clear-plot
De seguida inicia todos os patches com cor branca (desocupados) e associa a cada um uma turtle da espécie livres que funciona como etiqueta dos patches livres e por essa razão escondemo-la:
ask patches [ set pcolor white sprout-livres 1 [ ht ] ]
usamos esta artimanha, pois o NetLogo não nos permite criar espécies de patches.
Depois cria o estado inicial escolhido pelo utilizador:
set particulas (count patches) * densidade / 100 if estado-inicial = "aleatorio" [ prepara-aleatorio ] if estado-inicial = "gota" [ prepara-gota ] if estado-inicial = "interface" [ prepara-interface ]
De seguida a cada patch atribui o número de ligacoes ("interacções") possíveis nesse patch, número esse que corresponde ao número de patches ocupados e adjacentes na horizontal ou na vertical (neighbors4 with [ pcolor = black ]):
ask patches [ set ligacoes count neighbors4 with [ pcolor = black ] ]
Para tornarmos o código mais legível criamos o conjunto dos patches-ocupados com o comando set patches-ocupados patches-from ocupados [ patch-here ], que corresponde aos patches referenciados pelo repórter [ patch-here ] aplicado às turtles da espécie ocupados.
De seguida calcula a energia do sistema, a qual é metade do simétrico da soma do número de pares de patches pretos adjacentes na horizontal ou na vertical através do seguinte comando:
set energia sum values-from patches-ocupados [ligacoes] / (-2).
Vemos aqui o primeiro exemplo do uso de listas, pois o comando values-from patches-ocupados [ligacoes] cria uma lista formada pelos valores da variável ligacoes relativos ao conjunto de agentes patches-ocupados, valores esses que são depois somados com a instrução sum.
Dividimos por 2, pois contámos a "ligações" duas vezes: –quando chegámos ao patch A ligado ao patch B, contámos uma "ligação", "ligação" esta que tornou a ser contada quando chegámos ao patch B (que obviamente está ligado ao patch A). Tomamos para a energia o simétrico do número de "ligações", pois as energias potenciais são convencionalmente representadas por números negativos.
De seguida a energia média por partícula é calculada com o comando set energia energia / particulas e por fim activa-se a actualização da janela gráfica (com a instrução display, ver à frente), que pode ter sido desactivada por uma execução anterior do modelo, e inicia-se o gráfico da energia média (EM) marcando o ponto correspondente à configuração inicial:
display preparar-grafico grafico
to executar locals [ ocupado1 livre1 patches-ocupados ] no-display set ocupado1 one-of ocupados set livre1 one-of livres Trocar ocupado1 livre1 every 0.1 [ display set patches-ocupados patches-from ocupados [ patch-here ] set energia sum values-from patches-ocupados [ligacoes] / (-2) set energia energia / particulas grafico ] end
Esta é a rotina responsável pelo guião dos patches. Os comandos
set ocupado1 one-of ocupados set livre1 one-of livres
escolhem ao acaso uma etiqueta (turtle) ocupada e uma livre e os patches executam de seguida as regras definidas no guião (Trocar ocupado1 livre1).
O comando no-display é usado para que a janela gráfica não mostre a actualização do mundo, pois essa actualização consome muitos recursos de processamento. Este comando é usado em conjunto com o comando display o qual actualiza o mundo e está activo a cada 0.1 segundos, em consequência do comando every 0.1 [ comandos ]. Tal contribui significativamente para que o modelo corra a uma velocidade aceitável.
to densidade_automatica set estado-inicial "gota" set-current-plot "energia / densidade" clear-plot set densidade 1 while [ densidade < 100 ][ preparar calcula-energia-media set-current-plot "energia / densidade" plotxy densidade energia set densidade densidade + 1 ] end
Esta é a rotina que desenha o gráfico da energia média em função da densidade a temperatura constante (dada pelo cursor com o mesmo nome). No gráfico a densidade varia entre 0 e 100%, em intervalos de 1%.
to temperatura_automatica set estado-inicial "gota" set-current-plot "energia / temperatura" set-plot-pen-color blue ppu plotxy .55 -.5 ppd plotxy .55 -2 if cor = 0 [ set cor 5 ] set-plot-pen-color cor set temperatura 0.45 while [ temperatura < 0.65 ][ preparar calcula-energia-media set-current-plot "energia / temperatura" if temperatura = .45 [ ppu plotxy temperatura energia ppd ] plotxy temperatura energia set temperatura temperatura + .01 ] set cor cor + 10 end
Esta é a rotina que desenha o gráfico da energia média em função da temperatura a densidade constante (dada pelo cursor com o mesmo nome). No gráfico a temperatura varia entre 0.45 e 0.65, em intervalos de 0.01. Esta rotina desenha também uma recta vertical sobre o ponto correspondente à temperatura = 0.55.
to prepara-aleatorio ask patches [ if random-float 100 < densidade [ set pcolor black ask livres-here [ set breed ocupados ] ] ] set particulas count ocupados end
Esta é a rotina que cria o estado inicial aleatorio (estado gasoso). A qual ocupa cada patch com a probabilidade densidade / 100 pintando o patch de preto (set pcolor black) e mudando-lhe a etiqueta para ocupados (ask livres-here [ set breed ocupados ]).
to prepara-gota locals [ lado ] set particulas (count patches) * densidade / 100 set lado int ((sqrt particulas - 1) / 2) ask patches with [ abs pxcor <= lado and abs pycor <= lado ][ set pcolor black ask livres-here [ set breed ocupados ] ] ask n-of (particulas - (2 * lado + 1) ^ 2) patches with [ (abs pxcor = lado + 1 and abs pycor <= lado + 1) or (abs pxcor <= lado + 1 and abs pycor = lado + 1) ][ set pcolor black ask livres-here [ set breed ocupados ] ] end
Esta rotina é semelhante à anterior, o que varia é a disposição das partículas.
to prepara-interface locals [ altura ] set particulas (count patches) * densidade / 100 set altura int (particulas / world-width) ask patches with [ pycor < altura + min-pycor ][ set pcolor black ask livres-here [ set breed ocupados ] ] ask n-of (particulas - altura * world-width) patches with [ pycor = altura + min-pycor ][ set pcolor black ask livres-here [ set breed ocupados ] ] end
Esta rotina é semelhante à anterior, o que varia é a disposição das partículas.
to trocar [ ocupado1 livre1 ] locals [ diferenca ] set diferenca ligacoes-of livre1 - ligacoes-of ocupado1 if random-float 1.0 < exp (diferenca / temperatura) [ ask livre1 [ ask neighbors4 [ set ligacoes ligacoes + 1 ] ask patch-here [ set pcolor black ] set breed ocupados ] ask ocupado1 [ ask neighbors4 [ set ligacoes ligacoes - 1 ] ask patch-here [ set pcolor white ] set breed livres ] ] set tempo tempo + 1 end
Esta rotina recebe dois parâmetros uma turtle ocupada e uma livre. Se a energia potencial da partícula no patch livre for maior que a energia potencial da partícula no patch ocupado, a troca é feita com probabilidade exp (diferenca / temperatura), caso contrário a troca é sempre feita, pois nesse caso exp (diferenca / temperatura) ≥ 1.
A troca consiste em actualizar o número de ligacoes resultante da transferência da partícula, em mudar a cor do patch onde a turtle (etiqueta) está, através da instrução ask patch-here, e em mudar a espécie da turtle.
to preparar-grafico set-current-plot "EM" set-current-plot-pen "eixo" auto-plot-off plotxy 0 -2 plotxy 100000000 -2 auto-plot-on end
Esta rotina prepara o gráfico de energia média, desenhando uma linha de base no valor -2.0, que é o valor mínimo possível para a energia média. Este valor só é atingido se todos os patches estiverem ocupados (densidade = 100%).
to grafico set-current-plot "EM" set-current-plot-pen "epp" plotxy tempo energia end
Esta rotina simplesmente acrescenta ao gráfico da energia média (EM) o novo ponto (tempo, energia).
to calcula-energia-media locals [ lista ] set lista [] while [ length lista < 50 ][ executar every 0.1 [ display ifelse length lista < 30 [ set lista lput energia lista ][ ifelse (energia > sum lista / 30) and (length lista = 30) [ set lista but-first lista set lista lput energia lista ][ set lista lput energia lista ] ] ] ] set lista sublist lista 30 49 set energia sum lista / 20 end
Esta é a rotina que calcula a energia média por partícula. Para o fazer deixa a energia por partícula estabilizar em torno do valor de equilíbrio e de seguida pega em vinte valores consecutivos e calcula a média.
A parte aparentemente complicada é o "estabilizar em torno do ponto de equilíbrio", mas tal até que acaba por ser fácil, pois quando se começa com o estado-inicial gota a energia vai crescendo com o tempo até estabilizar em torno do ponto de equilíbrio. Precisamos apenas de um critério para saber que a energia já não está a crescer mais.
As médias móveis, bastante usadas na análise técnica de acções, fornecem esse critério. Para calcularmos uma média móvel pegamos nos últimos n valores da energia e dividimos por n. Neste modelo escolhemos n = 30 para suavizar as flutuações na energia e dizemos que esta já não está a crescer mais se o último valor for inferior à média móvel.
Esta rotina faz um extenso uso de listas. Começa por iniciar a variável lista com uma lista vazia (set lista []), de seguida aumenta, em cada iteração, o tamanho da lista enquanto este for menor que trinta (length lista < 30) adicionando a última energia ao fim da lista com o seguinte comando:
set lista lput energia lista
Quando a lista tiver trinta elementos, remove a energia mais antiga da lista e adiciona a mais recente usando os seguintes comandos:
set lista but-first lista set lista lput energia lista
até que a energia por partícula estabilize. Quando tal acontecer junta à lista as vinte energias seguintes e constrói uma lista com essas últimas vinte energias (set lista sublist lista 30 49) e depois calcula a média.