MBA: Gás simples: mudanças entre as edições
Sem resumo de edição |
Sem resumo de edição |
||
(2 revisões intermediárias pelo mesmo usuário não estão sendo mostradas) | |||
Linha 57: | Linha 57: | ||
= Distribuição de velocidades para um gás a certa temperatura = | = Distribuição de velocidades para um gás a certa temperatura = | ||
A distribuição das | A distribuição das velocidades das moléculas de um gás é dada pela distribuição de Maxwell-Boltzmann <ref>[https://edisciplinas.usp.br/pluginfile.php/48089/course/section/16461/qsp_chapter4-kineticTheory.pdf The Kinetic Theory of Gases]</ref> | ||
<math display="block"> f\left(v\right)=\left(\frac{m}{2\pi kT}\right)^{3/2}4\pi v^{2}\exp\left(-\frac{mv^{2}}{kT}\right) </math> | <math display="block"> f\left(v\right)=\left(\frac{m}{2\pi kT}\right)^{3/2}4\pi v^{2}\exp\left(-\frac{mv^{2}}{kT}\right) </math> | ||
Linha 63: | Linha 63: | ||
Foi realizado uma simulação com 100 partículas por | Foi realizado uma simulação com 100 partículas por 500.000 de passos em uma grade 100x100 com fronteira toroidal, o resultado encontra-se na figura abaixo assim como o código. | ||
<div class="center">[[Ficheiro:mba_colisao.png|centro|miniaturadaimagem|750x750px|Resultado da simulação com a distribuição de Maxwell-Boltmann para kT=0.7 e m=1.]]</div> | <div class="center">[[Ficheiro:mba_colisao.png|centro|miniaturadaimagem|750x750px|Resultado da simulação com a distribuição de Maxwell-Boltmann para kT=0.7 e m=1.]]</div> | ||
Linha 97: | Linha 97: | ||
self.vel = (v*np.cos(ang),v*np.sin(ang)) #Velocidade decomposta | self.vel = (v*np.cos(ang),v*np.sin(ang)) #Velocidade decomposta | ||
self.colisao=False | self.colisao=False | ||
self.ac=False | |||
def prox_pos(self): | def prox_pos(self): | ||
Linha 128: | Linha 129: | ||
nvel1=(self.vel[0]+u1*d[0],self.vel[1]+u1*d[1]) | nvel1=(self.vel[0]+u1*d[0],self.vel[1]+u1*d[1]) | ||
#partícula 2,pela conservação de momento: | #partícula 2,pela conservação de momento: | ||
nvel2=(self.vel[0]+a.vel[0]-nvel1[0],self.vel[1]+a.vel[1]-nvel1[1]) | nvel2=(self.vel[0]+a.vel[0]-nvel1[0],self.vel[1]+a.vel[1]-nvel1[1]) | ||
#Atualiza as velocidades | #Se nenhuma partícula tinha se colidido | ||
if (self.colisao==False and a.colisao==False): | |||
#Atualiza as velocidades | |||
self.vel=nvel1; a.vel=nvel2 | |||
self.ac=True;a.ac=True | |||
#Registra a colisão | #Registra a colisão | ||
self.colisao=True; a.colisao=True | self.colisao=True; a.colisao=True | ||
break | break | ||
return () | return () | ||
Linha 138: | Linha 142: | ||
def movimento(self): | def movimento(self): | ||
if(self.colisao): | if(self.colisao): | ||
return (self.pos) | return (self.pos) | ||
else: | else: | ||
Linha 195: | Linha 198: | ||
"""Avançar um passo do modelo""" | """Avançar um passo do modelo""" | ||
self.schedule.step() #Avançamos os agentes | self.schedule.step() #Avançamos os agentes | ||
#Limpamos as colisões | |||
for a in self.schedule.agents: #Vamos percorrer os agentes | |||
a.colisao=False | |||
#Parâmetros | #Parâmetros | ||
MAX = | MAX =1000000 | ||
N=100 | N=100 | ||
modelo = {"Largura": | modelo = {"Largura":100 ,"Altura":100 ,"Seed":1} | ||
M = Modelo(modelo,N) | M = Modelo(modelo,N) | ||
for i in range(MAX): | for i in range(MAX): | ||
Linha 206: | Linha 211: | ||
#clear_output() | #clear_output() | ||
print(str(100*(1+i)/MAX)+"%") | print(str(100*(1+i)/MAX)+"%") | ||
vel=[] | vel=[] | ||
Linha 220: | Linha 218: | ||
E+=a.vel[0]**2+a.vel[1]**2 | E+=a.vel[0]**2+a.vel[1]**2 | ||
print(E) | print(E) | ||
a,b,c=plt.hist(vel, | with open('velocidades0.2R100K1000.txt', 'w') as f: | ||
f.write(str(vel)) | |||
</pre> | |||
Para plotar o gráfico, podemos então usar simplesmente: | |||
<pre> | |||
import numpy as np | |||
import matplotlib.pyplot as plt | |||
a,b,c=plt.hist(vel,8, density=True, facecolor='g', alpha=0.75) | |||
m=1 | m=1 | ||
K=0.7 | K=0.7 | ||
x=np.arange(0,2, 0.00001) | x=np.arange(0,2.5, 0.00001) | ||
y = (4/np.sqrt(np.pi))*((m/K)**(3/2))*(x**2)*np.exp(-m*(x**2)/K) | y = (4/np.sqrt(np.pi))*((m/K)**(3/2))*(x**2)*np.exp(-m*(x**2)/K) | ||
plt.plot(x,y) | plt.plot(x,y) |
Edição atual tal como às 20h54min de 9 de agosto de 2022
Anterior: Por que usar e o que são modelos baseados em indivíduos | Índice: Ecologia | Próximo: MBA: Caminhante aleatório
Colisão entre partículas
Considerando um modelo simples de gás ideal, não há força atuando sob as partículas, então a interação que ocorre entre as partículas se dá apenas por meio de colisões. Assim é necessário calcular a variação na velocidade de cada partícula após a colisão. Começando em uma dimensão, precisamos garantir a conservação do momento:
Além disso vale lembrar que há a componente da velocidade perpendicular a , que vamos denotar como . Esta componente perpendicular permanece inalterada e pode ser visualizada na figura ao lado.
Sendo assim, a velocidade final é dada por:
Distribuição de velocidades para um gás a certa temperatura
A distribuição das velocidades das moléculas de um gás é dada pela distribuição de Maxwell-Boltzmann [1]
Foi realizado uma simulação com 100 partículas por 500.000 de passos em uma grade 100x100 com fronteira toroidal, o resultado encontra-se na figura abaixo assim como o código.
Código
Aqui chamamos a atenção que a principal diferença do código discutido para autômatos celulares é que agora não temos mais uma grade, mas um modelo contínuo. Também temos a possibilidade de configuração se as fronteiras serão toroidais (extremidades conectadas) ou não. Quanto aos resultados, precisamos considerar que é um modelo simplificado. O Calculo foi realizado para uma colisão entre duas partículas se dentro do mesmo passo deveria ocorrer mais de uma colisão, ou com mais de uma partícula simultaneamente o código falha, para remediar isso, o ideal é utilizar passos de tempo pequenos e/ou uma caixa relativamente grande em relação a quantidade de partículas. Além disso ao optarmos por uma fronteira toroidal ou não, estamos considerando uma caixa fechada ou não, ao considerarmos precisamos considerar a colisão com as fronteira também. Nesse último caso, uma simplificação simples é considerar que esta colisão ocorre primeiro. Novamente o problema surge se houver duas colisões no mesmo passo (agora podendo colidir com a fronteira), logo a recomendação é a mesma.
#Bibliotecas necessárias from mesa import Agent, Model #Classes Agente e Modelo from mesa.time import SimultaneousActivation #Agendador simultâneo from mesa.space import ContinuousSpace #Malha multigrid import random #Número aleatórios from mesa.datacollection import DataCollector #Importamos um coletor de dados import matplotlib.pyplot as plt #Plotar gráicos #from IPython.display import clear_output #Configurações de saída do Colab import numpy as np #AGENTE--------------------------------------------------------------------------------- class Agente(Agent): """Classe do agente""" def __init__(self, modelo,largura,altura): """Bibliotecas necessárias""" #modelo - Modelo que ao qual o agente pertence super().__init__(self, modelo) #Necessário para funcionar o modelo self.ppos = (0,0) #Poição que irá se mover self.rai= 0.2 #Raio self.lim=(largura,altura) #Limites da caixa v=1 #Módulo da velocidade inicial ang = 2*random.random()*np.pi self.vel = (v*np.cos(ang),v*np.sin(ang)) #Velocidade decomposta self.colisao=False self.ac=False def prox_pos(self): dt=0.01 nx=self.pos[0]+self.vel[0]*0.01 ny=self.pos[1]+self.vel[1]*0.01 #Testar os limites if (nx < 0): nx = - nx; self.vel=(-self.vel[0],self.vel[1]) if (nx > self.lim[0]): nx = 2*self.lim[0] - nx; self.vel=(-self.vel[0],self.vel[1]) if (ny < 0): ny = - ny; self.vel=(self.vel[0], - self.vel[1]) if (ny > self.lim[1]): ny = 2*self.lim[1] - ny;self.vel=(self.vel[0], - self.vel[1]) return((nx,ny)) def prox_vel(self): """Movimentação dos animais""" #Checamos se há colisão com outro animal: agentes = self.model.continuous.get_neighbors(pos=self.ppos, radius = 3*self.rai, include_center=True) for a in agentes: #Percorremos a lista if (a.unique_id!=self.unique_id): d=np.sqrt((a.ppos[0]-self.ppos[0])**2+(a.ppos[1]-self.ppos[1])**2) if (d<=2*self.rai): #Direção da colisão d=(a.ppos[0]-self.ppos[0],a.ppos[1]-self.ppos[1])/np.sqrt((a.ppos[0]-self.ppos[0])**2+(a.ppos[1]-self.ppos[1])**2) #Partícula 1 u1=(a.vel[0]-self.vel[0])*d[0]+(a.vel[1]-self.vel[1])*d[1] nvel1=(self.vel[0]+u1*d[0],self.vel[1]+u1*d[1]) #partícula 2,pela conservação de momento: nvel2=(self.vel[0]+a.vel[0]-nvel1[0],self.vel[1]+a.vel[1]-nvel1[1]) #Se nenhuma partícula tinha se colidido if (self.colisao==False and a.colisao==False): #Atualiza as velocidades self.vel=nvel1; a.vel=nvel2 self.ac=True;a.ac=True #Registra a colisão self.colisao=True; a.colisao=True break return () def movimento(self): if(self.colisao): return (self.pos) else: return(self.ppos) def step(self): """Método obrigatório que prepara as mudanças""" self.ppos = self.prox_pos() def advance(self): """Método obrigatório que aplica as mudanças""" self.prox_vel() self.model.continuous.move_agent(self, self.movimento()) #MODELO class Modelo(Model): """Modelo geral""" def gerar_particulas(self,N,largura,altura): """Função para gerar animais iniciais""" #N - Número de animais #largura - Largura da grade #altura - Altura da grade for n in range(N): con=True while(con): con=False a = Agente(self,largura,altura) X= largura*random.random() Y= altura*random.random() if (len(self.schedule.agents)==0): self.schedule.add(a) self.continuous.place_agent(a, (X, Y)) else: agentes = self.continuous.get_neighbors(pos=(X,Y), radius = 2*a.rai, include_center=True) for viz in agentes: con = (True) if (len(agentes)==0) else (con) #Precisamos checar se nasceu no mesmo lugar de outro animal if(con==False): self.schedule.add(a) self.continuous.place_agent(a, (X, Y)) return() def __init__(self, modelo,N,seed=None): """Função chamada quando o modelo é inicializazdo""" # Modelo - Dicionário com especificações do modelo # N - Número de partículas # seed - Seed dos números aleatórios do modelo do mesa # Desempacotar o dicionário largura = modelo["Largura"];altura=modelo["Altura"]; random.seed(modelo["Seed"]) self.continuous = ContinuousSpace(x_max= largura, y_max=altura, torus= True, x_min=0, y_min= 0) #Configura a grade self.schedule = SimultaneousActivation(self) #Configura o agendador self.running = True #Condiçao para seguir executando o modelo self.gerar_particulas(N,largura,altura) #Distribuir as ovelhas def step(self): """Avançar um passo do modelo""" self.schedule.step() #Avançamos os agentes #Limpamos as colisões for a in self.schedule.agents: #Vamos percorrer os agentes a.colisao=False #Parâmetros MAX =1000000 N=100 modelo = {"Largura":100 ,"Altura":100 ,"Seed":1} M = Modelo(modelo,N) for i in range(MAX): M.step() if ((i+1)%(MAX/100)==0): #clear_output() print(str(100*(1+i)/MAX)+"%") vel=[] E=0 for a in M.schedule.agents: vel.append(np.sqrt(a.vel[0]**2+a.vel[1]**2)) E+=a.vel[0]**2+a.vel[1]**2 print(E) with open('velocidades0.2R100K1000.txt', 'w') as f: f.write(str(vel))
Para plotar o gráfico, podemos então usar simplesmente:
import numpy as np import matplotlib.pyplot as plt a,b,c=plt.hist(vel,8, density=True, facecolor='g', alpha=0.75) m=1 K=0.7 x=np.arange(0,2.5, 0.00001) y = (4/np.sqrt(np.pi))*((m/K)**(3/2))*(x**2)*np.exp(-m*(x**2)/K) plt.plot(x,y)
Citações
Anterior: Por que usar e o que são modelos baseados em indivíduos | Índice: Ecologia | Próximo: MBA: Caminhante aleatório