Enchendo ou esvaziando tanques, caixas ou estoques
Um tipo especial de recurso no SimPy é o container. Intuitivamente, um container seria um taque ou caixa em que se armazenam coisas. Você pode encher ou esvaziar em quantidade, como se fosse um tanque de água ou uma caixa de laranjas.
import simpyenv = simpy.Environment()# cria um tanque de 100 m3 de capacidade, com 50 m3 no início da simulaçãotanque = simpy.Container(env, capacity=100, init=50)
O containerpossui três comandos importantes:
Para encher: tanque.put(quantidade)
Para esvaziar: tanque.get(quantidade)
Para obter o nível atual: tanque.level
Enchendo o meu container yield meuContainer.put(quantidade)
import simpyimport random TANQUE_CAMINHAO =50# capacidade de abastecimento do caminhãodefenchimentoTanque(env,qtd,tanque): # enche o tanqueprint("%d Novo caminhão com %4.1f m3.\t Nível atual: %5.1f m3"% (env.now, qtd, tanque.level))yield tanque.put(qtd)print("%d Tanque enchido com %4.1f m3.\t Nível atual: %5.1f m3"% (env.now, qtd, tanque.level))random.seed(150)env = simpy.Environment()#cria um tanque de 100 m3, com 50 m3 no início da simulaçãotanque = simpy.Container(env, capacity=100, init=50)env.process(enchimentoTanque(env, TANQUE_CAMINHAO, tanque))env.run(until =500)
A saída do programa é bastante simples, afinal o processo de enchimento do tanque é executado apenas uma vez:
0 Novo caminhão de combustível com 50.0 m3. Nível atual:50.0 m30 Tanque enchido com 50.0 m3. Nível atual:100.0 m3
yield tanque.put(qtd)
Dentro da função enchimentoTanque.
Esvaziando o meu container: yield meuContainer.get(quantidade)
Partindo do modelo anterior, vamos criar duas funções: uma para gerar os veículos e outra para transferir o combustível do tanque para o veículo.
Uma possível máscara para o modelo seria:
import simpyimport random TANQUE_CAMINHAO =50# capacidade de abastecimento do caminhãoTANQUE_VEICULO =0.10# capacidade do veículoTEMPO_CHEGADAS =5# tempo entre chegadas sucessivas de veículosdefchegadasVeiculos(env,tanque):# gera chegadas de veículos por produtodefesvaziamentoTanque(env,qtd,tanque):# esvazia o tanquedefenchimentoTanque(env,qtd,tanque): # enche o tanqueprint("%d Novo caminhão com %4.1f m3.\t Nível atual: %5.1f m3"% (env.now, qtd, tanque.level))yield tanque.put(qtd)print("%d Tanque enchido com %4.1f m3.\t Nível atual: %5.1f m3"% (env.now, qtd, tanque.level))random.seed(150)env = simpy.Environment()# cria um tanque de 100 m3, com 50 m3 no início da simulaçãotanque = simpy.Container(env, capacity=100, init=50)env.process(chegadasVeiculos(env, tanque))env.run(until =20)
A função chegadasVeiculosgera os veículos que buscam abastecimento no posto e que, a seguir, chamam a função esvaziamentoTanque responsável por provocar o esvaziamento do tanque do posto na quantidade desejada pelo veículo:
defchegadasVeiculos(env,tanque):# gera chegadas de veículos por produtowhileTrue:yield env.timeout(TEMPO_CHEGADAS)# carrega veículo env.process(esvaziamentoTanque(env, TANQUE_VEICULO, tanque))
A função que representa o processo de esvaziamento do tanque é semelhante a de enchimento da seção anterior, a menos da opção get(qtd), que retira a quantidade qtd do container tanque:
defesvaziamentoTanque(env,qtd,tanque):# esvazia o tanqueprint("%d Novo veículo de %3.2f m3.\t Nível atual: %5.1f m3"% (env.now, qtd, tanque.level))yield tanque.get(qtd)print("%d Veículo atendido de %3.2f.\t Nível atual: %5.1f m3"% (env.now, qtd, tanque.level))
O modelo de simulação completo do posto de gasolina fica:
import simpyimport random TANQUE_CAMINHAO =50# capacidade de abastecimento do caminhãoTANQUE_VEICULO =0.10# capacidade do veículoTEMPO_CHEGADAS =5# tempo entre chegadas sucessivas de veículosdefchegadasVeiculos(env,tanque):# gera chegadas de veículos por produtowhileTrue:yield env.timeout(TEMPO_CHEGADAS)# carrega veículo env.process(esvaziamentoTanque(env, TANQUE_VEICULO, tanque))defesvaziamentoTanque(env,qtd,tanque):# esvazia o tanqueprint("%d Novo veículo de %3.2f m3.\t Nível atual: %5.1f m3"% (env.now, qtd, tanque.level))yield tanque.get(qtd)print("%d Veículo atendido de %3.2f m3.\t Nível atual: %5.1f m3"% (env.now, qtd, tanque.level))defenchimentoTanque(env,qtd,tanque): # enche o tanqueprint("%d Novo caminhão com %4.1f m3.\t Nível atual: %5.1f m3"% (env.now, qtd, tanque.level))yield tanque.put(qtd)print("%d Tanque enchido com %4.1f m3.\t Nível atual: %5.1f m3"% (env.now, qtd, tanque.level))random.seed(150)env = simpy.Environment()#cria um tanque de 100 m3, com 50 m3 no início da simulaçãotanque = simpy.Container(env, capacity=100, init=50)env.process(chegadasVeiculos(env, tanque))env.run(until =200)
Quando por 200 minutos, o modelo anterior fornece como saída:
5 Novo veículo de 0.10 m3. Nível atual:50.0 m35 Veículo atendido de 0.10 m3. Nível atual:49.9 m310 Novo veículo de 0.10 m3. Nível atual:49.9 m310 Veículo atendido de 0.10. Nível atual:49.8 m315 Novo veículo de 0.10 m3. Nível atual:49.8 m315 Veículo atendido de 0.10 m3. Nível atual:49.7 m3
Criando um sensor para o nível atual do container
Inicialmente, para identificar se o nível do tanque abaixou além no nível mínimo, precisamos verificar qual o nível atual. Contudo, esse processo de verificação não é contínuo no tempo e deve ter o seu intervalo entre verificações pré-definido no modelo.
Assim, são necessários dois parâmetros: um para o nível mínimo e outro para o intervalo entre verificações do nível do tanque. Uma possível codificação para a função sensorTanqueseria:
NIVEL_MINIMO =50# nível mínimo de reabastecimento do tanqueTEMPO_CONTROLE =1# tempo entre verificações do nível do tanquedefsensorTanque(env,tanque):# quando o tanque baixar se certo nível, dispara o enchimentowhileTrue:if tanque.level <= NIVEL_MINIMO:# dispara pedido de enchimentoyield env.process(enchimentoTanque(env, TANQUE_CAMINHAO, tanque))# aguarda um tempo para fazer a nova chegagem do nível do tanqueyield env.timeout(TEMPO_CONTROLE)
A função sensorTanqueé um laço infinito (while True) que a cada 1 minuto (configurável na constante TEMPO_CONTROLE) verifica se o nível atual do tanque está abaixo ou igual ao nível mínimo (configurável na constante `NIVEL_MINIMO).
O modelo completo com a implentação do sensor fica:
import simpyimport random TANQUE_CAMINHAO =50# capacidade de abastecimento do caminhãoTANQUE_VEICULO =0.10# capacidade do veículoTEMPO_CHEGADAS =5# tempo entre chegadas sucessivas de veículosNIVEL_MINIMO =50# nível mínimo de reabastecimento do tanqueTEMPO_CONTROLE =1# tempo entre verificações do nível do tanquedefsensorTanque(env,tanque):# quando o tanque baixar se certo nível, dispara o enchimentowhileTrue:if tanque.level <= NIVEL_MINIMO:# dispara pedido de enchimentoyield env.process(enchimentoTanque(env, TANQUE_CAMINHAO, tanque))# aguarda um tempo para fazer a nova chegagem do nível do tanqueyield env.timeout(TEMPO_CONTROLE)defchegadasVeiculos(env,tanque):# gera chegadas de veículos por produtowhileTrue:yield env.timeout(TEMPO_CHEGADAS)# carrega veículo env.process(esvaziamentoTanque(env, TANQUE_VEICULO, tanque))defesvaziamentoTanque(env,qtd,tanque):# esvazia o tanqueprint("%d Novo veículo de %3.2f m3.\t Nível atual: %5.1f m3"% (env.now, qtd, tanque.level))yield tanque.get(qtd)print("%d Veículo atendido de %3.2f m3.\t Nível atual: %5.1f m3"% (env.now, qtd, tanque.level))defenchimentoTanque(env,qtd,tanque): # enche o tanqueprint("%d Novo caminhão com %4.1f m3.\t Nível atual: %5.1f m3"% (env.now, qtd, tanque.level))yield tanque.put(qtd)print("%d Tanque enchido com %4.1f m3.\t Nível atual: %5.1f m3"% (env.now, qtd, tanque.level))random.seed(150)env = simpy.Environment()#cria um tanque de 100 m3, com 50 m3 no início da simulaçãotanque = simpy.Container(env, capacity=100, init=50)env.process(chegadasVeiculos(env, tanque))env.process(sensorTanque(env, tanque))env.run(until =20)
Note a criação do processo do sensorTanque na penúltima linha do programa:
env.process(sensorTanque(env, tanque))
Este processo garante que o sensor estará operante ao longo de toda a simulação. Quando executado, o programa anterior retorna:
0 Novo caminhão com 50.0 m3. Nível atual:50.0 m30 Tanque enchido com 50.0 m3. Nível atual:100.0 m35 Novo veículo de 0.10 m3. Nível atual:100.0 m35 Veículo atendido de 0.10 m3. Nível atual:99.9 m310 Novo veículo de 0.10 m3. Nível atual:99.9 m310 Veículo atendido de 0.10 m3. Nível atual:99.8 m315 Novo veículo de 0.10 m3. Nível atual:99.8 m315 Veículo atendido de 0.10 m3. Nível atual:99.7 m3
Observação 1: Note que o enchimento ou esvaziamento dos tanques é instantâneo, isto é: não existe nenhuma taxa de enchimento ou esvaziamento associada aos processos. Cabe ao programador modelar situações em que a taxa de transferência é relevante (veja o Desafio 17, a seguir).
Observação 2: O tanque pode ser esvaziado ou enchido simultaneamente. Novamente cabe ao programador modelar a situação em que isto não se verifica (veja o Desafio 18, a seguir).
Conceitos desta seção
Desafios
Desafio 17: considere, no exemplo do posto, que a taxa de enchimento do tanque é de 1 litro/min e a de esvaziamento é de 2 litros/min. Altere o modelo para que ele incorpore os tempos de enchimento e esvaziamento, bem como forneça o tempo que o veículo aguardou na fila por atendimento.
Desafio 18: continuando o exemplo, modifique o modelo de modo que ele represente a situação em que o tanque não pode ser enchido e esvaziado simultaneamente.
A sua utilização é bastante simples, por exemplo, podemos modelar um tanque de 100 unidades de capacidade (m3, por exemplo), com um estoque inicial de 50 unidades, por meio do seguinte código:
Considere que um posto de gasolina possui um tanque com capacidade de 100 m3 (ou 100.000 litros) de combustível e que o tanque já contém 50 m3 armazenado.
Criaremos uma função, enchimentoTanque, que enche o tanque com 50 m3 sempre que um novo caminhão de reabastecimento de combustível chega ao posto:
Se você iniciar o tanque do posto a sua plena capacidade (100 m3), o caminhão tentará abastecer, mas não conseguirá por falta de espaço, virtualmente aguardando espaço no tanque na linha:
Considere que o posto atende automóveis que chegam em intervalos constantes de 5 minutos entre si e que cada veículo abastece 100 litros ou 0,10 m3.
Ainda no exemplo do posto, vamos chamar um caminhão de reabastecimento sempre que o tanque atingir o nível de 50 m3. Para isso, criaremos uma função sensorTanquecapaz de reconhecer o instante exato em que o nível do tanque abaixou do valor desejado e, portanto, deve ser enviado um caminhão de reabastecimento.