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 simpy

env = simpy.Environment()
# cria um tanque de 100 m3 de capacidade, com 50 m3 no início da simulação
tanque = 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 simpy
import random        

TANQUE_CAMINHAO = 50       # capacidade de abastecimento do caminhão

def enchimentoTanque(env, qtd, tanque):  
    # enche o tanque
    print("%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ção
tanque = 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 m3
0 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 simpy
import random        

TANQUE_CAMINHAO = 50        # capacidade de abastecimento do caminhão
TANQUE_VEICULO = 0.10       # capacidade do veículo
TEMPO_CHEGADAS = 5          # tempo entre chegadas sucessivas de veículos

def chegadasVeiculos(env, tanque):
    # gera chegadas de veículos por produto

def esvaziamentoTanque(env, qtd, tanque):
    # esvazia o tanque

def enchimentoTanque(env, qtd, tanque):  
    # enche o tanque
    print("%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ção
tanque = 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:

def chegadasVeiculos(env, tanque):
    # gera chegadas de veículos por produto
    while True:
        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:

def esvaziamentoTanque(env, qtd, tanque):
    # esvazia o tanque
    print("%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 simpy
import random        

TANQUE_CAMINHAO = 50        # capacidade de abastecimento do caminhão
TANQUE_VEICULO = 0.10       # capacidade do veículo
TEMPO_CHEGADAS = 5          # tempo entre chegadas sucessivas de veículos

def chegadasVeiculos(env, tanque):
    # gera chegadas de veículos por produto
    while True:
        yield env.timeout(TEMPO_CHEGADAS)
        # carrega veículo
        env.process(esvaziamentoTanque(env, TANQUE_VEICULO, tanque))

def esvaziamentoTanque(env, qtd, tanque):
    # esvazia o tanque
    print("%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))

def enchimentoTanque(env, qtd, tanque):  
    # enche o tanque
    print("%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ção
tanque = 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 m3
5 Veículo atendido de 0.10 m3.   Nível atual:  49.9 m3
10 Novo veículo de 0.10 m3.      Nível atual:  49.9 m3
10 Veículo atendido de 0.10.     Nível atual:  49.8 m3
15 Novo veículo de 0.10 m3.      Nível atual:  49.8 m3
15 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 tanque
TEMPO_CONTROLE = 1          # tempo entre verificações do nível do tanque

def sensorTanque(env, tanque):
    # quando o tanque baixar se certo nível, dispara o enchimento
    while True:
        if tanque.level <= NIVEL_MINIMO:
            # dispara pedido de enchimento
            yield env.process(enchimentoTanque(env, TANQUE_CAMINHAO, tanque))
        # aguarda um tempo para fazer a nova chegagem do nível do tanque
        yield 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 simpy
import random        

TANQUE_CAMINHAO = 50        # capacidade de abastecimento do caminhão
TANQUE_VEICULO = 0.10       # capacidade do veículo
TEMPO_CHEGADAS = 5          # tempo entre chegadas sucessivas de veículos
NIVEL_MINIMO = 50           # nível mínimo de reabastecimento do tanque
TEMPO_CONTROLE = 1          # tempo entre verificações do nível do tanque

def sensorTanque(env, tanque):
    # quando o tanque baixar se certo nível, dispara o enchimento
    while True:
        if tanque.level <= NIVEL_MINIMO:
            # dispara pedido de enchimento
            yield env.process(enchimentoTanque(env, TANQUE_CAMINHAO, tanque))
        # aguarda um tempo para fazer a nova chegagem do nível do tanque
        yield env.timeout(TEMPO_CONTROLE)

def chegadasVeiculos(env, tanque):
    # gera chegadas de veículos por produto
    while True:
        yield env.timeout(TEMPO_CHEGADAS)
        # carrega veículo
        env.process(esvaziamentoTanque(env, TANQUE_VEICULO, tanque))

def esvaziamentoTanque(env, qtd, tanque):
    # esvazia o tanque
    print("%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))

def enchimentoTanque(env, qtd, tanque):  
    # enche o tanque
    print("%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ção
tanque = 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 m3
0 Tanque enchido com 50.0 m3.    Nível atual: 100.0 m3
5 Novo veículo de 0.10 m3.       Nível atual: 100.0 m3
5 Veículo atendido de 0.10 m3.   Nível atual:  99.9 m3
10 Novo veículo de 0.10 m3.      Nível atual:  99.9 m3
10 Veículo atendido de 0.10 m3.  Nível atual:  99.8 m3
15 Novo veículo de 0.10 m3.      Nível atual:  99.8 m3
15 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.

Last updated