Em uma postagem anterior do blog, documentei o simmer em R para simulação de eventos discretos. Neste post, quero fornecer um exemplo mais prático. É um exemplo muito simples, para ser honesto.
Independentemente disso, e independentemente deste exemplo em geral, eu recomendo aprender simmer em R para qualquer pessoa interessada em simulação de eventos discretos. Compreender o pacote simmer em R significa que você deu uma boa olhada sob o capô de como é um software de simulação de eventos discretos, o que deve considerar em termos de arquitetura e governança.
Um modelo conceitual simples de um processo de inspeção de recebimento
Eu forneço um modelo conceitual muito simples de um processo de inspeção de recebimento na figura abaixo.
O processo é o seguinte: Os paletes recebidos são descarregados caixa a caixa e colocados em uma primeira linha de transporte. Esta linha de transporte leva à estação de inspeção. Neste modelo simples, a
suposição é que cada caixa é inspecionada. Após a inspeção, a caixa é encaminhada para a área de armazenamento central por meio de outra linha de transporte.
Implementação de modelo com pacote simmer em R
Tendo elaborado um modelo conceitual, agora posso implementá-lo no código. É aqui que o pacote simmer em R entra em ação. O código R é exibido abaixo. Como você pode ver, eu também uso os pacotes R magrittr e dplyr.
# importando simmer e outros pacotes
library(magrittr)
library(simmer)
library(simmer.plot)
library(dplyr)
# define semente para geração de números aleatórios
set.seed(42)
# declara/cria ambiente de simulação
env = simmer("Inspection model")
# configurar um fluxo de trabalho de trajetória de inspeção de recebimento
inspection = trajectory("receival inspection") %>%
seize("conveyor1", 1) %>%
timeout(3) %>%
release("conveyor1", 1) %>%
seize("inspection", 1) %>%
timeout(15) %>%
release("inspection",1) %>%
seize("conveyor2",1) %>%
timeout(3) %>%
release("conveyor2",1)
# adicionando um recurso ao ambiente de simulação
env %>%
# há uma correia transportadora indo para inspeção
add_resource("conveyor1",
capacity=1,
queue_size=10) %>%
# existe um posto de inspeção
add_resource("inspection",
capacity = 1,
queue_size=0) %>%
# há outra linha de transporte indo da inspeção para a área de
armazenamento central
add_resource("conveyor2",
capacity=1,
queue_size=10)
# adicionando gerador ao ambiente de simulação e atribuindo trajetória
de produção ao gerador
trajectory to generator
env %>%
add_generator(name_prefix = "boxes",
trajectory = inspection,
distribution = function() rnorm(n=1,
mean=6,
sd=1))
Tendo implementado o código, agora posso executar uma simulação.
Simulação executada com o pacote simmer em R
Na linha de código R exibida abaixo eu executo a simulação. Deixo a simulação correr até o tempo de simulação 1000. Neste caso, isso representa um tempo de simulação de 1000 seg.
env %>% run(1000)
## simmer environment: Inspection model | now: 1000 | next: 1001.26780219819
## { Monitor: in memory }
## { Resource: conveyor1 | monitored: TRUE | server status: 0(1) | queue status: 0(10) }
## { Resource: inspection | monitored: TRUE | server status: 1(1) | queue status: 0(0) }
## { Resource: conveyor2 | monitored: TRUE | server status: 0(1) | queue status: 0(10) }
## { Source: boxes | monitored: 1 | n_generated: 168 }
As informações exibidas acima não nos dizem muito. Podemos ver que a fonte acionou 168 chegadas, o que corresponde ao tempo de descarga da caixa de 6 segundos (1000 seg/168 caixas = 5,95 seg). Mas isso NÃO significa que 168 caixas foram inspecionadas. Se olharmos para o modelo conceitual, isso claramente não seria possível, pois o tempo de inspeção é de 15 segundos por caixa. Assim, dentro de 1000 seg. no máximo. 66 caixas podem ser inspecionadas. Em outras palavras, só porque 168 chegadas foram geradas pela fonte não significa que todas elas foram inspecionadas/processadas. Muitas dessas chegadas foram rejeitadas. Quando uma chegada não pode ser atendida por um recurso e quando a fila não é grande o suficiente para contê-lo, o recurso é rejeitado e descartado da trajetória.
Como vou demonstrar em outro post do blog, o steam permite sub-trajetórias. As chegadas rejeitadas podem ser atribuídas a essas sub-trajetórias. No entanto, por enquanto: Se eu quiser analisar os
resultados da simulação, tenho que usar as funções de monitoramento fornecidas pelo pacote simmer em R
Funções getter para dados monitorados em simmer
Conforme apresentado por mim em minha documentação do steam (veja minha postagem anterior no blog), o pacote simmer em R fornece funções de monitoramento para análise de simulação.
No código abaixo eu uso a função get_mon_resources() getter:
dfResults_resources = env %>% get_mon_resources()
dfResults_resources %>% head()
resource<chr> | time<dbl> | server<int> | queue<int> | capacity<dbl> | queue_size<dbl> | system<int> | limit<dbl> | replication<int> | |
---|---|---|---|---|---|---|---|---|---|
1 | conveyor1 | 7.370958 | 1 | 0 | 1 | 10 | 1 | 11 | 1 |
2 | conveyor1 | 10.370958 | 0 | 0 | 1 | 10 | 0 | 11 | 1 |
3 | inspection | 10.370958 | 1 | 0 | 1 | 0 | 1 | 1 | 1 |
4 | conveyor1 | 12.806260 | 1 | 0 | 1 | 10 | 1 | 11 | 1 |
5 | conveyor1 | 15.806260 | 0 | 0 | 1 | 10 | 0 | 11 | 1 |
6 | conveyor1 | 19.169389 | 1 | 0 | 1 | 10 | 1 | 11 | 1 |
get_mon_resources() é uma função getter para obtenção de dados que estão sendo monitorados por swift. O pacote simmer em R fornece essas funções getter para chegadas, atributos e recursos. Como fica claro no trecho de dataframe exibido acima, as alterações de estado relacionadas aos recursos são documentadas nos dados retornados por get_mon_resources(). Por exemplo, o transportador 1 está servindo uma caixa em t = 7,37 s e termina de servir essa caixa 3 s depois, em t = 10,37 s.
Três funções getter vêm junto com o pacote simmer em R. Todos eles retornam dataframes.
As funções getter são as seguintes:
get_mon_arrivals(): Retorna dados para cada chegada, incluindo nome,
hora inicial, hora final, hora ativa, sinalizador boolean finalizado.
get_mon_resources(): Retorna dados que documentam mudanças de estado
nos recursos, incluindo nome do recurso, hora do evento (tempo de
disparo), contagem de servidor e fila, capacidade, tamanho da fila,
contagem do sistema (servidor + fila) e limite do sistema (capacidade capacidade_tamanho).
get_mon_attributes(): Retorna dados sobre mudanças de estado em
atributos, incluindo nome, hora do evento de mudança de atributo e
chave de atributo.
Calculando o rendimento do sistema simulado com base em dados de simmer monitorados
Usando dados obtidos por funções getter, posso desenvolver estatísticas personalizadas para avaliar o desempenho de um sistema simulado. Neste caso, usarei a função getter get_mon_arrivals() para
implementar uma estatística de taxa de transferência. Faço isso no código abaixo:
throughput = function(env){
throughput_count = env %>% get_mon_arrivals() %>% filter(finished==TRUE) %>% nrow()
return(throughput_count)
}
throughput(env)
## [1] 54
Após o tempo de simulação de 1000 segundos, 54 caixas foram inspecionadas e guardadas na área de armazenamento central.
Com o pacote simmer em R posso visualizar dados monitorados, por exemplo. para recursos
Usando os dados de recursos monitorados recuperados como um dataframe com a função getter get_mon_resources() fornecida pelo pacote simmer em R, posso produzir gráficos úteis. No exemplo abaixo eu implemento um gráfico de utilização de recursos.
plot(get_mon_resources(env),
metric="utilization",
c("conveyor1","inspection","conveyor2"))
A visualização acima indica que a estação de inspeção atingiu o tempo limite em mais de 80% do seu tempo. A partir dos parâmetros do modelo, sabemos que o processo de inspeção em si leva 15 segundos. Se isso representa aproximadamente 83,33% do tempo disponível total das estações de inspeção, isso significa que o tempo disponível por caixa está em torno de 18,00 segundos (cálculo aproximado). Isso também significa que a estação de inspeção está gastando 3,00 segundos em
outra coisa. Este “algo mais” é o tempo de transporte do transportador1 para a estação de inspeção.
Aumentar a utilização da estação de inspeção aumentando o tamanho da fila
Aumentarei o tamanho da fila da estação de inspeção para 1, acima de 0. Isso deve aumentar a utilização da estação de inspeção.
env2 = simmer("Inspection model 2") %>%
add_resource("conveyor1",
capacity=1,
queue_size=10) %>%
add_resource("inspection",
capacity = 1,
queue_size=1) %>%
add_resource("conveyor2",
capacity=1,
queue_size=10) %>%
add_generator(name_prefix = "boxes",
trajectory = inspection,
distribution = function() rnorm(n=1,
mean=6,
sd=1)) %>%
run(1000)
env2 %>%
get_mon_resources() %>%
plot(metric="utilization",
c("conveyor1","inspection","conveyor2"))
Aí está. Como o transporte agora pode ser executado em uma posição de buffer em paralelo à estação de inspeção, a utilização do próprio processo de inspeção aumenta. Não se perde tempo na transmissão.
Concluo esta análise avaliando o rendimento dessa configuração de sistema ajustada.
throughput(env2)
## [1] 65
A taxa de transferência agora é de 65 caixas após 1000 segundos de tempo de simulação, o que verifica o modelo de simulação.
Observações finais sobre esta simulação simples do processo de inspeção de recebimento com simmer
Neste artigo, apresentei o pacote simmer em R e forneci um exemplo prático muito simples. Em futuras postagens do blog, fornecerei exemplos adicionais. Procuro, assim, proporcionar uma melhor compreensão sobre a fervura. Estou confiante em convencer os engenheiros de simulação sobre o fato de que o simmer é uma alternativa válida quando comparado com o software de simulação comercial, como, por exemplo, AnyLogic, Simulação de Planta, FlexSim etc.
Cientista de dados com foco em simulação, otimização e modelagem em R, SQL, VBA e Python
Leave a Reply